@noy-db/hub 0.1.0-pre.3
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/LICENSE +21 -0
- package/README.md +197 -0
- package/dist/aggregate/index.cjs +476 -0
- package/dist/aggregate/index.cjs.map +1 -0
- package/dist/aggregate/index.d.cts +38 -0
- package/dist/aggregate/index.d.ts +38 -0
- package/dist/aggregate/index.js +53 -0
- package/dist/aggregate/index.js.map +1 -0
- package/dist/blobs/index.cjs +1480 -0
- package/dist/blobs/index.cjs.map +1 -0
- package/dist/blobs/index.d.cts +45 -0
- package/dist/blobs/index.d.ts +45 -0
- package/dist/blobs/index.js +48 -0
- package/dist/blobs/index.js.map +1 -0
- package/dist/bundle/index.cjs +436 -0
- package/dist/bundle/index.cjs.map +1 -0
- package/dist/bundle/index.d.cts +7 -0
- package/dist/bundle/index.d.ts +7 -0
- package/dist/bundle/index.js +40 -0
- package/dist/bundle/index.js.map +1 -0
- package/dist/chunk-2QR2PQTT.js +217 -0
- package/dist/chunk-2QR2PQTT.js.map +1 -0
- package/dist/chunk-4OWFYIDQ.js +79 -0
- package/dist/chunk-4OWFYIDQ.js.map +1 -0
- package/dist/chunk-5AATM2M2.js +90 -0
- package/dist/chunk-5AATM2M2.js.map +1 -0
- package/dist/chunk-ACLDOTNQ.js +543 -0
- package/dist/chunk-ACLDOTNQ.js.map +1 -0
- package/dist/chunk-BTDCBVJW.js +160 -0
- package/dist/chunk-BTDCBVJW.js.map +1 -0
- package/dist/chunk-CIMZBAZB.js +72 -0
- package/dist/chunk-CIMZBAZB.js.map +1 -0
- package/dist/chunk-E445ICYI.js +365 -0
- package/dist/chunk-E445ICYI.js.map +1 -0
- package/dist/chunk-EXQRC2L4.js +722 -0
- package/dist/chunk-EXQRC2L4.js.map +1 -0
- package/dist/chunk-FZU343FL.js +32 -0
- package/dist/chunk-FZU343FL.js.map +1 -0
- package/dist/chunk-GJILMRPO.js +354 -0
- package/dist/chunk-GJILMRPO.js.map +1 -0
- package/dist/chunk-GOUT6DND.js +1285 -0
- package/dist/chunk-GOUT6DND.js.map +1 -0
- package/dist/chunk-J66GRPNH.js +111 -0
- package/dist/chunk-J66GRPNH.js.map +1 -0
- package/dist/chunk-M2F2JAWB.js +464 -0
- package/dist/chunk-M2F2JAWB.js.map +1 -0
- package/dist/chunk-M5INGEFC.js +84 -0
- package/dist/chunk-M5INGEFC.js.map +1 -0
- package/dist/chunk-M62XNWRA.js +72 -0
- package/dist/chunk-M62XNWRA.js.map +1 -0
- package/dist/chunk-MR4424N3.js +275 -0
- package/dist/chunk-MR4424N3.js.map +1 -0
- package/dist/chunk-NPC4LFV5.js +132 -0
- package/dist/chunk-NPC4LFV5.js.map +1 -0
- package/dist/chunk-NXFEYLVG.js +311 -0
- package/dist/chunk-NXFEYLVG.js.map +1 -0
- package/dist/chunk-R36SIKES.js +79 -0
- package/dist/chunk-R36SIKES.js.map +1 -0
- package/dist/chunk-TDR6T5CJ.js +381 -0
- package/dist/chunk-TDR6T5CJ.js.map +1 -0
- package/dist/chunk-UF3BUNQZ.js +1 -0
- package/dist/chunk-UF3BUNQZ.js.map +1 -0
- package/dist/chunk-UQFSPSWG.js +1109 -0
- package/dist/chunk-UQFSPSWG.js.map +1 -0
- package/dist/chunk-USKYUS74.js +793 -0
- package/dist/chunk-USKYUS74.js.map +1 -0
- package/dist/chunk-XCL3WP6J.js +121 -0
- package/dist/chunk-XCL3WP6J.js.map +1 -0
- package/dist/chunk-XHFOENR2.js +680 -0
- package/dist/chunk-XHFOENR2.js.map +1 -0
- package/dist/chunk-ZFKD4QMV.js +430 -0
- package/dist/chunk-ZFKD4QMV.js.map +1 -0
- package/dist/chunk-ZLMV3TUA.js +490 -0
- package/dist/chunk-ZLMV3TUA.js.map +1 -0
- package/dist/chunk-ZRG4V3F5.js +17 -0
- package/dist/chunk-ZRG4V3F5.js.map +1 -0
- package/dist/consent/index.cjs +204 -0
- package/dist/consent/index.cjs.map +1 -0
- package/dist/consent/index.d.cts +24 -0
- package/dist/consent/index.d.ts +24 -0
- package/dist/consent/index.js +23 -0
- package/dist/consent/index.js.map +1 -0
- package/dist/crdt/index.cjs +152 -0
- package/dist/crdt/index.cjs.map +1 -0
- package/dist/crdt/index.d.cts +30 -0
- package/dist/crdt/index.d.ts +30 -0
- package/dist/crdt/index.js +24 -0
- package/dist/crdt/index.js.map +1 -0
- package/dist/crypto-IVKU7YTT.js +44 -0
- package/dist/crypto-IVKU7YTT.js.map +1 -0
- package/dist/delegation-XDJCBTI2.js +16 -0
- package/dist/delegation-XDJCBTI2.js.map +1 -0
- package/dist/dev-unlock-CeXic1xC.d.cts +263 -0
- package/dist/dev-unlock-KrKkcqD3.d.ts +263 -0
- package/dist/hash-9KO1BGxh.d.cts +63 -0
- package/dist/hash-ChfJjRjQ.d.ts +63 -0
- package/dist/history/index.cjs +1215 -0
- package/dist/history/index.cjs.map +1 -0
- package/dist/history/index.d.cts +62 -0
- package/dist/history/index.d.ts +62 -0
- package/dist/history/index.js +79 -0
- package/dist/history/index.js.map +1 -0
- package/dist/i18n/index.cjs +746 -0
- package/dist/i18n/index.cjs.map +1 -0
- package/dist/i18n/index.d.cts +38 -0
- package/dist/i18n/index.d.ts +38 -0
- package/dist/i18n/index.js +55 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index-BRHBCmLt.d.ts +1940 -0
- package/dist/index-C8kQtmOk.d.ts +380 -0
- package/dist/index-DN-J-5wT.d.cts +1940 -0
- package/dist/index-DhjMjz7L.d.cts +380 -0
- package/dist/index.cjs +14756 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +269 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.js +6085 -0
- package/dist/index.js.map +1 -0
- package/dist/indexing/index.cjs +736 -0
- package/dist/indexing/index.cjs.map +1 -0
- package/dist/indexing/index.d.cts +36 -0
- package/dist/indexing/index.d.ts +36 -0
- package/dist/indexing/index.js +77 -0
- package/dist/indexing/index.js.map +1 -0
- package/dist/lazy-builder-BwEoBQZ9.d.ts +304 -0
- package/dist/lazy-builder-CZVLKh0Z.d.cts +304 -0
- package/dist/ledger-2NX4L7PN.js +33 -0
- package/dist/ledger-2NX4L7PN.js.map +1 -0
- package/dist/mime-magic-CBBSOkjm.d.cts +50 -0
- package/dist/mime-magic-CBBSOkjm.d.ts +50 -0
- package/dist/periods/index.cjs +1035 -0
- package/dist/periods/index.cjs.map +1 -0
- package/dist/periods/index.d.cts +21 -0
- package/dist/periods/index.d.ts +21 -0
- package/dist/periods/index.js +25 -0
- package/dist/periods/index.js.map +1 -0
- package/dist/predicate-SBHmi6D0.d.cts +161 -0
- package/dist/predicate-SBHmi6D0.d.ts +161 -0
- package/dist/query/index.cjs +1957 -0
- package/dist/query/index.cjs.map +1 -0
- package/dist/query/index.d.cts +3 -0
- package/dist/query/index.d.ts +3 -0
- package/dist/query/index.js +62 -0
- package/dist/query/index.js.map +1 -0
- package/dist/session/index.cjs +487 -0
- package/dist/session/index.cjs.map +1 -0
- package/dist/session/index.d.cts +45 -0
- package/dist/session/index.d.ts +45 -0
- package/dist/session/index.js +44 -0
- package/dist/session/index.js.map +1 -0
- package/dist/shadow/index.cjs +133 -0
- package/dist/shadow/index.cjs.map +1 -0
- package/dist/shadow/index.d.cts +16 -0
- package/dist/shadow/index.d.ts +16 -0
- package/dist/shadow/index.js +20 -0
- package/dist/shadow/index.js.map +1 -0
- package/dist/store/index.cjs +1069 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.cts +491 -0
- package/dist/store/index.d.ts +491 -0
- package/dist/store/index.js +34 -0
- package/dist/store/index.js.map +1 -0
- package/dist/strategy-BSxFXGzb.d.cts +110 -0
- package/dist/strategy-BSxFXGzb.d.ts +110 -0
- package/dist/strategy-D-SrOLCl.d.cts +548 -0
- package/dist/strategy-D-SrOLCl.d.ts +548 -0
- package/dist/sync/index.cjs +1062 -0
- package/dist/sync/index.cjs.map +1 -0
- package/dist/sync/index.d.cts +42 -0
- package/dist/sync/index.d.ts +42 -0
- package/dist/sync/index.js +28 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/team/index.cjs +1233 -0
- package/dist/team/index.cjs.map +1 -0
- package/dist/team/index.d.cts +117 -0
- package/dist/team/index.d.ts +117 -0
- package/dist/team/index.js +39 -0
- package/dist/team/index.js.map +1 -0
- package/dist/tx/index.cjs +212 -0
- package/dist/tx/index.cjs.map +1 -0
- package/dist/tx/index.d.cts +20 -0
- package/dist/tx/index.d.ts +20 -0
- package/dist/tx/index.js +20 -0
- package/dist/tx/index.js.map +1 -0
- package/dist/types-BZpCZB8N.d.ts +7526 -0
- package/dist/types-Bfs0qr5F.d.cts +7526 -0
- package/dist/ulid-COREQ2RQ.js +9 -0
- package/dist/ulid-COREQ2RQ.js.map +1 -0
- package/dist/util/index.cjs +230 -0
- package/dist/util/index.cjs.map +1 -0
- package/dist/util/index.d.cts +77 -0
- package/dist/util/index.d.ts +77 -0
- package/dist/util/index.js +190 -0
- package/dist/util/index.js.map +1 -0
- package/package.json +244 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/refs.ts","../src/crdt/strategy.ts","../src/i18n/strategy.ts","../src/history/strategy.ts","../src/indexing/strategy.ts","../src/cache/lru.ts","../src/cache/policy.ts","../src/team/sync-strategy.ts","../src/blobs/strategy.ts","../src/collection.ts","../src/shadow/strategy.ts","../src/consent/strategy.ts","../src/periods/strategy.ts","../src/team/magic-link-grant.ts","../src/vault.ts","../src/events.ts","../src/tx/strategy.ts","../src/session/strategy.ts","../src/noydb.ts","../src/vault-diff.ts","../src/validation.ts"],"sourcesContent":["/**\n * Standard Schema v1 integration.\n *\n * This file is the entry point for **schema validation**. Any\n * validator that implements the [Standard Schema v1\n * protocol](https://standardschema.dev) — Zod, Valibot, ArkType, Effect\n * Schema, etc. — can be attached to a `Collection` or `defineNoydbStore`\n * and will:\n *\n * 1. Validate the record BEFORE encryption on `put()` — bad data is\n * rejected at the store boundary with a rich issue list.\n * 2. Validate the record AFTER decryption on `get()`/`list()`/`query()`\n * — stored data that has drifted from the current schema throws\n * loudly instead of silently propagating garbage to the UI.\n *\n * ## Why vendor the types?\n *\n * Standard Schema is a protocol, not a library. The spec is <200 lines of\n * TypeScript and has no runtime. There's an official `@standard-schema/spec`\n * types package on npm, but pulling it in would add a dependency edge\n * purely for type definitions. Vendoring the minimal surface keeps\n * `@noy-db/core` at **zero runtime dependencies** and gives us freedom to\n * evolve the helpers without a version-lock on the spec package.\n *\n * If the spec changes in a breaking way (unlikely — it's frozen at v1),\n * we update this file and bump our minor.\n *\n * ## Why not just run `schema.parse(value)` directly?\n *\n * Because then we'd be locked to whichever validator happens to have\n * `.parse`. Standard Schema's `'~standard'.validate` contract is the same\n * across every implementation and includes a structured issues list,\n * which is much more useful than a thrown error for programmatic error\n * handling (e.g., rendering field-level messages in a Vue component).\n */\n\nimport { SchemaValidationError } from './errors.js'\n\n/**\n * The Standard Schema v1 protocol. A schema is any object that exposes a\n * `'~standard'` property with `version: 1` and a `validate` function.\n *\n * The type parameters are:\n * - `Input` — the type accepted by `validate` (what the user passes in)\n * - `Output` — the type produced by `validate` (what we store/return,\n * may differ from Input if the schema transforms or coerces)\n *\n * In most cases `Input === Output`, but validators that transform\n * (Zod's `.transform`, Valibot's `transform`, etc.) can narrow or widen.\n *\n * We intentionally keep the `types` field `readonly` and optional — the\n * spec marks it as optional because it's only used for inference, and\n * not every implementation bothers populating it at runtime.\n */\nexport interface StandardSchemaV1<Input = unknown, Output = Input> {\n readonly '~standard': {\n readonly version: 1\n readonly vendor: string\n readonly validate: (\n value: unknown,\n ) =>\n | StandardSchemaV1SyncResult<Output>\n | Promise<StandardSchemaV1SyncResult<Output>>\n readonly types?:\n | {\n readonly input: Input\n readonly output: Output\n }\n | undefined\n }\n}\n\n/**\n * The result of a single call to `schema['~standard'].validate`. Either\n * `{ value }` on success or `{ issues }` on failure — never both.\n *\n * The spec allows `issues` to be undefined on success (and some\n * validators leave it that way), so consumers should discriminate on\n * `issues?.length` rather than on truthiness of `value`.\n */\nexport type StandardSchemaV1SyncResult<Output> =\n | { readonly value: Output; readonly issues?: undefined }\n | {\n readonly value?: undefined\n readonly issues: readonly StandardSchemaV1Issue[]\n }\n\n/**\n * A single validation issue. The `message` is always present; the `path`\n * is optional and points at the offending field when the schema tracks\n * it (virtually every validator does for object types).\n *\n * The path is deliberately permissive — both a plain `PropertyKey` and a\n * `{ key }` wrapper are allowed so validators that wrap path segments in\n * objects (Zod does this in some modes) don't need special handling.\n */\nexport interface StandardSchemaV1Issue {\n readonly message: string\n readonly path?:\n | ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>\n | undefined\n}\n\n/**\n * Infer the output type of a Standard Schema. Consumers use this to\n * pull the type out of a schema instance when they want to declare a\n * Collection<T> or defineNoydbStore<T> with `T` derived from the schema.\n *\n * Example:\n * ```ts\n * const InvoiceSchema = z.object({ id: z.string(), amount: z.number() })\n * type Invoice = InferOutput<typeof InvoiceSchema>\n * ```\n */\nexport type InferOutput<T extends StandardSchemaV1> =\n T extends StandardSchemaV1<unknown, infer O> ? O : never\n\n/**\n * Validate an input value against a schema. Throws\n * `SchemaValidationError` if the schema rejects, with the rich issue\n * list attached. Otherwise returns the (possibly transformed) output\n * value.\n *\n * The `context` string is included in the thrown error's message so the\n * caller knows where the failure happened (e.g. `\"put(inv-001)\"`) without\n * every caller having to wrap the throw in a try/catch.\n *\n * This function is ALWAYS async because some validators (notably Effect\n * Schema and Zod's `.refine` with async predicates) can return a\n * Promise. We `await` the result unconditionally to normalize the\n * contract — the extra microtask is free compared to the cost of an\n * encrypt/decrypt round-trip.\n */\nexport async function validateSchemaInput<Output>(\n schema: StandardSchemaV1<unknown, Output>,\n value: unknown,\n context: string,\n): Promise<Output> {\n const result = await schema['~standard'].validate(value)\n if (result.issues !== undefined && result.issues.length > 0) {\n throw new SchemaValidationError(\n `Schema validation failed on ${context}: ${summarizeIssues(result.issues)}`,\n result.issues,\n 'input',\n )\n }\n // Safe: the spec guarantees `value` is present when `issues` is absent.\n return result.value as Output\n}\n\n/**\n * Validate an already-stored value coming OUT of the collection. This\n * is a distinct helper from `validateSchemaInput` because the error\n * semantics differ: an output-validation failure means the data in\n * storage has drifted from the current schema (an unexpected state),\n * whereas an input-validation failure means the user passed bad data\n * (an expected state for a UI that isn't guarding its inputs).\n *\n * We still throw — silently returning bad data would be worse — but\n * the error carries `direction: 'output'` so upstream code (and a\n * potential migrate hook) can distinguish the two cases.\n */\nexport async function validateSchemaOutput<Output>(\n schema: StandardSchemaV1<unknown, Output>,\n value: unknown,\n context: string,\n): Promise<Output> {\n const result = await schema['~standard'].validate(value)\n if (result.issues !== undefined && result.issues.length > 0) {\n throw new SchemaValidationError(\n `Stored data for ${context} does not match the current schema — ` +\n `schema drift? ${summarizeIssues(result.issues)}`,\n result.issues,\n 'output',\n )\n }\n return result.value as Output\n}\n\n/**\n * Produce a short human-readable summary of an issue list for the\n * thrown error's message. The full issue array is still attached to the\n * error as a property — this is only for the `.message` string that\n * shows up in console.error / stack traces.\n *\n * Format: `field: message; field2: message2` (up to 3 issues, then `…`).\n * Issues without a path are shown as `root: message`.\n */\nfunction summarizeIssues(\n issues: readonly StandardSchemaV1Issue[],\n): string {\n const shown = issues.slice(0, 3).map((issue) => {\n const pathStr = formatPath(issue.path)\n return `${pathStr}: ${issue.message}`\n })\n const suffix = issues.length > 3 ? ` (+${issues.length - 3} more)` : ''\n return shown.join('; ') + suffix\n}\n\nfunction formatPath(\n path: StandardSchemaV1Issue['path'],\n): string {\n if (!path || path.length === 0) return 'root'\n return path\n .map((segment) =>\n typeof segment === 'object' && segment !== null\n ? String(segment.key)\n : String(segment),\n )\n .join('.')\n}\n","/**\n * Foreign-key references — the soft-FK mechanism.\n *\n * A collection declares its references as metadata at construction\n * time:\n *\n * ```ts\n * import { ref } from '@noy-db/hub'\n *\n * const invoices = company.collection<Invoice>('invoices', {\n * refs: {\n * clientId: ref('clients'), // default: strict\n * categoryId: ref('categories', 'warn'),\n * parentId: ref('invoices', 'cascade'), // self-reference OK\n * },\n * })\n * ```\n *\n * Three modes:\n *\n * - **strict** — the default. `put()` rejects records whose\n * reference target doesn't exist, and `delete()` of the target\n * rejects if any strict-referencing records still exist.\n * Matches SQL's default FK semantics.\n *\n * - **warn** — both operations succeed unconditionally. Broken\n * references surface only through\n * `vault.checkIntegrity()`, which walks every collection\n * and reports orphans. Use when you want soft validation for\n * imports from messy sources.\n *\n * - **cascade** — `put()` is same as warn. `delete()` of the\n * target deletes every referencing record. Cycles are detected\n * and broken via an in-progress set, so mutual cascades\n * terminate instead of recursing forever.\n *\n * Cross-vault refs are explicitly rejected: if the target\n * name contains a `/`, `ref()` throws `RefScopeError`. Cross-\n * vault refs need an auth story (multi-keyring reads) that\n * doesn't ship — tracked for.\n */\n\nimport { NoydbError } from './errors.js'\n\n/** The three enforcement modes. Default for new refs is `'strict'`. */\nexport type RefMode = 'strict' | 'warn' | 'cascade'\n\n/**\n * Descriptor returned by `ref()`. Collections accept a\n * `Record<string, RefDescriptor>` in their options. The key is the\n * field name on the record (top-level only — dotted paths are out of\n * scope), the value describes which target collection the\n * field references and under what mode.\n *\n * The descriptor carries only plain data so it can be serialized,\n * passed around, and introspected without any class machinery.\n */\nexport interface RefDescriptor {\n readonly target: string\n readonly mode: RefMode\n}\n\n/**\n * Thrown when a strict reference is violated — either `put()` with a\n * missing target id, or `delete()` of a target that still has\n * strict-referencing records.\n *\n * Carries structured detail so UI code (and a potential future\n * devtools panel) can render \"client X cannot be deleted because\n * invoices 1, 2, and 3 reference it\" instead of a bare error string.\n */\nexport class RefIntegrityError extends NoydbError {\n readonly collection: string\n readonly id: string\n readonly field: string\n readonly refTo: string\n readonly refId: string | null\n\n constructor(opts: {\n collection: string\n id: string\n field: string\n refTo: string\n refId: string | null\n message: string\n }) {\n super('REF_INTEGRITY', opts.message)\n this.name = 'RefIntegrityError'\n this.collection = opts.collection\n this.id = opts.id\n this.field = opts.field\n this.refTo = opts.refTo\n this.refId = opts.refId\n }\n}\n\n/**\n * Thrown when `ref()` is called with a target name that looks like\n * a cross-vault reference (contains a `/`). Separate error\n * class because the fix is different: RefIntegrityError means \"data\n * is wrong\"; RefScopeError means \"the ref declaration is wrong\".\n */\nexport class RefScopeError extends NoydbError {\n constructor(target: string) {\n super(\n 'REF_SCOPE',\n `Cross-vault references are not supported in — got target \"${target}\". ` +\n `Use a simple collection name (e.g. \"clients\"), not a path. ` +\n `Cross-vault refs are tracked for a future release.`,\n )\n this.name = 'RefScopeError'\n }\n}\n\n/**\n * Helper constructor. Thin wrapper around the object literal so user\n * code reads like `ref('clients')` instead of `{ target: 'clients',\n * mode: 'strict' }` — this is the only ergonomics reason it exists.\n *\n * Validates the target name eagerly so a misconfigured ref declaration\n * fails at collection construction time, not at the first put.\n */\nexport function ref(target: string, mode: RefMode = 'strict'): RefDescriptor {\n if (target.includes('/')) {\n throw new RefScopeError(target)\n }\n if (!target || target.startsWith('_')) {\n throw new Error(\n `ref(): target collection name must be non-empty and cannot start with '_' (reserved for internal collections). Got \"${target}\".`,\n )\n }\n return { target, mode }\n}\n\n/**\n * Per-vault registry of reference declarations.\n *\n * The registry is populated by `Collection` constructors (which pass\n * their `refs` option through the Vault) and consulted by the\n * Vault on every `put` / `delete` and by `checkIntegrity`. A\n * single instance lives on the Vault for its lifetime; there's\n * no global state.\n *\n * The data structure is two parallel maps:\n *\n * - `outbound`: `collection → { field → RefDescriptor }` — what\n * refs does `collection` declare? Used on put to check\n * strict-target-exists and on checkIntegrity to walk each\n * collection's outbound refs.\n *\n * - `inbound`: `target → Array<{ collection, field, mode }>` —\n * which collections reference `target`? Used on delete to find\n * the records that might be affected by cascade / strict.\n *\n * The two views are kept in sync by `register()` and never mutated\n * otherwise — refs can't be unregistered at runtime in.\n */\nexport class RefRegistry {\n private readonly outbound = new Map<string, Record<string, RefDescriptor>>()\n private readonly inbound = new Map<\n string,\n Array<{ collection: string; field: string; mode: RefMode }>\n >()\n\n /**\n * Register the refs declared by a single collection. Idempotent in\n * the happy path — calling twice with the same data is a no-op.\n * Calling twice with DIFFERENT data throws, because silent\n * overrides would be confusing (\"I changed the ref and it doesn't\n * update\" vs \"I declared the same collection twice with different\n * refs and the second call won\").\n */\n register(collection: string, refs: Record<string, RefDescriptor>): void {\n const existing = this.outbound.get(collection)\n if (existing) {\n // Compare shallowly — if any field disagrees, reject.\n const existingKeys = Object.keys(existing).sort()\n const newKeys = Object.keys(refs).sort()\n if (existingKeys.join(',') !== newKeys.join(',')) {\n throw new Error(\n `RefRegistry: conflicting ref declarations for collection \"${collection}\"`,\n )\n }\n for (const k of existingKeys) {\n const a = existing[k]\n const b = refs[k]\n if (!a || !b || a.target !== b.target || a.mode !== b.mode) {\n throw new Error(\n `RefRegistry: conflicting ref declarations for collection \"${collection}\" field \"${k}\"`,\n )\n }\n }\n return\n }\n this.outbound.set(collection, { ...refs })\n for (const [field, desc] of Object.entries(refs)) {\n const list = this.inbound.get(desc.target) ?? []\n list.push({ collection, field, mode: desc.mode })\n this.inbound.set(desc.target, list)\n }\n }\n\n /** Get the outbound refs declared by a collection (or `{}` if none). */\n getOutbound(collection: string): Record<string, RefDescriptor> {\n return this.outbound.get(collection) ?? {}\n }\n\n /** Get the inbound refs that target a given collection (or `[]`). */\n getInbound(\n target: string,\n ): ReadonlyArray<{ collection: string; field: string; mode: RefMode }> {\n return this.inbound.get(target) ?? []\n }\n\n /**\n * Iterate every (collection → refs) pair that has at least one\n * declared reference. Used by `checkIntegrity` to walk the full\n * universe of outbound refs without needing to track collection\n * names elsewhere.\n */\n entries(): Array<[string, Record<string, RefDescriptor>]> {\n return [...this.outbound.entries()]\n }\n\n /** Clear the registry. Test-only escape hatch; never called from production code. */\n clear(): void {\n this.outbound.clear()\n this.inbound.clear()\n }\n}\n\n/**\n * Shape of a single violation reported by `vault.checkIntegrity()`.\n *\n * `refId` is the value we saw in the referencing field — it's the\n * ID we expected to find in `refTo`, but didn't. Left as `unknown`\n * because records are loosely typed at the integrity-check layer.\n */\nexport interface RefViolation {\n readonly collection: string\n readonly id: string\n readonly field: string\n readonly refTo: string\n readonly refId: unknown\n readonly mode: RefMode\n}\n","/**\n * Strategy seam between core Collection and the optional CRDT\n * subsystem. Core imports `CrdtStrategy` as a TYPE-ONLY symbol and\n * `NO_CRDT` as a minimal runtime stub.\n *\n * The state-construction / merge / snapshot-resolution helpers —\n * `buildLwwMapState`, `buildRgaState`, `mergeCrdtStates`,\n * `resolveCrdtSnapshot` — are only reachable from `withCrdt()` in\n * `./active.ts`, which is only exported through the `@noy-db/hub/crdt`\n * subpath. Consumers without CRDT mode configured never pull the\n * ~221 LOC into their bundle.\n *\n * @internal\n */\n\nimport type { CrdtState, LwwMapState, RgaState } from './crdt.js'\n\n/**\n * Seam interface. `@internal`.\n *\n * @internal\n */\nexport interface CrdtStrategy {\n buildLwwMapState(\n record: Record<string, unknown>,\n previous: LwwMapState | undefined,\n now: string,\n ): LwwMapState\n buildRgaState(\n items: readonly unknown[],\n previous: RgaState | undefined,\n idGen: () => string,\n ): RgaState\n mergeCrdtStates(local: CrdtState, remote: CrdtState): CrdtState\n resolveCrdtSnapshot(state: CrdtState): unknown\n}\n\nconst NOT_ENABLED = new Error(\n 'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from ' +\n '\"@noy-db/hub/crdt\" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.',\n)\n\n/**\n * No-CRDT stub. Every method throws with a pointer at the subpath.\n * If a Collection declares `crdt: '...'` without this strategy wired,\n * the first put/sync-merge/read that hits the CRDT path surfaces the\n * error immediately.\n *\n * @internal\n */\nexport const NO_CRDT: CrdtStrategy = {\n buildLwwMapState() { throw NOT_ENABLED },\n buildRgaState() { throw NOT_ENABLED },\n mergeCrdtStates() { throw NOT_ENABLED },\n resolveCrdtSnapshot() { throw NOT_ENABLED },\n}\n","/**\n * Strategy seam for the optional i18n (multi-locale + dictionary)\n * subsystem. Core imports `I18nStrategy` type-only + `NO_I18N` stub;\n * real `applyI18nLocale` / `validateI18nTextValue` /\n * `DictionaryHandle` are only reachable via `withI18n()` in\n * `./active.ts`.\n *\n * Solo apps that don't use `i18nText()` fields, don't declare\n * `dictKey()` fields, and don't open a `vault.dictionary(...)` handle\n * ship none of the ~854 LOC behind this seam.\n *\n * Behavior under NO_I18N:\n *\n * - **applyI18nLocale** — returns the record unchanged. Apps without\n * any i18n descriptors never observe a difference; apps that\n * *did* declare i18nText/dictKey fields without opting into the\n * strategy still get raw values back (locale resolution silently\n * skipped). The validators below ensure the misconfiguration is\n * caught at write time instead.\n * - **validateI18nTextValue** — throws when called. Only fires when\n * a collection declared `i18nFields`; if you declared the field,\n * you must opt in.\n * - **buildDictionaryHandle** — throws when called. Only fires when\n * user code calls `vault.dictionary(...)`.\n *\n * @internal\n */\n\nimport type { NoydbStore } from '../types.js'\nimport type { LedgerStore } from '../history/ledger/store.js'\nimport type { UnlockedKeyring } from '../team/keyring.js'\nimport type { NoydbEventEmitter } from '../events.js'\nimport type { I18nTextDescriptor } from './core.js'\nimport type { DictionaryHandle, DictionaryOptions } from './dictionary.js'\n\n/**\n * Options accepted by `I18nStrategy.buildDictionaryHandle`. Mirrors\n * the `DictionaryHandle` constructor verbatim — kept here so core\n * code never imports the dictionary module at runtime.\n *\n * @internal\n */\nexport interface BuildDictionaryHandleOptions<Keys extends string = string> {\n adapter: NoydbStore\n compartmentName: string\n dictionaryName: string\n keyring: UnlockedKeyring\n getDEK: (collectionName: string) => Promise<CryptoKey>\n encrypted: boolean\n ledger: LedgerStore | undefined\n options: DictionaryOptions\n findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined\n emitter: NoydbEventEmitter\n /**\n * Used by the active strategy to satisfy the generic-key parameter\n * on the returned handle. The NO_I18N stub never reads it.\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n}\n\n/**\n * @internal\n */\nexport interface I18nStrategy {\n /**\n * Resolve `i18nText` fields on a record to the requested locale and\n * return a new object. Returns the input unchanged under\n * `NO_I18N`.\n */\n applyI18nLocale(\n record: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n locale: string,\n fallback?: string | readonly string[],\n ): Record<string, unknown>\n\n /**\n * Validate that an i18nText field's value satisfies its descriptor\n * (required locales present, etc.). Throws under `NO_I18N` —\n * declaring i18nFields without opting in is a misconfiguration.\n */\n validateI18nTextValue(\n value: unknown,\n field: string,\n descriptor: I18nTextDescriptor,\n ): void\n\n /**\n * Construct a typed `DictionaryHandle` for the named dictionary.\n * Throws under `NO_I18N`.\n */\n buildDictionaryHandle<Keys extends string = string>(\n opts: BuildDictionaryHandleOptions<Keys>,\n ): DictionaryHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the i18n strategy. Import ` +\n '`{ withI18n }` from \"@noy-db/hub/i18n\" and pass it to ' +\n '`createNoydb({ i18nStrategy: withI18n() })`.',\n )\n}\n\n/**\n * No-i18n stub. Locale resolution is the identity; validation and\n * dictionary construction throw with an actionable pointer.\n *\n * @internal\n */\nexport const NO_I18N: I18nStrategy = {\n applyI18nLocale(record) { return record },\n validateI18nTextValue() { throw notEnabled('i18nText field validation') },\n buildDictionaryHandle() { throw notEnabled('vault.dictionary()') },\n}\n","/**\n * Strategy seam for the optional history + ledger + time-machine\n * subsystem. Core imports `HistoryStrategy` type-only + `NO_HISTORY`\n * stub; real implementations of `saveHistory`, `LedgerStore`,\n * `VaultInstant`, `computePatch`, `diff` etc. are only reachable via\n * `withHistory()` in `./active.ts`.\n *\n * Applications that don't track per-record versioning, don't need the\n * hash-chained audit ledger, and don't restore to past instants ship\n * none of the ~1,880 LOC behind this seam.\n *\n * Strategy contract:\n *\n * - **saveHistory / pruneHistory / clearHistory** — no-ops under\n * NO_HISTORY. Writes still succeed; no snapshot is captured.\n * - **getHistoryEntries / getVersionEnvelope / diff** — throw under\n * NO_HISTORY. These are read APIs the consumer would only call\n * after explicitly asking for history; the throw guides them to\n * `@noy-db/hub/history`.\n * - **envelopePayloadHash / computePatch** — return empty / `[]`\n * under NO_HISTORY. These are only used inside the\n * `if (this.ledger)` branch, which is itself gated by\n * `buildLedger()` returning null.\n * - **buildLedger** — returns `null` under NO_HISTORY. The Vault's\n * public `vault.ledger()` accessor throws when null.\n * - **buildVaultInstant** — throws under NO_HISTORY. `vault.at()`\n * propagates the throw.\n *\n * @internal\n */\n\nimport type {\n EncryptedEnvelope,\n NoydbStore,\n HistoryOptions,\n PruneOptions,\n} from '../types.js'\nimport type { LedgerStore } from './ledger/store.js'\nimport type { JsonPatch } from './ledger/patch.js'\nimport type { DiffEntry } from './diff.js'\nimport type { VaultInstant, VaultEngine } from './time-machine.js'\n\n/**\n * Options accepted by `HistoryStrategy.buildLedger`. Mirrors the\n * `LedgerStore` constructor verbatim — kept in this file so `core`\n * code never imports the LedgerStore module at runtime.\n *\n * @internal\n */\nexport interface BuildLedgerOptions {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<CryptoKey>\n actor: string\n}\n\n/**\n * @internal\n */\nexport interface HistoryStrategy {\n /**\n * Persist a full encrypted envelope snapshot of the prior version\n * under `_history/{collection}:{id}:{paddedVersion}`. No-op under\n * `NO_HISTORY`.\n */\n saveHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n envelope: EncryptedEnvelope,\n ): Promise<void>\n\n /**\n * List history envelopes for a record, newest first. Throws under\n * `NO_HISTORY` — callers reach this via `collection.history()` /\n * `collection.getVersion()` / `collection.diff()`, which only work\n * with the strategy enabled.\n */\n getHistoryEntries(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n options?: HistoryOptions,\n ): Promise<EncryptedEnvelope[]>\n\n /**\n * Fetch a specific version's envelope. Throws under `NO_HISTORY`.\n */\n getVersionEnvelope(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string,\n version: number,\n ): Promise<EncryptedEnvelope | null>\n\n /**\n * Prune history entries by retention rule. Returns `0` under\n * `NO_HISTORY`.\n */\n pruneHistory(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n recordId: string | undefined,\n options: PruneOptions,\n ): Promise<number>\n\n /**\n * Clear all history for vault/collection/record. Returns `0` under\n * `NO_HISTORY`.\n */\n clearHistory(\n adapter: NoydbStore,\n vault: string,\n collection?: string,\n recordId?: string,\n ): Promise<number>\n\n /**\n * Compute the SHA-256 hash of an envelope's encrypted payload, used\n * by `LedgerStore.append` to track tamper-evidence. Returns the\n * empty string under `NO_HISTORY` (the call site is gated by\n * `if (this.ledger)`, so the value is never observed).\n */\n envelopePayloadHash(envelope: EncryptedEnvelope | null): Promise<string>\n\n /**\n * Compute the JSON patch from `from` → `to`. Returns `[]` under\n * `NO_HISTORY`.\n */\n computePatch(from: unknown, to: unknown): JsonPatch\n\n /**\n * Compute the typed diff between two records. Throws under\n * `NO_HISTORY` — `collection.diff()` is a history-read API.\n */\n diff(recordA: unknown, recordB: unknown): DiffEntry[]\n\n /**\n * Construct (or return null) a `LedgerStore` for the vault. Returns\n * `null` under `NO_HISTORY`; the Vault treats null as \"no ledger\n * attached\" — collection write paths skip the append branch and the\n * public `vault.ledger()` accessor throws.\n */\n buildLedger(opts: BuildLedgerOptions): LedgerStore | null\n\n /**\n * Construct a `VaultInstant` for time-machine reads. Throws under\n * `NO_HISTORY`.\n */\n buildVaultInstant(engine: VaultEngine, timestamp: string): VaultInstant\n}\n\n/**\n * Error thrown when the consumer reaches a history-gated surface\n * without opting into the strategy. The message names the offending\n * operation and points to the subpath import.\n *\n * @internal\n */\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the history strategy. Import ` +\n '`{ withHistory }` from \"@noy-db/hub/history\" and pass it to ' +\n '`createNoydb({ historyStrategy: withHistory() })`.',\n )\n}\n\n/**\n * No-history stub. Snapshots and prune/clear are no-ops; reads and\n * time-machine throw with an actionable message; ledger construction\n * returns null so the write-path's `if (this.ledger)` branch is dead\n * code in the bundle.\n *\n * @internal\n */\nexport const NO_HISTORY: HistoryStrategy = {\n async saveHistory() {},\n async getHistoryEntries() { throw notEnabled('collection.history()') },\n async getVersionEnvelope() { throw notEnabled('collection.getVersion()') },\n async pruneHistory() { return 0 },\n async clearHistory() { return 0 },\n async envelopePayloadHash() { return '' },\n computePatch() { return [] },\n diff() { throw notEnabled('collection.diff()') },\n buildLedger() { return null },\n buildVaultInstant() { throw notEnabled('vault.at() / vault.timeMachine()') },\n}\n","/**\n * Strategy seam between core Collection and the optional indexing\n * subsystem. Core imports `IndexStrategy` and `IndexState` as\n * TYPE-ONLY symbols and `NO_INDEXING` as a tiny runtime stub.\n *\n * The heavy classes — `CollectionIndexes`, `PersistedCollectionIndex`,\n * `LazyQuery` — are only instantiated inside the `withIndexing()`\n * factory under `./active.ts`, which in turn is only reachable through\n * the `@noy-db/hub/indexing` subpath export. A consumer that never\n * imports the subpath ships none of those classes in their bundle\n * (ESM tree-shaking + hub's `\"sideEffects\": false`).\n *\n * @internal\n */\n\nimport type { CollectionIndexes, IndexDef } from './eager-indexes.js'\nimport type { PersistedCollectionIndex } from './persisted-indexes.js'\n\n/**\n * Per-collection container for whatever mirrors the active strategy\n * decided to materialize. Both accessors may return `null` — they do\n * for `NO_INDEXING`, and `getEagerIndexes` returns null in a\n * lazy-mode collection even when indexing is active (lazy uses the\n * persisted mirror instead).\n *\n * `isEnabled` is a cheap guard so collection code can short-circuit\n * the full indexing path without inspecting either mirror.\n *\n * @internal\n */\nexport interface IndexState {\n readonly isEnabled: boolean\n getEagerIndexes(): CollectionIndexes | null\n getPersistedIndexes(): PersistedCollectionIndex | null\n}\n\n/**\n * Factory that builds one `IndexState` per Collection. Called exactly\n * once inside each Collection constructor with the declared\n * `IndexDef[]` and the lazy-mode flag (so lazy collections get the\n * persisted mirror and eager collections get the in-memory one).\n *\n * @internal\n */\nexport interface IndexStrategy {\n createState(args: {\n readonly defs: readonly IndexDef[]\n readonly lazy: boolean\n }): IndexState\n}\n\n/**\n * No-indexing stub. Every Collection defaults to this; it returns a\n * cheap `IndexState` whose mirrors are both `null`. Collection code\n * null-checks both accessors and short-circuits, so no indexing code\n * path runs and the heavy classes never arrive in the bundle.\n *\n * @internal\n */\nexport const NO_INDEXING: IndexStrategy = {\n createState() {\n return DISABLED_STATE\n },\n}\n\nconst DISABLED_STATE: IndexState = {\n isEnabled: false,\n getEagerIndexes: () => null,\n getPersistedIndexes: () => null,\n}\n","/**\n * Generic LRU cache for `Collection`'s lazy hydration mode.\n *\n * Backed by a JavaScript `Map`, which preserves insertion order. Promotion\n * is implemented as `delete()` + `set()` — O(1) on `Map` since both\n * operations are constant-time. Eviction walks the iterator from the front\n * (least recently used) until both budgets are satisfied.\n *\n * ships in-memory only. The cache is never persisted; on collection\n * close every entry is dropped. Persisting cache state is a follow-up\n * once the access patterns from real consumers tell us whether it would\n * pay back the complexity.\n */\n\nexport interface LruEntry<V> {\n /** The cached value. */\n readonly value: V\n /**\n * Approximate decrypted byte size of the entry. Used by the byte-budget\n * eviction path. Callers compute this once at insert time and pass it\n * in — recomputing on every access would dominate the per-record cost.\n */\n readonly size: number\n}\n\nexport interface LruOptions {\n /** Maximum number of entries before eviction. Required if `maxBytes` is unset. */\n maxRecords?: number\n /** Maximum total bytes before eviction. Computed from per-entry `size`. */\n maxBytes?: number\n}\n\nexport interface LruStats {\n /** Total cache hits since construction (or `resetStats()`). */\n hits: number\n /** Total cache misses since construction (or `resetStats()`). */\n misses: number\n /** Total entries evicted since construction (or `resetStats()`). */\n evictions: number\n /** Current number of cached entries. */\n size: number\n /** Current sum of cached entry sizes (in bytes, approximate). */\n bytes: number\n}\n\n/**\n * O(1) LRU cache. Both `get()` and `set()` promote the touched entry to\n * the most-recently-used end. Eviction happens after every insert and\n * walks the front of the Map iterator dropping entries until both\n * budgets are satisfied.\n */\nexport class Lru<K, V> {\n private readonly entries = new Map<K, LruEntry<V>>()\n private readonly maxRecords: number | undefined\n private readonly maxBytes: number | undefined\n private currentBytes = 0\n private hits = 0\n private misses = 0\n private evictions = 0\n\n constructor(options: LruOptions) {\n if (options.maxRecords === undefined && options.maxBytes === undefined) {\n throw new Error('Lru: must specify maxRecords, maxBytes, or both')\n }\n this.maxRecords = options.maxRecords\n this.maxBytes = options.maxBytes\n }\n\n /**\n * Look up a key. Hits promote the entry to most-recently-used; misses\n * return undefined. Both update the running stats counters.\n */\n get(key: K): V | undefined {\n const entry = this.entries.get(key)\n if (!entry) {\n this.misses++\n return undefined\n }\n // Promote: re-insert moves the entry to the end of the iteration order.\n this.entries.delete(key)\n this.entries.set(key, entry)\n this.hits++\n return entry.value\n }\n\n /**\n * Insert or update a key. If the key already exists, its size is\n * accounted for and the entry is promoted to MRU. After insertion,\n * eviction runs to maintain both budgets.\n */\n set(key: K, value: V, size: number): void {\n const existing = this.entries.get(key)\n if (existing) {\n // Update path: subtract the old size before adding the new one.\n this.currentBytes -= existing.size\n this.entries.delete(key)\n }\n this.entries.set(key, { value, size })\n this.currentBytes += size\n this.evictUntilUnderBudget()\n }\n\n /**\n * Remove a key without affecting hit/miss stats. Used by `Collection.delete()`.\n * Returns true if the key was present.\n */\n remove(key: K): boolean {\n const existing = this.entries.get(key)\n if (!existing) return false\n this.currentBytes -= existing.size\n this.entries.delete(key)\n return true\n }\n\n /** True if the cache currently holds an entry for the given key. */\n has(key: K): boolean {\n return this.entries.has(key)\n }\n\n /**\n * Drop every entry. Stats counters survive — call `resetStats()` if you\n * want a clean slate. Used by `Collection.invalidate()` on key rotation.\n */\n clear(): void {\n this.entries.clear()\n this.currentBytes = 0\n }\n\n /** Reset hit/miss/eviction counters to zero. Does NOT touch entries. */\n resetStats(): void {\n this.hits = 0\n this.misses = 0\n this.evictions = 0\n }\n\n /** Snapshot of current cache statistics. Cheap — no copying. */\n stats(): LruStats {\n return {\n hits: this.hits,\n misses: this.misses,\n evictions: this.evictions,\n size: this.entries.size,\n bytes: this.currentBytes,\n }\n }\n\n /**\n * Iterate over all currently-cached values. Order is least-recently-used\n * first. Used by tests and devtools — production callers should use\n * `Collection.scan()` instead.\n */\n *values(): IterableIterator<V> {\n for (const entry of this.entries.values()) yield entry.value\n }\n\n /**\n * Walk the cache from the LRU end and drop entries until both budgets\n * are satisfied. Called after every `set()`. Single pass — entries are\n * never re-promoted during eviction.\n */\n private evictUntilUnderBudget(): void {\n while (this.overBudget()) {\n const oldest = this.entries.keys().next()\n if (oldest.done) return // empty cache; nothing more to evict\n const key = oldest.value\n const entry = this.entries.get(key)\n if (entry) this.currentBytes -= entry.size\n this.entries.delete(key)\n this.evictions++\n }\n }\n\n private overBudget(): boolean {\n if (this.maxRecords !== undefined && this.entries.size > this.maxRecords) return true\n if (this.maxBytes !== undefined && this.currentBytes > this.maxBytes) return true\n return false\n }\n}\n","/**\n * Cache policy helpers — parse human-friendly byte budgets into raw numbers.\n *\n * Accepted shapes (case-insensitive on suffix):\n * number — interpreted as raw bytes\n * '1024' — string of digits, raw bytes\n * '50KB' — kilobytes (×1024)\n * '50MB' — megabytes (×1024²)\n * '1GB' — gigabytes (×1024³)\n *\n * Decimals are accepted (`'1.5GB'` → 1610612736 bytes).\n *\n * Anything else throws — better to fail loud at construction time than\n * to silently treat a typo as 0 bytes (which would evict everything).\n */\n\nconst UNITS: Record<string, number> = {\n '': 1,\n 'B': 1,\n 'KB': 1024,\n 'MB': 1024 * 1024,\n 'GB': 1024 * 1024 * 1024,\n // 'TB' deliberately not supported — if you need it, you're not using NOYDB.\n}\n\n/** Parse a byte budget into a positive integer number of bytes. */\nexport function parseBytes(input: number | string): number {\n if (typeof input === 'number') {\n if (!Number.isFinite(input) || input <= 0) {\n throw new Error(`parseBytes: numeric input must be a positive finite number, got ${String(input)}`)\n }\n return Math.floor(input)\n }\n\n const trimmed = input.trim()\n if (trimmed === '') {\n throw new Error('parseBytes: empty string is not a valid byte budget')\n }\n\n // Accept either a bare number or a number followed by a unit suffix.\n // Regex: optional sign, digits with optional decimal, optional unit.\n const match = /^([0-9]+(?:\\.[0-9]+)?)\\s*([A-Za-z]*)$/.exec(trimmed)\n if (!match) {\n throw new Error(`parseBytes: invalid byte budget \"${input}\". Expected format: \"1024\", \"50KB\", \"50MB\", \"1GB\"`)\n }\n\n const value = parseFloat(match[1]!)\n const unit = (match[2] ?? '').toUpperCase()\n\n if (!(unit in UNITS)) {\n throw new Error(`parseBytes: unknown unit \"${match[2]}\" in \"${input}\". Supported: B, KB, MB, GB`)\n }\n\n const bytes = Math.floor(value * UNITS[unit]!)\n if (bytes <= 0) {\n throw new Error(`parseBytes: byte budget must be > 0, got ${bytes} from \"${input}\"`)\n }\n return bytes\n}\n\n/**\n * Estimate the in-memory byte size of a decrypted record.\n *\n * Uses `JSON.stringify().length` as a stand-in for actual heap usage.\n * It's a deliberate approximation: real V8 heap size includes pointer\n * overhead, hidden classes, and string interning that we can't measure\n * from JavaScript. The JSON length is a stable, monotonic proxy that\n * costs O(record size) per insert — fine when records are typically\n * < 1 KB and the cache eviction is the slow path anyway.\n *\n * Returns `0` (and the caller must treat it as 1 for accounting) if\n * stringification throws on circular references; this is documented\n * but in practice records always come from JSON-decoded envelopes.\n */\nexport function estimateRecordBytes(record: unknown): number {\n try {\n return JSON.stringify(record).length\n } catch {\n return 0\n }\n}\n","/**\n * Strategy seam for the optional sync engine + presence subsystem.\n * Core imports `SyncStrategy` type-only + `NO_SYNC` stub; the real\n * `SyncEngine`, `SyncTransaction`, and `PresenceHandle` constructors\n * are only reachable via `withSync()` in `./sync-active.ts`.\n *\n * Solo apps that never configure `sync` and never call\n * `collection.presence()` ship none of the ~856 LOC behind this seam\n * (`sync.ts` + `sync-transaction.ts` + `presence.ts`).\n *\n * Note: `keyring.ts` (~746 LOC) stays in core because it's required\n * for any multi-user vault — even single-owner vaults use a keyring\n * to wrap the DEK. The team package's grant/revoke/magic-link/\n * delegation modules tree-shake naturally via direct named imports.\n *\n * Behavior under NO_SYNC:\n *\n * - **buildSyncEngine** — throws. Only fires when `createNoydb({ sync })`\n * passes a remote target.\n * - **buildSyncTransaction** — throws. Only fires when `db.transaction(vault)`\n * is called on a vault with sync configured.\n * - **buildPresence** — throws. Only fires when user code calls\n * `collection.presence()`.\n *\n * @internal\n */\n\nimport type {\n NoydbStore,\n ConflictStrategy,\n SyncTargetRole,\n} from '../types.js'\nimport type { NoydbEventEmitter } from '../events.js'\nimport type { SyncPolicy } from '../store/sync-policy.js'\nimport type { SyncEngine } from './sync.js'\nimport type { SyncTransaction } from './sync-transaction.js'\nimport type { PresenceHandle, PresenceHandleOpts } from './presence.js'\nimport type { Vault } from '../vault.js'\n\n/**\n * Options accepted by `SyncStrategy.buildSyncEngine`. Mirrors the\n * `SyncEngine` constructor verbatim — kept here so core code never\n * imports the sync module at runtime.\n *\n * @internal\n */\nexport interface BuildSyncEngineOptions {\n local: NoydbStore\n remote: NoydbStore\n vault: string\n strategy: ConflictStrategy\n emitter: NoydbEventEmitter\n syncPolicy?: SyncPolicy\n role?: SyncTargetRole\n label?: string\n}\n\n/**\n * @internal\n */\nexport interface SyncStrategy {\n buildSyncEngine(opts: BuildSyncEngineOptions): SyncEngine\n buildSyncTransaction(vault: Vault, engine: SyncEngine): SyncTransaction\n buildPresence<P>(opts: PresenceHandleOpts): PresenceHandle<P>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the sync strategy. Import ` +\n '`{ withSync }` from \"@noy-db/hub/sync\" and pass it to ' +\n '`createNoydb({ syncStrategy: withSync() })`.',\n )\n}\n\n/**\n * No-sync stub. Every constructor throws with an actionable pointer\n * — there is no useful \"off\" mode for sync engine / presence /\n * sync-transaction; if the consumer reached one of these surfaces,\n * they intended to use it.\n *\n * @internal\n */\nexport const NO_SYNC: SyncStrategy = {\n buildSyncEngine() { throw notEnabled('SyncEngine') },\n buildSyncTransaction() { throw notEnabled('SyncTransaction') },\n buildPresence() { throw notEnabled('collection.presence()') },\n}\n","/**\n * Strategy seam between core Collection and the optional blob subsystem.\n *\n * Core imports `BlobStrategy` as a TYPE-ONLY symbol and `NO_BLOBS` as a\n * minimal runtime stub. Neither pulls in the heavy `BlobSet` / chunk /\n * MIME machinery — those only arrive when the consumer explicitly\n * imports `@noy-db/hub/blobs` (see `./index.ts` → `withBlobs()` factory).\n *\n * This file is intentionally tiny and free of side effects so the\n * bundler keeps it in the graph without dragging everything else in.\n *\n * @internal\n */\n\nimport type { BlobSet } from './blob-set.js'\nimport type { NoydbStore } from '../types.js'\n\n/**\n * Args forwarded by `Collection.blob(id)` to the active strategy's\n * `openSlot`. The strategy is responsible for returning a live\n * `BlobSet` bound to the given record.\n *\n * @internal\n */\nexport interface BlobStrategyOpenArgs {\n readonly store: NoydbStore\n readonly vault: string\n readonly collection: string\n readonly recordId: string\n readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n readonly encrypted: boolean\n readonly userId: string\n}\n\n/**\n * The seam interface. `@internal` — do not build public APIs on this\n * shape; it can evolve freely until blobs are extracted into their\n * own package, at which point it will be promoted to public.\n *\n * @internal\n */\nexport interface BlobStrategy {\n openSlot(args: BlobStrategyOpenArgs): BlobSet\n}\n\n/**\n * Default strategy for collections that did not opt into blob storage.\n * Every operation surfaces an actionable error that points the caller\n * at the opt-in path.\n *\n * @internal\n */\nexport const NO_BLOBS: BlobStrategy = {\n openSlot() {\n throw new Error(\n 'Blob storage is not enabled on this Noydb instance. ' +\n 'Import `{ withBlobs }` from \"@noy-db/hub/blobs\" and pass `withBlobs()` to `createNoydb({ blobStrategy: withBlobs() })`.',\n )\n },\n}\n","import type { NoydbStore, EncryptedEnvelope, ChangeEvent, HistoryConfig, HistoryOptions, HistoryEntry, PruneOptions, ListPageResult, LocaleReadOptions, ConflictPolicy, CollectionConflictResolver, PutManyItemOptions, PutManyOptions, PutManyResult, DeleteManyResult } from './types.js'\nimport { NOYDB_FORMAT_VERSION } from './types.js'\nimport type { CrdtMode, CrdtState, LwwMapState, RgaState } from './crdt/crdt.js'\nimport { NO_CRDT, type CrdtStrategy } from './crdt/strategy.js'\nimport type { I18nTextDescriptor } from './i18n/core.js'\nimport type { DictKeyDescriptor } from './i18n/dictionary.js'\nimport { NO_I18N, type I18nStrategy } from './i18n/strategy.js'\nimport { encrypt, decrypt, encryptDeterministic } from './crypto.js'\nimport { ConflictError, ReadOnlyError, TranslatorNotConfiguredError, TierDemoteDeniedError } from './errors.js'\nimport { dekKey, assertTierAccess } from './team/tiers.js'\nimport type { GhostRecord, TierMode, CrossTierAccessEvent } from './types.js'\nimport type { UnlockedKeyring } from './team/keyring.js'\nimport { hasWritePermission } from './team/keyring.js'\nimport type { NoydbEventEmitter } from './events.js'\nimport type { StandardSchemaV1 } from './schema.js'\nimport { validateSchemaInput, validateSchemaOutput } from './schema.js'\nimport type { LedgerStore } from './history/ledger/index.js'\nimport type { DiffEntry } from './history/diff.js'\nimport { NO_HISTORY, type HistoryStrategy } from './history/strategy.js'\nimport { Query, ScanBuilder } from './query/index.js'\nimport type { QuerySource, JoinContext, JoinableSource } from './query/index.js'\nimport type { CollectionIndexes, IndexDef } from './indexing/eager-indexes.js'\nimport { encodeIdxId, decodeIdxId } from './indexing/persisted-indexes.js'\nimport type { PersistedCollectionIndex, PersistedIndexDef } from './indexing/persisted-indexes.js'\nimport { LazyQuery } from './indexing/lazy-builder.js'\nimport type { LazyQuerySource } from './indexing/lazy-builder.js'\nimport { NO_INDEXING, type IndexStrategy, type IndexState } from './indexing/strategy.js'\nimport { IndexWriteFailureError } from './errors.js'\nimport type { RefDescriptor } from './refs.js'\nimport { Lru, parseBytes, estimateRecordBytes, type LruStats } from './cache/index.js'\nimport { generateULID } from './bundle/ulid.js'\nimport type { PresenceHandle, PresenceHandleOpts } from './team/presence.js'\nimport { NO_SYNC, type SyncStrategy } from './team/sync-strategy.js'\nimport type { BlobSet } from './blobs/blob-set.js'\nimport { NO_BLOBS, type BlobStrategy } from './blobs/strategy.js'\nimport { NO_AGGREGATE, type AggregateStrategy } from './aggregate/strategy.js'\n\n/** Callback for dirty tracking (sync engine integration). */\nexport type OnDirtyCallback = (collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>\n\n/**\n * Event delivered to a `collection.subscribe()` callback. Distinct\n * from the hub-level `ChangeEvent` — this one is bound to a single\n * collection's type `T` and hydrates the record from cache on put.\n *\n * - `type: 'put'` — `record` is the current decrypted value, or\n * `null` in the rare case where another op deleted the record\n * between the emit and the handler firing.\n * - `type: 'delete'` — `record` is always `null`; the deletion is\n * the only information.\n */\nexport interface CollectionChangeEvent<T> {\n readonly type: 'put' | 'delete'\n readonly id: string\n readonly record: T | null\n}\n\n/**\n * Per-collection cache configuration. Only meaningful when paired with\n * `prefetch: false` (lazy mode); eager mode keeps the entire decrypted\n * cache in memory and ignores these bounds.\n */\nexport interface CacheOptions {\n /** Maximum number of records to keep in memory before LRU eviction. */\n maxRecords?: number\n /**\n * Maximum total decrypted byte size before LRU eviction. Accepts a raw\n * number or a human-friendly string: `'50KB'`, `'50MB'`, `'1GB'`.\n * Eviction picks the least-recently-used entry until both budgets\n * (maxRecords AND maxBytes, if both are set) are satisfied.\n */\n maxBytes?: number | string\n}\n\n/** Statistics exposed via `Collection.cacheStats()`. */\nexport interface CacheStats extends LruStats {\n /** True if this collection is in lazy mode. */\n lazy: boolean\n}\n\n/**\n * Track which adapter names have already triggered the listPage fallback\n * warning. We only emit once per adapter per process so consumers see the\n * heads-up without log spam.\n */\nconst fallbackWarned = new Set<string>()\nfunction warnOnceFallback(adapterName: string): void {\n if (fallbackWarned.has(adapterName)) return\n fallbackWarned.add(adapterName)\n // Only warn in non-test environments — vitest runs are noisy enough.\n if (typeof process !== 'undefined' && process.env['NODE_ENV'] === 'test') return\n console.warn(\n `[noy-db] Adapter \"${adapterName}\" does not implement listPage(); ` +\n `Collection.scan()/listPage() are using a synthetic fallback (slower). ` +\n `Add a listPage method to opt into the streaming fast path.`,\n )\n}\n\n/** A typed collection of records within a vault. */\nexport class Collection<T> {\n private readonly adapter: NoydbStore\n private readonly vault: string\n private readonly name: string\n private readonly keyring: UnlockedKeyring\n private readonly encrypted: boolean\n private readonly emitter: NoydbEventEmitter\n private readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n private readonly onDirty: OnDirtyCallback | undefined\n private readonly historyConfig: HistoryConfig\n\n /**\n * tree-shake seam — the strategy that backs `collection.blob(id)`.\n * Defaults to `NO_BLOBS`, a ~10-line stub that throws with an actionable\n * message. Consumers opt into real blob storage by importing\n * `{ blobs }` from `@noy-db/hub/blobs` and passing the returned\n * strategy to `createNoydb({ blobStrategy: blobs() })`. With the\n * default stub, none of the BlobSet / chunk / MIME-magic machinery\n * reaches the bundle.\n */\n private readonly blobStrategy: BlobStrategy\n private readonly aggregateStrategy: AggregateStrategy\n private readonly crdtStrategy: CrdtStrategy\n private readonly historyStrategy: HistoryStrategy\n private readonly i18nStrategy: I18nStrategy\n private readonly syncStrategy: SyncStrategy\n\n // In-memory cache of decrypted records (eager mode only). Lazy mode\n // uses `lru` instead. Both fields exist so a single Collection instance\n // doesn't need a runtime branch on every cache access.\n private readonly cache = new Map<string, { record: T; version: number }>()\n private hydrated = false\n\n /**\n * Lazy mode flag. `true` when constructed with `prefetch: false`.\n * In lazy mode the cache is bounded by an LRU and `list()`/`query()`\n * throw — callers must use `scan()` or per-id `get()` instead.\n */\n private readonly lazy: boolean\n\n /**\n * LRU cache for lazy mode. Only allocated when `prefetch: false` is set.\n * Stores `{ record, version }` entries the same shape as `this.cache`.\n * Tree-shaking note: importing Collection without setting `prefetch:false`\n * still pulls in the Lru class today; future bundle-size work could\n * lazy-import the cache module.\n */\n private readonly lru: Lru<string, { record: T; version: number }> | null\n\n /**\n * tree-shake seam — per-Collection indexing state. Owned by the\n * `IndexStrategy` passed through from `createNoydb({ indexStrategy })`.\n * Defaults to a disabled state (both accessors return null) so the\n * `CollectionIndexes` / `PersistedCollectionIndex` / `LazyQuery`\n * classes never reach the bundle when indexing is unused.\n *\n * Accessor helpers below (`get indexes()`, `get persistedIndexes()`)\n * preserve the field-access ergonomics without changing every\n * caller site.\n */\n private readonly indexState: IndexState\n\n /**\n * True once `_idx/*` side-cars have been bulk-loaded into\n * `persistedIndexes`. Flipped by `ensurePersistedIndexesLoaded()` on\n * first lazy-mode query so subsequent queries skip the adapter round\n * trip. Invalidation (remote sync, rotation) resets it alongside\n * `persistedIndexes.clear()`.\n */\n private persistedIndexesLoaded = false\n\n /**\n * Accessor for the in-memory eager-mode index mirror. Returns `null`\n * when indexing is disabled on this Noydb instance (the\n * `NO_INDEXING` default) or when the collection is in lazy mode\n * (which uses the persisted mirror instead).\n */\n private get indexes(): CollectionIndexes | null {\n return this.indexState.getEagerIndexes()\n }\n\n /**\n * Accessor for the persisted-mirror (lazy-mode) index. Returns `null`\n * when indexing is disabled or the collection is in eager mode.\n */\n private get persistedIndexes(): PersistedCollectionIndex | null {\n return this.indexState.getPersistedIndexes()\n }\n\n /**\n * per-collection reconcile-on-open policy. Read once\n * from `CollectionOptions.reconcileOnOpen` and applied by\n * `ensurePersistedIndexesLoaded()` on the first lazy-mode query.\n */\n private readonly reconcileOnOpen: 'off' | 'dry-run' | 'auto'\n\n /**\n * Re-entrancy guard for the auto-reconcile path. `reconcileIndex`\n * reloads the mirror after applying fixes, which re-enters\n * `ensurePersistedIndexesLoaded`; without this flag we'd trigger a\n * second auto-reconcile pass and potentially infinite recursion.\n */\n private autoReconciling = false\n\n /**\n * Optional Standard Schema v1 validator. When set, every `put()` runs\n * the input through `validateSchemaInput` before encryption, and every\n * record coming OUT of `decryptRecord` runs through\n * `validateSchemaOutput`. A rejected input throws\n * `SchemaValidationError` with `direction: 'input'`; drifted stored\n * data throws with `direction: 'output'`. Both carry the rich issue\n * list from the validator so UI code can render field-level messages.\n *\n * The schema is stored as `StandardSchemaV1<unknown, T>` because the\n * collection type parameter `T` is the OUTPUT type — whatever the\n * validator produces after transforms and coercion. Users who pass a\n * schema to `defineNoydbStore` (or `Collection.constructor`) get their\n * `T` inferred automatically via `InferOutput<Schema>`.\n */\n private readonly schema: StandardSchemaV1<unknown, T> | undefined\n\n /**\n * Vault-default locale. Used as the fallback when no per-call\n * locale option is passed to `get()`/`list()`. Provided by Vault\n * at collection construction time via the `collection({ locale })` or\n * `openVault(name, { locale })` path.\n *\n * `undefined` means \"no default locale set\" — i18nText fields will\n * throw `LocaleNotSpecifiedError` unless a per-call locale is passed.\n */\n private readonly defaultLocale: string | undefined\n\n /**\n * Map of field name → `I18nTextDescriptor` for fields declared with\n * `i18nText()`. Used by:\n * - `put()` via `i18nPutValidator` to enforce required translations\n * - `get()`/`list()` to apply locale resolution after decryption\n *\n * Declared via the `i18nFields` collection option.\n */\n private readonly i18nFields: Record<string, I18nTextDescriptor> | undefined\n\n /**\n * Map of field name → `DictKeyDescriptor` for fields declared with\n * `dictKey()`. Used by `get()`/`list()` to add `<field>Label` virtual\n * fields when a locale is requested.\n */\n private readonly dictKeyFields: Record<string, DictKeyDescriptor> | undefined\n\n /**\n * Async callback provided by the Vault that resolves a dict key\n * to its label for a given locale. Used by the locale-read path for\n * dictKey fields.\n *\n * Signature: `(dictName, key, locale, fallback?) => Promise<string | undefined>`\n */\n private readonly dictLabelResolver:\n | ((\n dictName: string,\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ) => Promise<string | undefined>)\n | undefined\n\n /**\n * Synchronous callback provided by the Vault that validates\n * i18nText fields on `put()`. Throws `MissingTranslationError` when\n * a required translation is absent. Called after schema validation,\n * before encryption.\n */\n private readonly i18nPutValidator: ((record: unknown) => void) | undefined\n\n /**\n * declared deterministic fields. `null` when the feature\n * is inactive for this collection; a frozen `Set` otherwise.\n */\n private readonly deterministicFields: ReadonlySet<string> | null\n\n /**\n * declared tiers for this collection. `null` when\n * tier-aware methods are disabled. Tier 0 is implicit and never\n * stored here.\n */\n private readonly tiers: ReadonlySet<number> | null\n private readonly tierMode: TierMode\n private readonly onCrossTierAccess: ((event: CrossTierAccessEvent) => void) | undefined\n\n /**\n * Async translator callback provided by Noydb via Vault for\n * `i18nText` fields with `autoTranslate: true`. Called\n * before i18n validation so translated values are present when the\n * validator runs. `undefined` when no `plaintextTranslator` was\n * configured on `createNoydb()`.\n */\n private readonly autoTranslateHook:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n\n /**\n * Optional reference to the vault-level hash-chained audit\n * log. When present, every successful `put()` and `delete()` appends\n * an entry to the ledger AFTER the adapter write succeeds (so a\n * failed adapter write never produces an orphan ledger entry).\n *\n * The ledger is always a vault-wide singleton — all\n * collections in the same vault share the same LedgerStore.\n * Vault.ledger() does the lazy init; this field just holds\n * the reference so Collection doesn't need to reach back up to the\n * vault on every mutation.\n *\n * `undefined` means \"no ledger attached\" — supported for tests that\n * construct a Collection directly without a vault, and for\n * future backwards-compat scenarios. Production usage always has a\n * ledger because Vault.collection() passes one through.\n */\n private readonly ledger: LedgerStore | undefined\n\n /** — per-collection CRDT mode, or undefined for normal LWW-at-record-level. */\n private readonly crdtMode: CrdtMode | undefined\n\n /** — optional remote/sync adapter for presence broadcasting. */\n private readonly syncAdapter: NoydbStore | undefined\n\n /** — consent-audit hook, no-op when no scope is active. */\n private readonly onAccess:\n | ((op: 'get' | 'put' | 'delete', id: string) => Promise<void>)\n | undefined\n\n /**\n * accounting-period write guard. Called BEFORE any\n * adapter write with:\n * - `existing` — the prior envelope's `_ts` and decrypted record\n * (or `null` if no prior envelope exists)\n * - `incoming` — the record being written (or `null` for delete)\n *\n * Throws `PeriodClosedError` if either side falls inside a closed\n * period. Installed by Vault; no-op when no period has been closed.\n * Async so the Vault can lazy-load the period list from the\n * adapter on first use.\n */\n private readonly periodGuard:\n | ((\n existing: { ts: string | null; record: Record<string, unknown> | null } | null,\n incoming: Record<string, unknown> | null,\n ) => Promise<void>)\n | undefined\n\n /**\n * Optional back-reference to the owning compartment's ref\n * enforcer. When present, `Collection.put` calls\n * `refEnforcer.enforceRefsOnPut(name, record)` before the adapter\n * write, and `Collection.delete` calls\n * `refEnforcer.enforceRefsOnDelete(name, id)` before its own\n * adapter delete. The Vault handles the actual registry\n * lookup and cross-collection enforcement — Collection just\n * notifies it at the right points in the lifecycle.\n *\n * Typed as a structural interface rather than `Vault`\n * directly to avoid a circular import. Vault implements\n * these two methods; any other object with the same shape would\n * work too (used only in unit tests).\n */\n private readonly refEnforcer:\n | {\n enforceRefsOnPut(collectionName: string, record: unknown): Promise<void>\n enforceRefsOnDelete(collectionName: string, id: string): Promise<void>\n }\n | undefined\n\n /**\n * Optional back-reference to the owning compartment's join resolver\n *`). When present,\n * `Collection.query()` builds a `JoinContext` that lets the Query\n * resolve `.join(field)` calls into target collections via this\n * resolver.\n *\n * Two methods:\n * - `resolveSource(name)` — fetch a `JoinableSource` for the\n * right-side collection by name. Returning `null` means \"no\n * such collection in this compartment\" — the executor then\n * throws an actionable error naming the missing target.\n * - `resolveRef(leftCollection, field)` — look up the ref\n * descriptor the left collection declared for this field.\n * `null` when the field has no ref, which makes `.join()`\n * throw at plan time before any records are touched.\n *\n * Typed structurally rather than as `Vault` to avoid a\n * circular import. Vault implements these two methods; any\n * other object with the same shape works too (used only in unit\n * tests against a plain object).\n */\n private readonly joinResolver:\n | {\n resolveSource(collectionName: string): JoinableSource | null\n resolveRef(leftCollection: string, field: string): RefDescriptor | null\n resolveDictSource?: (leftCollection: string, field: string) => JoinableSource | null\n }\n | undefined\n\n constructor(opts: {\n adapter: NoydbStore\n vault: string\n name: string\n keyring: UnlockedKeyring\n encrypted: boolean\n emitter: NoydbEventEmitter\n getDEK: (collectionName: string) => Promise<CryptoKey>\n historyConfig?: HistoryConfig | undefined\n onDirty?: OnDirtyCallback | undefined\n /**\n * tree-shake seam. When omitted, `collection.blob(id)` throws\n * with a pointer at the `@noy-db/hub/blobs` subpath. When set (via\n * `createNoydb({ blobStrategy: blobs() })`), blob storage is live.\n * `@internal` by virtue of `BlobStrategy` being `@internal`.\n */\n blobStrategy?: BlobStrategy | undefined\n aggregateStrategy?: AggregateStrategy | undefined\n crdtStrategy?: CrdtStrategy | undefined\n /**\n * tree-shake seam — strategy for optional history/ledger/\n * time-machine. When omitted, history snapshots and ledger appends\n * become silent no-ops (data still writes); the read APIs\n * (`history`, `getVersion`, `revert`, `diff`, `clearHistory`,\n * `pruneRecordHistory`) throw with a pointer at `@noy-db/hub/history`.\n */\n historyStrategy?: HistoryStrategy | undefined\n i18nStrategy?: I18nStrategy | undefined\n syncStrategy?: SyncStrategy | undefined\n /**\n * tree-shake seam. When omitted, indexing is off for this\n * collection — every `.lazyQuery()` call throws, `.rebuildIndexes()`\n * is a no-op, and `indexes: [...]` declarations are ignored. Enable\n * by passing `withIndexing()` from `@noy-db/hub/indexing` at\n * `createNoydb` time.\n */\n indexStrategy?: IndexStrategy | undefined\n indexes?: IndexDef[] | undefined\n /**\n * Auto-reconcile behavior for persisted-index drift on lazy-mode\n * collections. Defaults to `'off'` — operators call\n * `collection.reconcileIndex(field)` explicitly.\n *\n * - `'off'` (default): no implicit work. Same semantics as.\n * - `'dry-run'`: on first lazy-mode query, run\n * `reconcileIndex(field, { dryRun: true })` per declared field\n * and emit `index:reconciled` with the diff. Nothing is written.\n * - `'auto'`: same walk as `'dry-run'` but with `dryRun: false`.\n * Drift is repaired in-place and the fix count surfaces on the\n * event.\n *\n * Unattended long-lived processes (Workers, Node services with no\n * human operator) should set `'auto'`. Attended desktop apps should\n * leave it `'off'` and surface a manual \"rebuild indexes\" button.\n */\n reconcileOnOpen?: 'off' | 'dry-run' | 'auto'\n /**\n * Hydration mode. `'eager'` (default) loads everything into memory on\n * first access — matches behavior exactly. `'lazy'` defers loads\n * to per-id `get()` calls and bounds memory via the `cache` option.\n */\n prefetch?: boolean\n /**\n * LRU cache options. Only meaningful when `prefetch: false`. At least\n * one of `maxRecords` or `maxBytes` must be set in lazy mode — an\n * unbounded lazy cache defeats the purpose.\n */\n cache?: CacheOptions | undefined\n /**\n * Optional Standard Schema v1 validator (Zod, Valibot, ArkType,\n * Effect Schema, etc.). When set, every `put()` is validated before\n * encryption and every read is validated after decryption. See the\n * `schema` field docstring for the error semantics.\n */\n schema?: StandardSchemaV1<unknown, T> | undefined\n /**\n * Optional reference to the compartment's hash-chained ledger.\n * When present, successful mutations append a ledger entry via\n * `LedgerStore.append()`. Constructed at the Vault level and\n * threaded through — see the Vault.collection() source for\n * the wiring.\n */\n ledger?: LedgerStore | undefined\n /**\n * Optional back-reference to the owning compartment's ref\n * enforcer`).\n * Collection.put calls `enforceRefsOnPut` before the adapter\n * write; Collection.delete calls `enforceRefsOnDelete` before\n * its own adapter delete. See the `refEnforcer` field docstring\n * for the full protocol.\n */\n refEnforcer?:\n | {\n enforceRefsOnPut(collectionName: string, record: unknown): Promise<void>\n enforceRefsOnDelete(collectionName: string, id: string): Promise<void>\n }\n | undefined\n /**\n * Optional back-reference to the owning compartment's join\n * resolver. When present, `query()` builds a\n * `JoinContext` so `.join(field)` can resolve through the\n * existing `ref()` declaration into the target collection.\n * Absent in tests that construct a Collection directly without\n * a vault; production usage always has one because\n * Vault.collection() passes `this` through.\n */\n joinResolver?:\n | {\n resolveSource(collectionName: string): JoinableSource | null\n resolveRef(leftCollection: string, field: string): RefDescriptor | null\n }\n | undefined\n /** — i18nText field descriptors for locale-aware reads. */\n i18nFields?: Record<string, I18nTextDescriptor> | undefined\n /** — dictKey field descriptors for label resolution on reads. */\n dictKeyFields?: Record<string, DictKeyDescriptor> | undefined\n /**\n * async callback that resolves a dict key to its label\n * for a given locale. Provided by the Vault.\n */\n dictLabelResolver?:\n | ((\n dictName: string,\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ) => Promise<string | undefined>)\n | undefined\n /**\n * synchronous callback that validates i18nText fields\n * on put. Provided by the Vault. Throws MissingTranslationError.\n */\n i18nPutValidator?: ((record: unknown) => void) | undefined\n /**\n * translator callback from Noydb. When present, missing\n * translations for `autoTranslate: true` i18nText fields are generated\n * before the i18n validator runs.\n */\n autoTranslateHook?:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n /**\n * vault-default locale, inherited from\n * `openVault(name, { locale })` or `vault.setLocale()`.\n */\n defaultLocale?: string | undefined\n /**\n * collection-level conflict resolution policy.\n * Overrides the db-level `conflict` option for this collection only.\n */\n conflictPolicy?: ConflictPolicy<T> | undefined\n /**\n * callback to register an envelope-level resolver with the\n * SyncEngine. Provided by the Vault (wired from the SyncEngine).\n */\n onRegisterConflictResolver?: ((name: string, resolver: CollectionConflictResolver) => void) | undefined\n /**\n * CRDT mode for this collection. When set, `put()` stores\n * CRDT state in the envelope and `get()` returns the resolved snapshot.\n * `getRaw(id)` returns the full CRDT state for merge operations.\n */\n crdt?: CrdtMode | undefined\n /**\n * optional remote/sync adapter. When present, `presence()`\n * writes heartbeats to this adapter so other devices can read them.\n * If the adapter implements pub/sub, presence updates are real-time.\n */\n syncAdapter?: NoydbStore | undefined\n /**\n * called by the collection after every successful\n * `get` / `put` / `delete`. The Vault installs a callback that\n * appends a consent-audit entry when `withConsent` is active;\n * outside a consent scope the callback is a no-op. Awaited so a\n * thrown audit write surfaces to the caller.\n */\n onAccess?: (op: 'get' | 'put' | 'delete', id: string) => Promise<void>\n /**\n * invoked by `put`/`delete` before any adapter\n * write. Receives the prior envelope timestamp + decrypted\n * record (or `null` if no prior) and the incoming record (or\n * `null` for delete). Throws `PeriodClosedError` to abort.\n */\n /**\n * opt-in deterministic-encryption index.\n *\n * Field names listed here get a deterministic AES-GCM ciphertext\n * attached to every envelope's `_det` map, which enables blind\n * equality search via `collection.findByDet(field, value)`.\n *\n * **Leaks equality.** Two records with the same value in a\n * deterministic field produce identical ciphertexts, so anyone\n * with store access can tell which records share a value without\n * learning the value itself. This is the textbook trade-off of\n * deterministic encryption — strictly opt-in for that reason.\n *\n * Declaring any field here without also passing\n * `acknowledgeDeterministicRisk: true` throws at construction,\n * so the risk must be explicitly acknowledged.\n */\n deterministicFields?: readonly string[] | undefined\n /**\n * gate for `deterministicFields`. Must be `true` when\n * any deterministic field is declared. Any other value throws.\n */\n acknowledgeDeterministicRisk?: boolean | undefined\n /**\n * declared tiers this collection supports. An\n * undefined or empty list disables the hierarchical-tier surface\n * on this collection (`putAtTier`, `getAtTier`, `elevate`, `demote`\n * throw). Tier 0 is implicit and always available.\n */\n tiers?: readonly number[] | undefined\n /**\n * what a lower-tier caller sees for above-tier\n * records. Default `'invisibility'`.\n */\n tierMode?: TierMode | undefined\n /**\n * optional callback fired on every cross-tier access.\n * Provided by the Vault; collects notification events and writes\n * to the ledger.\n */\n onCrossTierAccess?: ((event: CrossTierAccessEvent) => void) | undefined\n periodGuard?: (\n existing: { ts: string | null; record: Record<string, unknown> | null } | null,\n incoming: Record<string, unknown> | null,\n ) => Promise<void>\n }) {\n this.adapter = opts.adapter\n this.vault = opts.vault\n this.name = opts.name\n this.keyring = opts.keyring\n this.encrypted = opts.encrypted\n this.emitter = opts.emitter\n this.blobStrategy = opts.blobStrategy ?? NO_BLOBS\n this.aggregateStrategy = opts.aggregateStrategy ?? NO_AGGREGATE\n this.crdtStrategy = opts.crdtStrategy ?? NO_CRDT\n this.historyStrategy = opts.historyStrategy ?? NO_HISTORY\n this.i18nStrategy = opts.i18nStrategy ?? NO_I18N\n this.syncStrategy = opts.syncStrategy ?? NO_SYNC\n this.reconcileOnOpen = opts.reconcileOnOpen ?? 'off'\n this.getDEK = opts.getDEK\n this.onDirty = opts.onDirty\n this.historyConfig = opts.historyConfig ?? { enabled: true }\n this.schema = opts.schema\n this.ledger = opts.ledger\n this.refEnforcer = opts.refEnforcer\n this.joinResolver = opts.joinResolver\n this.i18nFields = opts.i18nFields\n this.dictKeyFields = opts.dictKeyFields\n this.dictLabelResolver = opts.dictLabelResolver\n this.i18nPutValidator = opts.i18nPutValidator\n this.autoTranslateHook = opts.autoTranslateHook\n this.defaultLocale = opts.defaultLocale\n this.crdtMode = opts.crdt\n this.syncAdapter = opts.syncAdapter\n this.onAccess = opts.onAccess\n this.periodGuard = opts.periodGuard\n\n // hierarchical-tier wiring\n this.tiers = opts.tiers && opts.tiers.length > 0 ? new Set(opts.tiers) : null\n this.tierMode = opts.tierMode ?? 'invisibility'\n this.onCrossTierAccess = opts.onCrossTierAccess\n\n // deterministic-encryption wiring\n if (opts.deterministicFields && opts.deterministicFields.length > 0) {\n if (opts.acknowledgeDeterministicRisk !== true) {\n throw new Error(\n `Collection \"${opts.name}\": deterministicFields requires \\`acknowledgeDeterministicRisk: true\\`. ` +\n `Deterministic encryption leaks equality between records — two records with the same field value ` +\n `produce identical ciphertexts visible to anyone with store access. If that trade-off is acceptable ` +\n `for your threat model, set \\`acknowledgeDeterministicRisk: true\\` to enable.`,\n )\n }\n this.deterministicFields = Object.freeze(new Set(opts.deterministicFields))\n } else {\n this.deterministicFields = null\n }\n\n // register CRDT conflict resolver with SyncEngine\n if (opts.crdt && opts.onRegisterConflictResolver) {\n const crdtMode = opts.crdt\n const crdtResolver: CollectionConflictResolver = async (_id, local, remote) => {\n if (crdtMode === 'yjs') {\n // Core cannot merge Yjs without the yjs package — take the higher version\n return local._v >= remote._v ? local : remote\n }\n const localJson = await this.decryptJsonString(local)\n const remoteJson = await this.decryptJsonString(remote)\n const localState = JSON.parse(localJson) as CrdtState\n const remoteState = JSON.parse(remoteJson) as CrdtState\n const merged = this.crdtStrategy.mergeCrdtStates(localState, remoteState)\n const mergedVersion = Math.max(local._v, remote._v) + 1\n return this.encryptJsonString(JSON.stringify(merged), mergedVersion)\n }\n opts.onRegisterConflictResolver(this.name, crdtResolver)\n }\n\n // build and register per-collection conflict resolver with SyncEngine\n if (opts.conflictPolicy !== undefined && opts.onRegisterConflictResolver) {\n const policy = opts.conflictPolicy\n const compartmentName = this.vault\n const collectionName = this.name\n const emitter = this.emitter\n let resolver: CollectionConflictResolver\n\n if (policy === 'last-writer-wins') {\n resolver = async (_id, local, remote) => (local._ts >= remote._ts ? local : remote)\n } else if (policy === 'first-writer-wins') {\n resolver = async (_id, local, remote) => (local._v <= remote._v ? local : remote)\n } else if (policy === 'manual') {\n resolver = (id, local, remote) =>\n new Promise<EncryptedEnvelope | null>(resolvePromise => {\n let settled = false\n const resolveCallback = (winner: EncryptedEnvelope | null) => {\n if (!settled) {\n settled = true\n resolvePromise(winner)\n }\n }\n emitter.emit('sync:conflict', {\n vault: compartmentName,\n collection: collectionName,\n id,\n local,\n remote,\n localVersion: local._v,\n remoteVersion: remote._v,\n resolve: resolveCallback,\n })\n // Defer if no handler called resolve synchronously\n if (!settled) {\n settled = true\n resolvePromise(null)\n }\n })\n } else {\n // Custom merge fn: decrypt both → merge → re-encrypt\n const mergeFn = policy as (local: T, remote: T) => T\n resolver = async (_id, local, remote) => {\n const localRecord = await this.decryptRecord(local, { skipValidation: true })\n const remoteRecord = await this.decryptRecord(remote, { skipValidation: true })\n const merged = mergeFn(localRecord, remoteRecord)\n const mergedVersion = Math.max(local._v, remote._v) + 1\n return this.encryptRecord(merged, mergedVersion)\n }\n }\n\n opts.onRegisterConflictResolver(collectionName, resolver)\n }\n\n // Default `prefetch: true` keeps semantics. Only opt-in to lazy\n // mode when the consumer explicitly sets `prefetch: false`.\n this.lazy = opts.prefetch === false\n\n if (this.lazy) {\n if (!opts.cache || (opts.cache.maxRecords === undefined && opts.cache.maxBytes === undefined)) {\n throw new Error(\n `Collection \"${this.name}\": lazy mode (prefetch: false) requires a cache option ` +\n `with maxRecords and/or maxBytes. An unbounded lazy cache defeats the purpose.`,\n )\n }\n const lruOptions: { maxRecords?: number; maxBytes?: number } = {}\n if (opts.cache.maxRecords !== undefined) lruOptions.maxRecords = opts.cache.maxRecords\n if (opts.cache.maxBytes !== undefined) lruOptions.maxBytes = parseBytes(opts.cache.maxBytes)\n this.lru = new Lru<string, { record: T; version: number }>(lruOptions)\n this.hydrated = true // lazy mode is always \"hydrated\" — no bulk load\n } else {\n this.lru = null\n }\n\n // delegate mirror construction + declaration to the active\n // indexing strategy. `NO_INDEXING` returns a state whose accessors\n // both return null; the active strategy (from `@noy-db/hub/indexing`)\n // constructs the appropriate mirror based on lazy vs eager mode and\n // declares every IndexDef. With NO_INDEXING the heavy index classes\n // never reach the bundle.\n const strategy = opts.indexStrategy ?? NO_INDEXING\n this.indexState = strategy.createState({\n defs: opts.indexes ?? [],\n lazy: this.lazy,\n })\n }\n\n /**\n * Return the Standard Schema validator attached to this collection,\n * or `undefined` if none was provided at construction time.\n *\n * Exposed (read-only) for the Vault-level export primitive,\n * which surfaces each collection's schema in the per-chunk metadata\n * so downstream serializers (`@noy-db/as-*` packages, custom\n * exporters) can produce schema-aware output without poking at\n * collection internals. The validator object is returned by\n * reference — callers must treat it as immutable.\n */\n getSchema(): StandardSchemaV1<unknown, T> | undefined {\n return this.schema\n }\n\n /**\n * Get a single record by ID.\n *\n * @param id Record identifier.\n * @param locale Optional locale options. When provided,\n * `i18nText` fields are resolved to the requested locale\n * string, and `dictKey` fields get a `<field>Label`\n * virtual field added. Pass `{ locale: 'raw' }` to\n * return the full `{ [locale]: string }` map instead.\n *\n * @returns The decrypted (and optionally locale-resolved) record, or\n * `null` if not found.\n */\n async get(id: string, locale?: LocaleReadOptions): Promise<T | null> {\n let record: T | null\n\n if (this.lazy && this.lru) {\n // Cache hit: promote and return.\n const cached = this.lru.get(id)\n if (cached) {\n record = cached.record\n } else {\n // Cache miss: hit the adapter, decrypt, populate the LRU.\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) return null\n record = await this.decryptRecord(envelope)\n this.lru.set(id, { record, version: envelope._v }, estimateRecordBytes(record))\n }\n } else {\n // Eager mode: load everything once, then serve from the in-memory map.\n await this.ensureHydrated()\n const entry = this.cache.get(id)\n record = entry ? entry.record : null\n }\n\n if (record === null) return null\n await this.onAccess?.('get', id)\n return this.applyLocaleToRecord(record, locale)\n }\n\n /**\n * Return the raw CRDT state for a record.\n * Only available on collections configured with `crdt: 'lww-map' | 'rga' | 'yjs'`.\n * Use this for merge operations or to pass to `@noy-db/yjs`.\n * Throws if the collection is not in CRDT mode.\n */\n async getRaw(id: string): Promise<CrdtState | null> {\n if (!this.crdtMode) {\n throw new Error(\n `Collection \"${this.name}\": getRaw() is only available when the collection ` +\n `is created with a 'crdt' option ('lww-map', 'rga', or 'yjs').`,\n )\n }\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) return null\n const json = await this.decryptJsonString(envelope)\n return JSON.parse(json) as CrdtState\n }\n\n /**\n * Return a presence handle for this collection.\n *\n * The handle manages an encrypted ephemeral presence channel keyed by an\n * HKDF derivation of this collection's DEK. Presence payloads are invisible\n * to the adapter.\n *\n * @param opts.staleMs Milliseconds before a peer is considered inactive.\n * Default: 30 000.\n * @param opts.pollIntervalMs Milliseconds between storage polls (fallback mode).\n * Default: 5 000.\n */\n presence<P = unknown>(opts?: { staleMs?: number; pollIntervalMs?: number }): PresenceHandle<P> {\n const presenceOpts: PresenceHandleOpts = {\n adapter: this.adapter,\n vault: this.vault,\n collectionName: this.name,\n userId: this.keyring.userId,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n }\n if (this.syncAdapter !== undefined) presenceOpts.syncAdapter = this.syncAdapter\n if (opts?.staleMs !== undefined) presenceOpts.staleMs = opts.staleMs\n if (opts?.pollIntervalMs !== undefined) presenceOpts.pollIntervalMs = opts.pollIntervalMs\n return this.syncStrategy.buildPresence<P>(presenceOpts)\n }\n\n /** Create or update a record. */\n async put(id: string, record: T): Promise<void> {\n if (!hasWritePermission(this.keyring, this.name)) {\n throw new ReadOnlyError()\n }\n\n // accounting-period guard. Runs BEFORE any other\n // work so a closed-period write fails fast and leaves no partial\n // trace (no schema work, no i18n translation, no history). Reads\n // the existing envelope + decrypts the prior record so\n // business-date comparison against the closed period's\n // `dateField` can use the stored value (late entries don't slip\n // through a write-time check). For first-time inserts the prior\n // is null.\n if (this.periodGuard !== undefined) {\n const existingEnv = await this.adapter.get(this.vault, this.name, id)\n let priorRecord: Record<string, unknown> | null = null\n if (existingEnv) {\n try {\n priorRecord = (await this.decryptRecord(existingEnv, { skipValidation: true })) as unknown as Record<string, unknown>\n } catch {\n priorRecord = null\n }\n }\n await this.periodGuard(\n existingEnv ? { ts: existingEnv._ts, record: priorRecord } : null,\n record as unknown as Record<string, unknown>,\n )\n }\n\n // Schema validation — runs BEFORE encryption so invalid records are\n // rejected at the store boundary. The validator may transform the\n // input (e.g., coerce strings → numbers, strip unknown fields), in\n // which case we persist the validated value rather than the raw one.\n // Users who pass a bad shape get a SchemaValidationError with a\n // structured issue list, not a stack trace from deep inside the\n // encrypt path.\n if (this.schema !== undefined) {\n record = await validateSchemaInput(this.schema, record, `put(${id})`)\n }\n\n // Auto-translate missing i18nText translations.\n // Runs BEFORE i18n validation so translated values satisfy the\n // required-locale constraint. Throws TranslatorNotConfiguredError\n // when a field has autoTranslate: true but no hook was configured.\n if (this.i18nFields) {\n const obj = record as Record<string, unknown>\n for (const [field, descriptor] of Object.entries(this.i18nFields)) {\n if (!descriptor.options.autoTranslate) continue\n const value = obj[field]\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue\n const map = value as Record<string, string>\n // Determine which locales need translation. For 'all', translate all\n // declared languages that are missing. For 'any', only translate if\n // none are present. For string[], translate the listed required ones.\n const { languages, required } = descriptor.options\n const missing: string[] = languages.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length === 0) continue\n // Find a source locale (first present non-empty value)\n const sourceLocale = languages.find((l) => l in map && map[l] !== '')\n if (!sourceLocale) continue\n if (!this.autoTranslateHook) {\n throw new TranslatorNotConfiguredError(field, this.name)\n }\n // Only translate locales that are actually needed\n const toTranslate =\n required === 'any'\n ? [] // 'any' is already satisfied since sourceLocale exists\n : required === 'all'\n ? missing\n : missing.filter((l) => required.includes(l))\n const translated = { ...map }\n for (const targetLocale of toTranslate) {\n translated[targetLocale] = await this.autoTranslateHook(\n map[sourceLocale]!,\n sourceLocale,\n targetLocale,\n field,\n this.name,\n )\n }\n ;(record as Record<string, unknown>)[field] = translated\n }\n }\n\n // i18nText validation — runs AFTER schema validation so\n // the record shape is trustworthy. Throws MissingTranslationError\n // when required translations are absent.\n if (this.i18nPutValidator !== undefined) {\n this.i18nPutValidator(record)\n }\n\n // Foreign-key ref enforcement. Runs AFTER schema\n // validation (so the record shape is trustworthy) but BEFORE\n // any write (so a failed strict ref leaves no trace on disk,\n // in history, or in the ledger). The Vault handles the\n // actual target lookups — see `enforceRefsOnPut` over there.\n if (this.refEnforcer !== undefined) {\n await this.refEnforcer.enforceRefsOnPut(this.name, record)\n }\n\n // ─── CRDT mode ─────────────────────────────────────────\n // In CRDT mode we always read the raw envelope from the adapter to get\n // the existing CRDT state, merge the incoming record into it, then\n // encrypt the merged CRDT state — bypassing the normal version path.\n if (this.crdtMode) {\n const existingEnvelope = await this.adapter.get(this.vault, this.name, id)\n const existingVersion = existingEnvelope?._v ?? 0\n const now = new Date().toISOString()\n\n let crdtState: CrdtState\n\n if (this.crdtMode === 'lww-map') {\n let existingState: LwwMapState | undefined\n if (existingEnvelope) {\n const prevJson = await this.decryptJsonString(existingEnvelope)\n const prevParsed = JSON.parse(prevJson) as unknown\n if (prevParsed !== null && typeof prevParsed === 'object' && '_crdt' in prevParsed) {\n existingState = prevParsed as LwwMapState\n }\n }\n crdtState = this.crdtStrategy.buildLwwMapState(record as Record<string, unknown>, existingState, now)\n } else if (this.crdtMode === 'rga') {\n let existingState: RgaState | undefined\n if (existingEnvelope) {\n const prevJson = await this.decryptJsonString(existingEnvelope)\n const prevParsed = JSON.parse(prevJson) as unknown\n if (prevParsed !== null && typeof prevParsed === 'object' && '_crdt' in prevParsed) {\n existingState = prevParsed as RgaState\n }\n }\n const arr = Array.isArray(record) ? record : [record]\n crdtState = this.crdtStrategy.buildRgaState(arr, existingState, generateULID)\n } else {\n // yjs: record is the base64 update string (produced by @noy-db/yjs)\n crdtState = { _crdt: 'yjs', update: record as unknown as string }\n }\n\n const version = existingVersion + 1\n const envelope = await this.encryptJsonString(JSON.stringify(crdtState), version)\n await this.adapter.put(this.vault, this.name, id, envelope)\n\n // Resolve snapshot for cache and history\n const resolvedRecord = this.crdtStrategy.resolveCrdtSnapshot(crdtState) as T\n const existingResolved = existingEnvelope\n ? { record: await this.decryptRecord(existingEnvelope, { skipValidation: true }), version: existingVersion }\n : undefined\n\n if (existingResolved && this.historyConfig.enabled !== false) {\n const histEnvelope = await this.encryptRecord(existingResolved.record, existingResolved.version)\n await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, histEnvelope)\n this.emitter.emit('history:save', { vault: this.vault, collection: this.name, id, version: existingResolved.version })\n if (this.historyConfig.maxVersions) {\n await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, { keepVersions: this.historyConfig.maxVersions })\n }\n }\n\n if (this.ledger) {\n const appendInput: Parameters<typeof this.ledger.append>[0] = {\n op: 'put', collection: this.name, id, version, actor: this.keyring.userId,\n payloadHash: await this.historyStrategy.envelopePayloadHash(envelope),\n }\n if (existingResolved) appendInput.delta = this.historyStrategy.computePatch(resolvedRecord, existingResolved.record)\n await this.ledger.append(appendInput)\n }\n\n if (this.lazy && this.lru) {\n this.lru.set(id, { record: resolvedRecord, version }, estimateRecordBytes(resolvedRecord))\n await this.maintainPersistedIndexesOnPut(\n id,\n resolvedRecord,\n existingResolved ? existingResolved.record : null,\n version,\n )\n } else {\n this.cache.set(id, { record: resolvedRecord, version })\n this.indexes?.upsert(id, resolvedRecord, existingResolved ? existingResolved.record : null)\n }\n\n await this.onDirty?.(this.name, id, 'put', version)\n this.emitter.emit('change', { vault: this.vault, collection: this.name, id, action: 'put' } satisfies ChangeEvent)\n await this.onAccess?.('put', id)\n return\n }\n // ─── End CRDT mode ──────────────────────────────────────────────────\n\n // Resolve the previous record. In eager mode this comes from the\n // in-memory map (no I/O); in lazy mode we have to ask the adapter\n // because the record may have been evicted (or never loaded).\n let existing: { record: T; version: number } | undefined\n if (this.lazy && this.lru) {\n existing = this.lru.get(id)\n if (!existing) {\n const previousEnvelope = await this.adapter.get(this.vault, this.name, id)\n if (previousEnvelope) {\n const previousRecord = await this.decryptRecord(previousEnvelope)\n existing = { record: previousRecord, version: previousEnvelope._v }\n }\n }\n } else {\n await this.ensureHydrated()\n existing = this.cache.get(id)\n }\n\n const version = existing ? existing.version + 1 : 1\n\n // Save history snapshot of the PREVIOUS version before overwriting\n if (existing && this.historyConfig.enabled !== false) {\n const historyEnvelope = await this.encryptRecord(existing.record, existing.version)\n await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, historyEnvelope)\n\n this.emitter.emit('history:save', {\n vault: this.vault,\n collection: this.name,\n id,\n version: existing.version,\n })\n\n // Auto-prune if maxVersions configured\n if (this.historyConfig.maxVersions) {\n await this.historyStrategy.pruneHistory(this.adapter, this.vault, this.name, id, {\n keepVersions: this.historyConfig.maxVersions,\n })\n }\n }\n\n const envelope = await this.encryptRecord(record, version)\n await this.adapter.put(this.vault, this.name, id, envelope)\n\n // Ledger append — AFTER the adapter write succeeds so a failed\n // write never produces an orphan ledger entry. Computing the\n // payloadHash here uses the envelope we just wrote, which is the\n // exact bytes the adapter now holds. The ledger entry records\n // only metadata (collection, id, version, hash) — NOT the record\n // itself — and is then encrypted with the compartment's ledger\n // DEK, preserving zero-knowledge. See `LedgerStore.append`.\n //\n // **Delta history**: if there was a previous version, we\n // compute a JSON Patch from it to the new record and pass it\n // through `append.delta`. The LedgerStore stores the patch in\n // the sibling `_ledger_deltas/` collection and records its hash\n // in the entry's `deltaHash` field. Genesis puts (no existing\n // record) leave `delta` undefined — there's nothing to diff\n // against — and the ledger entry has no `deltaHash`.\n if (this.ledger) {\n const appendInput: Parameters<typeof this.ledger.append>[0] = {\n op: 'put',\n collection: this.name,\n id,\n version,\n actor: this.keyring.userId,\n payloadHash: await this.historyStrategy.envelopePayloadHash(envelope),\n }\n if (existing) {\n // REVERSE patch: describes how to undo this put — i.e., how\n // to transform the NEW record back into the PREVIOUS one.\n // Storing reverse patches lets `ledger.reconstruct()` walk\n // backward from the current state (readily available in the\n // data collection) without needing a forward-walking base\n // snapshot, which would double the storage cost of the\n // delta scheme. See `LedgerStore.reconstruct` for the walk.\n appendInput.delta = this.historyStrategy.computePatch(record, existing.record)\n }\n await this.ledger.append(appendInput)\n }\n\n if (this.lazy && this.lru) {\n this.lru.set(id, { record, version }, estimateRecordBytes(record))\n // Maintain persisted-index side-cars. Lazy mode is the\n // only place `persistedIndexes` is populated; eager mode uses the\n // in-memory `CollectionIndexes` above.\n await this.maintainPersistedIndexesOnPut(id, record, existing ? existing.record : null, version)\n } else {\n this.cache.set(id, { record, version })\n // Update secondary indexes incrementally — no-op if no indexes are\n // declared. Pass the previous record (if any) so old buckets are\n // cleaned up before the new value is added.\n this.indexes?.upsert(id, record, existing ? existing.record : null)\n }\n\n await this.onDirty?.(this.name, id, 'put', version)\n\n this.emitter.emit('change', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'put',\n } satisfies ChangeEvent)\n\n await this.onAccess?.('put', id)\n }\n\n /** Delete a record by ID. */\n async delete(id: string): Promise<void> {\n if (!hasWritePermission(this.keyring, this.name)) {\n throw new ReadOnlyError()\n }\n\n // accounting-period guard (same contract as put;\n // incoming is null because this is a delete).\n if (this.periodGuard !== undefined) {\n const existingEnv = await this.adapter.get(this.vault, this.name, id)\n let priorRecord: Record<string, unknown> | null = null\n if (existingEnv) {\n try {\n priorRecord = (await this.decryptRecord(existingEnv, { skipValidation: true })) as unknown as Record<string, unknown>\n } catch {\n priorRecord = null\n }\n }\n await this.periodGuard(\n existingEnv ? { ts: existingEnv._ts, record: priorRecord } : null,\n null,\n )\n }\n\n // Foreign-key ref enforcement on delete. Runs BEFORE\n // the adapter delete so a `strict` inbound ref with existing\n // references blocks the delete entirely (no partial state, no\n // history churn, no ledger entry for a rejected op). `cascade`\n // recursively deletes the referencing records first, then falls\n // through to the normal delete path below. `warn` is a no-op\n // here — violations surface through `checkIntegrity()`.\n if (this.refEnforcer !== undefined) {\n await this.refEnforcer.enforceRefsOnDelete(this.name, id)\n }\n\n // In lazy mode the record may not be cached; ask the adapter so we\n // can still write a history snapshot if history is enabled.\n let existing: { record: T; version: number } | undefined\n if (this.lazy && this.lru) {\n existing = this.lru.get(id)\n if (!existing && this.historyConfig.enabled !== false) {\n const previousEnvelope = await this.adapter.get(this.vault, this.name, id)\n if (previousEnvelope) {\n const previousRecord = await this.decryptRecord(previousEnvelope)\n existing = { record: previousRecord, version: previousEnvelope._v }\n }\n }\n } else {\n existing = this.cache.get(id)\n }\n\n // Save history snapshot before deleting\n if (existing && this.historyConfig.enabled !== false) {\n const historyEnvelope = await this.encryptRecord(existing.record, existing.version)\n await this.historyStrategy.saveHistory(this.adapter, this.vault, this.name, id, historyEnvelope)\n }\n\n // Capture the previous envelope's payloadHash BEFORE delete so we\n // have a stable reference for the ledger entry. The hash is of\n // whatever was last visible to readers — for a `delete` of a\n // never-existed record, we use the empty string (which the\n // ledger entry's `payloadHash` field tolerates).\n const previousEnvelope = await this.adapter.get(this.vault, this.name, id)\n const previousPayloadHash = await this.historyStrategy.envelopePayloadHash(previousEnvelope)\n\n await this.adapter.delete(this.vault, this.name, id)\n\n // Ledger append — same after-write timing as put(). The recorded\n // version is the version that WAS deleted (existing?.version), not\n // a successor. A delete of a missing record still appends an\n // entry with version 0 so the chain captures the intent.\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.name,\n id,\n version: existing?.version ?? 0,\n actor: this.keyring.userId,\n payloadHash: previousPayloadHash,\n })\n }\n\n if (this.lazy && this.lru) {\n this.lru.remove(id)\n // Tear down persisted-index side-cars for any declared fields on\n // this record. No-op when no fields are declared or the record\n // had never been indexed (e.g. a delete of a missing id).\n if (existing) {\n await this.maintainPersistedIndexesOnDelete(id, existing.record)\n }\n } else {\n this.cache.delete(id)\n // Remove from secondary indexes — no-op if no indexes are declared\n // or the record wasn't previously indexed.\n if (existing) {\n this.indexes?.remove(id, existing.record)\n }\n }\n\n await this.onDirty?.(this.name, id, 'delete', existing?.version ?? 0)\n\n this.emitter.emit('change', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'delete',\n } satisfies ChangeEvent)\n\n await this.onAccess?.('delete', id)\n }\n\n /**\n * List all records in the collection.\n *\n * Throws in lazy mode — bulk listing defeats the purpose of lazy\n * hydration. Use `scan()` to iterate over the full collection\n * page-by-page without holding more than `pageSize` records in memory.\n *\n * @param locale Optional locale options. When provided,\n * each record is locale-resolved before being returned.\n */\n async list(locale?: LocaleReadOptions): Promise<T[]> {\n if (this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": list() is not available in lazy mode (prefetch: false). ` +\n `Use collection.scan({ pageSize }) to iterate over the full collection.`,\n )\n }\n await this.ensureHydrated()\n const records = [...this.cache.values()].map(e => e.record)\n if (!locale) return records\n return Promise.all(records.map(r => this.applyLocaleToRecord(r, locale)))\n }\n\n // ─── Bulk operations ─────────────────────────────────────\n\n /**\n * Put many records in one call. Each item is processed sequentially\n * through the normal `put()` path — meaning per-item validation,\n * history snapshots, ledger appends, and change events all still\n * fire. The round-trip saving comes from the adapter staying hot\n * across the batch (no connection re-open, no keyring re-unlock).\n *\n * ## Semantics\n *\n * **Best-effort with per-item results.** If item 5 of 10 fails, items\n * 1–4 are already persisted and items 6–10 are still attempted.\n * The returned {@link PutManyResult} lists every success and failure\n * individually so the caller can decide whether to roll forward\n * (retry the failures) or roll back (manually delete the successes).\n *\n * **True tx-atomic putMany** — pass `{ atomic: true }` to switch\n * to the transaction executor: pre-flight CAS against every\n * item's `expectedVersion`, then commit all ops with best-effort\n * revert on mid-batch failure. Atomic mode throws on failure rather\n * than returning a mixed-results object.\n *\n * ## Change events\n *\n * One `change` event per successfully-written record, same as N\n * single-record puts. Subscribers don't need to special-case bulk.\n */\n async putMany(\n entries: ReadonlyArray<readonly [id: string, record: T, opts?: PutManyItemOptions]>,\n options?: PutManyOptions,\n ): Promise<PutManyResult> {\n if (options?.atomic) {\n return this.putManyAtomic(entries)\n }\n const success: string[] = []\n const failures: Array<{ id: string; error: Error }> = []\n for (const entry of entries) {\n const [id, record] = entry\n try {\n await this.put(id, record)\n success.push(id)\n } catch (error) {\n failures.push({ id, error: error as Error })\n }\n }\n return { ok: failures.length === 0, success, failures }\n }\n\n /**\n * Atomic-mode implementation of {@link putMany}. Pre-flights every\n * `expectedVersion`, executes all puts in declaration order, and\n * reverts executed ops via the raw adapter on mid-batch failure.\n * See `runTransaction` for the shared semantics + crash-window caveat.\n *\n * @internal\n */\n private async putManyAtomic(\n entries: ReadonlyArray<readonly [id: string, record: T, opts?: PutManyItemOptions]>,\n ): Promise<PutManyResult> {\n // Phase 1 — pre-flight CAS + prior-envelope snapshot for revert.\n const priors = new Map<string, EncryptedEnvelope | null>()\n for (const [id, , opts] of entries) {\n if (!priors.has(id)) {\n priors.set(id, await this.adapter.get(this.vault, this.name, id))\n }\n if (opts?.expectedVersion !== undefined) {\n const env = priors.get(id) ?? null\n const actual = env?._v ?? 0\n if (actual !== opts.expectedVersion) {\n throw new ConflictError(\n actual,\n `putMany atomic: ${this.vault}/${this.name}/${id} ` +\n `expected v${opts.expectedVersion}, found v${actual}`,\n )\n }\n }\n }\n // Phase 2 — execute; revert on failure.\n const executed: Array<{ id: string; prior: EncryptedEnvelope | null }> = []\n try {\n for (const [id, record] of entries) {\n await this.put(id, record)\n executed.push({ id, prior: priors.get(id) ?? null })\n }\n return { ok: true, success: executed.map((e) => e.id), failures: [] }\n } catch (err) {\n for (const { id, prior } of executed.slice().reverse()) {\n try {\n if (prior) await this.adapter.put(this.vault, this.name, id, prior)\n else await this.adapter.delete(this.vault, this.name, id)\n } catch { /* best-effort */ }\n }\n throw err\n }\n }\n\n /**\n * Get many records in one call. Returns a `Map<id, T | null>` —\n * missing records surface as `null` entries so the caller can\n * distinguish \"not found\" from \"lookup failed\". Order-stable\n * iteration (Map preserves insertion order = input `ids` order).\n *\n * Reads go through the per-id `get()` path, which means the cache\n * / hydration logic stays consistent with single-record reads.\n */\n async getMany(ids: readonly string[]): Promise<Map<string, T | null>> {\n const result = new Map<string, T | null>()\n for (const id of ids) {\n result.set(id, await this.get(id))\n }\n return result\n }\n\n /**\n * Delete many records in one call. Same best-effort contract as\n * {@link putMany}: if item 5 fails, items 1–4 are already deleted\n * and items 6–10 are still attempted.\n *\n * Deleting a non-existent id is not a failure — matches the\n * idempotent semantics of single-record `delete()`.\n */\n async deleteMany(ids: readonly string[]): Promise<DeleteManyResult> {\n const success: string[] = []\n const failures: Array<{ id: string; error: Error }> = []\n for (const id of ids) {\n try {\n await this.delete(id)\n success.push(id)\n } catch (error) {\n failures.push({ id, error: error as Error })\n }\n }\n return { ok: failures.length === 0, success, failures }\n }\n\n /**\n * Build a chainable query against the collection. Returns a `Query<T>`\n * builder when called with no arguments.\n *\n * Backward-compatible overload: passing a predicate function returns\n * the filtered records directly (the API). Prefer the chainable\n * form for new code.\n *\n * @example\n * ```ts\n * // New chainable API:\n * const overdue = invoices.query()\n * .where('status', '==', 'open')\n * .where('dueDate', '<', new Date())\n * .orderBy('dueDate')\n * .toArray();\n *\n * // Legacy predicate form (still supported):\n * const drafts = invoices.query(i => i.status === 'draft');\n * ```\n */\n query(): Query<T>\n query(predicate: (record: T) => boolean): T[]\n query(predicate?: (record: T) => boolean): Query<T> | T[] {\n if (this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": query() is not available in lazy mode (prefetch: false). ` +\n `Use collection.lazyQuery() for indexed reads, or collection.scan({ pageSize }) ` +\n `and filter the streamed records with a regular for-await loop.`,\n )\n }\n if (predicate !== undefined) {\n // Legacy form: synchronous predicate filter against the cache.\n return [...this.cache.values()].map(e => e.record).filter(predicate)\n }\n // New form: return a chainable builder bound to this collection's cache.\n const source: QuerySource<T> = {\n snapshot: () => [...this.cache.values()].map(e => e.record),\n subscribe: (cb: () => void) => {\n const handler = (event: ChangeEvent): void => {\n if (event.vault === this.vault && event.collection === this.name) {\n cb()\n }\n }\n this.emitter.on('change', handler)\n return () => this.emitter.off('change', handler)\n },\n // Index-aware fast path for `==` and `in` operators on indexed\n // fields. The Query builder consults these when present and falls\n // back to a linear scan otherwise.\n getIndexes: () => this.getIndexes(),\n lookupById: (id: string) => this.cache.get(id)?.record,\n }\n // Build a JoinContext if the vault passed a join resolver.\n // Without one, .join() on the resulting Query will throw with an\n // actionable error — the case is unreachable in production but\n // matters for unit tests that construct Collection directly.\n const resolver = this.joinResolver\n const leftCollection = this.name\n const joinContext: JoinContext | undefined = resolver\n ? {\n leftCollection,\n resolveRef: (field: string) => resolver.resolveRef(leftCollection, field),\n resolveSource: (collectionName: string) => resolver.resolveSource(collectionName),\n ...(resolver.resolveDictSource\n ? { resolveDictSource: (field: string) => resolver.resolveDictSource!(leftCollection, field) }\n : {}),\n }\n : undefined\n return new Query<T>(source, undefined, joinContext, this.aggregateStrategy)\n }\n\n /**\n * Subscribe to every put/delete on this collection. Returns an\n * unsubscribe function.\n *\n * Fires **after** the store write has committed — subscribers see\n * only materialised state, never in-flight or rolled-back writes.\n *\n * This is an event stream, not a reactive value. For reactive\n * \"current array state\" semantics use `query().live()`. Typical\n * use cases for `subscribe()`:\n * - audit-trail / activity-feed UI that lists events as they happen\n * - Pinia-per-collection wiring where each store subscribes once\n * - outbox-style workers that process every new record\n *\n * The callback receives a `CollectionChangeEvent<T>`:\n * - `{ type: 'put', id, record }` — record is the current\n * decrypted value. May be `null` if another op deleted the\n * record between the emit and the handler firing (rare race).\n * - `{ type: 'delete', id, record: null }` — deletion event;\n * the record content is gone by the time the handler runs.\n *\n * The callback is invoked synchronously *with respect to the emit\n * moment*, but the record lookup is async (cache hit for eager\n * collections; one `get()` for lazy collections). If your handler\n * does not need the record, cast it away and ignore — the lookup\n * is still performed, but it's cheap on the hydrated path.\n *\n * ergonomic wrapper over `db.on('change', …)` that\n * filters to this collection and hydrates the record.\n */\n subscribe(cb: (event: CollectionChangeEvent<T>) => void): () => void {\n const handler = (event: ChangeEvent): void => {\n if (event.vault !== this.vault || event.collection !== this.name) return\n if (event.action === 'put') {\n // Cache hit in eager mode; get() in lazy mode.\n void this.get(event.id).then(record => {\n cb({ type: 'put', id: event.id, record: record ?? null })\n }).catch(() => {\n // Record vanished between emit + lookup (race). Emit with null\n // so subscribers still see the event they were promised.\n cb({ type: 'put', id: event.id, record: null })\n })\n } else {\n // delete\n cb({ type: 'delete', id: event.id, record: null })\n }\n }\n this.emitter.on('change', handler)\n return () => {\n this.emitter.off('change', handler)\n }\n }\n\n /**\n * Return a minimal JoinableSource view of this collection's\n * in-memory cache. Used by the Vault's `resolveSource`\n * method when another collection's `.join()` needs to probe this\n * one as the right side.\n *\n * The returned object captures the cache reference through a\n * closure, so subsequent mutations to the cache are visible to\n * the joined query. That's intentional: a join that fires after\n * the right-side collection has been updated should see the\n * fresh data.\n *\n * Throws in lazy mode because the cache is bounded and could\n * silently miss records — consistent with the `query()` /\n * `list()` lazy-mode policy. If this becomes a blocker for a\n * real consumer, the fix is to add an async `scan()`-backed\n * variant of this method, which is exactly what streaming\n * joins will need anyway.\n */\n querySourceForJoin(): JoinableSource {\n if (this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": .join() cannot use a lazy-mode ` +\n `collection as the right side. Opening it in eager mode ` +\n `(prefetch: true, default) makes it joinable. Streaming joins ` +\n `over lazy collections are not yet supported.`,\n )\n }\n // Structural source — the join executor calls snapshot() and\n // lookupById(); the live-join executor additionally calls\n // subscribe() so right-side mutations propagate. We capture\n // `this.cache` and `this.emitter` by closure so later mutations\n // are visible to the snapshot view AND drive live re-fires.\n return {\n snapshot: () => [...this.cache.values()].map(e => e.record),\n lookupById: (id: string) => this.cache.get(id)?.record,\n subscribe: (cb: () => void) => {\n const handler = (event: ChangeEvent): void => {\n if (event.vault === this.vault && event.collection === this.name) {\n cb()\n }\n }\n this.emitter.on('change', handler)\n return () => this.emitter.off('change', handler)\n },\n }\n }\n\n /**\n * Cache statistics — useful for devtools, monitoring, and verifying\n * that LRU eviction is happening as expected in lazy mode.\n *\n * In eager mode, returns size only (no hits/misses are tracked because\n * every read is a cache hit by construction). In lazy mode, returns\n * the full LRU stats: `{ hits, misses, evictions, size, bytes }`.\n */\n cacheStats(): CacheStats {\n if (this.lazy && this.lru) {\n return { ...this.lru.stats(), lazy: true }\n }\n return {\n hits: 0,\n misses: 0,\n evictions: 0,\n size: this.cache.size,\n bytes: 0,\n lazy: false,\n }\n }\n\n // ─── History Methods ────────────────────────────────────────────\n\n /** Get version history for a record, newest first. */\n async history(id: string, options?: HistoryOptions): Promise<HistoryEntry<T>[]> {\n const envelopes = await this.historyStrategy.getHistoryEntries(\n this.adapter, this.vault, this.name, id, options,\n )\n\n const entries: HistoryEntry<T>[] = []\n for (const env of envelopes) {\n // History reads skip schema validation — see getVersion() docs.\n const record = await this.decryptRecord(env, { skipValidation: true })\n entries.push({\n version: env._v,\n timestamp: env._ts,\n userId: env._by ?? '',\n record,\n })\n }\n return entries\n }\n\n /**\n * Get a specific past version of a record.\n *\n * History reads intentionally **skip schema validation** — historical\n * records predate the current schema by definition, so validating them\n * against today's shape would be a false positive on any schema\n * evolution. If a caller needs validated history, they should filter\n * and re-put the records through the normal `put()` path.\n */\n async getVersion(id: string, version: number): Promise<T | null> {\n const envelope = await this.historyStrategy.getVersionEnvelope(\n this.adapter, this.vault, this.name, id, version,\n )\n if (!envelope) return null\n return this.decryptRecord(envelope, { skipValidation: true })\n }\n\n /** Revert a record to a past version. Creates a new version with the old content. */\n async revert(id: string, version: number): Promise<void> {\n const oldRecord = await this.getVersion(id, version)\n if (!oldRecord) {\n throw new Error(`Version ${version} not found for record \"${id}\"`)\n }\n await this.put(id, oldRecord)\n }\n\n /**\n * Compare two versions of a record and return the differences.\n * Use version 0 to represent \"before creation\" (empty).\n * Omit versionB to compare against the current version.\n */\n async diff(id: string, versionA: number, versionB?: number): Promise<DiffEntry[]> {\n const recordA = versionA === 0 ? null : await this.resolveVersion(id, versionA)\n const recordB = versionB === undefined || versionB === 0\n ? (versionB === 0 ? null : await this.resolveCurrentOrVersion(id))\n : await this.resolveVersion(id, versionB)\n return this.historyStrategy.diff(recordA, recordB)\n }\n\n /** Resolve a version: try history first, then check if it's the current version. */\n private async resolveVersion(id: string, version: number): Promise<T | null> {\n // Check history\n const fromHistory = await this.getVersion(id, version)\n if (fromHistory) return fromHistory\n // Check if it's the current live version\n await this.ensureHydrated()\n const current = this.cache.get(id)\n if (current && current.version === version) return current.record\n return null\n }\n\n private async resolveCurrentOrVersion(id: string): Promise<T | null> {\n await this.ensureHydrated()\n return this.cache.get(id)?.record ?? null\n }\n\n /** Prune history entries for a record (or all records if id is undefined). */\n async pruneRecordHistory(id: string | undefined, options: PruneOptions): Promise<number> {\n const pruned = await this.historyStrategy.pruneHistory(\n this.adapter, this.vault, this.name, id, options,\n )\n if (pruned > 0) {\n this.emitter.emit('history:prune', {\n vault: this.vault,\n collection: this.name,\n id: id ?? '*',\n pruned,\n })\n }\n return pruned\n }\n\n /** Clear all history for this collection (or a specific record). */\n async clearHistory(id?: string): Promise<number> {\n return this.historyStrategy.clearHistory(this.adapter, this.vault, this.name, id)\n }\n\n // ─── Core Methods ─────────────────────────────────────────────\n\n /**\n * Count records in the collection.\n *\n * In eager mode this returns the in-memory cache size (instant). In\n * lazy mode it asks the adapter via `list()` to enumerate ids — slower\n * but still correct, and avoids loading any record bodies into memory.\n */\n async count(): Promise<number> {\n if (this.lazy) {\n const ids = await this.adapter.list(this.vault, this.name)\n return ids.length\n }\n await this.ensureHydrated()\n return this.cache.size\n }\n\n // ─── Pagination & Streaming ───────────────────────────────────\n\n /**\n * Fetch a single page of records via the adapter's optional `listPage`\n * extension. Returns the decrypted records for this page plus an opaque\n * cursor for the next page.\n *\n * Pass `cursor: undefined` (or omit it) to start from the beginning.\n * The final page returns `nextCursor: null`.\n *\n * If the adapter does NOT implement `listPage`, this falls back to a\n * synthetic implementation: it loads all ids via `list()`, sorts them,\n * and slices a window. The first call emits a one-time console.warn so\n * developers can spot adapters that should opt into the fast path.\n */\n async listPage(opts: { cursor?: string; limit?: number } = {}): Promise<{\n items: T[]\n nextCursor: string | null\n }> {\n const limit = opts.limit ?? 100\n\n if (this.adapter.listPage) {\n const result = await this.adapter.listPage(this.vault, this.name, opts.cursor, limit)\n const decrypted: T[] = []\n for (const { record, version, id } of await this.decryptPage(result.items)) {\n // Update cache opportunistically — if the page-fetched record isn't\n // in cache yet, populate it. This makes a subsequent .get(id) free.\n // In LAZY mode we deliberately do NOT populate the LRU here:\n // streaming a 100K-record collection should not turn the LRU into\n // a giant write-once buffer that immediately evicts everything.\n // Random-access workloads via .get() are what the LRU is for.\n if (!this.lazy && !this.cache.has(id)) {\n this.cache.set(id, { record, version })\n }\n decrypted.push(record)\n }\n return { items: decrypted, nextCursor: result.nextCursor }\n }\n\n // Fallback: synthetic pagination over list() + get(). Slower than the\n // native path because every id requires its own round-trip, but\n // correct for adapters that haven't opted in.\n warnOnceFallback(this.adapter.name ?? 'unknown')\n const ids = (await this.adapter.list(this.vault, this.name)).slice().sort()\n const start = opts.cursor ? parseInt(opts.cursor, 10) : 0\n const end = Math.min(start + limit, ids.length)\n const items: T[] = []\n for (let i = start; i < end; i++) {\n const id = ids[i]!\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (envelope) {\n const record = await this.decryptRecord(envelope)\n items.push(record)\n // Same lazy-mode skip as the native path: don't pollute the LRU\n // with sequential scan results.\n if (!this.lazy && !this.cache.has(id)) {\n this.cache.set(id, { record, version: envelope._v })\n }\n }\n }\n return {\n items,\n nextCursor: end < ids.length ? String(end) : null,\n }\n }\n\n /**\n * Stream every record in the collection page-by-page as an async\n * iterable, with chainable `.where()` / `.filter()` clauses and a\n * memory-bounded `.aggregate(spec)` terminal.\n *\n * The whole point: process collections larger than RAM without\n * ever holding more than `pageSize` records decrypted at once.\n *\n * @example\n * ```ts\n * // Backward-compatible iteration — unchanged from the previous\n * // async-generator shape. `ScanBuilder` implements AsyncIterable.\n * for await (const record of invoices.scan({ pageSize: 500 })) {\n * await processOne(record)\n * }\n *\n * // — streaming aggregation with O(reducers) memory.\n * const { total, n } = await invoices.scan()\n * .where('year', '==', 2025)\n * .aggregate({ total: sum('amount'), n: count() })\n * ```\n *\n * Returns a `ScanBuilder<T>` instead of the raw async iterator\n * that previous versions used. The builder implements\n * `AsyncIterable<T>`, so every existing `for await … of` call\n * continues to work unchanged. Direct `.next()` calls on the\n * iterator — not idiomatic, not used in the codebase — are no\n * longer supported; upgrade to `for await` or call the new\n * `.aggregate()` terminal.\n *\n * Uses `adapter.listPage` when available; otherwise falls back\n * to the synthetic pagination path with the same one-time\n * warning (`listPage()` routes through that fallback internally).\n */\n scan(opts: { pageSize?: number } = {}): ScanBuilder<T> {\n const pageSize = opts.pageSize ?? 100\n // Build a JoinContext if the vault passed a join resolver\n // — same machinery as `query()`. Without one, `.join()`\n // on the resulting ScanBuilder will throw with an actionable\n // error. The resolver is unreachable in production but matters\n // for unit tests that construct Collection directly.\n const resolver = this.joinResolver\n const leftCollection = this.name\n const joinContext: JoinContext | undefined = resolver\n ? {\n leftCollection,\n resolveRef: (field: string) => resolver.resolveRef(leftCollection, field),\n resolveSource: (collectionName: string) => resolver.resolveSource(collectionName),\n ...(resolver.resolveDictSource\n ? { resolveDictSource: (field: string) => resolver.resolveDictSource!(leftCollection, field) }\n : {}),\n }\n : undefined\n // The page provider closure is bound to this collection's\n // listPage method so the builder is free of any `this`\n // coupling. Rebinding through the arrow keeps the unbound-\n // method lint rule happy — matches the pattern used in\n // builder.ts's candidateRecords helper.\n return new ScanBuilder<T>(\n {\n listPage: (listOpts) => this.listPage(listOpts),\n },\n pageSize,\n [],\n [],\n joinContext,\n )\n }\n\n /** Decrypt a page of envelopes returned by `adapter.listPage`. */\n private async decryptPage(\n items: ListPageResult['items'],\n ): Promise<Array<{ id: string; record: T; version: number }>> {\n const out: Array<{ id: string; record: T; version: number }> = []\n for (const { id, envelope } of items) {\n const record = await this.decryptRecord(envelope)\n out.push({ id, record, version: envelope._v })\n }\n return out\n }\n\n // ─── Internal ──────────────────────────────────────────────────\n\n /** Load all records from adapter into memory cache. */\n private async ensureHydrated(): Promise<void> {\n if (this.hydrated) return\n\n const ids = await this.adapter.list(this.vault, this.name)\n for (const id of ids) {\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (envelope) {\n const record = await this.decryptRecord(envelope)\n this.cache.set(id, { record, version: envelope._v })\n }\n }\n this.hydrated = true\n this.rebuildEagerIndexesFromCache()\n }\n\n /** Hydrate from a pre-loaded snapshot (used by Vault). */\n async hydrateFromSnapshot(records: Record<string, EncryptedEnvelope>): Promise<void> {\n for (const [id, envelope] of Object.entries(records)) {\n const record = await this.decryptRecord(envelope)\n this.cache.set(id, { record, version: envelope._v })\n }\n this.hydrated = true\n this.rebuildEagerIndexesFromCache()\n }\n\n /**\n * Rebuild secondary indexes from the current in-memory cache.\n *\n * Called after any bulk hydration. Incremental put/delete updates\n * are handled by `indexes.upsert()` / `indexes.remove()` directly,\n * so this only fires for full reloads.\n *\n * Synchronous and O(N × indexes.size); for the target scale of\n * 1K–50K records this completes in single-digit milliseconds.\n */\n private rebuildEagerIndexesFromCache(): void {\n const eager = this.indexes\n if (!eager || eager.fields().length === 0) return\n const snapshot: Array<{ id: string; record: T }> = []\n for (const [id, entry] of this.cache) {\n snapshot.push({ id, record: entry.record })\n }\n eager.build(snapshot)\n }\n\n /**\n * Rebuild every declared index from scratch.\n *\n * Eager mode: refreshes the in-memory `CollectionIndexes` from the\n * current cache — O(records × declaredFields).\n *\n * Lazy mode: tears down every `_idx/<field>/<recordId>`\n * side-car, walks the canonical record namespace, and materialises\n * fresh side-cars for every declared field. The in-memory mirror is\n * cleared and re-ingested. Intended for two scenarios:\n * 1. Adding a new indexed field to a collection that already holds\n * records — after the schema change, call `rebuildIndexes()` to\n * backfill the side-cars.\n * 2. Recovery from a catastrophic drift (audit noticed many\n * `index:write-partial` events, operator wants a clean slate).\n *\n * The rebuild is NOT incremental — it's a full bulk-replace. For\n * per-field drift repair, use `reconcileIndex(field)` instead.\n */\n async rebuildIndexes(): Promise<void> {\n if (!this.lazy) {\n await this.ensureHydrated()\n this.rebuildEagerIndexesFromCache()\n return\n }\n\n const persisted = this.persistedIndexes\n if (!persisted) return\n const fields = persisted.fields()\n if (fields.length === 0) return\n\n // 1. Collect canonical ids (skip every reserved-namespace id —\n // `_idx/`, `_keyring`, `_history/`, `_ledger_deltas/`, `_meta/`,\n // `_ledger`, `_blob_`, etc. User records may not start with `_`\n // per the monorepo convention used across the hub).\n const allIds = await this.adapter.list(this.vault, this.name)\n const canonicalIds: string[] = []\n const staleIdxIds: string[] = []\n for (const id of allIds) {\n if (decodeIdxId(id)) {\n staleIdxIds.push(id)\n } else if (!id.startsWith('_')) {\n canonicalIds.push(id)\n }\n }\n\n // 2. Drop every existing side-car. Errors here are tolerated — the\n // next step overwrites any remnants. If a side-car is for a\n // field that is no longer declared, the delete still removes\n // the stale row from storage.\n for (const id of staleIdxIds) {\n try { await this.adapter.delete(this.vault, this.name, id) } catch { /* ignore */ }\n }\n persisted.clear()\n\n // 3. Walk records and write fresh side-cars for every declared field.\n for (const recordId of canonicalIds) {\n const envelope = await this.adapter.get(this.vault, this.name, recordId)\n if (!envelope) continue\n const record = await this.decryptRecord(envelope, { skipValidation: true })\n await this.maintainPersistedIndexesOnPut(recordId, record, null, envelope._v)\n }\n\n this.persistedIndexesLoaded = true\n }\n\n /**\n * Compare the persisted `_idx/<field>/*` side-cars against the\n * canonical records for a single field, reporting the drift (and\n * optionally repairing it).\n *\n * Lazy mode only. Eager mode throws — the in-memory index cannot\n * drift.\n *\n * `missing` — record ids whose value is indexable but no side-car\n * exists. Happens when a `put()` succeeded but the side-car put\n * failed (surfaced as `index:write-partial`).\n * `stale` — side-car ids pointing to a record that no longer exists\n * or whose current value no longer matches the side-car body.\n * `applied` — number of writes that were actually applied (always 0\n * when `dryRun: true`).\n *\n * Design reference: acceptance criteria.\n */\n async reconcileIndex(\n field: string,\n opts: { dryRun?: boolean } = {},\n ): Promise<{ field: string; missing: string[]; stale: string[]; applied: number }> {\n if (!this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": reconcileIndex is only meaningful in lazy mode ` +\n `(prefetch: false). Eager mode maintains indexes in memory with no drift.`,\n )\n }\n const persisted = this.persistedIndexes\n if (!persisted) {\n throw new Error(\n `Collection \"${this.name}\": indexing is disabled on this Noydb instance. ` +\n `Pass \\`withIndexing()\\` from \"@noy-db/hub/indexing\" to \\`createNoydb({ indexStrategy })\\`.`,\n )\n }\n if (!persisted.has(field)) {\n throw new Error(\n `Collection \"${this.name}\": field \"${field}\" is not declared in indexes. ` +\n `Declare it in the collection options before reconciling.`,\n )\n }\n\n const dryRun = opts.dryRun === true\n const allIds = await this.adapter.list(this.vault, this.name)\n\n // Map side-car recordId → stored value (if readable). Also capture\n // \"stale\" side-cars whose field matches but whose record is gone.\n const sidecar = new Map<string, unknown>()\n const sidecarIds = new Map<string, string>() // recordId -> sidecar id\n for (const id of allIds) {\n const decoded = decodeIdxId(id)\n if (!decoded || decoded.field !== field) continue\n sidecarIds.set(decoded.recordId, id)\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) continue\n try {\n const body = JSON.parse(await this.decryptJsonString(env)) as { value: unknown }\n sidecar.set(decoded.recordId, body.value)\n } catch {\n // Unreadable — treat as stale so it gets rewritten.\n sidecar.set(decoded.recordId, undefined)\n }\n }\n\n // Walk canonical records and compare against side-car state.\n const missing: string[] = []\n const stale: string[] = []\n const fixesPut: Array<{ recordId: string; record: T; version: number }> = []\n for (const id of allIds) {\n if (decodeIdxId(id)) continue\n if (id.startsWith('_')) continue\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) continue\n const record = await this.decryptRecord(env, { skipValidation: true })\n const live = readPersistedValue(record as unknown as Record<string, unknown>, field)\n const stored = sidecar.get(id)\n const hasSidecar = sidecarIds.has(id)\n const indexable = live !== null && live !== undefined\n\n if (indexable && !hasSidecar) {\n missing.push(id)\n fixesPut.push({ recordId: id, record, version: env._v })\n } else if (indexable && hasSidecar && !valuesMatch(stored, live)) {\n // Side-car body drifted from live value (e.g. partial write\n // after an update). Rewrite so lookups agree with reality.\n missing.push(id)\n fixesPut.push({ recordId: id, record, version: env._v })\n } else if (!indexable && hasSidecar) {\n // Record exists but its value is no longer indexable (null/\n // undefined). The side-car is stale.\n stale.push(sidecarIds.get(id)!)\n }\n sidecarIds.delete(id)\n }\n // Any side-car whose canonical record vanished is stale.\n for (const [, idxId] of sidecarIds) stale.push(idxId)\n\n let applied = 0\n if (!dryRun) {\n for (const idxId of stale) {\n try {\n await this.adapter.delete(this.vault, this.name, idxId)\n applied++\n } catch { /* ignore — next reconcile picks it up */ }\n }\n for (const fix of fixesPut) {\n await this.maintainPersistedIndexesOnPut(fix.recordId, fix.record, null, fix.version)\n applied++\n }\n // In-memory mirror is authoritative for query dispatch — make\n // sure it matches what's on disk now.\n persisted.clear()\n this.persistedIndexesLoaded = false\n await this.ensurePersistedIndexesLoaded()\n }\n\n return { field, missing, stale, applied }\n }\n\n /**\n * Get the in-memory index store. Used by `Query` to short-circuit\n * `==` and `in` lookups when an index covers the where clause.\n *\n * Returns `null` if no indexes are declared on this collection.\n */\n getIndexes(): CollectionIndexes | null {\n const eager = this.indexes\n return eager && eager.fields().length > 0 ? eager : null\n }\n\n /**\n * Return a `BlobSet` for the given record id.\n *\n * No I/O is performed until you call a method on the handle.\n *\n * ```ts\n * const blobs = invoices.blob('inv-001')\n *\n * // Upload a PDF (deduplicates automatically, MIME auto-detected)\n * await blobs.put('receipt.pdf', pdfBytes)\n *\n * // List slots\n * const files = await blobs.list() // SlotInfo[]\n *\n * // Serve as HTTP response (Content-Type, ETag, streaming body)\n * const res = await blobs.response('receipt.pdf', { inline: true })\n *\n * // Publish a named version (amendment versioning)\n * await blobs.publish('receipt.pdf', 'issued-2025-01')\n *\n * // Raw bytes\n * const bytes = await blobs.get('receipt.pdf')\n * ```\n *\n * Blobs are stored in internal collections (`_blob_slots_*`, `_blob_index`,\n * `_blob_chunks`, `_blob_versions_*`) that are excluded from queries and\n * `list()`. Slot metadata uses this collection's DEK; chunk data uses a\n * vault-shared `_blob` DEK (enabling cross-collection deduplication).\n */\n blob(id: string): BlobSet {\n // tree-shake refactor: delegate to `blobStrategy`. The default\n // is `NO_BLOBS` (throws with a message pointing at the `@noy-db/hub/blobs`\n // subpath). Users who want blob storage pass `blobs()` from that\n // subpath into `createNoydb({ blobStrategy: blobs() })`, which\n // threads the active strategy through Vault → Collection.\n return this.blobStrategy.openSlot({\n store: this.adapter,\n vault: this.vault,\n collection: this.name,\n recordId: id,\n getDEK: this.getDEK,\n encrypted: this.encrypted,\n userId: this.keyring.userId,\n })\n }\n\n /** Get all records as encrypted envelopes (for dump). */\n async dumpEnvelopes(): Promise<Record<string, EncryptedEnvelope>> {\n await this.ensureHydrated()\n const result: Record<string, EncryptedEnvelope> = {}\n for (const [id, entry] of this.cache) {\n result[id] = await this.encryptRecord(entry.record, entry.version)\n }\n return result\n }\n\n /**\n * Apply locale resolution to a record.\n *\n * Called from `get()` and `list()` when locale options are present.\n * Uses the effective locale: per-call `locale` takes precedence over\n * `this.defaultLocale`.\n *\n * - i18nText fields: replaced with the resolved string (or the full\n * map when `locale === 'raw'`).\n * - dictKey fields: `<field>Label` virtual fields added.\n *\n * Returns the record unchanged when no locale is active and no i18n/dict\n * fields are registered.\n */\n private async applyLocaleToRecord(\n record: T,\n localeOpts?: LocaleReadOptions,\n ): Promise<T> {\n const hasI18n = this.i18nFields && Object.keys(this.i18nFields).length > 0\n const hasDict = this.dictKeyFields && Object.keys(this.dictKeyFields).length > 0\n if (!hasI18n && !hasDict) return record\n\n const locale = localeOpts?.locale ?? this.defaultLocale\n if (!locale) return record\n\n let result = record as unknown as Record<string, unknown>\n\n // 1. i18nText resolution\n if (hasI18n && this.i18nFields) {\n result = this.i18nStrategy.applyI18nLocale(result, this.i18nFields, locale, localeOpts?.fallback)\n }\n\n // 2. dictKey label resolution\n if (hasDict && this.dictKeyFields && this.dictLabelResolver && locale !== 'raw') {\n const withLabels = { ...result }\n for (const [field, desc] of Object.entries(this.dictKeyFields)) {\n const key = result[field]\n if (typeof key !== 'string') continue\n const label = await this.dictLabelResolver(\n desc.name,\n key,\n locale,\n localeOpts?.fallback,\n )\n if (label !== undefined) {\n withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n return result as T\n }\n\n /**\n * Low-level: encrypt a pre-serialised JSON string into an EncryptedEnvelope.\n * Used by both the normal record path and the CRDT path (which serialises\n * a CrdtState rather than a T).\n */\n /**\n * Write / update / delete the `_idx/<field>/<recordId>` side-cars for\n * every declared persistence-index field on this collection after a\n * successful main-record `put()`.\n *\n * Timing: called AFTER `adapter.put()` of the main record succeeds, so\n * a failed main write never leaves a stale index entry. Side-car write\n * failures do NOT fail the overall `put()` — the main record is already\n * durably committed. Per-field failures surface as\n * `IndexWriteFailureError` on the emitter's `index:write-partial`\n * channel and the operator runs a reconcile pass later.\n *\n * Null/undefined field values are not indexed — matches the\n * `PersistedCollectionIndex.stringifyKey` contract. If the prior value\n * was non-null and the new value is null, the side-car is deleted.\n */\n private async maintainPersistedIndexesOnPut(\n id: string,\n newRecord: T,\n previousRecord: T | null,\n version: number,\n ): Promise<void> {\n const persisted = this.persistedIndexes\n if (!persisted) return\n const defs = persisted.definitions()\n if (defs.length === 0) return\n\n const newRec = newRecord as unknown as Record<string, unknown>\n const prevRec = previousRecord as unknown as Record<string, unknown> | null\n\n for (const def of defs) {\n const newValue = extractIndexValue(newRec, def)\n const previousValue = prevRec ? extractIndexValue(prevRec, def) : null\n\n // Update the in-memory mirror first — it's the authoritative source\n // for query dispatch. If the adapter write below fails, the mirror\n // still reflects intended state; the reconciler compares mirror\n // against side-cars on next run.\n persisted.upsert(id, def.key, newValue, previousValue)\n\n const idxId = encodeIdxId(def.key, id)\n try {\n if (newValue === null || newValue === undefined) {\n // Clear any pre-existing side-car for this (field, record).\n if (previousValue !== null && previousValue !== undefined) {\n await this.adapter.delete(this.vault, this.name, idxId)\n }\n } else {\n const body = JSON.stringify({\n field: def.key,\n value: serializeIndexValue(newValue),\n recordId: id,\n writtenAt: new Date().toISOString(),\n })\n const envelope = await this.encryptJsonString(body, version)\n await this.adapter.put(this.vault, this.name, idxId, envelope)\n }\n } catch (cause) {\n this.emitter.emit('index:write-partial', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'put',\n error: new IndexWriteFailureError({ recordId: id, field: def.key, op: 'put', cause }),\n })\n }\n }\n }\n\n /**\n * Tear down `_idx/<field>/<recordId>` side-cars for a deleted record.\n * Mirror state updates regardless of adapter outcome; adapter failures\n * surface on `index:write-partial` the same way put does.\n */\n private async maintainPersistedIndexesOnDelete(id: string, previousRecord: T): Promise<void> {\n const persisted = this.persistedIndexes\n if (!persisted) return\n const defs = persisted.definitions()\n if (defs.length === 0) return\n\n const prevRec = previousRecord as unknown as Record<string, unknown>\n for (const def of defs) {\n const previousValue = extractIndexValue(prevRec, def)\n if (previousValue !== null && previousValue !== undefined) {\n persisted.remove(id, def.key, previousValue)\n }\n\n const idxId = encodeIdxId(def.key, id)\n try {\n await this.adapter.delete(this.vault, this.name, idxId)\n } catch (cause) {\n this.emitter.emit('index:write-partial', {\n vault: this.vault,\n collection: this.name,\n id,\n action: 'delete',\n error: new IndexWriteFailureError({ recordId: id, field: def.key, op: 'delete', cause }),\n })\n }\n }\n }\n\n /**\n * Bulk-load the persisted-index mirror from `_idx/<field>/*` side-cars\n * on first lazy-mode query. Idempotent — subsequent calls short-circuit\n * on the `persistedIndexesLoaded` flag.\n *\n * Listing the whole id namespace is acceptable here because the caller\n * has already decided to pay a first-query cost (this is the indexed\n * equivalent of lazy-mode hydration, not a per-query scan).\n */\n private async ensurePersistedIndexesLoaded(): Promise<void> {\n if (this.persistedIndexesLoaded) return\n const persisted = this.persistedIndexes\n if (!persisted || persisted.fields().length === 0) {\n this.persistedIndexesLoaded = true\n return\n }\n\n const ids = await this.adapter.list(this.vault, this.name)\n const byField = new Map<string, Array<{ recordId: string; value: unknown }>>()\n for (const id of ids) {\n const decoded = decodeIdxId(id)\n if (!decoded) continue\n if (!persisted.has(decoded.field)) continue\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) continue\n try {\n const json = await this.decryptJsonString(envelope)\n const body = JSON.parse(json) as { value: unknown; recordId: string }\n if (typeof body.recordId !== 'string') continue\n const rows = byField.get(decoded.field) ?? []\n rows.push({ recordId: body.recordId, value: body.value })\n byField.set(decoded.field, rows)\n } catch {\n // Skip unreadable side-cars — the reconciler picks them up later.\n }\n }\n for (const [field, rows] of byField) {\n persisted.ingest(field, rows)\n }\n this.persistedIndexesLoaded = true\n\n // auto-reconcile on first query. The mirror is now\n // populated from whatever side-cars existed; reconcileIndex will\n // diff that against the canonical records and repair (or just\n // report) drift per-field. Skip on the inner reload triggered by\n // reconcileIndex itself — see `autoReconciling` guard.\n if (this.reconcileOnOpen !== 'off' && !this.autoReconciling) {\n await this.autoReconcile()\n }\n }\n\n /**\n * Walk every declared persisted-index field, run `reconcileIndex`\n * per the configured policy, and emit `index:reconciled` for each.\n * Called internally by `ensurePersistedIndexesLoaded()` — exposed as\n * a private helper for readability, not as a public API (the public\n * entry points are `reconcileIndex` and `rebuildIndexes`).\n */\n private async autoReconcile(): Promise<void> {\n const persisted = this.persistedIndexes\n if (!persisted) return\n this.autoReconciling = true\n try {\n const dryRun = this.reconcileOnOpen === 'dry-run'\n for (const def of persisted.definitions()) {\n try {\n const report = await this.reconcileIndex(def.key, { dryRun })\n this.emitter.emit('index:reconciled', {\n vault: this.vault,\n collection: this.name,\n field: def.key,\n missing: report.missing,\n stale: report.stale,\n applied: report.applied,\n skipped: false,\n })\n } catch {\n // Tolerate a single field's failure — a broken reconcile\n // shouldn't prevent the rest of the collection from\n // working. The `index:write-partial` channel captures\n // per-field failures during put/delete; this is its\n // sibling for the reconcile path.\n }\n }\n } finally {\n this.autoReconciling = false\n }\n }\n\n /**\n * Construct a `LazyQuery<T>` bound to this collection. Used by the\n * lazy-mode branch of `query()` and kept private because callers should\n * always go through `query()` to pick up the eager/lazy dispatch.\n */\n /**\n * Build a chainable indexed-read query against a lazy-mode collection.\n *\n * Companion to `query()`, which is eager-mode only and materialises a\n * snapshot. `lazyQuery()` dispatches every read through the persisted\n * index side-cars — no bulk decrypt, no snapshot. Every field touched by\n * `.where(...)` or `.orderBy(...)` MUST be declared in `indexes`;\n * otherwise `.toArray()` throws `IndexRequiredError`.\n *\n * The returned builder is always Promise-returning on its terminals\n * (`toArray`, `first`, `count`) because candidate records are decrypted\n * from the adapter on demand.\n *\n * @example\n * ```ts\n * const disbursements = vault.collection<Disbursement>('disbursements', {\n * prefetch: false,\n * cache: { maxRecords: 1000 },\n * indexes: ['clientId', 'period'],\n * })\n * const rows = await disbursements.lazyQuery()\n * .where('clientId', '==', 'c-42')\n * .orderBy('period', 'desc')\n * .limit(50)\n * .toArray()\n * ```\n *\n * Throws at call time when the collection is in eager mode — use\n * `query()` there. Throws if no index is declared, because a lazy\n * query with no index would need to enumerate the whole collection.\n */\n lazyQuery(): LazyQuery<T> {\n if (!this.lazy) {\n throw new Error(\n `Collection \"${this.name}\": lazyQuery() is only available in lazy mode ` +\n `(prefetch: false). Use collection.query() for eager-mode chainable reads.`,\n )\n }\n const persisted = this.persistedIndexes\n if (!persisted) {\n throw new Error(\n `Collection \"${this.name}\": lazyQuery() requires indexing to be enabled. ` +\n `Pass \\`withIndexing()\\` from \"@noy-db/hub/indexing\" to ` +\n `\\`createNoydb({ indexStrategy: withIndexing() })\\`.`,\n )\n }\n if (persisted.fields().length === 0) {\n throw new Error(\n `Collection \"${this.name}\": lazyQuery() requires at least one field declared ` +\n `in \\`indexes\\`. Declare the fields you'll filter or sort by, or use ` +\n `collection.scan({ pageSize }) for non-indexed iteration.`,\n )\n }\n const source: LazyQuerySource<T> = {\n collectionName: this.name,\n persistedIndexes: persisted,\n ensurePersistedIndexesLoaded: () => this.ensurePersistedIndexesLoaded(),\n getRecord: (id: string) => this.get(id),\n }\n return new LazyQuery<T>(source)\n }\n\n private async encryptJsonString(json: string, version: number): Promise<EncryptedEnvelope> {\n const by = this.keyring.userId\n\n if (!this.encrypted) {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: json,\n _by: by,\n }\n }\n\n const dek = await this.getDEK(this.name)\n const { iv, data } = await encrypt(json, dek)\n\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: by,\n }\n }\n\n private async encryptRecord(record: T, version: number): Promise<EncryptedEnvelope> {\n const base = await this.encryptJsonString(JSON.stringify(record), version)\n if (!this.deterministicFields || !this.encrypted) return base\n\n // compute deterministic-ciphertext slots for every\n // declared field. Non-primitive values are JSON-stringified so\n // objects/arrays still dedupe on structural equality.\n const dek = await this.getDEK(this.name)\n const rec = record as unknown as Record<string, unknown>\n const det: Record<string, string> = {}\n for (const field of this.deterministicFields) {\n const value = rec[field]\n if (value === undefined || value === null) continue\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${this.name}/${field}`)\n det[field] = `${iv}:${data}`\n }\n if (Object.keys(det).length === 0) return base\n return { ...base, _det: det }\n }\n\n /**\n * find the first record whose deterministic field matches\n * the given plaintext. Returns `null` when no match exists.\n *\n * Reads every envelope via the adapter and compares the stored\n * `_det[field]` to a freshly computed deterministic ciphertext — no\n * record bodies are decrypted during the search, which is the whole\n * point of a deterministic index.\n *\n * Throws when the field is not declared in `deterministicFields`, so a\n * typo fails loudly at the call site rather than silently returning\n * null forever.\n */\n async findByDet(field: string, value: unknown): Promise<T | null> {\n if (!this.deterministicFields || !this.deterministicFields.has(field)) {\n throw new Error(\n `Collection \"${this.name}\": field \"${field}\" is not declared in deterministicFields`,\n )\n }\n if (!this.encrypted) {\n throw new Error(\n `Collection \"${this.name}\": findByDet is only meaningful on encrypted collections`,\n )\n }\n const dek = await this.getDEK(this.name)\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${this.name}/${field}`)\n const target = `${iv}:${data}`\n\n const ids = await this.adapter.list(this.vault, this.name)\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env || !env._det) continue\n if (env._det[field] === target) {\n return this.decryptRecord(env)\n }\n }\n return null\n }\n\n /**\n * return every record whose deterministic field matches.\n * Same semantics as {@link findByDet} but without the short-circuit.\n */\n async queryByDet(field: string, value: unknown): Promise<T[]> {\n if (!this.deterministicFields || !this.deterministicFields.has(field)) {\n throw new Error(\n `Collection \"${this.name}\": field \"${field}\" is not declared in deterministicFields`,\n )\n }\n if (!this.encrypted) {\n throw new Error(\n `Collection \"${this.name}\": queryByDet is only meaningful on encrypted collections`,\n )\n }\n const dek = await this.getDEK(this.name)\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, dek, `${this.name}/${field}`)\n const target = `${iv}:${data}`\n\n const ids = await this.adapter.list(this.vault, this.name)\n const matches: T[] = []\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env || !env._det) continue\n if (env._det[field] === target) {\n matches.push(await this.decryptRecord(env))\n }\n }\n return matches\n }\n\n // ─── Hierarchical Access ──────────────────────────\n\n private assertTiersEnabled(): void {\n if (!this.tiers) {\n throw new Error(\n `Collection \"${this.name}\": hierarchical tiers are not enabled. ` +\n `Pass { tiers: [0, 1, 2, …] } to vault.collection() to opt in.`,\n )\n }\n }\n\n private assertDeclaredTier(tier: number): void {\n if (tier < 0 || !Number.isInteger(tier)) {\n throw new Error(`Collection \"${this.name}\": tier must be a non-negative integer, got ${tier}`)\n }\n if (tier === 0) return\n if (!this.tiers || !this.tiers.has(tier)) {\n throw new Error(\n `Collection \"${this.name}\": tier ${tier} is not declared in { tiers: [...] }`,\n )\n }\n }\n\n /**\n * tier-aware put. Encrypts the record with the\n * collection's tier-N DEK and stamps `_tier: N` on the envelope. The\n * caller's keyring must hold the tier-N DEK (directly, by\n * delegation, or by virtue of being the grantor); otherwise throws\n * `TierNotGrantedError`.\n *\n * accepts an optional `elevation` context. When\n * present, the emitted cross-tier event is stamped with\n * `authorization: 'elevation'`, the elevation's reason, and the\n * caller's pre-elevation tier. `vault.elevate(...).collection().put`\n * threads this through; direct `putAtTier` calls leave it undefined\n * and fall back to the inherent-write event shape.\n */\n async putAtTier(\n id: string,\n record: T,\n tier: number,\n opts?: { elevation?: { reason: string; fromTier: number } },\n ): Promise<void> {\n this.assertTiersEnabled()\n this.assertDeclaredTier(tier)\n assertTierAccess(this.keyring, this.name, tier)\n\n const key = dekKey(this.name, tier)\n const dek = await this.getDEK(key)\n\n const existing = await this.adapter.get(this.vault, this.name, id)\n const version = existing ? existing._v + 1 : 1\n const json = JSON.stringify(record)\n const { iv, data } = await encrypt(json, dek)\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n ...(tier > 0 && { _tier: tier }),\n }\n\n await this.adapter.put(this.vault, this.name, id, envelope)\n\n if (tier > 0) {\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier,\n authorization: opts?.elevation ? 'elevation' : 'inherent',\n op: 'put',\n ts: envelope._ts,\n ...(opts?.elevation && {\n reason: opts.elevation.reason,\n elevatedFrom: opts.elevation.fromTier,\n }),\n })\n }\n }\n\n /**\n * tier-aware get. When the stored record is at a\n * tier the caller cannot decrypt:\n * - `'invisibility'` mode (default) → returns `null`.\n * - `'ghost'` mode → returns a `GhostRecord` placeholder with the\n * tier and the record id (the record exists but contents are\n * withheld).\n *\n * Fully-cleared reads return the plaintext record and fire a\n * cross-tier event when `_tier > 0`.\n */\n async getAtTier(id: string): Promise<T | GhostRecord | null> {\n this.assertTiersEnabled()\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) return null\n const tier = envelope._tier ?? 0\n if (tier === 0) {\n return this.decryptRecord(envelope)\n }\n\n const key = dekKey(this.name, tier)\n if (!this.keyring.deks.has(key)) {\n if (this.tierMode === 'ghost') {\n return { _ghost: true, _tier: tier } as GhostRecord\n }\n return null\n }\n\n const dek = await this.getDEK(key)\n const plaintext = await decrypt(envelope._iv, envelope._data, dek)\n const record = JSON.parse(plaintext) as T\n\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier,\n authorization: this.isElevatorOrOwner() ? 'inherent' : 'delegation',\n op: 'get',\n ts: new Date().toISOString(),\n })\n\n return record\n }\n\n /**\n * list ids grouped by the caller's readability.\n * Returns only ids whose tier the caller can read. Above-tier ids\n * are omitted in `'invisibility'` mode and included (with tier\n * metadata) in `'ghost'` mode.\n */\n async listAtTier(): Promise<Array<{ id: string; tier: number; readable: boolean }>> {\n this.assertTiersEnabled()\n const ids = await this.adapter.list(this.vault, this.name)\n const out: Array<{ id: string; tier: number; readable: boolean }> = []\n for (const id of ids) {\n const env = await this.adapter.get(this.vault, this.name, id)\n if (!env) continue\n const tier = env._tier ?? 0\n const readable = tier === 0 || this.keyring.deks.has(dekKey(this.name, tier))\n if (!readable && this.tierMode === 'invisibility') continue\n out.push({ id, tier, readable })\n }\n return out\n }\n\n /**\n * elevate a record to a higher tier. Re-encrypts with\n * the target tier's DEK. The caller must hold DEKs for both the\n * current tier (to decrypt) and the target tier (to re-encrypt).\n * Stamps `_elevatedBy` with the caller id so `demote()` can check\n * the reverse operation.\n */\n async elevate(id: string, toTier: number): Promise<void> {\n this.assertTiersEnabled()\n this.assertDeclaredTier(toTier)\n assertTierAccess(this.keyring, this.name, toTier)\n\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) throw new Error(`Record \"${id}\" not found in collection \"${this.name}\"`)\n const fromTier = envelope._tier ?? 0\n if (toTier === fromTier) return\n if (toTier < fromTier) {\n throw new Error(`Use demote() to lower the tier of \"${id}\" from ${fromTier} to ${toTier}`)\n }\n // Caller must have access at the existing tier to decrypt.\n if (fromTier > 0) assertTierAccess(this.keyring, this.name, fromTier)\n\n const fromKey = dekKey(this.name, fromTier)\n const toKey = dekKey(this.name, toTier)\n const fromDek = await this.getDEK(fromKey)\n const toDek = await this.getDEK(toKey)\n\n const plaintext = await decrypt(envelope._iv, envelope._data, fromDek)\n const { iv, data } = await encrypt(plaintext, toDek)\n const now = new Date().toISOString()\n const next: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: envelope._v + 1,\n _ts: now,\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n _tier: toTier,\n _elevatedBy: this.keyring.userId,\n }\n await this.adapter.put(this.vault, this.name, id, next)\n\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier: toTier,\n authorization: 'elevation',\n op: 'elevate',\n ts: now,\n })\n }\n\n /**\n * demote a record to a lower tier. Allowed only for\n * the user who performed the last elevation or an owner.\n */\n async demote(id: string, toTier: number): Promise<void> {\n this.assertTiersEnabled()\n if (toTier < 0) throw new Error(`Cannot demote to negative tier ${toTier}`)\n\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) throw new Error(`Record \"${id}\" not found in collection \"${this.name}\"`)\n const fromTier = envelope._tier ?? 0\n if (toTier === fromTier) return\n if (toTier > fromTier) {\n throw new Error(`Use elevate() to raise the tier of \"${id}\" from ${fromTier} to ${toTier}`)\n }\n const isOwner = this.keyring.role === 'owner'\n const isOriginalElevator = envelope._elevatedBy === this.keyring.userId\n if (!isOwner && !isOriginalElevator) {\n throw new TierDemoteDeniedError(id, fromTier)\n }\n // Caller must still hold the DEK of the current tier to decrypt.\n assertTierAccess(this.keyring, this.name, fromTier)\n if (toTier > 0) this.assertDeclaredTier(toTier)\n\n const fromDek = await this.getDEK(dekKey(this.name, fromTier))\n const toDek = await this.getDEK(dekKey(this.name, toTier))\n\n const plaintext = await decrypt(envelope._iv, envelope._data, fromDek)\n const { iv, data } = await encrypt(plaintext, toDek)\n const now = new Date().toISOString()\n const next: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: envelope._v + 1,\n _ts: now,\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n ...(toTier > 0 && { _tier: toTier }),\n }\n await this.adapter.put(this.vault, this.name, id, next)\n\n this.emitCrossTierEvent({\n actor: this.keyring.userId,\n collection: this.name,\n id,\n tier: fromTier,\n authorization: 'elevation',\n op: 'demote',\n ts: now,\n })\n }\n\n private isElevatorOrOwner(): boolean {\n return this.keyring.role === 'owner' || this.keyring.role === 'admin'\n }\n\n private emitCrossTierEvent(event: CrossTierAccessEvent): void {\n try {\n this.onCrossTierAccess?.(event)\n } catch {\n // notification sink failures must never block a tier operation\n }\n }\n\n /** Low-level: decrypt an envelope and return the raw JSON string. */\n private async decryptJsonString(envelope: EncryptedEnvelope): Promise<string> {\n if (!this.encrypted) return envelope._data\n const dek = await this.getDEK(this.name)\n return decrypt(envelope._iv, envelope._data, dek)\n }\n\n /**\n * Decrypt an envelope into a record of type `T`.\n *\n * When a schema is attached, the decrypted value is validated before\n * being returned. A divergence between the stored bytes and the\n * current schema throws `SchemaValidationError` with\n * `direction: 'output'` — silently returning drifted data would\n * propagate garbage into the UI and break the whole point of having\n * a schema.\n *\n * `skipValidation` exists for history reads: when calling\n * `getVersion()` the caller is explicitly asking for an old snapshot\n * that may predate a schema change, so validating it would be a\n * false positive. Every non-history read leaves this flag `false`.\n */\n private async decryptRecord(\n envelope: EncryptedEnvelope,\n opts: { skipValidation?: boolean } = {},\n ): Promise<T> {\n const json = await this.decryptJsonString(envelope)\n let parsed: unknown = JSON.parse(json)\n\n // CRDT resolution: if this collection is in CRDT mode, the\n // stored JSON is a CrdtState, not T directly. Resolve to the snapshot.\n if (this.crdtMode && parsed !== null && typeof parsed === 'object' && '_crdt' in parsed) {\n parsed = this.crdtStrategy.resolveCrdtSnapshot(parsed as CrdtState)\n }\n\n let record = parsed as T\n\n if (this.schema !== undefined && !opts.skipValidation) {\n // Context string deliberately avoids leaking the record id — the\n // envelope only carries the version, not the id (the id lives in\n // the adapter-side key). `<collection>@v<n>` is enough for the\n // developer to find the offending record.\n record = await validateSchemaOutput(\n this.schema,\n record,\n `${this.name}@v${envelope._v}`,\n )\n }\n\n return record\n }\n}\n\n/**\n * Read a field value from a plain record for persisted-index maintenance.\n * Supports dotted paths so declarations like `indexes: ['billing.clientId']`\n * work the same way `readPath` handles them for the eager-mode builder.\n */\nfunction readPersistedValue(record: Record<string, unknown>, field: string): unknown {\n if (!field.includes('.')) return record[field]\n const segments = field.split('.')\n let cursor: unknown = record\n for (const segment of segments) {\n if (cursor === null || cursor === undefined) return undefined\n cursor = (cursor as Record<string, unknown>)[segment]\n }\n return cursor\n}\n\n/**\n * Canonicalize a typed value for storage inside the side-car body so it\n * round-trips through `JSON.parse` without losing fidelity. Dates are\n * serialised as ISO strings; everything else passes through.\n *\n * The in-memory mirror compares on the stringified bucket key, so the\n * exact storage form is not query-critical — this just protects the\n * reconciler, which compares the stored body against the\n * live record value and would otherwise mismatch on Date objects.\n */\nfunction serializeIndexValue(value: unknown): unknown {\n if (value instanceof Date) return value.toISOString()\n return value\n}\n\n/**\n * Extract the indexable value for a declaration — a scalar for\n * single-field, or a tuple array for composite. Returns `null` when\n * the value is not indexable (single-field null/undefined, composite\n * with any null/undefined component — the whole composite is skipped\n * if any part is missing).\n */\nfunction extractIndexValue(\n record: Record<string, unknown>,\n def: PersistedIndexDef,\n): unknown {\n if (def.kind === 'single') {\n const v = readPersistedValue(record, def.field)\n return v === undefined || v === null ? null : v\n }\n const tuple: unknown[] = []\n for (const f of def.fields) {\n const v = readPersistedValue(record, f)\n if (v === undefined || v === null) return null\n tuple.push(v)\n }\n return tuple\n}\n\n/**\n * Compare the decrypted side-car body's `value` against the live record\n * field value, in the same canonical form used for storage. Handles the\n * Date-is-ISO-string round trip so reconcile doesn't flag a false drift.\n */\nfunction valuesMatch(stored: unknown, live: unknown): boolean {\n const serialized = serializeIndexValue(live)\n if (stored === serialized) return true\n if (stored === undefined || serialized === undefined) return stored === serialized\n // JSON-stringify both sides for structural equality on arrays/objects.\n try {\n return JSON.stringify(stored) === JSON.stringify(serialized)\n } catch {\n return false\n }\n}\n","/**\n * Strategy seam for the optional VaultFrame snapshot primitive.\n * Core imports `ShadowStrategy` as TYPE-ONLY and `NO_SHADOW` as a\n * 4-line stub. `VaultFrame` is only constructed inside `withShadow()`\n * — consumers who never import `@noy-db/hub/shadow` ship none of\n * the ~129 LOC.\n *\n * @internal\n */\n\nimport type { VaultFrame } from './vault-frame.js'\n\n/**\n * @internal\n */\nexport interface ShadowStrategy {\n /**\n * Build a `VaultFrame` bound to the given vault. The factory type\n * is kept loose (`unknown`) to avoid a core → shadow type\n * dependency — the consumer always calls this through\n * `vault.frame()`, which returns `VaultFrame` at its surface.\n */\n buildFrame(vault: unknown): VaultFrame\n}\n\nconst NOT_ENABLED = new Error(\n 'VaultFrame requires the shadow strategy. Import `{ withShadow }` ' +\n 'from \"@noy-db/hub/shadow\" and pass it to ' +\n '`createNoydb({ shadowStrategy: withShadow() })`.',\n)\n\n/**\n * No-shadow stub.\n *\n * @internal\n */\nexport const NO_SHADOW: ShadowStrategy = {\n buildFrame() { throw NOT_ENABLED },\n}\n","/**\n * Strategy seam for the optional consent-audit subsystem. Core\n * imports `ConsentStrategy` as a TYPE-ONLY symbol and `NO_CONSENT`\n * as a tiny runtime stub.\n *\n * `writeConsentEntry` / `loadConsentEntries` are only reachable from\n * `withConsent()` in `./active.ts`, exported through\n * `@noy-db/hub/consent`. Applications without a consent scope ship\n * none of the ~194 LOC.\n *\n * @internal\n */\n\nimport type { NoydbStore } from '../types.js'\nimport type {\n ConsentAuditEntry,\n ConsentAuditFilter,\n} from './consent.js'\n\n/**\n * @internal\n */\nexport interface ConsentStrategy {\n /**\n * Record one consent audit entry. No-op under NO_CONSENT.\n */\n write(\n adapter: NoydbStore,\n vault: string,\n encrypted: boolean,\n entry: Omit<ConsentAuditEntry, 'id' | 'timestamp'>,\n getDEK: (collectionName: string) => Promise<CryptoKey>,\n ): Promise<void>\n\n /**\n * Read filtered consent entries. Returns `[]` under NO_CONSENT.\n */\n read(\n adapter: NoydbStore,\n vault: string,\n encrypted: boolean,\n getDEK: (collectionName: string) => Promise<CryptoKey>,\n filter?: ConsentAuditFilter,\n ): Promise<ConsentAuditEntry[]>\n}\n\n/**\n * No-consent stub. `write` is a no-op (returns a resolved promise);\n * `read` returns `[]`. Consumers get a consistent API surface without\n * pulling the consent module into the bundle.\n *\n * @internal\n */\nexport const NO_CONSENT: ConsentStrategy = {\n async write() {},\n async read() { return [] },\n}\n","/**\n * Strategy seam for the optional accounting-periods subsystem. Core\n * imports `PeriodsStrategy` type-only + `NO_PERIODS` stub; the real\n * `loadPeriods` / `chainAnchor` / `assertTsWritable` /\n * `validatePeriodName` / `appendPeriodLedgerEntry` functions are\n * only reachable via `withPeriods()` in `./active.ts`.\n *\n * Applications that never call `vault.closePeriod()` /\n * `vault.openPeriod()` ship none of the ~363 LOC.\n *\n * @internal\n */\n\nimport type { EncryptedEnvelope, NoydbStore } from '../types.js'\nimport type { LedgerStore } from '../history/ledger/store.js'\nimport type { PeriodRecord } from './periods.js'\n\n/**\n * @internal\n */\nexport interface PeriodsStrategy {\n loadPeriods(\n adapter: NoydbStore,\n vault: string,\n decrypt: (envelope: EncryptedEnvelope) => Promise<PeriodRecord>,\n ): Promise<PeriodRecord[]>\n chainAnchor(records: readonly PeriodRecord[]): Promise<{\n priorPeriodName?: string\n priorPeriodHash: string\n }>\n assertTsWritable(\n existing: { ts: string | null; record: Record<string, unknown> | null } | null,\n incoming: Record<string, unknown> | null,\n periods: readonly PeriodRecord[],\n ): void\n validatePeriodName(name: string, existing: readonly PeriodRecord[]): void\n appendPeriodLedgerEntry(\n ledger: LedgerStore | null,\n actor: string,\n envelope: EncryptedEnvelope,\n periodName: string,\n ): Promise<void>\n}\n\n/**\n * No-periods stub. `loadPeriods` returns `[]`; the write-guards do\n * nothing (vaults without closed periods never reject writes);\n * `validatePeriodName` / `appendPeriodLedgerEntry` throw because\n * those paths are only reached when the user explicitly called\n * `closePeriod()` / `openPeriod()` — if they did that without the\n * strategy, they need to wire it.\n *\n * @internal\n */\nconst NOT_ENABLED = new Error(\n 'Accounting periods require the periods strategy. Import ' +\n '`{ withPeriods }` from \"@noy-db/hub/periods\" and pass it to ' +\n '`createNoydb({ periodsStrategy: withPeriods() })`.',\n)\n\nexport const NO_PERIODS: PeriodsStrategy = {\n async loadPeriods() { return [] },\n async chainAnchor() { return { priorPeriodHash: '' } },\n assertTsWritable() {},\n validatePeriodName() { throw NOT_ENABLED },\n async appendPeriodLedgerEntry() { throw NOT_ENABLED },\n}\n","/**\n * Magic-link-bound cross-user delegation grants.\n *\n * This module is the **core storage + encryption layer** that lets a\n * grantor issue a tier-DEK to a user whose KEK they do not know. The\n * trust bridge is provided by the `@noy-db/on-magic-link` package:\n *\n * 1. Grantor picks a grantee identity (user id + email handle).\n * 2. Grantor mints a magic-link token (ULID) via `createMagicLinkToken`.\n * 3. Grantor derives a **content key** + a **KEK** from\n * `(serverSecret, token, vault)` using HKDF-SHA256 with separate\n * `info` tags — both callers (grantor and grantee) can derive the\n * same keys given the same inputs.\n * 4. Grantor persists a record in `_magic_link_grants/<token>`:\n * - envelope `_data` is AES-GCM encrypted under the content key\n * - the inner `wrappedDek` is AES-KW wrapped under the KEK\n * 5. Grantee receives the URL, derives the same content key + KEK,\n * loads the grant, decrypts the envelope, unwraps the tier DEK.\n *\n * ## Why a separate collection from `_delegations`\n *\n * `_delegations` envelopes are encrypted under a DEK shared across\n * every vault user (audit-visibility). External auditors / client\n * portal users have NO pre-existing keyring, so they cannot read that\n * DEK. Magic-link grants live in their own collection whose envelope\n * encryption is derived purely from the magic-link URL + server secret\n * — nothing else is required to decrypt.\n *\n * ## Batch grants\n *\n * One magic-link token may point to MULTIPLE grants (e.g. the client\n * portal case: invoices + payments + etax all share one link). Each\n * grant is persisted under a distinct record id:\n *\n * `<token>` for the single-grant / primary entry\n * `<token>:<index>` for subsequent entries\n *\n * `listMagicLinkGrants(store, vault, token)` enumerates every record\n * whose id begins with `<token>` so the claimant can materialize all\n * DEKs in one pass.\n *\n * ## Revocation\n *\n * `store.delete(vault, _magic_link_grants, <token>)` immediately\n * invalidates the link — even if the URL was captured and the server\n * secret leaked, no payload remains to decrypt.\n *\n * @module\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport type { UnlockedKeyring } from './keyring.js'\nimport { encrypt, decrypt, wrapKey, unwrapKey } from '../crypto.js'\nimport { dekKey } from './tiers.js'\nimport { DelegationTargetMissingError } from '../errors.js'\n\n/** Reserved collection holding magic-link grant envelopes. */\nexport const MAGIC_LINK_GRANTS_COLLECTION = '_magic_link_grants'\n\n/** HKDF `info` for the AES-GCM content key. Version-namespaced. */\nexport const MAGIC_LINK_CONTENT_INFO_PREFIX = 'noydb-magic-link-content-v1:'\n\n/** HKDF `info` for the AES-KW KEK. Matches `@noy-db/on-magic-link`. */\nexport const MAGIC_LINK_KEK_INFO_PREFIX = 'noydb-magic-link-v1:'\n\n// ─── Types ──────────────────────────────────────────────────────────────\n\n/**\n * Decrypted payload of a magic-link grant record. Mirrors\n * `DelegationToken` in `team/delegation.ts` but tracked separately\n * because the two flows persist under different collections + envelope\n * encryption schemes.\n */\nexport interface MagicLinkGrantPayload {\n readonly id: string\n readonly toUser: string\n readonly fromUser: string\n readonly tier: number\n /** Collection name or `null` for the vault-wide tier DEK. */\n readonly collection: string | null\n /** Optional specific record id scope. */\n readonly record?: string\n /** ISO timestamp — grant expires at this instant. */\n readonly until: string\n /** AES-KW-wrapped tier DEK, unwrap with the magic-link KEK. */\n readonly wrappedDek: string\n /** ISO timestamp the grant was issued. */\n readonly createdAt: string\n /** Optional caller-provided label (surfaced in audit UIs). */\n readonly note?: string\n}\n\nexport interface IssueMagicLinkGrantOptions {\n readonly toUser: string\n readonly tier: number\n readonly collection?: string\n readonly record?: string\n readonly until: Date | string\n readonly note?: string\n}\n\nexport interface MagicLinkGrantRecord {\n /** Store record id — `<token>` or `<token>:<index>` for batch entries. */\n readonly recordId: string\n readonly payload: MagicLinkGrantPayload\n}\n\n// ─── Key derivation ─────────────────────────────────────────────────────\n\n/**\n * Derive the AES-GCM content key from the same HKDF inputs used for\n * the magic-link KEK. Different `info` suffix → domain-separated key.\n *\n * Exported so the `@noy-db/on-magic-link` package can share the exact\n * derivation path without cross-dependency between the two modules.\n */\nexport async function deriveMagicLinkContentKey(\n serverSecret: string | Uint8Array<ArrayBuffer>,\n token: string,\n vault: string,\n): Promise<CryptoKey> {\n const subtle = globalThis.crypto.subtle\n const ikmBytes =\n serverSecret instanceof Uint8Array\n ? serverSecret\n : new TextEncoder().encode(serverSecret)\n const tokenBytes = new TextEncoder().encode(token)\n const saltBuffer = await subtle.digest('SHA-256', tokenBytes)\n const info = new TextEncoder().encode(MAGIC_LINK_CONTENT_INFO_PREFIX + vault)\n const ikm = await subtle.importKey('raw', ikmBytes, 'HKDF', false, ['deriveKey'])\n return subtle.deriveKey(\n { name: 'HKDF', hash: 'SHA-256', salt: saltBuffer, info },\n ikm,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt'],\n )\n}\n\n// ─── Issue ──────────────────────────────────────────────────────────────\n\n/**\n * Persist a magic-link grant record. Caller derives + provides both\n * the content key and the KEK; this function performs the wrap/encrypt\n * and writes the envelope.\n *\n * `recordId` lets the caller use either the bare token (primary grant)\n * or a suffixed id (batch entry). The writer is responsible for\n * collision-avoidance across batch entries.\n */\nexport async function writeMagicLinkGrant(\n store: NoydbStore,\n vault: string,\n grantor: UnlockedKeyring,\n contentKey: CryptoKey,\n grantKek: CryptoKey,\n recordId: string,\n opts: IssueMagicLinkGrantOptions,\n): Promise<MagicLinkGrantRecord> {\n const collectionName = opts.collection ?? null\n const sourceKey = collectionName\n ? dekKey(collectionName, opts.tier)\n : `__any#${opts.tier}`\n const sourceDek = grantor.deks.get(sourceKey)\n if (!sourceDek) {\n throw new DelegationTargetMissingError(\n `grantor cannot find tier ${opts.tier} DEK for ${collectionName ?? '(any)'}`,\n )\n }\n const wrappedDek = await wrapKey(sourceDek, grantKek)\n\n const until = typeof opts.until === 'string' ? opts.until : opts.until.toISOString()\n const createdAt = new Date().toISOString()\n const payload: MagicLinkGrantPayload = {\n id: recordId,\n toUser: opts.toUser,\n fromUser: grantor.userId,\n tier: opts.tier,\n collection: collectionName,\n ...(opts.record && { record: opts.record }),\n until,\n wrappedDek,\n createdAt,\n ...(opts.note && { note: opts.note }),\n }\n\n const { iv, data } = await encrypt(JSON.stringify(payload), contentKey)\n const envelope: EncryptedEnvelope = {\n _noydb: 1,\n _v: 1,\n _ts: createdAt,\n _iv: iv,\n _data: data,\n _by: grantor.userId,\n }\n await store.put(vault, MAGIC_LINK_GRANTS_COLLECTION, recordId, envelope)\n return { recordId, payload }\n}\n\n// ─── Claim ──────────────────────────────────────────────────────────────\n\n/**\n * Fetch + decrypt a single magic-link grant record by id. Returns null\n * when the record is absent OR when decryption fails (wrong server\n * secret, wrong vault, tampered envelope) — callers treat a null as\n * \"this URL is not valid for this server\".\n *\n * The returned payload's `wrappedDek` is still AES-KW-wrapped; the\n * caller unwraps it with the magic-link KEK to obtain the tier DEK.\n */\nexport async function readMagicLinkGrantRecord(\n store: NoydbStore,\n vault: string,\n contentKey: CryptoKey,\n recordId: string,\n): Promise<MagicLinkGrantPayload | null> {\n const env = await store.get(vault, MAGIC_LINK_GRANTS_COLLECTION, recordId)\n if (!env) return null\n try {\n const json = await decrypt(env._iv, env._data, contentKey)\n return JSON.parse(json) as MagicLinkGrantPayload\n } catch {\n return null\n }\n}\n\n/**\n * Enumerate every grant record sharing the magic-link `token` prefix\n * (i.e. the primary `<token>` entry plus any `<token>:*` batch entries).\n * Expired grants are still returned — the caller filters on `until`.\n */\nexport async function listMagicLinkGrants(\n store: NoydbStore,\n vault: string,\n contentKey: CryptoKey,\n token: string,\n): Promise<MagicLinkGrantPayload[]> {\n const ids = await store.list(vault, MAGIC_LINK_GRANTS_COLLECTION)\n const matching = ids.filter(id => id === token || id.startsWith(`${token}:`))\n const out: MagicLinkGrantPayload[] = []\n for (const id of matching) {\n const payload = await readMagicLinkGrantRecord(store, vault, contentKey, id)\n if (payload) out.push(payload)\n }\n return out\n}\n\n/**\n * Unwrap the tier DEK from a grant payload using the magic-link KEK.\n * Thin wrapper around `unwrapKey` — provided so the claimant can avoid\n * importing `crypto.js` directly.\n */\nexport async function unwrapMagicLinkGrant(\n payload: MagicLinkGrantPayload,\n grantKek: CryptoKey,\n): Promise<CryptoKey> {\n return unwrapKey(payload.wrappedDek, grantKek)\n}\n\n/**\n * Delete a magic-link grant (primary + every batch entry sharing the\n * token). Safe to call when nothing exists.\n */\nexport async function revokeMagicLinkGrant(\n store: NoydbStore,\n vault: string,\n token: string,\n): Promise<number> {\n const ids = await store.list(vault, MAGIC_LINK_GRANTS_COLLECTION)\n const matching = ids.filter(id => id === token || id.startsWith(`${token}:`))\n for (const id of matching) {\n await store.delete(vault, MAGIC_LINK_GRANTS_COLLECTION, id)\n }\n return matching.length\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────\n\n/**\n * Compose the batch-entry record id. `index === 0` → bare token.\n * Subsequent entries use `<token>:<index>` so `store.list()` can\n * enumerate them all by common prefix.\n */\nexport function magicLinkGrantRecordId(token: string, index: number): string {\n return index === 0 ? token : `${token}:${index}`\n}\n\n/**\n * True when the payload's `until` is in the past relative to `now`.\n * Kept here (rather than inlined) so the semantics stay aligned with\n * the canonical `DelegationToken` expiry check.\n */\nexport function isMagicLinkGrantExpired(\n payload: MagicLinkGrantPayload,\n now: Date = new Date(),\n): boolean {\n return payload.until <= now.toISOString()\n}\n","import type {\n NoydbStore,\n EncryptedEnvelope,\n VaultBackup,\n VaultSnapshot,\n HistoryConfig,\n ExportStreamOptions,\n ExportChunk,\n CollectionConflictResolver,\n CrossTierAccessEvent,\n TierMode,\n Role,\n} from './types.js'\nimport type { Noydb } from './noydb.js'\nimport type { IssueDelegationOptions, DelegationToken } from './team/delegation.js'\nimport { NOYDB_BACKUP_VERSION, NOYDB_FORMAT_VERSION } from './types.js'\nimport { Collection } from './collection.js'\nimport type { CacheOptions } from './collection.js'\nimport type { IndexDef } from './indexing/eager-indexes.js'\nimport type { JoinableSource } from './query/index.js'\nimport type { OnDirtyCallback } from './collection.js'\nimport type { UnlockedKeyring, BundleRecipient } from './team/keyring.js'\nimport { buildRecipientKeyringFile } from './team/keyring.js'\nimport { ensureCollectionDEK, hasAccess, hasExportCapability, hasImportCapability } from './team/keyring.js'\nimport type { ExportFormat, KeyringFile } from './types.js'\nimport {\n ExportCapabilityError,\n ImportCapabilityError,\n ValidationError,\n AlreadyElevatedError,\n ElevationExpiredError,\n TierNotGrantedError,\n} from './errors.js'\nimport type { NoydbEventEmitter } from './events.js'\nimport { BackupLedgerError, BackupCorruptedError } from './errors.js'\nimport type { StandardSchemaV1 } from './schema.js'\nimport type { BlobStrategy } from './blobs/strategy.js'\nimport type { IndexStrategy } from './indexing/strategy.js'\nimport type { AggregateStrategy } from './aggregate/strategy.js'\nimport type { CrdtStrategy } from './crdt/strategy.js'\n// — import from leaf modules (NOT from ./history/ledger/index.js\n// or store.js) so the LedgerStore class never reaches the floor\n// bundle. The leaf files hold pure constants + a tiny hash helper;\n// the class lives behind the history strategy seam.\nimport type { LedgerStore } from './history/ledger/store.js'\nimport { LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION } from './history/ledger/constants.js'\nimport { sha256Hex } from './history/ledger/entry.js'\nimport type { VaultInstant } from './history/time-machine.js'\nimport { NO_HISTORY, type HistoryStrategy } from './history/strategy.js'\nimport type { VaultFrame } from './shadow/vault-frame.js'\nimport { NO_SHADOW, type ShadowStrategy } from './shadow/strategy.js'\nimport type { ConsentContext, ConsentAuditEntry, ConsentAuditFilter, ConsentOp } from './consent/consent.js'\nimport { NO_CONSENT, type ConsentStrategy } from './consent/strategy.js'\nimport { NO_PERIODS, type PeriodsStrategy } from './periods/strategy.js'\nimport {\n RefRegistry,\n RefIntegrityError,\n type RefDescriptor,\n type RefViolation,\n} from './refs.js'\nimport type { DictionaryHandle, DictionaryOptions, DictKeyDescriptor } from './i18n/dictionary.js'\nimport { isDictCollectionName } from './i18n/dictionary.js'\nimport type { I18nTextDescriptor } from './i18n/core.js'\nimport { NO_I18N, type I18nStrategy } from './i18n/strategy.js'\nimport { NO_SYNC, type SyncStrategy } from './team/sync-strategy.js'\nimport type { LocaleReadOptions, ConflictPolicy } from './types.js'\nimport type { CrdtMode } from './crdt/crdt.js'\nimport { ReservedCollectionNameError } from './errors.js'\nimport {\n PERIODS_COLLECTION,\n type PeriodRecord,\n type ClosePeriodOptions,\n type OpenPeriodOptions,\n} from './periods/index.js'\nimport { encrypt, decrypt } from './crypto.js'\nimport {\n createExportBlobsHandle,\n EXPORT_AUDIT_COLLECTION,\n type ExportBlobsOptions,\n type ExportBlobsHandle,\n type ExportBlobsAuditEntry,\n} from './blobs/export-blobs.js'\nimport { runCompaction, type BlobFieldsConfig, type CompactRunOptions, type CompactionResult } from './blobs/blob-compaction.js'\nimport {\n writeMagicLinkGrant,\n type IssueMagicLinkGrantOptions,\n type MagicLinkGrantRecord,\n} from './team/magic-link-grant.js'\n\n/** A vault (tenant namespace) containing collections. */\nexport class Vault {\n private readonly adapter: NoydbStore\n /** The vault's name as passed to `openVault()`. Stable for the instance lifetime. */\n public readonly name: string\n /**\n * Backreference to the parent `Noydb`. Lets vault-scoped subsystems\n * (e.g. `as-*` reader `apply()` paths gating on `withTransactions()`)\n * reach the strategy seam without threading `db` through every API.\n *\n * Type-only Noydb import keeps the module graph acyclic at runtime.\n */\n public readonly noydb: Noydb\n /**\n * The active in-memory keyring. NOT readonly because `load()`\n * needs to refresh it after restoring a different keyring file —\n * otherwise the in-memory DEKs (from the pre-load session) and\n * the on-disk wrapped DEKs (from the loaded backup) drift apart\n * and every subsequent decrypt fails with TamperedError.\n */\n private keyring: UnlockedKeyring\n private readonly encrypted: boolean\n private readonly emitter: NoydbEventEmitter\n private readonly onDirty: OnDirtyCallback | undefined\n private readonly onRegisterConflictResolver: ((name: string, resolver: CollectionConflictResolver) => void) | undefined\n private readonly syncAdapter: NoydbStore | undefined\n private readonly historyConfig: HistoryConfig\n /**\n * tree-shake seam for the optional blob subsystem. Undefined\n * means \"blobs are off for this vault\"; every `collection.blob(id)`\n * call throws with a pointer at `@noy-db/hub/blobs`.\n */\n private readonly blobStrategy: BlobStrategy | undefined\n private readonly indexStrategy: IndexStrategy | undefined\n private readonly aggregateStrategy: AggregateStrategy | undefined\n private readonly crdtStrategy: CrdtStrategy | undefined\n private readonly consentStrategy: ConsentStrategy\n private readonly periodsStrategy: PeriodsStrategy\n private readonly shadowStrategy: ShadowStrategy\n private readonly historyStrategy: HistoryStrategy\n private readonly i18nStrategy: I18nStrategy\n private readonly syncStrategy: SyncStrategy\n private getDEK: (collectionName: string) => Promise<CryptoKey>\n\n /**\n * Optional callback that re-derives an UnlockedKeyring from the\n * adapter using the active user's passphrase. Called by `load()`\n * after the on-disk keyring file has been replaced — refreshes\n * `this.keyring` so the next DEK access uses the loaded wrapped\n * DEKs instead of the stale pre-load ones.\n *\n * Provided by Noydb at openVault() time. Tests that\n * construct Vault directly can pass `undefined`; load()\n * skips the refresh in that case (which is fine for plaintext\n * compartments — there's nothing to re-unwrap).\n */\n private readonly reloadKeyring: (() => Promise<UnlockedKeyring>) | undefined\n private readonly collectionCache = new Map<string, Collection<unknown>>()\n\n /**\n * per-collection `blobFields` retention/TTL config.\n * Populated on `collection({ blobFields })` and read by\n * `vault.compact()`. Indexed by collection name.\n */\n private readonly blobFieldsRegistry = new Map<string, BlobFieldsConfig<unknown>>()\n\n /**\n * Per-vault ledger store. Lazy-initialized on first\n * `collection()` call (which passes it through to the Collection)\n * or on first `ledger()` call from user code.\n *\n * One LedgerStore is shared across all collections in a vault\n * because the hash chain is vault-scoped: the chain head is a\n * single \"what did this vault do last\" identifier, not a\n * per-collection one. Two collections appending concurrently is the\n * single-writer concurrency concern documented in the LedgerStore\n * docstring.\n */\n private ledgerStore: LedgerStore | null = null\n\n /**\n * Per-vault foreign-key reference registry. Collections\n * register their `refs` option here on construction; the\n * vault uses the registry on every put/delete/checkIntegrity\n * call. One instance lives for the compartment's lifetime.\n */\n private readonly refRegistry = new RefRegistry()\n\n /**\n * Set of collection record-ids currently being deleted as part of\n * a cascade. Populated on entry to `enforceRefsOnDelete` and\n * drained on exit. Used to break mutual-cascade cycles: deleting\n * A → cascade to B → cascade back to A would otherwise recurse\n * forever, so we short-circuit when we see an already-in-progress\n * delete on the same (collection, id) pair.\n */\n private readonly cascadeInProgress = new Set<string>()\n\n /**\n * Vault-default locale. Set via\n * `openVault(name, { locale })`. Used as the fallback locale\n * when per-call `{ locale }` options are not specified on individual\n * `get()`/`list()` calls.\n */\n private locale: string | undefined\n\n /**\n * Current consent scope. Set by `withConsent()` and\n * restored in its finally block. When non-null, every collection\n * access inside the scope writes one entry to `_consent_audit`.\n *\n * Single-slot by design — two concurrent withConsent calls on the\n * same Vault stomp each other. Adopters needing per-flight scoping\n * should use separate Vault instances.\n */\n private consentContext: ConsentContext | null = null\n\n /**\n * Cache of closed/opened accounting periods.\n * Populated on first `closePeriod` / `openPeriod` / `listPeriods` /\n * per-collection write call. Kept in memory as an ordered list (by\n * `closedAt`) so the `periodGuard` hook runs synchronously against\n * each collection's put/delete path.\n *\n * Sentinel `null` means \"not yet loaded\" — the first consumer\n * triggers a one-time `loadPeriods()` pass. Every subsequent\n * closure/opening pushes into the cache in-place so the next write\n * sees the updated chain without re-reading the adapter.\n */\n private periodCache: PeriodRecord[] | null = null\n\n /**\n * Registry of dictKey fields declared across all collections in this\n * vault. Keyed by collection name → field name → dictionary name.\n * Used by `DictionaryHandle.rename()` to find and update all records\n * referencing a renamed key.\n *\n * Populated by `collection()` when the `dictKeyFields` option is passed.\n */\n private readonly dictKeyFieldRegistry = new Map<\n string, // collection name\n Record<string, string> // field name → dictionary name\n >()\n\n /**\n * Registry of i18nText fields declared across all collections. Keyed\n * by collection name → field name → I18nTextDescriptor. Used by\n * `applyI18nLocale` on reads and by `validateI18nTextValue` on puts.\n *\n * Populated by `collection()` when the `i18nFields` option is passed.\n */\n private readonly i18nFieldRegistry = new Map<\n string, // collection name\n Record<string, I18nTextDescriptor>\n >()\n\n /** Cache of DictionaryHandle instances, one per dictionary name. */\n private readonly dictionaryCache = new Map<string, DictionaryHandle>()\n\n /** — subscribers for cross-tier access events. */\n private readonly crossTierSubs = new Set<(event: CrossTierAccessEvent) => void>()\n\n /** — currently-active elevation, or null. One per vault. */\n private activeElevation: {\n readonly tier: number\n readonly expiresAt: number\n readonly reason: string\n readonly handle: ElevatedHandle\n } | null = null\n\n /**\n * Optional translator callback threaded from `Noydb.invokeTranslator`.\n * Present only when `plaintextTranslator` was configured on `createNoydb()`.\n */\n private readonly translateText:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n\n constructor(opts: {\n adapter: NoydbStore\n name: string\n noydb: Noydb\n keyring: UnlockedKeyring\n encrypted: boolean\n emitter: NoydbEventEmitter\n onDirty?: OnDirtyCallback | undefined\n historyConfig?: HistoryConfig | undefined\n reloadKeyring?: (() => Promise<UnlockedKeyring>) | undefined\n /** Vault-default locale. */\n locale?: string | undefined\n /** Translator callback from Noydb. */\n plaintextTranslator?:\n | ((text: string, from: string, to: string, field: string, collection: string) => Promise<string>)\n | undefined\n /**\n * callback to register a per-collection envelope-level\n * conflict resolver with the SyncEngine. Present when sync is configured.\n */\n onRegisterConflictResolver?: ((name: string, resolver: CollectionConflictResolver) => void) | undefined\n /** — optional remote/sync adapter for presence broadcasting. */\n syncAdapter?: NoydbStore | undefined\n /**\n * tree-shake seam — strategy for optional blob storage.\n * Passed through to every `Collection` built by `vault.collection()`.\n * `undefined` => every `collection.blob(id)` throws with a pointer\n * at `@noy-db/hub/blobs`.\n */\n blobStrategy?: BlobStrategy | undefined\n indexStrategy?: IndexStrategy | undefined\n aggregateStrategy?: AggregateStrategy | undefined\n crdtStrategy?: CrdtStrategy | undefined\n consentStrategy?: ConsentStrategy | undefined\n periodsStrategy?: PeriodsStrategy | undefined\n shadowStrategy?: ShadowStrategy | undefined\n historyStrategy?: HistoryStrategy | undefined\n i18nStrategy?: I18nStrategy | undefined\n syncStrategy?: SyncStrategy | undefined\n }) {\n this.adapter = opts.adapter\n this.name = opts.name\n this.noydb = opts.noydb\n this.keyring = opts.keyring\n this.encrypted = opts.encrypted\n this.emitter = opts.emitter\n this.onDirty = opts.onDirty\n this.onRegisterConflictResolver = opts.onRegisterConflictResolver\n this.syncAdapter = opts.syncAdapter\n this.blobStrategy = opts.blobStrategy\n this.indexStrategy = opts.indexStrategy\n this.aggregateStrategy = opts.aggregateStrategy\n this.crdtStrategy = opts.crdtStrategy\n this.consentStrategy = opts.consentStrategy ?? NO_CONSENT\n this.periodsStrategy = opts.periodsStrategy ?? NO_PERIODS\n this.shadowStrategy = opts.shadowStrategy ?? NO_SHADOW\n this.historyStrategy = opts.historyStrategy ?? NO_HISTORY\n this.i18nStrategy = opts.i18nStrategy ?? NO_I18N\n this.syncStrategy = opts.syncStrategy ?? NO_SYNC\n this.historyConfig = opts.historyConfig ?? { enabled: true }\n this.reloadKeyring = opts.reloadKeyring\n this.locale = opts.locale\n this.translateText = opts.plaintextTranslator\n\n // Build the lazy DEK resolver. Pulled out into a private method\n // so `load()` can rebuild it after a keyring refresh — the\n // closure captures `this.keyring` by reference, so changing the\n // field is enough, but resetting the cached `getDEKFn` ensures\n // ensureCollectionDEK runs again against the freshly-loaded\n // wrapped DEKs.\n this.getDEK = this.makeGetDEK()\n }\n\n /**\n * Construct (or reconstruct) the lazy DEK resolver. Captures the\n * CURRENT value of `this.keyring` and `this.adapter` in a closure,\n * memoizing the inner getDEKFn after first use so subsequent\n * lookups are O(1).\n *\n * `load()` calls this after refreshing `this.keyring` to discard\n * the prior session's cached DEKs.\n */\n private makeGetDEK(): (collectionName: string) => Promise<CryptoKey> {\n let getDEKFn: ((collectionName: string) => Promise<CryptoKey>) | null = null\n return async (collectionName: string): Promise<CryptoKey> => {\n if (!getDEKFn) {\n getDEKFn = await ensureCollectionDEK(this.adapter, this.name, this.keyring)\n }\n return getDEKFn(collectionName)\n }\n }\n\n /**\n * Open a typed collection within this vault.\n *\n * - `options.indexes` declares secondary indexes for the query DSL.\n * Indexes are computed in memory after decryption; adapters never\n * see plaintext index data.\n * - `options.prefetch` (default `true`) controls hydration. Eager mode\n * loads everything on first access; lazy mode (`prefetch: false`)\n * loads records on demand and bounds memory via the LRU cache.\n * - `options.cache` configures the LRU bounds. Required in lazy mode.\n * Accepts `{ maxRecords, maxBytes: '50MB' | 1024 }`.\n * - `options.schema` attaches a Standard Schema v1 validator (Zod,\n * Valibot, ArkType, Effect Schema, etc.). Every `put()` is validated\n * before encryption; every read is validated after decryption.\n * Failing records throw `SchemaValidationError`.\n * - `options.i18nFields` declares per-field `i18nText()` descriptors\n *. Validated on `put()` and locale-resolved on reads.\n * - `options.dictKeyFields` declares per-field `dictKey()` descriptors\n *. `put()` validates keys against the declared set; reads\n * with `{ locale }` add `<field>Label` virtual fields.\n *\n * Throws `ReservedCollectionNameError` for names starting with `_dict_`.\n * Use `vault.dictionary(name)` to access dictionary collections.\n *\n * Lazy mode + indexes is rejected at construction time — see the\n * Collection constructor for the rationale.\n */\n collection<T>(collectionName: string, options?: {\n indexes?: IndexDef[]\n /** — auto-reconcile policy for persisted-index drift. */\n reconcileOnOpen?: 'off' | 'dry-run' | 'auto'\n prefetch?: boolean\n cache?: CacheOptions\n schema?: StandardSchemaV1<unknown, T>\n refs?: Record<string, RefDescriptor>\n /** — declare i18nText fields for locale-aware reads. */\n i18nFields?: Record<string, I18nTextDescriptor>\n /** — declare dictKey fields for label resolution on reads. */\n dictKeyFields?: Record<string, DictKeyDescriptor>\n /** — per-collection conflict resolution policy. */\n conflictPolicy?: ConflictPolicy<T>\n /** — CRDT mode for collaborative editing without conflicts. */\n crdt?: CrdtMode\n /**\n * declare deterministic-encryption fields for blind\n * equality search. See `Collection` constructor docs for the full\n * trade-off. Requires `acknowledgeDeterministicRisk: true`.\n */\n deterministicFields?: readonly string[]\n /** — explicit ack that deterministic encryption leaks equality. */\n acknowledgeDeterministicRisk?: boolean\n /**\n * declarative blob retention / TTL policy per slot\n * name. Values are `{ retainDays?, evictWhen? }`. Evaluated only\n * when `vault.compact()` runs.\n */\n blobFields?: BlobFieldsConfig<T>\n /** — declared tiers for this collection. */\n tiers?: readonly number[]\n /** — how lower-tier reads see above-tier records. */\n tierMode?: TierMode\n }): Collection<T> {\n // Guard: reject reserved _dict_* names\n if (isDictCollectionName(collectionName)) {\n throw new ReservedCollectionNameError(collectionName)\n }\n\n let coll = this.collectionCache.get(collectionName)\n if (!coll) {\n // Register ref declarations (if any) with the vault-level\n // registry BEFORE constructing the Collection. This way the\n // first put() on the new collection already sees its refs via\n // vault.enforceRefsOnPut.\n if (options?.refs) {\n this.refRegistry.register(collectionName, options.refs)\n }\n\n // Register i18nText fields\n if (options?.i18nFields) {\n this.i18nFieldRegistry.set(collectionName, options.i18nFields)\n }\n\n // register blobFields retention/TTL policy\n if (options?.blobFields) {\n this.blobFieldsRegistry.set(collectionName, options.blobFields as BlobFieldsConfig<unknown>)\n }\n\n // Register dictKey fields: store field → dictionary name mapping\n if (options?.dictKeyFields) {\n const dictFieldMap: Record<string, string> = {}\n for (const [field, desc] of Object.entries(options.dictKeyFields)) {\n dictFieldMap[field] = desc.name\n }\n this.dictKeyFieldRegistry.set(collectionName, dictFieldMap)\n }\n\n const collOpts: ConstructorParameters<typeof Collection<T>>[0] = {\n adapter: this.adapter,\n vault: this.name,\n name: collectionName,\n keyring: this.keyring,\n encrypted: this.encrypted,\n emitter: this.emitter,\n getDEK: this.getDEK,\n onDirty: this.onDirty,\n historyConfig: this.historyConfig,\n // thread the vault-wide blob strategy into every\n // collection. `undefined` is intentionally preserved so the\n // Collection constructor uses its NO_BLOBS default.\n ...(this.blobStrategy !== undefined ? { blobStrategy: this.blobStrategy } : {}),\n ...(this.indexStrategy !== undefined ? { indexStrategy: this.indexStrategy } : {}),\n ...(this.aggregateStrategy !== undefined ? { aggregateStrategy: this.aggregateStrategy } : {}),\n ...(this.crdtStrategy !== undefined ? { crdtStrategy: this.crdtStrategy } : {}),\n historyStrategy: this.historyStrategy,\n i18nStrategy: this.i18nStrategy,\n syncStrategy: this.syncStrategy,\n ledger: this.getLedgerOrNull() ?? undefined,\n refEnforcer: this,\n joinResolver: this,\n defaultLocale: this.locale,\n onRegisterConflictResolver: this.onRegisterConflictResolver,\n onAccess: (op, id) => this._logConsent(op, collectionName, id),\n periodGuard: (existing, incoming) => this._assertTsWritable(existing, incoming),\n }\n if (options?.indexes !== undefined) collOpts.indexes = options.indexes\n if (options?.reconcileOnOpen !== undefined) collOpts.reconcileOnOpen = options.reconcileOnOpen\n if (options?.prefetch !== undefined) collOpts.prefetch = options.prefetch\n if (options?.cache !== undefined) collOpts.cache = options.cache\n if (options?.schema !== undefined) collOpts.schema = options.schema\n if (options?.conflictPolicy !== undefined) collOpts.conflictPolicy = options.conflictPolicy\n if (options?.crdt !== undefined) collOpts.crdt = options.crdt\n if (options?.deterministicFields !== undefined) {\n collOpts.deterministicFields = options.deterministicFields\n }\n if (options?.acknowledgeDeterministicRisk !== undefined) {\n collOpts.acknowledgeDeterministicRisk = options.acknowledgeDeterministicRisk\n }\n if (options?.tiers !== undefined) collOpts.tiers = options.tiers\n if (options?.tierMode !== undefined) collOpts.tierMode = options.tierMode\n collOpts.onCrossTierAccess = (event) => this.emitCrossTier(event)\n if (this.syncAdapter !== undefined) collOpts.syncAdapter = this.syncAdapter\n if (options?.i18nFields !== undefined) collOpts.i18nFields = options.i18nFields\n if (options?.dictKeyFields !== undefined) {\n // Build the label resolver callback for this collection\n collOpts.dictLabelResolver = async (dictName, key, locale, fallback) => {\n const handle = this.dictionary(dictName)\n return handle.resolveLabel(key, locale, fallback)\n }\n collOpts.dictKeyFields = options.dictKeyFields\n }\n // i18n validation on put — enforced via the compartment's put hook\n if (options?.i18nFields !== undefined || options?.dictKeyFields !== undefined) {\n collOpts.i18nPutValidator = (record: unknown) => {\n this.enforceI18nOnPut(collectionName, record)\n }\n }\n // Wire the translator for autoTranslate: true fields\n if (options?.i18nFields !== undefined && this.translateText) {\n collOpts.autoTranslateHook = this.translateText\n }\n coll = new Collection<T>(collOpts)\n this.collectionCache.set(collectionName, coll)\n }\n return coll as Collection<T>\n }\n\n /**\n * Validate i18nText fields on a `put()`. Called by Collection just\n * before the adapter write, after schema validation. Throws\n * `MissingTranslationError` when a required translation is absent.\n */\n enforceI18nOnPut(collectionName: string, record: unknown): void {\n const i18nFields = this.i18nFieldRegistry.get(collectionName)\n if (!i18nFields || Object.keys(i18nFields).length === 0) return\n if (!record || typeof record !== 'object') return\n\n const obj = record as Record<string, unknown>\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n const value = obj[field]\n if (value === undefined || value === null) continue\n this.i18nStrategy.validateI18nTextValue(value, field, descriptor)\n }\n }\n\n /**\n * Apply locale resolution to a record for the given collection.\n *\n * Called by Collection after decryption when locale options are present.\n * Returns a new object (never mutates the cached record).\n */\n async applyLocale(\n collectionName: string,\n record: Record<string, unknown>,\n localeOpts: LocaleReadOptions,\n ): Promise<Record<string, unknown>> {\n const locale = localeOpts.locale ?? this.locale\n if (!locale) return record\n\n let result = record\n\n // 1. i18nText resolution\n const i18nFields = this.i18nFieldRegistry.get(collectionName)\n if (i18nFields && Object.keys(i18nFields).length > 0) {\n result = this.i18nStrategy.applyI18nLocale(result, i18nFields, locale, localeOpts.fallback)\n }\n\n // 2. dictKey label resolution — add <field>Label virtual fields\n const dictFields = this.dictKeyFieldRegistry.get(collectionName)\n if (dictFields && Object.keys(dictFields).length > 0 && locale !== 'raw') {\n const withLabels = { ...result }\n for (const [field, dictName] of Object.entries(dictFields)) {\n const key = result[field]\n if (typeof key !== 'string') continue\n const handle = this.dictionary(dictName)\n const label = await handle.resolveLabel(key, locale, localeOpts.fallback)\n if (label !== undefined) {\n withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n return result\n }\n\n /**\n * Open a dictionary by name. Returns a `DictionaryHandle` for CRUD\n * operations on the `_dict_<name>/` reserved collection.\n *\n * The handle is cached — multiple calls with the same name return the\n * same instance.\n *\n * @param name The dictionary name (e.g. `'status'` → `_dict_status/`).\n * @param options Optional ACL overrides (default `writableBy: 'admin'`).\n *\n * @example\n * ```ts\n * await company.dictionary('status').putAll({\n * draft: { en: 'Draft', th: 'ฉบับร่าง' },\n * paid: { en: 'Paid', th: 'ชำระแล้ว' },\n * })\n * ```\n */\n dictionary<Keys extends string = string>(\n name: string,\n options: DictionaryOptions = {},\n ): DictionaryHandle<Keys> {\n let handle = this.dictionaryCache.get(name)\n if (!handle) {\n handle = this.i18nStrategy.buildDictionaryHandle<Keys>({\n adapter: this.adapter,\n compartmentName: this.name,\n dictionaryName: name,\n keyring: this.keyring,\n getDEK: this.getDEK,\n encrypted: this.encrypted,\n ledger: this.getLedgerOrNull() ?? undefined,\n options,\n // findAndUpdateReferences: rewrite dictKey fields in all\n // registered collections when rename() is called\n findAndUpdateReferences: async (dictionaryName, oldKey, newKey) => {\n for (const [collectionName, dictFields] of this.dictKeyFieldRegistry) {\n // Find fields that point at this dictionary\n const fields = Object.entries(dictFields)\n .filter(([, dn]) => dn === dictionaryName)\n .map(([field]) => field)\n if (fields.length === 0) continue\n\n const coll = this.collection<Record<string, unknown>>(collectionName)\n const records = await coll.list()\n for (const record of records) {\n let changed = false\n const updated = { ...record }\n for (const field of fields) {\n if (updated[field] === oldKey) {\n updated[field] = newKey\n changed = true\n }\n }\n if (changed) {\n const id = (record['id'] as string | undefined)\n if (id !== undefined) {\n await coll.put(id, updated)\n }\n }\n }\n }\n },\n emitter: this.emitter,\n })\n this.dictionaryCache.set(name, handle)\n }\n return handle as DictionaryHandle<Keys>\n }\n\n /**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins\n *. Returns a source whose snapshot contains `{ key, ...labels }`\n * records — one per dictionary entry — keyed by the stable key.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n *\n * The snapshot is built synchronously from whatever the dictionary\n * handle has in its cached state. For empty dictionaries this returns\n * an empty snapshot rather than `null`.\n */\n /**\n * Build a `JoinableSource` for a dictKey field, for use in dict joins\n *. Returns a source whose snapshot contains\n * `{ key, labels, ...labels }` records — one per dictionary entry —\n * keyed by the stable key.\n *\n * The snapshot is built synchronously from the DictionaryHandle's\n * write-through cache, which is populated on every `put()`, `rename()`,\n * `delete()`, and `list()` call. For pre-existing data not yet touched\n * this session, call `await vault.dictionary(name).list()` first\n * to warm the cache.\n *\n * Returns `null` when `field` is not a dictKey in `leftCollection`.\n */\n resolveDictSource(leftCollection: string, field: string): JoinableSource | null {\n const dictFields = this.dictKeyFieldRegistry.get(leftCollection)\n if (!dictFields || !(field in dictFields)) return null\n const dictName = dictFields[field]\n if (!dictName) return null\n const handle = this.dictionary(dictName)\n return {\n snapshot(): readonly unknown[] {\n return handle.snapshotEntries()\n },\n lookupById(id: string): unknown {\n const entries = handle.snapshotEntries()\n return entries.find((e) => e['key'] === id)\n },\n }\n }\n\n /**\n * Set or update the vault-default locale at runtime.\n * Useful when the user switches their preferred language after opening\n * the vault.\n */\n setLocale(locale: string | undefined): void {\n this.locale = locale\n }\n\n /** Return the current vault-default locale. */\n getLocale(): string | undefined {\n return this.locale\n }\n\n /**\n * The user id of the keyring backing this vault session. Useful for\n * UI affordances (\"you are alice\"), audit trails, and orchestration\n * composables that need to stamp records with the current actor.\n */\n get userId(): string {\n return this.keyring.userId\n }\n\n /**\n * The role of the keyring backing this vault session — one of\n * `owner | admin | operator | viewer | client`. Useful for UI\n * affordance gates and approval workflows that need to confirm\n * the caller can perform a given action before attempting it.\n */\n get role(): Role {\n return this.keyring.role\n }\n\n /**\n * Build keyring files for bundle recipients without persisting them\n * to the source vault. Used by `writeNoydbBundle()` when the bundle\n * is re-keyed for distinct recipients.\n *\n * Each recipient becomes its own `KeyringFile` sealed with that\n * recipient's passphrase. The DEKs wrapped into each slot are\n * exactly those the recipient's role + permissions justify, and\n * never wider than the source keyring's own DEK set\n * (privilege-escalation check).\n *\n * Returns a `Record<userId, KeyringFile>` ready to substitute for\n * the `keyrings` field of a `vault.dump()` JSON. Adapter is never\n * touched; the produced files exist only in the bundle bytes.\n *\n * @public\n */\n async buildBundleRecipientKeyrings(\n recipients: readonly BundleRecipient[],\n ): Promise<Record<string, KeyringFile>> {\n const result: Record<string, KeyringFile> = {}\n for (const recipient of recipients) {\n if (recipient.id in result) {\n throw new Error(`buildBundleRecipientKeyrings: duplicate recipient id \"${recipient.id}\"`)\n }\n result[recipient.id] = await buildRecipientKeyringFile(this.keyring, recipient)\n }\n return result\n }\n\n /**\n * Authorize an `@noy-db/as-*` export against the current keyring's\n * `exportCapability`. Throws `ExportCapabilityError` if\n * the invoking keyring is not authorised.\n *\n * `as-*` packages MUST call this before invoking the underlying\n * export primitive (`exportStream()` / `writeNoydbBundle()` / …).\n *\n * - `assertCanExport('plaintext', 'xlsx')` — check plaintext tier\n * for a specific format. Defaults to empty for every role; owner\n * must positively grant.\n * - `assertCanExport('bundle')` — check encrypted-bundle tier.\n * Defaults to on for owner/admin, off for others.\n *\n * See `docs/patterns/as-exports.md` for the full policy.\n */\n assertCanExport(tier: 'plaintext', format: ExportFormat): void\n assertCanExport(tier: 'bundle'): void\n assertCanExport(tier: 'plaintext' | 'bundle', format?: ExportFormat): void {\n if (tier === 'plaintext') {\n if (format === undefined) {\n throw new Error('vault.assertCanExport: plaintext tier requires a format')\n }\n if (!hasExportCapability(this.keyring, 'plaintext', format)) {\n throw new ExportCapabilityError({\n tier: 'plaintext',\n userId: this.keyring.userId,\n format,\n })\n }\n return\n }\n if (!hasExportCapability(this.keyring, 'bundle')) {\n throw new ExportCapabilityError({\n tier: 'bundle',\n userId: this.keyring.userId,\n })\n }\n }\n\n /**\n * Authorize an `@noy-db/as-*` import against the current keyring's\n * `importCapability` (issue ). Throws `ImportCapabilityError` if\n * the invoking keyring is not authorised.\n *\n * `as-*` reader entry-points (`fromString` / `fromBytes`) MUST call\n * this before parsing or building an `ImportPlan`.\n *\n * - `assertCanImport('plaintext', 'csv')` — check plaintext-tier\n * import for a specific format. Default-closed for every role.\n * - `assertCanImport('bundle')` — check `.noydb` bundle-import gate.\n * Default-closed for every role, including owner — import is more\n * dangerous than export (corrupts vs leaks).\n *\n * Owner who wants to import re-grants own keyring with\n * `importCapability` set explicitly.\n */\n assertCanImport(tier: 'plaintext', format: ExportFormat): void\n assertCanImport(tier: 'bundle'): void\n assertCanImport(tier: 'plaintext' | 'bundle', format?: ExportFormat): void {\n if (tier === 'plaintext') {\n if (format === undefined) {\n throw new Error('vault.assertCanImport: plaintext tier requires a format')\n }\n if (!hasImportCapability(this.keyring, 'plaintext', format)) {\n throw new ImportCapabilityError({\n tier: 'plaintext',\n userId: this.keyring.userId,\n format,\n })\n }\n return\n }\n if (!hasImportCapability(this.keyring, 'bundle')) {\n throw new ImportCapabilityError({\n tier: 'bundle',\n userId: this.keyring.userId,\n })\n }\n }\n\n /**\n * Bulk blob extraction primitive.\n *\n * Returns an async-iterable handle over every blob attached to\n * records in the vault. Single capability check (`plaintext/blob`)\n * at handle creation; single audit entry to `_export_audit` before\n * the first yield. Per-blob decryption happens lazily as the\n * consumer pulls tuples.\n *\n * ```ts\n * const handle = vault.exportBlobs({\n * collections: ['invoiceScans'],\n * where: (rec) => (rec as { clientId?: string }).clientId === 'c-123',\n * })\n * for await (const { bytes, meta, recordRef } of handle) {\n * await uploadToColdStorage(bytes, recordRef)\n * }\n * ```\n *\n * @see `@noy-db/hub/store/export-blobs` for the full option surface.\n */\n /**\n * Evict blob slots per the per-collection `blobFields` retention\n * policy.\n *\n * Iterates every collection declared with `{ blobFields: {...} }`.\n * For each record, checks every configured slot against its\n * policy — `retainDays` (age-based TTL) and/or `evictWhen(record)`\n * (predicate) — and evicts matching slots. Every eviction writes\n * one entry to `_blob_eviction_audit` (actor + eTag + reason +\n * timestamp, no plaintext). Consumer-scheduled; noy-db never runs\n * this on its own.\n *\n * ```ts\n * await vault.compact() // run full pass\n * await vault.compact({ dryRun: true }) // preview counts\n * await vault.compact({ maxEvictions: 1000 }) // cap batch\n * ```\n */\n async compact(options: CompactRunOptions = {}): Promise<CompactionResult> {\n return runCompaction({\n adapter: this.adapter,\n vault: this.name,\n actor: this.keyring.userId,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n getBlobFields: <T>(name: string): BlobFieldsConfig<T> | null =>\n (this.blobFieldsRegistry.get(name) as BlobFieldsConfig<T> | undefined) ?? null,\n listCollections: () => this.collections(),\n listRecords: (name: string) => this.adapter.list(this.name, name),\n getRecord: async <T>(name: string, id: string) => {\n const coll = this.collection<T>(name)\n return coll.get(id)\n },\n listSlots: async (name: string, id: string) => {\n const coll = this.collection(name)\n return coll.blob(id).list()\n },\n deleteSlot: async (name: string, id: string, slotName: string) => {\n const coll = this.collection(name)\n await coll.blob(id).delete(slotName)\n },\n }, options)\n }\n\n exportBlobs(options: ExportBlobsOptions = {}): ExportBlobsHandle {\n this.assertCanExport('plaintext', 'blob')\n return createExportBlobsHandle(\n this.keyring.userId,\n () => this.collections(),\n (name) => this.collection(name),\n (entry) => this.writeExportAudit(entry),\n options,\n )\n }\n\n private async writeExportAudit(entry: ExportBlobsAuditEntry): Promise<void> {\n const json = JSON.stringify(entry)\n const envelope: EncryptedEnvelope = this.encrypted\n ? await (async () => {\n const dek = await this.getDEK(EXPORT_AUDIT_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n return { _noydb: NOYDB_FORMAT_VERSION, _v: 1, _ts: entry.startedAt, _iv: iv, _data: data, _by: entry.actor }\n })()\n : { _noydb: NOYDB_FORMAT_VERSION, _v: 1, _ts: entry.startedAt, _iv: '', _data: json, _by: entry.actor }\n await this.adapter.put(this.name, EXPORT_AUDIT_COLLECTION, entry.id, envelope)\n }\n\n /**\n * Read-only accessor for the invoking keyring's export capability,\n * with role-based defaults resolved. Useful for UI affordances\n * (grey out the export button if no capability) without throwing.\n */\n canExport(tier: 'plaintext', format: ExportFormat): boolean\n canExport(tier: 'bundle'): boolean\n canExport(tier: 'plaintext' | 'bundle', format?: ExportFormat): boolean {\n if (tier === 'plaintext') {\n if (format === undefined) return false\n return hasExportCapability(this.keyring, 'plaintext', format)\n }\n return hasExportCapability(this.keyring, 'bundle')\n }\n\n /**\n * Decrypt a single envelope using the per-collection DEK, returning\n * the parsed plaintext record. Internal helper for bundle-pipeline\n * plaintext filters — keeps DEK access encapsulated\n * inside Vault so callers don't reach into private state.\n *\n * @internal\n */\n async _decryptEnvelopeForBundleFilter(\n env: EncryptedEnvelope,\n collectionName: string,\n ): Promise<unknown> {\n if (!this.encrypted) {\n return JSON.parse(env._data)\n }\n const dek = await this.getDEK(collectionName)\n const json = await decrypt(env._iv, env._data, dek)\n return JSON.parse(json)\n }\n\n /**\n * Read-only accessor for the invoking keyring's import capability\n * (issue ). UI affordance — returns false in every default-closed\n * case (every role with no explicit `importCapability` grant).\n */\n canImport(tier: 'plaintext', format: ExportFormat): boolean\n canImport(tier: 'bundle'): boolean\n canImport(tier: 'plaintext' | 'bundle', format?: ExportFormat): boolean {\n if (tier === 'plaintext') {\n if (format === undefined) return false\n return hasImportCapability(this.keyring, 'plaintext', format)\n }\n return hasImportCapability(this.keyring, 'bundle')\n }\n\n /**\n * Enforce strict outbound refs on a `put()`. Called by Collection\n * just before it writes to the adapter. For every strict ref\n * declared on the collection, check that the target id exists in\n * the target collection; throw `RefIntegrityError` if not.\n *\n * `warn` and `cascade` modes don't affect put semantics — they're\n * enforced at delete time or via `checkIntegrity()`.\n */\n async enforceRefsOnPut(collectionName: string, record: unknown): Promise<void> {\n const outbound = this.refRegistry.getOutbound(collectionName)\n if (Object.keys(outbound).length === 0) return\n if (!record || typeof record !== 'object') return\n const obj = record as Record<string, unknown>\n\n for (const [field, descriptor] of Object.entries(outbound)) {\n if (descriptor.mode !== 'strict') continue\n const rawId = obj[field]\n // Nullish ref values are allowed — treat them as \"no reference\".\n // Users who want \"always required\" should express it in their\n // Standard Schema validator via a non-optional field.\n if (rawId === null || rawId === undefined) continue\n // Refs must be strings or numbers — anything else (object,\n // array, boolean) is a programming error and should fail\n // loudly rather than serialize as \"[object Object]\".\n if (typeof rawId !== 'string' && typeof rawId !== 'number') {\n throw new RefIntegrityError({\n collection: collectionName,\n id: (obj['id'] as string | undefined) ?? '<unknown>',\n field,\n refTo: descriptor.target,\n refId: null,\n message:\n `Ref field \"${collectionName}.${field}\" must be a string or number, got ${typeof rawId}.`,\n })\n }\n const refId = String(rawId)\n const target = this.collection<Record<string, unknown>>(descriptor.target)\n const exists = await target.get(refId)\n if (!exists) {\n throw new RefIntegrityError({\n collection: collectionName,\n id: (obj['id'] as string | undefined) ?? '<unknown>',\n field,\n refTo: descriptor.target,\n refId,\n message:\n `Strict ref \"${collectionName}.${field}\" → \"${descriptor.target}\" ` +\n `cannot be satisfied: target id \"${refId}\" not found in \"${descriptor.target}\".`,\n })\n }\n }\n }\n\n /**\n * Enforce inbound ref modes on a `delete()`. Called by Collection\n * just before it deletes from the adapter. Walks every inbound\n * ref that targets this (collection, id) and:\n *\n * - `strict`: throws if any referencing records exist\n * - `cascade`: deletes every referencing record\n * - `warn`: no-op (checkIntegrity picks it up)\n *\n * Cascade cycles are broken via `cascadeInProgress` — re-entering\n * for the same (collection, id) returns immediately so two\n * mutually-cascading collections don't recurse forever.\n */\n async enforceRefsOnDelete(collectionName: string, id: string): Promise<void> {\n const key = `${collectionName}/${id}`\n if (this.cascadeInProgress.has(key)) return\n this.cascadeInProgress.add(key)\n\n try {\n const inbound = this.refRegistry.getInbound(collectionName)\n for (const rule of inbound) {\n const fromCollection = this.collection<Record<string, unknown>>(rule.collection)\n // Scan the referencing collection for records whose ref\n // field matches this id. For eager-mode collections this\n // is an in-memory filter; for lazy-mode it requires a scan.\n const allRecords = await fromCollection.list()\n const matches = allRecords.filter((rec) => {\n const raw = rec[rule.field]\n // Same string/number-only restriction as enforceRefsOnPut.\n // Anything else can't have been a valid ref to begin with,\n // so it can't match.\n if (typeof raw !== 'string' && typeof raw !== 'number') return false\n return String(raw) === id\n })\n if (matches.length === 0) continue\n\n if (rule.mode === 'strict') {\n const first = matches[0]\n throw new RefIntegrityError({\n collection: rule.collection,\n id: (first?.['id'] as string | undefined) ?? '<unknown>',\n field: rule.field,\n refTo: collectionName,\n refId: id,\n message:\n `Cannot delete \"${collectionName}\"/\"${id}\": ` +\n `${matches.length} record(s) in \"${rule.collection}\" still reference it via strict ref \"${rule.field}\".`,\n })\n }\n if (rule.mode === 'cascade') {\n for (const match of matches) {\n const matchId = (match['id'] as string | undefined) ?? null\n if (matchId === null) continue\n // Recursive delete — the cycle breaker above catches\n // infinite loops.\n await fromCollection.delete(matchId)\n }\n }\n // warn: no-op\n }\n } finally {\n this.cascadeInProgress.delete(key)\n }\n }\n\n // ─── Join resolver) ────────────────────\n\n /**\n * Look up the `RefDescriptor` the left collection declared for a\n * given field name. Returns `null` when the field has no ref\n * declaration — the Query builder turns that into an actionable\n * error at plan time (before any records are touched).\n *\n * Implements the `joinResolver.resolveRef` half of the structural\n * interface that `Collection.query()` consumes. See\n * `query/join.ts` for the full design.\n */\n resolveRef(leftCollection: string, field: string): RefDescriptor | null {\n const outbound = this.refRegistry.getOutbound(leftCollection)\n return outbound[field] ?? null\n }\n\n /**\n * Resolve a right-side join source by target collection name.\n * Returns `null` for unknown collections so the Query executor can\n * surface an actionable error naming the missing target.\n *\n * Implements the `joinResolver.resolveSource` half of the\n * structural interface. The returned JoinableSource is a thin\n * wrapper that reads the target collection's in-memory cache via\n * `list()` / `get()` synchronously — the cache is populated by an\n * earlier `ensureHydrated()` call through the target's query/list\n * path. If the target has not been opened yet in this session the\n * join will see an empty snapshot; consumers who hit this can\n * open the target collection explicitly before running the query.\n *\n * Only same-vault targets are resolvable — cross-vault\n * joins are explicitly forbidden by the architecture`).\n */\n resolveSource(collectionName: string): JoinableSource | null {\n // Reject internal / reserved collection names — joins against\n // `_ledger/`, `_keyring/`, `_deltas/`, etc. are never legitimate.\n if (collectionName.startsWith('_')) return null\n const coll = this.collectionCache.get(collectionName)\n if (!coll) return null\n // Collection exposes a structural `querySourceForJoin()` method\n // that returns a lightweight snapshot/lookupById view backed by\n // its in-memory cache. Typed as unknown here because\n // Collection<T> is covariant on T — the join executor only\n // reads fields by name and doesn't care about the concrete type.\n return (coll as unknown as {\n querySourceForJoin(): JoinableSource\n }).querySourceForJoin()\n }\n\n /**\n * Walk every collection that has declared refs, load its records,\n * and report any reference whose target id is missing. Modes are\n * reported alongside each violation so the caller can distinguish\n * \"this is a warning the user asked for\" from \"this should never\n * have happened\" (strict violations produced by out-of-band\n * writes).\n *\n * Returns `{ violations: [...] }` instead of throwing — the whole\n * point of `checkIntegrity()` is to surface a list for display\n * or repair, not to fail noisily.\n */\n async checkIntegrity(): Promise<{ violations: RefViolation[] }> {\n const violations: RefViolation[] = []\n for (const [collectionName, refs] of this.refRegistry.entries()) {\n const coll = this.collection<Record<string, unknown>>(collectionName)\n const records = await coll.list()\n for (const record of records) {\n const recId = (record['id'] as string | undefined) ?? '<unknown>'\n for (const [field, descriptor] of Object.entries(refs)) {\n const rawId = record[field]\n if (rawId === null || rawId === undefined) continue\n // Non-scalar ref values are flagged as a violation rather\n // than thrown — `checkIntegrity` is a \"report what's wrong\"\n // tool, not a \"block on first failure\" tool. The thrown\n // version lives in `enforceRefsOnPut`.\n if (typeof rawId !== 'string' && typeof rawId !== 'number') {\n violations.push({\n collection: collectionName,\n id: recId,\n field,\n refTo: descriptor.target,\n refId: rawId,\n mode: descriptor.mode,\n })\n continue\n }\n const refId = String(rawId)\n const target = this.collection<Record<string, unknown>>(descriptor.target)\n const exists = await target.get(refId)\n if (!exists) {\n violations.push({\n collection: collectionName,\n id: recId,\n field,\n refTo: descriptor.target,\n refId: rawId,\n mode: descriptor.mode,\n })\n }\n }\n }\n }\n return { violations }\n }\n\n /**\n * Return this compartment's hash-chained audit log.\n *\n * The ledger is lazy-initialized on first access and cached for the\n * lifetime of the Vault instance. Every LedgerStore instance\n * shares the same adapter and DEK resolver, so `vault.ledger()`\n * can be called repeatedly without performance cost.\n *\n * The LedgerStore itself is the public API: consumers call\n * `.append()` (via Collection internals), `.head()`, `.verify()`,\n * and `.entries({ from, to })`. See the LedgerStore docstring for\n * the full surface and the concurrency caveats.\n */\n ledger(): LedgerStore {\n const store = this.getLedgerOrNull()\n if (!store) {\n throw new Error(\n 'vault.ledger() requires the history strategy. Import ' +\n '`{ withHistory }` from \"@noy-db/hub/history\" and pass it to ' +\n '`createNoydb({ historyStrategy: withHistory() })`.',\n )\n }\n return store\n }\n\n /**\n * Internal accessor — returns the LedgerStore if the history\n * strategy is opted in, or `null` otherwise. Used by dump/restore/\n * verifyBackupIntegrity and by Collection write paths that already\n * gate on `if (this.ledger)`. The public `ledger()` accessor above\n * throws on null; this one stays silent so the off-path no-ops.\n */\n private getLedgerOrNull(): LedgerStore | null {\n if (!this.ledgerStore) {\n this.ledgerStore = this.historyStrategy.buildLedger({\n adapter: this.adapter,\n vault: this.name,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n actor: this.keyring.userId,\n })\n }\n return this.ledgerStore\n }\n\n /**\n * Return a read-only view of this vault as it existed at\n * `timestamp`. Time-machine queries are reconstructed from the\n * per-version history snapshots persisted by every `put()`, then\n * cross-checked against the ledger for deletes that happened\n * between the snapshot and the target timestamp.\n *\n * ```ts\n * const q1End = vault.at('2026-03-31T23:59:59Z')\n * const invoice = await q1End.collection<Invoice>('invoices').get('inv-001')\n * // → the record as it stood at the close of Q1 2026\n * ```\n *\n * `timestamp` accepts an ISO-8601 string or a `Date`. Time-machine\n * views are read-only — writes throw {@link ReadOnlyAtInstantError}.\n * Accuracy bounded by history retention: if `historyConfig.maxVersions`\n * pruned earlier versions, queries before the oldest retained\n * snapshot return null even for records that existed.\n *\n *.\n */\n at(timestamp: string | Date): VaultInstant {\n const iso = timestamp instanceof Date ? timestamp.toISOString() : timestamp\n return this.historyStrategy.buildVaultInstant(\n {\n adapter: this.adapter,\n name: this.name,\n encrypted: this.encrypted,\n getDEK: this.getDEK,\n getLedger: () => (this.historyConfig.enabled === false ? null : this.getLedgerOrNull()),\n },\n iso,\n )\n }\n\n /**\n * Return a read-only \"shadow\" view of this vault. Every read method\n * on the returned {@link VaultFrame} delegates to the underlying\n * live collection; every write method throws\n * {@link ReadOnlyFrameError}.\n *\n * ```ts\n * const presentation = vault.frame()\n * const invoices = await presentation.collection<Invoice>('invoices').list()\n * ```\n *\n * Use for screen-sharing a live vault, demo mode, or compliance\n * review where the reviewer should not be able to edit. Writes are\n * blocked at the JavaScript layer — the keyring DEKs are unchanged,\n * so this is **not** a cryptographic security boundary against a\n * hostile caller in the same process. See {@link VaultFrame} for\n * the full caveat.\n *\n *.\n */\n frame(): VaultFrame {\n return this.shadowStrategy.buildFrame(this)\n }\n\n /**\n * Run `fn` under a consent scope. Every `get` / `put` / `delete`\n * that happens inside `fn` writes one entry to `_consent_audit`\n * with the supplied `purpose` and `consentHash`. Outside a scope,\n * no entries are written — consent logging is opt-in by design.\n *\n * ```ts\n * await vault.withConsent(\n * { purpose: 'quarterly-review', consentHash: '7f3a...' },\n * async () => {\n * const invoices = await vault.collection<Invoice>('invoices').list()\n * return invoices\n * },\n * )\n * ```\n *\n * The scope is a single slot on this Vault instance — two\n * concurrent `withConsent` calls stomp each other. Use separate\n * Vault instances (or an external `AsyncLocalStorage` shim) for\n * per-flight scoping.\n *\n *.\n */\n async withConsent<T>(ctx: ConsentContext, fn: () => Promise<T>): Promise<T> {\n const prior = this.consentContext\n this.consentContext = ctx\n try {\n return await fn()\n } finally {\n this.consentContext = prior\n }\n }\n\n /**\n * Query the consent-audit log. Returns every entry matching the\n * filter, newest-first isn't enforced — entries carry ULID ids so\n * sorting by id is insertion-order stable. Caller may sort further.\n *\n *.\n */\n async consentAudit(filter: ConsentAuditFilter = {}): Promise<ConsentAuditEntry[]> {\n return this.consentStrategy.read(this.adapter, this.name, this.encrypted, this.getDEK, filter)\n }\n\n /**\n * Called by Collection after every access when a consent scope is\n * active. Internal — not part of the public API.\n *\n * @internal\n */\n async _logConsent(op: ConsentOp, collection: string, recordId: string): Promise<void> {\n const ctx = this.consentContext\n if (!ctx) return\n await this.consentStrategy.write(\n this.adapter,\n this.name,\n this.encrypted,\n {\n actor: this.keyring.userId,\n purpose: ctx.purpose,\n consentHash: ctx.consentHash,\n op,\n collection,\n recordId,\n },\n this.getDEK,\n )\n }\n\n // ─── Hierarchical access ─────────────────────────\n\n /**\n * Subscribe to cross-tier access events. The callback fires every\n * time a record at a tier above the caller's inherent clearance is\n * read, written, elevated, or demoted successfully via this vault.\n * Returns an unsubscribe function.\n */\n onCrossTierAccess(\n listener: (event: CrossTierAccessEvent) => void,\n ): () => void {\n this.crossTierSubs.add(listener)\n return () => this.crossTierSubs.delete(listener)\n }\n\n private emitCrossTier(event: CrossTierAccessEvent): void {\n for (const sub of this.crossTierSubs) {\n try {\n sub(event)\n } catch {\n // subscriber failures are swallowed — audit sinks must be best-effort\n }\n }\n }\n\n /**\n * issue a time-boxed cross-tier delegation. Writes an\n * encrypted envelope to the reserved `_delegations` collection that\n * the target user's runtime will pick up next time they open the\n * vault.\n *\n * Caller must hold the tier DEK for the requested tier and\n * collection.\n */\n async delegate(opts: IssueDelegationOptions): Promise<DelegationToken> {\n const { issueDelegation, DELEGATIONS_COLLECTION } = await import('./team/delegation.js')\n // The target user's KEK is derived from THEIR keyring — we read\n // the keyring file to pick up the wrapped DEKs and their KEK salt,\n // but we cannot derive their KEK from our side (we don't have\n // their passphrase). For the delegation wraps against the\n // grantor's own KEK as a simpler first cut; swapping to a proper\n // per-target KEK exchange (via `on-magic-link` or OIDC) is a\n // follow-up tracked in the design doc.\n const targetKek = this.keyring.kek\n const delegationsDek = await this.getDEK(DELEGATIONS_COLLECTION)\n return issueDelegation(\n this.adapter,\n this.name,\n this.keyring,\n targetKek,\n delegationsDek,\n opts,\n )\n }\n\n /**\n * revoke an issued delegation by id. Safe to call even\n * if the id does not exist.\n */\n async revokeDelegation(id: string): Promise<void> {\n const { revokeDelegation, DELEGATIONS_COLLECTION } = await import('./team/delegation.js')\n await revokeDelegation(this.adapter, this.name, id)\n // Trigger store to note the delete.\n void DELEGATIONS_COLLECTION\n }\n\n // ─── Scoped tier elevation ───────────────────────────\n\n /**\n * Briefly elevate this vault to a higher tier and return a scoped\n * handle whose writes land at that tier. Reads on the original\n * vault continue at the caller's inherent tier; only the returned\n * handle is privileged. Auto-reverts when `release()` is called or\n * `ttlMs` elapses, whichever comes first.\n *\n * Capability semantics:\n * - The keyring must already carry a wrap for the target tier on\n * at least one collection (or be `owner` / `admin`, who can\n * auto-mint). Otherwise throws {@link TierNotGrantedError}.\n * - Per-collection capability gates (`canExportPlaintext`,\n * `canExportBundle`) are NOT bypassed — elevation is a tier\n * projection, not a privilege escalation path.\n * - Only one elevation can be active per vault at a time.\n * Calling `elevate(...)` while another is live throws\n * {@link AlreadyElevatedError}.\n *\n * Audit:\n * - One `_elevation_audit` envelope is written at start with\n * `{ id, actor, tier, reason, ttlMs, startedAt, expiresAt }`.\n * - Each write through the elevated handle additionally fires a\n * {@link CrossTierAccessEvent} with `authorization: 'elevation'`,\n * stamped with `reason` and `elevatedFrom`.\n */\n async elevate(\n tier: number,\n options: { ttlMs: number; reason: string },\n ): Promise<ElevatedHandle> {\n if (!Number.isInteger(tier) || tier <= 0) {\n throw new ValidationError(`elevate: tier must be a positive integer, got ${tier}`)\n }\n if (!options || typeof options.reason !== 'string' || options.reason.length === 0) {\n throw new ValidationError('elevate: reason is required (non-empty string)')\n }\n if (typeof options.ttlMs !== 'number' || options.ttlMs <= 0) {\n throw new ValidationError('elevate: ttlMs must be a positive number')\n }\n if (this.activeElevation) {\n throw new AlreadyElevatedError(this.activeElevation.tier)\n }\n // Construction-time tier-reach check: scan keyring for any\n // `*#${tier}` DEK. Owners and admins skip — they auto-mint at\n // write time per the existing `assertTierAccess` rules.\n if (this.keyring.role !== 'owner' && this.keyring.role !== 'admin') {\n const suffix = `#${tier}`\n let found = false\n for (const k of this.keyring.deks.keys()) {\n if (k.endsWith(suffix)) { found = true; break }\n }\n if (!found) {\n // Match the existing error class so adopters with one catch()\n // for tier-related failures don't need a second branch.\n throw new TierNotGrantedError('(any collection)', tier)\n }\n }\n\n const startedAt = new Date()\n const expiresAt = startedAt.getTime() + options.ttlMs\n const reason = options.reason\n\n const handle = new ElevatedHandle({\n vault: this,\n tier,\n reason,\n expiresAt,\n onRelease: () => {\n if (this.activeElevation && this.activeElevation.handle === handle) {\n this.activeElevation = null\n }\n },\n })\n\n this.activeElevation = { tier, expiresAt, reason, handle }\n await this.writeElevationAudit({\n actor: this.keyring.userId,\n tier,\n reason,\n ttlMs: options.ttlMs,\n startedAt: startedAt.toISOString(),\n expiresAt: new Date(expiresAt).toISOString(),\n })\n return handle\n }\n\n /**\n * Internal — invoked by an `ElevatedHandle.collection().put()` call.\n * Routes through the existing `Collection.putAtTier` code path with\n * the elevation context attached so the cross-tier event reflects\n * the right authorization class.\n */\n async _elevatedPut<T>(\n collectionName: string,\n id: string,\n record: T,\n tier: number,\n reason: string,\n ): Promise<void> {\n const coll = this.collection<T>(collectionName)\n await coll.putAtTier(id, record, tier, {\n elevation: { reason, fromTier: 0 },\n })\n }\n\n private async writeElevationAudit(entry: {\n actor: string\n tier: number\n reason: string\n ttlMs: number\n startedAt: string\n expiresAt: string\n }): Promise<void> {\n const id = `elev-${Date.now().toString(36)}-${Math.random().toString(16).slice(2, 10)}`\n const json = JSON.stringify({ id, ...entry })\n const envelope: EncryptedEnvelope = this.encrypted\n ? await (async () => {\n const dek = await this.getDEK(ELEVATION_AUDIT_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: entry.startedAt,\n _iv: iv,\n _data: data,\n _by: entry.actor,\n }\n })()\n : {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: entry.startedAt,\n _iv: '',\n _data: json,\n _by: entry.actor,\n }\n await this.adapter.put(this.name, ELEVATION_AUDIT_COLLECTION, id, envelope)\n }\n\n /**\n * low-level escape hatch used by `@noy-db/on-magic-link`\n * to persist a magic-link-bound grant after the auth package has\n * derived the content key + KEK from `(serverSecret, token, vault)`.\n *\n * Callers outside of `@noy-db/on-magic-link` should use\n * `issueMagicLinkDelegation()` from that package instead — it handles\n * the HKDF derivation, record-id composition, and batch logic so the\n * grantor doesn't touch this method directly.\n */\n async writeMagicLinkGrant(\n contentKey: CryptoKey,\n grantKek: CryptoKey,\n recordId: string,\n opts: IssueMagicLinkGrantOptions,\n ): Promise<MagicLinkGrantRecord> {\n return writeMagicLinkGrant(\n this.adapter,\n this.name,\n this.keyring,\n contentKey,\n grantKek,\n recordId,\n opts,\n )\n }\n\n // ─── Accounting periods ────────────────────────\n\n /**\n * Close an accounting period. After this call every record whose\n * envelope `_ts` is at or before `endDate` is write-locked: further\n * `put` or `delete` calls against such records throw\n * {@link PeriodClosedError}. New records (with fresh timestamps)\n * remain freely writable, and records last written AFTER `endDate`\n * are unaffected.\n *\n * Each closure writes a `PeriodRecord` to the reserved `_periods`\n * collection. The record carries the hash of the prior period's\n * record, so a tamper with any closure breaks the chain visible to\n * {@link listPeriods} + `vault.ledger().verify()`.\n *\n * Correctness is tied to the `_ts` field the hub assigns on every\n * write. Backdating records by editing the envelope directly is\n * outside the threat model — see SPEC § zero-knowledge envelopes.\n *\n *.\n */\n async closePeriod(options: ClosePeriodOptions): Promise<PeriodRecord> {\n const existing = await this._loadPeriodsCache()\n this.periodsStrategy.validatePeriodName(options.name, existing)\n if (typeof options.endDate !== 'string' || options.endDate.length === 0) {\n throw new ValidationError('closePeriod: endDate must be a non-empty ISO string.')\n }\n const anchor = await this.periodsStrategy.chainAnchor(existing)\n const record: PeriodRecord = {\n name: options.name,\n kind: 'closed',\n endDate: options.endDate,\n closedAt: new Date().toISOString(),\n closedBy: this.keyring.userId,\n priorPeriodHash: anchor.priorPeriodHash,\n ...(anchor.priorPeriodName !== undefined && { priorPeriodName: anchor.priorPeriodName }),\n ...(options.dateField !== undefined && { dateField: options.dateField }),\n }\n const envelope = await this._writePeriodRecord(record)\n await this.periodsStrategy.appendPeriodLedgerEntry(this.getLedgerOrNull(), this.keyring.userId, envelope, record.name)\n existing.push(record)\n this.periodCache = existing\n return record\n }\n\n /**\n * Open a new period that carries forward from a prior closed one\n *. The `carryForward` callback receives a read-only\n * {@link VaultInstant} view anchored at the prior period's\n * `endDate` — use it to compute opening balances, closing-trial\n * snapshots, or any aggregate the new period should inherit. The\n * returned `{ [collection]: { [id]: record } }` map is written\n * before the new `PeriodRecord` lands, so the opening entries\n * materialise with fresh `_ts` values that fall outside every\n * closed period (the guard lets them through).\n *\n * The new period is stored with `kind: 'opened'` and hash-chained\n * to the same chain the close calls build — `listPeriods()` sees\n * both closed and opened entries in `closedAt` order.\n */\n async openPeriod<TCollections extends Record<string, Record<string, unknown>>>(\n options: OpenPeriodOptions<TCollections>,\n ): Promise<PeriodRecord> {\n const existing = await this._loadPeriodsCache()\n this.periodsStrategy.validatePeriodName(options.name, existing)\n const prior = existing.find((p) => p.name === options.fromPeriod)\n if (!prior) {\n throw new ValidationError(\n `openPeriod: fromPeriod \"${options.fromPeriod}\" does not exist in this vault.`,\n )\n }\n if (prior.kind !== 'closed') {\n throw new ValidationError(\n `openPeriod: fromPeriod \"${options.fromPeriod}\" is of kind \"${prior.kind}\" — only closed periods can be carried forward.`,\n )\n }\n\n // Build a read-only facade over CURRENT state + the prior\n // period's endDate; after close, records dated <= endDate are\n // frozen so current state equals closing state. The caller\n // filters by business date via their own query against this\n // facade.\n const ctx = {\n priorEndDate: prior.endDate,\n collection: <T = unknown>(name: string) => {\n const c = this.collection<T>(name)\n return {\n get: (id: string) => c.get(id),\n list: () => c.list(),\n }\n },\n }\n const openings = await options.carryForward(ctx)\n\n // Write opening entries via the normal Collection path so they\n // get encryption, ledger entries, and change events. Each record\n // is timestamped NOW (outside every closed period) — that's why\n // the guard permits them.\n const openingCollections: string[] = []\n for (const [collName, records] of Object.entries(openings)) {\n if (!records || typeof records !== 'object') continue\n const recordEntries = Object.entries(records)\n if (recordEntries.length === 0) continue\n const coll = this.collection(collName)\n for (const [id, record] of recordEntries) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n await coll.put(id, record as any)\n }\n openingCollections.push(collName)\n }\n\n const anchor = await this.periodsStrategy.chainAnchor(existing)\n const record: PeriodRecord = {\n name: options.name,\n kind: 'opened',\n startDate: options.startDate,\n endDate: prior.endDate, // sealing boundary inherited from prior close\n closedAt: new Date().toISOString(),\n closedBy: this.keyring.userId,\n priorPeriodHash: anchor.priorPeriodHash,\n priorPeriodName: anchor.priorPeriodName ?? prior.name,\n ...(openingCollections.length > 0 && { openingCollections }),\n }\n const envelope = await this._writePeriodRecord(record)\n await this.periodsStrategy.appendPeriodLedgerEntry(this.getLedgerOrNull(), this.keyring.userId, envelope, record.name)\n existing.push(record)\n this.periodCache = existing\n return record\n }\n\n /** Return every closed / opened period in `closedAt` order. */\n async listPeriods(): Promise<readonly PeriodRecord[]> {\n return [...(await this._loadPeriodsCache())]\n }\n\n /** Look up a single period by name. Returns `null` if not found. */\n async getPeriod(name: string): Promise<PeriodRecord | null> {\n const all = await this._loadPeriodsCache()\n return all.find((p) => p.name === name) ?? null\n }\n\n /** @internal — periodGuard callback installed on every Collection. */\n async _assertTsWritable(\n existing: { ts: string | null; record: Record<string, unknown> | null } | null,\n incoming: Record<string, unknown> | null,\n ): Promise<void> {\n // Fast path: nothing to check, and no periods ever touched this\n // vault — avoid a full adapter scan for every put.\n if (existing === null && incoming === null) return\n if (this.periodCache === null) {\n this.periodCache = await this.periodsStrategy.loadPeriods(\n this.adapter,\n this.name,\n (env) => this._decryptPeriodRecord(env),\n )\n }\n if (this.periodCache.length === 0) return\n this.periodsStrategy.assertTsWritable(existing, incoming, this.periodCache)\n }\n\n private async _loadPeriodsCache(): Promise<PeriodRecord[]> {\n if (this.periodCache !== null) return this.periodCache\n const loaded = await this.periodsStrategy.loadPeriods(\n this.adapter,\n this.name,\n (env: EncryptedEnvelope) => this._decryptPeriodRecord(env),\n )\n this.periodCache = loaded\n return loaded\n }\n\n private async _writePeriodRecord(record: PeriodRecord): Promise<EncryptedEnvelope> {\n const json = JSON.stringify(record)\n let envelope: EncryptedEnvelope\n if (this.encrypted) {\n const dek = await this.getDEK(PERIODS_COLLECTION)\n const { iv, data } = await encrypt(json, dek)\n envelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n }\n } else {\n envelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: json,\n _by: this.keyring.userId,\n }\n }\n await this.adapter.put(this.name, PERIODS_COLLECTION, record.name, envelope)\n return envelope\n }\n\n private async _decryptPeriodRecord(envelope: EncryptedEnvelope): Promise<PeriodRecord> {\n let json: string\n if (this.encrypted) {\n const dek = await this.getDEK(PERIODS_COLLECTION)\n json = await decrypt(envelope._iv, envelope._data, dek)\n } else {\n json = envelope._data\n }\n return JSON.parse(json) as PeriodRecord\n }\n\n /** List all collection names in this vault. */\n async collections(): Promise<string[]> {\n const snapshot = await this.adapter.loadAll(this.name)\n return Object.keys(snapshot)\n }\n\n /**\n * Return the stable opaque bundle handle for this vault,\n * generating and persisting a fresh ULID on first call.\n *\n * used by `writeNoydbBundle()` to identify the\n * vault in the unencrypted bundle header without\n * exposing the vault name. The handle is persisted in\n * the reserved `_meta` internal collection so subsequent\n * exports of the same vault produce the same handle —\n * bundle adapters (Drive, Dropbox, iCloud) will use it\n * as their primary key.\n *\n * **Storage path:** the handle is written via the adapter\n * directly with collection name `_meta` and id `handle`. The\n * envelope's `_data` field contains a plain JSON\n * `{ handle: '...' }` payload — the handle is opaque, doesn't\n * need encryption, and the bundle header exposes the same\n * value anyway. This mirrors the storage approach `_keyring`\n * uses for its plain-JSON wrapped-DEK envelopes (also bypasses\n * the AES-GCM layer; the `_iv` field is left empty).\n *\n * **Cross-process stability:** the handle survives process\n * restarts because it's persisted on the adapter, not just\n * cached in memory. A new Vault instance opened on the\n * same adapter sees the same `_meta/handle` envelope and\n * returns the same ULID.\n *\n * **Round-trip after restore:** the receiving vault of a\n * `load()` call generates its OWN handle on first export. The\n * dump body does not include `_meta`, because handle stability\n * is per-vault-instance, not per-vault-content. Two\n * separate restorations of the same backup produce two\n * distinct handles, which is the right behavior — they're\n * separate vault instances now.\n */\n async getBundleHandle(): Promise<string> {\n const existing = await this.adapter.get(this.name, '_meta', 'handle')\n if (existing) {\n try {\n const parsed = JSON.parse(existing._data) as unknown\n if (parsed !== null && typeof parsed === 'object' && 'handle' in parsed) {\n const handle = (parsed as { handle: unknown }).handle\n if (typeof handle === 'string' && /^[0-9A-HJKMNP-TV-Z]{26}$/.test(handle)) {\n return handle\n }\n }\n } catch {\n // Fall through to regenerate — corrupted handle envelope\n // is treated as missing, not as an error. The new handle\n // overwrites the bad one.\n }\n }\n // Lazy import to avoid a top-of-file circular dependency:\n // bundle/bundle.ts imports from vault.ts (the\n // Vault type), and vault.ts can't statically\n // import from bundle/* without forming a cycle. The dynamic\n // import is invoked once per fresh handle generation, which\n // is rare enough that the cost doesn't matter.\n const { generateULID } = await import('./bundle/ulid.js')\n const handle = generateULID()\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ handle }),\n }\n await this.adapter.put(this.name, '_meta', 'handle', envelope)\n return handle\n }\n\n /**\n * Dump vault as a verifiable encrypted JSON backup string.\n *\n * backups embed the current ledger head and the full\n * `_ledger` + `_ledger_deltas` internal collections so the\n * receiver can run `verifyBackupIntegrity()` after `load()` and\n * detect any tampering between dump and restore. Backups produced\n * without a ledger (older formats or hub instances built without\n * the history strategy) skip the integrity check with a warning —\n * both modes round-trip cleanly.\n */\n async dump(): Promise<string> {\n const snapshot = await this.adapter.loadAll(this.name)\n\n // Load keyrings (separate path because loadAll filters them out\n // along with all other underscore-prefixed internal collections).\n const keyringIds = await this.adapter.list(this.name, '_keyring')\n const keyrings: Record<string, unknown> = {}\n for (const keyringId of keyringIds) {\n const envelope = await this.adapter.get(this.name, '_keyring', keyringId)\n if (envelope) {\n keyrings[keyringId] = JSON.parse(envelope._data)\n }\n }\n\n // Load the ledger entries + deltas so the receiver can replay\n // the chain after restore. Without this, `load()` would have an\n // empty ledger and `verifyBackupIntegrity()` would have nothing\n // to compare against.\n const internalSnapshot: VaultSnapshot = {}\n for (const internalName of [LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION]) {\n const ids = await this.adapter.list(this.name, internalName)\n if (ids.length === 0) continue\n const records: Record<string, EncryptedEnvelope> = {}\n for (const id of ids) {\n const envelope = await this.adapter.get(this.name, internalName, id)\n if (envelope) records[id] = envelope\n }\n internalSnapshot[internalName] = records\n }\n\n // Embed the ledger head if there's a chain. An empty ledger\n // (fresh vault) leaves `ledgerHead` undefined, which\n // load() treats the same as a legacy backup (no integrity\n // check, console warning). If history is not opted in,\n // `getLedgerOrNull` returns null and we skip embedding entirely\n // — the backup is still valid, just without the integrity head.\n const ledgerForHead = this.getLedgerOrNull()\n const head = ledgerForHead ? await ledgerForHead.head() : null\n const backup: VaultBackup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: this.name,\n _exported_at: new Date().toISOString(),\n _exported_by: this.keyring.userId,\n keyrings: keyrings as VaultBackup['keyrings'],\n collections: snapshot,\n ...(Object.keys(internalSnapshot).length > 0\n ? { _internal: internalSnapshot }\n : {}),\n ...(head\n ? {\n ledgerHead: {\n hash: head.hash,\n index: head.entry.index,\n ts: head.entry.ts,\n },\n }\n : {}),\n }\n\n return JSON.stringify(backup)\n }\n\n /**\n * Restore a vault from a verifiable backup.\n *\n * After loading, runs `verifyBackupIntegrity()` to confirm:\n * 1. The hash chain is intact (no `prevHash` mismatches)\n * 2. The chain head matches the embedded `ledgerHead.hash`\n * from the backup\n * 3. Every data envelope's `payloadHash` matches the\n * corresponding ledger entry — i.e. nobody swapped\n * ciphertext between dump and restore\n *\n * On any failure, throws `BackupLedgerError` (chain or head\n * mismatch) or `BackupCorruptedError` (data envelope mismatch).\n * The vault state on the adapter has already been written\n * by the time we throw, so the caller is responsible for either\n * accepting the suspect state or wiping it and trying a different\n * backup.\n *\n * Legacy backups (no `ledgerHead` field, no `_internal`) load\n * with a console warning and skip the integrity check entirely\n * — there's no chain to verify against.\n */\n async load(backupJson: string): Promise<void> {\n const backup = JSON.parse(backupJson) as VaultBackup\n\n // 1. Restore data collections.\n await this.adapter.saveAll(this.name, backup.collections)\n\n // 2. Restore keyrings.\n for (const [userId, keyringFile] of Object.entries(backup.keyrings)) {\n const envelope = {\n _noydb: 1 as const,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(keyringFile),\n }\n await this.adapter.put(this.name, '_keyring', userId, envelope)\n }\n\n // 3. Restore internal collections (`_ledger`, `_ledger_deltas`).\n // Required so verifyBackupIntegrity has the chain to walk.\n if (backup._internal) {\n for (const [internalName, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await this.adapter.put(this.name, internalName, id, envelope)\n }\n }\n }\n\n // 4. Refresh the in-memory keyring from the freshly-loaded\n // keyring file. Without this, the Vault's getDEK\n // closure still holds the OLD session's DEKs, and every\n // decrypt of a loaded ledger entry / data envelope fails\n // with TamperedError because the DEK doesn't match the\n // ciphertext that was encrypted with the SOURCE user's DEK.\n // Skipped for plaintext vaults and for tests that\n // construct Vault without a reloadKeyring callback.\n if (this.reloadKeyring) {\n this.keyring = await this.reloadKeyring()\n // Rebuild the DEK resolver against the refreshed keyring so\n // the next ensureCollectionDEK call sees the loaded wrapped\n // DEKs, not the cached pre-load ones.\n this.getDEK = this.makeGetDEK()\n }\n\n // 5. Clear collection cache + reset the ledger store so the\n // next ledger() call rebuilds its head cache from the\n // freshly-loaded entries.\n this.collectionCache.clear()\n this.ledgerStore = null\n\n // 5. Run the verification gate. Legacy backups (no ledgerHead)\n // skip this with a one-line warning so existing consumers can\n // still read them while migrating.\n if (!backup.ledgerHead) {\n console.warn(\n `[noy-db] Loaded a legacy backup with no ledgerHead — ` +\n `verifiable-backup integrity check skipped. ` +\n `Re-export with a ledger-aware build to get tamper detection.`,\n )\n return\n }\n\n const result = await this.verifyBackupIntegrity()\n if (!result.ok) {\n // Surface the most specific error class we can. The result\n // shape carries enough info for callers to inspect.\n if (result.kind === 'data') {\n throw new BackupCorruptedError(\n result.collection,\n result.id,\n result.message,\n )\n }\n throw new BackupLedgerError(result.message, result.divergedAt)\n }\n\n // 6. Cross-check: the freshly-verified head must match the\n // value embedded at dump time. A mismatch means someone\n // truncated or extended the chain after dump.\n if (result.head !== backup.ledgerHead.hash) {\n throw new BackupLedgerError(\n `Backup ledger head mismatch: embedded \"${backup.ledgerHead.hash}\" ` +\n `but reconstructed \"${result.head}\".`,\n )\n }\n }\n\n /**\n * End-to-end backup integrity check. Runs both:\n *\n * 1. `ledger.verify()` — walks the hash chain and confirms\n * every `prevHash` matches the recomputed hash of its\n * predecessor.\n *\n * 2. **Data envelope cross-check** — for every (collection, id)\n * that has a current value, find the most recent ledger\n * entry recording a `put` for that pair, recompute the\n * sha256 of the stored envelope's `_data`, and compare to\n * the entry's `payloadHash`. Any mismatch means an\n * out-of-band write modified the data without updating the\n * ledger.\n *\n * Returns a discriminated union so callers can handle the two\n * failure modes differently:\n * - `{ ok: true, head, length }` — chain verified and all\n * data matches; safe to use.\n * - `{ ok: false, kind: 'chain', divergedAt, message }` — the\n * chain itself is broken at the given index.\n * - `{ ok: false, kind: 'data', collection, id, message }` —\n * a specific data envelope doesn't match its ledger entry.\n *\n * This method is exposed so users can call it any time, not just\n * during `load()`. A scheduled background check is the simplest\n * way to detect tampering of an in-place vault.\n */\n async verifyBackupIntegrity(): Promise<\n | { readonly ok: true; readonly head: string; readonly length: number }\n | {\n readonly ok: false\n readonly kind: 'chain'\n readonly divergedAt: number\n readonly message: string\n }\n | {\n readonly ok: false\n readonly kind: 'data'\n readonly collection: string\n readonly id: string\n readonly message: string\n }\n > {\n // Step 1: chain verification. Without the history strategy there\n // is no ledger; an unaudited backup verifies trivially as `ok`\n // because there's nothing to diverge from.\n const ledgerForVerify = this.getLedgerOrNull()\n if (!ledgerForVerify) {\n return { ok: true, head: '', length: 0 }\n }\n const chainResult = await ledgerForVerify.verify()\n if (!chainResult.ok) {\n return {\n ok: false,\n kind: 'chain',\n divergedAt: chainResult.divergedAt,\n message:\n `Ledger chain diverged at index ${chainResult.divergedAt}: ` +\n `expected prevHash \"${chainResult.expected}\" but found \"${chainResult.actual}\".`,\n }\n }\n\n // Step 2: data envelope cross-check. Walk every entry in the\n // ledger and, for the LATEST `put` per (collection, id), recompute\n // the data envelope's payloadHash and compare. Earlier puts of the\n // same id are skipped because the data collection only holds the\n // current version — historical envelopes live in the deltas\n // collection (which is itself protected by the chain).\n // Reuse the ledger we already resolved in step 1.\n const allEntries = await ledgerForVerify.loadAllEntries()\n\n // Find the latest non-delete entry per (collection, id). Walk\n // the entries in reverse so we hit the latest first; mark each\n // (collection, id) as seen and skip subsequent entries.\n const seen = new Set<string>()\n const latest = new Map<\n string,\n { collection: string; id: string; expectedHash: string }\n >()\n for (let i = allEntries.length - 1; i >= 0; i--) {\n const entry = allEntries[i]\n if (!entry) continue\n const key = `${entry.collection}/${entry.id}`\n if (seen.has(key)) continue\n seen.add(key)\n // For deletes the data collection should NOT have the record,\n // so we skip — there's nothing to cross-check.\n if (entry.op === 'delete') continue\n latest.set(key, {\n collection: entry.collection,\n id: entry.id,\n expectedHash: entry.payloadHash,\n })\n }\n\n for (const { collection, id, expectedHash } of latest.values()) {\n const envelope = await this.adapter.get(this.name, collection, id)\n if (!envelope) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Ledger expects data record \"${collection}/${id}\" to exist, ` +\n `but the adapter has no envelope for it.`,\n }\n }\n const actualHash = await sha256Hex(envelope._data)\n if (actualHash !== expectedHash) {\n return {\n ok: false,\n kind: 'data',\n collection,\n id,\n message:\n `Data envelope \"${collection}/${id}\" has been tampered with: ` +\n `expected payloadHash \"${expectedHash}\", got \"${actualHash}\".`,\n }\n }\n }\n\n return {\n ok: true,\n head: chainResult.head,\n length: chainResult.length,\n }\n }\n\n /**\n * Stream every collection in this vault as decrypted, ACL-scoped\n * chunks.\n *\n * ⚠ **This method decrypts your records.** noy-db's threat model assumes\n * that records on disk are encrypted; the values yielded here are\n * plaintext. The consumer is responsible for ensuring the yielded data\n * is handled in a way that matches the data's sensitivity. If your goal\n * is encrypted backup or transport between noy-db instances, use\n * `dump()` instead — it produces a tamper-evident encrypted envelope and\n * never exposes plaintext.\n *\n * ## Behavior\n *\n * - **ACL-scoped.** Collections the calling principal cannot read are\n * silently skipped (same rule as `Collection.list()`). An operator\n * with `{ invoices: 'rw', clients: 'ro' }` permissions on a\n * five-collection vault exports only `invoices` and `clients`,\n * with no error on the others.\n * - **Streaming.** Returns an `AsyncIterableIterator` so consumers can\n * process chunks as they arrive without holding the full export in\n * memory. Note: the underlying adapter call (`loadAll`) is still a\n * single bulk read — the streaming benefit is on the *output* side.\n * True per-record adapter streaming arrives with the query DSL.\n * - **Schema + refs surfaced** as metadata on every chunk so downstream\n * serializers (`@noy-db/as-csv`, `@noy-db/as-xlsx`, custom\n * exporters) can produce schema-aware output without reaching into\n * collection internals.\n * - **Internal collections filtered.** `_ledger`, `_keyring`, etc. are\n * never yielded — they're noy-db's own bookkeeping and have no value\n * in a plaintext export. Use `dump()` for full backup including\n * internal collections.\n *\n * ## Composition\n *\n * Once cross-vault queries land, fanning this out across\n * every vault the caller can unlock is `queryAcross(ids, c =>\n * c.exportStream())` — no new primitive needed. That's part of why this\n * method belongs in core: it's the single decrypt+ACL+metadata path\n * that every export-format package will build on, and pushing it into\n * a `@noy-db/as-*` package would force every format to re-solve\n * the same problems independently.\n *\n * @example\n * ```ts\n * for await (const chunk of company.exportStream()) {\n * // chunk.collection: 'invoices'\n * // chunk.schema: ZodObject | null\n * // chunk.refs: { clientId: { target: 'clients', mode: 'strict' } }\n * // chunk.records: Invoice[]\n * }\n * ```\n *\n * @example\n * ```ts\n * // Per-record streaming for arbitrarily large collections.\n * for await (const chunk of company.exportStream({ granularity: 'record' })) {\n * // chunk.records is always length 1\n * await writer.write(serialize(chunk.records[0]))\n * }\n * ```\n */\n async *exportStream(opts: ExportStreamOptions = {}): AsyncIterableIterator<ExportChunk> {\n const granularity = opts.granularity ?? 'collection'\n\n // One bulk read to enumerate collections. `loadAll` filters out\n // underscore-prefixed internal collections, which is exactly what we\n // want — internal bookkeeping has no place in a plaintext export.\n const snapshot = await this.adapter.loadAll(this.name)\n const collectionNames = Object.keys(snapshot).sort()\n\n // Resolve the ledger head once if requested. The head is identical\n // across every yielded chunk (one ledger per vault) — we copy\n // it onto each chunk so consumers doing per-record streaming don't\n // have to thread state across yields, and so the chunk shape stays\n // forward-compatible with future per-partition ledgers where the\n // head genuinely will differ per chunk.\n const ledgerHead = opts.withLedgerHead\n ? await (async () => {\n const ledger = this.getLedgerOrNull()\n if (!ledger) return undefined\n const head = await ledger.head()\n return head\n ? { hash: head.hash, index: head.entry.index, ts: head.entry.ts }\n : undefined\n })()\n : undefined\n\n // Capture ALL dictionary snapshots upfront before the first yield.\n // Building all snapshots eagerly before yielding anything ensures that\n // concurrent mutations during streaming do not affect the snapshot — any\n // dictionary.put() that happens after the first yield sees the pre-yield\n // state here. Keyed by collection name.\n const dictSnapshotCache = new Map<\n string, // collection name\n Record<string, Record<string, Record<string, string>>> // field → key → locale → label\n >()\n for (const collectionName of collectionNames) {\n const dictFields = this.dictKeyFieldRegistry.get(collectionName)\n if (dictFields && Object.keys(dictFields).length > 0) {\n const snap: Record<string, Record<string, Record<string, string>>> = {}\n for (const [fieldName, dictName] of Object.entries(dictFields)) {\n const entries = await this.dictionary(dictName).list()\n const keyMap: Record<string, Record<string, string>> = {}\n for (const entry of entries) {\n keyMap[entry.key] = entry.labels\n }\n snap[fieldName] = keyMap\n }\n dictSnapshotCache.set(collectionName, snap)\n }\n }\n\n for (const collectionName of collectionNames) {\n // ACL gate. The same `hasAccess` check that `Collection.list()`\n // honors — silent skip, no error, matches the \"operator can read\n // some but not all\" pattern.\n if (!hasAccess(this.keyring, collectionName)) continue\n\n const coll = this.collection(collectionName)\n const schema = coll.getSchema() ?? null\n const refs = this.refRegistry.getOutbound(collectionName)\n const ids = Object.keys(snapshot[collectionName] ?? {})\n\n const dictionaries = dictSnapshotCache.get(collectionName)\n\n if (granularity === 'collection') {\n // Decrypt every record in the collection, then yield once.\n // Using `coll.get(id)` rather than the loadAll envelope directly\n // because `get()` is the canonical decrypt+schema-validate path\n // and any future cache/index plumbing rides through it.\n const records: unknown[] = []\n for (const id of ids) {\n const record = await coll.get(id)\n if (record !== null) records.push(record)\n }\n const chunk: ExportChunk = {\n collection: collectionName,\n schema,\n refs,\n records,\n ...(dictionaries !== undefined ? { dictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n }\n yield chunk\n } else {\n // Per-record yield. Memory profile: O(1 record) at a time.\n // The schema/refs metadata is repeated on every chunk so\n // consumers don't have to thread state across yields.\n for (const id of ids) {\n const record = await coll.get(id)\n if (record === null) continue\n const chunk: ExportChunk = {\n collection: collectionName,\n schema,\n refs,\n records: [record],\n ...(dictionaries !== undefined ? { dictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n }\n yield chunk\n }\n }\n }\n }\n\n /**\n * Convenience wrapper that consumes `exportStream()` and serializes the\n * result to a single JSON string.\n *\n * ⚠ **`exportJSON()` decrypts your records and produces plaintext.**\n *\n * noy-db's threat model assumes that records on disk are encrypted.\n * This function deliberately violates that assumption: it produces a\n * JSON string in plaintext, which the consumer is then responsible for\n * protecting (filesystem permissions, full-disk encryption, secure\n * transfer, secure deletion).\n *\n * Use this function only when:\n * - You are the authorized owner of the data, **and**\n * - You have a legitimate downstream tool that requires plaintext\n * JSON, **and**\n * - You have a documented plan for how the resulting plaintext will be\n * protected and eventually destroyed.\n *\n * If your goal is encrypted backup or transport between noy-db\n * instances, use `dump()` instead — it produces a tamper-evident\n * encrypted envelope, never plaintext.\n *\n * ## Why `Promise<string>` instead of writing to a file path\n *\n * Core has zero `node:` imports — it runs unchanged in browsers, Node,\n * Bun, Deno, and edge runtimes. Accepting a file path would force a\n * `node:fs` import (breaks browsers) or a runtime dynamic import\n * (doesn't tree-shake, inflates bundles). Returning a string lets the\n * consumer choose any sink and forces the destination decision to be\n * explicit at the call site — which is also better for the security\n * warning.\n *\n * @example\n * ```ts\n * // Node: write to a file\n * import { writeFile } from 'node:fs/promises'\n * await writeFile('./backup.json', await company.exportJSON())\n * ```\n *\n * @example\n * ```ts\n * // Browser: download as a file\n * const json = await company.exportJSON()\n * const blob = new Blob([json], { type: 'application/json' })\n * const url = URL.createObjectURL(blob)\n * // ... attach to an <a download> and click\n * ```\n *\n * @example\n * ```ts\n * // Stream upload to a server\n * await fetch('/upload', {\n * method: 'POST',\n * body: await company.exportJSON(),\n * })\n * ```\n *\n * ## On-disk shape\n *\n * ```json\n * {\n * \"_noydb_export\": 1,\n * \"_compartment\": \"acme\",\n * \"_exported_at\": \"2026-04-07T12:00:00.000Z\",\n * \"_exported_by\": \"alice@acme.example\",\n * \"collections\": {\n * \"invoices\": {\n * \"schema\": null,\n * \"refs\": { \"clientId\": { \"target\": \"clients\", \"mode\": \"strict\" } },\n * \"records\": [ ... ]\n * }\n * },\n * \"ledgerHead\": { \"hash\": \"...\", \"index\": 42, \"ts\": \"...\" }\n * }\n * ```\n *\n * `schema` is included for forward compatibility but is currently\n * always `null` because Standard Schema validators are not JSON-\n * serializable. Format-package serializers that need the schema\n * should use `exportStream()` directly and read `chunk.schema` (which\n * is the live validator object, not a serialization of it).\n */\n async exportJSON(opts: ExportStreamOptions = {}): Promise<string> {\n // Force per-collection granularity regardless of caller setting:\n // record-by-record output doesn't make sense in a single string.\n const collections: Record<\n string,\n {\n schema: null\n refs: Record<string, { target: string; mode: 'strict' | 'warn' | 'cascade' }>\n records: unknown[]\n }\n > = {}\n let ledgerHead: ExportChunk['ledgerHead'] | undefined\n // Merged dictionary snapshot across all collections.\n // Only populated when `resolveLabels` is not set.\n const allDictionaries: Record<\n string, // collection name\n Record<string, Record<string, Record<string, string>>>\n > = {}\n\n for await (const chunk of this.exportStream({\n granularity: 'collection',\n withLedgerHead: opts.withLedgerHead === true,\n })) {\n collections[chunk.collection] = {\n schema: null, // Standard Schema validators are not JSON-serializable\n refs: chunk.refs,\n records: chunk.records,\n }\n if (chunk.ledgerHead) ledgerHead = chunk.ledgerHead\n // Collect dictionary snapshots unless resolveLabels is set\n if (!opts.resolveLabels && chunk.dictionaries) {\n allDictionaries[chunk.collection] = chunk.dictionaries\n }\n }\n\n const hasDictionaries = Object.keys(allDictionaries).length > 0\n return JSON.stringify({\n _noydb_export: 1,\n _compartment: this.name,\n _exported_at: new Date().toISOString(),\n _exported_by: this.keyring.userId,\n collections,\n ...(hasDictionaries ? { _dictionaries: allDictionaries } : {}),\n ...(ledgerHead ? { ledgerHead } : {}),\n })\n }\n}\n\n// ─── Elevation handle ────────────────────────────────────\n\n/**\n * Reserved collection that holds the audit ledger of elevation\n * sessions. One envelope per `vault.elevate(...)` call.\n */\nexport const ELEVATION_AUDIT_COLLECTION = '_elevation_audit'\n\n/**\n * Scoped handle returned by `vault.elevate(...)`. Writes through this\n * handle land at the elevated tier with `authorization: 'elevation'`\n * stamped on the audit event; reads stay on the original `Vault`.\n *\n * The handle lazily checks its TTL on every operation, so a\n * forgotten `release()` cannot keep elevated writes alive past\n * `expiresAt` — the next call simply throws\n * {@link ElevationExpiredError}.\n *\n * Naming note: the issue's spec text used `elevated.session`\n * for this field; we name the field `handle` to avoid conflicting\n * with the codebase's existing `SessionToken` value type. The\n * semantics are unchanged.\n */\nexport class ElevatedHandle {\n /** Target tier this handle writes at. */\n readonly tier: number\n /** Audit string stamped on every cross-tier event. */\n readonly reason: string\n /** Absolute expiration in ms (Date.now()). */\n readonly expiresAt: number\n private released = false\n private readonly vault: Vault\n private readonly onRelease: () => void\n\n constructor(opts: {\n vault: Vault\n tier: number\n reason: string\n expiresAt: number\n onRelease: () => void\n }) {\n this.vault = opts.vault\n this.tier = opts.tier\n this.reason = opts.reason\n this.expiresAt = opts.expiresAt\n this.onRelease = opts.onRelease\n }\n\n /**\n * Scoped collection accessor. Returns a thin wrapper exposing the\n * single elevated operation (`put`). Reads, deletes, queries —\n * everything else — should go through the original `vault`'s\n * `collection(...)`, which keeps \"writes elevated, reads\n * unprivileged\" trivially true.\n */\n collection<T>(name: string): { put(id: string, record: T): Promise<void> } {\n // Don't gate the wrapper itself — just the operation. Adopters\n // commonly cache `const docs = elev.collection('docs')` and the\n // lazy-check still works correctly because assertActive runs at\n // every `put` call, against a fresh `Date.now()`.\n return {\n put: async (id: string, record: T): Promise<void> => {\n this.assertActive()\n await this.vault._elevatedPut<T>(name, id, record, this.tier, this.reason)\n },\n }\n }\n\n /**\n * Manually revert the elevation. Idempotent — calling twice (or\n * after the TTL expired) is a safe no-op. The vault's\n * active-elevation slot is cleared so a subsequent\n * `vault.elevate(...)` succeeds without throwing\n * {@link AlreadyElevatedError}.\n */\n async release(): Promise<void> {\n if (this.released) return\n this.released = true\n this.onRelease()\n }\n\n private assertActive(): void {\n if (this.released) {\n throw new ElevationExpiredError({ tier: this.tier, expiresAt: this.expiresAt })\n }\n if (Date.now() > this.expiresAt) {\n // Auto-release on first use past TTL so the vault's active\n // slot frees up without requiring the caller to think about\n // explicit release on expiry.\n this.released = true\n this.onRelease()\n throw new ElevationExpiredError({ tier: this.tier, expiresAt: this.expiresAt })\n }\n }\n}\n","import type { NoydbEventMap } from './types.js'\n\ntype EventHandler<T> = (data: T) => void\n\n/** Typed event emitter for NOYDB events. */\nexport class NoydbEventEmitter {\n private readonly listeners = new Map<string, Set<EventHandler<unknown>>>()\n\n on<K extends keyof NoydbEventMap>(\n event: K,\n handler: EventHandler<NoydbEventMap[K]>,\n ): void {\n let set = this.listeners.get(event as string)\n if (!set) {\n set = new Set()\n this.listeners.set(event as string, set)\n }\n set.add(handler as EventHandler<unknown>)\n }\n\n off<K extends keyof NoydbEventMap>(\n event: K,\n handler: EventHandler<NoydbEventMap[K]>,\n ): void {\n this.listeners.get(event as string)?.delete(handler as EventHandler<unknown>)\n }\n\n emit<K extends keyof NoydbEventMap>(event: K, data: NoydbEventMap[K]): void {\n const set = this.listeners.get(event as string)\n if (set) {\n for (const handler of set) {\n handler(data)\n }\n }\n }\n\n removeAllListeners(): void {\n this.listeners.clear()\n }\n}\n","/**\n * Strategy seam for the optional multi-record transaction subsystem.\n * `runTransaction` is only reachable through `withTransactions()`\n * exported from `@noy-db/hub/tx`. Consumers who don't use\n * `db.transaction(fn)` ship none of the ~288 LOC.\n *\n * @internal\n */\n\nimport type { Noydb } from '../noydb.js'\nimport type { TxContext } from './transaction.js'\n\n/**\n * @internal\n */\nexport interface TxStrategy {\n runTransaction<T>(\n db: Noydb,\n fn: (tx: TxContext) => Promise<T> | T,\n ): Promise<T>\n}\n\nconst NOT_ENABLED = new Error(\n 'Multi-record transactions require the tx strategy. Import ' +\n '`{ withTransactions }` from \"@noy-db/hub/tx\" and pass it to ' +\n '`createNoydb({ txStrategy: withTransactions() })`.',\n)\n\n/**\n * @internal\n */\nexport const NO_TX: TxStrategy = {\n async runTransaction() { throw NOT_ENABLED },\n}\n","/**\n * Strategy seam for the optional session-policy subsystem. Core\n * imports `SessionStrategy` type-only + `NO_SESSION` stub; real\n * `validateSessionPolicy`, `createEnforcer`, and `revokeAllSessions`\n * are only reachable via `withSession()` in `./active.ts`.\n *\n * Solo apps that never set `sessionPolicy` and never issue a session\n * token ship none of the ~495 LOC of policy + token machinery\n * (session-policy.ts + session.ts). Dev-unlock (~299 LOC) is a\n * separate import already tree-shake-friendly via direct named\n * imports.\n *\n * Behavior under NO_SESSION:\n *\n * - **validateSessionPolicy** — throws when called. Only fires if\n * `createNoydb({ sessionPolicy })` was passed; if you set a policy\n * you must opt into the strategy.\n * - **createEnforcer** — throws. Same gate.\n * - **revokeAllSessions** — silent no-op. Called unconditionally on\n * `db.close()`; without the strategy the global session registry\n * never recorded anything, so the no-op is correct.\n *\n * @internal\n */\n\nimport type { SessionPolicy } from '../types.js'\nimport type { PolicyEnforcer, PolicyEnforcerOptions } from './session-policy.js'\n\n/**\n * @internal\n */\nexport interface SessionStrategy {\n validateSessionPolicy(policy: SessionPolicy): void\n createEnforcer(opts: PolicyEnforcerOptions): PolicyEnforcer\n revokeAllSessions(): void\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the session strategy. Import ` +\n '`{ withSession }` from \"@noy-db/hub/session\" and pass it to ' +\n '`createNoydb({ sessionStrategy: withSession() })`.',\n )\n}\n\n/**\n * No-session stub. Policy validation + enforcer construction throw\n * with an actionable pointer; global session revocation is a silent\n * no-op (the registry was never populated).\n *\n * @internal\n */\nexport const NO_SESSION: SessionStrategy = {\n validateSessionPolicy() { throw notEnabled('sessionPolicy') },\n createEnforcer() { throw notEnabled('session policy enforcement') },\n revokeAllSessions() {},\n}\n","import type {\n NoydbOptions,\n NoydbEventMap,\n GrantOptions,\n RevokeOptions,\n UserInfo,\n PushResult,\n PullResult,\n PushOptions,\n PullOptions,\n SyncStatus,\n SyncTarget,\n NoydbStore,\n Role,\n AccessibleVault,\n ListAccessibleVaultsOptions,\n QueryAcrossOptions,\n QueryAcrossResult,\n ReAuthOperation,\n TranslatorAuditEntry,\n} from './types.js'\nimport { ValidationError, NoAccessError, InvalidKeyError, StoreCapabilityError } from './errors.js'\nimport { Vault } from './vault.js'\nimport { NoydbEventEmitter } from './events.js'\nimport {\n loadKeyring,\n createOwnerKeyring,\n grant as keyringGrant,\n revoke as keyringRevoke,\n rotateKeys as keyringRotate,\n changeSecret as keyringChangeSecret,\n listUsers as keyringListUsers,\n} from './team/keyring.js'\nimport type { UnlockedKeyring } from './team/keyring.js'\nimport type { SyncEngine } from './team/sync.js'\nimport type { SyncTransaction } from './team/sync-transaction.js'\nimport { NO_SYNC, type SyncStrategy } from './team/sync-strategy.js'\nimport type { TxContext } from './tx/transaction.js'\nimport { NO_TX, type TxStrategy } from './tx/strategy.js'\nimport { INDEXED_STORE_POLICY } from './store/sync-policy.js'\nimport type { PolicyEnforcer } from './session/session-policy.js'\nimport { NO_SESSION, type SessionStrategy } from './session/strategy.js'\n\n/**\n * Privilege rank used by `listAccessibleVaults({ minRole })` to\n * filter the result. Higher number = more privileged. Owner is at the\n * top; client is at the bottom. Viewer outranks client because viewer\n * has read-all access while client has only explicit-collection read\n * — the ordering reflects \"how much can this principal see,\" not\n * \"how much can this principal modify.\"\n */\nconst ROLE_RANK: Record<Role, number> = {\n client: 1,\n viewer: 2,\n operator: 3,\n admin: 4,\n owner: 5,\n}\n\n/** Dummy keyring for unencrypted mode. */\nfunction createPlaintextKeyring(userId: string): UnlockedKeyring {\n return {\n userId,\n displayName: userId,\n role: 'owner',\n permissions: {},\n deks: new Map(),\n kek: null as unknown as CryptoKey,\n salt: new Uint8Array(0),\n }\n}\n\n/** The top-level NOYDB instance. */\nexport class Noydb {\n private readonly options: NoydbOptions\n private readonly emitter = new NoydbEventEmitter()\n private readonly vaultCache = new Map<string, Vault>()\n private readonly keyringCache = new Map<string, UnlockedKeyring>()\n private readonly syncEngines = new Map<string, SyncEngine>()\n private closed = false\n private sessionTimer: ReturnType<typeof setTimeout> | null = null\n /** Per-vault policy enforcers. */\n private readonly policyEnforcers = new Map<string, PolicyEnforcer>()\n private readonly txStrategy: TxStrategy\n private readonly sessionStrategy: SessionStrategy\n private readonly syncStrategy: SyncStrategy\n\n // ─── plaintextTranslator state ─────────────────────────\n /**\n * In-process translation cache. Key is `\"${field}\\x00${collection}\\x00${from}\\x00${to}\\x00${text}\"`.\n * Cleared on `close()` alongside the KEK and DEKs.\n */\n private readonly translatorCache = new Map<string, string>()\n /** Audit log for all translator invocations in this session. Cleared on `close()`. */\n private readonly _translatorAuditLog: TranslatorAuditEntry[] = []\n\n constructor(options: NoydbOptions) {\n this.options = options\n this.txStrategy = options.txStrategy ?? NO_TX\n this.sessionStrategy = options.sessionStrategy ?? NO_SESSION\n this.syncStrategy = options.syncStrategy ?? NO_SYNC\n // Validate sessionPolicy at construction time (developer error if invalid).\n // The strategy's stub throws with a pointer at the subpath if the\n // consumer set a policy without opting in.\n if (options.sessionPolicy) {\n this.sessionStrategy.validateSessionPolicy(options.sessionPolicy)\n }\n this.resetSessionTimer()\n }\n\n private resetSessionTimer(): void {\n if (this.sessionTimer) clearTimeout(this.sessionTimer)\n // Honor the new sessionPolicy.idleTimeoutMs if present, fall back to\n // the legacy sessionTimeout for backwards compatibility.\n const idleMs = this.options.sessionPolicy?.idleTimeoutMs ?? this.options.sessionTimeout\n if (idleMs && idleMs > 0) {\n this.sessionTimer = setTimeout(() => {\n this.close()\n }, idleMs)\n }\n }\n\n /**\n * Attach a policy enforcer for a vault.\n * Called internally when a session is started for a vault; the\n * enforcer handles idle/absolute timeouts and background-lock behavior.\n */\n private attachPolicyEnforcer(vault: string, sessionId: string): void {\n const policy = this.options.sessionPolicy\n if (!policy) return\n\n // Tear down any previous enforcer for this vault\n this.policyEnforcers.get(vault)?.destroy()\n\n const enforcer = this.sessionStrategy.createEnforcer({\n policy,\n sessionId,\n onRevoke: (_reason) => {\n this.keyringCache.delete(vault)\n this.vaultCache.delete(vault)\n this.policyEnforcers.delete(vault)\n },\n })\n this.policyEnforcers.set(vault, enforcer)\n }\n\n /**\n * Touch the policy enforcer for a vault (records activity, resets\n * idle timer). Also touches the legacy session timer. No-op if no enforcer.\n */\n private touchPolicy(vault?: string): void {\n this.resetSessionTimer()\n if (vault) {\n this.policyEnforcers.get(vault)?.touch()\n }\n }\n\n /**\n * Check that a policy-guarded operation is permitted.\n * Throws `SessionPolicyError` if re-auth is required.\n */\n private checkPolicyOperation(vault: string, op: ReAuthOperation): void {\n this.policyEnforcers.get(vault)?.checkOperation(op)\n }\n\n /**\n * Open a vault by name.\n *\n * @param name Vault identifier.\n * @param opts Optional settings for this session.\n * @param opts.locale Default locale for i18n/dictKey field resolution\n *. Set here to avoid passing `{ locale }`\n * on every individual `get()`/`list()` call.\n */\n async openVault(\n name: string,\n opts?: { locale?: string },\n ): Promise<Vault> {\n if (this.closed) throw new ValidationError('Instance is closed')\n this.touchPolicy(name)\n\n let comp = this.vaultCache.get(name)\n if (comp) {\n // Update locale on existing cached vault if specified\n if (opts?.locale !== undefined) {\n comp.setLocale(opts.locale)\n }\n return comp\n }\n\n const keyring = await this.getKeyring(name)\n\n // Set up sync engine(s) — handles bare NoydbStore, SyncTarget, or SyncTarget[]\n let syncEngine: SyncEngine | undefined\n const targets = normalizeSyncTargets(this.options.sync)\n if (targets.length > 0) {\n // Primary sync engine is the first sync-peer (or first target if none)\n const primary = targets.find(t => t.role === 'sync-peer') ?? targets[0]!\n const effectivePolicy = this.options.syncPolicy ?? primary.policy ?? INDEXED_STORE_POLICY\n syncEngine = this.syncStrategy.buildSyncEngine({\n local: this.options.store,\n remote: primary.store,\n vault: name,\n strategy: this.options.conflict ?? 'version',\n emitter: this.emitter,\n syncPolicy: effectivePolicy,\n role: primary.role,\n ...(primary.label !== undefined ? { label: primary.label } : {}),\n })\n this.syncEngines.set(name, syncEngine)\n\n // Additional targets get their own engines (backup/archive are push-only)\n for (const target of targets) {\n if (target === primary) continue\n const targetPolicy = target.policy ?? this.options.syncPolicy ?? INDEXED_STORE_POLICY\n const engine = this.syncStrategy.buildSyncEngine({\n local: this.options.store,\n remote: target.store,\n vault: name,\n strategy: this.options.conflict ?? 'version',\n emitter: this.emitter,\n syncPolicy: targetPolicy,\n role: target.role,\n ...(target.label !== undefined ? { label: target.label } : {}),\n })\n const key = `${name}::${target.label ?? target.role}`\n this.syncEngines.set(key, engine)\n }\n }\n\n comp = new Vault({\n adapter: this.options.store,\n name,\n noydb: this,\n keyring,\n encrypted: this.options.encrypt !== false,\n emitter: this.emitter,\n onDirty: targets.length > 0\n ? async (coll, id, action, version) => {\n // Fan out dirty tracking to all sync engines for this vault\n for (const [key, engine] of this.syncEngines) {\n if (key === name || key.startsWith(`${name}::`)) {\n void engine.trackChange(coll, id, action, version)\n }\n }\n }\n : undefined,\n onRegisterConflictResolver: syncEngine\n ? (resolverName, resolver) => syncEngine.registerConflictResolver(resolverName, resolver)\n : undefined,\n syncAdapter: targets.length > 0 ? targets[0]!.store : undefined,\n historyConfig: this.options.history,\n ...(this.options.blobStrategy !== undefined ? { blobStrategy: this.options.blobStrategy } : {}),\n ...(this.options.indexStrategy !== undefined ? { indexStrategy: this.options.indexStrategy } : {}),\n ...(this.options.aggregateStrategy !== undefined ? { aggregateStrategy: this.options.aggregateStrategy } : {}),\n ...(this.options.crdtStrategy !== undefined ? { crdtStrategy: this.options.crdtStrategy } : {}),\n ...(this.options.consentStrategy !== undefined ? { consentStrategy: this.options.consentStrategy } : {}),\n ...(this.options.periodsStrategy !== undefined ? { periodsStrategy: this.options.periodsStrategy } : {}),\n ...(this.options.shadowStrategy !== undefined ? { shadowStrategy: this.options.shadowStrategy } : {}),\n ...(this.options.historyStrategy !== undefined ? { historyStrategy: this.options.historyStrategy } : {}),\n ...(this.options.i18nStrategy !== undefined ? { i18nStrategy: this.options.i18nStrategy } : {}),\n ...(this.options.syncStrategy !== undefined ? { syncStrategy: this.options.syncStrategy } : {}),\n locale: opts?.locale,\n // Thread the translator hook so Collection.put() can invoke it\n plaintextTranslator: this.options.plaintextTranslator\n ? (text, from, to, field, collection) =>\n this.invokeTranslator(text, from, to, field, collection)\n : undefined,\n // Refresh callback used by Vault.load() to re-derive\n // the in-memory keyring from a freshly-loaded keyring file.\n // Encrypted compartments need this so post-load decrypts work\n // against the loaded session's wrapped DEKs; plaintext\n // compartments leave it null and load() skips the refresh.\n reloadKeyring:\n this.options.encrypt !== false && this.options.secret\n ? async () => {\n // Drop the cached keyring so the next loadKeyring\n // call reads fresh from the adapter, then update the\n // cache so subsequent openVault calls see the\n // refreshed keyring too.\n this.keyringCache.delete(name)\n const refreshed = await loadKeyring(\n this.options.store,\n name,\n this.options.user,\n this.options.secret as string,\n )\n this.keyringCache.set(name, refreshed)\n return refreshed\n }\n : undefined,\n })\n this.vaultCache.set(name, comp)\n return comp\n }\n\n /** Synchronous vault access (must call openVault first, or auto-opens). */\n vault(name: string): Vault {\n const cached = this.vaultCache.get(name)\n if (cached) return cached\n\n // For backwards compat: if not opened yet, create with cached keyring or plaintext\n if (this.options.encrypt === false) {\n const keyring = createPlaintextKeyring(this.options.user)\n const comp = new Vault({\n adapter: this.options.store,\n name,\n noydb: this,\n keyring,\n encrypted: false,\n emitter: this.emitter,\n historyConfig: this.options.history,\n ...(this.options.blobStrategy !== undefined ? { blobStrategy: this.options.blobStrategy } : {}),\n ...(this.options.indexStrategy !== undefined ? { indexStrategy: this.options.indexStrategy } : {}),\n ...(this.options.aggregateStrategy !== undefined ? { aggregateStrategy: this.options.aggregateStrategy } : {}),\n ...(this.options.crdtStrategy !== undefined ? { crdtStrategy: this.options.crdtStrategy } : {}),\n ...(this.options.consentStrategy !== undefined ? { consentStrategy: this.options.consentStrategy } : {}),\n ...(this.options.periodsStrategy !== undefined ? { periodsStrategy: this.options.periodsStrategy } : {}),\n ...(this.options.shadowStrategy !== undefined ? { shadowStrategy: this.options.shadowStrategy } : {}),\n ...(this.options.historyStrategy !== undefined ? { historyStrategy: this.options.historyStrategy } : {}),\n ...(this.options.i18nStrategy !== undefined ? { i18nStrategy: this.options.i18nStrategy } : {}),\n ...(this.options.syncStrategy !== undefined ? { syncStrategy: this.options.syncStrategy } : {}),\n })\n this.vaultCache.set(name, comp)\n return comp\n }\n\n const keyring = this.keyringCache.get(name)\n if (!keyring) {\n throw new ValidationError(\n `Vault \"${name}\" not opened. Use await db.openVault(\"${name}\") first.`,\n )\n }\n\n const comp = new Vault({\n adapter: this.options.store,\n name,\n noydb: this,\n keyring,\n encrypted: true,\n historyConfig: this.options.history,\n ...(this.options.blobStrategy !== undefined ? { blobStrategy: this.options.blobStrategy } : {}),\n ...(this.options.indexStrategy !== undefined ? { indexStrategy: this.options.indexStrategy } : {}),\n ...(this.options.aggregateStrategy !== undefined ? { aggregateStrategy: this.options.aggregateStrategy } : {}),\n ...(this.options.crdtStrategy !== undefined ? { crdtStrategy: this.options.crdtStrategy } : {}),\n ...(this.options.consentStrategy !== undefined ? { consentStrategy: this.options.consentStrategy } : {}),\n ...(this.options.periodsStrategy !== undefined ? { periodsStrategy: this.options.periodsStrategy } : {}),\n ...(this.options.shadowStrategy !== undefined ? { shadowStrategy: this.options.shadowStrategy } : {}),\n ...(this.options.historyStrategy !== undefined ? { historyStrategy: this.options.historyStrategy } : {}),\n ...(this.options.i18nStrategy !== undefined ? { i18nStrategy: this.options.i18nStrategy } : {}),\n ...(this.options.syncStrategy !== undefined ? { syncStrategy: this.options.syncStrategy } : {}),\n emitter: this.emitter,\n })\n this.vaultCache.set(name, comp)\n return comp\n }\n\n /** Grant access to a user for a vault. */\n async grant(vault: string, options: GrantOptions): Promise<void> {\n this.checkPolicyOperation(vault, 'grant')\n const keyring = await this.getKeyring(vault)\n await keyringGrant(this.options.store, vault, keyring, options)\n }\n\n /** Revoke a user's access to a vault. */\n async revoke(vault: string, options: RevokeOptions): Promise<void> {\n this.checkPolicyOperation(vault, 'revoke')\n const keyring = await this.getKeyring(vault)\n await keyringRevoke(this.options.store, vault, keyring, options)\n }\n\n /**\n * Rotate the DEKs for the given collections in a vault.\n *\n * Generates fresh DEKs, re-encrypts every record in each collection,\n * and re-wraps the new DEKs into every remaining user's keyring. The\n * old DEKs become unreachable — useful as a defense-in-depth measure\n * after a suspected key leak, or as the scheduled half of a\n * key-rotation policy.\n *\n * Unlike `revoke({ rotateKeys: true })`, this call does NOT remove\n * any users — every current member keeps access, but with fresh\n * keys. This is the \"just rotate\" path; the \"revoke and rotate\"\n * path still lives in `revoke()`.\n *\n * Exposed on Noydb (rather than only on the lower-level keyring\n * module) so CLI and admin tooling can trigger rotation without\n * reaching into internals. See `noy-db rotate` for the CLI wrapper.\n */\n async rotate(vault: string, collections: string[]): Promise<void> {\n this.checkPolicyOperation(vault, 'rotate')\n const keyring = await this.getKeyring(vault)\n await keyringRotate(this.options.store, vault, keyring, collections)\n // Refresh the cached keyring so subsequent operations see the\n // freshly-rotated DEKs. Without this, `ensureCollectionDEK` on\n // the next Collection access would still hold the old ones.\n this.keyringCache.set(vault, keyring)\n }\n\n /** List all users with access to a vault. */\n async listUsers(vault: string): Promise<UserInfo[]> {\n return keyringListUsers(this.options.store, vault)\n }\n\n // ─── Cross-vault queries ──────────────────────\n\n /**\n * Enumerate every vault the calling principal can unwrap,\n * optionally filtered by minimum role.\n *\n * The walk is a two-step pipeline: first ask the adapter for the\n * universe of compartments it stores, then for each one attempt to\n * load the calling user's keyring with the in-memory passphrase.\n * Compartments where the user has no keyring file (`NoAccessError`)\n * or where the passphrase doesn't unwrap (`InvalidKeyError`) are\n * silently dropped from the result — the existence of those\n * compartments is **not** confirmed in the return value.\n *\n * Requires the optional `NoydbStore.listVaults()` capability.\n * Throws `StoreCapabilityError` against stores that don't\n * implement it (today: store-aws-dynamo, store-aws-s3, store-browser-local, store-browser-idb). For those backends the\n * consumer should either pass an explicit candidate list to\n * `queryAcross()` directly, or maintain a vault index out of\n * band.\n *\n * **Privacy note.** This method's return value never reveals the\n * existence of a vault the caller cannot unwrap. The adapter\n * sees the enumeration call (it has to — it owns the storage), but\n * downstream consumers of `listAccessibleVaults()` only see\n * the filtered list. That's the boundary the existence-leak\n * guarantee draws.\n *\n * **Known edge case.** A vault whose keyring file\n * happens to have an empty wrapped-DEKs map (because the owner\n * granted access before any collection was created) will pass the\n * `loadKeyring` probe with *any* passphrase — there are no DEKs to\n * unwrap, so the integrity-checked unwrap that normally rejects\n * wrong passphrases never runs. The result is that an unrelated\n * principal who happens to know the user-id and the vault\n * name can show up in `listAccessibleVaults()` as having\n * access to that empty vault. They cannot read any actual\n * data (their DEK set is empty), so this is a metadata leak\n * (vault name + user-id), not a content leak. Hardening this\n * via a passphrase canary in the keyring file is a deferred\n * follow-up.\n *\n * **Cost.** O(compartments × keyring-load) — one `loadKeyring`\n * attempt per vault in the universe. Each attempt does one\n * adapter `get` + one PBKDF2 derivation + N AES-KW unwraps. For\n * dozens of compartments this is fine; for thousands the consumer\n * should cache the result and refresh on grant/revoke events. A\n * future optimization could batch the keyring reads via\n * `loadAll('_keyring')` if such a thing existed at the adapter\n * layer, but the contract doesn't expose that.\n *\n * @example\n * ```ts\n * // All compartments I can unwrap\n * const all = await db.listAccessibleVaults()\n *\n * // Only compartments where I'm at least admin\n * const admin = await db.listAccessibleVaults({ minRole: 'admin' })\n *\n * // Only compartments I own\n * const owned = await db.listAccessibleVaults({ minRole: 'owner' })\n * ```\n */\n async listAccessibleVaults(\n options: ListAccessibleVaultsOptions = {},\n ): Promise<AccessibleVault[]> {\n if (this.closed) throw new ValidationError('Instance is closed')\n this.resetSessionTimer()\n\n const adapter = this.options.store\n if (typeof adapter.listVaults !== 'function') {\n throw new StoreCapabilityError(\n 'listVaults',\n 'Noydb.listAccessibleVaults()',\n adapter.name,\n )\n }\n\n if (this.options.encrypt === false) {\n // Plaintext mode: no keyrings exist; every vault the\n // adapter knows about is \"accessible\" trivially as owner.\n const all = await adapter.listVaults()\n return all.map((id) => ({ id, role: 'owner' as Role }))\n }\n\n if (!this.options.secret) {\n throw new ValidationError(\n 'Noydb.listAccessibleVaults(): a secret (passphrase) is required ' +\n 'when encryption is enabled.',\n )\n }\n\n const minRank = ROLE_RANK[options.minRole ?? 'client']\n const universe = await adapter.listVaults()\n const accessible: AccessibleVault[] = []\n\n for (const vault of universe) {\n // Probe with loadKeyring directly (NOT getKeyring, which would\n // auto-create a fresh owner keyring on miss — that would\n // silently grant access to every empty vault in the\n // universe and is exactly the wrong shape for an enumeration\n // API). The two expected failure modes — no keyring file, or\n // wrong passphrase — are caught and silently dropped so the\n // return value never leaks existence.\n let keyring: UnlockedKeyring\n try {\n keyring = await loadKeyring(\n adapter,\n vault,\n this.options.user,\n this.options.secret,\n )\n } catch (err) {\n if (err instanceof NoAccessError || err instanceof InvalidKeyError) {\n continue // silent: caller has no key material for this vault\n }\n throw err // unexpected error — surface it\n }\n\n if (ROLE_RANK[keyring.role] < minRank) continue\n accessible.push({ id: vault, role: keyring.role })\n\n // Opportunistically prime the keyring cache so a subsequent\n // openVault() doesn't have to re-derive the KEK. The cost\n // is one Map.set per vault we already paid to unwrap.\n this.keyringCache.set(vault, keyring)\n }\n\n return accessible\n }\n\n /**\n * Run a per-vault callback against a list of compartments and\n * collect the results.\n *\n * Pure orchestration — there is no new crypto, no new sync, no new\n * authorization layer. Each vault is opened via the existing\n * `openVault()` path (which honors the cache primed by\n * `listAccessibleVaults`), the callback runs against the\n * resulting `Vault` instance, and the result (or thrown\n * error) is captured into the per-vault slot.\n *\n * **Per-vault errors do not abort the fan-out.** If one\n * vault's callback throws, that vault's slot carries\n * the error and the remaining compartments still run. The caller\n * decides how to handle the partition between success and failure.\n * This is the right shape for cross-tenant reports where one\n * tenant's outage shouldn't hide the other tenants' data.\n *\n * **Concurrency** is opt-in via `options.concurrency`. The default\n * is `1` (sequential) — conservative because per-vault\n * callbacks typically do their own I/O and an unbounded fan-out\n * can exhaust adapter connections (DynamoDB throughput, S3 socket\n * limits, browser fetch concurrency). Bump to 4-8 for cloud-backed\n * adapters where parallelism is the whole point.\n *\n * @example\n * ```ts\n * // Cross-tenant invoice totals as a flat list\n * const accessible = await db.listAccessibleVaults({ minRole: 'admin' })\n * const results = await db.queryAcross(\n * accessible.map((c) => c.id),\n * async (comp) => {\n * return comp.collection<Invoice>('invoices').query()\n * .where('month', '==', '2026-03')\n * .toArray()\n * },\n * { concurrency: 4 },\n * )\n * // results: Array<{ vault, result?: Invoice[], error?: Error }>\n *\n * // Compose with exportStream() — cross-vault plaintext export\n * const exports = await db.queryAcross(accessible.map((c) => c.id), async (comp) => {\n * const out: unknown[] = []\n * for await (const chunk of comp.exportStream()) out.push(chunk)\n * return out\n * })\n * ```\n */\n async queryAcross<T>(\n vaultIds: string[],\n fn: (vault: Vault) => Promise<T>,\n options: QueryAcrossOptions = {},\n ): Promise<QueryAcrossResult<T>[]> {\n if (this.closed) throw new ValidationError('Instance is closed')\n this.resetSessionTimer()\n\n const concurrency = Math.max(1, options.concurrency ?? 1)\n const results: QueryAcrossResult<T>[] = new Array(vaultIds.length)\n\n // Tiny inline p-limit. Maintains a sliding window of `concurrency`\n // in-flight promises and schedules the next vault as each\n // one settles. No external dep. Index-keyed result array so the\n // output preserves caller-supplied order even when concurrency\n // > 1 lets later compartments finish before earlier ones.\n let nextIndex = 0\n const inFlight: Set<Promise<void>> = new Set()\n\n const launch = (): Promise<void> | null => {\n if (nextIndex >= vaultIds.length) return null\n const idx = nextIndex++\n const vaultId = vaultIds[idx]!\n const task = (async () => {\n try {\n const comp = await this.openVault(vaultId)\n const result = await fn(comp)\n results[idx] = { vault: vaultId, result }\n } catch (err) {\n results[idx] = {\n vault: vaultId,\n error: err instanceof Error ? err : new Error(String(err)),\n }\n }\n })()\n inFlight.add(task)\n // Fire-and-forget cleanup. The task itself never rejects (the\n // try/catch above swallows everything into the result slot), so\n // there's no rejection to handle here — `void` tells the linter\n // we know what we're doing.\n void task.finally(() => inFlight.delete(task))\n return task\n }\n\n // Prime the window.\n for (let i = 0; i < concurrency; i++) {\n if (launch() === null) break\n }\n\n // Drain. As each task settles, kick off the next one until the\n // input is exhausted. `Promise.race` against the live set is the\n // simplest way to \"wake up on whichever finishes first\" without\n // pulling in p-limit / async-pool / etc.\n while (inFlight.size > 0) {\n await Promise.race(inFlight)\n while (inFlight.size < concurrency && nextIndex < vaultIds.length) {\n if (launch() === null) break\n }\n }\n\n return results\n }\n\n /** Change the current user's passphrase for a vault. */\n async changeSecret(vault: string, newPassphrase: string): Promise<void> {\n this.checkPolicyOperation(vault, 'changeSecret')\n const keyring = await this.getKeyring(vault)\n const updated = await keyringChangeSecret(\n this.options.store,\n vault,\n keyring,\n newPassphrase,\n )\n this.keyringCache.set(vault, updated)\n }\n\n // ─── Sync ──────────────────────────────────────────────────────\n\n /** Push local changes to remote for a vault. */\n async push(vault: string, options?: PushOptions): Promise<PushResult> {\n const engine = this.getSyncEngine(vault)\n return engine.push(options)\n }\n\n /** Pull remote changes to local for a vault. */\n async pull(vault: string, options?: PullOptions): Promise<PullResult> {\n const engine = this.getSyncEngine(vault)\n return engine.pull(options)\n }\n\n /**\n * Bidirectional sync: pull then push for all targets.\n * `sync-peer` targets do pull+push; `backup`/`archive` targets do push-only.\n */\n async sync(vault: string, options?: { push?: PushOptions; pull?: PullOptions }): Promise<{ pull: PullResult; push: PushResult }> {\n const primary = this.getSyncEngine(vault)\n const result = await primary.sync(options)\n\n // Fan out push to backup/archive targets (fire-and-mark-dirty)\n for (const [key, engine] of this.syncEngines) {\n if (key === vault) continue\n if (!key.startsWith(`${vault}::`)) continue\n if (engine.role === 'sync-peer') {\n await engine.sync(options).catch((err: Error) => {\n this.emitter.emit('sync:backup-error', {\n vault,\n target: engine.label ?? engine.role,\n error: err,\n })\n })\n } else {\n // backup/archive: push-only\n await engine.push(options?.push).catch((err: Error) => {\n this.emitter.emit('sync:backup-error', {\n vault,\n target: engine.label ?? engine.role,\n error: err,\n })\n })\n }\n }\n\n return result\n }\n\n /**\n * Multi-record atomic transaction.\n *\n * The callback stages writes across any number of vaults /\n * collections; on return the hub pre-flights version checks, then\n * commits every staged op. If the body throws, nothing is\n * persisted. If any staged op fails its `expectedVersion` check,\n * the batch throws `ConflictError` with zero writes performed. If a\n * mid-commit failure occurs after one or more ops have already\n * written, each executed op is reverted best-effort (see\n * `runTransaction` for the crash-window caveat).\n *\n * Distinct from `transaction(vault: string) → SyncTransaction`\n * which batches push/pull across sync peers.\n */\n transaction<T>(fn: (tx: TxContext) => Promise<T> | T): Promise<T>\n /**\n * Create a sync transaction for the given vault.\n * The vault must already be open via `openVault()`.\n * Call `tx.put()` / `tx.delete()` to stage changes, then `tx.commit()`\n * to write all locally and push atomically to remote.\n */\n transaction(vault: string): SyncTransaction\n transaction<T>(\n arg: string | ((tx: TxContext) => Promise<T> | T),\n ): SyncTransaction | Promise<T> {\n if (typeof arg === 'function') {\n return this.txStrategy.runTransaction(this, arg)\n }\n const vault = arg\n const comp = this.vaultCache.get(vault)\n if (!comp) {\n throw new ValidationError(\n `Vault \"${vault}\" is not open. Call openVault() first.`,\n )\n }\n const engine = this.getSyncEngine(vault)\n return this.syncStrategy.buildSyncTransaction(comp, engine)\n }\n\n /**\n * Internal accessor for the primary store — used by the tx\n * executor to perform raw adapter reads for pre-flight CAS and\n * raw writes for rollback. Not part of the public API.\n *\n * @internal\n */\n get _store(): NoydbStore {\n return this.options.store\n }\n\n /** Get sync status for a vault. */\n syncStatus(vault: string): SyncStatus {\n const engine = this.syncEngines.get(vault)\n if (!engine) {\n return { dirty: 0, lastPush: null, lastPull: null, online: true }\n }\n return engine.status()\n }\n\n private getSyncEngine(vault: string): SyncEngine {\n const engine = this.syncEngines.get(vault)\n if (!engine) {\n throw new ValidationError('No sync adapter configured. Pass a `sync` adapter to createNoydb().')\n }\n return engine\n }\n\n // ─── Events ────────────────────────────────────────────────────\n\n on<K extends keyof NoydbEventMap>(event: K, handler: (data: NoydbEventMap[K]) => void): void {\n this.emitter.on(event, handler)\n }\n\n off<K extends keyof NoydbEventMap>(event: K, handler: (data: NoydbEventMap[K]) => void): void {\n this.emitter.off(event, handler)\n }\n\n close(): void {\n this.closed = true\n if (this.sessionTimer) {\n clearTimeout(this.sessionTimer)\n this.sessionTimer = null\n }\n // Destroy all policy enforcers (cancels timers + visibility listeners)\n for (const enforcer of this.policyEnforcers.values()) {\n enforcer.destroy()\n }\n this.policyEnforcers.clear()\n // Revoke all in-memory session keys\n this.sessionStrategy.revokeAllSessions()\n // Stop all sync engines\n for (const engine of this.syncEngines.values()) {\n engine.stopAutoSync()\n }\n this.syncEngines.clear()\n this.keyringCache.clear()\n this.vaultCache.clear()\n this.emitter.removeAllListeners()\n // Clear translator state — same lifetime as KEK/DEKs\n this.translatorCache.clear()\n this._translatorAuditLog.length = 0\n }\n\n /**\n * Returns a snapshot of all translator invocations since the last\n * `close()`. Useful for testing and compliance auditing. The log is\n * in-memory only — it is cleared when `db.close()` is called.\n *\n * Entries deliberately omit content hashes. See `TranslatorAuditEntry`\n * and issue for the rationale.\n */\n translatorAuditLog(): readonly TranslatorAuditEntry[] {\n return [...this._translatorAuditLog]\n }\n\n /**\n * Invoke the configured `plaintextTranslator` (or serve from cache).\n * Records one `TranslatorAuditEntry` per call regardless of cache hit.\n * Called by `Vault` during `put()` for `autoTranslate: true` fields.\n *\n * @internal — not part of the public API surface\n */\n async invokeTranslator(\n text: string,\n from: string,\n to: string,\n field: string,\n collection: string,\n ): Promise<string> {\n const cacheKey = `${field}\\x00${collection}\\x00${from}\\x00${to}\\x00${text}`\n const translatorName = this.options.plaintextTranslatorName ?? 'anonymous'\n\n const cached = this.translatorCache.get(cacheKey)\n if (cached !== undefined) {\n this._translatorAuditLog.push({\n type: 'translator-invocation',\n field,\n collection,\n fromLocale: from,\n toLocale: to,\n translatorName,\n timestamp: new Date().toISOString(),\n cached: true,\n })\n return cached\n }\n\n const result = await this.options.plaintextTranslator!({ text, from, to, field, collection })\n this.translatorCache.set(cacheKey, result)\n this._translatorAuditLog.push({\n type: 'translator-invocation',\n field,\n collection,\n fromLocale: from,\n toLocale: to,\n translatorName,\n timestamp: new Date().toISOString(),\n })\n return result\n }\n\n /** Get or load the keyring for a vault. */\n private async getKeyring(vault: string): Promise<UnlockedKeyring> {\n if (this.options.encrypt === false) {\n return createPlaintextKeyring(this.options.user)\n }\n\n const cached = this.keyringCache.get(vault)\n if (cached) return cached\n\n if (!this.options.secret) {\n throw new ValidationError('A secret (passphrase) is required when encryption is enabled')\n }\n\n let keyring: UnlockedKeyring\n try {\n keyring = await loadKeyring(this.options.store, vault, this.options.user, this.options.secret)\n } catch (err) {\n // Only create a new keyring if no keyring exists (NoAccessError).\n // If the keyring exists but the passphrase is wrong (InvalidKeyError), propagate the error.\n if (err instanceof NoAccessError) {\n keyring = await createOwnerKeyring(this.options.store, vault, this.options.user, this.options.secret)\n } else {\n throw err\n }\n }\n\n this.keyringCache.set(vault, keyring)\n return keyring\n }\n}\n\n/** Create a new NOYDB instance. */\nexport async function createNoydb(options: NoydbOptions): Promise<Noydb> {\n const encrypted = options.encrypt !== false\n\n if (encrypted && !options.secret) {\n throw new ValidationError('A secret (passphrase) is required when encryption is enabled')\n }\n\n return new Noydb(options)\n}\n\n// ─── Internal helpers ─────────────────────────────────────────────────\n\n/**\n * Normalize `NoydbOptions.sync` to a `SyncTarget[]`.\n * Accepts a bare NoydbStore, a SyncTarget, or an array.\n */\nfunction normalizeSyncTargets(\n sync: NoydbOptions['sync'],\n): SyncTarget[] {\n if (!sync) return []\n if (Array.isArray(sync)) return sync\n // SyncTarget has a `role` property; bare NoydbStore does not\n if ('role' in sync && typeof sync.role === 'string') {\n return [sync]\n }\n // Bare NoydbStore — wrap as sync-peer\n return [{ store: sync as NoydbStore, role: 'sync-peer' }]\n}\n","/**\n * Vault-level diff orchestrator.\n *\n * Compares a live `Vault`'s plaintext state against a candidate state\n * (another vault, a plain `{ collection: records[] }` map, or a vault\n * dump JSON) and returns a structured `VaultDiff` plan listing the\n * records that would be added, modified, or deleted to bring the live\n * vault into the candidate's shape.\n *\n * Builds on two existing record-level helpers:\n *\n * 1. `diff(a, b)` from `./history/diff.ts` — emits dot-pathed\n * `DiffEntry[]` with `type: 'added' | 'removed' | 'changed'` for\n * each changed field of two records. Used here for the\n * `fieldDiffs` of every `modified` entry, and (with empty result)\n * as the default deep-equal check.\n *\n * 2. `Vault.exportStream()` from `./vault.ts` — the canonical\n * decrypt-and-stream-records iterator. Used to walk both sides\n * when the candidate is itself a `Vault`. ACL-scoped: collections\n * the caller can't read silently drop out, the same way every\n * other plaintext-emitting export pipeline filters them.\n *\n * The new orchestration is the **vault-level** enumeration: bucket\n * each record id into added (only in candidate), deleted (only in\n * vault), or modified (in both with field changes); leave the\n * field-level granularity to the existing `diff()`.\n *\n * Use cases:\n *\n * - Import preview (`@noy-db/as-*` `fromString` returns a plan\n * whose body is a `VaultDiff`).\n * - Backup verification (\"does this `.noydb` bundle from yesterday\n * match the current vault?\").\n * - Two-vault reconciliation (\"what's different between Office A\n * and Office B before we sync?\").\n * - Test assertions (golden-file testing with one-liner\n * `expect(plan.summary).toEqual(...)`).\n *\n * @module\n */\n\nimport type { Vault } from './vault.js'\nimport { diff as fieldDiff, type DiffEntry as FieldDiffEntry } from './history/diff.js'\n\n// ─── Public types ──────────────────────────────────────────────────────\n\n/** Per-record entry shape — added and deleted records carry only the record value. */\nexport interface VaultDiffEntry<T = unknown> {\n readonly collection: string\n readonly id: string\n readonly record: T\n}\n\n/** Modified records carry both halves of the diff plus the field-level breakdown. */\nexport interface VaultDiffModifiedEntry<T = unknown> extends VaultDiffEntry<T> {\n /** The record as it stands in the live vault. */\n readonly before: T\n /** Top-level keys whose values differ between `before` and `record`. */\n readonly fieldsChanged: readonly string[]\n /**\n * Field-level diff entries from `diff(before, record)`. Reuses the\n * existing per-record diff helper so consumers can render git-style\n * `path: from → to` rows without re-walking the records.\n */\n readonly fieldDiffs: readonly FieldDiffEntry[]\n}\n\nexport interface VaultDiff<T = unknown> {\n readonly added: readonly VaultDiffEntry<T>[]\n readonly modified: readonly VaultDiffModifiedEntry<T>[]\n readonly deleted: readonly VaultDiffEntry<T>[]\n /** Only populated when `options.includeUnchanged: true`. */\n readonly unchanged: readonly VaultDiffEntry<T>[] | undefined\n readonly summary: {\n readonly add: number\n readonly modify: number\n readonly delete: number\n readonly total: number\n }\n /**\n * Format the diff as a human-readable string.\n *\n * - `'count'` — one line, just the numbers (`12 added · 3 modified · 0 deleted`)\n * - `'one-line'` — count plus a single overview line\n * - `'full'` — count + one row per added/modified/deleted record (default)\n */\n format(opts?: { detail?: 'count' | 'one-line' | 'full' }): string\n}\n\nexport interface DiffOptions {\n /** Restrict the diff to a subset of collections. */\n readonly collections?: readonly string[]\n /** Field on each record that carries its id. Defaults to `'id'`. */\n readonly idKey?: string\n /** Override the default deep-equal check for \"modified vs unchanged\". */\n readonly compareFn?: (a: unknown, b: unknown) => boolean\n /** If true, include unchanged records in the diff (off by default to save memory). */\n readonly includeUnchanged?: boolean\n}\n\n/**\n * Candidate state to diff the vault against:\n *\n * - A `Vault` instance — both sides are walked via `exportStream()`.\n * - A `Record<collection, records[]>` map — same shape `as-json.toObject()`\n * produces. Useful for diffing parsed file content against the live vault.\n * - A `VaultDump` (output of `vault.dump()`) — a JSON string carrying the\n * full vault state. Parsed and reduced to the map shape above.\n */\nexport type DiffCandidate<T = unknown> =\n | Vault\n | Record<string, readonly T[]>\n | string\n\n// ─── Implementation ────────────────────────────────────────────────────\n\n/**\n * Compute the diff between a live vault and a candidate state.\n *\n * Returns a fully buffered `VaultDiff` — no streaming. Memory cost is\n * O(n + m) in the row count of vault + candidate. For documented\n * 1K-50K-record vaults this is fine; a streaming variant lands as a\n * follow-up if a > 100K-record consumer arrives.\n */\nexport async function diffVault<T = unknown>(\n vault: Vault,\n candidate: DiffCandidate<T>,\n options: DiffOptions = {},\n): Promise<VaultDiff<T>> {\n const idKey = options.idKey ?? 'id'\n const filter = options.collections ? new Set(options.collections) : null\n const compareFn =\n options.compareFn ?? ((a: unknown, b: unknown) => fieldDiff(a, b).length === 0)\n\n // Side A — walk the live vault via exportStream(). Each chunk arrives\n // already decrypted and ACL-scoped, so collections the caller can't\n // read silently drop out. exportStream's records are typed `unknown[]`\n // — diffVault is the type-erasure boundary; the caller asserts the\n // record shape via the function's `<T>` generic.\n const live = new Map<string, Map<string, T>>()\n for await (const chunk of vault.exportStream({ granularity: 'collection' })) {\n if (filter && !filter.has(chunk.collection)) continue\n const collection = live.get(chunk.collection) ?? new Map<string, T>()\n for (const record of chunk.records) {\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record as T)\n }\n live.set(chunk.collection, collection)\n }\n\n // Side B — normalise the candidate into the same shape.\n const cand = await normaliseCandidate<T>(candidate, idKey, filter)\n\n // Walk every (collection, id) on either side and bucket.\n const added: VaultDiffEntry<T>[] = []\n const modified: VaultDiffModifiedEntry<T>[] = []\n const deleted: VaultDiffEntry<T>[] = []\n const unchanged: VaultDiffEntry<T>[] | undefined = options.includeUnchanged ? [] : undefined\n\n const collectionNames = new Set([...live.keys(), ...cand.keys()])\n for (const collection of [...collectionNames].sort()) {\n const liveColl = live.get(collection) ?? new Map<string, T>()\n const candColl = cand.get(collection) ?? new Map<string, T>()\n const allIds = new Set([...liveColl.keys(), ...candColl.keys()])\n\n for (const id of [...allIds].sort()) {\n const before = liveColl.get(id)\n const after = candColl.get(id)\n\n if (before === undefined && after !== undefined) {\n added.push({ collection, id, record: after })\n } else if (before !== undefined && after === undefined) {\n deleted.push({ collection, id, record: before })\n } else if (before !== undefined && after !== undefined) {\n if (compareFn(before, after)) {\n unchanged?.push({ collection, id, record: after })\n } else {\n const fieldDiffs = fieldDiff(before, after)\n const fieldsChanged = uniqueTopLevelKeys(fieldDiffs)\n modified.push({\n collection,\n id,\n record: after,\n before,\n fieldsChanged,\n fieldDiffs,\n })\n }\n }\n }\n }\n\n const summary = {\n add: added.length,\n modify: modified.length,\n delete: deleted.length,\n total: added.length + modified.length + deleted.length,\n }\n\n return {\n added,\n modified,\n deleted,\n unchanged,\n summary,\n format(opts) {\n return formatDiff(opts?.detail ?? 'full', { added, modified, deleted, summary })\n },\n }\n}\n\n// ─── Internals ─────────────────────────────────────────────────────────\n\nasync function normaliseCandidate<T>(\n candidate: DiffCandidate<T>,\n idKey: string,\n filter: Set<string> | null,\n): Promise<Map<string, Map<string, T>>> {\n const out = new Map<string, Map<string, T>>()\n\n // Vault instance — duck-type via the exportStream method (matches\n // vault.ts's structural shape without forcing a runtime instanceof check\n // that would import the class and risk circular deps).\n if (\n typeof candidate === 'object' &&\n candidate !== null &&\n 'exportStream' in candidate &&\n typeof (candidate as Vault).exportStream === 'function'\n ) {\n for await (const chunk of (candidate as Vault).exportStream({ granularity: 'collection' })) {\n if (filter && !filter.has(chunk.collection)) continue\n const collection = out.get(chunk.collection) ?? new Map<string, T>()\n for (const record of chunk.records) {\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record as T)\n }\n out.set(chunk.collection, collection)\n }\n return out\n }\n\n // String — assume a vault.dump() JSON string. Parse and reduce to the map shape.\n if (typeof candidate === 'string') {\n let parsed: unknown\n try {\n parsed = JSON.parse(candidate)\n } catch (err) {\n throw new Error(\n `diffVault: candidate string is not valid JSON (${(err as Error).message})`,\n )\n }\n return collectionsFromObject<T>(parsed, idKey, filter)\n }\n\n // Plain object — `Record<collection, records[]>` (same shape as-json.toObject() returns).\n return collectionsFromObject<T>(candidate, idKey, filter)\n}\n\nfunction collectionsFromObject<T>(\n raw: unknown,\n idKey: string,\n filter: Set<string> | null,\n): Map<string, Map<string, T>> {\n const out = new Map<string, Map<string, T>>()\n if (raw === null || typeof raw !== 'object') {\n throw new Error('diffVault: candidate must be a Vault, an object, or a JSON string')\n }\n // A vault dump JSON has a top-level shape like { _compartment, _keyring, <coll>: <records[]> }.\n // We accept both: keys starting with `_` are skipped (they're metadata), the rest are collections.\n for (const [key, value] of Object.entries(raw)) {\n if (key.startsWith('_')) continue\n if (filter && !filter.has(key)) continue\n if (!Array.isArray(value)) continue\n const collection = new Map<string, T>()\n for (const record of value as readonly T[]) {\n if (record === null || typeof record !== 'object') continue\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record)\n }\n out.set(key, collection)\n }\n return out\n}\n\nfunction uniqueTopLevelKeys(diffs: readonly FieldDiffEntry[]): readonly string[] {\n const keys = new Set<string>()\n for (const d of diffs) {\n // path is dot-separated; the top-level key is everything before the\n // first `.` or `[`. (`a.b.c` → `a`, `tags[0]` → `tags`, `(root)` → `(root)`).\n const m = /^[^.[]+/.exec(d.path)\n if (m) keys.add(m[0])\n }\n return [...keys]\n}\n\n/**\n * Pull the id field off a record without going through `String(obj)`,\n * which would emit `[object Object]` for nested objects and silently\n * collapse rows that share the same parent. Only string and number ids\n * are accepted; anything else returns the empty string and the record\n * is skipped at the call site.\n */\nfunction readIdField(record: unknown, idKey: string): string {\n if (record === null || typeof record !== 'object') return ''\n const v = (record as Record<string, unknown>)[idKey]\n if (typeof v === 'string') return v\n if (typeof v === 'number' && Number.isFinite(v)) return String(v)\n return ''\n}\n\ninterface FormatBuckets<T> {\n readonly added: readonly VaultDiffEntry<T>[]\n readonly modified: readonly VaultDiffModifiedEntry<T>[]\n readonly deleted: readonly VaultDiffEntry<T>[]\n readonly summary: VaultDiff<T>['summary']\n}\n\nfunction formatDiff<T>(\n detail: 'count' | 'one-line' | 'full',\n b: FormatBuckets<T>,\n): string {\n const head = `${b.summary.add} added · ${b.summary.modify} modified · ${b.summary.delete} deleted`\n if (detail === 'count') return head\n if (b.summary.total === 0) return head + '\\n(no changes)'\n if (detail === 'one-line') return head\n\n const rows: string[] = [head, '']\n for (const e of b.added) rows.push(`${e.collection}/${e.id}\\tadded`)\n for (const e of b.modified) {\n const fields = e.fieldDiffs\n .map((f) => `${f.path}: ${shortJSON(f.from)} → ${shortJSON(f.to)}`)\n .join(', ')\n rows.push(`${e.collection}/${e.id}\\tmodified\\t${fields}`)\n }\n for (const e of b.deleted) rows.push(`${e.collection}/${e.id}\\tdeleted`)\n return rows.join('\\n')\n}\n\nfunction shortJSON(value: unknown): string {\n if (value === undefined) return 'undefined'\n const s = JSON.stringify(value)\n // JSON.stringify returns string for any JSON value except `undefined`\n // (handled above), `function`, and `symbol`. Fall back to a static\n // tag for those — never let an arbitrary object hit the default\n // stringifier (which the lint rule explicitly bans).\n if (typeof s !== 'string') return '<unrepresentable>'\n return s.length > 60 ? s.slice(0, 57) + '...' : s\n}\n","import { ValidationError } from './errors.js'\n\n/**\n * Validate passphrase strength.\n * Checks length and basic entropy heuristics.\n * Throws ValidationError if too weak.\n */\nexport function validatePassphrase(passphrase: string): void {\n if (passphrase.length < 8) {\n throw new ValidationError(\n 'Passphrase too short — minimum 8 characters. ' +\n 'Recommended: 12+ characters or a 4+ word passphrase.',\n )\n }\n\n const entropy = estimateEntropy(passphrase)\n if (entropy < 28) {\n throw new ValidationError(\n 'Passphrase too weak — too little entropy. ' +\n 'Use a mix of uppercase, lowercase, numbers, and symbols, ' +\n 'or use a 4+ word passphrase.',\n )\n }\n}\n\n/**\n * Estimate passphrase entropy in bits.\n * Uses character class analysis (not dictionary-based).\n */\nexport function estimateEntropy(passphrase: string): number {\n let charsetSize = 0\n\n if (/[a-z]/.test(passphrase)) charsetSize += 26\n if (/[A-Z]/.test(passphrase)) charsetSize += 26\n if (/[0-9]/.test(passphrase)) charsetSize += 10\n if (/[^a-zA-Z0-9]/.test(passphrase)) charsetSize += 32\n\n if (charsetSize === 0) charsetSize = 26 // fallback\n\n return Math.floor(passphrase.length * Math.log2(charsetSize))\n}\n"],"mappings":"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","names":["notEnabled","notEnabled","version","envelope","previousEnvelope","NOT_ENABLED","NOT_ENABLED","issueDelegation","DELEGATIONS_COLLECTION","revokeDelegation","record","handle","generateULID","NOT_ENABLED","notEnabled","keyring","comp","formatDiff"]}
|