{"id":20098387,"url":"https://github.com/wikibonsai/caudex","last_synced_at":"2026-05-04T18:34:15.340Z","repository":{"id":144711088,"uuid":"608254390","full_name":"wikibonsai/caudex","owner":"wikibonsai","description":"A lightweight in-memory graph database with first-class tree support.","archived":false,"fork":false,"pushed_at":"2026-04-04T20:00:23.000Z","size":225,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-04T20:54:12.565Z","etag":null,"topics":["ai-memory","data-structure","db","graph","graph-database","in-memory-database","index","knowledge-graph","ontology","tree","typescript","wikibonsai"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/caudex","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wikibonsai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-03-01T16:30:43.000Z","updated_at":"2026-04-04T20:00:27.000Z","dependencies_parsed_at":"2023-07-28T04:15:26.476Z","dependency_job_id":"23f96a36-54cf-4387-b900-52b736b1eea4","html_url":"https://github.com/wikibonsai/caudex","commit_stats":{"total_commits":4,"total_committers":2,"mean_commits":2.0,"dds":0.25,"last_synced_commit":"fb6a41dc218c97d11b6a684944cbd514f50f8b6e"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/wikibonsai/caudex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wikibonsai%2Fcaudex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wikibonsai%2Fcaudex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wikibonsai%2Fcaudex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wikibonsai%2Fcaudex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wikibonsai","download_url":"https://codeload.github.com/wikibonsai/caudex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wikibonsai%2Fcaudex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32619825,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"ssl_error","status_checked_at":"2026-05-04T10:08:02.005Z","response_time":58,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-memory","data-structure","db","graph","graph-database","in-memory-database","index","knowledge-graph","ontology","tree","typescript","wikibonsai"],"created_at":"2024-11-13T17:03:30.134Z","updated_at":"2026-05-04T18:34:15.332Z","avatar_url":"https://github.com/wikibonsai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# caudex\n\n[![A WikiBonsai Project](https://img.shields.io/badge/%F0%9F%8E%8B-A%20WikiBonsai%20Project-brightgreen)](https://github.com/wikibonsai/wikibonsai)\n[![NPM package](https://img.shields.io/npm/v/caudex)](https://npmjs.org/package/caudex)\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./caudex.svg\" width=\"300\" height=\"300\"/\u003e\n\u003c/p\u003e\n\n.[^inspire]\n\nAn index/db for tracking complex relationships in collections, such as personal [wiki](https://github.com/wikibonsai/wikirefs)s, with support for a [semantic tree](https://github.com/wikibonsai/semtree).\n\n🍄 Cultivate connections in your [🎋 WikiBonsai](https://github.com/wikibonsai/wikibonsai) digital garden.\n\n## Install\n\nInstall with [npm](https://docs.npmjs.com/cli/v9/commands/npm-install):\n\n```\nnpm install caudex\n```\n\n## Use\n\nIf you have some file data you want to store or index...\n\n```js\nimport { Caudex } from 'caudex';\n\nlet fileData = [\n  {\n    id: '\u003csome-unique-id\u003e',\n    filename: 'fname',\n    uri: '/uri',\n    title: 'Title',\n    type: 'default',\n  },\n  // ...\n];\nconst caudex = new Caudex(fileData);\n```\n\n...Or just a web (graph):\n\n```js\nimport { Base } from './base';\nimport { Web } from './web';\n\nclass WebOnlyCaudex extends Web(Base) {}\nconst web = new WebOnlyCaudex(fileData);\n```\n\n...Or just a tree:\n\n```js\nimport { Base } from './base';\nimport { Tree } from './tree';\n\nclass TreeOnlyCaudex extends Tree(Base) {}\nconst tree = new TreeOnlyCaudex(fileData);\n```\n\n### Async\n\nCaudex is synchronously implemented, but asynchronous access can be facilitated by turning on the `thread` option:\n\n```js\nimport { Caudex } from 'caudex';\n\nlet opts = { thread: true };\nconst caudex = new Caudex(fileData, opts);\n```\n\nThen subsequent calls to `caudex` will use [mutex locks](https://github.com/DirtyHairy/async-mutex) to ensure atomic access to the internal index. Remember to acquire the lock before performing actions on the caudex. For example, a call to [`has()`](https://github.com/wikibonsai/caudex?tab=readme-ov-file#hasid-string-boolean)...\n\n```ts\n// node with id '1'\ncaudex.has('1');\n```\n\n...turns into:\n\n```ts\ncaudex.lock.acquire()\n           .then((release) =\u003e { // node with id '1'\n                                const res: boolean = locky.has('1');\n                                release();\n                                return res;\n                              });\n```\n\n## Terms\n\nThere is some terminology that will help in understanding the innerworkings of the `caudex` as well as the internal variable name choice.\n\n### Data Structures\n\n- Base: Basic functions of the index, such as storing the hash map of node id's to nodes and the ability to add/edit/remove nodes.\n- Tree: A hierarchical structure; good for ordering information.\n- Web: A graph structure; good for associative traversal.\n\nUnder the hood, the `caudex` is essentially one hash table whose keys are node ids and values are the nodes themselves. Properties (`all()`) and actions (`add()`, `edit()`, `rm()`) are all functions being run over the hash table to calculate the desired data. This implementation mirrors [pointers](https://en.wikipedia.org/wiki/Pointer_(computer_programming)), since [javascript/typescript doesn't have them](https://stackoverflow.com/questions/17382427/are-there-pointers-in-javascript#:~:text=No%2C%20JS%20doesn't%20have,the%20address%20of%20an%20object.). So, in pointer parlance, to \"pass around a reference\" you pass around a node id and to \"dereference a pointer\" in order to obtain the value (node) from the key (node id) in the hash table.\n\nMirroring pointer behavior allows for implementing tree and graph data structures that are truer to form. And, since most everything is a function, tree and web related functions are grouped into mix-ins that can be used (or not) based on need. By using the main `caudex`, which contains both `tree` and `web` functions, a hybrid tree-web data structure can be leveraged. (\"web\" can be thought of as synonymous with the computer science \"graph\" data structure)\n\nThe \"base\" portion handles all operations that would be expected in either the `tree` or `web` data structures, such as adding, editing, or removing a node.\n\n### Function Kinds\n\n- Properties: Methods that return a property of either the caudex or some node(s).\n- Relational Properties: Methods that return relationship information of some node(s).\n- Actions: Methods that perform some action on the caudex or some node(s).\n\nAs said before, the `caudex` is essentially a hash with a collection of functions to answer questions about the hash table. It is helpful to think of each function as fitting into one of a few categories that dictate how the function works and what it will return.\n\n\"Properties\" are functions that describe the state of the `caudex`. For example, `all()` returns all of the node ids that currently exist and `nodetypes()` returns all of the nodetypes that exist.\n\n\"Relational properties\" are functions that describe relationships between nodes and often take an `id: string` argument. For example, `ancestors(id: string)` returns an array of node ids that form the ancestry of the node with the given `id` and `backlinks(id: string)` returns an array of node ids who contain the node with the given `id` in its links.\n\nGenerally speaking, \"property\" and \"relational property\" functions will accept a `QUERY_TYPE` in addition to the required arguments. This can alter the return type based on need. For example, instead of receiving an array of node ids, by adding `QUERY_TYPE.NODE`, an array of all the nodes would be returned instead. See individual function docs for details.\n\nFinally, \"Actions\" are functions that perform some action on the `caudex` or a node in the `caudex`. For example, `add(data: any)` will parse the data payload and add a new node based on the data if it is valid and `edit(id: string, key: any, newValue: any)` updates the value for a node with the given `id` at the givne `key`.\n\n## Other Terms\n\nThere are also wikibonsai-specific terminologies that you can read more about [here](https://github.com/wikibonsai/wikibonsai/blob/main/docs/TERMS.md).\n\n## API\n\n'Properties', 'Relational Properties', and 'Actions' are all just methods. But properties describe the state of the caudex and relational properties describe the state of a node within the caudex, whereas actions change the state of the caudex.\n\nProperties can be called with a `QUERY_TYPE`, which will determine the type of data returned.\n\n### Base\n\n#### 'Properties'\n\n##### `all(): string[]`\n\nReturns all node ids in the caudex.\n\n##### `nodetypes(): string[]`\n\nReturns an array of all nodetypes in the caudex.\n\n##### `zombies(): string[]`\n\nReturns an array of node ids for all zombie nodes in the caudex.\n\n#### Actions\n\n##### `has(id: string): boolean`\n\nVerifies if a node id exists in the caudex; returns `true` if it does and `false` if it does not.\n\n##### `flushData([id: string]): boolean`\n\nFlushes / deletes node data. If no `id` is given, all data for all nodes is deleted. If an `id` is provided, then just the node data for the node with that id is flushed / deleted.\n\n##### `flushRels(): boolean`\n\nFlushes / deletes all node relationships, including family (tree) relationships and reference relationships (web) -- in the caudex.\n\n##### `clear(): void`\n\nDelete the entire caudex.\n\n##### `add(data: any[, typeinfo: NodeTypeInfo]): Node | undefined`\n\nAdd a new node to the caudex with the given `data` payload. If the node was added, whether successfully or by generating a zombie node, return the Node. If no node was created successfully, then `undefined` is returned.\n\nIf an `id` is included in the `data` payload, it will be used as the node's id. If not, a new id will be generated for the node internally.\n\n##### `edit(id: string, key: any, newValue: any): boolean`\n\nEdit the node with the given `id` so that its `key` points to thew `newValue`. Returns `true` if the edit was successful and `false` if it failed.\n\n##### `fill(id: string, data: any): Node | undefined`\n\nFill the zombie node with the given `id` via the given `data` payload. If the population was successful, the now-not-zombie-node will be returned. If population was not successful, `undefined` will be returned.\n\n##### `get(id: string): Node | undefined`\n\nGet the node with the given `id`. Returns the node if found and `undefined` if not found.\n\n##### `find(key: any, value: any): Node | undefined`\n\nFind a node in the caudex where it has a given `key` with the given `value` in its data. Returns the node if one is found and `undefined` if none is found.\n\nThis action requires that the `key` is one of the caudex's `uniqDataKeys`. If is not, try using `filter` instead.\n\n##### `filter(key: any, value: any): Node[] | undefined`\n\nFind all nodes in the caudex whose given `key` matches the given `value`. Returns an array of nodes with valid matches and `undefined` if none are found.\n\nAlternatively, if the `key` is one of the caudex's `uniqKeys` `find` may be used instead to find a specific node.\n\n##### `rm(id: string): boolean`\n\nRemove / delete a node from the caudex with the given `id`. Returns `true` if the node was deleted successfully and `false` if not.\n\n### Tree\n\n#### Properties\n\n##### `root(): string | undefined`\n\nReturns the id of the root of the tree or `undefined` if none is set.\n\n##### `orphans(treeIDs: string[]): string[] | undefined`\n\nReturns all of the ids of orphan nodes in the tree of the caudex.\n\n`treeIDs` defines what nodes should be considered part of the tree.\n\n#### Relational Properties\n\n##### `ancestors(id: string): string[]`\n\nReturn an array of node ids for all ancestor nodes (all nodes along the path from the root to the target node) to the node with the given `id`.\n\n##### `parent(id: string): string`\n\nReturn the node id for the parent (the node above, which points the target node) of the node with the given `id`.\n\n##### `siblings(id: string): string`\n\nReturn an array of node ids for the siblings (all nodes at the same level as the target node) of the node with the given `id`.\n\n##### `children(id: string): string`\n\nReturn an array of node ids for the children (all nodes one level below the target node) of the node with the given `id`.\n\n##### `descendants(id: string): string`\n\nReturn an array of node ids for the descendents (all nodes below the target node) of the node with the given `id`.\n\n##### `lineage(id: string): string`\n\nReturn an array of node ids for the lineage (all ancestors and descendents, excluding the target node) of the node with the given `id`.\n\n##### `level(id: string): number`\n\nReturns the numeric level of the target node.\n\n#### Actions\n\n##### `flushRelFams()`\n\nFlush / delete family relationships in the caudex.\n\n##### `graft(parentID: string, childID: string, force: boolean = false): boolean`\n\nGraft a node with the given `childID` to another node with the given `parentID`. Setting `force` to `true` will skip tree validation, which means the tree's structure won't be verified but grafting will complete faster.\n\nTo perform subtree-sized changes, see [`transplant()`](https://github.com/wikibonsai/caudex/?tab=readme-ov-file#transplantsubrootid-string-subtree--id-string-children-string--boolean).\n\n##### `replace(source: string, target: string): Node | undefined`\n\nReplace a `source` node's position in the tree with the `target` node via their IDs. The updated target node is returned on success.\n\n##### `transplant(subrootID: string, subtree: { id: string, children: string[] }[]): boolean`\n\nReplace a subtree in the tree with another subtree. This will return `true` if the subtree was successfully \"transplanted\" and the result was a valid tree. Otherwise, the original tree will be left alone and the function will return `false`.\n\n##### `prune(parentID: string, childID: string, force: boolean = false): boolean`\n\nPrune a node with the given `childID` from another node with the given `parentID`. This method will fail if the node with the given `childID` has children. Setting `force` to `true` will skip tree validation, which means the tree's structure won't be verified but grafting will complete faster.\n\nTo perform subtree-sized changes, see [`transplant()`](https://github.com/wikibonsai/caudex/?tab=readme-ov-file#transplantsubrootid-string-subtree--id-string-children-string--boolean).\n\n##### `printTree()`\n\nPrint the tree to the console.\n\n### Web\n\n#### Properties\n\n##### `isolates(): string[] | undefined`\n\nReturns all of the ids of isolated nodes (nodes not connected to the web) in the graph of the caudex.\n\n##### `reftypes(): Set\u003cstring\u003e`\n\nReturn all reftypes in the caudex.\n\n##### `attrtypes(): Set\u003cstring\u003e`\n\nReturn all attrtypes in the caudex.\n\n##### `linktypes(): Set\u003cstring\u003e`\n\nReturn all linktypes in the caudex.\n\n#### Relational Properties\n\n##### (⚠️ coming soon!) `forerefs(id: string): Attrs | undefined`\n\n##### (⚠️ coming soon!) `backrefs(id: string): Attrs | undefined`\n\n##### `foreattrs(id: string): Attrs | undefined`\n\nReturns foreward attributes for the given node id.\n\n##### `backattrs(id: string): Attrs | undefined`\n\nReturns back attributes fore the given node id.\n\n##### `forelinks(id: string): Links | undefined`\n\nReturns foreward links for the given node id.\n\n##### `backlinks(id: string): Links | undefined`\n\nReturns back links for the given node id.\n\n##### `foreembeds(id: string): Embeds | undefined`\n\nReturns foreward embeds for the given node id.\n\n##### `backembeds(id: string): Embeds | undefined`\n\nReturns back embeds for the given node id.\n\n##### `neighbors(id: string): string[]`\n\nReturn an array of node ids for all neighbors / references.\n\n#### Actions\n\n##### `flushRelRefs([id: string]): boolean`\n\nFlush / delete all reference relationships. If no id is given, flush all reference\n\n##### `connect(source: string, target: string, ref: REL.REF, type: string = ''): boolean`\n\nConnect a `source` node id to a `target` node id via the given `ref` kind (`attr` or `link`) and `type` text.\n\n##### `retype(oldType: string, newType: string[, type: REL.REF]): boolean`\n\n##### `transfer(source: string, target: string, kind: REL.REF = REL.REF.REF): Node | undefined`\n\nTransfer the relationships from the `source` node to the `target` node via their IDs. Kind of relationships to transfer can be filtered by the `kind` var. Returns the target node on successful transfer.\n\n##### `disconnect(source: string, target: string, ref: REL.REF, type: string = ''): boolean`\n\nDisconnect a `source` node id from a `target` node id of the given `ref` kind (`attr` or `link`) and `type` text.\n\n\n[^inspire]: Logo inspired by [databases](https://cdn-icons-png.flaticon.com/512/20/20093.png) and [caudexes](https://www.google.com/search?q=caudex\u0026source=lnms\u0026tbm=isch\u0026sa=X\u0026ved=2ahUKEwiD_LbPwr36AhUsRTABHdXOBq0Q_AUoAXoECAIQAw\u0026biw=1011\u0026bih=800\u0026dpr=2) -- especially [this one](https://thumbs.dreamstime.com/z/adenium-shrub-branched-caudex-green-foliage-illustration-colored-pencils-229255411.jpg).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwikibonsai%2Fcaudex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwikibonsai%2Fcaudex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwikibonsai%2Fcaudex/lists"}