@bjornpagen/bumbledb 0.14.0 → 0.15.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.
package/src/index.ts CHANGED
@@ -5,9 +5,8 @@
5
5
  * never declared: THE LAWS TYPE THE COLUMNS, `schema()` computing every
6
6
  * field's equivalence class FROM the statement list at both tiers), the
7
7
  * statement algebra with `schema()` and `SchemaSpec` lowering (PRD-06), the `Db`
8
- * runtime (exclusive-lock stores, transactions, typed violations, scoped
9
- * snapshot reads, one-shot `write`/`writeFrom` with `abandon` — PRD-07, zero
10
- * closables), the query surface (kysely-shaped:
8
+ * runtime (exclusive-lock stores, transactions, typed violations, callback
9
+ * instance reads, one-shot `write`/`writeFrom` with `abandon` — PRD-07), the query surface (kysely-shaped:
11
10
  * `query(S).rule(r => { const { id, name } = v(Holder); return r.match(Holder, { id, name }).find({ name }) })` —
12
11
  * variables minted by `v()` and joined by OBJECT REFERENCE (reuse is the
13
12
  * join), the head a `find` RECORD whose keys name the answer columns
@@ -17,10 +16,7 @@
17
16
  * `db.prepare` as a plain value; the comparison/connective builders are
18
17
  * also free exports, and the free names `eq`/`not`/`and`/`or` collide with
19
18
  * common host identifiers — import aliasing is the answer; the SDK does
20
- * not rename for collision-avoidance), the exhume surface
21
- * (`Db.exhume` — the one schema-independent read path: the store's
22
- * self-described shapes and raw facts by name, typed at bare structural
23
- * values, deliberately schema-free). The raw native bridge is not exported.
19
+ * not rename for collision-avoidance). The raw native bridge is not exported.
24
20
  */
25
21
 
26
22
  export type {
@@ -51,7 +47,9 @@ export { closed } from "#closed.ts"
51
47
  export type {
52
48
  Abandon,
53
49
  AbandonedArm,
50
+ Admission,
54
51
  CapacityViolation,
52
+ Committed,
55
53
  ContainmentViolation,
56
54
  DeclaredKeyFact,
57
55
  DeclaredKeyViolation,
@@ -62,26 +60,31 @@ export type {
62
60
  MirrorViolation,
63
61
  MutationReport,
64
62
  OffendingFact,
63
+ OwnedInstance,
65
64
  Prepared,
66
- ReadScope,
65
+ ReadInstance,
66
+ SyncResult,
67
67
  Tx,
68
68
  Violation,
69
- WriteResult
69
+ Witness,
70
+ WriteFromOutcome,
71
+ WriteOutcome,
72
+ WriteTx
70
73
  } from "#db.ts"
71
- export { abandon, Db, ErrGenerationMoved, ErrNewtypeMismatch } from "#db.ts"
72
- export type {
73
- Exhumed,
74
- ExhumedAxiom,
75
- ExhumedDescriptor,
76
- ExhumedFact,
77
- ExhumedField,
78
- ExhumedRelation
79
- } from "#exhume.ts"
80
74
  export {
81
- ErrExhumeCorruption,
82
- ErrExhumeFormatMismatch,
83
- ErrExhumeNoDescriptor
84
- } from "#exhume.ts"
75
+ abandon,
76
+ Db,
77
+ ErrAsyncCallback,
78
+ ErrForeignPrepared,
79
+ ErrForeignWitness,
80
+ ErrFingerprintMismatch,
81
+ ErrIrError,
82
+ ErrNewtypeMismatch,
83
+ ErrSchemaError,
84
+ ErrSpentHandle,
85
+ ErrUseAfterScope,
86
+ InstanceBuilder
87
+ } from "#db.ts"
85
88
  export type {
86
89
  AnyFace,
87
90
  Arity,
package/src/native.ts CHANGED
@@ -22,22 +22,21 @@ import type { SchemaSpec, ValueSpec, ValueTypeSpec } from "#spec.ts"
22
22
  /** The opaque database handle (owns the LMDB environment + exclusive lock). */
23
23
  type DbHandle = { readonly __brand: "bumbledb.db" }
24
24
 
25
- /** One live MVCC read snapshot. */
26
- type SnapshotHandle = { readonly __brand: "bumbledb.snapshot" }
25
+ /** One live borrowed instance valid only inside a read callback. */
26
+ type InstanceHandle = { readonly __brand: "bumbledb.instance" }
27
27
 
28
- /**
29
- * One exhumed store — the read-only, theory-less open (engine 70-api.md
30
- * § exhume). Lifetimes are disposables (ruled 2026-07-23, R12):
31
- * `exhumeClose` is the deterministic teardown the SDK's `Symbol.dispose`
32
- * rides — releasing the environment (and the store's exclusive lock)
33
- * scope-shaped, never a GC race; the engine-side drop remains the
34
- * reclamation-only backstop for a collected-but-undisposed handle.
35
- */
36
- type ExhumeHandle = { readonly __brand: "bumbledb.exhume" }
28
+ /** One cloneable generation witness. May outlive the read that minted it. */
29
+ type WitnessHandle = { readonly __brand: "bumbledb.witness" }
30
+
31
+ /** One unproved heap builder. Spent by `instanceBuilderAdmit` / close. */
32
+ type BuilderHandle = { readonly __brand: "bumbledb.builder" }
33
+
34
+ /** One admitted heap instance. */
35
+ type OwnedHandle = { readonly __brand: "bumbledb.owned" }
37
36
 
38
37
  /**
39
38
  * One live write transaction — the submitted delta with the engine's
40
- * final-state point-read view. Spent by `txCommit`/`txAbort`.
39
+ * final-state point-read view. Valid only inside a write callback.
41
40
  */
42
41
  type TxHandle = { readonly __brand: "bumbledb.tx" }
43
42
 
@@ -56,7 +55,8 @@ interface WireMutationReport {
56
55
  /**
57
56
  * Engine fresh-id range as it crosses napi. Empty cannot yield a start —
58
57
  * `start` is a minted id only on the nonempty arm. (C wires empty as
59
- * `{ start: 0, end_exclusive: 0 }` at that boundary only.)
58
+ * `BDB_FRESH_RANGE_TAG_EMPTY`. The JS wire is `{ empty: true }`, not that
59
+ * C sentinel.)
60
60
  */
61
61
  type WireFreshRange =
62
62
  | { readonly empty: true }
@@ -295,14 +295,22 @@ type Violation =
295
295
  }
296
296
 
297
297
  /**
298
- * `dbCreate`/`dbOpen`'s domain outcome. `schemaError` spans both spec
298
+ * `dbCreate`'s domain outcome. Admission is `accepted` / `rejected`.
299
+ * Declaration-boundary refusals ride as their own tags (not theory
300
+ * admission) and the SDK throws them.
301
+ */
302
+ type CreateResult =
303
+ | { readonly tag: "accepted"; readonly db: DbHandle }
304
+ | { readonly tag: "rejected"; readonly violations: readonly Violation[] }
305
+ | { readonly tag: "schemaError"; readonly message: string }
306
+ | { readonly tag: "newtypeMismatch"; readonly message: string }
307
+
308
+ /**
309
+ * `dbOpen`'s domain outcome. `schemaError` spans both spec
299
310
  * resolution (unresolvable names, banned spellings — every issue in one
300
311
  * message) and schema validation at the declaration boundary;
301
- * `newtypeMismatch` is the coherence wall's own kind — a spec whose
302
- * statement pairs faces with disagreeing newtype labels (the engine twin
303
- * of the schema-level class wall; unreachable through the typed builder,
304
- * which computes every label from the laws, so only a raw spec can reach
305
- * it); `fingerprintMismatch` is `dbOpen`'s stored-theory refusal.
312
+ * `newtypeMismatch` is the coherence wall's own kind; `fingerprintMismatch`
313
+ * is `dbOpen`'s stored-theory refusal.
306
314
  */
307
315
  type DbOpenResult =
308
316
  | { readonly ok: true; readonly db: DbHandle }
@@ -313,46 +321,23 @@ type DbOpenResult =
313
321
  }
314
322
 
315
323
  /**
316
- * `dbExhume`'s domain outcome: the live exhume handle, or one of the three
317
- * adoption-era refusals as data — `descriptorMissing` (the store predates
318
- * self-describing stores and has not been adopted; the remedy is one
319
- * fingerprint-matching `dbOpen` under the creating schema),
320
- * `formatMismatch`, and `corruption` (the persisted descriptor fails its
321
- * integrity gates). Genuine failures — a missing path, a held exclusive
322
- * lock — throw.
324
+ * `dbWrite` / `dbWriteFrom` native outcome. The SDK attaches the callback
325
+ * return onto the accepted arm. Moved is data, never an error kind.
323
326
  */
324
- type ExhumeResult =
325
- | { readonly ok: true; readonly exhume: ExhumeHandle }
326
- | {
327
- readonly ok: false
328
- readonly kind: "descriptorMissing" | "formatMismatch" | "corruption"
329
- readonly message: string
330
- }
327
+ type NativeWriteOutcome =
328
+ | { readonly tag: "accepted"; readonly generation: bigint }
329
+ | { readonly tag: "rejected"; readonly violations: readonly Violation[] }
330
+ | { readonly tag: "abandoned" }
331
+ | { readonly tag: "moved"; readonly witnessed: bigint; readonly current: bigint }
331
332
 
332
333
  /**
333
- * `dbWriteFrom`'s domain outcome: the live witnessed transaction, or the
334
- * typed stale-premise verdict (a state-changing commit landed after the
335
- * witness snapshot; retry policy is host-side).
334
+ * Builder `admit` native outcome.
336
335
  */
337
- type WriteFromResult =
338
- | { readonly ok: true; readonly tx: TxHandle }
339
- | {
340
- readonly ok: false
341
- readonly kind: "generationMoved"
342
- readonly witnessed: bigint
343
- readonly current: bigint
344
- }
336
+ type AdmitResult =
337
+ | { readonly tag: "accepted"; readonly value: OwnedHandle }
338
+ | { readonly tag: "rejected"; readonly violations: readonly Violation[] }
345
339
 
346
- /**
347
- * `txCommit`'s domain outcome: the committed generation, or the COMPLETE
348
- * violation set (every violated statement cited once, per direction for a
349
- * containment, in materialized statement order).
350
- */
351
- type CommitResult =
352
- | { readonly ok: true; readonly generation: bigint }
353
- | { readonly ok: false; readonly violations: readonly Violation[] }
354
-
355
- /** `dbPrepare`'s domain outcome (IR roster errors are data). */
340
+ /** `dbPrepare`/`instancePrepare`'s domain outcome (IR roster errors are data). */
356
341
  type PrepareResult =
357
342
  | { readonly ok: true; readonly prepared: PreparedHandle }
358
343
  | { readonly ok: false; readonly kind: "irError"; readonly message: string }
@@ -374,13 +359,37 @@ interface Staleness {
374
359
  readonly maxRatio: number
375
360
  }
376
361
 
377
- /**
378
- * `dbSnapshot`'s reply: the live handle WITH its witnessed generation —
379
- * one crossing carries both (read inside the snapshot's own transaction,
380
- * the race-closing rule of 50-storage.md), so no second `dbGeneration`
381
- * call exists to pay or defend (finding 016's bridge shape).
382
- */
383
- type SnapshotOpened = { readonly ok: true; readonly snapshot: SnapshotHandle; readonly generation: bigint }
362
+ type ErrorFamilyKind =
363
+ | "formatMismatch"
364
+ | "schemaMismatch"
365
+ | "alreadyInitialized"
366
+ | "destinationExists"
367
+ | "publishedButUnsynced"
368
+ | "environmentLocked"
369
+ | "io"
370
+ | "lmdb"
371
+ | "readersFull"
372
+ | "schema"
373
+ | "validation"
374
+ | "factShape"
375
+ | "freshExhausted"
376
+ | "closedRelationWrite"
377
+ | "commitSync"
378
+ | "transactionPoisoned"
379
+ | "foreignPrepared"
380
+ | "foreignWitness"
381
+ | "param"
382
+ | "measureOfRay"
383
+ | "capacityRayMeasure"
384
+ | "derivedBudgetExceeded"
385
+ | "overflow"
386
+ | "resultBytesOverflow"
387
+ | "corruption"
388
+
389
+ type AdmissionTag = "accepted" | "rejected"
390
+ type WriteTag = "accepted" | "rejected" | "abandoned" | "moved"
391
+ type OpenKind = "schemaError" | "newtypeMismatch" | "fingerprintMismatch"
392
+ type PrepareKind = "irError"
384
393
 
385
394
  /**
386
395
  * The plan-as-data report (ruled 2026-07-23, R13): the engine's
@@ -411,16 +420,15 @@ interface Native {
411
420
  engineVersion(): string
412
421
 
413
422
  /**
414
- * Creates a fresh DURABLE store at `path` (frozen ruling 3: no ephemeral
415
- * kind crosses this bridge). Refuses an already-initialized directory
416
- * (throws); schema failures return as data.
423
+ * Creates a fresh durable store at `path`. Refuses an already-initialized
424
+ * directory (throws); schema failures return as data.
417
425
  */
418
- dbCreate(path: string, spec: SchemaSpec): DbOpenResult
426
+ dbCreate(path: string, spec: SchemaSpec): Promise<CreateResult>
419
427
  /**
420
- * Opens an existing durable store, verifying format version, store
421
- * kind, and schema fingerprint (`fingerprintMismatch` as data).
428
+ * Opens an existing durable store, verifying format version and
429
+ * schema fingerprint (`fingerprintMismatch` as data).
422
430
  */
423
- dbOpen(path: string, spec: SchemaSpec): DbOpenResult
431
+ dbOpen(path: string, spec: SchemaSpec): Promise<DbOpenResult>
424
432
  /**
425
433
  * Closes the handle. Dependent handles each hold the engine alive; the
426
434
  * environment (and its exclusive lock) releases when the last closes.
@@ -439,80 +447,40 @@ interface Native {
439
447
  dbFingerprint(db: DbHandle): string
440
448
  /**
441
449
  * The current committed generation — diagnostics only. The write-side
442
- * witness is always the SNAPSHOT handle (`dbWriteFrom`), never this
443
- * integer: an integer witness would be a claim a caller could fabricate
444
- * or stale-cache (the engine's recorded refusal).
450
+ * witness is always a {@link WitnessHandle}, never this integer.
445
451
  */
446
452
  dbGeneration(db: DbHandle): bigint
453
+ /** Publishes an admitted heap instance at `path` without re-judgment. */
454
+ dbFromInstance(path: string, instance: OwnedHandle): Promise<DbHandle>
447
455
 
448
456
  /**
449
- * Opens a store FROM ITS OWN PERSISTED DESCRIPTOR (the read-only,
450
- * theory-less open; engine 70-api.md § exhume) — no schema crosses in.
451
- * The three adoption-era refusals return as data ({@link ExhumeResult});
452
- * genuine failures throw. The handle's deterministic teardown is
453
- * `exhumeClose` (R12); GC reclamation remains the backstop only.
454
- */
455
- dbExhume(path: string): ExhumeResult
456
- /**
457
- * Closes the exhume handle, releasing its environment (and the store's
458
- * exclusive lock) deterministically — the native teardown under the
459
- * SDK's `Symbol.dispose` (ruled 2026-07-23, R12: lifetimes are
460
- * disposables, never `close()` methods to remember).
461
- */
462
- exhumeClose(exhume: ExhumeHandle): void
463
- /**
464
- * The exhumed store's persisted schema as manifest-shaped data — the
465
- * engine's own manifest rendering of the STORED descriptor: relations
466
- * in engine-id order, sealed field lists (a closed relation opens with
467
- * the synthetic (`id`, u64) handle field) with structural value types,
468
- * and closed-relation rosters.
457
+ * Runs `callback` synchronously inside the engine read lease. The
458
+ * instance handle is invalid after the callback returns; the witness
459
+ * handle is a clone and may escape.
469
460
  */
470
- exhumeDescriptor(exhume: ExhumeHandle): Manifest
471
- /**
472
- * Full-relation export by NAME in row-id order, values marshaled per
473
- * the STORED descriptor (str already resolved through `_dict` inside
474
- * the engine; a closed relation scans its sealed roster). Each call is
475
- * one self-contained snapshot read; an unknown relation name throws.
476
- */
477
- exhumeScan(exhume: ExhumeHandle, relationName: string): FactValue[][]
478
-
479
- /**
480
- * Opens one MVCC read snapshot as a live handle, returned WITH its
481
- * witnessed generation — one crossing carries both (finding 016), so
482
- * no separate `dbGeneration` call (with its own transient read
483
- * transaction and fault-pairing close branch) exists on this path.
484
- */
485
- dbSnapshot(db: DbHandle): SnapshotOpened
486
- /** Closes the snapshot, releasing its LMDB reader slot. */
487
- snapshotClose(snap: SnapshotHandle): void
488
- /** Full-relation export in row-id order (one row per fact). */
489
- snapshotScan(snap: SnapshotHandle, relationId: number): FactValue[][]
490
- /** Committed-state membership of one fact (sealed field order). */
491
- snapshotContains(snap: SnapshotHandle, relationId: number, values: readonly FactValue[]): boolean
492
- /**
493
- * Committed-state point lookup through a key statement (`keyValues` in
494
- * the statement's projection order); `null` on a miss.
495
- */
496
- snapshotGet(
497
- snap: SnapshotHandle,
461
+ dbRead<R>(db: DbHandle, callback: (instance: InstanceHandle, witness: WitnessHandle) => R): R
462
+ instanceGeneration(instance: InstanceHandle): bigint
463
+ instanceScan(instance: InstanceHandle, relationId: number): FactValue[][]
464
+ instanceContains(instance: InstanceHandle, relationId: number, values: readonly FactValue[]): boolean
465
+ instanceGet(
466
+ instance: InstanceHandle,
498
467
  relationId: number,
499
468
  keyStatementId: number,
500
469
  keyValues: readonly FactValue[]
501
470
  ): FactValue[] | null
471
+ instancePrepare(instance: InstanceHandle, query: ParsedQuery): PrepareResult
472
+ witnessClose(witness: WitnessHandle): void
502
473
 
503
474
  /**
504
- * Begins a write transaction: the submitted delta. One write
505
- * transaction may be open per db handle at a time (single-writer
506
- * engine; a second begin throws rather than deadlocking the process).
475
+ * Runs `callback` synchronously inside the engine write region.
476
+ * Return `true` to commit, `false` to abandon. Nested writes throw.
507
477
  */
508
- dbWriteBegin(db: DbHandle): TxHandle
478
+ dbWrite(db: DbHandle, callback: (tx: TxHandle) => boolean): NativeWriteOutcome
509
479
  /**
510
- * Begins a WITNESSED write transaction: commits only if no
511
- * state-changing commit landed since `snap` was taken —
512
- * `generationMoved` as data otherwise (the optimistic
513
- * read-compute-write loop's entry; retry policy stays host-side).
480
+ * Witnessed write: `moved` is data when the store advanced since the
481
+ * witness was minted. The callback does not run on that arm.
514
482
  */
515
- dbWriteFrom(db: DbHandle, snap: SnapshotHandle): WriteFromResult
483
+ dbWriteFrom(db: DbHandle, witness: WitnessHandle, callback: (tx: TxHandle) => boolean): NativeWriteOutcome
516
484
  /**
517
485
  * Records a collection of inserts into the delta; returns the engine
518
486
  * `{ submitted, changed }` report. `rows` is an array of value-arrays
@@ -520,6 +488,16 @@ interface Native {
520
488
  * is observed). Nothing is judged until commit; shape violations throw typed.
521
489
  */
522
490
  txInsert(tx: TxHandle, relationId: number, rows: readonly (readonly FactValue[])[]): WireMutationReport
491
+ /**
492
+ * Records a collection of inserts from per-column arrays in sealed
493
+ * field order — the column transport, same parse-all-first batch as
494
+ * {@link Native.txInsert}.
495
+ */
496
+ txInsertColumns(
497
+ tx: TxHandle,
498
+ relationId: number,
499
+ columns: readonly (readonly FactValue[])[]
500
+ ): WireMutationReport
523
501
  /** Records a collection of deletes; returns the engine `{ submitted, changed }` report. */
524
502
  txDelete(tx: TxHandle, relationId: number, rows: readonly (readonly FactValue[])[]): WireMutationReport
525
503
  /**
@@ -534,14 +512,6 @@ interface Native {
534
512
  * `count === 0n` is empty and does not yield a start.
535
513
  */
536
514
  txReserve(tx: TxHandle, relationId: number, fieldId: number, count: bigint): WireFreshRange
537
- /**
538
- * Commits the delta: every dependency statement judged against the
539
- * final state; a rejection carries the complete violation rendering.
540
- * The handle is spent either way.
541
- */
542
- txCommit(tx: TxHandle): CommitResult
543
- /** Aborts the delta (LMDB was never touched). The handle is spent. */
544
- txAbort(tx: TxHandle): void
545
515
 
546
516
  /**
547
517
  * Prepares a query (IR as data, ids only; plan pinned at prepare).
@@ -549,24 +519,64 @@ interface Native {
549
519
  */
550
520
  dbPrepare(db: DbHandle, query: ParsedQuery): PrepareResult
551
521
  /**
552
- * Executes against a snapshot with positional params. One-copy owned
522
+ * Executes against a live instance with positional params. One-copy owned
553
523
  * rows out, column order = the query's head order; answers are a set
554
524
  * — the host sorts.
555
525
  */
556
- preparedExecute(prepared: PreparedHandle, snap: SnapshotHandle, params: readonly QueryParam[]): FactValue[][]
526
+ preparedExecute(prepared: PreparedHandle, instance: InstanceHandle, params: readonly QueryParam[]): FactValue[][]
557
527
  /**
558
528
  * Plan introspection as data (ruled 2026-07-23, R13): runs the prepared
559
- * query against the snapshot with counting instrumentation (the
560
- * engine's `Snapshot::profile`, ANALYZE semantics) and returns the
561
- * structured stats — plan sections and counters as plain values.
562
- * Scalar params only (the engine's profile entry has no param-set
563
- * spelling).
529
+ * query against a store read with counting instrumentation and returns
530
+ * the structured stats. Store-read only.
564
531
  */
565
- preparedExplain(prepared: PreparedHandle, snap: SnapshotHandle, params: readonly QueryParam[]): Explain
566
- /** The pull-based plan-drift signal against a snapshot. */
567
- preparedStaleness(prepared: PreparedHandle, snap: SnapshotHandle): Staleness
532
+ preparedExplain(prepared: PreparedHandle, instance: InstanceHandle, params: readonly QueryParam[]): Explain
533
+ /** The pull-based plan-drift signal against a store read. */
534
+ preparedStaleness(prepared: PreparedHandle, instance: InstanceHandle): Staleness
568
535
  /** Releases the prepared query. */
569
536
  preparedClose(prepared: PreparedHandle): void
537
+
538
+ instanceBuilderNew(spec: SchemaSpec): BuilderHandle
539
+ instanceBuilderLoad(
540
+ builder: BuilderHandle,
541
+ relationId: number,
542
+ rows: readonly (readonly FactValue[])[]
543
+ ): WireMutationReport
544
+ instanceBuilderLoadColumns(
545
+ builder: BuilderHandle,
546
+ relationId: number,
547
+ columns: readonly (readonly FactValue[])[]
548
+ ): WireMutationReport
549
+ instanceBuilderDelete(
550
+ builder: BuilderHandle,
551
+ relationId: number,
552
+ rows: readonly (readonly FactValue[])[]
553
+ ): WireMutationReport
554
+ instanceBuilderReserve(
555
+ builder: BuilderHandle,
556
+ relationId: number,
557
+ fieldId: number,
558
+ count: bigint
559
+ ): WireFreshRange
560
+ instanceBuilderContains(builder: BuilderHandle, relationId: number, values: readonly FactValue[]): boolean
561
+ instanceBuilderGet(
562
+ builder: BuilderHandle,
563
+ relationId: number,
564
+ keyStatementId: number,
565
+ keyValues: readonly FactValue[]
566
+ ): FactValue[] | null
567
+ instanceBuilderClose(builder: BuilderHandle): void
568
+ instanceBuilderAdmit(builder: BuilderHandle): Promise<AdmitResult>
569
+ ownedInstanceClose(instance: OwnedHandle): void
570
+ ownedScan(instance: OwnedHandle, relationId: number): FactValue[][]
571
+ ownedContains(instance: OwnedHandle, relationId: number, values: readonly FactValue[]): boolean
572
+ ownedGet(
573
+ instance: OwnedHandle,
574
+ relationId: number,
575
+ keyStatementId: number,
576
+ keyValues: readonly FactValue[]
577
+ ): FactValue[] | null
578
+ ownedPrepare(instance: OwnedHandle, query: ParsedQuery): PrepareResult
579
+ ownedExecute(prepared: PreparedHandle, instance: OwnedHandle, params: readonly QueryParam[]): FactValue[][]
570
580
  }
571
581
 
572
582
  /**
@@ -643,37 +653,79 @@ function loadNativeBinding(platform: string, arch: string): Native {
643
653
  const native: Native = loadNativeBinding(process.platform, process.arch)
644
654
 
645
655
  /**
646
- * The bridge guard — THE one wrapper every native call crosses (db.ts and
647
- * exhume.ts both import it): runs one native call and wraps anything it
656
+ * Engine throw identity: a real `Error` carrying `kind` from the
657
+ * `ErrorFamily` table, or a leftover `{ kind, message }` object.
658
+ */
659
+ function isEngineThrow(value: unknown): value is { kind: ErrorFamilyKind; message: string } {
660
+ if (typeof value !== "object" || value === null) {
661
+ return false
662
+ }
663
+ const rec = value as { kind?: unknown; message?: unknown }
664
+ return typeof rec.kind === "string" && typeof rec.message === "string"
665
+ }
666
+
667
+ function errorFromThrow(caught: unknown): Error {
668
+ if (caught instanceof Error) {
669
+ return caught
670
+ }
671
+ if (isEngineThrow(caught)) {
672
+ const error = errors.new(`bumbledb ${caught.kind}: ${caught.message}`)
673
+ Object.defineProperty(error, "kind", { value: caught.kind, enumerable: true })
674
+ return error
675
+ }
676
+ return errors.new(String(caught))
677
+ }
678
+
679
+ /**
680
+ * The bridge guard — THE one wrapper every native call crosses (db.ts
681
+ * imports it): runs one native call and wraps anything it
648
682
  * throws, so marshal-shape refusals and handle-lifecycle refusals cross as
649
- * genuine typed failures, never bare foreign errors.
683
+ * genuine typed failures, never bare foreign errors. Engine throws keep
684
+ * their forced kind.
650
685
  */
651
686
  function bridged<T>(context: string, run: () => T): T {
652
- const result = errors.trySync(run)
653
- if (result.error) {
654
- throw errors.wrap(result.error, context)
687
+ try {
688
+ return run()
689
+ } catch (caught) {
690
+ const inner = errorFromThrow(caught)
691
+ throw errors.wrap(inner, `${context}: ${inner.message}`)
692
+ }
693
+ }
694
+
695
+ /**
696
+ * The async twin of {@link bridged}: every control-plane native is an
697
+ * `AsyncTask` Promise, and this is the one wrapper those awaits cross.
698
+ */
699
+ async function bridgedAsync<T>(context: string, run: () => Promise<T>): Promise<T> {
700
+ try {
701
+ return await run()
702
+ } catch (caught) {
703
+ const inner = errorFromThrow(caught)
704
+ throw errors.wrap(inner, `${context}: ${inner.message}`)
655
705
  }
656
- return result.data
657
706
  }
658
707
 
659
708
  export type {
709
+ AdmissionTag,
710
+ AdmitResult,
660
711
  AggOpIr,
661
712
  AtomIr,
662
713
  AtomSourceIr,
714
+ BuilderHandle,
663
715
  CmpOpIr,
664
- CommitResult,
665
716
  ComparisonIr,
666
717
  ConditionTreeIr,
718
+ CreateResult,
667
719
  DbHandle,
668
720
  DbOpenResult,
669
- ExhumeHandle,
670
- ExhumeResult,
721
+ ErrorFamilyKind,
671
722
  Explain,
672
723
  FactValue,
673
724
  FindTermIr,
674
725
  FoldOpIr,
675
726
  HeadOpIr,
676
727
  HeadTermIr,
728
+ InstanceHandle,
677
729
  InteriorIr,
678
730
  IntervalValue,
679
731
  Manifest,
@@ -682,16 +734,18 @@ export type {
682
734
  ManifestRow,
683
735
  ManifestStatement,
684
736
  Native,
737
+ NativeWriteOutcome,
685
738
  OccurrenceDrift,
739
+ OpenKind,
740
+ OwnedHandle,
686
741
  ParsedQuery,
687
742
  PreparedHandle,
743
+ PrepareKind,
688
744
  PrepareResult,
689
745
  QueryIr,
690
746
  QueryParam,
691
747
  RecIr,
692
748
  RuleIr,
693
- SnapshotHandle,
694
- SnapshotOpened,
695
749
  Staleness,
696
750
  StatementKindTag,
697
751
  TaggedValue,
@@ -701,6 +755,7 @@ export type {
701
755
  ViolationFact,
702
756
  WireFreshRange,
703
757
  WireMutationReport,
704
- WriteFromResult
758
+ WitnessHandle,
759
+ WriteTag
705
760
  }
706
- export { bridged, loadNativeBinding, native, SHIPPED_PLATFORMS }
761
+ export { bridged, bridgedAsync, errorFromThrow, loadNativeBinding, native, SHIPPED_PLATFORMS }