{"id":16363,"library":"fortune","title":"Fortune.js","description":"Fortune.js is a non-native graph database abstraction layer designed for both Node.js and web browsers, currently at stable version 5.5.19. It provides an application-level implementation of graph-like features, including bi-directional relationships, inverse updates, and referential integrity, all built upon a user-defined data model. The library maintains a steady release cadence, with recent updates focusing on dependency management. Key differentiators include its ability to enable portable storage options and facilitate the sharing of identical data models across server and client environments, streamlining full-stack development. While the core module handles data modeling and relationship management, persistent storage is achieved via optional, separate database adapters for systems like MongoDB, Postgres, or IndexedDB. It avoids traditional ORM complexities by treating records as plain data structures and managing relationships at the application level.","status":"active","version":"5.5.19","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/fortunejs/fortune","tags":["javascript","database","adapter","data","model","record"],"install":[{"cmd":"npm install fortune","lang":"bash","label":"npm"},{"cmd":"yarn add fortune","lang":"bash","label":"yarn"},{"cmd":"pnpm add fortune","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core utility for custom error types.","package":"error-class","optional":false},{"reason":"Lightweight event emitter for internal event handling.","package":"event-lite","optional":false}],"imports":[{"note":"While CommonJS `require` works in Node.js, ESM `import` is preferred for modern applications and browser compatibility. The library exports a default function to initialize the store.","wrong":"const fortune = require('fortune')","symbol":"fortune","correct":"import fortune from 'fortune'"},{"note":"The `message` function (for internationalized errors) is a static property exposed on the default `fortune` instance, not a direct named export from the module itself. It must be destructured from the imported default instance.","wrong":"import { message } from 'fortune'","symbol":"message","correct":"import fortune from 'fortune'; const { message } = fortune;"},{"note":"The `Adapter` abstract base class, `errors`, `methods`, and other static properties are exposed on the default `fortune` instance, not as top-level named exports from the module. They should be destructured from the `fortune` instance after it's imported.","wrong":"import { Adapter } from 'fortune'","symbol":"Adapter","correct":"import fortune from 'fortune'; const { Adapter } = fortune;"}],"quickstart":{"code":"const fortune = require('fortune') // Or use `import fortune from 'fortune';` in an ESM project.\n\n// Define record types for a micro-blogging service\nconst store = fortune({\n  user: {\n    name: String,\n    // Many-to-many inversely related fields\n    following: [ Array('user'), 'followers' ],\n    followers: [ Array('user'), 'following' ],\n    // One-to-many relationship\n    posts: [ Array('post'), 'author' ]\n  },\n  post: {\n    message: String,\n    // Many-to-one relationship\n    author: [ 'user', 'posts' ]\n  }\n})\n\n// Example: Create a user and a post, then find them\n(async () => {\n  // Create a user record\n  const [ user ] = await store.create('user', [\n    { id: 'user123', name: 'Alice' }\n  ]);\n  console.log('Created User:', user);\n\n  // Create a post record associated with the user\n  const [ post ] = await store.create('post', [\n    { id: 'post456', message: 'Hello Fortune.js!', author: user.id }\n  ]);\n  console.log('Created Post:', post);\n\n  // Find the user and include their posts\n  const foundUsers = await store.find('user', ['user123'], null, [['posts']]);\n  console.log('Found Users with posts:', JSON.stringify(foundUsers, null, 2));\n\n  // Find the post and include its author\n  const foundPosts = await store.find('post', ['post456'], null, [['author']]);\n  console.log('Found Posts with author:', JSON.stringify(foundPosts, null, 2));\n\n  // Disconnect the store (important if using a persistent adapter)\n  await store.disconnect();\n})().catch(console.error);","lang":"javascript","description":"This quickstart initializes a Fortune.js store with a basic micro-blogging schema, demonstrating bi-directional and one-to-many relationships, then performs asynchronous create and find operations with includes."},"warnings":[{"fix":"Migrate to using explicit `require` or `import` statements for `fortune-indexeddb`, `fortune-http`, `fortune-ws`, and other plugins. Remove references to the `fortune.net` namespace.","message":"Version 5.0.0 extracted several core functionalities (IndexedDB adapter, HTTP, and WebSocket implementations) into separate npm packages. The `fortune.net` namespace was removed. For example, `fortune-http` must now be explicitly imported and used instead of `fortune.net.http`. The IndexedDB adapter is no longer the default for browsers and must be manually specified.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Review migration guides for version 2.x and update serializer configurations, adapter definitions, and transform functions to use array formats. Adjust `fortune.request` options as per the updated API.","message":"Version 2.0.0 introduced several breaking changes including the removal of `Serializer` from the core (moved to `net.http.Serializer`), changes to serializer configuration to accept arrays, and changes in how adapters and transform functions are defined (now also as arrays). The `fortune.request` options object format was also modified to match `fortune.net.request`.","severity":"breaking","affected_versions":">=2.0.0 <5.0.0"},{"fix":"Ensure that your record type definitions do not include a field named `id`. The library will automatically handle primary key assignment and management.","message":"The primary key `id` is a reserved field name for all record types and should not be explicitly defined in your schema. Fortune.js automatically manages this field for unique identification.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Be mindful that modifying relationships (links) on one record will automatically update the corresponding inverse links on related records. Understand the implications for data consistency and validation within your application logic.","message":"Fortune.js automatically manages inverse relationship updates and referential integrity. Changes to a record's links will automatically affect related records by denormalizing relationships, meaning updates can cascade across your data model. This behavior is by design but requires awareness.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"For persistent data, install and configure a suitable database adapter by passing it in the options when initializing the Fortune store: `fortune(recordTypes, { adapter: [myAdapter, { /* options */ }] })`.","message":"By default, Fortune.js uses an in-memory database for persistence, which is suitable for development but does not persist data beyond the application lifecycle. For production use or persistent storage, you must explicitly configure a database adapter (e.g., `fortune-mongodb`, `fortune-postgres`, `fortune-indexeddb`).","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"If your project uses ES Modules (e.g., `\"type\": \"module\"` in `package.json`), use `import fortune from 'fortune'` instead of `const fortune = require('fortune')`. Ensure that any plugins you use are imported correctly based on their module type.","cause":"Attempting to use `require()` to import Fortune.js (or one of its ESM-only plugins) in a Node.js project configured for ES Modules, or when the package itself only provides an ESM entry point.","error":"ERR_REQUIRE_ESM: require() of ES Module ... not supported."},{"fix":"For CommonJS environments, use `const fortune = require('fortune')`. If you intend to use ES Modules, ensure your project is configured for it (e.g., by adding `\"type\": \"module\"` to your `package.json` or using `.mjs` file extensions).","cause":"Attempting to use `import` statements for Fortune.js (or any other module) in a CommonJS context (e.g., a `.js` file without `\"type\": \"module\"` in `package.json` in Node.js, or in older browser environments without module support).","error":"SyntaxError: Cannot use import statement outside a module"},{"fix":"Ensure all fields in your record type definitions use one of the allowed native types (String, Number, Boolean, Date, Object, Buffer) or a correctly defined custom type function. For nested data, declare the field as `Object`. For example, `coordinates: Object` instead of `coordinates: { lat: Number, lon: Number }`.","cause":"A field in your record type definition has an invalid type. Fortune.js expects specific native JavaScript types (String, Number, Boolean, Date, Object, Buffer) or a custom type function. Nested object structures must explicitly use the `Object` type, not nested inline definitions.","error":"TypeError: Invalid type for field 'yourFieldName'"}],"ecosystem":"npm"}