@bjornpagen/bumbledb 0.1.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 (108) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +84 -0
  3. package/dist/brand.d.ts +59 -0
  4. package/dist/brand.d.ts.map +1 -0
  5. package/dist/brand.js +47 -0
  6. package/dist/brand.js.map +1 -0
  7. package/dist/closed.d.ts +97 -0
  8. package/dist/closed.d.ts.map +1 -0
  9. package/dist/closed.js +107 -0
  10. package/dist/closed.js.map +1 -0
  11. package/dist/count.d.ts +55 -0
  12. package/dist/count.d.ts.map +1 -0
  13. package/dist/count.js +92 -0
  14. package/dist/count.js.map +1 -0
  15. package/dist/db.d.ts +341 -0
  16. package/dist/db.d.ts.map +1 -0
  17. package/dist/db.js +1016 -0
  18. package/dist/db.js.map +1 -0
  19. package/dist/exhume.d.ts +130 -0
  20. package/dist/exhume.d.ts.map +1 -0
  21. package/dist/exhume.js +145 -0
  22. package/dist/exhume.js.map +1 -0
  23. package/dist/face.d.ts +91 -0
  24. package/dist/face.d.ts.map +1 -0
  25. package/dist/face.js +69 -0
  26. package/dist/face.js.map +1 -0
  27. package/dist/fields.d.ts +187 -0
  28. package/dist/fields.d.ts.map +1 -0
  29. package/dist/fields.js +204 -0
  30. package/dist/fields.js.map +1 -0
  31. package/dist/index.d.ts +49 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +31 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/lower.d.ts +34 -0
  36. package/dist/lower.d.ts.map +1 -0
  37. package/dist/lower.js +105 -0
  38. package/dist/lower.js.map +1 -0
  39. package/dist/marshal.d.ts +79 -0
  40. package/dist/marshal.d.ts.map +1 -0
  41. package/dist/marshal.js +167 -0
  42. package/dist/marshal.js.map +1 -0
  43. package/dist/native.d.ts +532 -0
  44. package/dist/native.d.ts.map +1 -0
  45. package/dist/native.js +64 -0
  46. package/dist/native.js.map +1 -0
  47. package/dist/query/atom.d.ts +285 -0
  48. package/dist/query/atom.d.ts.map +1 -0
  49. package/dist/query/atom.js +281 -0
  50. package/dist/query/atom.js.map +1 -0
  51. package/dist/query/lower.d.ts +145 -0
  52. package/dist/query/lower.d.ts.map +1 -0
  53. package/dist/query/lower.js +604 -0
  54. package/dist/query/lower.js.map +1 -0
  55. package/dist/query/predicate.d.ts +101 -0
  56. package/dist/query/predicate.d.ts.map +1 -0
  57. package/dist/query/predicate.js +85 -0
  58. package/dist/query/predicate.js.map +1 -0
  59. package/dist/query/run.d.ts +30 -0
  60. package/dist/query/run.d.ts.map +1 -0
  61. package/dist/query/run.js +94 -0
  62. package/dist/query/run.js.map +1 -0
  63. package/dist/query/scope.d.ts +168 -0
  64. package/dist/query/scope.d.ts.map +1 -0
  65. package/dist/query/scope.js +134 -0
  66. package/dist/query/scope.js.map +1 -0
  67. package/dist/query/select.d.ts +106 -0
  68. package/dist/query/select.d.ts.map +1 -0
  69. package/dist/query/select.js +69 -0
  70. package/dist/query/select.js.map +1 -0
  71. package/dist/relation.d.ts +120 -0
  72. package/dist/relation.d.ts.map +1 -0
  73. package/dist/relation.js +108 -0
  74. package/dist/relation.js.map +1 -0
  75. package/dist/schema.d.ts +50 -0
  76. package/dist/schema.d.ts.map +1 -0
  77. package/dist/schema.js +235 -0
  78. package/dist/schema.js.map +1 -0
  79. package/dist/spec.d.ts +218 -0
  80. package/dist/spec.d.ts.map +1 -0
  81. package/dist/spec.js +154 -0
  82. package/dist/spec.js.map +1 -0
  83. package/dist/statements.d.ts +91 -0
  84. package/dist/statements.d.ts.map +1 -0
  85. package/dist/statements.js +101 -0
  86. package/dist/statements.js.map +1 -0
  87. package/package.json +66 -0
  88. package/src/brand.ts +82 -0
  89. package/src/closed.ts +228 -0
  90. package/src/count.ts +117 -0
  91. package/src/db.ts +1519 -0
  92. package/src/exhume.ts +243 -0
  93. package/src/face.ts +161 -0
  94. package/src/fields.ts +385 -0
  95. package/src/index.ts +185 -0
  96. package/src/lower.ts +118 -0
  97. package/src/marshal.ts +220 -0
  98. package/src/native.ts +576 -0
  99. package/src/query/atom.ts +556 -0
  100. package/src/query/lower.ts +855 -0
  101. package/src/query/predicate.ts +195 -0
  102. package/src/query/run.ts +106 -0
  103. package/src/query/scope.ts +301 -0
  104. package/src/query/select.ts +140 -0
  105. package/src/relation.ts +252 -0
  106. package/src/schema.ts +297 -0
  107. package/src/spec.ts +325 -0
  108. package/src/statements.ts +148 -0
package/src/native.ts ADDED
@@ -0,0 +1,576 @@
1
+ import { createRequire } from "node:module"
2
+ import * as errors from "@superbuilders/errors"
3
+ import type { SchemaSpec, ValueSpec, ValueTypeSpec } from "#spec.ts"
4
+
5
+ /**
6
+ * The complete typed surface of the bumbledb-node napi bridge. ALL FFI
7
+ * typing lives in this one file — no other module may know the `.node`
8
+ * artifact exists. The bridge is a dumb bridge (PRD-04): descriptor in as
9
+ * data, queries in as IR data, facts in/out as value rows, rejections out as
10
+ * structured violation sets; anything smart lives in the SDK or the engine.
11
+ *
12
+ * Marshaling law: fact rows cross as NATURAL JS values, schema-directed by
13
+ * the engine descriptor (`boolean ⇄ bool`, `bigint ⇄ u64/i64`,
14
+ * `string ⇄ str`, `Uint8Array ⇄ bytes<N>`, `{ start, end }` ⇄ interval);
15
+ * IR, spec, and query params cross as TAGGED plain objects mirroring the
16
+ * engine's own data enums 1:1. Every u64/i64 crosses as `bigint`, never
17
+ * `number`. Domain outcomes (schema errors, fingerprint mismatches,
18
+ * rejections, generation moves, IR errors) are DATA; marshaling/shape
19
+ * violations and use-after-close THROW.
20
+ */
21
+
22
+ /** The opaque database handle (owns the LMDB environment + exclusive lock). */
23
+ type DbHandle = { readonly __brand: "bumbledb.db" }
24
+
25
+ /** One live MVCC read snapshot. */
26
+ type SnapshotHandle = { readonly __brand: "bumbledb.snapshot" }
27
+
28
+ /**
29
+ * One exhumed store — the read-only, theory-less open (engine 70-api.md
30
+ * § exhume). No close function exists for this handle anywhere on the
31
+ * bridge (the zero-closables law): the engine side is dropped when the
32
+ * handle is garbage-collected — reclamation only, never correctness.
33
+ */
34
+ type ExhumeHandle = { readonly __brand: "bumbledb.exhume" }
35
+
36
+ /**
37
+ * One live write transaction — the submitted delta with the engine's
38
+ * final-state point-read view. Spent by `txCommit`/`txAbort`.
39
+ */
40
+ type TxHandle = { readonly __brand: "bumbledb.tx" }
41
+
42
+ /** One prepared query/program (plan pinned at prepare). */
43
+ type PreparedHandle = { readonly __brand: "bumbledb.prepared" }
44
+
45
+ /** A half-open interval `[start, end)` as it crosses the boundary. */
46
+ interface IntervalValue {
47
+ readonly start: bigint
48
+ readonly end: bigint
49
+ }
50
+
51
+ /**
52
+ * One fact-row cell as a natural JS value. The expected engine type comes
53
+ * from the schema descriptor (marshaling is schema-directed, never guessed):
54
+ * `boolean` for bool, `bigint` for u64/i64, `string` for str, `Uint8Array`
55
+ * for bytes<N> (width-checked), `{ start, end }` for intervals.
56
+ */
57
+ type FactValue = boolean | bigint | string | Uint8Array | IntervalValue
58
+
59
+ /**
60
+ * One tagged engine value — the 1:1 mirror of `bumbledb::Value` for the
61
+ * positions no schema field directs (IR literals, query params). The spec's
62
+ * `ValueSpec` vocabulary plus the bind-time-only Allen mask.
63
+ */
64
+ type TaggedValue = ValueSpec | { readonly kind: "allenMask"; readonly mask: number }
65
+
66
+ /**
67
+ * One positional execution argument: a tagged scalar, or a param SET
68
+ * (`Term.paramSet` positions) as `{ kind: "set", values }`.
69
+ */
70
+ type QueryParam = TaggedValue | { readonly kind: "set"; readonly values: readonly TaggedValue[] }
71
+
72
+ /**
73
+ * The IR mirror (`bumbledb::ir`, 1:1): relations, fields, predicates, and
74
+ * params by NUMERIC id — the SDK resolves names through the manifest and
75
+ * sends ids; the bridge never sees names in queries. A plain query is sent
76
+ * as its degenerate one-predicate program.
77
+ */
78
+ interface ProgramIr {
79
+ readonly predicates: readonly PredicateDefIr[]
80
+ readonly output: number
81
+ }
82
+
83
+ /** One predicate: the head shape its rules align against, and the rules. */
84
+ interface PredicateDefIr {
85
+ readonly head: readonly HeadTermIr[]
86
+ readonly rules: readonly RuleIr[]
87
+ }
88
+
89
+ /** One head position: a plain variable slot or an aggregate-op kind. */
90
+ type HeadTermIr = { readonly kind: "var" } | { readonly kind: "aggregate"; readonly op: HeadOpIr }
91
+
92
+ /** The var-free aggregate-op kind at a head position. */
93
+ type HeadOpIr = "sum" | "min" | "max" | "count" | "countDistinct" | "argMax" | "argMin" | "pack"
94
+
95
+ /** One rule: conjunctive body, anti-join atoms, condition trees. */
96
+ interface RuleIr {
97
+ readonly finds: readonly FindTermIr[]
98
+ readonly atoms: readonly AtomIr[]
99
+ readonly negated: readonly AtomIr[]
100
+ readonly conditions: readonly ConditionTreeIr[]
101
+ }
102
+
103
+ /** One find term (mirrors `ir::FindTerm`). */
104
+ type FindTermIr =
105
+ | { readonly kind: "var"; readonly var: number }
106
+ | { readonly kind: "aggregate"; readonly op: AggOpIr; readonly over?: number }
107
+ | { readonly kind: "measure"; readonly var: number }
108
+ | { readonly kind: "aggregateMeasure"; readonly op: AggOpIr; readonly over: number }
109
+
110
+ /** One aggregate operator (mirrors `ir::AggOp`; Arg ops carry their key). */
111
+ type AggOpIr =
112
+ | { readonly kind: "sum" }
113
+ | { readonly kind: "min" }
114
+ | { readonly kind: "max" }
115
+ | { readonly kind: "count" }
116
+ | { readonly kind: "countDistinct" }
117
+ | { readonly kind: "argMax"; readonly key: number }
118
+ | { readonly kind: "argMin"; readonly key: number }
119
+ | { readonly kind: "pack" }
120
+
121
+ /** Where an atom draws its facts: a stored relation or a program predicate. */
122
+ type AtomSourceIr =
123
+ | { readonly kind: "edb"; readonly relation: number }
124
+ | { readonly kind: "idb"; readonly pred: number }
125
+
126
+ /**
127
+ * One atom: named-field bindings as `[fieldId, term]` pairs; absence of a
128
+ * field is the wildcard.
129
+ */
130
+ interface AtomIr {
131
+ readonly source: AtomSourceIr
132
+ readonly bindings: ReadonlyArray<readonly [number, TermIr]>
133
+ }
134
+
135
+ /** One term of an atom binding or comparison (mirrors `ir::Term`). */
136
+ type TermIr =
137
+ | { readonly kind: "var"; readonly var: number }
138
+ | { readonly kind: "param"; readonly param: number }
139
+ | { readonly kind: "paramSet"; readonly param: number }
140
+ | { readonly kind: "literal"; readonly value: TaggedValue }
141
+ | { readonly kind: "measure"; readonly var: number }
142
+
143
+ /** The `Allen` comparison's mask position: a literal mask or a param. */
144
+ type MaskTermIr =
145
+ | { readonly kind: "literal"; readonly mask: number }
146
+ | { readonly kind: "param"; readonly param: number }
147
+
148
+ /** One comparison operator (mirrors `ir::CmpOp`). */
149
+ type CmpOpIr =
150
+ | { readonly kind: "eq" }
151
+ | { readonly kind: "ne" }
152
+ | { readonly kind: "lt" }
153
+ | { readonly kind: "le" }
154
+ | { readonly kind: "gt" }
155
+ | { readonly kind: "ge" }
156
+ | { readonly kind: "allen"; readonly mask: MaskTermIr }
157
+ | { readonly kind: "pointIn" }
158
+
159
+ /** One comparison condition. */
160
+ interface ComparisonIr {
161
+ readonly op: CmpOpIr
162
+ readonly lhs: TermIr
163
+ readonly rhs: TermIr
164
+ }
165
+
166
+ /**
167
+ * The input condition grammar: any boolean combination of comparisons
168
+ * (validation distributes to DNF engine-side).
169
+ */
170
+ type ConditionTreeIr =
171
+ | { readonly kind: "leaf"; readonly cmp: ComparisonIr }
172
+ | { readonly kind: "and"; readonly children: readonly ConditionTreeIr[] }
173
+ | { readonly kind: "or"; readonly children: readonly ConditionTreeIr[] }
174
+
175
+ /** A statement's form tag. */
176
+ type StatementKindTag = "functionality" | "containment" | "cardinality"
177
+
178
+ /** One field's name, dense id, and structural type. */
179
+ interface ManifestField {
180
+ readonly name: string
181
+ readonly id: number
182
+ readonly valueType: ValueTypeSpec
183
+ }
184
+
185
+ /**
186
+ * One closed-relation ground axiom as manifest data: handle →
187
+ * declaration-order id → (column, value) pairs.
188
+ */
189
+ interface ManifestRow {
190
+ readonly handle: string
191
+ readonly id: bigint
192
+ readonly values: ReadonlyArray<{ readonly name: string; readonly value: FactValue }>
193
+ }
194
+
195
+ /**
196
+ * One relation's names and ids; a closed relation's sealed field list opens
197
+ * with the synthetic (`id`, u64) handle field and carries its extension.
198
+ */
199
+ interface ManifestRelation {
200
+ readonly name: string
201
+ readonly id: number
202
+ readonly fields: readonly ManifestField[]
203
+ readonly extension?: readonly ManifestRow[]
204
+ }
205
+
206
+ /** One statement's identity, form tag, and canonical spelling. */
207
+ interface ManifestStatement {
208
+ readonly id: number
209
+ readonly kind: StatementKindTag
210
+ readonly spelling: string
211
+ }
212
+
213
+ /**
214
+ * The theory's manifest: every name → id pairing as plain data (PRD-02's
215
+ * tables, one JS object) — called once per open by the SDK.
216
+ */
217
+ interface Manifest {
218
+ readonly relations: readonly ManifestRelation[]
219
+ readonly statements: readonly ManifestStatement[]
220
+ }
221
+
222
+ /** One offending fact of a violation, decoded to named natural values. */
223
+ interface ViolationFact {
224
+ readonly relation: string
225
+ readonly fields: ReadonlyArray<{ readonly name: string; readonly value: FactValue }>
226
+ }
227
+
228
+ /**
229
+ * One violated statement of a rejected commit, rendered to plain data: the
230
+ * statement id (materialized order), form tag, CANONICAL spelling (the
231
+ * engine's one renderer — a bijection on legal statements, paste-back-able),
232
+ * the form's direction/count payloads, and the decoded offending facts.
233
+ */
234
+ interface Violation {
235
+ readonly statementId: number
236
+ readonly kind: StatementKindTag
237
+ readonly canonical: string
238
+ readonly direction?: "sourceUnsatisfied" | "targetRequired"
239
+ readonly count?: bigint
240
+ readonly facts: readonly ViolationFact[]
241
+ }
242
+
243
+ /**
244
+ * `dbCreate`/`dbOpen`'s domain outcome. `schemaError` covers both spec
245
+ * resolution (unresolvable names, banned spellings — every issue in one
246
+ * message) and schema validation at the declaration boundary;
247
+ * `fingerprintMismatch` is `dbOpen`'s stored-theory refusal.
248
+ */
249
+ type DbOpenResult =
250
+ | { readonly ok: true; readonly db: DbHandle }
251
+ | {
252
+ readonly ok: false
253
+ readonly kind: "schemaError" | "fingerprintMismatch"
254
+ readonly message: string
255
+ }
256
+
257
+ /**
258
+ * `dbExhume`'s domain outcome: the live exhume handle, or one of the three
259
+ * adoption-era refusals as data — `descriptorMissing` (the store predates
260
+ * self-describing stores and has not been adopted; the remedy is one
261
+ * fingerprint-matching `dbOpen` under the creating schema),
262
+ * `formatMismatch`, and `corruption` (the persisted descriptor fails its
263
+ * integrity gates). Genuine failures — a missing path, a held exclusive
264
+ * lock — throw.
265
+ */
266
+ type ExhumeResult =
267
+ | { readonly ok: true; readonly exhume: ExhumeHandle }
268
+ | {
269
+ readonly ok: false
270
+ readonly kind: "descriptorMissing" | "formatMismatch" | "corruption"
271
+ readonly message: string
272
+ }
273
+
274
+ /**
275
+ * `dbWriteFrom`'s domain outcome: the live witnessed transaction, or the
276
+ * typed stale-premise verdict (a state-changing commit landed after the
277
+ * witness snapshot; retry policy is host-side).
278
+ */
279
+ type WriteFromResult =
280
+ | { readonly ok: true; readonly tx: TxHandle }
281
+ | {
282
+ readonly ok: false
283
+ readonly kind: "generationMoved"
284
+ readonly witnessed: bigint
285
+ readonly current: bigint
286
+ }
287
+
288
+ /**
289
+ * `txCommit`'s domain outcome: the committed generation, or the COMPLETE
290
+ * violation set (every violated statement cited once, per direction for a
291
+ * containment, in materialized statement order).
292
+ */
293
+ type CommitResult =
294
+ | { readonly ok: true; readonly generation: bigint }
295
+ | { readonly ok: false; readonly violations: readonly Violation[] }
296
+
297
+ /** `dbPrepare`'s domain outcome (IR roster errors are data). */
298
+ type PrepareResult =
299
+ | { readonly ok: true; readonly prepared: PreparedHandle }
300
+ | { readonly ok: false; readonly kind: "irError"; readonly message: string }
301
+
302
+ /** One occurrence's plan drift (pinned vs live row counts). */
303
+ interface OccurrenceDrift {
304
+ readonly relation: number
305
+ readonly pinned: bigint
306
+ readonly live: bigint
307
+ readonly ratio: number
308
+ }
309
+
310
+ /**
311
+ * The pull-based plan-drift report: engine-policy-free — no threshold
312
+ * exists engine-side; the host owns reprepare policy.
313
+ */
314
+ interface Staleness {
315
+ readonly perOccurrence: readonly OccurrenceDrift[]
316
+ readonly maxRatio: number
317
+ }
318
+
319
+ interface Native {
320
+ /**
321
+ * Proof-of-life export (PRD-03): a non-empty string naming the bridge
322
+ * crate version and the engine's storage format version — evidence the
323
+ * cargo path dependency compiled, linked, and loaded through Node-API.
324
+ */
325
+ engineVersion(): string
326
+
327
+ /**
328
+ * Creates a fresh DURABLE store at `path` (frozen ruling 3: no ephemeral
329
+ * kind crosses this bridge). Refuses an already-initialized directory
330
+ * (throws); schema failures return as data.
331
+ */
332
+ dbCreate(path: string, spec: SchemaSpec): DbOpenResult
333
+ /**
334
+ * Opens an existing durable store, verifying format version, store
335
+ * kind, and schema fingerprint (`fingerprintMismatch` as data).
336
+ */
337
+ dbOpen(path: string, spec: SchemaSpec): DbOpenResult
338
+ /**
339
+ * Closes the handle. Dependent handles each hold the engine alive; the
340
+ * environment (and its exclusive lock) releases when the last closes.
341
+ */
342
+ dbClose(db: DbHandle): void
343
+ /** The PRD-02 manifest — every name → id table, one plain object. */
344
+ dbManifest(db: DbHandle): Manifest
345
+ /**
346
+ * The open store's schema fingerprint, 64 lowercase hex chars — the
347
+ * cross-host identity readback (`dbCreate` stored this exact value,
348
+ * `dbOpen` verified it). The engine computes; the bridge hex-encodes.
349
+ * Test-facing (the cross-host fingerprint lock); the SDK surface stays
350
+ * bijective with the Rust surface, which exposes no fingerprint
351
+ * accessor on `Db` — so no `Db` method wraps this.
352
+ */
353
+ dbFingerprint(db: DbHandle): string
354
+ /**
355
+ * The current committed generation — diagnostics only. The write-side
356
+ * witness is always the SNAPSHOT handle (`dbWriteFrom`), never this
357
+ * integer: an integer witness would be a claim a caller could fabricate
358
+ * or stale-cache (the engine's recorded refusal).
359
+ */
360
+ dbGeneration(db: DbHandle): bigint
361
+
362
+ /**
363
+ * Opens a store FROM ITS OWN PERSISTED DESCRIPTOR (the read-only,
364
+ * theory-less open; engine 70-api.md § exhume) — no schema crosses in.
365
+ * The three adoption-era refusals return as data ({@link ExhumeResult});
366
+ * genuine failures throw. The handle has no close anywhere on this
367
+ * bridge (zero closables): GC reclaims the engine side and releases the
368
+ * store's exclusive lock — reclamation only, never correctness.
369
+ */
370
+ dbExhume(path: string): ExhumeResult
371
+ /**
372
+ * The exhumed store's persisted schema as manifest-shaped data — the
373
+ * engine's own manifest rendering of the STORED descriptor: relations
374
+ * in engine-id order, sealed field lists (a closed relation opens with
375
+ * the synthetic (`id`, u64) handle field) with structural value types,
376
+ * and closed-relation rosters.
377
+ */
378
+ exhumeDescriptor(exhume: ExhumeHandle): Manifest
379
+ /**
380
+ * Full-relation export by NAME in row-id order, values marshaled per
381
+ * the STORED descriptor (str already resolved through `_dict` inside
382
+ * the engine; a closed relation scans its sealed roster). Each call is
383
+ * one self-contained snapshot read; an unknown relation name throws.
384
+ */
385
+ exhumeScan(exhume: ExhumeHandle, relationName: string): FactValue[][]
386
+
387
+ /** Opens one MVCC read snapshot as a live handle. */
388
+ dbSnapshot(db: DbHandle): SnapshotHandle
389
+ /** Closes the snapshot, releasing its LMDB reader slot. */
390
+ snapshotClose(snap: SnapshotHandle): void
391
+ /** Full-relation export in row-id order (one row per fact). */
392
+ snapshotScan(snap: SnapshotHandle, relationId: number): FactValue[][]
393
+ /** Committed-state membership of one fact (sealed field order). */
394
+ snapshotContains(snap: SnapshotHandle, relationId: number, values: readonly FactValue[]): boolean
395
+ /**
396
+ * Committed-state point lookup through a key statement (`keyValues` in
397
+ * the statement's projection order); `null` on a miss.
398
+ */
399
+ snapshotGet(
400
+ snap: SnapshotHandle,
401
+ relationId: number,
402
+ keyStatementId: number,
403
+ keyValues: readonly FactValue[]
404
+ ): FactValue[] | null
405
+
406
+ /**
407
+ * Begins a write transaction: the submitted delta. One write
408
+ * transaction may be open per db handle at a time (single-writer
409
+ * engine; a second begin throws rather than deadlocking the process).
410
+ */
411
+ dbWriteBegin(db: DbHandle): TxHandle
412
+ /**
413
+ * Begins a WITNESSED write transaction: commits only if no
414
+ * state-changing commit landed since `snap` was taken —
415
+ * `generationMoved` as data otherwise (the optimistic
416
+ * read-compute-write loop's entry; retry policy stays host-side).
417
+ */
418
+ dbWriteFrom(db: DbHandle, snap: SnapshotHandle): WriteFromResult
419
+ /**
420
+ * Records an insert into the delta; `true` iff the final state changed.
421
+ * Nothing is judged until commit; shape violations throw typed.
422
+ */
423
+ txInsert(tx: TxHandle, relationId: number, values: readonly FactValue[]): boolean
424
+ /** Records a delete into the delta; `true` iff the final state changed. */
425
+ txDelete(tx: TxHandle, relationId: number, values: readonly FactValue[]): boolean
426
+ /**
427
+ * Final-state membership (base + pending delta — the exact view the
428
+ * commit judgment judges; check-then-act is race-free by construction).
429
+ */
430
+ txContains(tx: TxHandle, relationId: number, values: readonly FactValue[]): boolean
431
+ /** Final-state point lookup through a key statement; `null` on a miss. */
432
+ txGet(tx: TxHandle, relationId: number, keyStatementId: number, keyValues: readonly FactValue[]): FactValue[] | null
433
+ /**
434
+ * Mints the next fresh value for `(relationId, fieldId)` and returns it
435
+ * — the engine's alloc-then-insert dyn-lane mint (there is no
436
+ * insert-with-omitted-fields spelling; include the minted id in the
437
+ * full row).
438
+ */
439
+ txAlloc(tx: TxHandle, relationId: number, fieldId: number): bigint
440
+ /**
441
+ * Commits the delta: every dependency statement judged against the
442
+ * final state; a rejection carries the complete violation rendering.
443
+ * The handle is spent either way.
444
+ */
445
+ txCommit(tx: TxHandle): CommitResult
446
+ /** Aborts the delta (LMDB was never touched). The handle is spent. */
447
+ txAbort(tx: TxHandle): void
448
+
449
+ /**
450
+ * Prepares a program (IR as data, ids only; plan pinned at prepare).
451
+ * Roster errors return as data.
452
+ */
453
+ dbPrepare(db: DbHandle, program: ProgramIr): PrepareResult
454
+ /**
455
+ * Executes against a snapshot with positional params. One-copy owned
456
+ * rows out, column order = the program's head order; answers are a set
457
+ * — the host sorts.
458
+ */
459
+ preparedExecute(prepared: PreparedHandle, snap: SnapshotHandle, params: readonly QueryParam[]): FactValue[][]
460
+ /** The pull-based plan-drift signal against a snapshot. */
461
+ preparedStaleness(prepared: PreparedHandle, snap: SnapshotHandle): Staleness
462
+ /** Releases the prepared query. */
463
+ preparedClose(prepared: PreparedHandle): void
464
+ }
465
+
466
+ /**
467
+ * The sole platform this release ships (PRD-03 ruling 1: prebuilt-only,
468
+ * darwin-arm64). The per-platform-package structure below makes adding
469
+ * `darwin-x64`/`linux-*`/`win32-*` pure addition — one more `os`/`cpu`-gated
470
+ * package plus a CI matrix — never a redesign, so this string is the only
471
+ * place the shipped set is named for the unsupported-platform message.
472
+ */
473
+ const SHIPPED_PLATFORMS = "darwin-arm64"
474
+
475
+ /**
476
+ * CommonJS require anchored to this module, the only mechanism ESM has for
477
+ * loading a Node-API addon without an experimental flag (static `import` of
478
+ * `.node` files still sits behind `--experimental-addon-modules` on Node 24).
479
+ * It resolves the per-platform binary package by name (see
480
+ * {@link loadNativeBinding}); the addon never crosses as a relative path.
481
+ * createRequire is the only unflagged Node-API addon loader in ESM, and this
482
+ * file is the package's single sanctioned FFI boundary
483
+ * (docs/road-to-1.0.0/prd-03-arch-split-packaging.md).
484
+ */
485
+ const requireNative = createRequire(import.meta.url)
486
+
487
+ /**
488
+ * Resolves and loads the native bridge from its per-platform binary package
489
+ * (`@bjornpagen/bumbledb-<platform>-<arch>`) — the Biome/esbuild/napi-rs
490
+ * pattern. npm/pnpm install ONLY the `optionalDependency` whose `os`/`cpu`
491
+ * match the host, so a matching host resolves the addon and every other host
492
+ * resolves nothing. The two failure modes are distinct and both typed:
493
+ *
494
+ * - the platform package is ABSENT (the expected state on any
495
+ * non-darwin-arm64 host, and on a foreign `platform`/`arch` passed under
496
+ * test) — an actionable unsupported-platform error naming the running
497
+ * `platform-arch` and the shipped set;
498
+ * - the platform package is PRESENT but its `bumbledb.node` will not load
499
+ * (a genuine ABI/corruption fault) — the wrapped loader error.
500
+ *
501
+ * Parameterized on `platform`/`arch` so the resolution law is exercised for
502
+ * foreign hosts as a unit, without spawning a foreign process.
503
+ */
504
+ function loadNativeBinding(platform: string, arch: string): Native {
505
+ const platformPackage = `@bjornpagen/bumbledb-${platform}-${arch}`
506
+
507
+ // Presence probe: the platform package's OWN manifest resolves iff the
508
+ // matching optional dependency was installed. Its absence is the
509
+ // expected, benign "unsupported platform" — never a corruption signal.
510
+ const present = errors.trySync(() => requireNative.resolve(`${platformPackage}/package.json`))
511
+ if (present.error) {
512
+ throw errors.wrap(
513
+ present.error,
514
+ `no native binary for ${platform}-${arch}: @bjornpagen/bumbledb ships ${SHIPPED_PLATFORMS} only`
515
+ )
516
+ }
517
+
518
+ // The package is present; load its addon (its `main` is `bumbledb.node`).
519
+ // A failure HERE is corruption or an ABI mismatch, not an absent platform.
520
+ const loaded = errors.trySync(() => requireNative(platformPackage))
521
+ if (loaded.error) {
522
+ throw errors.wrap(loaded.error, `load the ${platformPackage} native binary (package present but unloadable)`)
523
+ }
524
+ return loaded.data
525
+ }
526
+
527
+ /**
528
+ * The loaded bumbledb-node bridge for the running host. Import this object
529
+ * for every native call; the resolve-and-load happens once at module
530
+ * initialization and an absent or unloadable artifact fails fast here rather
531
+ * than at first use.
532
+ */
533
+ const native: Native = loadNativeBinding(process.platform, process.arch)
534
+
535
+ export type {
536
+ AggOpIr,
537
+ AtomIr,
538
+ AtomSourceIr,
539
+ CmpOpIr,
540
+ CommitResult,
541
+ ComparisonIr,
542
+ ConditionTreeIr,
543
+ DbHandle,
544
+ DbOpenResult,
545
+ ExhumeHandle,
546
+ ExhumeResult,
547
+ FactValue,
548
+ FindTermIr,
549
+ HeadOpIr,
550
+ HeadTermIr,
551
+ IntervalValue,
552
+ Manifest,
553
+ ManifestField,
554
+ ManifestRelation,
555
+ ManifestRow,
556
+ ManifestStatement,
557
+ MaskTermIr,
558
+ Native,
559
+ OccurrenceDrift,
560
+ PredicateDefIr,
561
+ PreparedHandle,
562
+ PrepareResult,
563
+ ProgramIr,
564
+ QueryParam,
565
+ RuleIr,
566
+ SnapshotHandle,
567
+ Staleness,
568
+ StatementKindTag,
569
+ TaggedValue,
570
+ TermIr,
571
+ TxHandle,
572
+ Violation,
573
+ ViolationFact,
574
+ WriteFromResult
575
+ }
576
+ export { loadNativeBinding, native }