@noy-db/hub 0.2.0-pre.1 → 0.2.0-pre.2
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/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.js +2 -2
- package/dist/attestation/index.cjs +305 -0
- package/dist/attestation/index.cjs.map +1 -0
- package/dist/attestation/index.d.cts +52 -0
- package/dist/attestation/index.d.ts +52 -0
- package/dist/attestation/index.js +36 -0
- package/dist/attestation/index.js.map +1 -0
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +4 -3
- package/dist/blobs/index.d.ts +4 -3
- package/dist/blobs/index.js +9 -7
- package/dist/blobs/index.js.map +1 -1
- package/dist/bundle/index.cjs +16701 -129
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +172 -3
- package/dist/bundle/index.d.ts +172 -3
- package/dist/bundle/index.js +533 -5
- package/dist/bundle/index.js.map +1 -1
- package/dist/{chunk-5SCJ5UEF.js → chunk-243PNUA6.js} +2 -2
- package/dist/{chunk-WCA2NROQ.js → chunk-2PAQNPE3.js} +2 -2
- package/dist/chunk-3QAKZ37R.js +83 -0
- package/dist/chunk-3QAKZ37R.js.map +1 -0
- package/dist/chunk-3S4BJX25.js +36 -0
- package/dist/chunk-3S4BJX25.js.map +1 -0
- package/dist/chunk-3XHOCQK4.js +118 -0
- package/dist/chunk-3XHOCQK4.js.map +1 -0
- package/dist/{chunk-4TFSM22V.js → chunk-3Y53S2SA.js} +3 -3
- package/dist/{chunk-6HPZY4ON.js → chunk-3Z2TPHC4.js} +3 -3
- package/dist/chunk-4HIL6AHQ.js +57 -0
- package/dist/chunk-4HIL6AHQ.js.map +1 -0
- package/dist/{chunk-DYECX3IX.js → chunk-7BRE6EUA.js} +2 -2
- package/dist/{chunk-DYBQG5PQ.js → chunk-7BUTTVMR.js} +2 -2
- package/dist/{chunk-KESP7GOK.js → chunk-7Q5PLD5C.js} +3 -3
- package/dist/{chunk-UA4RI7OT.js → chunk-7Z23ZFLV.js} +4 -4
- package/dist/chunk-AHPFONIL.js +59 -0
- package/dist/chunk-AHPFONIL.js.map +1 -0
- package/dist/{chunk-EGQYGYIU.js → chunk-CXSCDO5T.js} +2 -2
- package/dist/chunk-E535SAN4.js +8834 -0
- package/dist/chunk-E535SAN4.js.map +1 -0
- package/dist/{chunk-CBAHB2BF.js → chunk-EUYOGYGV.js} +6 -69
- package/dist/chunk-EUYOGYGV.js.map +1 -0
- package/dist/{chunk-OMLIZL2P.js → chunk-FAQVNJD4.js} +2 -2
- package/dist/{chunk-I6MX32UC.js → chunk-G6FRSBKK.js} +4 -4
- package/dist/{chunk-FCXOFQAJ.js → chunk-GIV6DWBG.js} +2 -2
- package/dist/{chunk-34YSDCDP.js → chunk-HXJXPZRE.js} +2 -2
- package/dist/{chunk-23TTQXVO.js → chunk-J4KLMEUL.js} +2 -2
- package/dist/{chunk-VMIO4IXG.js → chunk-JYQTXEIO.js} +5 -228
- package/dist/chunk-JYQTXEIO.js.map +1 -0
- package/dist/{chunk-NIOHFJPJ.js → chunk-LRAZDV5X.js} +6 -118
- package/dist/chunk-LRAZDV5X.js.map +1 -0
- package/dist/{chunk-P7EQ2S5O.js → chunk-MUWOSVEP.js} +2 -2
- package/dist/chunk-NWZ3I6R6.js +79 -0
- package/dist/chunk-NWZ3I6R6.js.map +1 -0
- package/dist/{chunk-HB3Z2GCR.js → chunk-OVZDFEOR.js} +2 -2
- package/dist/chunk-PFSNOPBQ.js +233 -0
- package/dist/chunk-PFSNOPBQ.js.map +1 -0
- package/dist/{chunk-UZXLQCHP.js → chunk-PLI5TV7N.js} +2 -2
- package/dist/{chunk-PA6R5ZCI.js → chunk-Q6W2CMEJ.js} +3 -3
- package/dist/{chunk-537VFZTR.js → chunk-QPEXPHJR.js} +4 -4
- package/dist/{chunk-ZNOEIM6Y.js → chunk-QXQRKXCU.js} +2 -2
- package/dist/{chunk-RD5LYKD6.js → chunk-RTZVQAJ7.js} +2 -2
- package/dist/{chunk-DPMFBCV6.js → chunk-TBKOGSYR.js} +2 -2
- package/dist/{chunk-DPMFBCV6.js.map → chunk-TBKOGSYR.js.map} +1 -1
- package/dist/chunk-UND4XIB6.js +251 -0
- package/dist/chunk-UND4XIB6.js.map +1 -0
- package/dist/{chunk-7H6DOO3E.js → chunk-VCGTOS2A.js} +211 -36
- package/dist/chunk-VCGTOS2A.js.map +1 -0
- package/dist/{chunk-MKSA2V7A.js → chunk-VE6YVP32.js} +2 -2
- package/dist/{chunk-5DWL3JBF.js → chunk-VK5EER6C.js} +2 -2
- package/dist/{chunk-MIQHZESA.js → chunk-VPSUZLOJ.js} +4 -4
- package/dist/{chunk-MIQHZESA.js.map → chunk-VPSUZLOJ.js.map} +1 -1
- package/dist/{chunk-XGSOTWYX.js → chunk-VRBCTEKQ.js} +2 -2
- package/dist/{chunk-ADQ5MQ54.js → chunk-W3XXT26A.js} +29 -1
- package/dist/{chunk-ADQ5MQ54.js.map → chunk-W3XXT26A.js.map} +1 -1
- package/dist/{chunk-2AXFIYHT.js → chunk-XG3PTSCD.js} +1 -1
- package/dist/chunk-XG3PTSCD.js.map +1 -0
- package/dist/{chunk-SIZWEV2Y.js → chunk-Y2RKOPNC.js} +4 -4
- package/dist/{chunk-SIZWEV2Y.js.map → chunk-Y2RKOPNC.js.map} +1 -1
- package/dist/{chunk-Z72JH4KG.js → chunk-YTXSFG3C.js} +4 -34
- package/dist/chunk-YTXSFG3C.js.map +1 -0
- package/dist/consent/index.cjs.map +1 -1
- package/dist/consent/index.d.cts +4 -3
- package/dist/consent/index.d.ts +4 -3
- package/dist/consent/index.js +3 -3
- package/dist/{crypto-A7FRXYHC.js → crypto-5ZDIY3NG.js} +3 -3
- package/dist/{delegation-YBA4X4JN.js → delegation-QYXZW25W.js} +5 -5
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +5 -4
- package/dist/derivations/index.d.ts +5 -4
- package/dist/derivations/index.js +4 -4
- package/dist/{dev-unlock-DRwVSy2S.d.cts → dev-unlock-DQCNDfFp.d.cts} +1 -1
- package/dist/{dev-unlock-D9s-loPr.d.ts → dev-unlock-utkybTKb.d.ts} +1 -1
- package/dist/executor-AS2IDHKZ.js +11 -0
- package/dist/executor-HLXFXNFM.js +8 -0
- package/dist/executor-HN6YBHZ5.js +8 -0
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +5 -4
- package/dist/guards/index.d.ts +5 -4
- package/dist/guards/index.js +3 -3
- package/dist/{hash-DXXXusyk.d.ts → hash-DcoYWfJ_.d.ts} +1 -1
- package/dist/{hash-DtRih9MQ.d.cts → hash-jDowCrK2.d.cts} +1 -1
- package/dist/history/index.cjs +1 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +5 -4
- package/dist/history/index.d.ts +5 -4
- package/dist/history/index.js +5 -5
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +4 -3
- package/dist/i18n/index.d.ts +4 -3
- package/dist/i18n/index.js +13 -11
- package/dist/i18n/index.js.map +1 -1
- package/dist/{index-CNwA-B6-.d.ts → index-BCKdioeh.d.ts} +29 -1
- package/dist/{index-CmVgTkqk.d.cts → index-BMjrzNZr.d.cts} +29 -1
- package/dist/index.cjs +507 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -11
- package/dist/index.d.ts +12 -11
- package/dist/index.js +106 -8817
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.cjs.map +1 -1
- package/dist/indexing/index.js +2 -2
- package/dist/issue-ORP37MVW.js +12 -0
- package/dist/{ledger-3TXNP47J.js → ledger-3IU5GMXA.js} +5 -5
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +6 -5
- package/dist/materialized-views/index.d.ts +6 -5
- package/dist/materialized-views/index.js +6 -6
- package/dist/noydb-5H3C24GG.js +34 -0
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +5 -4
- package/dist/overlay-views/index.d.ts +5 -4
- package/dist/overlay-views/index.js +6 -4
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +4 -3
- package/dist/periods/index.d.ts +4 -3
- package/dist/periods/index.js +5 -5
- package/dist/{public-envelope-PY6NKFLI.js → public-envelope-U3CMEOMV.js} +3 -3
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +1 -1
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +3 -3
- package/dist/{registry-3L3N3PTG.js → registry-3ALP62P6.js} +3 -3
- package/dist/registry-7HE6VJGC.js +8 -0
- package/dist/registry-PSIPG2QR.js +8 -0
- package/dist/registry-PSIPG2QR.js.map +1 -0
- package/dist/revoke-KY2GB4KP.js +17 -0
- package/dist/revoke-KY2GB4KP.js.map +1 -0
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +5 -4
- package/dist/session/index.d.ts +5 -4
- package/dist/session/index.js +3 -3
- package/dist/shadow/index.cjs.map +1 -1
- package/dist/shadow/index.d.cts +4 -3
- package/dist/shadow/index.d.ts +4 -3
- package/dist/shadow/index.js +2 -2
- package/dist/signer-GRI5TZKH.js +18 -0
- package/dist/signer-GRI5TZKH.js.map +1 -0
- package/dist/{stale-HSC5YO2O.js → stale-OTOF3FH7.js} +2 -2
- package/dist/stale-OTOF3FH7.js.map +1 -0
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +4 -3
- package/dist/store/index.d.ts +4 -3
- package/dist/store/index.js +2 -2
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +3 -2
- package/dist/sync/index.d.ts +3 -2
- package/dist/sync/index.js +3 -3
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +4 -3
- package/dist/team/index.d.ts +4 -3
- package/dist/team/index.js +12 -10
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +4 -3
- package/dist/tx/index.d.ts +4 -3
- package/dist/tx/index.js +2 -2
- package/dist/{types-DW9RGSSs.d.ts → types-BoFFiskX.d.ts} +119 -3
- package/dist/{types-C4lwMKKF.d.cts → types-DJG8HG6F.d.cts} +119 -3
- package/dist/{index-hdFvZkBP.d.cts → ulid-BmBgooGm.d.ts} +51 -33
- package/dist/{index-4agOpzqd.d.ts → ulid-C7ms9oli.d.cts} +51 -33
- package/dist/util/index.cjs.map +1 -1
- package/dist/util/index.js +1 -1
- package/dist/{with-derivation-g-pGoMzL.d.ts → with-derivation-BKXXa8Vt.d.ts} +1 -1
- package/dist/{with-derivation-C8LDlV7t.d.cts → with-derivation-BjQ7q4NE.d.cts} +1 -1
- package/dist/{with-guard-DWOCK4Ca.d.ts → with-guard-C25yNjzd.d.ts} +1 -1
- package/dist/{with-guard-jI1x9Z3k.d.cts → with-guard-DQme5DKE.d.cts} +1 -1
- package/dist/{with-materialized-view-DcTx4H3j.d.cts → with-materialized-view-BbEPFIIJ.d.cts} +1 -1
- package/dist/{with-materialized-view-DaKR-N6J.d.ts → with-materialized-view-CqnRwI2S.d.ts} +1 -1
- package/dist/{with-overlayed-view-N7jYuNOS.d.ts → with-overlayed-view-Ct1fSJt-.d.ts} +1 -1
- package/dist/{with-overlayed-view-D-6oWAgM.d.cts → with-overlayed-view-bwlmmFjx.d.cts} +1 -1
- package/package.json +15 -3
- package/dist/chunk-2AXFIYHT.js.map +0 -1
- package/dist/chunk-7H6DOO3E.js.map +0 -1
- package/dist/chunk-CBAHB2BF.js.map +0 -1
- package/dist/chunk-NIOHFJPJ.js.map +0 -1
- package/dist/chunk-VMIO4IXG.js.map +0 -1
- package/dist/chunk-Z72JH4KG.js.map +0 -1
- package/dist/executor-7E3VFGW7.js +0 -11
- package/dist/executor-CEWX2FQI.js +0 -8
- package/dist/executor-X4SQ3ZLC.js +0 -8
- package/dist/registry-O47PUPSY.js +0 -8
- package/dist/registry-WLLMODKN.js +0 -8
- /package/dist/{chunk-5SCJ5UEF.js.map → chunk-243PNUA6.js.map} +0 -0
- /package/dist/{chunk-WCA2NROQ.js.map → chunk-2PAQNPE3.js.map} +0 -0
- /package/dist/{chunk-4TFSM22V.js.map → chunk-3Y53S2SA.js.map} +0 -0
- /package/dist/{chunk-6HPZY4ON.js.map → chunk-3Z2TPHC4.js.map} +0 -0
- /package/dist/{chunk-DYECX3IX.js.map → chunk-7BRE6EUA.js.map} +0 -0
- /package/dist/{chunk-DYBQG5PQ.js.map → chunk-7BUTTVMR.js.map} +0 -0
- /package/dist/{chunk-KESP7GOK.js.map → chunk-7Q5PLD5C.js.map} +0 -0
- /package/dist/{chunk-UA4RI7OT.js.map → chunk-7Z23ZFLV.js.map} +0 -0
- /package/dist/{chunk-EGQYGYIU.js.map → chunk-CXSCDO5T.js.map} +0 -0
- /package/dist/{chunk-OMLIZL2P.js.map → chunk-FAQVNJD4.js.map} +0 -0
- /package/dist/{chunk-I6MX32UC.js.map → chunk-G6FRSBKK.js.map} +0 -0
- /package/dist/{chunk-FCXOFQAJ.js.map → chunk-GIV6DWBG.js.map} +0 -0
- /package/dist/{chunk-34YSDCDP.js.map → chunk-HXJXPZRE.js.map} +0 -0
- /package/dist/{chunk-23TTQXVO.js.map → chunk-J4KLMEUL.js.map} +0 -0
- /package/dist/{chunk-P7EQ2S5O.js.map → chunk-MUWOSVEP.js.map} +0 -0
- /package/dist/{chunk-HB3Z2GCR.js.map → chunk-OVZDFEOR.js.map} +0 -0
- /package/dist/{chunk-UZXLQCHP.js.map → chunk-PLI5TV7N.js.map} +0 -0
- /package/dist/{chunk-PA6R5ZCI.js.map → chunk-Q6W2CMEJ.js.map} +0 -0
- /package/dist/{chunk-537VFZTR.js.map → chunk-QPEXPHJR.js.map} +0 -0
- /package/dist/{chunk-ZNOEIM6Y.js.map → chunk-QXQRKXCU.js.map} +0 -0
- /package/dist/{chunk-RD5LYKD6.js.map → chunk-RTZVQAJ7.js.map} +0 -0
- /package/dist/{chunk-MKSA2V7A.js.map → chunk-VE6YVP32.js.map} +0 -0
- /package/dist/{chunk-5DWL3JBF.js.map → chunk-VK5EER6C.js.map} +0 -0
- /package/dist/{chunk-XGSOTWYX.js.map → chunk-VRBCTEKQ.js.map} +0 -0
- /package/dist/{crypto-A7FRXYHC.js.map → crypto-5ZDIY3NG.js.map} +0 -0
- /package/dist/{delegation-YBA4X4JN.js.map → delegation-QYXZW25W.js.map} +0 -0
- /package/dist/{executor-7E3VFGW7.js.map → executor-AS2IDHKZ.js.map} +0 -0
- /package/dist/{executor-CEWX2FQI.js.map → executor-HLXFXNFM.js.map} +0 -0
- /package/dist/{executor-X4SQ3ZLC.js.map → executor-HN6YBHZ5.js.map} +0 -0
- /package/dist/{ledger-3TXNP47J.js.map → issue-ORP37MVW.js.map} +0 -0
- /package/dist/{public-envelope-PY6NKFLI.js.map → ledger-3IU5GMXA.js.map} +0 -0
- /package/dist/{registry-3L3N3PTG.js.map → noydb-5H3C24GG.js.map} +0 -0
- /package/dist/{registry-O47PUPSY.js.map → public-envelope-U3CMEOMV.js.map} +0 -0
- /package/dist/{registry-WLLMODKN.js.map → registry-3ALP62P6.js.map} +0 -0
- /package/dist/{stale-HSC5YO2O.js.map → registry-7HE6VJGC.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/policy/storage.ts","../src/auth-introspection/index.ts","../src/crdt/strategy.ts","../src/i18n/strategy.ts","../src/schema.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/derivations/stale.ts","../src/collection.ts","../src/shadow/strategy.ts","../src/consent/strategy.ts","../src/periods/strategy.ts","../src/refs.ts","../src/meta/user-envelope/api.ts","../src/persisted-schemas/canonicalize.ts","../src/persisted-schemas/derive.ts","../src/persisted-schemas/register.ts","../src/introspection/fields.ts","../src/introspection/walk.ts","../src/vault.ts","../src/events.ts","../src/session/unlock-state.ts","../src/tx/strategy.ts","../src/session/strategy.ts","../src/policy/presets.ts","../src/policy/engine.ts","../src/noydb.ts"],"sourcesContent":["/**\n * Persistence helpers for the vault-level policy document\n * (`_meta/policy`). Mirrors the bypass-AES pattern used by\n * `_meta/handle` — the policy document is plain JSON, the envelope's\n * `_iv` field is left empty.\n *\n * @see docs/subsystems/session-tiers.md → Storage location\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../types.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport type { VaultPolicy } from './types.js'\n\n/** Reserved collection name for vault-level metadata documents. */\nexport const META_COLLECTION = '_meta'\n/** Reserved id for the vault-level policy document. */\nexport const POLICY_RECORD_ID = 'policy'\n\n/**\n * Read the vault-level policy from `_meta/policy`. Returns `undefined`\n * when no policy has been persisted (fresh vault, or a vault written\n * before the policy module landed). The caller falls back to the\n * default preset.\n *\n * Tolerates corrupted documents the same way `_meta/handle` does: a\n * JSON parse failure surfaces as `undefined`, not a thrown error, so\n * a bad write never permanently locks a vault.\n */\nexport async function loadVaultPolicy(\n store: NoydbStore,\n vault: string,\n): Promise<VaultPolicy | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, POLICY_RECORD_ID)\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isVaultPolicy(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the vault-level policy at `_meta/policy`. Idempotent — call\n * once at vault creation and again on `db.updatePolicy()` invocations.\n */\nexport async function saveVaultPolicy(\n store: NoydbStore,\n vault: string,\n policy: VaultPolicy,\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(policy),\n }\n await store.put(vault, META_COLLECTION, POLICY_RECORD_ID, envelope)\n}\n\nfunction isVaultPolicy(x: unknown): x is VaultPolicy {\n if (x === null || typeof x !== 'object') return false\n if (!('gates' in x)) return false\n const gates = (x as { gates: unknown }).gates\n return gates !== null && typeof gates === 'object'\n}\n","/**\n * Authentication introspection — issue #13.\n *\n * Three surfaces over the configured tier model and the actual\n * per-user enrollment state:\n *\n * 1. **Vault-wide English summary** — {@link describeAuthConfig}.\n * 2. **Vault-wide Mermaid diagram** — {@link diagramAuthConfig}.\n * 3. **Per-user introspection** — {@link describeUserAuth}, gated by\n * the `view-user-auth` policy gate (off by default).\n *\n * The per-user surface is held to a strict allowlist — fields not on\n * the allowlist are dropped, never rendered. The negative test in\n * `auth-introspection.test.ts` exercises the allowlist by feeding a\n * contrived keyring with fake \"secret\" fields and asserting that none\n * of them appear in the output.\n *\n * @module\n */\nimport type { NoydbStore, KeyringFile, KeyringAuthenticator } from '../types.js'\nimport type { VaultPolicy, GatePolicy } from '../policy/types.js'\nimport { loadVaultPolicy } from '../policy/storage.js'\nimport { loadPaperRecoveryEntries } from '../team/recovery.js'\n\n/** Vault-wide English summary of the configured authentication graph. */\nexport async function describeAuthConfig(\n store: NoydbStore,\n vault: string,\n): Promise<string> {\n const policy = (await loadVaultPolicy(store, vault)) ?? defaultPolicySnapshot()\n const recoveryProfiles = await listRecoveryProfilesEnrolled(store, vault)\n\n const lines: string[] = []\n lines.push(`Vault \"${vault}\" — three-tier authentication`)\n lines.push('')\n lines.push('Tier 1 — Passphrase (master)')\n lines.push(` Phrase format: ${policy.passphrase?.minWords ?? 6}+ words, lowercase letters, ≥${policy.passphrase?.minWordLength ?? 3} chars/word`)\n lines.push(' Strength validator: enforced (override available for tests only)')\n lines.push('')\n lines.push('Tier 2 — Authenticate (routine login)')\n lines.push(' Allowed methods: WebAuthn (passkey), OIDC, Password')\n lines.push(' Slots per user: unlimited')\n lines.push('')\n lines.push('Tier 3 — Unlock (quick resume)')\n lines.push(' Method: PIN (per-app configurable)')\n lines.push('')\n lines.push(`Recovery profiles enrolled: ${recoveryProfiles.length === 0 ? 'none' : recoveryProfiles.join(', ')}`)\n lines.push('Managed-passphrase mode: off (post-1.0)')\n lines.push('')\n lines.push('Sensitive-action gates:')\n for (const [gate, gp] of Object.entries(policy.gates) as Array<[string, GatePolicy]>) {\n lines.push(` ${gate} — ${describeGatePolicy(gp)}`)\n }\n return lines.join('\\n')\n}\n\n/**\n * Render the vault's auth graph as Mermaid `flowchart TB` source. The\n * caller pipes this through Mermaid (CLI or browser) to get an SVG.\n */\nexport async function diagramAuthConfig(\n store: NoydbStore,\n vault: string,\n): Promise<string> {\n const policy = (await loadVaultPolicy(store, vault)) ?? defaultPolicySnapshot()\n const lines: string[] = []\n lines.push('flowchart TB')\n lines.push(` vault[\"Vault: ${escapeMermaid(vault)}\"]`)\n lines.push(' tier1[\"Tier 1<br/>Passphrase\"]')\n lines.push(' tier2[\"Tier 2<br/>Multi-slot Authenticate\"]')\n lines.push(' tier3[\"Tier 3<br/>PIN / Quick-resume\"]')\n lines.push(' vault --> tier1')\n lines.push(' tier1 --> tier2')\n lines.push(' tier2 --> tier3')\n for (const [gateName, gp] of Object.entries(policy.gates) as Array<[string, GatePolicy]>) {\n if (gp.enabled === false) continue\n const id = sanitizeId(gateName)\n const label = `${gateName}<br/>tier ≥ ${gp.minTier}`\n lines.push(` ${id}[\"${escapeMermaid(label)}\"]`)\n const tierNode = gp.minTier === 1 ? 'tier1' : gp.minTier === 2 ? 'tier2' : 'tier3'\n lines.push(` ${tierNode} --> ${id}`)\n }\n return lines.join('\\n')\n}\n\n/**\n * Render the per-user enrollment summary. Returns an empty\n * (non-throwing) string when the user has no keyring file — never\n * confirms or denies the existence of the user from the document\n * alone.\n *\n * Sanitization is strict: only the slot list, enrollment dates, and\n * recovery-profile counts are rendered. WebAuthn cred ids, OIDC\n * subject ids, password hashes, recovery codes, TOTP secrets — all\n * dropped at the allowlist boundary, not redacted.\n */\nexport async function describeUserAuth(\n store: NoydbStore,\n vault: string,\n userId: string,\n): Promise<string> {\n const env = await store.get(vault, '_keyring', userId)\n if (!env) return ''\n const file = JSON.parse(env._data) as KeyringFile\n\n const lines: string[] = []\n lines.push(\n `User: ${file.user_id} (joined ${file.created_at.slice(0, 10)}, role: ${file.role})`,\n )\n lines.push('')\n lines.push('Tier 2 enrollments:')\n if (!file.authenticators || file.authenticators.length === 0) {\n lines.push(' (none enrolled)')\n } else {\n for (const slot of file.authenticators) {\n lines.push(` - ${describeSlot(slot)}`)\n }\n }\n return lines.join('\\n')\n}\n\n/** Bulk variant for owner dashboards. */\nexport async function describeAllUsersAuth(\n store: NoydbStore,\n vault: string,\n): Promise<Array<{ userId: string; description: string }>> {\n const ids = await store.list(vault, '_keyring')\n const results: Array<{ userId: string; description: string }> = []\n for (const userId of ids) {\n const description = await describeUserAuth(store, vault, userId)\n if (description !== '') results.push({ userId, description })\n }\n return results\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────\n\nconst SLOT_FIELD_ALLOWLIST: ReadonlyArray<keyof KeyringAuthenticator> = [\n 'id',\n 'method',\n 'enrolled_at',\n 'enrolled_via_tier',\n] as const\n\nfunction describeSlot(slot: KeyringAuthenticator): string {\n // Project to the allowlist FIRST — never read meta/wrapped_kek into\n // any user-facing string. The allowlist is the only path values\n // take to the renderer; off-allowlist fields are dropped, not redacted.\n const sanitized: Partial<KeyringAuthenticator> = {}\n for (const key of SLOT_FIELD_ALLOWLIST) {\n if (key in slot) {\n // @ts-expect-error narrow assignment from allowlist iteration\n sanitized[key] = slot[key]\n }\n }\n const date = (sanitized.enrolled_at ?? '').slice(0, 10)\n return `${sanitized.method ?? '?'} (id=${sanitized.id ?? '?'}, enrolled ${date}, via tier ${sanitized.enrolled_via_tier ?? '?'})`\n}\n\nfunction describeGatePolicy(gp: GatePolicy): string {\n if (gp.enabled === false) return 'disabled'\n const parts: string[] = []\n parts.push(`tier ${gp.minTier}`)\n if (gp.factors && gp.factors.length > 0) {\n for (const f of gp.factors) {\n parts.push(`+ ${f.count ?? 1}× ${f.anyOf.join('|')}`)\n }\n }\n if (gp.warn?.sharedDevice === 'block') parts.push('block-on-shared-device')\n return parts.join(' ')\n}\n\nfunction defaultPolicySnapshot(): VaultPolicy {\n return {\n passphrase: { minWords: 6, minWordLength: 3, rejectRepeatedAdjacent: true },\n gates: {},\n }\n}\n\nasync function listRecoveryProfilesEnrolled(\n store: NoydbStore,\n vault: string,\n): Promise<ReadonlyArray<string>> {\n const enrolled: string[] = []\n const paper = await loadPaperRecoveryEntries(store, vault)\n if (paper.length > 0) enrolled.push(`paper (${paper.length} codes)`)\n return enrolled\n}\n\nfunction escapeMermaid(s: string): string {\n return s.replace(/\"/g, '\\\\\"').replace(/\\n/g, ' ')\n}\n\nfunction sanitizeId(s: string): string {\n return s.replace(/[^a-zA-Z0-9]/g, '_')\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 * 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 * 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 { Collection } from '../collection.js'\nimport type { ReadOnlyVaultFacade } from '../guards/types.js'\nimport type { TxContext } from '../tx/transaction.js'\nimport type { DerivationRegistry } from './registry.js'\n// Type-only — runtime class loaded via dynamic import in\n// `resolveStaleOnRead` only when a stale flag actually fires. Keeps\n// the executor chunk out of the floor bundle (#130).\nimport type { DerivationExecutor as DerivationExecutorType } from './executor.js'\nimport type { DerivationStrategy } from './types.js'\n\n/**\n * Accessor shape passed through from the owning Vault. Provides the\n * registry (used to look up strategies and as the WeakMap key) and a\n * resolver from collection name to the live `Collection` instance.\n * Same shape as `Collection.derivationSource` so callers can pass it\n * through directly.\n */\nexport interface DerivationStaleAccessor {\n registry(): DerivationRegistry\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n /**\n * Read-only vault facade handed to `derive(source, ctx)` on the lazy\n * resolve-on-read path. Same instance/shape as the eager path uses\n * (#147).\n */\n getReadOnlyFacade(): ReadOnlyVaultFacade\n /**\n * Active multi-record TxContext or `null`. The lazy resolve-on-read\n * path uses this to register tombstone deletes on `_executed` so a\n * later rollback restores the prior emission. Mirrors the eager\n * path's #133-style tracking; the lazy `put` was historically\n * unregistered but #144's tombstone delete (a NEW write path)\n * matches the eager registration for symmetry.\n */\n getActiveTxContext(): TxContext | null\n}\n\n/**\n * In-memory stale map keyed by `DerivationRegistry` instance (stable\n * per vault). Maps `${source}/${sourceId}` → set of pending strategies.\n *\n * Persistence across vault close is NOT implemented in v1 (concern\n * flagged in the dim14 spec). On vault re-open, derived records'\n * `_derivedFrom.strategyHash` will still match the registered\n * strategies' hash, so an unset stale flag is interpreted as \"fresh.\"\n * `vault.deriveAll()` (Task D13) is the explicit recompute escape\n * hatch.\n *\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst _staleByRegistry = new WeakMap<DerivationRegistry, Map<string, Set<DerivationStrategy<any, any>>>>()\n\nconst keyFor = (source: string, sourceId: string): string => `${source}/${sourceId}`\n\n/** Mark every output of (strategy, sourceId) as stale. */\nexport async function markStale(\n registry: DerivationRegistry,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n strategy: DerivationStrategy<any, any>,\n sourceId: string,\n): Promise<void> {\n let map = _staleByRegistry.get(registry)\n if (!map) {\n map = new Map()\n _staleByRegistry.set(registry, map)\n }\n const k = keyFor(strategy.source, sourceId)\n let set = map.get(k)\n if (!set) {\n set = new Set()\n map.set(k, set)\n }\n set.add(strategy)\n}\n\n/**\n * Called from `Collection.get` on lazy-mode output collections. If the\n * id has a pending stale flag for any strategy producing this output\n * collection, re-derive before returning the record. No-op when there\n * is no pending work — keeps the read fast path negligible.\n */\nexport async function resolveStaleOnRead(\n accessor: DerivationStaleAccessor,\n outputCollection: string,\n id: string,\n): Promise<void> {\n const registry = accessor.registry()\n const producers = registry.strategiesProducingOutput(outputCollection)\n if (producers.length === 0) return\n\n const map = _staleByRegistry.get(registry)\n if (!map) return\n\n // Dynamic-import the executor only when at least one stale flag\n // actually fires. Vaults with no derivation strategies never call\n // this function (gated on `derivationSource` in `Collection.get`);\n // vaults with strategies but no pending stale ids reach the\n // `pending.has(spec)` short-circuit below without ever touching\n // the executor chunk. See #130.\n let DerivationExecutor: typeof DerivationExecutorType | null = null\n\n for (const { spec, strategyHash } of producers) {\n const k = keyFor(spec.source, id)\n const pending = map.get(k)\n if (!pending || !pending.has(spec)) continue\n\n // Read the source record from the source collection and re-derive.\n // We use the same getCollection accessor that eager dispatch uses\n // — it returns the live `Collection<any>` instance with full\n // crypto / keyring wiring.\n const sourceColl = accessor.getCollection(spec.source)\n const source = await sourceColl.get(id)\n if (!source) {\n pending.delete(spec)\n continue\n }\n const sourceWithId = { ...(source as Record<string, unknown>), id } as Record<string, unknown> & { id: string }\n // sourceVersion: not tracked in v1 stale map; pass 0 — matches the\n // forthcoming v0 semantics, `_derivedFrom.sourceVersion` is\n // informational, not load-bearing for correctness.\n if (DerivationExecutor === null) {\n ({ DerivationExecutor } = (await import('./executor.js')) as { DerivationExecutor: typeof DerivationExecutorType })\n }\n const ctx = { vault: accessor.getReadOnlyFacade() }\n const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx)\n for (const key of Object.keys(spec.outputs)) {\n const out = result.outputs[key]\n if (!out) continue\n if (out.kind === 'failed') {\n const err = out.error\n if (spec.strict) {\n // Leave the stale flag set so a future read retries.\n throw err\n }\n console.warn(\n `[derivation] lazy output \"${key}\" for source \"${spec.source}\" id=\"${id}\" failed:`,\n err,\n )\n continue\n }\n if (out.kind === 'array') {\n // Defensive — array-shape requires `lifecycle: 'eager'`\n // (validated at withDerivation registration, #200 slice 1).\n // Reaching the lazy-resolve path for array-shape would mean\n // a registration check was bypassed. Log and skip.\n console.warn(\n `[derivation] unexpected array-shape output \"${key}\" in lazy resolve path; `\n + 'array-shape derivations require lifecycle: \"eager\" (#200 slice 1).',\n )\n continue\n }\n const outSpec = spec.outputs[key]\n if (!outSpec) continue\n const outputColl = accessor.getCollection(outSpec.collection)\n if (out.skipped === true) {\n // #144: optional output skipped on lazy resolve — delete any\n // prior emission so the read returns null (matches eager-path\n // tombstone semantics). Routed through `_internalDelete` so a\n // user-registered `onDelete` (#145) on the output collection\n // does NOT fire. The active TxContext (if any) is forwarded:\n // `resolveStaleOnRead` is reachable from `Collection.get()`\n // which can be called from inside a transaction, so the\n // tombstone must be observable to `revertExecuted` on\n // rollback. Closes the #133-asymmetry surfaced in PR #148\n // review.\n await outputColl._internalDelete(id, accessor.getActiveTxContext())\n continue\n }\n await outputColl.put(id, out.value)\n }\n pending.delete(spec)\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'\nimport type { GuardRegistry } from './guards/registry.js'\nimport type { ReadOnlyVaultFacade } from './guards/types.js'\n// Type-only — runtime class loaded via dynamic import in the\n// frozen-field branch of `put()` / amendment paths. Keeps the guard\n// executor chunk out of the floor bundle (#130).\nimport type { GuardExecutor as GuardExecutorType } from './guards/executor.js'\nimport type { DerivationRegistry } from './derivations/registry.js'\nimport type { TxContext, ExecutedOp } from './tx/transaction.js'\nimport { revertExecuted } from './tx/transaction.js'\n// Type-only — runtime class loaded via dynamic import in\n// `dispatchDerivations` when an eager-mode strategy fires. Keeps the\n// derivation executor chunk out of the floor bundle (#130).\nimport type { DerivationExecutor as DerivationExecutorType } from './derivations/executor.js'\nimport type {\n loadFanoutSidecar as LoadFanoutSidecarType,\n deleteFanoutSidecar as DeleteFanoutSidecarType,\n saveFanoutSidecar as SaveFanoutSidecarType,\n} from './derivations/fanout-sidecar.js'\nimport { markStale, resolveStaleOnRead } from './derivations/stale.js'\nimport type { MaterializedViewRegistry } from './materialized-views/registry.js'\nimport type { MVQueryContext } from './materialized-views/types.js'\nimport type { MaterializedViewExecutor as MVExecutorType } from './materialized-views/executor.js'\nimport type * as MVStaleModule from './materialized-views/stale.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] Store \"${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 vault's guard registry + a\n * read-only vault facade. When present, `Collection.put` and\n * `Collection.delete` consult the registry for guards declared\n * against this collection and run their `check` + `frozenFields`\n * before the adapter write. Absent in unit tests that construct\n * a Collection directly; production code always sets it via\n * `Vault.collection()`.\n *\n * Typed structurally rather than as `Vault` to avoid a circular\n * import (mirrors the `refEnforcer` / `joinResolver` pattern).\n */\n private readonly guardSource:\n | {\n registry(): GuardRegistry\n readOnlyVault(): ReadOnlyVaultFacade\n }\n | undefined\n\n /**\n * Vault-internal hook for derivation dispatch. When set,\n * `Collection.put` consults the registry after the source-write\n * commits and writes derived outputs through `getCollection(name).put`.\n * Same structural-interface pattern as `guardSource` to avoid a\n * circular Vault import.\n */\n private readonly derivationSource:\n | {\n registry(): DerivationRegistry\n getCollection(name: string): Collection<Record<string, unknown>>\n getReadOnlyFacade(): ReadOnlyVaultFacade\n getActiveTxContext(): TxContext | null\n /**\n * Construct a fresh transient TxContext bound to the owning\n * Noydb. Used by `Collection.putManyAtomic` to publish an\n * `_activeTxContext` for the duration of its Phase 2 loop so\n * recursive derived-output writes register their pre-write\n * envelopes on `ctx._executed` and roll back alongside the\n * bulk-put source ops (#133).\n */\n createTxContext(): TxContext\n /** Publish a TxContext for the duration of a bulk-atomic loop. */\n setActiveTxContext(ctx: TxContext): void\n /** Drop a previously-published TxContext (defensive no-op if mismatched). */\n clearActiveTxContext(ctx: TxContext): void\n }\n | undefined\n\n /**\n * Vault-internal hook for materialized-view dispatch (#143/#150).\n * Parallel to `derivationSource` — when set, `Collection.put` fires\n * `MaterializedViewRegistry.onSourceWrite` after the source-write\n * commits + after `dispatchDerivations` has run.\n */\n private readonly materializedViewSource:\n | {\n \n registry(): MaterializedViewRegistry\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n getQueryContext(): MVQueryContext\n }\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 * Optional back-reference to the owning vault's guard registry +\n * read-only facade. When present, put/delete consult registered\n * guards for this collection. Same structural-interface pattern\n * as `refEnforcer` to avoid a circular Vault import.\n */\n guardSource?: {\n registry(): GuardRegistry\n readOnlyVault(): ReadOnlyVaultFacade\n } | undefined\n /**\n * Optional back-reference to the owning vault's derivation\n * registry + collection accessor. When present, successful\n * `put()` dispatches registered derivation strategies for the\n * source collection. Same structural-interface pattern as\n * `guardSource` to avoid a circular Vault import.\n */\n derivationSource?: {\n registry(): DerivationRegistry\n getCollection(name: string): Collection<Record<string, unknown>>\n /**\n * Read-only vault facade handed to `derive(source, ctx)` so a\n * derivation can fetch sibling records (#147). Same shape and\n * instance the guards subsystem uses for `check(incoming, ctx)`.\n */\n getReadOnlyFacade(): ReadOnlyVaultFacade\n /**\n * Read access to the owning Noydb's currently-active multi-record\n * transaction context, or `null` when no transaction is running.\n * `dispatchDerivations` consults this so a recursive derived-output\n * write can register its pre-write envelope onto `ctx._executed`\n * and roll back alongside the source op on mid-batch failure (#133).\n */\n getActiveTxContext(): TxContext | null\n /**\n * Construct a transient TxContext bound to the owning Noydb. Used\n * by `Collection.putManyAtomic` to publish an active context for\n * its Phase 2 loop (#133).\n */\n createTxContext(): TxContext\n /** Publish a TxContext for the duration of a bulk-atomic loop. */\n setActiveTxContext(ctx: TxContext): void\n /** Drop a previously-published TxContext. */\n clearActiveTxContext(ctx: TxContext): void\n } | undefined\n /**\n * Vault-internal hook for materialized-view dispatch (#143/#150).\n * Parallel to `derivationSource`. When set, `Collection.put` fires\n * registered MV `onSourceWrite` after the standard derivation\n * dispatch.\n */\n materializedViewSource?: {\n \n registry(): MaterializedViewRegistry\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n getCollection(name: string): Collection<any>\n getActiveTxContext(): TxContext | null\n getQueryContext(): MVQueryContext\n } | undefined\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 this.guardSource = opts.guardSource\n this.derivationSource = opts.derivationSource\n this.materializedViewSource = opts.materializedViewSource\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 // --- Lazy derivation resolution ---\n // If this collection is the output of a lazy-mode derivation\n // strategy, consult the stale map and re-derive on demand before\n // reading. No-op when nothing is pending — keeps the read fast\n // path cheap.\n if (this.derivationSource !== undefined) {\n const registry = this.derivationSource.registry()\n if (registry.strategiesProducingOutput(this.name).length > 0) {\n await resolveStaleOnRead(this.derivationSource, this.name, id)\n }\n }\n\n // Lazy-MV resolve-on-read (#151). When the collection being read\n // is the output of a registered lazy MV that has at least one\n // pending stale flag, run the executor before returning. No-op\n // when nothing is pending.\n if (this.materializedViewSource !== undefined) {\n const { resolveStaleMVOnRead } = await import('./materialized-views/stale.js')\n await resolveStaleMVOnRead(this.materializedViewSource, this.name)\n }\n\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 /**\n * Create or update a record.\n *\n * @param id Record identifier.\n * @param record The record body (validated by the collection's schema\n * if one was attached at `vault.collection(...)` time).\n * @param options Optional metadata for audit + import workflows.\n * `reason` is stamped onto the resulting ledger entry\n * (see #1) so audit consumers can filter via\n * `entries.filter(e => e.reason?.startsWith('import:'))`.\n */\n async put(id: string, record: T, options?: { readonly reason?: string }): Promise<void> {\n if (!hasWritePermission(this.keyring, this.name)) {\n throw new ReadOnlyError()\n }\n\n // Guard hook (record lock + field freeze). Runs BEFORE the\n // period guard so a guard-blocked write fails before any\n // schema work, i18n translation, history, or ledger churn.\n // Inside an active amendment we skip the synchronous check\n // and frozen-field diff — those run at commit time on the\n // collected change-set instead.\n if (this.guardSource) {\n const registry = this.guardSource.registry()\n const guards = registry.guardsFor(this.name)\n if (guards.length > 0) {\n const existingEnv = await this.adapter.get(this.vault, this.name, id)\n let existingRecord: Record<string, unknown> | null = null\n if (existingEnv) {\n try {\n existingRecord = (await this.decryptRecord(existingEnv, { skipValidation: true })) as unknown as Record<string, unknown>\n } catch {\n existingRecord = null\n }\n }\n const incomingRecord = record as unknown as Record<string, unknown>\n const ctx = {\n existing: existingRecord,\n vault: this.guardSource.readOnlyVault(),\n userId: this.keyring.userId,\n role: this.keyring.role,\n }\n if (registry.isAmendmentActive()) {\n const vBefore = existingEnv?._v ?? 0\n // `put` deterministically bumps version by 1 — see the\n // `version = existing.version + 1` line further down in this\n // method. Computing vAfter here keeps the audit math local\n // to the call site that decides it.\n registry.collectChange(this.name, id, existingRecord, incomingRecord, vBefore, vBefore + 1)\n } else {\n await registry.runChecks(this.name, incomingRecord, ctx)\n // Dynamic-import the executor only when at least one guard\n // is registered AND a non-amendment write fires. Consumers\n // who never call `withGuard()` never reach this branch and\n // never pull `GuardExecutor` into their bundle (#130).\n const { GuardExecutor } = (await import('./guards/executor.js')) as { GuardExecutor: typeof GuardExecutorType }\n for (const g of guards) {\n await GuardExecutor.checkFrozenFields(g, id, existingRecord, incomingRecord)\n }\n }\n }\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 if (options?.reason !== undefined) appendInput.reason = options.reason\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 await this.dispatchDerivations(id, record, version)\n await this.dispatchMaterializedViews(id, record)\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 if (options?.reason !== undefined) appendInput.reason = options.reason\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 // Derivation dispatch — AFTER store + ledger + emitter commit so a\n // failed source-write never produces orphan derived outputs. The\n // recursive `put` into output collections re-enters this pipeline\n // (encrypt + ledger + emit) intentionally; cycle detection at vault\n // open is the primary defense against infinite recursion.\n await this.dispatchDerivations(id, record, version)\n await this.dispatchMaterializedViews(id, record)\n }\n\n /**\n * Fire registered MV strategies whose dependency set includes this\n * collection. Eager-mode MVs re-materialize inline via\n * `MaterializedViewExecutor.refresh`; lazy / manual modes are\n * no-ops in the foundation (subtask #150) — wired in #151.\n *\n * Skips entirely when the record being written is itself an\n * MV-emitted row (carries `_materializedFrom`) — defensive guard\n * against missed cycle detection.\n *\n * @internal\n */\n private async dispatchMaterializedViews(id: string, record: T): Promise<void> {\n void id\n if (this.materializedViewSource === undefined) return\n const incoming = record as unknown as Record<string, unknown>\n if (incoming && typeof incoming === 'object' && '_materializedFrom' in incoming) return\n const registry = this.materializedViewSource.registry()\n const mvs = registry.mvsForSource(this.name)\n if (mvs.length === 0) return\n // Dynamic-import the executor only on first eager-MV dispatch —\n // keeps the MV executor chunk out of the floor bundle (mirrors the\n // #130 dynamic-import pattern v1 uses for derivations). Lazy mode\n // uses the pure-helper `markMVStale` which lives in `stale.js` and\n // is also dynamic-imported (only when at least one lazy MV depends\n // on this source).\n let executor: typeof MVExecutorType | null = null\n let staleHelpers: typeof MVStaleModule | null = null\n for (const reg of mvs) {\n const mode = reg.spec.refresh\n if (mode === 'eager') {\n if (executor === null) {\n ;({ MaterializedViewExecutor: executor } = await import('./materialized-views/executor.js'))\n }\n await executor.refresh(reg, {\n getCollection: (name) => this.materializedViewSource!.getCollection(name),\n getActiveTxContext: () => this.materializedViewSource!.getActiveTxContext(),\n getQueryContext: () => this.materializedViewSource!.getQueryContext(),\n })\n } else if (mode === 'lazy') {\n if (staleHelpers === null) {\n staleHelpers = await import('./materialized-views/stale.js')\n }\n staleHelpers.markMVStale(registry, reg.spec.name)\n }\n // manual: no-op on source-write. `vault.refreshView(name)` is\n // the only path that materializes a manual MV.\n }\n }\n\n /**\n * Fire registered derivation strategies for this source collection.\n * Eager mode runs `derive` inline and writes each output via the\n * sibling `Collection.put`; lazy mode marks dependent outputs stale\n * (D11 stub today). Errors in non-strict mode are logged and\n * skipped; strict mode propagates the first failing output's error.\n *\n * Skips entirely when the record being written is itself a derived\n * output (carries `_derivedFrom`) — defensive guard against missed\n * cycle detection.\n */\n private async dispatchDerivations(id: string, record: T, version: number): Promise<void> {\n if (this.derivationSource === undefined) return\n const incoming = record as unknown as Record<string, unknown>\n if (incoming && typeof incoming === 'object' && '_derivedFrom' in incoming) return\n const registry = this.derivationSource.registry()\n const strategies = registry.strategiesForSource(this.name)\n if (strategies.length === 0) return\n // Dynamic-import the executor only on the first eager-mode\n // dispatch. Lazy-mode dispatches use `markStale` (a pure helper)\n // which doesn't reach into the executor at all. Keeps the\n // derivation executor chunk out of the floor bundle for any\n // consumer that doesn't fire an eager derivation (#130).\n let DerivationExecutor: typeof DerivationExecutorType | null = null\n for (const { spec, strategyHash } of strategies) {\n const mode = typeof spec.lifecycle === 'string' ? spec.lifecycle : spec.lifecycle.mode\n if (mode === 'eager') {\n if (DerivationExecutor === null) {\n ({ DerivationExecutor } = (await import('./derivations/executor.js')) as { DerivationExecutor: typeof DerivationExecutorType })\n }\n const sourceWithId = { ...incoming, id } as Record<string, unknown> & { id: string }\n const ctx = { vault: this.derivationSource.getReadOnlyFacade() }\n const result = await DerivationExecutor.run(spec, sourceWithId, version, strategyHash, ctx)\n for (const key of Object.keys(spec.outputs)) {\n const out = result.outputs[key]\n if (!out) continue\n if (out.kind === 'failed') {\n const err = out.error\n if (spec.strict) throw err\n console.warn(`[derivation] output \"${key}\" for source \"${spec.source}\" id=\"${id}\" failed:`, err)\n continue\n }\n const outSpec = spec.outputs[key]\n if (!outSpec) continue\n const outputCollection = this.derivationSource.getCollection(outSpec.collection)\n // #133 — if we're inside a multi-record transaction, register\n // derived writes as side-effect ops on the active ctx\n // BEFORE they fire. `revertExecuted` walks `_executed` in\n // reverse on rollback, so capturing the pre-write envelope\n // here lets a later mid-batch failure restore this output's\n // prior state alongside the source op. Outside a transaction\n // the context is null and tracking is skipped.\n const txCtx = this.derivationSource.getActiveTxContext()\n\n // ── Array-shape branch (#200) ──────────────────────────\n if (out.kind === 'array') {\n // Load the prior key set from the fanout sidecar.\n const { loadFanoutSidecar, saveFanoutSidecar } = await import('./derivations/fanout-sidecar.js')\n const prior = await loadFanoutSidecar(\n this.adapter,\n this.vault,\n spec.source,\n id,\n key,\n )\n const prevKeys = new Set<string>(prior?.keys ?? [])\n const newKeysList = out.entries.map(e => e.key)\n const newKeysSet = new Set<string>(newKeysList)\n\n // Diff — delete keys that were in prev but not in new.\n for (const k of prevKeys) {\n if (newKeysSet.has(k)) continue\n await outputCollection._internalDelete(k, txCtx)\n }\n\n // Upsert every entry in the new set. (Slice 1: no\n // identity-skip optimisation; write every row, idempotent\n // at the (collection, id) level.)\n for (const entry of out.entries) {\n if (txCtx !== null) {\n const priorEnvelope = await this.adapter.get(this.vault, outSpec.collection, entry.key)\n txCtx._executed.push({\n op: {\n type: 'put',\n vaultName: this.vault,\n collectionName: outSpec.collection,\n id: entry.key,\n },\n priorEnvelope,\n })\n }\n await outputCollection.put(entry.key, entry.value)\n }\n\n // Persist the new key set (last step — see spec §5.1\n // on failure-mode symmetry).\n await saveFanoutSidecar(this.adapter, this.vault, {\n source: spec.source,\n sourceId: id,\n outputKey: key,\n outputCollection: outSpec.collection,\n keys: newKeysList,\n })\n continue\n }\n\n // ── Record-shape branch (existing v1 behavior) ─────────\n if (out.skipped === true) {\n // #144: optional output returned null. Delete the\n // previously-emitted output at this id, if any. Routed\n // through `_internalDelete` so a user-registered\n // `onDelete` (#145) on the output collection does NOT\n // fire — this is a system-internal tombstone, not a\n // user-initiated delete. The txCtx hookup captures the\n // prior envelope inside `_internalDelete` for #133-style\n // rollback symmetry; delete-of-absent is a silent no-op.\n await outputCollection._internalDelete(id, txCtx)\n continue\n }\n if (txCtx !== null) {\n const prior = await this.adapter.get(this.vault, outSpec.collection, id)\n txCtx._executed.push({\n op: {\n type: 'put',\n vaultName: this.vault,\n collectionName: outSpec.collection,\n id,\n },\n priorEnvelope: prior,\n })\n }\n await outputCollection.put(id, out.value)\n }\n } else {\n await markStale(registry, spec, id)\n }\n }\n }\n\n /** Delete a record by ID. */\n async delete(id: string): Promise<void> {\n await this._doDelete(id, false)\n }\n\n /**\n * @internal — system-internal delete that bypasses user-facing\n * delete hooks (`onDelete`, accounting-period guard, FK ref\n * enforcer). Used by derivation tombstones (#144) and MV refresh\n * (Dim 14 v2) — system housekeeping shouldn't trip user invariants\n * registered against the output collection. The ledger entry and\n * history snapshot still fire so backup integrity and time-travel\n * reconstruction stay consistent.\n *\n * Returns silently for delete-of-absent (idempotent contract — both\n * paths honour this: the `txCtx === null` path also reads the prior\n * envelope and short-circuits before the ledger/event side-effects).\n *\n * When a `txCtx` is supplied, the prior envelope is captured and\n * pushed onto `txCtx._executed` BEFORE the delete fires — mirrors\n * the #133 rollback hardening for puts. Callers outside a\n * multi-record transaction pass `null` and skip the tracking.\n *\n * Amendment composition: if `_internalDelete` runs while a vault's\n * `GuardRegistry` has an amendment window open, the `{before, after:\n * null}` change pair is pushed onto the amendment change-set the\n * same way a user-initiated delete would. The `onDelete` user-hook\n * is still skipped (housekeeping must not trip user invariants in\n * normal mode), but the amendment's invariant DOES see the change\n * — so a `RCT-CANCEL-001`-style invariant pairing can reject a\n * derivation-driven tombstone fired during an admin amendment.\n *\n * Constraint to surface to consumers: output collections of\n * derivations with `optional: true` outputs should not be the\n * targets of `strict` or `cascade` inbound foreign-key refs —\n * `_internalDelete` bypasses the ref enforcer by design (the\n * `onDelete` bypass primitive). Treat the housekeeping path as\n * \"system can tombstone its own emissions regardless of FK shape.\"\n *\n * Permission handling is unchanged: the caller must still hold\n * write permission on the collection (derivations run under the\n * user's keyring).\n */\n async _internalDelete(id: string, txCtx: TxContext | null = null): Promise<void> {\n // Idempotency contract: short-circuit before any ledger/event\n // side-effect when the target is absent. Both txCtx-aware and\n // txCtx-null callers honour this — `deriveAll` recomputes\n // expense-only allocations that never emitted a receipt without\n // writing spurious v0 ledger entries.\n const prior = await this.adapter.get(this.vault, this.name, id)\n if (prior === null) return\n if (txCtx !== null) {\n txCtx._executed.push({\n op: {\n type: 'delete',\n vaultName: this.vault,\n collectionName: this.name,\n id,\n },\n priorEnvelope: prior,\n })\n }\n await this._doDelete(id, true)\n }\n\n private async _doDelete(id: string, internal: boolean): Promise<void> {\n if (!hasWritePermission(this.keyring, this.name)) {\n throw new ReadOnlyError()\n }\n\n // Guard hook for deletes. Symmetric to put(): consult the\n // registry, decrypt the prior record (if any), then either\n // collect the {before, null} change pair into an active\n // amendment or run the guards' `onDelete` callback. Frozen-field\n // diffing is skipped (it's a put concept). Delete-of-absent is\n // a no-op — no guard is consulted because there's nothing to\n // protect, matching the idempotent-delete contract.\n //\n // For `internal === true` (system housekeeping — derivation\n // tombstones, MV refresh): `onDelete` is bypassed, but the\n // amendment change-collection still runs if a window is open.\n // This means an `amendment.invariant` paired with `onDelete` for\n // \"TRULY unconditional\" rules sees the system delete and can\n // reject it — closing the niwat-review gap where a derivation\n // tombstone fired during an admin amendment would otherwise\n // silently bypass both hooks.\n if (this.guardSource) {\n const registry = this.guardSource.registry()\n const guards = registry.guardsFor(this.name)\n if (guards.length > 0) {\n const existingEnv = await this.adapter.get(this.vault, this.name, id)\n if (existingEnv) {\n let existingRecord: Record<string, unknown> | null = null\n try {\n existingRecord = (await this.decryptRecord(existingEnv, { skipValidation: true })) as unknown as Record<string, unknown>\n } catch {\n existingRecord = null\n }\n if (registry.isAmendmentActive()) {\n // For deletes, the record version is the version that was\n // visible at delete time; we record vBefore = that version\n // and vAfter = same (the ledger entry's `op` discriminator\n // is `delete`, not `put`, so the consumer treats the\n // tombstone shape correctly). Fires for BOTH user and\n // system-internal deletes (#145 follow-up).\n const vBefore = existingEnv._v\n registry.collectChange(\n this.name,\n id,\n existingRecord,\n null as unknown as Record<string, unknown>,\n vBefore,\n vBefore,\n )\n } else if (!internal) {\n // Dedicated delete-time hook (#145). `check` is put-only;\n // `onDelete(existing, ctx)` receives the currently-persisted\n // record and decides whether the deletion is permitted.\n // Skipped for internal deletes — housekeeping must not trip\n // user invariants in normal-mode operation.\n const ctx = {\n existing: existingRecord,\n vault: this.guardSource.readOnlyVault(),\n userId: this.keyring.userId,\n role: this.keyring.role,\n }\n await registry.runOnDelete(\n this.name,\n existingRecord ?? {},\n ctx,\n )\n }\n }\n }\n }\n\n // accounting-period guard (same contract as put;\n // incoming is null because this is a delete).\n if (!internal && 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 (!internal && 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 // Symmetric to put (#181): user-initiated deletes must fire MV\n // refresh so `onEmpty: 'delete'` MVs tombstone their now-orphan\n // output rows. Gated on `!internal` to prevent recursion — the\n // MV executor's own tombstoning round-trips through\n // `_internalDelete → _doDelete(_, true)` and must NOT re-fire\n // dispatch (matches put's `_materializedFrom` skip in spirit).\n //\n // Record-shape derivations intentionally NOT dispatched on delete:\n // their derived-output id equals the source id, so the user can\n // delete the output directly with `outputCollection.delete(id)` if\n // they want. Array-shape derivations (#200) DO cascade on delete\n // because their derived ids are opaque (from the `key(out)`\n // extractor) — without cascade the rows become unfindable orphans.\n if (!internal) {\n await this.dispatchMaterializedViewsOnDelete(id)\n await this.dispatchArrayDerivationsOnDelete(id)\n }\n }\n\n /**\n * Cascade deletes of array-shape derived rows when a source row is\n * deleted (#200). Reads each registered strategy's fanout sidecar\n * for this source id, deletes every listed derived row, then\n * deletes the sidecar itself.\n *\n * Record-shape derivations are skipped — see _doDelete's comment\n * for why the asymmetry is correct.\n *\n * @internal\n */\n private async dispatchArrayDerivationsOnDelete(id: string): Promise<void> {\n if (this.derivationSource === undefined) return\n const registry = this.derivationSource.registry()\n const strategies = registry.strategiesForSource(this.name)\n if (strategies.length === 0) return\n\n // Dynamic-import the sidecar helpers — keeps the derivation\n // chunk out of the floor bundle for consumers that don't use\n // array-shape derivations.\n let helpers: {\n loadFanoutSidecar: typeof LoadFanoutSidecarType\n deleteFanoutSidecar: typeof DeleteFanoutSidecarType\n saveFanoutSidecar: typeof SaveFanoutSidecarType\n } | null = null\n const txCtx = this.derivationSource.getActiveTxContext()\n\n for (const { spec } of strategies) {\n for (const [outputKey, outSpec] of Object.entries(spec.outputs)) {\n if (outSpec.shape !== 'array') continue\n if (helpers === null) {\n helpers = await import('./derivations/fanout-sidecar.js')\n }\n const sidecar = await helpers.loadFanoutSidecar(\n this.adapter,\n this.vault,\n spec.source,\n id,\n outputKey,\n )\n if (!sidecar) continue\n const outputCollection = this.derivationSource.getCollection(outSpec.collection)\n for (const derivedId of sidecar.keys) {\n await outputCollection._internalDelete(derivedId, txCtx)\n }\n await helpers.deleteFanoutSidecar(this.adapter, this.vault, spec.source, id, outputKey)\n }\n }\n }\n\n /**\n * Mirror of {@link dispatchMaterializedViews} for the delete path\n * (#181). No record content is available (it's gone), so the\n * `_materializedFrom` skip used by the put-side dispatch doesn't\n * apply here — instead, the recursion guard is the `internal` gate\n * at the `_doDelete` call site above.\n *\n * @internal\n */\n private async dispatchMaterializedViewsOnDelete(id: string): Promise<void> {\n void id\n if (this.materializedViewSource === undefined) return\n const registry = this.materializedViewSource.registry()\n const mvs = registry.mvsForSource(this.name)\n if (mvs.length === 0) return\n let executor: typeof MVExecutorType | null = null\n let staleHelpers: typeof MVStaleModule | null = null\n for (const reg of mvs) {\n const mode = reg.spec.refresh\n if (mode === 'eager') {\n if (executor === null) {\n ;({ MaterializedViewExecutor: executor } = await import('./materialized-views/executor.js'))\n }\n await executor.refresh(reg, {\n getCollection: (name) => this.materializedViewSource!.getCollection(name),\n getActiveTxContext: () => this.materializedViewSource!.getActiveTxContext(),\n getQueryContext: () => this.materializedViewSource!.getQueryContext(),\n })\n } else if (mode === 'lazy') {\n if (staleHelpers === null) {\n staleHelpers = await import('./materialized-views/stale.js')\n }\n staleHelpers.markMVStale(registry, reg.spec.name)\n }\n // manual: no-op — `vault.refreshView(name)` is the only path.\n }\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 // Lazy-MV resolve-on-read (#157 review): if this collection is the\n // output of a registered lazy MV with a pending stale flag, run\n // the executor before returning so callers see fresh data. No-op\n // when nothing is pending — keeps the read path negligible.\n if (this.materializedViewSource !== undefined) {\n const { resolveStaleMVOnRead } = await import('./materialized-views/stale.js')\n await resolveStaleMVOnRead(this.materializedViewSource, this.name)\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 //\n // #133 — when a derivation registry is wired, publish a transient\n // TxContext for the duration of this loop so `dispatchDerivations`\n // can register recursive derived-output writes onto `ctx._executed`.\n // The shared `revertExecuted` helper then unwinds the combined list\n // (source ops + side-effect ops) in reverse, matching the\n // `runTransaction` rollback semantics. When no derivation registry\n // is configured, we still build a local `executed` list and revert\n // it via `revertExecuted` — keeps a single code path.\n const txCtx = this.derivationSource?.createTxContext() ?? null\n if (txCtx !== null && this.derivationSource) {\n this.derivationSource.setActiveTxContext(txCtx)\n }\n const localExecuted: ExecutedOp[] = []\n try {\n for (const [id, record] of entries) {\n // Record the revert plan BEFORE the call so a mid-`put` throw\n // (e.g. strict derivation failure firing after `store.put`\n // already committed the source envelope) still has the source\n // write reverted. Mirrors `runTransaction`'s Phase 2 pattern.\n const entry: ExecutedOp = {\n op: { type: 'put', vaultName: this.vault, collectionName: this.name, id },\n priorEnvelope: priors.get(id) ?? null,\n }\n if (txCtx !== null) txCtx._executed.push(entry)\n else localExecuted.push(entry)\n await this.put(id, record)\n }\n return { ok: true, success: entries.map(([id]) => id), failures: [] }\n } catch (err) {\n const executedForRevert = txCtx !== null ? txCtx._executed : localExecuted\n // Restore prior envelopes via the raw store. Same helper as\n // `runTransaction` for symmetric semantics — walks in reverse,\n // best-effort on each restore.\n await revertExecuted(executedForRevert, this.adapter)\n // Cache desync guard. `revertExecuted` only invalidates caches\n // when given a `Noydb` reference (which we don't have here\n // without widening the constructor surface). Walk the executed\n // ops and invalidate caches via the source collection (this)\n // for entries that target this collection, and via\n // `derivationSource.getCollection(name)` for nested derived\n // outputs that live in sibling collections — otherwise an eager\n // cache on a derived-output collection still serves the\n // rolled-back record.\n for (const { op } of [...executedForRevert].reverse()) {\n if (op.vaultName !== this.vault) continue\n try {\n if (op.collectionName === this.name) {\n await this._invalidateCacheEntry(op.id)\n } else if (this.derivationSource) {\n const sibling = this.derivationSource.getCollection(op.collectionName)\n await sibling._invalidateCacheEntry(op.id)\n }\n } catch { /* best-effort */ }\n }\n throw err\n } finally {\n if (txCtx !== null && this.derivationSource) {\n this.derivationSource.clearActiveTxContext(txCtx)\n }\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 * **Lazy-MV gap (#157):** `query()` is synchronous and does NOT\n * trigger lazy materialized-view resolve-on-read. If this\n * collection is a lazy MV's output and the MV is currently stale,\n * `query().toArray()` returns the pre-stale snapshot. To force a\n * fresh read on a lazy MV, either call `list()` (which DOES\n * trigger resolve) or `vault.refreshView(mvName)` before querying.\n * The proper fix — extending `QuerySource` with an async prepare\n * hook — is a separate PR.\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 * **Lazy-MV gap (#157):** `scan()` is synchronous-build and does\n * NOT trigger lazy materialized-view resolve-on-read. For lazy\n * MVs, call `list()` (which DOES resolve) or `vault.refreshView(name)`\n * before scanning. Same shape as the `query()` limitation.\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 /**\n * @internal — refresh the in-memory cache entry for a single id by\n * re-reading from the adapter. Used by the transaction executor's\n * Phase-3 revert path: that path writes the prior envelope directly\n * via the raw store (to avoid re-firing Collection-level side\n * effects), which would otherwise leave this Collection's eager\n * cache holding the rolled-back value. After revert, the executor\n * calls this hook so subsequent `get` / `query` reads see the\n * actual on-disk state.\n *\n * Lazy mode: drops the LRU entry; the next `get` repopulates from\n * the adapter. Eager mode: re-reads the envelope and either sets\n * the cache entry (record still present) or deletes it (record was\n * gone before the tx and the revert deleted it again).\n */\n async _invalidateCacheEntry(id: string): Promise<void> {\n if (this.lazy && this.lru) {\n this.lru.remove(id)\n return\n }\n if (!this.hydrated) return\n const previous = this.cache.get(id)\n const envelope = await this.adapter.get(this.vault, this.name, id)\n if (!envelope) {\n this.cache.delete(id)\n if (previous) this.indexes?.remove(id, previous.record)\n return\n }\n const record = await this.decryptRecord(envelope)\n this.cache.set(id, { record, version: envelope._v })\n this.indexes?.upsert(id, record, previous ? previous.record : null)\n }\n\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 * 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 * Public `vault.user.*` API surface.\n *\n * Three families:\n * - Write-self: `me` / `updateMe` / `setMe` — always target the writer's\n * own keyringId. **Own-only write rule** is structural — no method\n * exists to write someone else's envelope.\n * - Read-anyone: `get` / `list` — read other principals' envelopes\n * (subject to `view-team-profiles` policy gate, wired in #22).\n * - Reactive: `subscribe` / `live` — in-process event emission on local\n * writes. Cross-instance updates land via the team/sync engine and\n * surface to subscribers when the sync diff replays through this API.\n *\n * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md\n *\n * @module\n */\nimport type { NoydbStore } from '../../types.js'\nimport { PolicyDeniedError } from '../../policy/errors.js'\nimport type { FactorProof } from '../../policy/types.js'\nimport {\n loadUserEnvelope,\n saveUserEnvelope,\n listUserEnvelopeIds,\n} from './storage.js'\nimport type { UserEnvelope } from './types.js'\nimport {\n persistUserVisibility,\n readUserVisibility,\n} from '../../directory/visibility.js'\nimport type { UserVisibility } from '../../directory/types.js'\n\n/**\n * Recursive partial. Used for `updateMe(patch)` so callers can hand in\n * deeply-nested partial shapes and have them deep-merged onto the\n * current envelope.\n */\nexport type DeepPartial<T> = T extends object\n ? { [P in keyof T]?: DeepPartial<T[P]> }\n : T\n\n/**\n * Recursive partial with `null` allowed at every level — used by\n * `updateMe` (#57) to express deletion intent in addition to merge.\n *\n * Semantics inside `updateMe`:\n * - `undefined` (or absent key) — skip; source value preserved\n * - `null` — delete the key from the resulting envelope\n * - any other value — overwrite (deep-merge for plain objects,\n * replace for primitives / arrays)\n *\n * Matches lodash `_.merge` behavior on `null` and Firestore's\n * `FieldValue.delete()` semantics. Loosened from `DeepPartial<T>` per\n * #57; consumers wanting the original \"merge-only\" surface can keep\n * importing `DeepPartial` and avoid passing `null`.\n */\nexport type DeepPartialOrNull<T> = T extends object\n ? { [P in keyof T]?: DeepPartialOrNull<T[P]> | null }\n : T\n\n/** Cancel a previously-registered subscription. */\nexport type Unsubscribe = () => void\n\n/**\n * Optional factor-proof bundle threaded into gated user-envelope\n * operations. Same shape as `Noydb.checkGate(vault, gate, presented)`\n * accepts elsewhere — apps that have already presented a TOTP/email-OTP\n * for this session pass it here to satisfy tightened policies.\n */\nexport interface UserEnvelopePresented {\n readonly factors?: readonly FactorProof[]\n readonly sharedDevice?: boolean\n}\n\n/**\n * Callback used by `UserApi` to validate the active session against a\n * policy gate. Provided by the `Vault` constructor; in production this\n * delegates to `Noydb.checkGate(vault, gate, presented)`. In tests, a\n * no-op stub is fine.\n */\nexport type UserEnvelopeCheckGate = (\n gate: 'edit-own-profile' | 'view-team-profiles',\n presented?: UserEnvelopePresented,\n) => Promise<void>\n\n/**\n * Reactive handle returned by `live()`. `current` is the most recently\n * observed value; `subscribe(cb)` fires on subsequent local writes.\n * `stop()` releases the underlying subscription.\n */\nexport interface LiveUserEnvelope<T> {\n current(): UserEnvelope<T> | null\n subscribe(cb: (env: UserEnvelope<T> | null) => void): Unsubscribe\n stop(): void\n}\n\ninterface ChangeListener<T = unknown> {\n (env: UserEnvelope<T> | null): void\n}\n\n/**\n * Implementation behind `vault.user`. Constructed once per Vault, holds\n * the writer's keyringId in closure so `updateMe`/`setMe` cannot target\n * any other principal — the own-only rule is enforced at the type level\n * (no `set(otherKeyringId, …)` method) AND at runtime (the\n * keyringId argument simply doesn't exist on the write path).\n */\nexport class UserApi {\n /** keyringId → set of listeners. Wildcard '*' fires on every change. */\n private readonly listeners = new Map<string, Set<ChangeListener>>()\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly vaultName: string,\n /** The writer's own keyringId. Frozen at construction time. */\n private readonly writerKeyringId: string,\n private readonly getDek: () => Promise<CryptoKey>,\n /**\n * Policy-gate validator. When omitted, gates are skipped — useful\n * for low-level tests that exercise the storage layer directly.\n * Production paths always wire the Noydb-backed implementation.\n */\n private readonly checkGate?: UserEnvelopeCheckGate,\n ) {}\n\n // ─── Write-self ──────────────────────────────────────────────────────\n\n /** Read the writer's own envelope. Returns null if never written. */\n async me<T = unknown>(): Promise<UserEnvelope<T> | null> {\n const dek = await this.getDek()\n return loadUserEnvelope<T>(this.adapter, this.vaultName, this.writerKeyringId, dek)\n }\n\n /**\n * Deep-merge a partial patch into the writer's own envelope. Creates\n * the envelope on first call. Optimistic-concurrency safe — a stale\n * `_v` (parallel writer on another device) throws `ConflictError`.\n *\n * Patch semantics (#57):\n * - `undefined` (or omitted key) — skip; existing value preserved\n * - `null` — delete the field from the merged result\n * - any other value — overwrite (deep-merge for plain objects,\n * replace for primitives / arrays)\n *\n * To clear a field, pass `null` rather than `undefined`. Callers\n * with shape `T = string | null` where `null` is a meaningful value\n * should use `setMe` for that specific field instead — `null` here\n * always means delete.\n *\n * Gated by the `edit-own-profile` policy gate (default `minTier: 3`).\n * Pass `presented` to satisfy tightened policies that require a\n * factor proof (e.g. STRICT_POLICY's TOTP requirement).\n */\n async updateMe<T extends object = Record<string, unknown>>(\n patch: DeepPartialOrNull<T>,\n presented?: UserEnvelopePresented,\n ): Promise<UserEnvelope<T>> {\n if (this.checkGate) await this.checkGate('edit-own-profile', presented)\n const dek = await this.getDek()\n const current = await loadUserEnvelope<T>(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n dek,\n )\n const merged: T = current ? deepMerge(current.data, patch) : (patch as unknown as T)\n const written = await saveUserEnvelope<T>(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n merged,\n dek,\n current?._v ?? 0,\n )\n this.fireChange(this.writerKeyringId, written)\n return written\n }\n\n /**\n * Replace the writer's own envelope with `payload`. Use sparingly —\n * `updateMe` is the canonical mutation. No `expectedVersion` check;\n * callers explicitly take last-write-wins semantics.\n *\n * Gated by `edit-own-profile`. See `updateMe` for `presented` usage.\n */\n async setMe<T = unknown>(\n payload: T,\n presented?: UserEnvelopePresented,\n ): Promise<UserEnvelope<T>> {\n if (this.checkGate) await this.checkGate('edit-own-profile', presented)\n const dek = await this.getDek()\n const written = await saveUserEnvelope<T>(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n payload,\n dek,\n )\n this.fireChange(this.writerKeyringId, written)\n return written\n }\n\n // ─── Visibility (#122) ───────────────────────────────────────────────\n\n /**\n * Read the current user's visibility flag from\n * `_meta/visibility/<keyringId>`. Returns `{ hidden: false }` when no\n * document has been persisted (the default-visible case).\n */\n async getMyVisibility(): Promise<UserVisibility> {\n const persisted = await readUserVisibility(this.adapter, this.vaultName, this.writerKeyringId)\n return persisted ?? { hidden: false }\n }\n\n /**\n * Update the current user's visibility in the team directory.\n *\n * - `hidden: true` — opt out of the default `listUsersWithEnvelopes`\n * listing. `owner`/`admin` callers can still see the user by passing\n * `{ includeHidden: true }`.\n * - `hidden: false` — opt back in.\n *\n * Own-only by construction: the keyringId argument doesn't exist on\n * this method, so no caller can hide or unhide another principal.\n *\n * Honest caveat: this is a UX flag, not a privacy guarantee. The\n * envelope ciphertext at `_users/<keyringId>` and the keyring file at\n * `_keyring/<userId>` are both still observable to anyone with direct\n * store read access. See `docs/subsystems/user-envelope.md` →\n * \"Directory visibility\".\n */\n async setMyVisibility(visibility: UserVisibility): Promise<void> {\n await persistUserVisibility(\n this.adapter,\n this.vaultName,\n this.writerKeyringId,\n { hidden: visibility.hidden },\n )\n }\n\n // ─── Read-anyone ─────────────────────────────────────────────────────\n\n /**\n * Read another principal's envelope by their keyringId. Returns null\n * if the principal exists but has no envelope yet, or if the\n * keyringId does not exist at all.\n *\n * Gated by `view-team-profiles` (default `minTier: 2`) — but ONLY for\n * cross-principal reads. Reading your own envelope (`keyringId ===\n * self`) is never gated; that's just `me()` written long-form.\n */\n async get<T = unknown>(\n keyringId: string,\n presented?: UserEnvelopePresented,\n ): Promise<UserEnvelope<T> | null> {\n if (this.checkGate && keyringId !== this.writerKeyringId) {\n await this.checkGate('view-team-profiles', presented)\n }\n const dek = await this.getDek()\n return loadUserEnvelope<T>(this.adapter, this.vaultName, keyringId, dek)\n }\n\n /**\n * Read every persisted envelope in the vault. Order is store-defined.\n *\n * Gated by `view-team-profiles`. Default policy (`minTier: 2`) lets\n * any authenticated session read all envelopes. Two privacy-strict\n * opt-outs:\n *\n * - `view-team-profiles.enabled: false` → list() returns only the\n * caller's own envelope (silent self-fallback, no thrown error).\n * - `view-team-profiles.minTier: 1` + insufficient tier → throws\n * `PolicyDeniedError` with `reason: 'insufficient-tier'`. The\n * caller is expected to elevate, not silently degrade.\n *\n * The asymmetry is deliberate: `enabled: false` is a deliberate\n * design choice (\"nobody sees teammate profiles in this app\");\n * `insufficient-tier` is \"you need to authenticate further\". Different\n * UX prompts for different intents.\n */\n async list<T = unknown>(presented?: UserEnvelopePresented): Promise<UserEnvelope<T>[]> {\n if (this.checkGate) {\n try {\n await this.checkGate('view-team-profiles', presented)\n } catch (err) {\n if (err instanceof PolicyDeniedError && err.reason === 'disabled') {\n // Privacy-strict opt-out: quietly return only self.\n const me = await this.me<T>()\n return me ? [me] : []\n }\n throw err\n }\n }\n const dek = await this.getDek()\n const ids = await listUserEnvelopeIds(this.adapter, this.vaultName)\n const envelopes = await Promise.all(\n ids.map((id) => loadUserEnvelope<T>(this.adapter, this.vaultName, id, dek)),\n )\n return envelopes.filter((e): e is UserEnvelope<T> => e !== null)\n }\n\n // ─── Reactive ────────────────────────────────────────────────────────\n\n /**\n * Listen for changes to a specific keyringId's envelope. The callback\n * fires synchronously after every successful local `updateMe` /\n * `setMe` for that principal.\n *\n * Cross-instance changes (a teammate edits their profile on their\n * device, the sync engine pulls the diff onto this device) will fire\n * subscribers when the sync layer replays the write through this API.\n * In v1, subscribers do NOT fire on raw store changes — wire your sync\n * layer to call back through `vault.user.setMe` / `updateMe` if you\n * need that.\n *\n * Pass keyringId `'*'` to fire on every change in the vault.\n */\n subscribe<T = unknown>(\n keyringId: string,\n cb: (env: UserEnvelope<T> | null) => void,\n ): Unsubscribe {\n let listeners = this.listeners.get(keyringId)\n if (!listeners) {\n listeners = new Set()\n this.listeners.set(keyringId, listeners)\n }\n const wrapped: ChangeListener = cb as ChangeListener\n listeners.add(wrapped)\n return () => {\n listeners?.delete(wrapped)\n if (listeners && listeners.size === 0) {\n this.listeners.delete(keyringId)\n }\n }\n }\n\n /**\n * Reactive handle that caches the current value and re-reads on every\n * change for the given keyringId. Convenient for framework bindings:\n *\n * const live = vault.user.live<UserShape>(vault.userId)\n * live.subscribe(env => render(env?.data))\n *\n * Initial value is `null` until the first `current()` call materializes\n * it via `vault.user.get()`. Call `stop()` when done to release the\n * subscription.\n */\n live<T = unknown>(keyringId: string): LiveUserEnvelope<T> {\n let value: UserEnvelope<T> | null = null\n let primed = false\n const unsubscribe = this.subscribe<T>(keyringId, (env) => {\n value = env\n })\n\n return {\n current(): UserEnvelope<T> | null {\n if (!primed) {\n primed = true\n // First call: kick off a read but return synchronously. The\n // subscriber will be re-fired by the next write or the caller\n // can await `vault.user.get()` directly for an immediate read.\n }\n return value\n },\n subscribe: (cb) => this.subscribe<T>(keyringId, cb),\n stop: unsubscribe,\n }\n }\n\n // ─── Internal: change emission ───────────────────────────────────────\n\n private fireChange<T>(keyringId: string, env: UserEnvelope<T> | null): void {\n const targeted = this.listeners.get(keyringId)\n if (targeted) for (const l of targeted) l(env)\n const wildcard = this.listeners.get('*')\n if (wildcard) for (const l of wildcard) l(env)\n }\n}\n\n/**\n * Recursive plain-object deep merge with delete intent (#57).\n *\n * Patch semantics:\n * - `undefined` — skip the key; source value preserved\n * - `null` — delete the key from output (lodash `_.merge` /\n * Firestore `FieldValue.delete()` semantics)\n * - plain object — recurse (deep merge)\n * - any other value — replace (arrays are replaced, not concatenated)\n *\n * Safe against the JS quirk where an own property explicitly set to\n * `undefined` is iterated by `Object.entries`. We dispatch on the value\n * BEFORE writing, so `{ k: undefined }` triggers the skip branch rather\n * than overwriting `out[k]` with undefined.\n */\nfunction deepMerge<T>(source: T, patch: DeepPartialOrNull<T>): T {\n if (!isPlainObject(source) || !isPlainObject(patch)) {\n // Top-level non-object replace. `null` patch at the leaf level\n // would have been caught by the parent recursion's branch table;\n // at the top level it means \"set the whole envelope to null,\"\n // which the type system already prevents (T extends object).\n return patch as unknown as T\n }\n const out: Record<string, unknown> = { ...(source as Record<string, unknown>) }\n for (const [key, patchVal] of Object.entries(patch as Record<string, unknown>)) {\n if (patchVal === undefined) {\n // Skip — preserve the source value at this key. Matches the\n // pre-#57 behavior so callers who never used `null` see no diff.\n continue\n }\n if (patchVal === null) {\n // Delete intent. `delete` rather than `out[key] = undefined`\n // because JSON.stringify drops undefined fields silently and\n // we want the deletion to be visible to consumers iterating\n // the merged object (e.g. `Object.keys(merged.profile)`).\n delete out[key]\n continue\n }\n const sourceVal = (source as Record<string, unknown>)[key]\n if (isPlainObject(patchVal)) {\n // Recurse for any plain-object patch — including the \"source is\n // missing this key\" case. Without recursing through a synthetic\n // empty source, nested `null` deletions in the patch would land\n // as literal `null` values instead of triggering the delete\n // branch (e.g. `{ app: { signature: null } }` against a missing\n // `app` would emit `{ app: { signature: null } }` instead of\n // `{ app: {} }`).\n const recurseSource = isPlainObject(sourceVal) ? sourceVal : {}\n out[key] = deepMerge(recurseSource, patchVal as DeepPartialOrNull<typeof recurseSource>)\n } else {\n out[key] = patchVal\n }\n }\n return out as T\n}\n\nfunction isPlainObject(x: unknown): x is Record<string, unknown> {\n if (x === null || typeof x !== 'object') return false\n if (Array.isArray(x)) return false\n const proto = Object.getPrototypeOf(x) as object | null\n return proto === Object.prototype || proto === null\n}\n","/**\n * Deterministic JSON serializer: sorts object keys lexicographically at every\n * depth so structurally-equivalent objects produce identical strings. Array\n * order is preserved (arrays are semantically ordered).\n *\n * Used by {@link sha256Hex} to fingerprint a derived JSON Schema for\n * hash-based skip on persisted-schema writes.\n *\n * @module\n */\n\nexport function canonicalize(value: unknown): string {\n if (value === null || typeof value !== 'object') {\n return JSON.stringify(value)\n }\n if (Array.isArray(value)) {\n return '[' + value.map(canonicalize).join(',') + ']'\n }\n const obj = value as Record<string, unknown>\n const keys = Object.keys(obj).sort()\n const parts = keys.map((k) => JSON.stringify(k) + ':' + canonicalize(obj[k]))\n return '{' + parts.join(',') + '}'\n}\n","/**\n * Derive a {@link PersistedSchemaEnvelope} from a Standard Schema v1\n * validator. v0 supports Zod via `zod-to-json-schema` (optional peer-dep);\n * other families write a stub envelope flagging the kind.\n *\n * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md\n *\n * @module\n */\n\nimport { canonicalize } from './canonicalize.js'\nimport { sha256Hex } from '../crypto.js'\nimport type { PersistedSchemaEnvelope, PersistedSchemaKind } from './types.js'\n\n/**\n * Heuristic Zod detection — Zod schemas carry a `_def.typeName` property\n * starting with `Zod` (e.g. `ZodObject`, `ZodString`). This survives Zod's\n * minor-version bumps because the typeName naming is stable across v3.\n */\nexport function isZodSchema(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false\n const def = (value as { _def?: { typeName?: unknown } })._def\n if (!def || typeof def !== 'object') return false\n return typeof def.typeName === 'string' && def.typeName.startsWith('Zod')\n}\n\nfunction detectKind(validator: unknown): PersistedSchemaKind {\n if (isZodSchema(validator)) return 'Zod'\n return 'Unknown'\n}\n\n/**\n * Lazy-require `zod-to-json-schema`. Returns the converter, or throws a\n * clear error if the peer-dep isn't installed.\n */\nasync function loadZodConverter(): Promise<(s: unknown) => object> {\n try {\n const mod = (await import('zod-to-json-schema')) as { zodToJsonSchema?: (s: unknown) => object }\n if (!mod.zodToJsonSchema) {\n throw new Error('zod-to-json-schema export missing')\n }\n return mod.zodToJsonSchema\n } catch (err) {\n throw new Error(\n 'persistJsonSchema requires the optional peer-dep `zod-to-json-schema`. '\n + 'Install it: `pnpm add zod-to-json-schema` (or npm/yarn equivalent). '\n + `Original error: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\nexport async function derivePersistedSchema(\n validator: unknown,\n): Promise<PersistedSchemaEnvelope> {\n const kind = detectKind(validator)\n const derivedAt = new Date().toISOString()\n\n if (kind === 'Zod') {\n const convert = await loadZodConverter()\n const jsonSchema = convert(validator)\n const canonical = canonicalize(jsonSchema)\n const hash = await sha256Hex(new TextEncoder().encode(canonical))\n return { _noydb_schema: 1, kind, jsonSchema, hash, derivedAt }\n }\n\n return {\n _noydb_schema: 1,\n kind,\n jsonSchema: null,\n hash: null,\n reason: `derivation not yet supported for kind=${kind} (v0 supports Zod only)`,\n derivedAt,\n }\n}\n","/**\n * Orchestrate the derive → hash → skip-or-write cycle for a collection's\n * persisted JSON Schema. Called by the Vault at collection-registration\n * time when the developer opts in via `collection({ persistJsonSchema:\n * true })`.\n *\n * Skip semantics:\n *\n * - Zod validators: skip when the new hash equals the stored hash.\n * - Non-Zod (stub envelopes have hash=null): skip when the stored\n * envelope's `kind` matches the freshly-detected kind (since there's\n * no body to compare yet — a kind change is the only signal).\n *\n * @module\n */\n\nimport { derivePersistedSchema } from './derive.js'\nimport { loadPersistedSchema, savePersistedSchema } from './storage.js'\nimport type { NoydbStore } from '../types.js'\nimport type { PersistedSchemaEnvelope } from './types.js'\n\nexport interface PersistSchemaResult {\n /** True when a fresh envelope was written to storage. */\n readonly written: boolean\n /** True when an existing envelope matched and the write was skipped. */\n readonly skipped: boolean\n /** The envelope that was either written or matched. */\n readonly envelope: PersistedSchemaEnvelope\n}\n\nexport async function persistSchemaIfNeeded(opts: {\n readonly store: NoydbStore\n readonly vault: string\n readonly collectionName: string\n readonly validator: unknown\n readonly dek: CryptoKey\n}): Promise<PersistSchemaResult> {\n const fresh = await derivePersistedSchema(opts.validator)\n const stored = await loadPersistedSchema(opts.store, opts.vault, opts.collectionName, opts.dek)\n\n if (stored && isEquivalent(stored, fresh)) {\n return { written: false, skipped: true, envelope: stored }\n }\n\n await savePersistedSchema(opts.store, opts.vault, opts.collectionName, opts.dek, fresh)\n return { written: true, skipped: false, envelope: fresh }\n}\n\nfunction isEquivalent(a: PersistedSchemaEnvelope, b: PersistedSchemaEnvelope): boolean {\n if (a.kind !== b.kind) return false\n // Zod path: real hashes — compare directly.\n if (a.hash && b.hash) return a.hash === b.hash\n // Stub path: both have hash=null. Kind equality is the only signal we have.\n if (a.hash === null && b.hash === null) return true\n // Mixed (one has a hash, the other doesn't) — treat as changed.\n return false\n}\n","/**\n * Map a JSON Schema (Draft 2020-12 produced by `zod-to-json-schema`) into\n * the {@link FieldDescriptor} map consumed by {@link VaultSchemaSnapshot}.\n *\n * Used by both the persisted-schema path (decrypted envelope body) and the\n * live-validator path (in-process derivation).\n *\n * @module\n */\n\nimport type { FieldDescriptor, FieldSource } from './types.js'\n\ninterface JsonSchemaShape {\n type?: string | string[]\n properties?: Record<string, JsonSchemaShape>\n required?: string[]\n enum?: unknown[]\n minLength?: number\n maxLength?: number\n pattern?: string\n minimum?: number\n maximum?: number\n exclusiveMinimum?: number\n exclusiveMaximum?: number\n format?: string\n items?: JsonSchemaShape\n}\n\nfunction jsonSchemaType(node: JsonSchemaShape): string {\n if (Array.isArray(node.type)) {\n const non = node.type.filter((t) => t !== 'null')\n return non[0] ?? 'opaque'\n }\n if (node.enum && Array.isArray(node.enum)) return 'enum'\n if (typeof node.type === 'string') return node.type\n return 'opaque'\n}\n\nfunction constraintsFor(node: JsonSchemaShape): Record<string, unknown> | undefined {\n const out: Record<string, unknown> = {}\n if (node.enum) out.values = node.enum\n if (node.minLength !== undefined) out.minLength = node.minLength\n if (node.maxLength !== undefined) out.maxLength = node.maxLength\n if (node.pattern !== undefined) out.pattern = node.pattern\n if (node.format !== undefined) out.format = node.format\n if (node.minimum !== undefined) out.minimum = node.minimum\n if (node.maximum !== undefined) out.maximum = node.maximum\n if (node.exclusiveMinimum !== undefined) out.gt = node.exclusiveMinimum\n if (node.exclusiveMaximum !== undefined) out.lt = node.exclusiveMaximum\n return Object.keys(out).length === 0 ? undefined : out\n}\n\nexport function jsonSchemaToFields(\n jsonSchema: unknown,\n source: FieldSource,\n refs?: Record<string, { target: string; mode: string }>,\n): Record<string, FieldDescriptor> {\n if (!jsonSchema || typeof jsonSchema !== 'object') return {}\n const root = jsonSchema as JsonSchemaShape\n if (!root.properties || typeof root.properties !== 'object') return {}\n\n const required = new Set(Array.isArray(root.required) ? root.required : [])\n const out: Record<string, FieldDescriptor> = {}\n\n for (const [name, node] of Object.entries(root.properties)) {\n const descriptor: FieldDescriptor = {\n type: jsonSchemaType(node),\n source,\n ...(required.has(name) ? {} : { optional: true }),\n ...(refs?.[name] ? { references: `${refs[name].target}.id` } : {}),\n }\n const constraints = constraintsFor(node)\n if (constraints) (descriptor as { constraints?: Record<string, unknown> }).constraints = constraints\n out[name] = descriptor\n }\n\n return out\n}\n","/**\n * Orchestrate the structural walk of a Vault, producing a\n * {@link VaultSchemaSnapshot}. Called from `Vault.dumpSchema()`.\n *\n * @module\n */\n\nimport { derivePersistedSchema } from '../persisted-schemas/derive.js'\nimport { loadPersistedSchema } from '../persisted-schemas/storage.js'\nimport { jsonSchemaToFields } from './fields.js'\nimport type {\n CollectionDescriptor,\n CollectionStats,\n DumpSchemaOptions,\n FieldDescriptor,\n InternalCollectionStats,\n MaterializedViewDescriptor,\n OverlayViewDescriptor,\n DerivationDescriptor,\n VaultSchemaSnapshot,\n} from './types.js'\nimport type { Collection } from '../collection.js'\nimport type { NoydbStore } from '../types.js'\nimport type { RefRegistry } from '../refs.js'\n\n/**\n * The minimal slice of Vault internal state the walker needs.\n * Exposed via `vault._introspectState()` to keep the public Vault\n * surface narrow.\n *\n * @internal\n */\nexport interface VaultIntrospectState {\n readonly name: string\n readonly adapter: NoydbStore\n readonly collectionCache: Map<string, Collection<unknown>>\n readonly refRegistry: RefRegistry\n readonly getDEK: (collectionName: string) => Promise<CryptoKey>\n readonly subsystems: Record<string, boolean>\n // Typed loosely on purpose — these are private subsystem registries\n // accessed only for \"is anything registered\" enumeration.\n readonly mvRegistry: unknown\n readonly overlayRegistry: unknown\n readonly derivationRegistry: unknown\n}\n\nconst INTERNAL_PREFIX = '_'\n\n/** Reserved internal collections always present in any real vault. */\nconst KNOWN_INTERNAL_NAMES = ['_keyring', '_ledger', '_meta', '_schemas', '_deltas']\n\nexport async function dumpVaultSchema(\n vault: { _introspectState(): VaultIntrospectState },\n opts: DumpSchemaOptions,\n): Promise<VaultSchemaSnapshot> {\n const state = vault._introspectState()\n const sampleSize = opts.sampleSize ?? 50\n const withStats = opts.withStats === true\n\n // 1. User-facing collections — alphabetical for diff stability\n const cacheNames = [...state.collectionCache.keys()]\n const storageNames = (await safeListAllCollections(state.adapter, state.name))\n .filter((n) => !n.startsWith(INTERNAL_PREFIX))\n const allNames = Array.from(new Set([...cacheNames, ...storageNames])).sort()\n\n const collections: Record<string, CollectionDescriptor> = {}\n for (const name of allNames) {\n collections[name] = await describeCollection(state, name, sampleSize, withStats)\n }\n\n // 2. Materialized views (placeholder — real walk in MV slice 2 follow-up)\n const materializedViews = describeMVs(state.mvRegistry)\n // 3. Overlay views\n const overlayViews = describeOverlays(state.overlayRegistry)\n // 4. Derivations\n const derivations = describeDerivations(state.derivationRegistry)\n\n // 5. Internal collections — only with stats\n let internal: Record<string, InternalCollectionStats> | undefined\n if (withStats) {\n internal = {}\n for (const name of KNOWN_INTERNAL_NAMES) {\n const stats = await statsForCollection(state.adapter, state.name, name)\n if (stats.records > 0) {\n internal[name] = { records: stats.records, bytes: stats.bytes }\n }\n }\n }\n\n const snap: VaultSchemaSnapshot = {\n _noydb_snapshot: 1,\n vault: state.name,\n emittedAt: new Date().toISOString(),\n subsystems: state.subsystems,\n collections,\n materializedViews,\n overlayViews,\n derivations,\n ...(internal !== undefined ? { internal } : {}),\n }\n return snap\n}\n\nasync function safeListAllCollections(adapter: NoydbStore, vault: string): Promise<string[]> {\n try {\n const snap = await adapter.loadAll(vault)\n return Object.keys(snap)\n } catch {\n return []\n }\n}\n\nasync function describeCollection(\n state: VaultIntrospectState,\n collectionName: string,\n sampleSize: number,\n withStats: boolean,\n): Promise<CollectionDescriptor> {\n let fields: Record<string, FieldDescriptor> = {}\n let validator: CollectionDescriptor['validator']\n\n const refsRaw = state.refRegistry.getOutbound(collectionName)\n const refs: CollectionDescriptor['refs'] = {}\n for (const [name, desc] of Object.entries(refsRaw)) {\n refs[name] = { target: desc.target, mode: desc.mode }\n }\n\n // 1. Try the persisted Route B envelope first.\n try {\n const dek = await state.getDEK(collectionName)\n const persisted = await loadPersistedSchema(state.adapter, state.name, collectionName, dek)\n if (persisted) {\n validator = { kind: persisted.kind, source: 'persisted' }\n if (persisted.jsonSchema) {\n fields = jsonSchemaToFields(persisted.jsonSchema, 'persisted', refsRaw)\n }\n }\n } catch {\n // No DEK or decrypt failure — fall through to live-validator\n }\n\n // 2. Try the live in-process validator (when no persisted envelope).\n if (!validator) {\n const coll = state.collectionCache.get(collectionName)\n const schema = coll?.getSchema()\n if (schema) {\n try {\n const derived = await derivePersistedSchema(schema)\n validator = { kind: derived.kind, source: 'live-validator' }\n if (derived.jsonSchema) {\n fields = jsonSchemaToFields(derived.jsonSchema, 'live-validator', refsRaw)\n }\n } catch {\n // Derivation failed (e.g. missing peer-dep) — silently leave fields empty\n }\n }\n }\n\n // 3. Sampling fallback — deferred to a follow-up. For now: empty when no schema.\n if (Object.keys(fields).length === 0 && sampleSize > 0) {\n // Sampling path not implemented in baseline slice 2; reserved for follow-up.\n }\n\n const descriptor: CollectionDescriptor = {\n fields,\n indexes: [],\n refs,\n ...(validator ? { validator } : {}),\n }\n if (withStats) {\n const stats = await statsForCollection(state.adapter, state.name, collectionName)\n ;(descriptor as { stats?: CollectionStats }).stats = stats\n }\n return descriptor\n}\n\nasync function statsForCollection(\n adapter: NoydbStore,\n vault: string,\n collection: string,\n): Promise<CollectionStats> {\n const ids = await adapter.list(vault, collection)\n if (ids.length === 0) {\n return { records: 0, bytes: 0, bytesAvg: 0, bytesMin: 0, bytesMax: 0, oldest: '', newest: '' }\n }\n let total = 0\n let min = Number.POSITIVE_INFINITY\n let max = 0\n let oldest = ''\n let newest = ''\n for (const id of ids) {\n const env = await adapter.get(vault, collection, id)\n if (!env) continue\n const size = env._data.length\n total += size\n if (size < min) min = size\n if (size > max) max = size\n if (env._ts < oldest) oldest = env._ts\n if (env._ts > newest) newest = env._ts\n }\n return {\n records: ids.length,\n bytes: total,\n bytesAvg: Math.round(total / ids.length),\n bytesMin: min === Number.POSITIVE_INFINITY ? 0 : min,\n bytesMax: max,\n oldest: oldest === '' ? '' : oldest,\n newest,\n }\n}\n\nfunction describeMVs(registry: unknown): Record<string, MaterializedViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const items = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, MaterializedViewDescriptor> = {}\n // Each item is RegisteredMV { spec, dependencies, outputCollection, ... }\n for (const item of items) {\n const reg = item as {\n spec?: {\n name?: string\n unionSources?: ReadonlyArray<{ collection: string }>\n groupBy?: string | ReadonlyArray<string>\n aggregate?: Record<string, unknown>\n refresh?: string\n }\n dependencies?: ReadonlySet<string>\n }\n const spec = reg.spec\n if (!spec?.name) continue\n const sources = spec.unionSources\n ? spec.unionSources.map((u) => u.collection)\n : (reg.dependencies ? [...reg.dependencies].sort() : [])\n const groupBy = spec.groupBy\n ? Array.isArray(spec.groupBy) ? [...spec.groupBy] : [spec.groupBy]\n : undefined\n const aggregate = spec.aggregate ? Object.fromEntries(\n Object.entries(spec.aggregate).map(([k, v]) => [k, summariseAggregateOp(v)]),\n ) : undefined\n out[spec.name] = {\n sources,\n ...(groupBy ? { groupBy } : {}),\n ...(aggregate ? { aggregate } : {}),\n refresh: spec.refresh ?? 'eager',\n }\n }\n return out\n}\n\nfunction describeOverlays(registry: unknown): Record<string, OverlayViewDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const specs = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, OverlayViewDescriptor> = {}\n for (const spec of specs) {\n const s = spec as { name?: string; base?: string; overlay?: string }\n if (!s.name || !s.base || !s.overlay) continue\n out[s.name] = { base: s.base, overlay: s.overlay }\n }\n return out\n}\n\nfunction describeDerivations(registry: unknown): Record<string, DerivationDescriptor> {\n if (!registry || typeof registry !== 'object') return {}\n const specs = listFromRegistry(registry as Record<string, unknown>)\n const out: Record<string, DerivationDescriptor> = {}\n for (const spec of specs) {\n const s = spec as { name?: string; source?: string; outputs?: ReadonlyArray<string> }\n if (!s.name) continue\n out[s.name] = {\n source: s.source ?? '',\n outputs: s.outputs ?? [],\n }\n }\n return out\n}\n\nfunction listFromRegistry(reg: Record<string, unknown>): readonly unknown[] {\n // Registries expose different accessor methods; try the common ones.\n for (const method of ['all', 'list', 'specs', 'values']) {\n const fn = reg[method]\n if (typeof fn === 'function') {\n try {\n const out = (fn as () => unknown).call(reg)\n if (Array.isArray(out)) return out\n if (out && typeof (out as { values?: () => unknown }).values === 'function') {\n return [...(out as { values: () => Iterable<unknown> }).values()]\n }\n } catch {\n continue\n }\n }\n }\n return []\n}\n\nfunction summariseAggregateOp(value: unknown): string {\n if (value && typeof value === 'object') {\n const op = (value as { op?: string; kind?: string; field?: string }).op\n ?? (value as { kind?: string }).kind\n const field = (value as { field?: string }).field\n if (op && field) return `${op}(${field})`\n if (op) return op\n }\n return String(value)\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 type { MaterializedViewRegistry } from './materialized-views/registry.js'\nimport type { MaterializedViewStrategyHandle, MVQueryContext } from './materialized-views/types.js'\nimport type { OverlayedViewRegistry } from './overlay-views/registry.js'\nimport type { OverlayedViewStrategyHandle } from './overlay-views/types.js'\nimport { OverlayedCollection } from './overlay-views/virtual-collection.js'\nimport type { PublicEnvelope } from './meta/public-envelope/types.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 AttestationError,\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'\n// Type-only imports for the guard + derivation subsystems. The\n// runtime classes are loaded on demand via `await import(...)` inside\n// `_initGuards` / `_initDerivations` (and the read-only-facade\n// accessor below) so consumers that never register a guard or\n// derivation strategy don't pay the chunk cost. See #130 for the\n// bundle regression this seam plugs.\nimport type { GuardRegistry } from './guards/registry.js'\nimport type { GuardStrategyHandleAny } from './guards/types.js'\nimport type { ReadOnlyVaultFacade } from './guards/read-only-facade.js'\nimport type { DerivationRegistry } from './derivations/registry.js'\nimport type { DerivationStrategyHandle } from './derivations/types.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'\nimport { UserApi } from './meta/user-envelope/api.js'\nimport { persistSchemaIfNeeded } from './persisted-schemas/register.js'\nimport { SCHEMAS_COLLECTION } from './persisted-schemas/storage.js'\nimport type { AttestationFieldSchema, RevocationList } from '@noy-db/attestation'\nimport type { IssueContext } from './attestation/issue.js'\nimport type { RevokeContext } from './attestation/revoke.js'\nimport type { DumpSchemaOptions, VaultSchemaSnapshot } from './introspection/types.js'\nimport { dumpVaultSchema, type VaultIntrospectState } from './introspection/walk.js'\nimport { USER_ENVELOPE_COLLECTION } from './meta/user-envelope/types.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 /**\n * Per-vault guard registry. `null` until `_initGuards()` runs; stays\n * `null` for vaults that never register any guard strategy. The\n * runtime class is dynamic-imported on demand so consumers that\n * never use guards don't pull `GuardRegistry`/`GuardExecutor` into\n * their bundle (#130).\n */\n private guardRegistry: GuardRegistry | null = null\n /**\n * Per-vault derivation registry. Same lazy-load contract as\n * `guardRegistry` — `null` until `_initDerivations()` runs with at\n * least one strategy handle. See #130 for the bundle motivation.\n */\n private derivationRegistry: DerivationRegistry | null = null\n /**\n * Per-vault materialized-view registry (#143/#150). Same lazy-load\n * contract as `derivationRegistry` — `null` until\n * `_initMaterializedViews()` runs with at least one MV handle.\n */\n private materializedViewRegistry: MaterializedViewRegistry | null = null\n /**\n * Per-vault overlay registry (#154). Same lazy-load contract as\n * `materializedViewRegistry` — `null` until `_initOverlayedViews()`\n * runs with at least one handle.\n */\n private overlayedViewRegistry: OverlayedViewRegistry | null = null\n /**\n * Cached read-only facade handed to guard callbacks via `ctx.vault`,\n * and to derivation callbacks via `derive(source, ctx)`. Allocated\n * eagerly inside `_initGuards()` and/or `_initDerivations()` so read\n * accessors stay synchronous (callers in `tx/transaction.ts` rely on\n * that). Stays `null` for vaults with neither subsystem configured.\n */\n private readOnlyFacade: ReadOnlyVaultFacade | null = null\n private getDEK: (collectionName: string) => Promise<CryptoKey>\n\n /**\n * Per-principal user envelope API.\n *\n * - Write-self: `me()`, `updateMe(patch)`, `setMe(payload)` — always\n * target this vault session's keyringId. There is no method to write\n * another principal's envelope (own-only write rule, structural).\n * - Read-anyone: `get(keyringId)`, `list()` — read other principals'\n * envelopes, subject to the `view-team-profiles` policy gate (#22).\n * - Reactive: `subscribe(id, cb)`, `live(id)` — fire on local writes.\n *\n * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md\n */\n public readonly user: UserApi\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-collection attestation field-schema (issue side). Populated on\n * `collection({ attestation })` and read by `issueAttestation()`.\n * Indexed by collection name.\n */\n private readonly attestationRegistry = new Map<string, AttestationFieldSchema>()\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 * Background writes for persisted-schema envelopes (#schema-dump v0\n * slice 1). One promise per `collection({ persistJsonSchema: true })`\n * registration that actually fired a derive call. Fire-and-forget\n * from the collection factory; tests await\n * {@link _drainPendingSchemaWrites} before asserting on storage.\n * Production code does not need to drain — the writes are\n * idempotent fingerprints, not correctness invariants.\n */\n private _pendingSchemaWrites: Promise<void>[] = []\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 guardStrategies?: ReadonlyArray<GuardStrategyHandleAny> | 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 // Guard + derivation registries are initialised lazily via\n // `_initGuards()` / `_initDerivations()` from `Noydb.openVault()`.\n // The classes are dynamic-imported there so vaults that never\n // register a strategy don't pull the subsystem code into the\n // floor bundle. See #130. The `opts.guardStrategies` argument is\n // intentionally accepted but unused on the constructor — the sync\n // `vault()` fallback path in `noydb.ts` does NOT call `_initGuards`,\n // matching the existing behaviour for `_initDerivations`. See #132\n // for the follow-up that makes the fallback path async.\n void opts.guardStrategies\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 // User envelope API — frozen writerKeyringId, dynamic DEK resolver\n // (so a post-load() keyring refresh transparently rotates the DEK\n // through the rebuilt this.getDEK), and a checkGate callback that\n // delegates to Noydb's policy engine (#22 wires edit-own-profile +\n // view-team-profiles).\n this.user = new UserApi(\n this.adapter,\n this.name,\n this.keyring.userId,\n () => this.getDEK(USER_ENVELOPE_COLLECTION),\n (gate, presented) => this.noydb.checkGate(this.name, gate, presented),\n )\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 /**\n * Opt-in persisted JSON Schema. When `true` AND a Zod `schema` is\n * provided, hub derives a JSON Schema via `zod-to-json-schema`\n * (optional peer-dep) and writes an encrypted snapshot to\n * `_schemas/<collectionName>`. Re-runs on every open; hash-skip\n * avoids write churn when the schema is unchanged.\n *\n * Default: `false`. Non-Zod Standard Schema validators receive a\n * stub envelope flagging the kind without a JSON Schema body.\n *\n * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md\n */\n persistJsonSchema?: boolean\n /** — declare the per-field schema for document attestation (issue side). */\n attestation?: AttestationFieldSchema\n }): Collection<T> {\n // Overlay intercept (#154). When the requested collection name\n // matches a registered `withOverlayedView`, return the virtual\n // proxy that merges base + overlay on read and routes writes to\n // the overlay collection. The proxy implements the core\n // Collection<T> read/write surface (get, list, put, delete);\n // reactive APIs (live, subscribe) are out of scope for #154.\n const overlayRegistry = this.overlayedViewRegistry\n if (overlayRegistry !== null && overlayRegistry.isOverlay(collectionName)) {\n const spec = overlayRegistry.byName(collectionName)\n if (spec) {\n // Recursive call into the same method — the base + overlay\n // are real collections, so they re-enter this method without\n // hitting the overlay intercept (their names won't match).\n const base = this.collection<T>(spec.base)\n const overlay = this.collection<T>(spec.overlay)\n const baseRowKey = overlayRegistry.resolveBaseRowKey(collectionName, this.materializedViewRegistry)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return new OverlayedCollection<any>(spec, base, overlay, baseRowKey) as unknown as Collection<T>\n }\n }\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 the per-collection attestation field-schema\n if (options?.attestation !== undefined) {\n this.attestationRegistry.set(collectionName, options.attestation)\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 // Guard / derivation sources are only wired when the\n // corresponding registry has been initialised. Vaults without\n // guards/derivations skip this entirely so `Collection.put`'s\n // `if (this.guardSource)` / `if (this.derivationSource)`\n // branches no-op without ever touching the subsystem code.\n ...(this.guardRegistry !== null\n ? {\n guardSource: {\n registry: () => this.guardRegistry as GuardRegistry,\n readOnlyVault: () => this._ensureReadOnlyFacade(),\n },\n }\n : {}),\n ...(this.derivationRegistry !== null\n ? {\n derivationSource: {\n registry: () => this.derivationRegistry as DerivationRegistry,\n getCollection: (name: string) =>\n this.collection(name) as unknown as Collection<Record<string, unknown>>,\n getReadOnlyFacade: () => this._ensureReadOnlyFacade(),\n getActiveTxContext: () => this.noydb._activeTxContextOrNull,\n createTxContext: () => this.noydb._createTxContext(),\n setActiveTxContext: (ctx) => this.noydb._setActiveTxContext(ctx),\n clearActiveTxContext: (ctx) => this.noydb._clearActiveTxContext(ctx),\n },\n }\n : {}),\n ...(this.materializedViewRegistry !== null\n ? {\n materializedViewSource: {\n \n registry: () => this.materializedViewRegistry!,\n getCollection: (name: string) => this.collection(name),\n getActiveTxContext: () => this.noydb._activeTxContextOrNull,\n getQueryContext: () => this as unknown as MVQueryContext,\n },\n }\n : {}),\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 // Fire-and-forget persisted-schema write when opted in. Pushed\n // onto _pendingSchemaWrites so tests can drain before asserting;\n // production code ignores it (the writes are idempotent fingerprints).\n if (options?.persistJsonSchema === true && options.schema !== undefined) {\n const validator: unknown = options.schema\n const work = (async () => {\n try {\n const dek = await this.getDEK(collectionName)\n await persistSchemaIfNeeded({\n store: this.adapter,\n vault: this.name,\n collectionName,\n validator,\n dek,\n })\n } catch (err) {\n // Schema persistence is a fingerprint, not a correctness\n // invariant — log and continue. Production callers can\n // still detect failures via _drainPendingSchemaWrites.\n \n console.warn(\n `[noy-db] persisted-schema write failed for \"${collectionName}\": `\n + (err instanceof Error ? err.message : String(err)),\n )\n }\n })()\n this._pendingSchemaWrites.push(work)\n }\n }\n return coll as Collection<T>\n }\n\n /**\n * Await all background persisted-schema writes triggered by\n * `collection({ persistJsonSchema: true })` calls on this vault.\n * Used in tests; production code does not need to call this.\n */\n async _drainPendingSchemaWrites(): Promise<void> {\n const pending = this._pendingSchemaWrites\n this._pendingSchemaWrites = []\n await Promise.allSettled(pending)\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 async issueAttestation(collectionName: string, id: string): Promise<{ docId: string; qr: string; keyId: string; publicKeyB64: string }> {\n const fieldSchema = this.attestationRegistry.get(collectionName)\n if (!fieldSchema) {\n throw new AttestationError(`issueAttestation: collection '${collectionName}' has no attestation field-schema. Declare it via vault.collection('${collectionName}', { attestation: { fields: [...] } }).`)\n }\n const { issueAttestationCore } = await import('./attestation/issue.js')\n const out = await issueAttestationCore(this.makeIssueContext(), { collection: collectionName, id, fieldSchema })\n return { docId: out.docId, qr: out.qr, keyId: out.keyId, publicKeyB64: out.publicKeyB64 }\n }\n\n async getDocumentSigningPublicKey(): Promise<{ keyId: string; publicKeyB64: string }> {\n const { loadSigner, loadOrCreateSigner } = await import('./attestation/signer.js')\n // Reading an existing public key is open to any role that holds the\n // _attestations DEK — the public key is not secret. But MINTING the\n // signer is the firm's identity operation (same rule as issueAttestation):\n // a non-owner read must not silently create it.\n const existing = await loadSigner(this.adapter, this.name, this.getDEK)\n if (existing) return { keyId: existing.keyId, publicKeyB64: existing.publicKeyB64 }\n if (this.keyring.role !== 'owner') {\n throw new AttestationError(`getDocumentSigningPublicKey: no document-signing key exists yet; only the 'owner' may mint it. Caller is '${this.keyring.role}'. Have the owner issue an attestation (or call this) first.`)\n }\n const signer = await loadOrCreateSigner(this.adapter, this.name, this.getDEK)\n return { keyId: signer.keyId, publicKeyB64: signer.publicKeyB64 }\n }\n\n private makeIssueContext(): IssueContext {\n const adapter = this.adapter, vaultName = this.name, getDEK = this.getDEK\n return {\n store: adapter,\n vault: vaultName,\n role: this.keyring.role,\n getDEK: async () => getDEK('_attestations'),\n readRecord: async (collection: string, recId: string) => {\n const env = await adapter.get(vaultName, collection, recId)\n if (!env) return null\n const record = (await this.collection(collection).get(recId, { locale: 'raw' })) as Record<string, unknown> | null\n if (record === null) return null\n return { record, version: env._v }\n },\n }\n }\n\n async revokeAttestation(docId: string): Promise<void> {\n const { revokeDocCore } = await import('./attestation/revoke.js')\n await revokeDocCore(this.makeRevokeContext(), docId)\n }\n\n async unrevokeAttestation(docId: string): Promise<void> {\n const { unrevokeDocCore } = await import('./attestation/revoke.js')\n await unrevokeDocCore(this.makeRevokeContext(), docId)\n }\n\n async getRevokedDocIds(): Promise<string[]> {\n const { getRevokedDocIdsCore } = await import('./attestation/revoke.js')\n return getRevokedDocIdsCore(this.makeRevokeContext())\n }\n\n async publishRevocationList(): Promise<RevocationList> {\n const { publishRevocationListCore } = await import('./attestation/revoke.js')\n return publishRevocationListCore(this.makeRevokeContext())\n }\n\n private makeRevokeContext(): RevokeContext {\n const adapter = this.adapter, vaultName = this.name, getDEK = this.getDEK\n return {\n store: adapter,\n vault: vaultName,\n role: this.keyring.role,\n getDEK: async () => getDEK('_attestations'),\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 * @internal — called by `Noydb.openVault` after construction.\n * Dynamic-imports `GuardRegistry` + `ReadOnlyVaultFacade` and seeds\n * the registry with the supplied strategy handles. No-op when the\n * handles array is empty — keeps the guard subsystem out of the\n * floor bundle for consumers that don't use guards (#130).\n *\n * The read-only facade is eagerly instantiated here so the sync\n * accessor `_getReadOnlyFacade()` (called from the tx amendment\n * runner) stays synchronous.\n */\n async _initGuards(handles: ReadonlyArray<GuardStrategyHandleAny>): Promise<void> {\n if (handles.length === 0) return\n const [{ GuardRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([\n import('./guards/registry.js'),\n import('./guards/read-only-facade.js'),\n ])\n const registry = new GuardRegistry()\n for (const h of handles) registry.register(h.spec)\n this.guardRegistry = registry\n this.readOnlyFacade = new ReadOnlyVaultFacade(this)\n }\n\n /**\n * @internal — Collection.put calls into this. Returns `null` for\n * vaults that never registered any guard strategy. Callers MUST\n * gate on null (the existing `if (this.guardSource)` branches in\n * `Collection` already do this transitively).\n */\n _getGuardRegistry(): GuardRegistry | null {\n return this.guardRegistry\n }\n\n /**\n * @internal — called by `Noydb.openVault` after construction.\n * Dynamic-imports `DerivationRegistry` and registers the supplied\n * derivation strategies (async because `strategyHash` computation\n * goes through `crypto.subtle.digest`). No-op when the handles\n * array is empty — keeps the derivation subsystem out of the floor\n * bundle for consumers that don't use derivations (#130). Throws\n * `DerivationCycleError` if a cycle is detected after registration.\n */\n async _initDerivations(handles: ReadonlyArray<DerivationStrategyHandle>): Promise<void> {\n if (handles.length === 0) return\n const [{ DerivationRegistry }, { ReadOnlyVaultFacade }] = await Promise.all([\n import('./derivations/registry.js'),\n import('./guards/read-only-facade.js'),\n ])\n const registry = new DerivationRegistry()\n for (const h of handles) {\n await registry.register(h.spec)\n }\n registry.validate()\n this.derivationRegistry = registry\n // Share the facade with guards: if `_initGuards` ran first the slot\n // is already populated. Otherwise allocate so `derive(source, ctx)`\n // has a vault accessor without re-importing the class per call.\n if (this.readOnlyFacade === null) {\n this.readOnlyFacade = new ReadOnlyVaultFacade(this)\n }\n }\n\n /**\n * @internal — consumed by `Collection.put` at write-time. Returns\n * `null` for vaults that never registered any derivation strategy.\n */\n _getDerivationRegistry(): DerivationRegistry | null {\n return this.derivationRegistry\n }\n\n /**\n * @internal — called by `Noydb.openVault` after collections are\n * wired. Dynamic-imports `MaterializedViewRegistry`, registers each\n * MV spec (which invokes its `query()` once for dependency\n * analysis), then runs the unified cycle detection across the MV +\n * derivation graphs. No-op when the handles array is empty — keeps\n * the MV subsystem out of the floor bundle (mirrors v1 #130).\n * Throws `MaterializedViewCycleError` if a cycle is detected.\n */\n async _initMaterializedViews(\n \n handles: ReadonlyArray<MaterializedViewStrategyHandle>,\n ): Promise<void> {\n if (handles.length === 0) return\n const { MaterializedViewRegistry } = await import('./materialized-views/registry.js')\n const registry = new MaterializedViewRegistry()\n // Phase 1: publish the (empty) registry on `this` BEFORE\n // registering any spec. The user's `query(db)` callback runs at\n // registration time and may construct source Collections via\n // `db.collection(name)` — those Collections are cached in the\n // vault and their `materializedViewSource` is populated from\n // `this.materializedViewRegistry` AT CONSTRUCTION TIME. If we\n // assigned `this.materializedViewRegistry` only after the\n // register() loop, the source Collections would cache with an\n // unset source and never dispatch MV refreshes on later writes.\n this.materializedViewRegistry = registry\n // Pass `this` Vault as the MVQueryContext — its `collection<T>()`\n // method is what the user's `query(db)` callback consumes.\n \n const db = this as unknown as MVQueryContext\n for (const h of handles) {\n await registry.register(h.spec, db)\n }\n // Phase 2: unified cycle detection across MV + derivation graphs.\n // Runs after all `register()` calls so the analyzer has every\n // dep-set; throws `MaterializedViewCycleError` on the first cycle.\n registry.validate(this.derivationRegistry)\n }\n\n /**\n * @internal — consumed by `Collection.put` at write-time. Returns\n * `null` for vaults that never registered any MV strategy.\n */\n _getMaterializedViewRegistry(): MaterializedViewRegistry | null {\n return this.materializedViewRegistry\n }\n\n /**\n * @internal — called by `Noydb.openVault` after MVs are wired.\n * Dynamic-imports `OverlayedViewRegistry`, registers each spec,\n * validates against the MV registry for name/base/overlay collisions.\n * Throws on validation failure.\n */\n async _initOverlayedViews(\n handles: ReadonlyArray<OverlayedViewStrategyHandle>,\n ): Promise<void> {\n if (handles.length === 0) return\n const { OverlayedViewRegistry } = await import('./overlay-views/registry.js')\n const registry = new OverlayedViewRegistry()\n const mvRegistry = this.materializedViewRegistry\n // Build the predicate set for registration validation:\n // - isOverlayName: an already-registered overlay's virtual name\n // - isMVOutput: a collection name owned by an MV\n const overlayNames = new Set<string>()\n for (const h of handles) overlayNames.add(h.spec.name)\n const isMVOutput = (name: string): boolean => {\n if (!mvRegistry) return false\n for (const reg of mvRegistry.all()) {\n if (reg.outputCollection === name) return true\n }\n return false\n }\n for (const h of handles) {\n registry.register(h.spec, {\n isOverlayName: (n) => overlayNames.has(n) && n !== h.spec.name,\n isMVOutput,\n })\n }\n this.overlayedViewRegistry = registry\n }\n\n /**\n * @internal — consumed by `Vault.collection()`. Returns `null` for\n * vaults with no overlays registered.\n */\n _getOverlayedViewRegistry(): OverlayedViewRegistry | null {\n return this.overlayedViewRegistry\n }\n\n /**\n * Manual re-materialize for a single registered MV (#151). Useful\n * for `refresh: 'manual'` MVs (whose consumer drives refreshes\n * externally), for stale-bit recovery on vault re-open, and as the\n * explicit bulk-recompute escape hatch after a strategy change.\n *\n * Returns `{ written, deleted, failed }`. `deleted` is always 0 in\n * foundation + this sub-issue — tombstoning lands in #152.\n *\n * Throws if `name` is not a registered MV.\n */\n async refreshView(name: string): Promise<{ written: number; deleted: number; failed: number }> {\n const registry = this.materializedViewRegistry\n if (registry === null) {\n return { written: 0, deleted: 0, failed: 0 }\n }\n const reg = registry.byName(name)\n if (!reg) {\n throw new Error(`refreshView: no MV registered with name \"${name}\"`)\n }\n const { MaterializedViewExecutor } = await import('./materialized-views/executor.js')\n const result = await MaterializedViewExecutor.refresh(reg, {\n getCollection: (n) => this.collection(n),\n getActiveTxContext: () => this.noydb._activeTxContextOrNull,\n getQueryContext: () => this as unknown as MVQueryContext,\n })\n // Manual refresh clears any pending stale bit — the post-refresh\n // state matches the registered strategy.\n const { clearMVStale } = await import('./materialized-views/stale.js')\n clearMVStale(registry, name)\n return result\n }\n\n /**\n * Re-derive every record in the named source collection. Useful\n * after a strategy change to bring previously-derived records\n * up-to-date.\n *\n * Sequential in v1; parallelisation deferred to v2.\n */\n async deriveAll(sourceCollection: string): Promise<{ derived: number; failed: number }> {\n const registry = this._getDerivationRegistry()\n if (registry === null) return { derived: 0, failed: 0 }\n const strategies = registry.strategiesForSource(sourceCollection)\n if (strategies.length === 0) return { derived: 0, failed: 0 }\n\n const { DerivationExecutor } = await import('./derivations/executor.js')\n\n const sourceColl = this.collection<Record<string, unknown>>(sourceCollection)\n const records = await sourceColl.list()\n // `_initDerivations` populates `readOnlyFacade` — assert non-null\n // for the closure-captured ctx. Falls back to a fresh facade on the\n // sync-fallback path (Noydb.vault() without await) for the same\n // defensive reason `_ensureReadOnlyFacade` exists.\n const ctx = { vault: this.readOnlyFacade ?? new (await import('./guards/read-only-facade.js')).ReadOnlyVaultFacade(this) }\n let derived = 0\n let failed = 0\n for (const record of records) {\n if (typeof record !== 'object' || record === null) continue\n const id = (record as { id?: unknown }).id\n if (typeof id !== 'string') continue\n for (const { spec, strategyHash } of strategies) {\n const sourceWithId = { ...record, id }\n const result = await DerivationExecutor.run(spec, sourceWithId, 0, strategyHash, ctx)\n let anyFailed = false\n for (const key of Object.keys(spec.outputs)) {\n const out = result.outputs[key]\n if (!out) continue\n if (out.kind === 'failed') { anyFailed = true; continue }\n const outSpec = spec.outputs[key]\n if (!outSpec) continue\n const outputColl = this.collection(outSpec.collection)\n\n // Array-shape branch (#200) — diff against the fanout sidecar.\n if (out.kind === 'array') {\n const { loadFanoutSidecar, saveFanoutSidecar } =\n await import('./derivations/fanout-sidecar.js')\n const prior = await loadFanoutSidecar(this.adapter, this.name, spec.source, id, key)\n const prevKeys = new Set<string>(prior?.keys ?? [])\n const newKeysList = out.entries.map(e => e.key)\n const newKeysSet = new Set<string>(newKeysList)\n for (const k of prevKeys) {\n if (newKeysSet.has(k)) continue\n await outputColl._internalDelete(k)\n }\n for (const entry of out.entries) {\n await outputColl.put(entry.key, entry.value)\n }\n await saveFanoutSidecar(this.adapter, this.name, {\n source: spec.source,\n sourceId: id,\n outputKey: key,\n outputCollection: outSpec.collection,\n keys: newKeysList,\n })\n continue\n }\n\n if (out.skipped === true) {\n // #144: optional output skipped — delete any prior emission.\n // No txCtx hookup needed: `deriveAll` runs outside the\n // multi-record transaction window by design. Routed\n // through `_internalDelete` so the bulk recompute does not\n // trip user `onDelete` (#145) on the output collection.\n await outputColl._internalDelete(id)\n continue\n }\n await outputColl.put(id, out.value)\n }\n if (anyFailed) failed++\n else derived++\n }\n }\n return { derived, failed }\n }\n\n /**\n * @internal — exposed for `runTransaction({ amendment: true })` so\n * the amendment invariant runner can pass the SAME read-only vault\n * facade that the per-record `Collection.put` guard hook uses\n * (`guardSource.readOnlyVault()` above). Eagerly instantiated by\n * `_initGuards()` so this accessor stays synchronous; returns\n * `null` for vaults that never registered any guard (amendments\n * require at least one guard, so the caller should never see null).\n */\n _getReadOnlyFacade(): ReadOnlyVaultFacade | null {\n return this.readOnlyFacade\n }\n\n /**\n * Internal lazy-allocator for the read-only facade. Used by the\n * per-collection `guardSource.readOnlyVault` callback when guards\n * ARE configured but `_initGuards()` raced with the first guard\n * invocation (theoretically impossible — `Noydb.openVault` awaits\n * `_initGuards` before returning — but we keep the defensive lazy\n * path so the closure's contract stays \"always returns a facade\").\n */\n private _ensureReadOnlyFacade(): ReadOnlyVaultFacade {\n if (this.readOnlyFacade !== null) return this.readOnlyFacade\n // Synchronous fall-back: dynamic import isn't available here,\n // but `_initGuards` always sets the facade before any\n // guard-hook can fire. Reaching this branch means a Vault was\n // constructed without `_initGuards` being awaited — e.g. via\n // the sync `Noydb.vault()` fallback path. Throw with a\n // pointer rather than silently building an invalid context.\n throw new Error(\n 'Vault: guard hook fired before _initGuards() completed. ' +\n 'This typically means the vault was opened via the sync ' +\n 'fallback path (Noydb.vault(name)) without first calling ' +\n 'await db.openVault(name). See issue #132.',\n )\n }\n\n /**\n * @internal — exposed for `runTransaction({ amendment: true })`\n * to append the structured `op: 'amendment'` audit entry without\n * dragging this private accessor onto the public surface or\n * forcing the tx executor to depend on the history-strategy\n * shape directly. Returns `null` when no history strategy is\n * configured, in which case the amendment commits silently\n * (the records still write through; only the multi-record\n * audit summary is skipped).\n */\n _getLedgerOrNull(): LedgerStore | null {\n return this.getLedgerOrNull()\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 if (!this.keyring.kek) {\n throw new ValidationError(\n 'issueDelegation: keyring.kek is null — issuing a delegation requires ' +\n 'a tier-1 unlock. Re-authenticate at tier 1 (passphrase) first.',\n )\n }\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 * Emit a structured introspection snapshot of this vault — vault name,\n * subsystem opt-in matrix, collections + their fields, materialized\n * views, overlay views, derivations. With `withStats: true`, walks\n * every collection's envelopes to compute record counts, byte totals,\n * and oldest/newest timestamps.\n *\n * Consumed by the `noydb describe` CLI to produce human-readable\n * audit YAML/JSON from a `.noydb` bundle.\n *\n * Field provenance:\n * - `persisted`: read from `_schemas/<col>` envelope (Route B opt-in)\n * - `live-validator`: derived in-process from a Zod schema attached\n * to the live `Collection`\n * - `sampled`: inferred from decrypted records (deferred to a follow-up)\n * - `unknown`: no schema info available\n *\n * @see docs/superpowers/specs/2026-05-22-schema-dump-design.md\n */\n async dumpSchema(opts: DumpSchemaOptions = {}): Promise<VaultSchemaSnapshot> {\n return dumpVaultSchema(this, opts)\n }\n\n /**\n * Internal accessor for {@link dumpVaultSchema}. Exposes the structural\n * state the walker needs (collection cache, registries, ref registry,\n * adapter) without widening the public Vault surface.\n *\n * @internal\n */\n _introspectState(): VaultIntrospectState {\n return {\n name: this.name,\n adapter: this.adapter,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n collectionCache: this.collectionCache as Map<string, any>,\n refRegistry: this.refRegistry,\n getDEK: this.getDEK,\n subsystems: {\n guards: this.guardRegistry !== null,\n derivations: this.derivationRegistry !== null,\n materializedViews: this.materializedViewRegistry !== null,\n overlayViews: this.overlayedViewRegistry !== null,\n },\n mvRegistry: this.materializedViewRegistry,\n overlayRegistry: this.overlayedViewRegistry,\n derivationRegistry: this.derivationRegistry,\n }\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 * Read the owner-curated public envelope for this vault (or\n * `undefined` if none is persisted). The envelope lives in\n * `_meta/public-envelope` as plaintext — readable without any KEK\n * — so `getBundleHandle`-style callers can label a vault before\n * unlock.\n *\n * Mirrors `Noydb.getPublicEnvelope(vault, opts)` but scoped to a\n * single, already-opened `Vault` instance so the\n * bundle writer can snapshot it without holding a `Noydb` reference.\n *\n * @see docs/subsystems/public-envelope.md\n */\n async getPublicEnvelope(\n opts: { readonly locale?: string } = {},\n ): Promise<PublicEnvelope | undefined> {\n const { readPublicEnvelope } = await import('./meta/public-envelope/index.js')\n return readPublicEnvelope(this.adapter, this.name, opts)\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, SCHEMAS_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 // Amendment entries are multi-record audit entries whose\n // `collection` and `id` are empty strings — building a `\"/\"`\n // key here would mark that synthetic slot as seen and falsely\n // trip the data check on a record that never existed. Skip\n // them BEFORE the key/seen bookkeeping so they neither\n // tombstone real entries nor enter the latest map.\n if (entry.op === 'amendment' || entry.op === 'lifecycle') 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. Marking the key\n // as seen above ensures any earlier `put` of the same id is\n // also skipped (the record was subsequently deleted).\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 * Per-vault tier-3 (PIN / quick-resume) state — issue #11.\n *\n * The hub holds a `PinResumeState`-shaped record in memory, keyed by\n * vault. `enrollUnlock` populates it; `unlockViaPin` consumes it via\n * `@noy-db/on-pin`'s `resumePin`. The cached state is wiped when the\n * idle timer fires or `db.close()` is called.\n *\n * Importantly, this module does NOT depend on `@noy-db/on-pin` — the\n * caller passes the already-built state in. That keeps the hub's\n * `peerDependencies` empty for tier-3 and lets developers swap the\n * primitive (e.g. an OS biometric in place of a PIN).\n *\n * @module\n */\n\n/**\n * Opaque `PinResumeState`-compatible record. Mirrored from\n * `@noy-db/on-pin/PinResumeState`. The hub treats the contents as\n * a black box.\n */\nexport interface QuickUnlockState {\n readonly _noydb_on_pin: 1\n readonly salt: string\n readonly iv: string\n readonly wrappedKeyring: string\n readonly expiresAt: string\n readonly maxAttempts: number\n attempts: number\n}\n\n/** In-memory store for tier-3 unlock state, keyed by vault. */\nexport class QuickUnlockStore {\n private readonly states = new Map<string, QuickUnlockState>()\n private readonly timers = new Map<string, ReturnType<typeof setTimeout>>()\n\n /**\n * Register a quick-unlock state for a vault. Replaces any existing\n * state. Schedules an automatic clear when the state's `expiresAt`\n * elapses.\n */\n set(vault: string, state: QuickUnlockState): void {\n this.clearTimer(vault)\n this.states.set(vault, state)\n const ttl = new Date(state.expiresAt).getTime() - Date.now()\n if (ttl > 0) {\n const timer = setTimeout(() => this.delete(vault), ttl)\n this.timers.set(vault, timer)\n }\n }\n\n /** Read the state for a vault. Returns undefined when none is registered. */\n get(vault: string): QuickUnlockState | undefined {\n return this.states.get(vault)\n }\n\n /** Drop the state for a vault. Cancels the auto-clear timer. */\n delete(vault: string): void {\n this.clearTimer(vault)\n this.states.delete(vault)\n }\n\n /** Drop every cached state. Called on `db.close()`. */\n clear(): void {\n for (const vault of this.states.keys()) {\n this.clearTimer(vault)\n }\n this.states.clear()\n }\n\n private clearTimer(vault: string): void {\n const t = this.timers.get(vault)\n if (t) clearTimeout(t)\n this.timers.delete(vault)\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, AmendmentTxOptions } 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 options?: AmendmentTxOptions,\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 { VaultPolicy } from './types.js'\n\n/**\n * Default policy for personal vaults and SMB deployments — the gates\n * that need an off-device factor get one (TOTP / email-OTP / paper\n * recovery), the rest take a tier-1 unlock alone. Tier-3 (PIN) is the\n * floor only for `rotate-unlock` because that's the\n * \"change my PIN\" flow.\n *\n * The unspecified gates (e.g. `view-user-auth`) inherit the engine\n * default of `{ enabled: false, minTier: 1 }` — they fail closed.\n *\n * @see docs/subsystems/session-tiers.md → Built-in gates\n */\nexport const PERSONAL_POLICY: VaultPolicy = Object.freeze({\n passphrase: {\n minWords: 6,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-passphrase': {\n minTier: 1,\n // Any second factor satisfies the gate — off-device kinds (TOTP,\n // email-OTP, paper recovery, roaming WebAuthn) are the strongest;\n // platform-bound kinds (platform WebAuthn, password, PIN) are\n // accepted because requiring \"something off-device\" is overkill\n // for personal/SMB threat models. Consumers needing the off-device\n // guarantee should use STRICT_POLICY or override this gate.\n factors: [{\n anyOf: [\n 'totp', 'email-otp', 'recovery',\n 'webauthn-roaming', 'webauthn-platform',\n 'password', 'pin',\n ],\n }],\n },\n 'recover-passphrase': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery (#121): deliberate paper-sheet regeneration\n // when the user remembers their passphrase. PERSONAL matches the\n // pre-#121 low-level flow's bar — knowing the passphrase is enough.\n 'rotate-recovery': { minTier: 1 },\n 'enroll-authenticator': { minTier: 1 },\n 'remove-authenticator': { minTier: 1 },\n // update-authenticator: meta-only mutation (slot rename, label\n // changes). Symmetric with enroll/remove under PERSONAL — tier-1\n // unlock alone. The structural anti-slot-swap guard inside the\n // implementation enforces wrap-material/id/method immutability\n // regardless of this gate's settings.\n 'update-authenticator': { minTier: 1 },\n 'rotate-unlock': { minTier: 2 },\n 'enroll-user': { minTier: 1 },\n 'revoke-user': { minTier: 1 },\n // Peer-recovery is a high-trust intentional op — co-owners\n // recovering each other should not need an off-device factor in\n // the personal/SMB threat model (the partner is already vetted by\n // virtue of being a co-owner). Tier-1 unlock is the floor; the\n // STRICT preset adds a recovery/email-OTP requirement.\n 'peer-recover-user': { minTier: 1 },\n // update-user: post-grant identity mutation (role/displayName/\n // permissions). PERSONAL_POLICY treats this on par with enroll-user\n // / revoke-user — tier-1 unlock alone. The role-elevation guard\n // inside the implementation is the structural backstop that this\n // gate's settings cannot weaken.\n 'update-user': { minTier: 1 },\n 'export-bundle': { minTier: 1 },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates (#22) ────────────────────────────────────\n // edit-own-profile: tier 3 floor — any active session can edit their\n // own profile/preferences. Tightening to require a TOTP for\n // profile changes is a one-line override.\n // view-team-profiles: tier 2 floor — an authenticated session can\n // read teammates' profiles (display names, avatars, locales).\n // Setting `enabled: false` makes vault.user.list() return only\n // self (privacy-strict opt-out).\n 'edit-own-profile': { minTier: 3 },\n 'view-team-profiles': { minTier: 2 },\n },\n}) as VaultPolicy\n\n/**\n * Strict policy for regulated deployments and shared workstations —\n * raises the phrase floor to 8 words, demands two distinct factors for\n * exports, and blocks export-on-shared-device. Use as a base for\n * `policy: { ...STRICT_POLICY, gates: { ...STRICT_POLICY.gates, ... } }`\n * tweaks.\n */\nexport const STRICT_POLICY: VaultPolicy = Object.freeze({\n passphrase: {\n minWords: 8,\n minWordLength: 3,\n rejectRepeatedAdjacent: true,\n },\n gates: {\n 'rotate-passphrase': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'recovery'], count: 2 }],\n },\n 'recover-passphrase': {\n minTier: 1,\n enabled: true,\n },\n // rotate-recovery (#121): STRICT requires an off-device factor —\n // rotating recovery is an off-site-trust event; a stolen unlocked\n // laptop must not be able to silently mint a new sheet for the\n // attacker. Matches the `peer-recover-user` STRICT default.\n 'rotate-recovery': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp', 'webauthn-roaming'] }],\n },\n 'enroll-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'remove-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT update-authenticator: same factor floor as enroll/remove.\n // Even though meta changes don't touch wrap material, a malicious\n // rename could mislead the user about which device a slot\n // corresponds to (\"MacBook Touch ID\" → \"iPhone Touch ID\" on a\n // shared workstation). STRICT requires a fresh factor proof.\n 'update-authenticator': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'rotate-unlock': { minTier: 1 },\n 'enroll-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'revoke-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n // STRICT peer-recovery: the issuer must present a recovery code\n // OR a fresh off-device second factor at the moment of recovery.\n // This binds the high-trust operation to a verifiable proof\n // (recovery sheet photographed by an attacker won't suffice —\n // they'd also need tier-1 unlock first; this gate is the freshness\n // binding on top). Roaming WebAuthn (YubiKey-class hardware key)\n // accepted; platform-bound kinds (Touch ID, password, PIN)\n // intentionally excluded under STRICT because they don't survive\n // device theft — the off-device requirement is the whole point.\n 'peer-recover-user': {\n minTier: 1,\n factors: [{ anyOf: ['recovery', 'totp', 'email-otp', 'webauthn-roaming'] }],\n },\n // STRICT update-user: matches the enroll-user / revoke-user shape\n // (off-device factor required). Update-user is admin-shaped — it\n // mutates someone else's role/permissions; STRICT requires a fresh\n // off-device factor proof so the operator affirmatively re-asserts\n // identity at the moment of mutation. Platform-bound factors\n // (Touch ID / password / PIN) intentionally excluded: same logic as\n // peer-recover-user — the off-device requirement is the whole\n // point under STRICT.\n 'update-user': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'export-bundle': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n warn: { sharedDevice: 'block' },\n },\n 'export-plaintext': {\n minTier: 1,\n factors: [{ anyOf: ['totp', 'email-otp'], count: 2 }],\n warn: { sharedDevice: 'block' },\n },\n 'view-user-auth': {\n minTier: 1,\n enabled: false,\n },\n // ─── User envelope gates (#22) ────────────────────────────────────\n // STRICT: profile edits require a TOTP/email-OTP factor (typical\n // shared-workstation hardening — your name/avatar shouldn't change\n // without a fresh second-factor proof).\n 'edit-own-profile': {\n minTier: 2,\n factors: [{ anyOf: ['totp', 'email-otp'] }],\n },\n 'view-team-profiles': { minTier: 2 },\n },\n}) as VaultPolicy\n\n/**\n * Merge a developer override onto a preset. Unspecified gates inherit;\n * specified gates fully replace the preset's entry for that gate.\n *\n * Example:\n *\n * ```ts\n * mergePolicy(PERSONAL_POLICY, {\n * gates: {\n * 'app:approve-large-payment': { minTier: 2, factors: [{ anyOf: ['totp'] }] },\n * },\n * })\n * // → PERSONAL_POLICY plus the new app gate; existing gates intact.\n * ```\n */\nexport function mergePolicy(\n base: VaultPolicy,\n override?: Partial<VaultPolicy>,\n): VaultPolicy {\n if (!override) return base\n const passphrase = override.passphrase ?? base.passphrase\n return {\n ...(passphrase !== undefined ? { passphrase } : {}),\n gates: {\n ...base.gates,\n ...(override.gates ?? {}),\n },\n }\n}\n","/**\n * Policy gate engine — the {@link checkGate} entry point.\n *\n * Given a configured {@link VaultPolicy}, an active session tier, and\n * the factor proofs an actor is presenting, decide whether the gate\n * permits the action. On denial, throws {@link PolicyDeniedError} with\n * a stable {@link PolicyDenyReason} so consumers can branch in error\n * UIs.\n *\n * @see docs/subsystems/session-tiers.md → checkGate() API\n *\n * @module\n */\nimport { PolicyDeniedError, type PolicyDenyReason } from './errors.js'\nimport type {\n ActiveTier,\n FactorProof,\n GateName,\n GatePolicy,\n VaultPolicy,\n FactorRequirement,\n} from './types.js'\n\n/** Default freshness window — 5 minutes. */\nexport const DEFAULT_FRESHNESS_MS = 5 * 60 * 1000\n\n/** Caller-supplied context for one `checkGate` invocation. */\nexport interface CheckGateContext {\n /** Tier the active session currently holds. */\n readonly activeTier: ActiveTier\n /** Proofs the actor is presenting for this gate. */\n readonly factors?: ReadonlyArray<FactorProof>\n /**\n * If the host knows the actor is on a shared device, set this to\n * `true` so the engine can apply `warn.sharedDevice` rules. Defaults\n * to `false`.\n */\n readonly sharedDevice?: boolean\n /**\n * Override `now()` for tests. Defaults to `Date.now()`.\n * @internal\n */\n readonly now?: number\n}\n\n/**\n * Decide whether `gate` permits the action under `context`. Throws\n * {@link PolicyDeniedError} on denial; resolves with `void` on success.\n *\n * Lookup rules:\n * - **Built-in gates** without a configured policy fail closed\n * (`enabled: false`).\n * - **App-defined gates** (`app:*`) without a configured policy are\n * treated as no-op (allow). The developer registered the policy if\n * they wanted enforcement; absence means the gate is informational.\n */\nexport async function checkGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<void> {\n const configured = policy.gates[gate]\n if (!configured) {\n if (gate.startsWith('app:')) {\n // Custom app gate without a policy — the developer hasn't\n // registered one; engine treats it as an unenforced label.\n return\n }\n // Built-in gate without a policy — fail closed.\n throw deny(gate, 'disabled', { minTier: 1, enabled: false })\n }\n\n if (configured.enabled === false) {\n throw deny(gate, 'disabled', configured)\n }\n\n // Tier check first — cheap and a hard prerequisite.\n if (context.activeTier > configured.minTier) {\n // Higher number is a LOWER tier in this model (1 is most privileged).\n throw deny(gate, 'insufficient-tier', configured)\n }\n\n // Factor checks — every requirement entry must be satisfied.\n if (configured.factors && configured.factors.length > 0) {\n const presented = context.factors ?? []\n const now = context.now ?? Date.now()\n for (const requirement of configured.factors) {\n const matches = countMatchingFactors(presented, requirement, now)\n const need = requirement.count ?? 1\n if (matches.fresh < need) {\n if (matches.totalKindMatches < need) {\n throw deny(gate, 'missing-factor', configured)\n }\n // Some matched the kind list but not the freshness window.\n throw deny(gate, 'stale-proof', configured)\n }\n }\n }\n\n // Soft signals — only `'block'` raises here.\n if (configured.warn?.sharedDevice === 'block' && context.sharedDevice === true) {\n throw deny(gate, 'shared-device-blocked', configured)\n }\n}\n\n/**\n * Same as {@link checkGate} but returns a structured verdict instead\n * of throwing. Useful when an error UI wants to show the user\n * \"you'll need TOTP plus a recovery code to do that\" without first\n * triggering the action.\n */\nexport async function describeGate(\n policy: VaultPolicy,\n gate: GateName,\n context: CheckGateContext,\n): Promise<{ ok: true } | { ok: false; reason: PolicyDenyReason; required: GatePolicy }> {\n try {\n await checkGate(policy, gate, context)\n return { ok: true }\n } catch (err) {\n if (err instanceof PolicyDeniedError) {\n return { ok: false, reason: err.reason, required: err.required }\n }\n throw err\n }\n}\n\nfunction countMatchingFactors(\n presented: ReadonlyArray<FactorProof>,\n requirement: FactorRequirement,\n now: number,\n): { totalKindMatches: number; fresh: number } {\n const freshnessMs = requirement.freshnessMs ?? DEFAULT_FRESHNESS_MS\n let totalKindMatches = 0\n let fresh = 0\n for (const proof of presented) {\n if (!requirement.anyOf.includes(proof.kind)) continue\n totalKindMatches += 1\n const minted = proof.mintedAt ? Date.parse(proof.mintedAt) : now\n if (Number.isFinite(minted) && now - minted <= freshnessMs) {\n fresh += 1\n }\n }\n return { totalKindMatches, fresh }\n}\n\nfunction deny(gate: GateName, reason: PolicyDenyReason, required: GatePolicy): PolicyDeniedError {\n return new PolicyDeniedError(gate, reason, required)\n}\n","import type {\n NoydbOptions,\n NoydbEventMap,\n GrantOptions,\n RevokeOptions,\n UpdateUserOptions,\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, KeyringCorruptError, StoreCapabilityError, PermissionDeniedError } from './errors.js'\nimport {\n readDirectoryConfig,\n persistDirectoryConfig,\n} from './directory/storage.js'\nimport type { PassphrasePolicy } from './validation.js'\nimport {\n rotatePassphrase as keyringRotatePassphrase,\n recoverPassphrase as keyringRecoverPassphrase,\n type RotatePassphraseInput,\n type RecoverPassphraseInput,\n type RecoverPassphraseResult,\n type RotateRecoveryOptions,\n type RotateRecoveryResult,\n type EnrollRecoveryResult,\n type RecoveryEnrollmentInput,\n type RecoveryProof,\n} from './team/rotate-recover.js'\nimport {\n recoverUser as keyringRecoverUser,\n type RecoverUserOptions,\n} from './team/peer-recover.js'\nimport {\n loadPaperRecoveryEntries,\n savePaperRecoveryEntries,\n hasRecoveryEnrolled,\n hasStrongRecoveryEnrolled,\n mintPaperRecoveryEntry,\n type PaperRecoveryEntry,\n loadShamirRecoveryEntries,\n saveShamirRecoveryEntries,\n mintShamirRecoveryEntry,\n type ShamirRecoveryEntry,\n} from './team/recovery.js'\nimport { resolveManagedSecret, saveSealedPassphrase } from './team/managed-passphrase.js'\nimport type { ShamirRecoveryProvider } from './team/shamir-recovery-provider.js'\nimport { generateULID } from './bundle/ulid.js'\nimport { RecoveryNotEnrolledError, RecoveryProfileNotImplementedError, ManagedRecoveryNotEnrolledError, PolicyDeniedError } from './policy/errors.js'\nimport {\n describeAuthConfig as fnDescribeAuthConfig,\n diagramAuthConfig as fnDiagramAuthConfig,\n describeUserAuth as fnDescribeUserAuth,\n describeAllUsersAuth as fnDescribeAllUsersAuth,\n} from './auth-introspection/index.js'\nimport {\n loadPublicEnvelope,\n savePublicEnvelope,\n readPublicEnvelope as fnReadPublicEnvelope,\n resolveSchema as resolvePublicEnvelopeSchema,\n validatePublicEnvelopeInput,\n type PublicEnvelope,\n type SetPublicEnvelopeInput,\n type ResolvedPublicEnvelopeSchema,\n} from './meta/public-envelope/index.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 updateKeyringIdentity,\n} from './team/keyring.js'\nimport type { UnlockedKeyring } from './team/keyring.js'\nimport {\n enrollAuthenticator as keyringEnrollAuthenticator,\n removeAuthenticator as keyringRemoveAuthenticator,\n updateAuthenticator as keyringUpdateAuthenticator,\n findAuthenticator,\n type EnrollAuthenticatorOptions,\n type UpdateAuthenticatorOptions,\n} from './team/authenticators.js'\nimport { QuickUnlockStore, type QuickUnlockState } from './session/unlock-state.js'\nimport type { KeyringAuthenticator } from './types.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 { AmendmentTxOptions } from './tx/transaction.js'\nimport { 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'\nimport {\n checkGate as policyCheckGate,\n loadVaultPolicy,\n saveVaultPolicy,\n PERSONAL_POLICY,\n mergePolicy,\n type ActiveTier,\n type FactorProofBundle,\n type GateName,\n type VaultPolicy,\n} from './policy/index.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,\n salt: new Uint8Array(0),\n authenticators: [],\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 /**\n * Per-vault active session tier — defaults to `1` after a passphrase\n * unlock; tier-2 / tier-3 unlocks (issue #11) downgrade it. Used by\n * {@link checkGate} to evaluate `gate.minTier`.\n */\n private readonly activeTier = new Map<string, ActiveTier>()\n /**\n * Per-vault loaded policy. Cached after the first\n * `_meta/policy` load; replaced by `db.updatePolicy()`.\n */\n private readonly policyCache = new Map<string, VaultPolicy>()\n /**\n * One-shot bypass for the managed-mode strong-recovery check (#195).\n * Set true by {@link openVaultAndEnrollRecovery} for the duration of\n * the bootstrap window so the keyring can be created before the\n * strong recovery is enrolled. Always cleared (try/finally).\n * @internal\n */\n private _skipNextManagedRecoveryCheck = false\n /** Per-vault tier-3 (PIN / quick-resume) state — issue #11. */\n private readonly quickUnlock = new QuickUnlockStore()\n /**\n * Resolved public-envelope schema. Lazily computed once from\n * `NoydbOptions.publicEnvelope`; `undefined` when the developer\n * didn't opt in.\n */\n private readonly publicEnvelopeSchema: ResolvedPublicEnvelopeSchema | undefined\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 * Currently-running multi-record transaction, set by\n * `runTransaction` at the start of Phase 2 (commit) and cleared in\n * the same function's `finally` block. Side-effect writes triggered\n * during a staged op's `Collection.put` (today: eager derivation\n * outputs) register their pre-write envelope on `_executed` here so\n * a mid-batch failure rolls them back alongside the main staged ops\n * (#133). `null` outside of Phase 2.\n * @internal\n */\n private _activeTxContext: TxContext | null = null\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 this.publicEnvelopeSchema = resolvePublicEnvelopeSchema(options.publicEnvelope)\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.getKeyringInternal(name)\n // Tier-1 unlock — passphrase / getKeyring callbacks both yield the\n // most-privileged tier. Tier-2 / tier-3 unlocks (issue #11) install\n // a lower tier here when they land.\n if (!this.activeTier.has(name)) {\n this.activeTier.set(name, 1)\n }\n // Load + persist the policy document. First call: persist the\n // developer-supplied policy (or default preset). Later calls: read\n // whatever's on disk and merge any developer override on top.\n if (this.options.encrypt !== false && !this.policyCache.has(name)) {\n await this.bootstrapPolicy(name)\n }\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 ...(this.options.guardStrategies !== undefined ? { guardStrategies: this.options.guardStrategies } : {}),\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 // Initialise the optional guard + derivation registries via\n // dynamic-import. Both calls are no-ops when the corresponding\n // strategies array is empty / unset, leaving the subsystem code\n // out of the floor bundle for consumers that don't use it (#130).\n await comp._initGuards(this.options.guardStrategies ?? [])\n await comp._initDerivations(this.options.derivationStrategies ?? [])\n await comp._initMaterializedViews(this.options.materializedViewStrategies ?? [])\n await comp._initOverlayedViews(this.options.overlayedViewStrategies ?? [])\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 ...(this.options.guardStrategies !== undefined ? { guardStrategies: this.options.guardStrategies } : {}),\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 ...(this.options.guardStrategies !== undefined ? { guardStrategies: this.options.guardStrategies } : {}),\n emitter: this.emitter,\n })\n this.vaultCache.set(name, comp)\n return comp\n }\n\n /**\n * Grant access to a user for a vault.\n *\n * Gated by `enroll-user`. `STRICT_POLICY` requires a TOTP / email-OTP\n * factor proof so the operator affirmatively re-asserts identity at\n * the moment of grant; `PERSONAL_POLICY` accepts a tier-1 unlock alone.\n *\n * The legacy `requireReAuthFor: ['grant']` session-policy check still\n * fires on top — both are independent opt-ins.\n */\n async grant(\n vault: string,\n options: GrantOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n this.checkPolicyOperation(vault, 'grant')\n await this.checkGate(vault, 'enroll-user', factors)\n const keyring = await this.getKeyringInternal(vault)\n await keyringGrant(this.options.store, vault, keyring, options)\n }\n\n /**\n * Revoke a user's access to a vault.\n *\n * Gated by `revoke-user`. `STRICT_POLICY` requires a TOTP / email-OTP\n * factor proof; `PERSONAL_POLICY` accepts a tier-1 unlock alone.\n *\n * The legacy `requireReAuthFor: ['revoke']` session-policy check still\n * fires on top — both are independent opt-ins.\n */\n async revoke(\n vault: string,\n options: RevokeOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n this.checkPolicyOperation(vault, 'revoke')\n await this.checkGate(vault, 'revoke-user', factors)\n const keyring = await this.getKeyringInternal(vault)\n await keyringRevoke(this.options.store, vault, keyring, options)\n }\n\n /**\n * Mutate post-grant identity fields on an existing keyring — `role`,\n * `displayName`, and/or `permissions`. Pure plaintext-header rewrite:\n * no DEK rewrap, no KEK required, no authenticator slots touched.\n * Tier-2 enrollments and recovery codes survive.\n *\n * Different from `db.revoke + db.grant`:\n *\n * - Same `userId`, same DEK wrappings, same `granted_by`, same\n * `_users/<keyringId>` envelope. Only the specified header\n * fields move. Last-write-wins via the standard keyring put.\n * - No cascade on role demotion (admins demoted to operator keep\n * the keyrings they previously granted; the cascade rules are\n * a `db.revoke` concern, not `db.updateUser`).\n * - Tier-2 slots NOT dropped — the wrapping is unaffected.\n *\n * Role-elevation guard: BOTH the old and new role must satisfy\n * `db.grant`'s hierarchy. Owner can do anything; admin manages\n * admin/operator/viewer/client laterally; admin cannot promote to\n * owner OR demote from owner. The guard runs regardless of the\n * `update-user` policy gate's settings — gates can only be more\n * permissive than the structural floor, never less.\n *\n * Gated by `update-user`. `STRICT_POLICY` requires a TOTP/email-OTP\n * factor proof so the operator affirmatively re-asserts identity at\n * the moment of mutation; `PERSONAL_POLICY` accepts a tier-1 unlock\n * alone.\n *\n * ```ts\n * await db.updateUser('acme', {\n * userId: 'bob',\n * role: 'operator', // promote\n * permissions: { invoices: 'rw' },\n * }, { factors: [{ kind: 'totp' }] })\n * ```\n *\n * @throws `NoAccessError` when no keyring exists for the target.\n * @throws `PermissionDeniedError` when the role hierarchy rejects.\n * @throws `ValidationError` when no field is provided.\n *\n * @see #54\n */\n async updateUser(\n vault: string,\n options: UpdateUserOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'update-user', factors)\n const keyring = await this.getKeyringInternal(vault)\n await updateKeyringIdentity(this.options.store, vault, keyring, options)\n // If the caller updated their own role / permissions, the cached\n // unlocked keyring is stale — drop it so the next access reloads\n // with the new header fields. (DEKs unchanged, so the cached\n // unlock still works; only the role-gated checks would diverge.)\n if (options.userId === this.options.user) {\n this.keyringCache.delete(vault)\n }\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.getKeyringInternal(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 (\n err instanceof NoAccessError ||\n err instanceof InvalidKeyError ||\n err instanceof KeyringCorruptError\n ) {\n // No accessible key material for this vault. KeyringCorruptError\n // is included so a single partially-corrupted vault does NOT\n // poison the enumeration of every other healthy vault — the\n // caller can probe a corrupted vault directly via openVault()\n // / loadKeyring() if they want to act on it.\n continue\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 /**\n * Change the current user's passphrase for a vault.\n *\n * Validates the new passphrase against the strength rules. Pass\n * `{ allowWeakPassphrase: true }` to skip — typically only useful for\n * fixtures and migrations. Pass a `PassphrasePolicy` to override the\n * default rules (e.g. consumer-tunable `pattern` / `customValidator`).\n */\n async changeSecret(\n vault: string,\n newPassphrase: string,\n options?: PassphrasePolicy & { allowWeakPassphrase?: boolean },\n ): Promise<void> {\n this.checkPolicyOperation(vault, 'changeSecret')\n const keyring = await this.getKeyringInternal(vault)\n const updated = await keyringChangeSecret(\n this.options.store,\n vault,\n keyring,\n newPassphrase,\n options,\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 * Open an amendment-mode transaction. Requires `admin` or `owner`\n * role on every vault touched by the body; throws\n * `AmendmentForbiddenError` on first non-privileged `tx.vault(name)`\n * call. Guard `check` callbacks are SKIPPED inside an amendment —\n * the staged change-set is fed to each guard's `amendment.invariant`\n * after the body returns, and the multi-record summary is appended\n * to the vault's ledger as `op: 'amendment'`.\n */\n transaction<T>(\n options: AmendmentTxOptions,\n fn: (tx: TxContext) => Promise<T> | T,\n ): 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 | AmendmentTxOptions | ((tx: TxContext) => Promise<T> | T),\n maybeFn?: (tx: TxContext) => Promise<T> | T,\n ): SyncTransaction | Promise<T> {\n if (typeof arg === 'function') {\n return this.txStrategy.runTransaction(this, arg)\n }\n if (typeof arg === 'object' && arg !== null && arg.amendment === true) {\n // Two-arg amendment form. We forward `arg` as the options bag —\n // the executor handles reason validation + per-vault role check.\n if (typeof maybeFn !== 'function') {\n throw new ValidationError(\n 'db.transaction({ amendment: true }, fn) requires the callback as the second argument.',\n )\n }\n return this.txStrategy.runTransaction(this, maybeFn, arg)\n }\n const vault = arg as string\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 /**\n * Currently-running multi-record transaction, or `null` outside\n * Phase 2. `Collection.dispatchDerivations` consults this so a\n * recursive derived-output write inside `Collection.put` can register\n * its envelope onto `ctx._executed` and roll back with the main\n * staged ops on mid-batch failure (#133).\n *\n * @internal\n */\n get _activeTxContextOrNull(): TxContext | null {\n return this._activeTxContext\n }\n\n /**\n * Called by `runTransaction` at Phase 2 start, and by\n * `Collection.putManyAtomic` (via `derivationSource.setActiveTxContext`)\n * for its own Phase 2 loop. Nested or concurrent (non-nested)\n * transactions on the same Noydb instance are NOT supported —\n * overwriting an active context means another transaction is still\n * running and its `_executed` list would be cross-contaminated by\n * the nested writes. We tolerate the overwrite (best-effort, no\n * throw) to keep the rare interleaving from breaking consumers who\n * currently get lucky with timing, but applications should ensure\n * their multi-record commits are serialised on a single Noydb.\n *\n * @internal\n */\n _setActiveTxContext(ctx: TxContext): void {\n this._activeTxContext = ctx\n }\n\n /**\n * Factory for a transient `TxContext` bound to this Noydb. Used by\n * `Collection.putManyAtomic` (via `derivationSource.createTxContext`)\n * to publish an active context for the duration of its bulk-atomic\n * Phase 2 loop, so recursive derivation-output writes register on\n * `ctx._executed` and roll back together with the source ops (#133).\n *\n * @internal\n */\n _createTxContext(): TxContext {\n return new TxContext(this)\n }\n\n /**\n * Called by `runTransaction` in its `finally`. Only clears when the\n * passed ctx matches the active one — a defensive no-op if some\n * other code path already cleared it.\n *\n * @internal\n */\n _clearActiveTxContext(ctx: TxContext): void {\n if (this._activeTxContext === ctx) {\n this._activeTxContext = null\n }\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 requireShamirProvider(): ShamirRecoveryProvider {\n const p = this.options.shamirRecovery\n if (!p) {\n throw new Error(\n \"shamir recovery requires a ShamirRecoveryProvider — pass \"\n + \"shamirRecovery: shamirRecoveryProvider() from '@noy-db/on-shamir' to createNoydb()\",\n )\n }\n return p\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 /**\n * Soft-lock a single vault: clear its in-memory keyring, DEKs, vault\n * instance, sync engine, policy enforcer, and active-tier entry —\n * WITHOUT destroying the `Noydb` instance.\n *\n * Designed for \"lock screen\" UX: the user taps **Lock** and DEKs are\n * scrubbed from memory immediately, but the same `Noydb` instance can\n * be re-unlocked via {@link unlockViaAuthenticator} (tier 2) or\n * {@link unlockViaPin} (tier 3) without re-running `createNoydb`.\n *\n * **QuickUnlock state is preserved.** That's the whole point — the\n * user can still resume via PIN without a full credential re-prompt.\n * The on-disk `_meta/policy` document is also kept in cache (it\n * survives lock; nothing about it changes when DEKs are scrubbed).\n *\n * No-op when `vault` is not currently in cache (idempotent).\n *\n * Unblocks vLannaAi/niwat#33.\n *\n * @see #17\n */\n lockVault(vault: string): void {\n // Sync engine: stop autosync + drop the engine so the next openVault\n // builds a fresh one against the freshly-loaded keyring.\n this.syncEngines.get(vault)?.stopAutoSync()\n this.syncEngines.delete(vault)\n // Policy enforcer: cancels its idle timer and any visibility listener.\n this.policyEnforcers.get(vault)?.destroy()\n this.policyEnforcers.delete(vault)\n // Live caches: scrub DEKs, vault instance, active tier.\n this.keyringCache.delete(vault)\n this.vaultCache.delete(vault)\n this.activeTier.delete(vault)\n // Intentionally NOT cleared:\n // - this.quickUnlock — preserves PIN resume (#17 contract).\n // - this.policyCache — vault policy is on-disk data, survives lock.\n // - this.sessionStrategy — no per-vault revoke; close() handles bulk.\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.activeTier.clear()\n this.policyCache.clear()\n this.quickUnlock.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 // ─── Policy gates (issue #9) ──────────────────────────────────\n /**\n * Read the active policy for a vault. Loads from `_meta/policy` on\n * first call; subsequent calls hit the in-memory cache. Throws\n * `ValidationError` if the vault has not been opened.\n */\n async getPolicy(vault: string): Promise<VaultPolicy> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const cached = this.policyCache.get(vault)\n if (cached) return cached\n await this.bootstrapPolicy(vault)\n return this.policyCache.get(vault) ?? PERSONAL_POLICY\n }\n\n /**\n * Replace the policy document at `_meta/policy` and update the\n * in-memory cache. Gated by the `enroll-user` policy (a policy\n * change is fundamentally a privilege-management action).\n */\n async updatePolicy(vault: string, override: Partial<VaultPolicy>): Promise<VaultPolicy> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const current = await this.getPolicy(vault)\n const merged = mergePolicy(current, override)\n if (this.options.encrypt !== false) {\n await saveVaultPolicy(this.options.store, vault, merged)\n }\n this.policyCache.set(vault, merged)\n return merged\n }\n\n /**\n * Read the current vault-level user-directory toggle (#122). Returns\n * the default-on shape (`{ enabled: true }`) when no `_meta/directory`\n * document has been persisted yet.\n *\n * No role gate — anyone who can open the vault can read the toggle.\n */\n async getDirectoryEnabled(vault: string): Promise<boolean> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const persisted = await readDirectoryConfig(this.options.store, vault)\n return persisted?.enabled ?? true\n }\n\n /**\n * Toggle the vault's user-directory listing on or off (#122).\n * Owner-only. When disabled, `listUsersWithEnvelopes()` throws\n * {@link import('./errors.js').DirectoryDisabledError} for callers\n * whose role is neither `owner` nor `admin`.\n *\n * Honest caveat: this is a UX flag, not a privacy guarantee. The\n * keyring file at `_keyring/<userId>` and the envelope ciphertext at\n * `_users/<keyringId>` remain observable to anyone with direct store\n * read access — only the hub-level enumeration is gated. See\n * `docs/subsystems/user-envelope.md` → \"Directory visibility\".\n */\n async setDirectoryEnabled(vault: string, enabled: boolean): Promise<void> {\n if (this.closed) throw new ValidationError('Instance is closed')\n const keyring = await this.getKeyringInternal(vault)\n if (keyring.role !== 'owner') {\n throw new PermissionDeniedError(\n `setDirectoryEnabled requires owner role; caller has role \"${keyring.role}\"`,\n )\n }\n await persistDirectoryConfig(this.options.store, vault, { enabled })\n }\n\n /**\n * Evaluate a policy gate against the active session tier and the\n * presented factor proofs. Throws {@link PolicyDeniedError} on\n * denial; resolves with `void` on success.\n *\n * @param vault The vault whose policy applies.\n * @param gate Gate name — built-in (e.g. `'rotate-passphrase'`)\n * or app-defined (`app:*`).\n * @param presented Caller-supplied factor proofs.\n */\n async checkGate(\n vault: string,\n gate: GateName,\n factors?: FactorProofBundle,\n ): Promise<void> {\n const policy = await this.getPolicy(vault)\n const tier = this.activeTier.get(vault) ?? 1\n await policyCheckGate(policy, gate, {\n activeTier: tier,\n ...(factors?.factors !== undefined ? { factors: factors.factors } : {}),\n ...(factors?.sharedDevice !== undefined\n ? { sharedDevice: factors.sharedDevice }\n : {}),\n })\n }\n\n /** Read or persist the vault policy at `_meta/policy` on first open. */\n private async bootstrapPolicy(\n vault: string,\n opts?: { skipManagedCheck?: boolean },\n ): Promise<void> {\n const onDisk = await loadVaultPolicy(this.options.store, vault)\n if (onDisk) {\n // Honour the on-disk document; developer overrides cannot\n // weaken what the vault committed to at creation time.\n this.policyCache.set(vault, onDisk)\n await this.assertRecoveryEnrolled(vault, onDisk, opts)\n return\n }\n // First time — persist the developer's policy (or default preset).\n const initial = this.options.policy\n ? mergePolicy(PERSONAL_POLICY, this.options.policy)\n : PERSONAL_POLICY\n await saveVaultPolicy(this.options.store, vault, initial)\n this.policyCache.set(vault, initial)\n await this.assertRecoveryEnrolled(vault, initial, opts)\n }\n\n /**\n * Throw {@link RecoveryNotEnrolledError} or\n * {@link ManagedRecoveryNotEnrolledError} when recovery enrollment\n * is missing.\n *\n * Two enforcement modes:\n *\n * 1. **Managed-mode mandatory strong-recovery (#195).** When\n * `passphraseMode === 'managed'`, the vault MUST have at least\n * one **strong** recovery profile (Shamir today). Paper alone is\n * rejected because under managed mode the user has no memorized\n * passphrase, so losing the paper sheet = losing every record.\n * This check is unconditional — independent of `requireRecovery`\n * and the `recover-passphrase` gate.\n *\n * 2. **Opt-in strict mandatory-recovery.** When\n * `requireRecovery: true` is set on createNoydb (and the gate is\n * not explicitly disabled), require ANY recovery profile (paper\n * or shamir). This is the v0.x default-off behavior; v1.0 may\n * flip it default-on.\n *\n * The managed-mode check fires from {@link bootstrapPolicy} unless\n * the `skipManagedCheck` flag is set (used by\n * {@link openVaultAndEnrollRecovery} to allow atomic create-and-enroll).\n */\n private async assertRecoveryEnrolled(\n vault: string,\n policy: VaultPolicy,\n opts?: { skipManagedCheck?: boolean },\n ): Promise<void> {\n const skipManaged = (opts?.skipManagedCheck ?? false) || this._skipNextManagedRecoveryCheck\n if (this.options.passphraseMode === 'managed' && !skipManaged) {\n const enrolled = await hasStrongRecoveryEnrolled(this.options.store, vault)\n if (!enrolled) {\n throw new ManagedRecoveryNotEnrolledError(vault)\n }\n }\n if (this.options.requireRecovery !== true) return\n const gate = policy.gates['recover-passphrase']\n if (gate?.enabled === false) return\n const enrolled = await hasRecoveryEnrolled(this.options.store, vault)\n if (enrolled) return\n throw new RecoveryNotEnrolledError()\n }\n\n /**\n * Internal accessor used by tier-2/tier-3 unlock paths (issue #11)\n * to mark the active session tier.\n * @internal\n */\n _setActiveTier(vault: string, tier: ActiveTier): void {\n this.activeTier.set(vault, tier)\n }\n\n // ─── Tier-2 enroll / remove (issue #11) ────────────────────────\n /**\n * Add a tier-2 authenticator slot to the calling user's keyring.\n * Each slot independently wraps the SAME KEK under a method-specific\n * key — adding a slot is a constant-time keyring write.\n *\n * The wrapping ciphertext is produced by the corresponding\n * `@noy-db/on-*` package (e.g. `enrollPasswordAuthenticator` from\n * `@noy-db/on-password`); the hub persists the result.\n *\n * Gated by `enroll-authenticator`; `presented` carries any factor\n * proofs the active policy demands.\n */\n async enrollAuthenticator(\n vault: string,\n options: EnrollAuthenticatorOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'enroll-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const next = await keyringEnrollAuthenticator(this.options.store, vault, keyring, options)\n this.keyringCache.set(vault, next)\n }\n\n /**\n * Remove a tier-2 authenticator slot. Idempotent — removing a\n * non-existent slot is a successful no-op. Gated by\n * `remove-authenticator`.\n */\n async removeAuthenticator(\n vault: string,\n slotId: string,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'remove-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const next = await keyringRemoveAuthenticator(this.options.store, vault, keyring, slotId)\n this.keyringCache.set(vault, next)\n }\n\n /** Read the slot list for a vault. Internal — `describeAuthConfig` (#13) consumes this. */\n async listAuthenticators(vault: string): Promise<ReadonlyArray<KeyringAuthenticator>> {\n const keyring = await this.getKeyringInternal(vault)\n return keyring.authenticators\n }\n\n /**\n * Mutate the `meta` blob on an existing authenticator slot — slot\n * rename, label change, attachment of UI hints. The slot's `id`,\n * `method`, and wrap material (`wrapped_kek` / `wrapped_deks` + `iv`)\n * are immutable through this method. Anti-slot-swap is structural,\n * not gate-driven.\n *\n * `meta` patch semantics (#57-aligned):\n * - Top-level merge — absent keys preserved\n * - `null` value — delete that meta key\n * - Other values — replace verbatim\n *\n * Use case: per-slot nickname for \"iPhone Touch ID\" vs \"MacBook\n * Touch ID\" disambiguation in admin UIs. The slot id (auto-derived\n * from credentialId prefix) is not human-friendly; `meta.nickname`\n * is.\n *\n * Gated by `update-authenticator`. PERSONAL_POLICY: tier-1 unlock\n * alone (matches enroll/remove). STRICT_POLICY: tier-1 +\n * TOTP/email-OTP factor proof — a malicious rename on a shared\n * workstation could mislead the user about which device a slot\n * corresponds to, so STRICT requires fresh factor binding.\n *\n * @throws `NoAccessError` when no slot with the given id exists.\n * @throws `ValidationError` when no patch field is provided.\n *\n * @see #55\n */\n async updateAuthenticator(\n vault: string,\n slotId: string,\n options: UpdateAuthenticatorOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'update-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const next = await keyringUpdateAuthenticator(this.options.store, vault, keyring, slotId, options)\n this.keyringCache.set(vault, next)\n }\n\n /**\n * Native WebAuthn enrollment using the **real** internal keyring (#16).\n *\n * Why this exists: when a consumer is using `createNoydb({ secret })`,\n * they cannot reach the live `UnlockedKeyring` to feed it to\n * `enrollWebAuthn(keyring, vault, opts)` from `@noy-db/on-webauthn`.\n * Constructing a synthetic keyring (the previous workaround) produces\n * a slot whose `wrapped_kek` references the synthetic payload, not\n * the live session — so `unlockViaAuthenticator()` later replaces the\n * live DEK map with stale wrapped DEKs and every decrypt fails.\n *\n * This method runs `ceremony` with the REAL keyring (still in\n * `keyringCache`). The ceremony performs the WebAuthn enrollment and\n * returns the slot options that hub then persists via the standard\n * tier-2 enrollAuthenticator path.\n *\n * Layering note: hub does not import `@noy-db/on-webauthn` (that\n * would invert the dep graph). The consumer wires it in:\n *\n * ```ts\n * import { enrollWebAuthn } from '@noy-db/on-webauthn'\n *\n * await db.enrollWebAuthn('demo', async (keyring) => {\n * const e = await enrollWebAuthn(keyring, 'demo', { rp: {...} })\n * return {\n * id: `webauthn-${e.credentialId.slice(0, 8)}`,\n * method: 'webauthn',\n * wrapped_kek: e.wrappedPayload,\n * meta: {\n * credentialId: e.credentialId,\n * wrapIv: e.wrapIv,\n * prfUsed: e.prfUsed,\n * beFlag: e.beFlag,\n * requireSingleDevice: e.requireSingleDevice,\n * },\n * }\n * })\n * ```\n *\n * Returns the WebAuthn `credentialId` (extracted from `meta.credentialId`)\n * for the caller's lookup index (a bootstrap vault, a PublicEnvelope,\n * a server-side allowlist).\n *\n * Gated by `enroll-authenticator` like `enrollAuthenticator()` itself.\n *\n * @see #16\n */\n async enrollWebAuthn(\n vault: string,\n ceremony: (keyring: UnlockedKeyring) => Promise<EnrollAuthenticatorOptions>,\n factors?: FactorProofBundle,\n ): Promise<{ credentialId: string }> {\n await this.checkGate(vault, 'enroll-authenticator', factors)\n const keyring = await this.getKeyringInternal(vault)\n const slotOptions = await ceremony(keyring)\n if (slotOptions.method !== 'webauthn') {\n throw new ValidationError(\n `enrollWebAuthn: ceremony returned method \"${slotOptions.method}\"; expected \"webauthn\". ` +\n 'Use db.enrollAuthenticator() for non-webauthn methods.',\n )\n }\n const credentialId = (slotOptions.meta as { credentialId?: unknown }).credentialId\n if (typeof credentialId !== 'string' || credentialId.length === 0) {\n throw new ValidationError(\n 'enrollWebAuthn: ceremony result must include `meta.credentialId` (base64 string). ' +\n 'See @noy-db/on-webauthn enrollWebAuthn() return shape.',\n )\n }\n const next = await keyringEnrollAuthenticator(this.options.store, vault, keyring, slotOptions)\n this.keyringCache.set(vault, next)\n return { credentialId }\n }\n\n /**\n * Filter the slot list to webauthn-method slots only. Useful for\n * \"you have N WebAuthn credentials enrolled\" UI surfaces and for\n * deciding when a new device prompt should appear. Identity is\n * `id` + `enrolled_at`; the `meta.credentialId` (base64) is used by\n * `allowCredentials` at unlock time.\n *\n * @see #16\n */\n async listWebAuthnSlots(vault: string): Promise<ReadonlyArray<{\n id: string\n enrolledAt: string\n credentialId: string\n }>> {\n const keyring = await this.getKeyringInternal(vault)\n return keyring.authenticators\n .filter((a) => a.method === 'webauthn')\n .map((a) => {\n const credentialId = (a.meta as { credentialId?: unknown }).credentialId\n return {\n id: a.id,\n enrolledAt: a.enrolled_at,\n credentialId: typeof credentialId === 'string' ? credentialId : '',\n }\n })\n }\n\n /**\n * Resolve a slot by id, then hand the wrapped-KEK ciphertext + meta\n * to the caller-supplied verifier. The verifier is the\n * `unlockWith*` function from the corresponding `@noy-db/on-*`\n * package, e.g. `unlockWithPassword(slot, password)`.\n *\n * On success, mark the active session tier as 2 — subsequent\n * `checkGate` calls see a tier-2 unlock.\n */\n async unlockViaAuthenticator(\n vault: string,\n slotId: string,\n verify: (slot: KeyringAuthenticator) => Promise<UnlockedKeyring>,\n ): Promise<UnlockedKeyring> {\n const keyring = await this.getKeyringInternal(vault)\n const slot = findAuthenticator(keyring, slotId)\n if (!slot) {\n throw new ValidationError(\n `unlockViaAuthenticator: no slot with id \"${slotId}\" in vault \"${vault}\".`,\n )\n }\n const unlocked = await verify(slot)\n this.keyringCache.set(vault, unlocked)\n this.activeTier.set(vault, 2)\n return unlocked\n }\n\n // ─── Public envelope (docs/subsystems/public-envelope.md) ──────\n /**\n * Set the owner-curated public envelope for a vault. Throws\n * `ValidationError` if the developer did not opt the hub into\n * `publicEnvelope` via `NoydbOptions`, or if the input violates\n * the resolved schema (oversized icon, disallowed MIME, oversized\n * string, unknown field).\n *\n * `createdAt` is set on the first write and preserved on every\n * subsequent write. `updatedAt` is refreshed on every write.\n * `version` is monotonic — increments on every successful write.\n */\n async setPublicEnvelope(\n vault: string,\n input: SetPublicEnvelopeInput,\n ): Promise<PublicEnvelope> {\n if (!this.publicEnvelopeSchema) {\n throw new ValidationError(\n 'setPublicEnvelope: the public-envelope feature is not enabled. ' +\n 'Pass `publicEnvelope: true` (or a schema object) to `createNoydb`.',\n )\n }\n validatePublicEnvelopeInput(input, this.publicEnvelopeSchema)\n\n const now = new Date().toISOString()\n const existing = await loadPublicEnvelope(this.options.store, vault)\n const next: PublicEnvelope = {\n _noydb_public: 1,\n version: (existing?.version ?? 0) + 1,\n ...(existing?.createdAt !== undefined ? { createdAt: existing.createdAt } : { createdAt: now }),\n updatedAt: now,\n ...(input.name !== undefined ? { name: input.name } : (existing?.name !== undefined ? { name: existing.name } : {})),\n ...(input.description !== undefined ? { description: input.description } : (existing?.description !== undefined ? { description: existing.description } : {})),\n ...(input.icon !== undefined ? { icon: input.icon } : (existing?.icon !== undefined ? { icon: existing.icon } : {})),\n ...(input.defaultLocale !== undefined ? { defaultLocale: input.defaultLocale } : (existing?.defaultLocale !== undefined ? { defaultLocale: existing.defaultLocale } : {})),\n }\n await savePublicEnvelope(this.options.store, vault, next)\n return next\n }\n\n /**\n * Read the public envelope for a vault. Returns `undefined` when\n * none has been written. Pass `locale` to resolve any locale-map\n * fields to plain strings; omitting `locale` returns the raw map.\n *\n * Works even when the developer didn't enable\n * `publicEnvelope` — reads are passive and never throw on a\n * missing schema (the envelope is plaintext and exists on disk\n * regardless).\n */\n async getPublicEnvelope(\n vault: string,\n opts: { readonly locale?: string } = {},\n ): Promise<PublicEnvelope | undefined> {\n return fnReadPublicEnvelope(this.options.store, vault, opts)\n }\n\n // ─── Auth introspection (issue #13) ────────────────────────────\n /** English summary of the configured auth model. */\n async describeAuthConfig(vault: string): Promise<string> {\n return fnDescribeAuthConfig(this.options.store, vault)\n }\n\n /** Mermaid `flowchart TB` source for the auth graph. */\n async diagramAuthConfig(vault: string): Promise<string> {\n return fnDiagramAuthConfig(this.options.store, vault)\n }\n\n /**\n * Per-user enrollment summary. Gated by `view-user-auth` (default:\n * disabled). Sanitization is allowlist-based — never renders cred\n * ids, password hashes, secrets, or any field outside the allowlist.\n */\n async describeUserAuth(\n vault: string,\n userId: string,\n factors?: FactorProofBundle,\n ): Promise<string> {\n await this.checkGate(vault, 'view-user-auth', factors)\n return fnDescribeUserAuth(this.options.store, vault, userId)\n }\n\n /** Bulk variant for owner dashboards. Gated by `view-user-auth`. */\n async describeAllUsersAuth(\n vault: string,\n factors?: FactorProofBundle,\n ): Promise<Array<{ userId: string; description: string }>> {\n await this.checkGate(vault, 'view-user-auth', factors)\n return fnDescribeAllUsersAuth(this.options.store, vault)\n }\n\n // ─── Tier-1 change flows (issue #10) ───────────────────────────\n /**\n * Rotate the user's passphrase (user remembers old). Validates the\n * new phrase against the configured `passphrase` policy, runs the\n * `rotate-passphrase` gate, then re-derives + re-wraps every DEK.\n *\n * Tier-2 authenticator slots are dropped — each slot wraps the old\n * KEK and would need its derivation key to be re-presented. Re-enrol\n * via `db.enrollAuthenticator` after rotation. Tracked as a\n * v0.1.0-pre.5 limitation.\n *\n * @throws `WeakPassphraseError` on a weak new phrase.\n * @throws `PolicyDeniedError` when the gate denies (missing factor, …).\n * @throws `InvalidKeyError` when `oldPassphrase` is wrong.\n */\n async rotatePassphrase(\n vault: string,\n input: RotatePassphraseInput,\n factors?: FactorProofBundle,\n ): Promise<void> {\n // Managed-passphrase mode (#14): the user does NOT know the\n // current passphrase (hub generated it and sealed it under the\n // provider). Manual rotation via this method is impossible by\n // construction — surface a clear error rather than fail mid-way\n // with InvalidKeyError once `oldPassphrase` doesn't match the\n // hub-generated one. Recovery-under-managed (which mints a fresh\n // sealed passphrase via the provider) is the supported path; it\n // lands in a follow-up.\n if (this.options.passphraseMode === 'managed') {\n throw new PolicyDeniedError(\n 'rotate-passphrase',\n 'disabled',\n { minTier: 1, enabled: false },\n 'Managed-passphrase mode (#14): the passphrase is hub-generated '\n + 'and sealed under the SealingKeyProvider — there is no '\n + 'plaintext to rotate. Use the recovery flow (follow-up issue) '\n + 'to mint a fresh sealed passphrase.',\n )\n }\n await this.checkGate(vault, 'rotate-passphrase', factors)\n const userId = this.options.user\n const next = await keyringRotatePassphrase(this.options.store, vault, userId, input)\n this.keyringCache.set(vault, next)\n }\n\n /**\n * Reset the passphrase using a recovery proof (user forgot the old).\n * v0.1.0-pre.5 supports the `'paper'` profile end-to-end; the\n * other three profiles throw {@link RecoveryProfileNotImplementedError}.\n *\n * Burns the used recovery entry on success.\n */\n async recoverPassphrase(\n vault: string,\n input: RecoverPassphraseInput,\n factors?: FactorProofBundle,\n ): Promise<RecoverPassphraseResult> {\n await this.checkGate(vault, 'recover-passphrase', factors)\n const userId = this.options.user\n\n // Snapshot the entries BEFORE recovery — the team function burns\n // exactly one entry, so post-recovery `_meta/recovery-paper`\n // contains `entriesBeforeRecovery.length - 1` entries (the ones\n // the user did NOT just consume). Those are what we replace\n // under the auto-rotation logic from #36.\n const entriesBeforeRecovery = await loadPaperRecoveryEntries(this.options.store, vault)\n\n const next = await keyringRecoverPassphrase(this.options.shamirRecovery, this.options.store, vault, userId, input)\n this.keyringCache.set(vault, next)\n\n const rotateRemaining = input.rotateRemainingCodes ?? true\n const remainingAfterBurn = Math.max(0, entriesBeforeRecovery.length - 1)\n if (!rotateRemaining || remainingAfterBurn === 0) {\n return { newCodes: [] }\n }\n\n // Auto-rotate: replace the remaining entries with a fresh set\n // minted under the new keyring's DEKs. Wraps the same DEK set the\n // recovered keyring just got, so the new codes round-trip through\n // a future `db.recoverPassphrase` cleanly.\n //\n // If this step fails (store error mid-mint), we leave the existing\n // post-burn entries in place — the user falls back to the\n // pre-#36 behavior (remaining N-1 codes still valid). Strictly\n // safer than wiping then failing.\n const codeGen = input.codeGenerator ?? generateULID\n const newCodeCount = input.newCodeCount ?? remainingAfterBurn\n const codes: string[] = []\n const newEntries: PaperRecoveryEntry[] = []\n for (let i = 0; i < newCodeCount; i++) {\n const rawCode = codeGen()\n const entry = await mintPaperRecoveryEntry(next.deks, rawCode, generateULID())\n codes.push(rawCode)\n newEntries.push(entry)\n }\n // Single replace-all write — `savePaperRecoveryEntries` overwrites\n // `_meta/recovery-paper` atomically (one envelope `put`).\n await savePaperRecoveryEntries(this.options.store, vault, newEntries)\n\n return { newCodes: codes }\n }\n\n /**\n * Deliberate paper-recovery-code regeneration (#121). User knows their\n * passphrase but wants a fresh sheet — they lost the printout or\n * suspect compromise of the off-site copy.\n *\n * Symmetric to {@link rotatePassphrase} for the recovery profile:\n * gated, audit-trackable, ergonomic. Replaces (not appends) the\n * paper sheet under `_meta/recovery-paper` in a single envelope `put`.\n *\n * Gated by the `rotate-recovery` policy gate:\n * - PERSONAL_POLICY: `{ minTier: 1 }` — knowing the passphrase\n * suffices, matching the pre-#121 low-level flow's bar.\n * - STRICT_POLICY: `{ minTier: 1, factors: [{ anyOf: ['totp',\n * 'email-otp', 'webauthn-roaming'] }] }` — rotation is an\n * off-site-trust event; require an off-device factor so a\n * stolen unlocked laptop cannot silently mint a sheet for the\n * attacker.\n *\n * Defaults `count` to the existing sheet size so consumers aren't\n * surprised by a different code count. Explicit `count` overrides.\n *\n * @throws {@link RecoveryProfileNotImplementedError} when `profile`\n * is anything other than `'paper'` (v1 dispatch limit).\n * @throws {@link PolicyDeniedError} when the gate denies (missing\n * factor, tier mismatch, ...).\n * @throws on missing paper sheet — \"nothing to rotate\" surfaces as\n * an error rather than silently minting an entire new sheet.\n *\n * @example Default count + show-once UI\n * ```ts\n * const { newCodes } = await db.rotateRecovery('acme', { profile: 'paper' })\n * showCodesToUser(newCodes)\n * ```\n *\n * @example STRICT-policy site with TOTP factor proof\n * ```ts\n * await db.rotateRecovery(\n * 'acme',\n * { profile: 'paper', count: 10 },\n * { factors: [{ kind: 'totp', proof: '123456' }] },\n * )\n * ```\n */\n async rotateRecovery(\n vault: string,\n options: RotateRecoveryOptions,\n factors?: FactorProofBundle,\n ): Promise<RotateRecoveryResult> {\n if (options.profile === 'paper') {\n return this.rotateRecoveryPaper(vault, options, factors)\n }\n if (options.profile === 'shamir') {\n return this.rotateRecoveryShamir(vault, options, factors)\n }\n // Defense-in-depth for `as unknown as ...` bypass.\n throw new RecoveryProfileNotImplementedError(\n (options as { profile: string }).profile,\n '#196',\n )\n }\n\n private async rotateRecoveryPaper(\n vault: string,\n options: Extract<RotateRecoveryOptions, { profile: 'paper' }>,\n factors?: FactorProofBundle,\n ): Promise<RotateRecoveryResult> {\n await this.checkGate(vault, 'rotate-recovery', factors)\n\n const existing = await loadPaperRecoveryEntries(this.options.store, vault)\n if (existing.length === 0) {\n throw new Error(\n `db.rotateRecovery: no recovery codes are enrolled for vault \"${vault}\". ` +\n `Call db.enrollRecovery({ profile: 'paper', entries }) first; ` +\n `rotateRecovery replaces an existing sheet rather than minting one from scratch.`,\n )\n }\n\n const keyring = await this.getKeyring(vault)\n const codeGen = options.codeGenerator ?? generateULID\n const count = options.count ?? existing.length\n\n const codes: string[] = []\n const newEntries: PaperRecoveryEntry[] = []\n for (let i = 0; i < count; i++) {\n const rawCode = codeGen()\n const entry = await mintPaperRecoveryEntry(keyring.deks, rawCode, generateULID())\n codes.push(rawCode)\n newEntries.push(entry)\n }\n // Atomic replace — `savePaperRecoveryEntries` overwrites\n // `_meta/recovery-paper` in a single envelope `put`.\n await savePaperRecoveryEntries(this.options.store, vault, newEntries)\n\n return { newCodes: codes, entryId: 'paper-batch' }\n }\n\n private async rotateRecoveryShamir(\n vault: string,\n options: Extract<RotateRecoveryOptions, { profile: 'shamir' }>,\n factors?: FactorProofBundle,\n ): Promise<RotateRecoveryResult> {\n await this.checkGate(vault, 'rotate-recovery', factors)\n\n const existing = await loadShamirRecoveryEntries(this.options.store, vault)\n if (existing.length === 0) {\n throw new Error(\n `db.rotateRecovery: no Shamir recovery entry is enrolled for vault \"${vault}\". ` +\n `Call db.enrollRecovery({ profile: 'shamir', k, n }) first; ` +\n `rotateRecovery replaces an existing entry rather than minting one from scratch.`,\n )\n }\n\n // Pick which entry to rotate.\n let targetEntryId: string\n if (options.entryId !== undefined) {\n const found = existing.find(e => e.entryId === options.entryId)\n if (!found) {\n throw new Error(\n `db.rotateRecovery: no Shamir entry with entryId=\"${options.entryId}\" found `\n + `in vault \"${vault}\". Available: ${existing.map(e => `\"${e.entryId}\"`).join(', ')}.`,\n )\n }\n targetEntryId = options.entryId\n } else {\n if (existing.length > 1) {\n throw new Error(\n `db.rotateRecovery: vault \"${vault}\" has ${existing.length} Shamir entries `\n + `enrolled (${existing.map(e => `\"${e.entryId}\"`).join(', ')}). `\n + `Pass \\`entryId\\` to disambiguate which one to rotate; ambiguous rotation `\n + `would risk replacing the wrong entry.`,\n )\n }\n targetEntryId = existing[0]!.entryId\n }\n\n const keyring = await this.getKeyring(vault)\n const { entry, shareStrings } = await mintShamirRecoveryEntry(\n this.requireShamirProvider(),\n keyring.deks,\n targetEntryId,\n options.k,\n options.n,\n options.label,\n )\n\n // Atomic single-doc replace: drop the old entry, insert the new one.\n const next: ShamirRecoveryEntry[] = existing\n .filter(e => e.entryId !== targetEntryId)\n .concat(entry)\n await saveShamirRecoveryEntries(this.options.store, vault, next)\n\n return { newShares: shareStrings, entryId: targetEntryId }\n }\n\n /**\n * **Atomic create-and-enroll for managed-mode vaults (#195).**\n *\n * Bootstraps a managed-mode vault and enrolls strong recovery in\n * a single ceremony. Under `passphraseMode: 'managed'`, every\n * `openVault` call requires a strong recovery profile (Shamir\n * today) to be enrolled — otherwise it throws\n * {@link ManagedRecoveryNotEnrolledError}. This method bypasses\n * the check temporarily so the keyring can be created, enrolls\n * the supplied recovery profile(s), then returns the vault.\n *\n * For Shamir enrollments, the show-once share strings come back\n * in `recoveryEnrollments[i].shares`. The hub never retains them\n * — the caller MUST display them to the user (once) before any\n * subsequent operation.\n *\n * Paper alone is NOT a strong profile under managed mode; passing\n * `{ profile: 'paper', ... }` without an accompanying shamir entry\n * is rejected at validation time.\n *\n * ```ts\n * const db = await createNoydb({\n * store, user: 'alice',\n * passphraseMode: 'managed',\n * sealingKey: macosKeychainSealingProvider({ ... }),\n * })\n *\n * const { vault, recoveryEnrollments } = await db.openVaultAndEnrollRecovery('acme', {\n * recovery: [{ profile: 'shamir', k: 2, n: 3 }],\n * })\n * for (const r of recoveryEnrollments) {\n * if (r.shares) showSharesToUser(r.shares) // ONCE\n * }\n * ```\n *\n * @throws ValidationError if recovery is empty, or contains no\n * strong profile under managed mode.\n */\n async openVaultAndEnrollRecovery(\n vault: string,\n opts: {\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly locale?: string\n },\n ): Promise<{\n readonly vault: Vault\n readonly recoveryEnrollments: ReadonlyArray<EnrollRecoveryResult>\n }> {\n if (opts.recovery.length === 0) {\n throw new ValidationError(\n 'openVaultAndEnrollRecovery: at least one recovery enrollment is required.',\n )\n }\n\n // Validate \"at least one strong\" when managed mode is on.\n if (this.options.passphraseMode === 'managed') {\n const hasStrong = opts.recovery.some(r => r.profile === 'shamir')\n if (!hasStrong) {\n throw new ValidationError(\n 'openVaultAndEnrollRecovery: managed-mode vaults require at least one strong '\n + 'recovery profile in the `recovery` array. Paper alone is not strong under '\n + 'managed mode (no user passphrase to fall back on). Include '\n + '{ profile: \"shamir\", k, n } in `recovery`.',\n )\n }\n }\n\n // Temporarily bypass the managed-mode strong-recovery check so\n // openVault can create the keyring. Recovery enrollment happens\n // inside this window; the check is restored at the end.\n this._skipNextManagedRecoveryCheck = true\n let vaultHandle: Vault\n try {\n vaultHandle = await this.openVault(vault, opts.locale !== undefined ? { locale: opts.locale } : undefined)\n } finally {\n this._skipNextManagedRecoveryCheck = false\n }\n\n // Enroll each recovery profile.\n const recoveryEnrollments: EnrollRecoveryResult[] = []\n for (const enrollment of opts.recovery) {\n recoveryEnrollments.push(await this.enrollRecovery(vault, enrollment))\n }\n\n // Belt-and-braces final check — by now, strong recovery must be on disk.\n if (this.options.passphraseMode === 'managed') {\n const policy = this.policyCache.get(vault)\n if (policy) {\n await this.assertRecoveryEnrolled(vault, policy)\n }\n }\n\n return { vault: vaultHandle, recoveryEnrollments }\n }\n\n /**\n * **Recovery flow under managed-passphrase mode (#195).**\n *\n * Replaces the sealed passphrase of a managed-mode vault with a\n * fresh 256-bit random, sealed under the configured\n * `SealingKeyProvider`. The user never sees the new passphrase.\n *\n * Internally:\n * 1. Verify the recovery proof (Shamir today) and unwrap the\n * DEK set.\n * 2. Mint a fresh 256-bit random as the new effective passphrase.\n * 3. Rewrap the DEK set under a fresh KEK derived from the new\n * passphrase (via the existing `recoverPassphrase` path).\n * 4. Seal the random bytes under the provider and overwrite\n * `_meta/sealed-passphrase`.\n * 5. Drop the keyring cache so the next operation re-derives.\n *\n * The vault's strong-recovery enrollment is preserved across\n * recovery (Shamir entries are not burned on use — see #196).\n *\n * @throws ValidationError if the Noydb instance is not in managed mode.\n */\n async recoverManagedPassphrase(\n vault: string,\n options: {\n readonly recoveryProof: RecoveryProof\n readonly passphrasePolicy?: PassphrasePolicy\n },\n ): Promise<void> {\n if (this.options.passphraseMode !== 'managed') {\n throw new ValidationError(\n 'recoverManagedPassphrase: this method only applies to vaults opened '\n + 'in managed-passphrase mode. For standard mode, use db.recoverPassphrase.',\n )\n }\n const provider = this.options.sealingKey\n if (!provider) {\n throw new ValidationError(\n 'recoverManagedPassphrase: createNoydb({ passphraseMode: \"managed\" }) requires '\n + '`sealingKey` to be supplied; without it the new sealed passphrase cannot '\n + 'be persisted.',\n )\n }\n\n // Mint fresh 256-bit random; base64 it for use as the new\n // effective passphrase. AES-GCM auth-tag failures in the\n // managed-mode envelope catch tampering.\n const randomBytes = new Uint8Array(32)\n globalThis.crypto.getRandomValues(randomBytes)\n let binary = ''\n for (let i = 0; i < randomBytes.length; i++) binary += String.fromCharCode(randomBytes[i]!)\n const newPassphrase = btoa(binary)\n\n try {\n // Seal first; if the provider fails (KMS down, keychain locked),\n // we don't touch the keyring. Then run recoverPassphrase which\n // rewraps DEKs under the new KEK derived from the random bytes.\n const sealed = await provider.seal(randomBytes)\n await keyringRecoverPassphrase(\n this.options.shamirRecovery,\n this.options.store,\n vault,\n this.options.user,\n {\n newPassphrase,\n recoveryProof: options.recoveryProof,\n // The new passphrase IS 256 bits of random; policy gates on\n // length/entropy don't apply.\n allowWeakPassphrase: true,\n ...(options.passphrasePolicy !== undefined\n ? { passphrasePolicy: options.passphrasePolicy }\n : {}),\n },\n )\n // Update _meta/sealed-passphrase with the freshly sealed random.\n // The previous envelope is overwritten by saveSealedPassphrase.\n await saveSealedPassphrase(this.options.store, vault, {\n providerId: provider.id,\n sealed,\n })\n } finally {\n // Best-effort zero of the in-memory random buffer.\n randomBytes.fill(0)\n }\n\n // Drop the keyring cache so the next openVault re-derives from\n // the new sealed envelope.\n this.keyringCache.delete(vault)\n }\n\n /**\n * Atomic peer-recovery — re-wraps an EXISTING user's keyring under\n * a fresh temp passphrase in a single store write. Closes #34's\n * partial-failure window (the previous compose-from-primitives\n * pattern was `db.revoke + db.grant`, two writes — if the issuer\n * cancelled between them the target was locked out entirely).\n *\n * Different from `db.revoke + db.grant`:\n *\n * - Same `userId`, role, permissions, capabilities preserved.\n * - DEKs unchanged → every other principal in the vault keeps\n * access. No key rotation.\n * - Allows owner→owner natively (#33). The existing\n * `db.revoke` retains its block — peer-recovery is a separate,\n * intentionally-named operation.\n * - Tier-2 slots dropped (they wrap the old KEK).\n *\n * Gated by `peer-recover-user`; `STRICT_POLICY` requires a\n * recovery / TOTP / email-OTP factor proof at the moment of\n * recovery, so the issuer affirmatively re-asserts identity.\n *\n * The recipient should call `db.rotatePassphrase` on first session\n * to choose their own phrase — the temp acts as a single-use\n * bridge.\n *\n * ```ts\n * await db.recoverUser('acme', {\n * userId: 'bob',\n * passphrase: 'temporary-correct-horse-battery-staple-printer',\n * }, { factors: [{ kind: 'recovery' }] })\n * // Bob opens createNoydb({ user: 'bob', secret: tempPhrase })\n * // and immediately calls db.rotatePassphrase to set his own.\n * ```\n *\n * @throws `NoAccessError` when no keyring exists for the target.\n * @throws `PermissionDeniedError` when the caller's role can't\n * recover the target's role (admin→owner is blocked even\n * under recovery).\n * @throws `PrivilegeEscalationError` when the caller lacks a DEK\n * the target previously had access to.\n *\n * @see #33 #34 — the issues this method closes.\n */\n async recoverUser(\n vault: string,\n options: RecoverUserOptions,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'peer-recover-user', factors)\n const callerKeyring = await this.getKeyringInternal(vault)\n await keyringRecoverUser(this.options.store, vault, callerKeyring, options)\n // If the caller is recovering THEIR OWN keyring (rare but\n // possible — e.g. a self-recovery flow that bypasses the password\n // ceremony), the keyringCache entry is now stale. Drop it so the\n // next access reloads with the fresh wrapping.\n if (options.userId === this.options.user) {\n this.keyringCache.delete(vault)\n }\n }\n\n /**\n * Persist a recovery enrollment. v0.1.0-pre.5 accepts the `'paper'`\n * profile.\n *\n * The hub wraps the user's DEK set (not the KEK) under a code-derived\n * AES-GCM key — see `team/recovery.ts` for the rationale. The mint\n * helper {@link mintPaperRecoveryEntry} is the canonical primitive;\n * pair it with `db.getKeyring(vault)` to obtain the live DEK set:\n *\n * ```ts\n * import { mintPaperRecoveryEntry } from '@noy-db/hub'\n *\n * const keyring = await db.getKeyring('acme')\n * const codes: string[] = ['CORRECT-HORSE-1', 'BATTERY-STAPLE-2', ...]\n * const entries = await Promise.all(\n * codes.map((code, i) => mintPaperRecoveryEntry(keyring.deks, code, `code-${i}`)),\n * )\n * await db.enrollRecovery('acme', { profile: 'paper', entries })\n * showCodesToUser(codes)\n * ```\n *\n * As of pre.8, `@noy-db/on-recovery`'s `generateRecoveryCodeSet`\n * delegates to `mintPaperRecoveryEntry` internally — its output is\n * fed directly to this API. Pick whichever fits your code-gen layer:\n *\n * ```ts\n * import { generateRecoveryCodeSet } from '@noy-db/on-recovery'\n * const { codes, entries } = await generateRecoveryCodeSet({ deks: keyring.deks, count: 8 })\n * await db.enrollRecovery('acme', { profile: 'paper', entries })\n * ```\n */\n async enrollRecovery(\n vault: string,\n enrollment: RecoveryEnrollmentInput,\n ): Promise<EnrollRecoveryResult> {\n if (enrollment.profile === 'paper') {\n const existing = await loadPaperRecoveryEntries(this.options.store, vault)\n await savePaperRecoveryEntries(this.options.store, vault, [\n ...existing,\n ...enrollment.entries,\n ])\n // Paper enrollments don't have a single entryId — callers\n // pre-mint with their own ids. Return a stable sentinel so the\n // result type is consistent for both profiles.\n return { entryId: 'paper-batch' }\n }\n if (enrollment.profile === 'shamir') {\n const keyring = await this.getKeyring(vault)\n const entryId = enrollment.entryId ?? generateULID()\n const { entry, shareStrings } = await mintShamirRecoveryEntry(\n this.requireShamirProvider(),\n keyring.deks,\n entryId,\n enrollment.k,\n enrollment.n,\n enrollment.label,\n )\n const existing = await loadShamirRecoveryEntries(this.options.store, vault)\n // If a Shamir entry with this id already exists, replace it\n // (allows callers to be idempotent on `entryId`); otherwise append.\n const next: ShamirRecoveryEntry[] = existing.filter(e => e.entryId !== entryId).concat(entry)\n await saveShamirRecoveryEntries(this.options.store, vault, next)\n return { entryId, shares: shareStrings }\n }\n // Defense-in-depth for `as unknown as ...` bypass at the call site.\n throw new RecoveryProfileNotImplementedError(\n (enrollment as { profile: string }).profile,\n '#196',\n )\n }\n\n /** Read the persisted recovery entries (paper + Shamir). Used by `describeAuthConfig` (#13). */\n async listRecoveryEntries(\n vault: string,\n ): Promise<{\n paper: ReadonlyArray<PaperRecoveryEntry>\n shamir: ReadonlyArray<ShamirRecoveryEntry>\n }> {\n const paper = await loadPaperRecoveryEntries(this.options.store, vault)\n const shamir = await loadShamirRecoveryEntries(this.options.store, vault)\n return { paper, shamir }\n }\n\n // ─── Tier-3 enroll / unlock (issue #11) ────────────────────────\n /**\n * Register a tier-3 quick-unlock state for the vault. The state is\n * an opaque blob produced by `@noy-db/on-pin/enrollPin` (or any\n * compatible primitive). It is held in memory only — never persisted\n * — and auto-clears when its `expiresAt` elapses.\n *\n * Gated by `rotate-unlock` (the same gate covers \"set\" and \"rotate\"\n * because tier-3 is a single-slot rolling secret).\n */\n async enrollUnlock(\n vault: string,\n state: QuickUnlockState,\n factors?: FactorProofBundle,\n ): Promise<void> {\n await this.checkGate(vault, 'rotate-unlock', factors)\n this.quickUnlock.set(vault, state)\n }\n\n /**\n * Resume a session via the registered tier-3 state. The verifier is\n * `@noy-db/on-pin/resumePin` (or compatible). On success, mark the\n * active session tier as 3 — every operation must re-authenticate at\n * tier 2 to elevate.\n *\n * Returns `undefined` (caller should fall back to tier 2) when no\n * tier-3 state is registered.\n */\n async unlockViaPin(\n vault: string,\n resume: (state: QuickUnlockState) => Promise<UnlockedKeyring>,\n ): Promise<UnlockedKeyring | undefined> {\n const state = this.quickUnlock.get(vault)\n if (!state) return undefined\n const keyring = await resume(state)\n this.keyringCache.set(vault, keyring)\n this.activeTier.set(vault, 3)\n return keyring\n }\n\n /** Drop the tier-3 state for a vault — explicit logout. */\n clearQuickUnlock(vault: string): void {\n this.quickUnlock.delete(vault)\n }\n\n /**\n * Public accessor for the unlocked keyring of a vault — issue #28.\n *\n * Returns a **defensive shallow copy** so consumers can read the DEK\n * map and authenticator list without the risk of mutating the hub's\n * internal cache (#88). Internal hub code paths use a live reference\n * via `getKeyringInternal`; ceremonies and external consumers always\n * get a snapshot.\n *\n * The CryptoKey values inside `deks` are not cloned — Web Crypto\n * keys are opaque handles, and a shared handle is intentional\n * (encrypt / decrypt go through the same key the cache holds).\n * Only the container Map / authenticator array is fresh.\n *\n * Used by `@noy-db/on-*` ceremonies that need the live DEK set\n * (paper recovery via {@link mintPaperRecoveryEntry}, tier-3 PIN\n * enrolment via on-pin's `enrollPin`, custom on-* ceremonies that\n * don't have a hub-side wrapper).\n *\n * No new permission gate — this is an accessor over already-unlocked\n * state. The keyring is materialized only after the calling session\n * has unlocked the vault at tier 1, 2, or 3, so exposing it does not\n * widen access. Throws `ValidationError` when encryption is enabled\n * and no `secret` / `getKeyring` is configured.\n *\n * ```ts\n * const keyring = await db.getKeyring('acme')\n * // keyring.deks: Map<collection, CryptoKey>\n * // keyring.kek: CryptoKey | null (null for tier-3 / wrap-DEKs sessions)\n * // keyring.role / .permissions / .authenticators\n * ```\n */\n async getKeyring(vault: string): Promise<UnlockedKeyring> {\n const live = await this.getKeyringInternal(vault)\n // Deep-ish defensive copy. Each container the consumer might\n // reasonably mutate is freshly cloned. CryptoKey handles inside\n // `deks` are intentionally shared — they're opaque references that\n // both encrypt and decrypt go through. `salt` (Uint8Array) is left\n // as-is: no realistic mutation path. (#88, extended in #114.)\n return {\n ...live,\n deks: new Map(live.deks),\n permissions: { ...live.permissions },\n authenticators: live.authenticators.map((a) => ({\n ...a,\n meta: { ...a.meta },\n })),\n ...(live.policy !== undefined ? { policy: { ...live.policy } } : {}),\n ...(live.exportCapability !== undefined\n ? { exportCapability: { ...live.exportCapability } }\n : {}),\n ...(live.importCapability !== undefined\n ? { importCapability: { ...live.importCapability } }\n : {}),\n }\n }\n\n /**\n * Live-reference variant used by the hub's own code paths. Internal\n * mutations on `deks` (e.g. {@link ensureCollectionDEK} adding a\n * collection key) need to land on the cached keyring so subsequent\n * accesses see them. Not exposed publicly — callers outside hub\n * should use {@link getKeyring}, which returns a defensive copy.\n */\n private async getKeyringInternal(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 // Custom unlock path (e.g. WebAuthn / OIDC / Shamir): caller-supplied\n // callback owns \"open existing vs create new\" — no automatic NoAccessError\n // fallback because the callback owner has the UI context for that choice.\n if (this.options.getKeyring) {\n const keyring = await this.options.getKeyring(vault)\n this.keyringCache.set(vault, keyring)\n return keyring\n }\n\n // Managed-passphrase mode (#14) — resolve the effective secret\n // before falling into the normal load/create path. The first call\n // mints + seals + persists; subsequent calls unseal what's there.\n // The returned string takes the place of `options.secret` for the\n // rest of this method (and is NOT persisted on `this.options`).\n let effectiveSecret: string | undefined\n if (this.options.passphraseMode === 'managed') {\n // sealingKey presence was validated at createNoydb time.\n \n effectiveSecret = await resolveManagedSecret(\n this.options.store,\n vault,\n this.options.sealingKey!,\n )\n } else {\n effectiveSecret = this.options.secret\n }\n\n if (!effectiveSecret) {\n throw new ValidationError('A secret (passphrase) or getKeyring callback 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, effectiveSecret)\n } catch (err) {\n if (err instanceof NoAccessError) {\n // No keyring on disk — first boot or cleared store.\n keyring = await createOwnerKeyring(\n this.options.store,\n vault,\n this.options.user,\n effectiveSecret,\n {\n // Managed mode generates 256-bit base64 strings that don't satisfy\n // the human-passphrase strength rules (no spaces, no \"words\").\n // Skip validation in managed mode — the entropy floor is already\n // 256 bits by construction.\n validate: this.options.passphraseMode === 'managed'\n ? false\n : this.options.validatePassphrase === true,\n },\n )\n } else if (err instanceof InvalidKeyError && this.options.onInvalidKey === 'reset') {\n // Stale keyring: exists in the store but the current credentials can't\n // decrypt it (e.g. the data records were cleared while the _keyring row\n // survived, or a WebAuthn credential was rotated between sessions).\n // The caller opted into reset — delete the stale row and start fresh.\n await this.options.store.delete(vault, '_keyring', this.options.user)\n keyring = await createOwnerKeyring(\n this.options.store,\n vault,\n this.options.user,\n effectiveSecret,\n {\n validate: this.options.passphraseMode === 'managed'\n ? false\n : this.options.validatePassphrase === true,\n },\n )\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 const managed = options.passphraseMode === 'managed'\n\n if (options.secret && options.getKeyring) {\n throw new ValidationError('Provide either `secret` or `getKeyring`, not both')\n }\n\n // Managed-passphrase mode (#14) — mutually exclusive with both\n // `secret` (the whole point is hub generates and seals; the user\n // doesn't supply one) and `getKeyring` (a custom unlock path that\n // bypasses the sealing flow entirely). Requires a SealingKeyProvider.\n if (managed) {\n if (options.secret) {\n throw new ValidationError(\n '`passphraseMode: \"managed\"` is mutually exclusive with `secret` — '\n + 'managed mode generates the passphrase itself. Drop `secret`.',\n )\n }\n if (options.getKeyring) {\n throw new ValidationError(\n '`passphraseMode: \"managed\"` is mutually exclusive with `getKeyring` — '\n + 'a custom unlock callback would bypass the sealing flow. Drop `getKeyring`.',\n )\n }\n if (!options.sealingKey) {\n throw new ValidationError(\n '`passphraseMode: \"managed\"` requires `sealingKey: SealingKeyProvider` '\n + '(see @noy-db/seal-macos-keychain / @noy-db/seal-aws-kms / etc.).',\n )\n }\n }\n\n if (encrypted && !managed && !options.secret && !options.getKeyring) {\n throw new ValidationError('A secret (passphrase) or getKeyring callback 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"],"mappings":"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","names":["notEnabled","notEnabled","version","envelope","previousEnvelope","NOT_ENABLED","NOT_ENABLED","checkGate","record","handle","generateULID","readPublicEnvelope","sha256Hex","NOT_ENABLED","notEnabled","keyring","comp","enrolled"]}
|