@kedem/okdb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/LICENSE +57 -0
  2. package/README.md +344 -0
  3. package/banner.jpg +0 -0
  4. package/bin/okdb.js +2 -0
  5. package/docs/OKDB-ARCHITECTURE.md +1036 -0
  6. package/docs/auth-and-sync.md +558 -0
  7. package/docs/auth-permissions.md +143 -0
  8. package/docs/change-log.md +169 -0
  9. package/docs/data-model.md +174 -0
  10. package/docs/embeddings.md +338 -0
  11. package/docs/files.md +131 -0
  12. package/docs/fts.md +139 -0
  13. package/docs/functions.md +514 -0
  14. package/docs/getting-started.md +233 -0
  15. package/docs/http-api.md +705 -0
  16. package/docs/index.md +115 -0
  17. package/docs/indexes.md +207 -0
  18. package/docs/logging.md +116 -0
  19. package/docs/manifest.json +38 -0
  20. package/docs/migration.md +154 -0
  21. package/docs/pipelines.md +598 -0
  22. package/docs/plugins.md +144 -0
  23. package/docs/querying.md +204 -0
  24. package/docs/queue.md +637 -0
  25. package/docs/sync.md +156 -0
  26. package/docs/transactions.md +140 -0
  27. package/docs/ttl.md +375 -0
  28. package/okdb.js +1 -0
  29. package/package.json +26 -0
  30. package/public/admin-app.js +1 -0
  31. package/public/android-chrome-192x192.png +0 -0
  32. package/public/android-chrome-512x512.png +0 -0
  33. package/public/apple-touch-icon.png +0 -0
  34. package/public/components/admin-route-host.ok.js +1 -0
  35. package/public/components/env-picker.ok.js +1 -0
  36. package/public/components/field-path-input.ok.js +1 -0
  37. package/public/components/field.html +6 -0
  38. package/public/components/geo-map.ok.js +1 -0
  39. package/public/components/ok-cron-input.ok.js +1 -0
  40. package/public/components/ok-dropzone.ok.js +1 -0
  41. package/public/components/ok-js-input.ok.js +1 -0
  42. package/public/components/ok-json-input.ok.js +1 -0
  43. package/public/components/ok-text-monaco-input.ok.js +1 -0
  44. package/public/components/theme-toggle.ok.js +1 -0
  45. package/public/favicon-16x16.png +0 -0
  46. package/public/favicon-32x32.png +0 -0
  47. package/public/favicon.ico +0 -0
  48. package/public/images/logo.png +0 -0
  49. package/public/images/logo.svg +333 -0
  50. package/public/index.html +6 -0
  51. package/public/layouts/_default.ok.html +1 -0
  52. package/public/layouts/okdb-cube.ok.html +1 -0
  53. package/public/login-app.js +1 -0
  54. package/public/login.html +1 -0
  55. package/public/modules/ok.js +1 -0
  56. package/public/sections/api/index.ok.html +1 -0
  57. package/public/sections/api/parts/api-endpoint.ok.js +1 -0
  58. package/public/sections/auth/index.ok.html +1 -0
  59. package/public/sections/auth/modals/create-token-modal.ok.js +1 -0
  60. package/public/sections/auth/modals/edit-token-modal.ok.js +1 -0
  61. package/public/sections/auth/modals/perm-info-popover.ok.js +1 -0
  62. package/public/sections/auth/parts/token-detail.ok.js +1 -0
  63. package/public/sections/auth/parts/token-list.ok.js +1 -0
  64. package/public/sections/db/index.ok.html +1 -0
  65. package/public/sections/db/modals/add-item-modal.ok.js +1 -0
  66. package/public/sections/db/modals/create-env-modal.ok.js +1 -0
  67. package/public/sections/db/modals/create-fts-modal.ok.js +1 -0
  68. package/public/sections/db/modals/create-index-modal.ok.js +1 -0
  69. package/public/sections/db/modals/create-pipeline-modal.ok.js +1 -0
  70. package/public/sections/db/modals/demo-env-modal.ok.js +1 -0
  71. package/public/sections/db/modals/remove-env-modal.ok.js +1 -0
  72. package/public/sections/db/modals/schema-edit-modal.ok.js +1 -0
  73. package/public/sections/db/parts/db-overview.ok.js +1 -0
  74. package/public/sections/db/parts/db-pipelines-panel.ok.js +1 -0
  75. package/public/sections/db/parts/edit-row.ok.js +1 -0
  76. package/public/sections/db/parts/tm-timeline.ok.js +1 -0
  77. package/public/sections/db/parts/type-changelog.ok.js +1 -0
  78. package/public/sections/db/parts/type-list.ok.js +1 -0
  79. package/public/sections/db/parts/type-pipelines-tab.ok.js +1 -0
  80. package/public/sections/db/parts/type-schema-tab.ok.js +1 -0
  81. package/public/sections/db/parts/type-viewer.ok.js +1 -0
  82. package/public/sections/db/parts/type-violations-tab.ok.js +1 -0
  83. package/public/sections/docs/index.ok.html +1 -0
  84. package/public/sections/embeddings/index.ok.html +1 -0
  85. package/public/sections/embeddings/modals/register-model-modal.ok.js +1 -0
  86. package/public/sections/embeddings/parts/embed-create-panel.ok.js +1 -0
  87. package/public/sections/embeddings/parts/embed-embedder-panel.ok.js +1 -0
  88. package/public/sections/embeddings/parts/embed-engine-declaration-editor.ok.js +1 -0
  89. package/public/sections/embeddings/parts/embed-engine-list.ok.js +1 -0
  90. package/public/sections/embeddings/parts/embed-indexer-panel.ok.js +1 -0
  91. package/public/sections/embeddings/parts/embed-lifecycle-bar.ok.js +1 -0
  92. package/public/sections/embeddings/parts/embed-model-catalog.ok.js +1 -0
  93. package/public/sections/embeddings/parts/embed-overview.ok.js +1 -0
  94. package/public/sections/embeddings/parts/embed-search-panel.ok.js +1 -0
  95. package/public/sections/embeddings/parts/embed-worker-panel.ok.js +1 -0
  96. package/public/sections/embeddings/parts/embeddings-engine-panel.ok.js +1 -0
  97. package/public/sections/embeddings/parts/engines-overview.ok.js +1 -0
  98. package/public/sections/embeddings/parts/pipeline-create-panel.ok.js +1 -0
  99. package/public/sections/engines/engine-panel-shared-style.js +1 -0
  100. package/public/sections/engines/engine-ui-utils.js +1 -0
  101. package/public/sections/engines/index.ok.html +1 -0
  102. package/public/sections/engines/modals/engine-modal.ok.js +1 -0
  103. package/public/sections/engines/parts/engine-declaration-editor.ok.js +1 -0
  104. package/public/sections/engines/parts/engine-lifecycle-actions.ok.js +1 -0
  105. package/public/sections/engines/parts/engine-panel-shell.ok.js +1 -0
  106. package/public/sections/engines/parts/engine-resource-card.ok.js +1 -0
  107. package/public/sections/engines/parts/engine-row-item.ok.js +1 -0
  108. package/public/sections/engines/parts/generic-engine-panel.ok.js +1 -0
  109. package/public/sections/files/index.ok.html +1 -0
  110. package/public/sections/files/parts/files-blob-status.ok.js +1 -0
  111. package/public/sections/files/parts/files-collection-list.ok.js +1 -0
  112. package/public/sections/files/parts/files-collection-panel.ok.js +1 -0
  113. package/public/sections/files/parts/files-file-list.ok.js +1 -0
  114. package/public/sections/files/parts/files-overview.ok.js +1 -0
  115. package/public/sections/files/parts/files-path-browser.ok.js +1 -0
  116. package/public/sections/files/parts/files-upload-panel.ok.js +1 -0
  117. package/public/sections/functions/index.ok.html +1 -0
  118. package/public/sections/functions/modals/function-modal.ok.js +1 -0
  119. package/public/sections/functions/parts/function-detail.ok.js +1 -0
  120. package/public/sections/functions/parts/function-logs.ok.js +1 -0
  121. package/public/sections/functions/parts/function-runner.ok.js +1 -0
  122. package/public/sections/functions/parts/functions-list.ok.js +1 -0
  123. package/public/sections/license/index.ok.html +1 -0
  124. package/public/sections/license/parts/license-panel.ok.js +1 -0
  125. package/public/sections/processors/index.ok.html +1 -0
  126. package/public/sections/queue/index.ok.html +1 -0
  127. package/public/sections/queue/modals/create-bucket-modal.ok.js +1 -0
  128. package/public/sections/queue/modals/edit-bucket-modal.ok.js +1 -0
  129. package/public/sections/queue/modals/edit-job-modal.ok.js +1 -0
  130. package/public/sections/queue/modals/enqueue-job-modal.ok.js +1 -0
  131. package/public/sections/queue/modals/job-type-modal.ok.js +1 -0
  132. package/public/sections/queue/parts/ok-job-form.ok.js +1 -0
  133. package/public/sections/queue/parts/queue-buckets.ok.js +1 -0
  134. package/public/sections/queue/parts/queue-job-types.ok.js +1 -0
  135. package/public/sections/queue/parts/queue-jobs.ok.js +1 -0
  136. package/public/sections/queue/parts/queue-types.ok.js +1 -0
  137. package/public/sections/queue/parts/queue-workers.ok.js +1 -0
  138. package/public/sections/sync/index.ok.html +5 -0
  139. package/public/sections/sync/parts/sync-node-detail.ok.js +1 -0
  140. package/public/sections/sync/parts/sync-retention.ok.js +1 -0
  141. package/public/sections/sync/parts/sync-topology.ok.js +1 -0
  142. package/public/sections/system/index.ok.html +1 -0
  143. package/public/sections/system/modals/data-ops-modal.ok.js +1 -0
  144. package/public/sections/system/parts/system-api-panel.ok.js +1 -0
  145. package/public/sections/system/parts/system-auth-panel.ok.js +1 -0
  146. package/public/sections/system/parts/system-log-history.ok.js +1 -0
  147. package/public/sections/system/parts/system-log.ok.js +1 -0
  148. package/public/sections/system/parts/system-status.ok.js +1 -0
  149. package/public/sections/system/parts/system-sync-panel.ok.js +1 -0
  150. package/public/sections/views/index.ok.html +1 -0
  151. package/public/sections/views/modals/create-view-modal.ok.js +1 -0
  152. package/public/sections/views/parts/view-detail.ok.js +1 -0
  153. package/public/sections/views/parts/views-list.ok.js +1 -0
  154. package/public/sections/views/parts/views-overview.ok.js +1 -0
  155. package/public/setup-app.js +1 -0
  156. package/public/setup.html +1 -0
  157. package/public/site.webmanifest +1 -0
  158. package/public/stores/auth-store.js +1 -0
  159. package/public/stores/events-store.js +1 -0
  160. package/public/stores/functions-store.js +1 -0
  161. package/public/stores/okdb-store.js +1 -0
  162. package/public/stores/theme-store.js +1 -0
  163. package/public/styles.css +1 -0
  164. package/public/test-cron-input.html +10 -0
  165. package/public/test-json-input.html +101 -0
  166. package/public/util/permissions.js +1 -0
  167. package/public/util/sift-schema.js +1 -0
  168. package/public/vendor/okjs/ok.esm.min.js +2 -0
  169. package/public/vendor/okjs/toolkit/behavior/async.ok.js +1 -0
  170. package/public/vendor/okjs/toolkit/components/ok-chart.ok.js +1 -0
  171. package/public/vendor/okjs/toolkit/components/ok-doc-viewer.ok.js +1 -0
  172. package/public/vendor/okjs/toolkit/components/ok-marked.ok.js +1 -0
  173. package/public/vendor/okjs/toolkit/components/ok-monaco.ok.js +1 -0
  174. package/public/vendor/okjs/toolkit/core/ok-layer-service.ok.js +1 -0
  175. package/public/vendor/okjs/toolkit/core/ok-layer.ok.js +1 -0
  176. package/public/vendor/okjs/toolkit/core/ok-overlay.ok.js +1 -0
  177. package/public/vendor/okjs/toolkit/core/ok-sandbox.ok.js +1 -0
  178. package/public/vendor/okjs/toolkit/core/transition.ok.js +1 -0
  179. package/public/vendor/okjs/toolkit/core/virtualized.ok.js +1 -0
  180. package/public/vendor/okjs/toolkit/devtools/ok-console-service.ok.js +1 -0
  181. package/public/vendor/okjs/toolkit/devtools/ok-console.ok.js +1 -0
  182. package/public/vendor/okjs/toolkit/devtools/ok-fps-monitor-service.ok.js +1 -0
  183. package/public/vendor/okjs/toolkit/devtools/ok-fps-monitor.ok.js +1 -0
  184. package/public/vendor/okjs/toolkit/devtools/ok-inspector-service.ok.js +1 -0
  185. package/public/vendor/okjs/toolkit/devtools/ok-inspector.ok.js +1 -0
  186. package/public/vendor/okjs/toolkit/devtools/ok-js-tree.ok.js +1 -0
  187. package/public/vendor/okjs/toolkit/devtools/ok-timeline-service.ok.js +1 -0
  188. package/public/vendor/okjs/toolkit/devtools/ok-timeline.ok.js +1 -0
  189. package/public/vendor/okjs/toolkit/docs/doc-viewer.ok.js +1 -0
  190. package/public/vendor/okjs/toolkit/editor/ok-live-component.ok.js +1 -0
  191. package/public/vendor/okjs/toolkit/editor/ok-live-example.ok.js +1 -0
  192. package/public/vendor/okjs/toolkit/editor/ok-live-shell.ok.js +1 -0
  193. package/public/vendor/okjs/toolkit/elements/ok-dropdown.ok.js +1 -0
  194. package/public/vendor/okjs/toolkit/elements/ok-icon.ok.js +1 -0
  195. package/public/vendor/okjs/toolkit/elements/ok-select.ok.js +1 -0
  196. package/public/vendor/okjs/toolkit/elements/ok-table.ok.js +1 -0
  197. package/public/vendor/okjs/toolkit/errors/ok-crash-boundary.ok.js +1 -0
  198. package/public/vendor/okjs/toolkit/errors/ok-crash-info.ok.js +1 -0
  199. package/public/vendor/okjs/toolkit/i18n/i18n-editor-examples.ok.js +1 -0
  200. package/public/vendor/okjs/toolkit/i18n/i18n-editor.ok.js +1 -0
  201. package/public/vendor/okjs/toolkit/i18n/i18n-key-editor-tips.ok.js +1 -0
  202. package/public/vendor/okjs/toolkit/i18n/i18n-key-editor.ok.js +1 -0
  203. package/public/vendor/okjs/toolkit/i18n/i18n-service.ok.js +1 -0
  204. package/public/vendor/okjs/toolkit/i18n/ok-i18n.js +1 -0
  205. package/public/vendor/okjs/toolkit/interaction/ok-contextmenu.ok.js +1 -0
  206. package/public/vendor/okjs/toolkit/interaction/ok-dismiss-service.ok.js +1 -0
  207. package/public/vendor/okjs/toolkit/interaction/ok-draggable.ok.js +1 -0
  208. package/public/vendor/okjs/toolkit/interaction/ok-flyover-panel.ok.js +1 -0
  209. package/public/vendor/okjs/toolkit/interaction/ok-flyover.ok.js +1 -0
  210. package/public/vendor/okjs/toolkit/interaction/ok-highlight-service.ok.js +1 -0
  211. package/public/vendor/okjs/toolkit/interaction/ok-highlight.ok.js +1 -0
  212. package/public/vendor/okjs/toolkit/interaction/ok-hotkeys-service.ok.js +1 -0
  213. package/public/vendor/okjs/toolkit/interaction/ok-picker-service.ok.js +1 -0
  214. package/public/vendor/okjs/toolkit/interaction/ok-popout-service.ok.js +1 -0
  215. package/public/vendor/okjs/toolkit/interaction/ok-popout.ok.js +1 -0
  216. package/public/vendor/okjs/toolkit/interaction/ok-portal-service.ok.js +1 -0
  217. package/public/vendor/okjs/toolkit/interaction/ok-submenu.ok.js +1 -0
  218. package/public/vendor/okjs/toolkit/layout/ok-resizer.ok.js +1 -0
  219. package/public/vendor/okjs/toolkit/manifest.js +1 -0
  220. package/public/vendor/okjs/toolkit/modals/ok-modal-service.ok.js +1 -0
  221. package/public/vendor/okjs/toolkit/modals/ok-modal.ok.js +1 -0
  222. package/public/vendor/okjs/toolkit/modals/ok-toast-service.ok.js +1 -0
  223. package/public/vendor/okjs/toolkit/modals/ok-window.ok.js +1 -0
  224. package/public/vendor/okjs/toolkit/navigation/hash-router.ok.js +1 -0
  225. package/public/vendor/okjs/toolkit/navigation/history-router.ok.js +1 -0
  226. package/public/vendor/okjs/toolkit/navigation/router.ok.js +1 -0
  227. package/public/vendor/okjs/toolkit/sync/reactive-sync-service.ok.js +1 -0
  228. package/public/vendor/okjs/toolkit/sync/reactive-sync.js +1 -0
  229. package/public/vendor/okjs/toolkit/theming/blocks/ok-design-button.css.js +1 -0
  230. package/public/vendor/okjs/toolkit/theming/blocks/ok-design-input.css.js +1 -0
  231. package/public/vendor/okjs/toolkit/theming/ok-design-style.js +1 -0
  232. package/public/vendor/okjs/toolkit/theming/ok-design-vars.js +1 -0
  233. package/public/vendor/okjs/toolkit/theming/ok-design.ok.js +1 -0
  234. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-input.ok.js +1 -0
  235. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-service.ok.js +1 -0
  236. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-style.js +1 -0
  237. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-utils.js +1 -0
  238. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-variable.ok.js +1 -0
  239. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor-vm.js +1 -0
  240. package/public/vendor/okjs/toolkit/theming/ok-theme-editor/ok-theme-editor.ok.js +1 -0
  241. package/public/vendor/okjs/toolkit/theming/ok-theme.ok.js +1 -0
  242. package/public/view-models/type-query-vm.js +1 -0
  243. package/types/environment.d.ts +130 -0
  244. package/types/errors.d.ts +98 -0
  245. package/types/features/admin.d.ts +4 -0
  246. package/types/features/api.d.ts +18 -0
  247. package/types/features/auth.d.ts +31 -0
  248. package/types/features/embeddings.d.ts +39 -0
  249. package/types/features/engines.d.ts +23 -0
  250. package/types/features/files.d.ts +29 -0
  251. package/types/features/fts.d.ts +25 -0
  252. package/types/features/functions.d.ts +23 -0
  253. package/types/features/mcp.d.ts +17 -0
  254. package/types/features/pipelines.d.ts +19 -0
  255. package/types/features/queue.d.ts +189 -0
  256. package/types/features/sync.d.ts +34 -0
  257. package/types/features/time-machine.d.ts +32 -0
  258. package/types/features/views.d.ts +16 -0
  259. package/types/index.d.ts +153 -0
  260. package/types/options.d.ts +202 -0
package/docs/index.md ADDED
@@ -0,0 +1,115 @@
1
+ # OKDB
2
+
3
+ **An embedded, document-centric database for Node.js.** No separate server. No network hop. Just open a path and write data.
4
+
5
+ OKDB wraps [LMDB](https://www.symas.com/lmdb) — one of the fastest key-value stores ever built — and adds typed collections, composite secondary indexes, full-text search, vector embeddings, multi-node sync, a durable job queue, and binary blob storage. All in one process, all ACID.
6
+
7
+ ---
8
+
9
+ ## What it is
10
+
11
+ OKDB is a **structured layer on top of LMDB**. The design decision is simple: LMDB gives you memory-mapped, copy-on-write B+ trees with MVCC and crash-safe writes. OKDB adds everything a real application needs on top of that without changing the embedding model.
12
+
13
+ Think of it as a document store where reads are synchronous (just a pointer dereference into mmap'd memory), writes are atomic, and all the derived structures — indexes, FTS posting lists, vector graphs, changelogs — are maintained automatically inside the same transaction.
14
+
15
+ ---
16
+
17
+ ## Strengths
18
+
19
+ - :zap: **Reads are synchronous** — no async, no round trips, no copies
20
+ - :lock: **ACID transactions** — inherited from LMDB; no partial state ever observable
21
+ - :package: **Self-contained** — everything in one process, one set of directories
22
+ - :refresh-cw: **Multi-node sync** — LWW replication over HTTP, no coordinator
23
+ - :search: **Vector + FTS + Geo** — search primitives built in, not bolted on
24
+ - :mail: **Durable queue** — jobs survive crashes, stored in the same database
25
+ - :folder: **File storage** — SHA-256 content-addressable blobs, integrated with sync
26
+
27
+ ---
28
+
29
+ ## What it is not
30
+
31
+ - Not a client/server database (no PostgreSQL-style network protocol)
32
+ - Not designed for browser or Bun (Node.js only)
33
+ - Not an audit-log — the change-log is LWW-deduplicated per key, not an immutable history
34
+ - Not horizontally scalable in the traditional sense — LMDB is one writer at a time per process
35
+
36
+ ---
37
+
38
+ ## Core concepts at a glance
39
+
40
+ | Concept | What it is |
41
+ | --------------- | -------------------------------------------------------------- |
42
+ | **Type** | A named collection of records (like a table/collection) |
43
+ | **Key** | String primary key for each record |
44
+ | **Value** | Any JSON-serialisable object |
45
+ | **Environment** | An isolated LMDB database directory |
46
+ | **Index** | A composite secondary index on one or more fields |
47
+ | **Clock** | A monotonic per-environment integer incremented on every write |
48
+ | **Change log** | An ordered log of all mutations, keyed by clock value |
49
+ | **Processor** | A reactive change handler — like triggers, but composable |
50
+
51
+ ---
52
+
53
+ ## Architecture overview
54
+
55
+ ```
56
+ Your app code
57
+
58
+
59
+ OKDB (orchestrator)
60
+
61
+ ├── ~system env ← node identity, env registry
62
+ ├── default env ← your data, indexes, change log
63
+ ├── queue env ← job queue
64
+ ├── embeddings env ← vector embedding status
65
+ └── custom envs ← whatever you create
66
+ ```
67
+
68
+ All environments are LMDB directories on disk. Each has its own clock, changelog, and HLC-based sync cursor.
69
+
70
+ ---
71
+
72
+ ## Quick example
73
+
74
+ ```javascript
75
+ const OKDB = require('src/okdb');
76
+
77
+ const okdb = new OKDB('./mydb');
78
+ await okdb.open();
79
+
80
+ await okdb.registerType('notes');
81
+ await okdb.registerIndex('notes', ['author', 'createdAt']);
82
+
83
+ await okdb.put('notes', 'n1', { author: 'alice', body: 'Hello world', createdAt: Date.now() });
84
+ await okdb.put('notes', 'n2', { author: 'bob', body: 'Hey there', createdAt: Date.now() });
85
+
86
+ // Synchronous reads
87
+ const note = okdb.get('notes', 'n1');
88
+
89
+ // Index scan
90
+ for (const { key, value } of okdb.byIndex('notes', ['author'], { prefix: ['alice'] })) {
91
+ console.log(key, value);
92
+ }
93
+
94
+ await okdb.close();
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Docs map
100
+
101
+ - [Getting Started](./getting-started.md) — install, open, first writes
102
+ - [Data Model](./data-model.md) — types, keys, environments, storage layout
103
+ - [Querying](./querying.md) — reads, ranges, MongoDB-style filters
104
+ - [Indexes](./indexes.md) — secondary, composite, unique, geo
105
+ - [Transactions](./transactions.md) — batching, versioning, optimistic concurrency
106
+ - [Change Log & Events](./change-log.md) — clock, changelog, processor, events
107
+ - [Sync](./sync.md) — multi-node replication
108
+ - [Full-Text Search](./fts.md) — FTS index, tokenizer, query
109
+ - [Embeddings](./embeddings.md) — vector pipeline, semantic search
110
+ - [Queue](./queue.md) — durable job queue
111
+ - [Files](./files.md) — blob / file storage
112
+ - [Custom Functions](./functions.md) — sandboxed stored JS functions, env/global scope, HTTP execution
113
+ - [HTTP API](./http-api.md) — built-in REST API
114
+ - [Plugins](./plugins.md) — extending OKDB before open
115
+ - [Migration](./migration.md) — export, import, backup, blob integrity
@@ -0,0 +1,207 @@
1
+ # Indexes
2
+
3
+ Secondary indexes let you scan records by field values without touching every record. They are maintained atomically inside every write transaction — there is no window where an index is out of sync with the data.
4
+
5
+ ---
6
+
7
+ ## Registering an index
8
+
9
+ ```javascript
10
+ // Single field
11
+ await okdb.registerIndex('articles', ['author']);
12
+
13
+ // Composite — multi-field
14
+ await okdb.registerIndex('articles', ['author', 'publishedAt']);
15
+
16
+ // Unique constraint
17
+ await okdb.registerIndex('users', ['email'], { unique: true });
18
+
19
+ // Geospatial
20
+ await okdb.registerIndex('places', ['location'], { type: 'geo', precision: 7 });
21
+ ```
22
+
23
+ ### MCP note
24
+
25
+ Index management is exposed through the grouped `okdb_index` MCP tool.
26
+ Use `action: "create"` and send either the canonical `index` string or the convenience `fields` array.
27
+
28
+ ```json
29
+ {
30
+ "name": "okdb_index",
31
+ "arguments": {
32
+ "action": "create",
33
+ "env": "default",
34
+ "type": "places",
35
+ "fields": ["location"],
36
+ "indexType": "geo",
37
+ "precision": 7
38
+ }
39
+ }
40
+ ```
41
+
42
+ For geo indexes, the indexed field should hold a single object shaped like `{ lat, lon }`.
43
+ That means the correct field path is usually `location`, not `location.lat` + `location.lon` as separate fields.
44
+
45
+ Indexes build **asynchronously** from existing data after registration. Writes during the build are tracked and the index converges to READY. To wait for completion:
46
+
47
+ ```javascript
48
+ await okdb.indexReady('articles', ['author', 'publishedAt']);
49
+ ```
50
+
51
+ Check status without waiting:
52
+
53
+ ```javascript
54
+ okdb.getIndexStatus('articles', ['author']);
55
+ // → 'creating' | 'resetting' | 'ready'
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Dropping an index
61
+
62
+ ```javascript
63
+ await okdb.dropIndex('articles', ['author', 'publishedAt']);
64
+ ```
65
+
66
+ The index sub-database is deleted. Existing query code that references it will throw `OKDBIndexNotRegisteredError`.
67
+
68
+ ---
69
+
70
+ ## Index names
71
+
72
+ Internally, an index is identified by its fields joined with `~`:
73
+
74
+ ```
75
+ ['author'] → "author"
76
+ ['author', 'publishedAt'] → "author~publishedAt"
77
+ ['status', 'priority', 'when'] → "status~priority~when"
78
+ ```
79
+
80
+ You rarely need to deal with index names directly — all API methods accept `string[]` and normalise for you.
81
+
82
+ ---
83
+
84
+ ## Composite indexes
85
+
86
+ A composite index orders records by the first field, then the second within ties, and so on. This mirrors SQL's multi-column index semantics.
87
+
88
+ ```javascript
89
+ await okdb.registerIndex('orders', ['customerId', 'createdAt']);
90
+
91
+ // All orders by customer 'c42', newest first
92
+ for (const { key, value } of okdb.byIndex('orders', ['customerId', 'createdAt'], {
93
+ prefix: ['c42'],
94
+ reverse: true,
95
+ limit: 50,
96
+ })) { ... }
97
+ ```
98
+
99
+ The trailing `null` sentinel in the LMDB key format ensures that a prefix scan on `['c42']` correctly returns all entries for that customer regardless of their `createdAt` value.
100
+
101
+ ---
102
+
103
+ ## Dot-notation for nested fields
104
+
105
+ Field paths can use dots to reach nested properties:
106
+
107
+ ```javascript
108
+ await okdb.registerIndex('users', ['address.city']);
109
+
110
+ // Records where address.city === 'Paris'
111
+ for (const { key, value } of okdb.byIndex('users', ['address.city'], { prefix: ['Paris'] })) { ... }
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Unique indexes
117
+
118
+ A unique index prevents two records from having the same value for the indexed fields.
119
+
120
+ ```javascript
121
+ await okdb.registerIndex('users', ['email'], { unique: true });
122
+
123
+ // This will throw OKDBUniqueConstraintError:
124
+ await okdb.put('users', 'user-2', { email: 'alice@example.com' }); // if 'alice@example.com' already exists
125
+ ```
126
+
127
+ ### Sync conflicts
128
+
129
+ When a duplicate arrives via sync (from another node), OKDB doesn't reject it — sync data is never lost. Instead, a **violation** is recorded, and a **winner** is deterministically chosen:
130
+
131
+ > Highest HLC timestamp wins. Ties broken by lexicographically largest `origin` node ID.
132
+
133
+ Violations are stored locally (not synced) and resolve automatically when the losing record is removed or updated.
134
+
135
+ ```javascript
136
+ // List all violations for a type
137
+ const violations = okdb.getUniqueViolations('users');
138
+
139
+ // Check if any violations exist for a specific index
140
+ const hasProb = okdb.hasUniqueViolations('users', ['email']);
141
+
142
+ // Get a specific violation
143
+ const v = okdb.getUniqueViolation('users', ['email'], 'alice@example.com');
144
+ // v = { winner, entries, count, detectedAt, ... }
145
+ ```
146
+
147
+ Events emitted:
148
+
149
+ ```javascript
150
+ okdb.events.on('unique:violation', ({ type, index, indexKey, winner }) => { ... });
151
+ okdb.events.on('unique:violation_resolved', ({ type, index, indexKey }) => { ... });
152
+ ```
153
+
154
+ :::note
155
+ Geo indexes cannot be unique. Geohash collisions make uniqueness semantics undefined — the registration will throw.
156
+ :::
157
+
158
+ ---
159
+
160
+ ## Geo indexes
161
+
162
+ Geospatial indexes use geohash encoding to map `{ lat, lon }` coordinates into a lexicographically ordered string space.
163
+
164
+ ```javascript
165
+ await okdb.registerIndex('restaurants', ['coords'], { type: 'geo', precision: 7 });
166
+
167
+ await okdb.put('restaurants', 'r1', { name: 'Le Bistro', coords: { lat: 48.87, lon: 2.31 } });
168
+
169
+ // Radius search
170
+ const results = okdb.geoQuery('restaurants', 'coords', {
171
+ lat: 48.87,
172
+ lon: 2.31,
173
+ radius: 1000, // metres
174
+ });
175
+ for (const { key, value, distance } of results) { ... }
176
+ ```
177
+
178
+ **Precision guide:**
179
+
180
+ | Precision | Cell size | Good for |
181
+ | --------- | --------- | ------------- |
182
+ | 5 | ~4.9km | Country-level |
183
+ | 6 | ~1.2km | City-level |
184
+ | 7 | ~153m | Neighbourhood |
185
+ | 8 | ~38m | Street |
186
+ | 9 | ~5m | Building |
187
+
188
+ Higher precision = more storage, slower builds, higher accuracy.
189
+
190
+ ---
191
+
192
+ ## `ensureType` shorthand
193
+
194
+ The most concise way to set up a type with indexes in one call:
195
+
196
+ ```javascript
197
+ await okdb.ensureType('products', {
198
+ indexes: [
199
+ ['category'],
200
+ ['category', 'price'],
201
+ { fields: ['location'], type: 'geo', precision: 6 },
202
+ { fields: ['sku'], unique: true },
203
+ ],
204
+ });
205
+ ```
206
+
207
+ This registers the type if missing, registers each index if missing, and is safe to call on startup every time.
@@ -0,0 +1,116 @@
1
+ # Logging
2
+
3
+ OKDB has a built-in structured logger available as `okdb.log`. Logs are emitted as plain objects and routed to any number of attached sinks. A console sink is attached by default.
4
+
5
+ ---
6
+
7
+ ## Entry Shape
8
+
9
+ Every log call produces an entry with this shape:
10
+
11
+ ```js
12
+ {
13
+ level: 'info' | 'warn' | 'error' | 'debug',
14
+ msg: string, // human-readable message
15
+ meta: object, // system identity set by child loggers
16
+ context: any, // user-provided call-site data (second arg)
17
+ ts: number // Date.now()
18
+ }
19
+ ```
20
+
21
+ `meta` contains machine-readable identity fields (feature, env name, function name, etc). `context` contains whatever you pass as the second argument to a log call — it is for human display only and not filtered on.
22
+
23
+ ### Known `meta` Keys
24
+
25
+ | Key | Who sets it | Example values |
26
+ | ---------- | -------------------------- | -------------------------------------------------------------- |
27
+ | `feature` | each feature child logger | `'queue'`, `'auth'`, `'fts'`, `'sync'`, `'functions'`, `'env'` |
28
+ | `env` | env logger, functions pool | `'demo-places'` |
29
+ | `fn` | functions pool (per run) | `'myFunction'` |
30
+ | `runId` | functions pool (per run) | `'abc123'` |
31
+ | `runnerId` | functions pool (per run) | `'fn-1'` |
32
+
33
+ ---
34
+
35
+ ## `okdb.log` — Basic Usage
36
+
37
+ ```js
38
+ okdb.log.info('server started', { port: 3000 });
39
+ okdb.log.warn('slow query', { ms: 420, type: 'events' });
40
+ okdb.log.error('unexpected failure', { err: err.message });
41
+ okdb.log.debug('cache miss', { key });
42
+ ```
43
+
44
+ ---
45
+
46
+ ## `okdb.log.child(meta)` — Scoped Loggers
47
+
48
+ `child(extraMeta)` returns a new logger instance that shares the same sinks but stamps every entry with additional `meta` fields. Use it to create feature or run-scoped loggers.
49
+
50
+ ```js
51
+ // Feature logger — created once, reused for all calls
52
+ const authLog = okdb.log.child({ feature: 'auth' });
53
+ authLog.warn('invalid token');
54
+ // → { level: 'warn', msg: 'invalid token', meta: { feature: 'auth' }, context: undefined, ts }
55
+
56
+ // Per-environment logger
57
+ const envLog = okdb.log.child({ feature: 'env', env: 'demo-places' });
58
+ envLog.info('env opened');
59
+ // → { ..., meta: { feature: 'env', env: 'demo-places' }, ... }
60
+
61
+ // Run-scoped child — created per function invocation
62
+ const runLog = okdb.log.child({ feature: 'functions', env, fn, runId, runnerId });
63
+ runLog.info('function invoked');
64
+ runLog.info('result ready', { value: 42 });
65
+ // → { ..., meta: { feature: 'functions', env, fn, runId, runnerId }, context: { value: 42 }, ts }
66
+ ```
67
+
68
+ `child()` does a shallow merge of meta fields. Child meta overrides parent meta for the same key. The returned logger shares the same sink set — attaching or detaching sinks on the root logger affects all children.
69
+
70
+ ---
71
+
72
+ ## Consuming Logs
73
+
74
+ ### `okdb.log.attach(fn)` — Custom Sink
75
+
76
+ Attach a function to receive every log entry:
77
+
78
+ ```js
79
+ okdb.log.attach((entry) => {
80
+ // entry: { level, msg, meta, context, ts }
81
+ myExternalLogger.log(entry);
82
+ });
83
+ ```
84
+
85
+ To detach, call the returned function:
86
+
87
+ ```js
88
+ const detach = okdb.log.attach(fn);
89
+ detach();
90
+ ```
91
+
92
+ ### `okdb.events.on('log', fn)` — Event Bus
93
+
94
+ Entries are also emitted on the OKDB event bus:
95
+
96
+ ```js
97
+ okdb.events.on('log', (entry) => {
98
+ console.log(entry.meta?.feature, entry.msg);
99
+ });
100
+ ```
101
+
102
+ ### `okdb.logs` — Ring Buffer
103
+
104
+ A circular buffer of recent log entries is available for inspection:
105
+
106
+ ```js
107
+ okdb.logs; // array of recent entries, newest last
108
+ ```
109
+
110
+ ---
111
+
112
+ ## `attachConsole()` — Console Output
113
+
114
+ `okdb.log.attachConsole()` adds a human-readable console sink. It is called automatically when OKDB starts in development mode.
115
+
116
+ Function-scoped logs (`meta.feature === 'functions'`) are suppressed from the console because they are stored in function run records and displayed in the Admin UI instead. All other features are printed.
@@ -0,0 +1,38 @@
1
+ [
2
+ { "file": "index.md", "label": "Overview" },
3
+ { "file": "getting-started.md", "label": "Getting Started" },
4
+ {
5
+ "label": "Core",
6
+ "children": [
7
+ { "file": "data-model.md", "label": "Data Model" },
8
+ { "file": "querying.md", "label": "Querying" },
9
+ { "file": "indexes.md", "label": "Indexes" },
10
+ { "file": "transactions.md", "label": "Transactions" },
11
+ { "file": "change-log.md", "label": "Change Log & Events" }
12
+ ]
13
+ },
14
+ {
15
+ "label": "Features",
16
+ "children": [
17
+ { "file": "sync.md", "label": "Sync" },
18
+ { "file": "fts.md", "label": "Full-Text Search" },
19
+ { "file": "embeddings.md", "label": "Embeddings" },
20
+ { "file": "pipelines.md", "label": "Pipelines" },
21
+ { "file": "queue.md", "label": "Queue" },
22
+ { "file": "files.md", "label": "Files" },
23
+ { "file": "functions.md", "label": "Custom Functions" },
24
+ { "file": "ttl.md", "label": "TTL (Time-to-Live)" }
25
+ ]
26
+ },
27
+ {
28
+ "label": "Reference",
29
+ "children": [
30
+ { "file": "auth-and-sync.md", "label": "Auth & Sync" },
31
+ { "file": "auth-permissions.md", "label": "Auth Permissions" },
32
+ { "file": "http-api.md", "label": "HTTP API" },
33
+ { "file": "plugins.md", "label": "Plugins" },
34
+ { "file": "logging.md", "label": "Logging" },
35
+ { "file": "migration.md", "label": "Migration" }
36
+ ]
37
+ }
38
+ ]
@@ -0,0 +1,154 @@
1
+ # Migration & Export
2
+
3
+ OKDB's migration feature handles export/import of all types and records as JSON, plus blob export/import for file storage, and blob integrity tools.
4
+
5
+ ---
6
+
7
+ ## Export
8
+
9
+ ```javascript
10
+ const data = await okdb.migrate.export();
11
+ ```
12
+
13
+ Returns an object:
14
+
15
+ ```javascript
16
+ {
17
+ types: {
18
+ users: {
19
+ entries: [
20
+ { key: 'alice', value: { name: 'Alice', role: 'admin' }, version: 3 },
21
+ { key: 'bob', value: { name: 'Bob', role: 'member' }, version: 1 },
22
+ ],
23
+ indexes: [...], // index definitions
24
+ ftsIndexes: {...}, // FTS index definitions
25
+ schema: {...}, // JSON Schema { definition, enforce } if set
26
+ },
27
+ orders: { entries: [...] },
28
+ },
29
+ meta: {}, // empty unless includeMeta: true
30
+ changes: [], // empty unless includeChangeLog: true
31
+ }
32
+ ```
33
+
34
+ **Indexes** are exported and restored on import. **JSON Schemas** (including foreign key `ref` annotations and `enforce` mode) are preserved across export/import. On import, schemas are applied after all data is loaded so `enforce: true` validation succeeds.
35
+
36
+ ### Options
37
+
38
+ ```javascript
39
+ const data = await okdb.migrate.export({
40
+ includeMeta: false, // include field schema metadata
41
+ includeChangeLog: false, // include the clock/change log entries
42
+ });
43
+ ```
44
+
45
+ ### Export to JSON string
46
+
47
+ ```javascript
48
+ const json = await okdb.migrate.exportJSON({ pretty: true });
49
+ fs.writeFileSync('./backup.json', json);
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Import
55
+
56
+ ```javascript
57
+ const data = JSON.parse(fs.readFileSync('./backup.json', 'utf8'));
58
+ await okdb.migrate.import(data);
59
+ ```
60
+
61
+ :::warning
62
+ Import **drops all existing types** before recreating them. This is a destructive operation. Back up your data first.
63
+ :::
64
+
65
+ Import recreates all types, populates records with their exact versions (preserving optimistic-concurrency state), and optionally restores the change log.
66
+
67
+ ### Import from JSON string
68
+
69
+ ```javascript
70
+ const json = fs.readFileSync('./backup.json', 'utf8');
71
+ await okdb.migrate.importJSON(json);
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Blob export / import
77
+
78
+ File blobs (from the [Files](./files.md) feature) are stored separately from the OKDB types. Exporting and importing blobs is a separate step:
79
+
80
+ ```javascript
81
+ // Export blobs to a target directory
82
+ const { count, bytes } = await okdb.migrate.exportBlobs('./backup-blobs');
83
+ console.log(`Exported ${count} blobs, ${bytes} bytes`);
84
+
85
+ // Import blobs from a source directory (skips blobs already present)
86
+ const { imported, skipped } = await okdb.migrate.importBlobs('./backup-blobs');
87
+ console.log(`Imported ${imported}, skipped ${skipped} already present`);
88
+ ```
89
+
90
+ The blob directory layout is preserved: `<dir>/<first2>/<rest>` (matching the SHA-256 hex filename structure).
91
+
92
+ ---
93
+
94
+ ## Blob integrity
95
+
96
+ Validate that blobs on disk match the `~files` metadata records:
97
+
98
+ ```javascript
99
+ const issues = await okdb.migrate.validateBlobIntegrity();
100
+
101
+ if (issues.length === 0) {
102
+ console.log('All blobs intact');
103
+ } else {
104
+ for (const issue of issues) {
105
+ console.warn(issue.type, issue.message);
106
+ }
107
+ }
108
+ ```
109
+
110
+ Issue types returned:
111
+
112
+ | Type | Description |
113
+ | -------------- | ------------------------------------------------------------------- |
114
+ | `missing_blob` | A `~files` record references a hash that has no blob on disk |
115
+ | `zero_refs` | A blob's ref-count is zero but a `~files` record still points to it |
116
+ | `orphan_blob` | A blob file on disk has no `~files` record in any environment |
117
+
118
+ ### Repair ref-counts
119
+
120
+ If ref-counts get out of sync (e.g. after a crash or manual blob manipulation), rebuild them from scratch:
121
+
122
+ ```javascript
123
+ const { rebuilt } = await okdb.migrate.repairBlobRefs();
124
+ console.log(`Rebuilt ref-counts for ${rebuilt} blobs`);
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Full backup workflow
130
+
131
+ ```javascript
132
+ // 1. Export type data
133
+ const json = await okdb.migrate.exportJSON({ pretty: false });
134
+ fs.writeFileSync('./backup/data.json', json);
135
+
136
+ // 2. Export blobs
137
+ await okdb.migrate.exportBlobs('./backup/blobs');
138
+
139
+ console.log('Backup complete');
140
+ ```
141
+
142
+ Restore:
143
+
144
+ ```javascript
145
+ // 1. Import type data
146
+ await okdb.migrate.importJSON(fs.readFileSync('./backup/data.json', 'utf8'));
147
+
148
+ // 2. Import blobs
149
+ await okdb.migrate.importBlobs('./backup/blobs');
150
+
151
+ // 3. Optional: verify integrity
152
+ const issues = await okdb.migrate.validateBlobIntegrity();
153
+ if (issues.length > 0) console.warn(issues);
154
+ ```