@noy-db/hub 0.2.0-pre.2 → 0.2.0-pre.21
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/README.md +126 -0
- package/dist/aggregate/index.cjs +643 -37
- package/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.d.cts +3 -2
- package/dist/aggregate/index.d.ts +3 -2
- package/dist/aggregate/index.js +9 -8
- package/dist/aggregate/index.js.map +1 -1
- package/dist/attestation/index.cjs.map +1 -1
- package/dist/attestation/index.d.cts +7 -5
- package/dist/attestation/index.d.ts +7 -5
- package/dist/attestation/index.js +6 -6
- package/dist/blobs/index.cjs +509 -22
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +9 -7
- package/dist/blobs/index.d.ts +9 -7
- package/dist/blobs/index.js +11 -6
- package/dist/blobs/index.js.map +1 -1
- package/dist/bundle/index.cjs +7886 -841
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +20 -18
- package/dist/bundle/index.d.ts +20 -18
- package/dist/bundle/index.js +24 -13
- package/dist/bundle/index.js.map +1 -1
- package/dist/{chunk-PFSNOPBQ.js → chunk-2XA2ZML4.js} +31 -3
- package/dist/chunk-2XA2ZML4.js.map +1 -0
- package/dist/{chunk-2PAQNPE3.js → chunk-37VGJM3T.js} +37 -2
- package/dist/chunk-37VGJM3T.js.map +1 -0
- package/dist/{chunk-7BRE6EUA.js → chunk-3HNKR65T.js} +4 -4
- package/dist/chunk-3HNKR65T.js.map +1 -0
- package/dist/{chunk-Y2RKOPNC.js → chunk-5YTXYPES.js} +46 -10
- package/dist/chunk-5YTXYPES.js.map +1 -0
- package/dist/{chunk-OVZDFEOR.js → chunk-6QAZ5O6X.js} +2 -2
- package/dist/chunk-6QAZ5O6X.js.map +1 -0
- package/dist/{chunk-RTZVQAJ7.js → chunk-6QE4DUYC.js} +19 -4
- package/dist/chunk-6QE4DUYC.js.map +1 -0
- package/dist/{chunk-7Q5PLD5C.js → chunk-7MRT7EPB.js} +3 -3
- package/dist/{chunk-E535SAN4.js → chunk-7PH4OPBZ.js} +4258 -520
- package/dist/chunk-7PH4OPBZ.js.map +1 -0
- package/dist/{chunk-PEULZC6M.js → chunk-A3JMGXPG.js} +8 -1
- package/dist/chunk-A3JMGXPG.js.map +1 -0
- package/dist/{chunk-UMLVJTYV.js → chunk-ADB7GPM3.js} +7 -4
- package/dist/chunk-ADB7GPM3.js.map +1 -0
- package/dist/{chunk-G6FRSBKK.js → chunk-AI4USDRI.js} +4 -4
- package/dist/chunk-BZW5IL43.js +151 -0
- package/dist/chunk-BZW5IL43.js.map +1 -0
- package/dist/chunk-C2RJVZZL.js +123 -0
- package/dist/chunk-C2RJVZZL.js.map +1 -0
- package/dist/{chunk-UND4XIB6.js → chunk-C6W5KVDV.js} +52 -38
- package/dist/chunk-C6W5KVDV.js.map +1 -0
- package/dist/chunk-CQYEDODS.js +125 -0
- package/dist/chunk-CQYEDODS.js.map +1 -0
- package/dist/{chunk-NWZ3I6R6.js → chunk-EYK72OTL.js} +5 -5
- package/dist/{chunk-7BUTTVMR.js → chunk-F5GWNSE2.js} +2 -2
- package/dist/{chunk-AHPFONIL.js → chunk-F5ILTHMU.js} +5 -5
- package/dist/{chunk-Q6W2CMEJ.js → chunk-FRRJIUSI.js} +18 -5
- package/dist/chunk-FRRJIUSI.js.map +1 -0
- package/dist/{chunk-YMYK7US4.js → chunk-GJTKMME7.js} +2 -2
- package/dist/chunk-GJTKMME7.js.map +1 -0
- package/dist/{chunk-EUYOGYGV.js → chunk-HYJMAV53.js} +6 -6
- package/dist/chunk-HYJMAV53.js.map +1 -0
- package/dist/{chunk-QPEXPHJR.js → chunk-I3IYTUUI.js} +4 -4
- package/dist/{chunk-3QAKZ37R.js → chunk-IVZWHIEK.js} +5 -5
- package/dist/{chunk-PLI5TV7N.js → chunk-IW4L4X65.js} +2 -2
- package/dist/chunk-IW4L4X65.js.map +1 -0
- package/dist/{chunk-3Z2TPHC4.js → chunk-IY24WS2P.js} +69 -5
- package/dist/chunk-IY24WS2P.js.map +1 -0
- package/dist/{chunk-HXJXPZRE.js → chunk-J6RGRZOY.js} +10 -3
- package/dist/chunk-J6RGRZOY.js.map +1 -0
- package/dist/{chunk-3S4BJX25.js → chunk-JBBWALNI.js} +2 -2
- package/dist/chunk-JBBWALNI.js.map +1 -0
- package/dist/{chunk-7Z23ZFLV.js → chunk-JDCPRJVS.js} +5 -5
- package/dist/chunk-JDCPRJVS.js.map +1 -0
- package/dist/{chunk-243PNUA6.js → chunk-JOK73NDT.js} +3 -3
- package/dist/chunk-JTI57WRT.js +164 -0
- package/dist/chunk-JTI57WRT.js.map +1 -0
- package/dist/{chunk-VRBCTEKQ.js → chunk-JYNH4FIM.js} +233 -11
- package/dist/chunk-JYNH4FIM.js.map +1 -0
- package/dist/{chunk-TBKOGSYR.js → chunk-KOAJ3TZM.js} +27 -5
- package/dist/chunk-KOAJ3TZM.js.map +1 -0
- package/dist/{chunk-YTXSFG3C.js → chunk-MBXKRHSS.js} +50 -20
- package/dist/chunk-MBXKRHSS.js.map +1 -0
- package/dist/{chunk-MUWOSVEP.js → chunk-NSXNXLYM.js} +10 -2
- package/dist/chunk-NSXNXLYM.js.map +1 -0
- package/dist/{chunk-J4KLMEUL.js → chunk-NV4IHBZS.js} +664 -51
- package/dist/chunk-NV4IHBZS.js.map +1 -0
- package/dist/{chunk-LRAZDV5X.js → chunk-O5XKZCUD.js} +31 -8
- package/dist/chunk-O5XKZCUD.js.map +1 -0
- package/dist/{chunk-W3XXT26A.js → chunk-OTWT6BAJ.js} +358 -3
- package/dist/chunk-OTWT6BAJ.js.map +1 -0
- package/dist/{chunk-XG3PTSCD.js → chunk-PDVP3C2I.js} +1 -1
- package/dist/chunk-PDVP3C2I.js.map +1 -0
- package/dist/{chunk-GIV6DWBG.js → chunk-S45MDEEF.js} +44 -5
- package/dist/chunk-S45MDEEF.js.map +1 -0
- package/dist/{chunk-VK5EER6C.js → chunk-SQKAECUL.js} +2 -2
- package/dist/{chunk-FAQVNJD4.js → chunk-SQOK5UM6.js} +12 -2
- package/dist/{chunk-FAQVNJD4.js.map → chunk-SQOK5UM6.js.map} +1 -1
- package/dist/chunk-STNPB3UM.js +9 -0
- package/dist/chunk-STNPB3UM.js.map +1 -0
- package/dist/{chunk-YS3POABP.js → chunk-TA6HPKWQ.js} +1 -1
- package/dist/chunk-TA6HPKWQ.js.map +1 -0
- package/dist/{chunk-4HIL6AHQ.js → chunk-TAMRU7A2.js} +4 -4
- package/dist/{chunk-QXQRKXCU.js → chunk-TGIJTNM3.js} +2 -2
- package/dist/chunk-TNH5SLCD.js +361 -0
- package/dist/chunk-TNH5SLCD.js.map +1 -0
- package/dist/{chunk-VPSUZLOJ.js → chunk-TYMDCIQM.js} +31 -5
- package/dist/chunk-TYMDCIQM.js.map +1 -0
- package/dist/chunk-U2XSUCDF.js +524 -0
- package/dist/chunk-U2XSUCDF.js.map +1 -0
- package/dist/{chunk-3Y53S2SA.js → chunk-UU6M64HI.js} +4 -4
- package/dist/{chunk-VCGTOS2A.js → chunk-WE2BUQD2.js} +3 -3
- package/dist/chunk-WE2BUQD2.js.map +1 -0
- package/dist/{chunk-JYQTXEIO.js → chunk-WWVJXBOT.js} +449 -29
- package/dist/chunk-WWVJXBOT.js.map +1 -0
- package/dist/chunk-YPIOFSN3.js +129 -0
- package/dist/chunk-YPIOFSN3.js.map +1 -0
- package/dist/chunk-ZC7J6ZYV.js +7 -0
- package/dist/chunk-ZC7J6ZYV.js.map +1 -0
- package/dist/{chunk-5ZGZ6HIZ.js → chunk-ZONKSLF2.js} +30 -7
- package/dist/chunk-ZONKSLF2.js.map +1 -0
- package/dist/consent/index.cjs.map +1 -1
- package/dist/consent/index.d.cts +8 -6
- package/dist/consent/index.d.ts +8 -6
- package/dist/consent/index.js +3 -3
- package/dist/{crypto-5ZDIY3NG.js → crypto-456N7UVX.js} +7 -3
- package/dist/{delegation-QYXZW25W.js → delegation-DP4COTXB.js} +5 -5
- package/dist/derivations/index.cjs +124 -6
- package/dist/derivations/index.cjs.map +1 -1
- package/dist/derivations/index.d.cts +11 -9
- package/dist/derivations/index.d.ts +11 -9
- package/dist/derivations/index.js +8 -6
- package/dist/{dev-unlock-DQCNDfFp.d.cts → dev-unlock-CY0HIZA0.d.cts} +1 -1
- package/dist/{dev-unlock-utkybTKb.d.ts → dev-unlock-CpKSkl2c.d.ts} +1 -1
- package/dist/discriminant-BN9REW3o.d.cts +60 -0
- package/dist/discriminant-BN9REW3o.d.ts +60 -0
- package/dist/errors-Dkc_fi-S.d.cts +1467 -0
- package/dist/errors-Dkc_fi-S.d.ts +1467 -0
- package/dist/executor-4IEW4KG5.js +8 -0
- package/dist/executor-KYJCJCIN.js +12 -0
- package/dist/executor-W7VIBOBZ.js +8 -0
- package/dist/{fanout-sidecar-VJ52RIEY.js → fanout-sidecar-YXNAEZ33.js} +2 -2
- package/dist/fanout-sidecar-YXNAEZ33.js.map +1 -0
- package/dist/forget/index.cjs +43 -0
- package/dist/forget/index.cjs.map +1 -0
- package/dist/forget/index.d.cts +1 -0
- package/dist/forget/index.d.ts +1 -0
- package/dist/forget/index.js +14 -0
- package/dist/guards/index.cjs +144 -4
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.d.cts +16 -8
- package/dist/guards/index.d.ts +16 -8
- package/dist/guards/index.js +13 -7
- package/dist/{hash-jDowCrK2.d.cts → hash-BSd0-_L8.d.cts} +1 -1
- package/dist/{hash-DcoYWfJ_.d.ts → hash-BnBQx39y.d.ts} +1 -1
- package/dist/history/index.cjs +28 -5
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +9 -7
- package/dist/history/index.d.ts +9 -7
- package/dist/history/index.js +9 -7
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.cjs +356 -26
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +8 -6
- package/dist/i18n/index.d.ts +8 -6
- package/dist/i18n/index.js +36 -15
- package/dist/i18n/index.js.map +1 -1
- package/dist/index-BMmajblo.d.cts +362 -0
- package/dist/index-BMmajblo.d.ts +362 -0
- package/dist/{index-BCKdioeh.d.ts → index-Bm9hIY7t.d.ts} +169 -1127
- package/dist/{index-BMjrzNZr.d.cts → index-tZqVB9g5.d.cts} +169 -1127
- package/dist/index.cjs +10286 -2168
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +258 -23
- package/dist/index.d.ts +258 -23
- package/dist/index.js +443 -110
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.cjs +97 -32
- package/dist/indexing/index.cjs.map +1 -1
- package/dist/indexing/index.d.cts +3 -3
- package/dist/indexing/index.d.ts +3 -3
- package/dist/indexing/index.js +4 -4
- package/dist/issue-JXC6T2QR.js +12 -0
- package/dist/{lazy-builder-Rpd-V3jP.d.ts → lazy-builder-ChSqcF5t.d.ts} +2 -2
- package/dist/{lazy-builder-C-rPfWG0.d.cts → lazy-builder-eYZzLEL1.d.cts} +2 -2
- package/dist/{ledger-3IU5GMXA.js → ledger-I7JUYP4L.js} +6 -6
- package/dist/materialized-views/index.cjs +687 -13
- package/dist/materialized-views/index.cjs.map +1 -1
- package/dist/materialized-views/index.d.cts +23 -20
- package/dist/materialized-views/index.d.ts +23 -20
- package/dist/materialized-views/index.js +8 -7
- package/dist/mime-magic-BnJCGJzB.d.cts +103 -0
- package/dist/mime-magic-CjSyakO4.d.ts +103 -0
- package/dist/noydb-ZZCRF6TE.js +38 -0
- package/dist/overlay-views/index.cjs +58 -18
- package/dist/overlay-views/index.cjs.map +1 -1
- package/dist/overlay-views/index.d.cts +32 -12
- package/dist/overlay-views/index.d.ts +32 -12
- package/dist/overlay-views/index.js +6 -6
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +8 -6
- package/dist/periods/index.d.ts +8 -6
- package/dist/periods/index.js +6 -6
- package/dist/{predicate-Dnu81tsS.d.cts → predicate-BmhBSPCH.d.cts} +87 -5
- package/dist/{predicate-Dnu81tsS.d.ts → predicate-BmhBSPCH.d.ts} +87 -5
- package/dist/{public-envelope-U3CMEOMV.js → public-envelope-5XRTUNKF.js} +4 -4
- package/dist/query/index.cjs +1438 -130
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +4 -3
- package/dist/query/index.d.ts +4 -3
- package/dist/query/index.js +13 -6
- package/dist/read-only-facade-EX6WZZBP.js +7 -0
- package/dist/registry-ATRHOG5B.js +8 -0
- package/dist/registry-DKEXOJVO.js +7 -0
- package/dist/registry-LEHB26TY.js +8 -0
- package/dist/{registry-3ALP62P6.js → registry-NWHOLD5M.js} +3 -3
- package/dist/{revoke-KY2GB4KP.js → revoke-5IEK22KT.js} +6 -6
- package/dist/sealed-record/index.cjs +139 -0
- package/dist/sealed-record/index.cjs.map +1 -0
- package/dist/sealed-record/index.d.cts +123 -0
- package/dist/sealed-record/index.d.ts +123 -0
- package/dist/sealed-record/index.js +42 -0
- package/dist/sealed-record/index.js.map +1 -0
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +9 -7
- package/dist/session/index.d.ts +9 -7
- package/dist/session/index.js +3 -3
- package/dist/shadow/index.cjs.map +1 -1
- package/dist/shadow/index.d.cts +8 -6
- package/dist/shadow/index.d.ts +8 -6
- package/dist/shadow/index.js +2 -2
- package/dist/{signer-GRI5TZKH.js → signer-I6YARZQA.js} +5 -5
- package/dist/snapshots/index.cjs +937 -0
- package/dist/snapshots/index.cjs.map +1 -0
- package/dist/snapshots/index.d.cts +30 -0
- package/dist/snapshots/index.d.ts +30 -0
- package/dist/snapshots/index.js +152 -0
- package/dist/snapshots/index.js.map +1 -0
- package/dist/{stale-OTOF3FH7.js → stale-CPESGAPL.js} +2 -2
- package/dist/stale-CPESGAPL.js.map +1 -0
- package/dist/state-vault-JR3CFGNP.js +14 -0
- package/dist/state-vault-JR3CFGNP.js.map +1 -0
- package/dist/store/index.cjs +8 -0
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +15 -6
- package/dist/store/index.d.ts +15 -6
- package/dist/store/index.js +2 -2
- package/dist/{strategy-DSTrsZ8t.d.ts → strategy-54eIwox5.d.ts} +456 -7
- package/dist/{strategy-DSTrsZ8t.d.cts → strategy-WtB-jXYv.d.cts} +456 -7
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +7 -5
- package/dist/sync/index.d.ts +7 -5
- package/dist/sync/index.js +4 -4
- package/dist/team/index.cjs +1 -1
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +8 -6
- package/dist/team/index.d.ts +8 -6
- package/dist/team/index.js +8 -8
- package/dist/transition-guard-D4bfIAiW.d.ts +165 -0
- package/dist/transition-guard-Dmpqzg-_.d.cts +165 -0
- package/dist/tx/index.cjs +155 -5
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +27 -9
- package/dist/tx/index.d.ts +27 -9
- package/dist/tx/index.js +61 -4
- package/dist/tx/index.js.map +1 -1
- package/dist/{types-BoFFiskX.d.ts → types-DLfWFr6U.d.ts} +3997 -1262
- package/dist/{types-DJG8HG6F.d.cts → types-DyOI6XZ_.d.cts} +3997 -1262
- package/dist/{ulid-BmBgooGm.d.ts → ulid-B2L_aqVA.d.ts} +19 -19
- package/dist/{ulid-C7ms9oli.d.cts → ulid-LaxfH2tK.d.cts} +19 -19
- package/dist/util/index.cjs +7 -0
- package/dist/util/index.cjs.map +1 -1
- package/dist/util/index.d.cts +2 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.js +5 -1
- package/dist/util/index.js.map +1 -1
- package/dist/vault-group-BB246VIM.js +804 -0
- package/dist/vault-group-BB246VIM.js.map +1 -0
- package/dist/{with-materialized-view-CqnRwI2S.d.ts → with-materialized-view-CeZYGJVf.d.cts} +2 -2
- package/dist/{with-materialized-view-BbEPFIIJ.d.cts → with-materialized-view-DNULSxoP.d.ts} +2 -2
- package/dist/{with-overlayed-view-Ct1fSJt-.d.ts → with-overlayed-view-C9joG7UZ.d.ts} +2 -2
- package/dist/{with-overlayed-view-bwlmmFjx.d.cts → with-overlayed-view-kdcPGHih.d.cts} +2 -2
- package/dist/with-rollup-DJDbrxjf.d.ts +47 -0
- package/dist/with-rollup-s58XAeWO.d.cts +47 -0
- package/package.json +35 -4
- package/dist/chunk-2PAQNPE3.js.map +0 -1
- package/dist/chunk-3S4BJX25.js.map +0 -1
- package/dist/chunk-3XHOCQK4.js +0 -118
- package/dist/chunk-3XHOCQK4.js.map +0 -1
- package/dist/chunk-3Z2TPHC4.js.map +0 -1
- package/dist/chunk-5ZGZ6HIZ.js.map +0 -1
- package/dist/chunk-7BRE6EUA.js.map +0 -1
- package/dist/chunk-7Z23ZFLV.js.map +0 -1
- package/dist/chunk-CXSCDO5T.js +0 -51
- package/dist/chunk-CXSCDO5T.js.map +0 -1
- package/dist/chunk-E535SAN4.js.map +0 -1
- package/dist/chunk-EUYOGYGV.js.map +0 -1
- package/dist/chunk-GIV6DWBG.js.map +0 -1
- package/dist/chunk-HXJXPZRE.js.map +0 -1
- package/dist/chunk-J4KLMEUL.js.map +0 -1
- package/dist/chunk-JYQTXEIO.js.map +0 -1
- package/dist/chunk-LRAZDV5X.js.map +0 -1
- package/dist/chunk-MRIBLZL3.js +0 -86
- package/dist/chunk-MRIBLZL3.js.map +0 -1
- package/dist/chunk-MUWOSVEP.js.map +0 -1
- package/dist/chunk-OVZDFEOR.js.map +0 -1
- package/dist/chunk-PEULZC6M.js.map +0 -1
- package/dist/chunk-PFSNOPBQ.js.map +0 -1
- package/dist/chunk-PLI5TV7N.js.map +0 -1
- package/dist/chunk-Q6W2CMEJ.js.map +0 -1
- package/dist/chunk-RTZVQAJ7.js.map +0 -1
- package/dist/chunk-TBKOGSYR.js.map +0 -1
- package/dist/chunk-UMLVJTYV.js.map +0 -1
- package/dist/chunk-UND4XIB6.js.map +0 -1
- package/dist/chunk-VCGTOS2A.js.map +0 -1
- package/dist/chunk-VE6YVP32.js +0 -19
- package/dist/chunk-VE6YVP32.js.map +0 -1
- package/dist/chunk-VPSUZLOJ.js.map +0 -1
- package/dist/chunk-VRBCTEKQ.js.map +0 -1
- package/dist/chunk-W3XXT26A.js.map +0 -1
- package/dist/chunk-XG3PTSCD.js.map +0 -1
- package/dist/chunk-Y2RKOPNC.js.map +0 -1
- package/dist/chunk-YMYK7US4.js.map +0 -1
- package/dist/chunk-YS3POABP.js.map +0 -1
- package/dist/chunk-YTXSFG3C.js.map +0 -1
- package/dist/executor-AS2IDHKZ.js +0 -11
- package/dist/executor-HLXFXNFM.js +0 -8
- package/dist/executor-HN6YBHZ5.js +0 -8
- package/dist/fanout-sidecar-VJ52RIEY.js.map +0 -1
- package/dist/issue-ORP37MVW.js +0 -12
- package/dist/mime-magic-CBBSOkjm.d.cts +0 -50
- package/dist/mime-magic-CBBSOkjm.d.ts +0 -50
- package/dist/noydb-5H3C24GG.js +0 -34
- package/dist/read-only-facade-ITU6L7BL.js +0 -7
- package/dist/registry-7HE6VJGC.js +0 -8
- package/dist/registry-PSIPG2QR.js +0 -8
- package/dist/registry-RFGGMVNJ.js +0 -7
- package/dist/with-derivation-BKXXa8Vt.d.ts +0 -13
- package/dist/with-derivation-BjQ7q4NE.d.cts +0 -13
- package/dist/with-guard-C25yNjzd.d.ts +0 -18
- package/dist/with-guard-DQme5DKE.d.cts +0 -18
- /package/dist/{chunk-7Q5PLD5C.js.map → chunk-7MRT7EPB.js.map} +0 -0
- /package/dist/{chunk-G6FRSBKK.js.map → chunk-AI4USDRI.js.map} +0 -0
- /package/dist/{chunk-NWZ3I6R6.js.map → chunk-EYK72OTL.js.map} +0 -0
- /package/dist/{chunk-7BUTTVMR.js.map → chunk-F5GWNSE2.js.map} +0 -0
- /package/dist/{chunk-AHPFONIL.js.map → chunk-F5ILTHMU.js.map} +0 -0
- /package/dist/{chunk-QPEXPHJR.js.map → chunk-I3IYTUUI.js.map} +0 -0
- /package/dist/{chunk-3QAKZ37R.js.map → chunk-IVZWHIEK.js.map} +0 -0
- /package/dist/{chunk-243PNUA6.js.map → chunk-JOK73NDT.js.map} +0 -0
- /package/dist/{chunk-VK5EER6C.js.map → chunk-SQKAECUL.js.map} +0 -0
- /package/dist/{chunk-4HIL6AHQ.js.map → chunk-TAMRU7A2.js.map} +0 -0
- /package/dist/{chunk-QXQRKXCU.js.map → chunk-TGIJTNM3.js.map} +0 -0
- /package/dist/{chunk-3Y53S2SA.js.map → chunk-UU6M64HI.js.map} +0 -0
- /package/dist/{crypto-5ZDIY3NG.js.map → crypto-456N7UVX.js.map} +0 -0
- /package/dist/{delegation-QYXZW25W.js.map → delegation-DP4COTXB.js.map} +0 -0
- /package/dist/{executor-AS2IDHKZ.js.map → executor-4IEW4KG5.js.map} +0 -0
- /package/dist/{executor-HLXFXNFM.js.map → executor-KYJCJCIN.js.map} +0 -0
- /package/dist/{executor-HN6YBHZ5.js.map → executor-W7VIBOBZ.js.map} +0 -0
- /package/dist/{issue-ORP37MVW.js.map → forget/index.js.map} +0 -0
- /package/dist/{ledger-3IU5GMXA.js.map → issue-JXC6T2QR.js.map} +0 -0
- /package/dist/{noydb-5H3C24GG.js.map → ledger-I7JUYP4L.js.map} +0 -0
- /package/dist/{public-envelope-U3CMEOMV.js.map → noydb-ZZCRF6TE.js.map} +0 -0
- /package/dist/{read-only-facade-ITU6L7BL.js.map → public-envelope-5XRTUNKF.js.map} +0 -0
- /package/dist/{registry-3ALP62P6.js.map → read-only-facade-EX6WZZBP.js.map} +0 -0
- /package/dist/{registry-7HE6VJGC.js.map → registry-ATRHOG5B.js.map} +0 -0
- /package/dist/{registry-PSIPG2QR.js.map → registry-DKEXOJVO.js.map} +0 -0
- /package/dist/{registry-RFGGMVNJ.js.map → registry-LEHB26TY.js.map} +0 -0
- /package/dist/{revoke-KY2GB4KP.js.map → registry-NWHOLD5M.js.map} +0 -0
- /package/dist/{signer-GRI5TZKH.js.map → revoke-5IEK22KT.js.map} +0 -0
- /package/dist/{stale-OTOF3FH7.js.map → signer-I6YARZQA.js.map} +0 -0
package/dist/bundle/index.d.cts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { T as TransferSealPayload } from '../ulid-
|
|
2
|
-
export { C as COMPRESSION_BROTLI, a as COMPRESSION_GZIP, b as COMPRESSION_NONE, c as CompressionAlgo, F as FLAG_COMPRESSED, d as FLAG_HAS_INTEGRITY_HASH, N as NOYDB_BUNDLE_FORMAT_VERSION, e as NOYDB_BUNDLE_MAGIC, f as NOYDB_BUNDLE_PREFIX_BYTES, g as NoydbBundleHeader, h as NoydbBundleReadResult, R as ReadNoydbBundleOptions, W as WriteNoydbBundleOptions, i as encodeBundleHeader, j as generateULID, k as isULID, r as readNoydbBundle, l as readNoydbBundleHeader, m as resetBrotliSupportCache, v as validateBundleHeader, w as writeNoydbBundle } from '../ulid-
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
5
|
-
import '../lazy-builder-
|
|
6
|
-
import '../predicate-
|
|
7
|
-
import '../strategy-
|
|
1
|
+
import { T as TransferSealPayload } from '../ulid-LaxfH2tK.cjs';
|
|
2
|
+
export { C as COMPRESSION_BROTLI, a as COMPRESSION_GZIP, b as COMPRESSION_NONE, c as CompressionAlgo, F as FLAG_COMPRESSED, d as FLAG_HAS_INTEGRITY_HASH, N as NOYDB_BUNDLE_FORMAT_VERSION, e as NOYDB_BUNDLE_MAGIC, f as NOYDB_BUNDLE_PREFIX_BYTES, g as NoydbBundleHeader, h as NoydbBundleReadResult, R as ReadNoydbBundleOptions, W as WriteNoydbBundleOptions, i as encodeBundleHeader, j as generateULID, k as isULID, r as readNoydbBundle, l as readNoydbBundleHeader, m as resetBrotliSupportCache, v as validateBundleHeader, w as writeNoydbBundle } from '../ulid-LaxfH2tK.cjs';
|
|
3
|
+
import { bh as Vault, aW as NoydbStore, bd as SealingKeyProvider, bi as RecoveryEnrollmentInput, bj as ShamirRecoveryProvider } from '../types-DyOI6XZ_.cjs';
|
|
4
|
+
export { t as AdoptionStateError, B as BackupCorruptedError, u as BackupLedgerError, v as BundleIntegrityError, w as BundleSealMismatchError, x as BundleVersionConflictError, P as PartitionExtractionError, y as TransferSealError } from '../errors-Dkc_fi-S.cjs';
|
|
5
|
+
import '../lazy-builder-eYZzLEL1.cjs';
|
|
6
|
+
import '../predicate-BmhBSPCH.cjs';
|
|
7
|
+
import '../strategy-WtB-jXYv.cjs';
|
|
8
8
|
import '../strategy-BSxFXGzb.cjs';
|
|
9
|
+
import '../index-BMmajblo.cjs';
|
|
10
|
+
import '../index-tZqVB9g5.cjs';
|
|
9
11
|
import '@noy-db/attestation';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
|
-
* Transitive-closure FK walker
|
|
14
|
+
* Transitive-closure FK walker. Computes the set of
|
|
13
15
|
* (collection, id) tuples reachable from seed predicates, so a
|
|
14
16
|
* partition extraction ships a referentially-complete subset.
|
|
15
17
|
*
|
|
@@ -48,7 +50,7 @@ interface ClosureResult {
|
|
|
48
50
|
declare function walkClosure(vault: Vault, opts: WalkClosureOptions): Promise<ClosureResult>;
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
|
-
* Partition-extraction dry-run
|
|
53
|
+
* Partition-extraction dry-run. Read-only preview of what an
|
|
52
54
|
* `extractPartition` would move: record counts, byte totals, and the
|
|
53
55
|
* timestamp span per collection — computed from raw encrypted
|
|
54
56
|
* envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.
|
|
@@ -81,7 +83,7 @@ interface ExtractionPreview {
|
|
|
81
83
|
declare function describeExtraction(vault: Vault, opts: WalkClosureOptions): Promise<ExtractionPreview>;
|
|
82
84
|
|
|
83
85
|
/**
|
|
84
|
-
* Partition extraction
|
|
86
|
+
* Partition extraction. Walks the FK closure, re-encrypts
|
|
85
87
|
* the selected records under fresh per-collection DEKs, seals those DEKs
|
|
86
88
|
* under a one-time transfer key, and serializes an unowned
|
|
87
89
|
* `extracted-partition` bundle.
|
|
@@ -96,8 +98,8 @@ interface ExtractPartitionResult {
|
|
|
96
98
|
readonly sealId: string;
|
|
97
99
|
}
|
|
98
100
|
/**
|
|
99
|
-
* Extract a re-keyed, transfer-sealed partition
|
|
100
|
-
* (
|
|
101
|
+
* Extract a re-keyed, transfer-sealed partition. Owner-only
|
|
102
|
+
* (invariant 5): producing a standalone re-keyed vault is an
|
|
101
103
|
* ownership operation. Non-destructive on the source.
|
|
102
104
|
*/
|
|
103
105
|
declare function extractPartition(vault: Vault, opts: WalkClosureOptions & {
|
|
@@ -107,7 +109,7 @@ declare function extractPartition(vault: Vault, opts: WalkClosureOptions & {
|
|
|
107
109
|
}): Promise<ExtractPartitionResult>;
|
|
108
110
|
|
|
109
111
|
/**
|
|
110
|
-
* Reverse of `sealDeks
|
|
112
|
+
* Reverse of `sealDeks`. Imports the transfer key, decrypts the
|
|
111
113
|
* sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and
|
|
112
114
|
* re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a
|
|
113
115
|
* wrong key (AES-GCM auth-tag failure) or malformed payload.
|
|
@@ -135,10 +137,10 @@ interface CreateOwnerStandardOptions {
|
|
|
135
137
|
readonly transferKey: Uint8Array;
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
138
|
-
* Managed-mode owner
|
|
140
|
+
* Managed-mode owner: the passphrase is minted + sealed under
|
|
139
141
|
* a `SealingKeyProvider` (e.g. an `at-*` OS keychain) so the partition
|
|
140
142
|
* auto-unlocks on the recipient's device. Managed mode mandates a strong
|
|
141
|
-
* (Shamir) recovery profile at creation
|
|
143
|
+
* (Shamir) recovery profile at creation, which needs the
|
|
142
144
|
* `shamirRecovery` provider injected.
|
|
143
145
|
*/
|
|
144
146
|
interface CreateOwnerManagedOptions {
|
|
@@ -151,12 +153,12 @@ interface CreateOwnerManagedOptions {
|
|
|
151
153
|
}
|
|
152
154
|
type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions;
|
|
153
155
|
/**
|
|
154
|
-
* Mint the first owner keyring on an adopted-but-unowned partition
|
|
155
|
-
* then destroy the transfer seal
|
|
156
|
+
* Mint the first owner keyring on an adopted-but-unowned partition,
|
|
157
|
+
* then destroy the transfer seal.
|
|
156
158
|
*
|
|
157
159
|
* Standard mode: the recipient supplies a passphrase. Managed mode: the
|
|
158
160
|
* passphrase is minted + sealed under a `SealingKeyProvider` and a strong
|
|
159
|
-
* (Shamir) recovery profile is enrolled
|
|
161
|
+
* (Shamir) recovery profile is enrolled — orchestrated via the existing
|
|
160
162
|
* `openVaultAndEnrollRecovery` ceremony.
|
|
161
163
|
*
|
|
162
164
|
* Either way, reuses `createOwnerKeyring` to derive the KEK + write the base
|
package/dist/bundle/index.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { T as TransferSealPayload } from '../ulid-
|
|
2
|
-
export { C as COMPRESSION_BROTLI, a as COMPRESSION_GZIP, b as COMPRESSION_NONE, c as CompressionAlgo, F as FLAG_COMPRESSED, d as FLAG_HAS_INTEGRITY_HASH, N as NOYDB_BUNDLE_FORMAT_VERSION, e as NOYDB_BUNDLE_MAGIC, f as NOYDB_BUNDLE_PREFIX_BYTES, g as NoydbBundleHeader, h as NoydbBundleReadResult, R as ReadNoydbBundleOptions, W as WriteNoydbBundleOptions, i as encodeBundleHeader, j as generateULID, k as isULID, r as readNoydbBundle, l as readNoydbBundleHeader, m as resetBrotliSupportCache, v as validateBundleHeader, w as writeNoydbBundle } from '../ulid-
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
5
|
-
import '../lazy-builder-
|
|
6
|
-
import '../predicate-
|
|
7
|
-
import '../strategy-
|
|
1
|
+
import { T as TransferSealPayload } from '../ulid-B2L_aqVA.js';
|
|
2
|
+
export { C as COMPRESSION_BROTLI, a as COMPRESSION_GZIP, b as COMPRESSION_NONE, c as CompressionAlgo, F as FLAG_COMPRESSED, d as FLAG_HAS_INTEGRITY_HASH, N as NOYDB_BUNDLE_FORMAT_VERSION, e as NOYDB_BUNDLE_MAGIC, f as NOYDB_BUNDLE_PREFIX_BYTES, g as NoydbBundleHeader, h as NoydbBundleReadResult, R as ReadNoydbBundleOptions, W as WriteNoydbBundleOptions, i as encodeBundleHeader, j as generateULID, k as isULID, r as readNoydbBundle, l as readNoydbBundleHeader, m as resetBrotliSupportCache, v as validateBundleHeader, w as writeNoydbBundle } from '../ulid-B2L_aqVA.js';
|
|
3
|
+
import { bh as Vault, aW as NoydbStore, bd as SealingKeyProvider, bi as RecoveryEnrollmentInput, bj as ShamirRecoveryProvider } from '../types-DLfWFr6U.js';
|
|
4
|
+
export { t as AdoptionStateError, B as BackupCorruptedError, u as BackupLedgerError, v as BundleIntegrityError, w as BundleSealMismatchError, x as BundleVersionConflictError, P as PartitionExtractionError, y as TransferSealError } from '../errors-Dkc_fi-S.js';
|
|
5
|
+
import '../lazy-builder-ChSqcF5t.js';
|
|
6
|
+
import '../predicate-BmhBSPCH.js';
|
|
7
|
+
import '../strategy-54eIwox5.js';
|
|
8
8
|
import '../strategy-BSxFXGzb.js';
|
|
9
|
+
import '../index-BMmajblo.js';
|
|
10
|
+
import '../index-Bm9hIY7t.js';
|
|
9
11
|
import '@noy-db/attestation';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
|
-
* Transitive-closure FK walker
|
|
14
|
+
* Transitive-closure FK walker. Computes the set of
|
|
13
15
|
* (collection, id) tuples reachable from seed predicates, so a
|
|
14
16
|
* partition extraction ships a referentially-complete subset.
|
|
15
17
|
*
|
|
@@ -48,7 +50,7 @@ interface ClosureResult {
|
|
|
48
50
|
declare function walkClosure(vault: Vault, opts: WalkClosureOptions): Promise<ClosureResult>;
|
|
49
51
|
|
|
50
52
|
/**
|
|
51
|
-
* Partition-extraction dry-run
|
|
53
|
+
* Partition-extraction dry-run. Read-only preview of what an
|
|
52
54
|
* `extractPartition` would move: record counts, byte totals, and the
|
|
53
55
|
* timestamp span per collection — computed from raw encrypted
|
|
54
56
|
* envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.
|
|
@@ -81,7 +83,7 @@ interface ExtractionPreview {
|
|
|
81
83
|
declare function describeExtraction(vault: Vault, opts: WalkClosureOptions): Promise<ExtractionPreview>;
|
|
82
84
|
|
|
83
85
|
/**
|
|
84
|
-
* Partition extraction
|
|
86
|
+
* Partition extraction. Walks the FK closure, re-encrypts
|
|
85
87
|
* the selected records under fresh per-collection DEKs, seals those DEKs
|
|
86
88
|
* under a one-time transfer key, and serializes an unowned
|
|
87
89
|
* `extracted-partition` bundle.
|
|
@@ -96,8 +98,8 @@ interface ExtractPartitionResult {
|
|
|
96
98
|
readonly sealId: string;
|
|
97
99
|
}
|
|
98
100
|
/**
|
|
99
|
-
* Extract a re-keyed, transfer-sealed partition
|
|
100
|
-
* (
|
|
101
|
+
* Extract a re-keyed, transfer-sealed partition. Owner-only
|
|
102
|
+
* (invariant 5): producing a standalone re-keyed vault is an
|
|
101
103
|
* ownership operation. Non-destructive on the source.
|
|
102
104
|
*/
|
|
103
105
|
declare function extractPartition(vault: Vault, opts: WalkClosureOptions & {
|
|
@@ -107,7 +109,7 @@ declare function extractPartition(vault: Vault, opts: WalkClosureOptions & {
|
|
|
107
109
|
}): Promise<ExtractPartitionResult>;
|
|
108
110
|
|
|
109
111
|
/**
|
|
110
|
-
* Reverse of `sealDeks
|
|
112
|
+
* Reverse of `sealDeks`. Imports the transfer key, decrypts the
|
|
111
113
|
* sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and
|
|
112
114
|
* re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a
|
|
113
115
|
* wrong key (AES-GCM auth-tag failure) or malformed payload.
|
|
@@ -135,10 +137,10 @@ interface CreateOwnerStandardOptions {
|
|
|
135
137
|
readonly transferKey: Uint8Array;
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
138
|
-
* Managed-mode owner
|
|
140
|
+
* Managed-mode owner: the passphrase is minted + sealed under
|
|
139
141
|
* a `SealingKeyProvider` (e.g. an `at-*` OS keychain) so the partition
|
|
140
142
|
* auto-unlocks on the recipient's device. Managed mode mandates a strong
|
|
141
|
-
* (Shamir) recovery profile at creation
|
|
143
|
+
* (Shamir) recovery profile at creation, which needs the
|
|
142
144
|
* `shamirRecovery` provider injected.
|
|
143
145
|
*/
|
|
144
146
|
interface CreateOwnerManagedOptions {
|
|
@@ -151,12 +153,12 @@ interface CreateOwnerManagedOptions {
|
|
|
151
153
|
}
|
|
152
154
|
type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions;
|
|
153
155
|
/**
|
|
154
|
-
* Mint the first owner keyring on an adopted-but-unowned partition
|
|
155
|
-
* then destroy the transfer seal
|
|
156
|
+
* Mint the first owner keyring on an adopted-but-unowned partition,
|
|
157
|
+
* then destroy the transfer seal.
|
|
156
158
|
*
|
|
157
159
|
* Standard mode: the recipient supplies a passphrase. Managed mode: the
|
|
158
160
|
* passphrase is minted + sealed under a `SealingKeyProvider` and a strong
|
|
159
|
-
* (Shamir) recovery profile is enrolled
|
|
161
|
+
* (Shamir) recovery profile is enrolled — orchestrated via the existing
|
|
160
162
|
* `openVaultAndEnrollRecovery` ceremony.
|
|
161
163
|
*
|
|
162
164
|
* Either way, reuses `createOwnerKeyring` to derive the KEK + write the base
|
package/dist/bundle/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SCHEMAS_COLLECTION,
|
|
3
|
+
resolveManagedSecret
|
|
4
|
+
} from "../chunk-C6W5KVDV.js";
|
|
1
5
|
import {
|
|
2
6
|
COMPRESSION_BROTLI,
|
|
3
7
|
COMPRESSION_GZIP,
|
|
@@ -16,15 +20,12 @@ import {
|
|
|
16
20
|
resetBrotliSupportCache,
|
|
17
21
|
validateBundleHeader,
|
|
18
22
|
writeNoydbBundle
|
|
19
|
-
} from "../chunk-
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
resolveManagedSecret
|
|
23
|
-
} from "../chunk-UND4XIB6.js";
|
|
24
|
-
import "../chunk-243PNUA6.js";
|
|
23
|
+
} from "../chunk-WE2BUQD2.js";
|
|
24
|
+
import "../chunk-JOK73NDT.js";
|
|
25
|
+
import "../chunk-BZW5IL43.js";
|
|
25
26
|
import {
|
|
26
27
|
createOwnerKeyring
|
|
27
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-FRRJIUSI.js";
|
|
28
29
|
import {
|
|
29
30
|
generateULID,
|
|
30
31
|
isULID
|
|
@@ -32,24 +33,26 @@ import {
|
|
|
32
33
|
import {
|
|
33
34
|
LEDGER_COLLECTION,
|
|
34
35
|
LedgerStore
|
|
35
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-JDCPRJVS.js";
|
|
36
37
|
import {
|
|
37
38
|
canonicalJson,
|
|
38
39
|
envelopePayloadHash,
|
|
39
40
|
hashEntry
|
|
40
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-PDVP3C2I.js";
|
|
41
42
|
import {
|
|
42
43
|
NOYDB_BACKUP_VERSION,
|
|
43
44
|
NOYDB_FORMAT_VERSION
|
|
44
|
-
} from "../chunk-
|
|
45
|
+
} from "../chunk-TA6HPKWQ.js";
|
|
45
46
|
import {
|
|
46
47
|
base64ToBuffer,
|
|
47
48
|
bufferToBase64,
|
|
48
49
|
decrypt,
|
|
49
50
|
encrypt,
|
|
50
51
|
generateDEK,
|
|
52
|
+
unwrapCek,
|
|
53
|
+
wrapCek,
|
|
51
54
|
wrapKey
|
|
52
|
-
} from "../chunk-
|
|
55
|
+
} from "../chunk-37VGJM3T.js";
|
|
53
56
|
import {
|
|
54
57
|
AdoptionStateError,
|
|
55
58
|
BackupCorruptedError,
|
|
@@ -60,7 +63,7 @@ import {
|
|
|
60
63
|
PartitionExtractionError,
|
|
61
64
|
TransferSealError,
|
|
62
65
|
ValidationError
|
|
63
|
-
} from "../chunk-
|
|
66
|
+
} from "../chunk-OTWT6BAJ.js";
|
|
64
67
|
|
|
65
68
|
// src/bundle/walk-closure.ts
|
|
66
69
|
async function walkClosure(vault, opts) {
|
|
@@ -217,6 +220,14 @@ async function reKeyClosure(vault, closure) {
|
|
|
217
220
|
for (const id of ids) {
|
|
218
221
|
const env = await adapter.get(vaultName, collectionName, id);
|
|
219
222
|
if (!env) continue;
|
|
223
|
+
if (env._cek !== void 0) {
|
|
224
|
+
const cek = await unwrapCek(env._cek, srcDek);
|
|
225
|
+
const plaintext2 = await decrypt(env._iv, env._data, cek);
|
|
226
|
+
const { iv: iv2, data: data2 } = await encrypt(plaintext2, cek);
|
|
227
|
+
const wrapped = await wrapCek(cek, destDek);
|
|
228
|
+
out[id] = { ...env, _iv: iv2, _data: data2, _cek: wrapped };
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
220
231
|
const plaintext = await decrypt(env._iv, env._data, srcDek);
|
|
221
232
|
const { iv, data } = await encrypt(plaintext, destDek);
|
|
222
233
|
out[id] = { ...env, _iv: iv, _data: data };
|
|
@@ -532,7 +543,7 @@ async function createOwnerOnAdoptedPartition(store, vaultName, opts) {
|
|
|
532
543
|
}
|
|
533
544
|
}
|
|
534
545
|
if (isManaged(opts)) {
|
|
535
|
-
const { createNoydb } = await import("../noydb-
|
|
546
|
+
const { createNoydb } = await import("../noydb-ZZCRF6TE.js");
|
|
536
547
|
const db = await createNoydb({
|
|
537
548
|
store,
|
|
538
549
|
user: userId,
|
package/dist/bundle/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bundle/walk-closure.ts","../../src/bundle/describe-extraction.ts","../../src/bundle/extract-partition.ts","../../src/bundle/adopt-partition.ts"],"sourcesContent":["/**\n * Transitive-closure FK walker (#201). Computes the set of\n * (collection, id) tuples reachable from seed predicates, so a\n * partition extraction ships a referentially-complete subset.\n *\n * Two-phase, plaintext, read-only (runs inside the unlocked vault\n * session — see foundation §13.4 / spec invariant 7):\n * 1. INBOUND expansion: from selected records, pull every record\n * that references them (children travel with parents), to a\n * fixed point.\n * 2. OUTBOUND completion: pull every parent the selected set\n * references (no dangling FKs), transitively, WITHOUT\n * re-expanding inbound from those parents (bounds the closure).\n *\n * The FK graph is auto-derived from the vault's existing RefRegistry\n * (the `ref('target')` declarations on collections) — no hand-written\n * edge list. See the design spec §4.1.\n *\n * @module\n */\nimport type { Vault } from '../vault.js'\nimport { PartitionExtractionError } from '../errors.js'\n\n/** Seed predicate per collection. Records that return true become roots. */\nexport interface WalkClosureOptions {\n readonly seeds: Record<\n string,\n (record: Record<string, unknown>) => boolean | Promise<boolean>\n >\n /** Max fixed-point iterations before throwing. Default 16. */\n readonly maxDepth?: number\n}\n\nexport interface ClosureResult {\n /** collection → set of record ids that travel together. */\n readonly closure: Map<string, Set<string>>\n readonly graph: {\n /** Fixed-point iterations the walk needed to converge. */\n readonly depth: number\n /** True if an edge pointed back to an already-selected node. */\n readonly cyclesDetected: boolean\n }\n}\n\nexport async function walkClosure(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ClosureResult> {\n const closure = new Map<string, Set<string>>()\n\n // Records carry a string `id` by construction (Collection.put(id: string)).\n // A non-string id during the walk means a malformed record — fail loud\n // rather than silently dropping it from the closure (which would leave a\n // dangling FK or a missing child in the extracted bundle).\n const requireStringId = (collection: string, record: Record<string, unknown>): string => {\n const id = record['id']\n if (typeof id !== 'string') {\n throw new PartitionExtractionError(\n `walkClosure: record in collection \"${collection}\" has a non-string ` +\n `id (${typeof id}); cannot include it in the partition closure.`,\n )\n }\n return id\n }\n\n const add = (collection: string, id: string): boolean => {\n let set = closure.get(collection)\n if (!set) {\n set = new Set<string>()\n closure.set(collection, set)\n }\n if (set.has(id)) return false\n set.add(id)\n return true\n }\n\n // Phase 0: evaluate seed predicates.\n for (const [collectionName, predicate] of Object.entries(opts.seeds)) {\n const coll = vault.collection<Record<string, unknown>>(collectionName)\n const records = await coll.list()\n for (const record of records) {\n if (await predicate(record)) {\n add(collectionName, requireStringId(collectionName, record))\n }\n }\n }\n\n const { refRegistry } = vault._introspectState()\n const maxDepth = opts.maxDepth ?? 16\n let cyclesDetected = false\n\n // `depth` counts PRODUCTIVE expansion generations (rounds that added at\n // least one new record), taken as the max over the two phases — i.e. the\n // FK hop-distance the closure needed, not the raw loop-iteration count.\n // The terminal draining pass that adds nothing does not count.\n let inboundDepth = 0\n let outboundDepth = 0\n\n // Phase 1 — INBOUND expansion. Worklist of newly-added (collection,id)\n // whose children we still need to pull.\n let frontier: Array<[string, string]> = []\n for (const [c, ids] of closure) for (const id of ids) frontier.push([c, id])\n\n while (frontier.length > 0) {\n const next: Array<[string, string]> = []\n for (const [collectionName, id] of frontier) {\n // Which collections reference THIS collection, and via which field?\n for (const inbound of refRegistry.getInbound(collectionName)) {\n const childColl = vault.collection<Record<string, unknown>>(inbound.collection)\n // TODO(perf): re-scans the full inbound collection on every frontier\n // element. O(frontier · inboundCollections · records) per depth. Fine\n // at consumer-firm scale (foundation §13.4); revisit with an index or\n // pagination if extraction over very large vaults gets slow.\n const childRecords = await childColl.list()\n for (const child of childRecords) {\n const fk = child[inbound.field]\n // Only scalar FK values can match an id; skip null/objects\n // (mirrors checkIntegrity's scalar guard, vault.ts).\n if (typeof fk !== 'string' && typeof fk !== 'number') continue\n if (String(fk) !== id) continue\n const childId = requireStringId(inbound.collection, child)\n if (add(inbound.collection, childId)) {\n next.push([inbound.collection, childId])\n } else {\n cyclesDetected = true\n }\n }\n }\n }\n if (next.length > 0 && ++inboundDepth > maxDepth) {\n throw new PartitionExtractionError(\n `walkClosure exceeded maxDepth=${maxDepth}; the FK graph may be ` +\n `unexpectedly deep or cyclic. Raise maxDepth or narrow the seeds.`,\n )\n }\n frontier = next\n }\n\n // Phase 2 — OUTBOUND completion. Pull referenced parents so no FK\n // dangles. Transitive over outbound edges only; parents are NOT\n // inbound-expanded (that would drag in unrelated siblings).\n let outboundFrontier: Array<[string, string]> = []\n for (const [c, ids] of closure) for (const id of ids) outboundFrontier.push([c, id])\n\n while (outboundFrontier.length > 0) {\n const next: Array<[string, string]> = []\n for (const [collectionName, id] of outboundFrontier) {\n const outbound = refRegistry.getOutbound(collectionName)\n if (Object.keys(outbound).length === 0) continue\n const coll = vault.collection<Record<string, unknown>>(collectionName)\n const record = await coll.get(id)\n if (!record) continue\n for (const [field, descriptor] of Object.entries(outbound)) {\n const rawId = record[field]\n // Only scalar FK values reference a parent id; skip null/objects.\n if (typeof rawId !== 'string' && typeof rawId !== 'number') continue\n const parentId = String(rawId)\n // Reaching an already-selected parent here is normal DAG\n // convergence (a child referencing its in-scope parent), not a\n // cycle — so do NOT flag cyclesDetected in the outbound phase.\n if (add(descriptor.target, parentId)) {\n next.push([descriptor.target, parentId])\n }\n }\n }\n if (next.length > 0 && ++outboundDepth > maxDepth) {\n throw new PartitionExtractionError(\n `walkClosure exceeded maxDepth=${maxDepth} during outbound completion.`,\n )\n }\n outboundFrontier = next\n }\n\n const depth = Math.max(inboundDepth, outboundDepth)\n\n return { closure, graph: { depth, cyclesDetected } }\n}\n","/**\n * Partition-extraction dry-run (#202). Read-only preview of what an\n * `extractPartition` would move: record counts, byte totals, and the\n * timestamp span per collection — computed from raw encrypted\n * envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.\n *\n * @module\n */\nimport type { Vault } from '../vault.js'\nimport { walkClosure, type WalkClosureOptions } from './walk-closure.js'\n\nexport interface ExtractionPreview {\n readonly totalRecords: number\n /** Sum of serialized encrypted-envelope sizes (bytes). */\n readonly totalBytes: number\n readonly byCollection: ReadonlyArray<{\n readonly name: string\n readonly recordCount: number\n readonly bytes: number\n /** Earliest envelope `_ts` in this collection (lexicographic). */\n readonly oldestTs?: string\n readonly newestTs?: string\n }>\n readonly graph: { readonly depth: number; readonly cyclesDetected: boolean }\n /** Records the walk reached but whose envelope couldn't be read. */\n readonly inaccessible: ReadonlyArray<{ readonly collection: string; readonly id: string }>\n}\n\nexport async function describeExtraction(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ExtractionPreview> {\n const { closure, graph } = await walkClosure(vault, opts)\n\n const { name: vaultName, adapter } = vault._introspectState()\n const encoder = new TextEncoder()\n\n const byCollection: Array<{\n name: string; recordCount: number; bytes: number; oldestTs?: string; newestTs?: string\n }> = []\n const inaccessible: Array<{ collection: string; id: string }> = []\n let totalBytes = 0\n let totalRecords = 0\n\n for (const [collectionName, ids] of closure) {\n let bytes = 0\n let oldestTs: string | undefined\n let newestTs: string | undefined\n let recordCount = 0\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) {\n // Walk reached it (via decrypted list) but the raw store read\n // returned nothing — surface rather than miscount.\n inaccessible.push({ collection: collectionName, id })\n continue\n }\n recordCount++\n bytes += encoder.encode(JSON.stringify(env)).length\n const ts = env._ts\n if (oldestTs === undefined || ts < oldestTs) oldestTs = ts\n if (newestTs === undefined || ts > newestTs) newestTs = ts\n }\n\n byCollection.push({\n name: collectionName,\n recordCount,\n bytes,\n // Spread conditionally — exactOptionalPropertyTypes forbids an\n // explicit `undefined` on an optional property.\n ...(oldestTs !== undefined ? { oldestTs } : {}),\n ...(newestTs !== undefined ? { newestTs } : {}),\n })\n totalBytes += bytes\n totalRecords += recordCount\n }\n\n byCollection.sort((a, b) => a.name.localeCompare(b.name))\n\n return Object.freeze({\n totalRecords,\n totalBytes,\n byCollection,\n graph,\n inaccessible,\n })\n}\n","/**\n * Partition extraction (#203 + #206). Walks the FK closure, re-encrypts\n * the selected records under fresh per-collection DEKs, seals those DEKs\n * under a one-time transfer key, and serializes an unowned\n * `extracted-partition` bundle.\n *\n * @module\n */\nimport type { Vault } from '../vault.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport { NOYDB_BACKUP_VERSION } from '../types.js'\nimport { decrypt, encrypt, generateDEK, bufferToBase64 } from '../crypto.js'\nimport { PartitionExtractionError } from '../errors.js'\nimport { walkClosure, type WalkClosureOptions } from './walk-closure.js'\nimport { generateULID } from './ulid.js'\nimport { SCHEMAS_COLLECTION } from '../persisted-schemas/storage.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport { LEDGER_COLLECTION } from '../history/ledger/constants.js'\nimport { canonicalJson, hashEntry } from '../history/ledger/entry.js'\nimport type { LedgerEntry } from '../history/ledger/entry.js'\nimport { envelopePayloadHash } from '../history/ledger/hash.js'\nimport {\n assembleBundleContainer,\n buildExtractedPartitionWrapper,\n type TransferSealPayload,\n} from './bundle.js'\n\n/** Re-keyed collections snapshot + the fresh DEKs used. */\nexport interface ReKeyResult {\n readonly collections: Record<string, Record<string, EncryptedEnvelope>>\n readonly deks: Map<string, CryptoKey>\n}\n\n/**\n * Re-encrypt every record in `closure` under a fresh per-collection DEK.\n * Reads raw source envelopes, decrypts under the source DEK, re-encrypts\n * under the new DEK. Plaintext-pipeline: requires an unlocked vault.\n */\nexport async function reKeyClosure(\n vault: Vault,\n closure: Map<string, Set<string>>,\n): Promise<ReKeyResult> {\n const { name: vaultName, adapter, getDEK } = vault._introspectState()\n const collections: Record<string, Record<string, EncryptedEnvelope>> = {}\n const deks = new Map<string, CryptoKey>()\n\n for (const [collectionName, ids] of closure) {\n const srcDek = await getDEK(collectionName)\n const destDek = await generateDEK()\n deks.set(collectionName, destDek)\n const out: Record<string, EncryptedEnvelope> = {}\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) continue\n const plaintext = await decrypt(env._iv, env._data, srcDek)\n const { iv, data } = await encrypt(plaintext, destDek)\n out[id] = { ...env, _iv: iv, _data: data }\n }\n collections[collectionName] = out\n }\n\n return { collections, deks }\n}\n\n/**\n * Re-key the persisted JSON Schemas (`_schemas/<collection>`) for the\n * closure collections under the destination DEKs (#204). Returns a\n * `{ collection: envelope }` map for the carried collections that actually\n * have a schema; collections without one are omitted.\n */\nexport async function reKeySchemas(\n vault: Vault,\n closure: Map<string, Set<string>>,\n destDeks: Map<string, CryptoKey>,\n): Promise<Record<string, EncryptedEnvelope>> {\n const { name: vaultName, adapter, getDEK } = vault._introspectState()\n const out: Record<string, EncryptedEnvelope> = {}\n\n for (const collectionName of closure.keys()) {\n const env = await adapter.get(vaultName, SCHEMAS_COLLECTION, collectionName)\n if (!env) continue // collection has no persisted schema — skip\n const destDek = destDeks.get(collectionName)\n if (!destDek) continue\n const srcDek = await getDEK(collectionName)\n const plaintext = await decrypt(env._iv, env._data, srcDek)\n const { iv, data } = await encrypt(plaintext, destDek)\n out[collectionName] = { ...env, _iv: iv, _data: data }\n }\n return out\n}\n\nconst paddedIndex = (n: number): string => String(n).padStart(10, '0')\n\nexport interface ReKeyLedgerResult {\n /** { paddedIndex: re-encrypted entry envelope } for backup._internal._ledger. */\n readonly entries: Record<string, EncryptedEnvelope>\n /** Recomputed ledgerHead for the carried chain (index -1 when empty). */\n readonly head: { hash: string; index: number; ts: string }\n}\n\n/**\n * Build the carried `_ledger` chain for an extracted partition (#205, slice 1).\n * Filters source entries to the closure, RE-CHAINS them (fresh index + prevHash),\n * and re-encrypts under `ledgerDek`. The `payloadHash` is recomputed against the\n * re-keyed envelope ONLY for the latest `put` per (collection,id) — the entry\n * `verifyBackupIntegrity` cross-checks; earlier puts + deletes keep their source\n * `payloadHash` verbatim (recomputing an intermediate put would assert a false\n * hash for an older version). Amendments + out-of-closure entries are dropped;\n * `_ledger_deltas`/`_history` are deferred to slice 2.\n */\nexport async function reKeyLedger(\n vault: Vault,\n closure: Map<string, Set<string>>,\n reKeyedCollections: Record<string, Record<string, EncryptedEnvelope>>,\n ledgerDek: CryptoKey,\n): Promise<ReKeyLedgerResult> {\n const { name: vaultName, adapter, getDEK } = vault._introspectState()\n const srcLedgerDek = await getDEK(LEDGER_COLLECTION)\n\n // 1. Load + decrypt source entries in index order.\n const ids = (await adapter.list(vaultName, LEDGER_COLLECTION)).sort()\n const srcEntries: LedgerEntry[] = []\n for (const id of ids) {\n const env = await adapter.get(vaultName, LEDGER_COLLECTION, id)\n if (!env) continue\n srcEntries.push(JSON.parse(await decrypt(env._iv, env._data, srcLedgerDek)) as LedgerEntry)\n }\n\n // 2. Keep closure put/delete entries (drop amendments + out-of-closure).\n const kept = srcEntries.filter(\n (e) => (e.op === 'put' || e.op === 'delete') && (closure.get(e.collection)?.has(e.id) ?? false),\n )\n\n // 3a. Reverse pass: index of the LATEST put per (collection,id).\n const latestPutIndex = new Map<string, number>()\n for (let i = kept.length - 1; i >= 0; i--) {\n const e = kept[i]!\n if (e.op !== 'put') continue\n const key = `${e.collection}/${e.id}`\n if (!latestPutIndex.has(key)) latestPutIndex.set(key, i)\n }\n\n // 3b. Forward re-chain + re-encrypt.\n const entries: Record<string, EncryptedEnvelope> = {}\n let prevHash = ''\n let last: LedgerEntry | undefined\n for (let i = 0; i < kept.length; i++) {\n const src = kept[i]!\n const key = `${src.collection}/${src.id}`\n const isLatestPut = src.op === 'put' && latestPutIndex.get(key) === i\n const reKeyedEnv = reKeyedCollections[src.collection]?.[src.id]\n const payloadHash = isLatestPut && reKeyedEnv\n ? await envelopePayloadHash(reKeyedEnv)\n : src.payloadHash\n const entry: LedgerEntry = {\n index: i,\n prevHash,\n op: src.op,\n collection: src.collection,\n id: src.id,\n version: src.version,\n ts: src.ts,\n actor: src.actor,\n payloadHash,\n ...(src.reason !== undefined ? { reason: src.reason } : {}),\n }\n const { iv, data } = await encrypt(canonicalJson(entry), ledgerDek)\n entries[paddedIndex(i)] = {\n _noydb: NOYDB_FORMAT_VERSION, _v: i + 1, _ts: entry.ts, _iv: iv, _data: data, _by: entry.actor,\n }\n prevHash = await hashEntry(entry)\n last = entry\n }\n\n return {\n entries,\n head: last ? { hash: prevHash, index: last.index, ts: last.ts } : { hash: '', index: -1, ts: '' },\n }\n}\n\n/** A minted transfer key (raw 32 bytes) + the seal carrying the DEK set. */\nexport interface SealResult {\n readonly seal: TransferSealPayload\n readonly transferKey: Uint8Array\n}\n\n/**\n * Mint a random 32-byte transfer key, export each DEK to raw bytes, and\n * AES-256-GCM-seal the `{ collection: base64(rawDEK) }` map under the\n * transfer key. The transfer key is returned to the caller out-of-band;\n * only the sealed bytes travel in the bundle. Layout: iv(12) ‖ ct ‖ tag.\n */\nexport async function sealDeks(deks: Map<string, CryptoKey>): Promise<SealResult> {\n const dekMap: Record<string, string> = {}\n for (const [collection, dek] of deks) {\n const raw = await crypto.subtle.exportKey('raw', dek)\n dekMap[collection] = bufferToBase64(raw)\n }\n\n const transferKey = crypto.getRandomValues(new Uint8Array(32))\n const key = await crypto.subtle.importKey('raw', transferKey, 'AES-GCM', false, ['encrypt'])\n const iv = crypto.getRandomValues(new Uint8Array(12))\n const plaintext = new TextEncoder().encode(JSON.stringify(dekMap))\n const ct = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext)\n\n const combined = new Uint8Array(iv.byteLength + ct.byteLength)\n combined.set(iv, 0)\n combined.set(new Uint8Array(ct), iv.byteLength)\n\n const sealId = bufferToBase64(crypto.getRandomValues(new Uint8Array(12)))\n return {\n seal: { v: 1, alg: 'aes-256-gcm-pre-shared', sealId, payload: bufferToBase64(combined) },\n transferKey,\n }\n}\n\nexport interface ExtractPartitionResult {\n readonly bundleBytes: Uint8Array\n /** Raw 32-byte transfer key — deliver out-of-band; required to adopt. */\n readonly transferKey: Uint8Array\n readonly sealId: string\n}\n\n/**\n * Extract a re-keyed, transfer-sealed partition (#203 + #206). Owner-only\n * (#198 invariant 5): producing a standalone re-keyed vault is an\n * ownership operation. Non-destructive on the source.\n */\nexport async function extractPartition(\n vault: Vault,\n opts: WalkClosureOptions & {\n readonly compression?: 'auto' | 'brotli' | 'gzip' | 'none'\n readonly carrySchemas?: boolean\n readonly carryLedger?: boolean\n },\n): Promise<ExtractPartitionResult> {\n if (vault.role !== 'owner') {\n throw new PartitionExtractionError(\n `extractPartition requires the 'owner' role on the source vault; caller is '${vault.role}'. `\n + `Producing a re-keyed standalone partition is an ownership operation.`,\n )\n }\n\n // Persisted-schema writes (collection({ persistJsonSchema: true })) are fire-\n // and-forget queued onto vault._pendingSchemaWrites — a caller that does\n // `collection() → put() → extractPartition({ carrySchemas: true })` in quick\n // succession can hit a window where _schemas/<col> is not yet on disk and\n // reKeySchemas silently drops the row. Drain BEFORE reKeySchemas reads.\n if (opts.carrySchemas) await vault._drainPendingSchemaWrites()\n\n const { closure } = await walkClosure(vault, opts)\n const { collections, deks } = await reKeyClosure(vault, closure)\n\n // carryLedger (#205): mint a fresh _ledger DEK, build the carried chain, and\n // SEAL the ledger DEK alongside the data DEKs so #208 wraps it into the\n // recipient keyring (lets them decrypt + verify the chain). Must run BEFORE\n // sealDeks.\n let ledgerHead: { hash: string; index: number; ts: string } | undefined\n let ledgerEntries: Record<string, EncryptedEnvelope> | undefined\n if (opts.carryLedger && vault._getLedgerOrNull() !== null) {\n // Skip when the source vault has no history strategy: reKeyLedger's first\n // `getDEK(LEDGER_COLLECTION)` would auto-mint and persist a phantom\n // _ledger DEK on the source keyring (contradicting \"non-destructive on\n // the source\"), and there's nothing to carry anyway. Mirrors the same\n // null-guard the source audit-append uses below.\n const ledgerDek = await generateDEK()\n const built = await reKeyLedger(vault, closure, collections, ledgerDek)\n if (built.head.index >= 0) {\n ledgerEntries = built.entries\n ledgerHead = built.head\n deks.set(LEDGER_COLLECTION, ledgerDek)\n }\n }\n\n // Build _internal (schemas #204 + ledger #205). reKeySchemas reads data-\n // collection DEKs only, so it is unaffected by the _ledger DEK added above.\n const internalSchemas = opts.carrySchemas ? await reKeySchemas(vault, closure, deks) : {}\n const internal: Record<string, Record<string, EncryptedEnvelope>> = {}\n if (Object.keys(internalSchemas).length > 0) internal[SCHEMAS_COLLECTION] = internalSchemas\n if (ledgerEntries) internal[LEDGER_COLLECTION] = ledgerEntries\n const hasInternal = Object.keys(internal).length > 0\n\n const { seal, transferKey } = await sealDeks(deks)\n\n // Source-side audit (#226 / spec §4.2 / invariant 4): record that a partition\n // was handed over. Non-destructive — an audit append, no record touched.\n // No-op when the source vault has no history strategy. append() fills\n // index/prevHash/ts and (since actor is '') the ledger's configured actor.\n await vault._getLedgerOrNull()?.append({\n op: 'lifecycle',\n collection: '',\n id: '',\n version: 0,\n actor: '',\n payloadHash: '',\n reason: `partition-handed-over:${seal.sealId}`,\n })\n\n // Build the dump JSON: unowned (empty keyrings), empty ledger (default),\n // re-keyed collections only.\n const { name: vaultName } = vault._introspectState()\n const backup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: vaultName,\n _exported_at: new Date().toISOString(),\n _exported_by: '', // unowned — no source user travels\n keyrings: {},\n collections,\n ...(hasInternal ? { _internal: internal } : {}),\n ...(ledgerHead ? { ledgerHead: { hash: ledgerHead.hash, index: ledgerHead.index, ts: ledgerHead.ts } } : {}),\n }\n const bodyJsonStr = JSON.stringify(buildExtractedPartitionWrapper(JSON.stringify(backup), seal))\n\n // An extracted partition is a NEW vault, not a re-export of the source —\n // mint a fresh handle rather than reusing the source's stable ULID\n // (which would collide if a recipient imports both source + partition).\n const handle = generateULID()\n const bundleBytes = await assembleBundleContainer({\n handle,\n bodyJsonStr,\n compression: opts.compression,\n headerExtras: {\n bundleKind: 'extracted-partition',\n transferSeal: { v: seal.v, alg: seal.alg, sealId: seal.sealId }, // indicator only\n },\n })\n\n return { bundleBytes, transferKey, sealId: seal.sealId }\n}\n","/**\n * Partition adoption (#207). Recipient side: verify an extracted bundle,\n * validate the transfer key, import the re-keyed collections into a\n * destination store, and record an `_meta/adoption` marker. The bundle\n * stays UNOWNED after adoption — `createOwnerOnAdoptedPartition` (#208)\n * mints the owner; `#209` destroys the seal.\n *\n * @module\n */\nimport { base64ToBuffer, wrapKey } from '../crypto.js'\nimport { TransferSealError, AdoptionStateError, ValidationError } from '../errors.js'\nimport type { NoydbStore, VaultSnapshot, KeyringFile } from '../types.js'\nimport { createOwnerKeyring } from '../team/keyring.js'\nimport { resolveManagedSecret } from '../team/managed-passphrase.js'\nimport type { SealingKeyProvider } from '../team/managed-passphrase.js'\nimport type { ShamirRecoveryProvider } from '../team/shamir-recovery-provider.js'\nimport type { RecoveryEnrollmentInput } from '../team/rotate-recover.js'\nimport { LedgerStore } from '../history/ledger/store.js'\nimport { LEDGER_COLLECTION } from '../history/ledger/constants.js'\nimport type { TransferSealPayload } from './bundle.js'\nimport { readNoydbBundleHeader, readNoydbBundle, parseExtractedPartitionBody } from './bundle.js'\n\n/**\n * Reverse of `sealDeks` (#206). Imports the transfer key, decrypts the\n * sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and\n * re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a\n * wrong key (AES-GCM auth-tag failure) or malformed payload.\n */\nexport async function unsealDeks(\n seal: TransferSealPayload,\n transferKey: Uint8Array,\n): Promise<Map<string, CryptoKey>> {\n if (transferKey.byteLength !== 32) {\n throw new TransferSealError(\n `transfer key must be 32 bytes, got ${transferKey.byteLength}.`,\n )\n }\n const key = await crypto.subtle.importKey('raw', transferKey as BufferSource, 'AES-GCM', false, ['decrypt'])\n const raw = base64ToBuffer(seal.payload)\n let plaintext: ArrayBuffer\n try {\n plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: raw.slice(0, 12) as BufferSource },\n key,\n raw.slice(12) as BufferSource,\n )\n } catch {\n throw new TransferSealError(\n 'transfer seal could not be opened — wrong transfer key (AES-GCM authentication failed).',\n )\n }\n let dekMap: Record<string, string>\n try {\n dekMap = JSON.parse(new TextDecoder().decode(plaintext)) as Record<string, string>\n } catch {\n throw new TransferSealError('transfer seal payload is not valid JSON after decryption.')\n }\n const deks = new Map<string, CryptoKey>()\n for (const [collection, b64] of Object.entries(dekMap)) {\n // Extractable: the recipient must be able to re-wrap these under their\n // own KEK (AES-KW) at owner-creation (#208). Matches generateDEK.\n const dek = await crypto.subtle.importKey('raw', base64ToBuffer(b64) as BufferSource, 'AES-GCM', true, ['encrypt', 'decrypt'])\n deks.set(collection, dek)\n }\n return deks\n}\n\nexport interface AdoptPartitionOptions {\n readonly transferKey: Uint8Array\n readonly destinationStore: NoydbStore\n readonly vaultName: string\n}\n\nexport interface AdoptPartitionResult {\n readonly vaultName: string\n readonly needsOwner: true\n readonly sealId: string\n}\n\nexport async function adoptPartition(\n bundleBytes: Uint8Array,\n opts: AdoptPartitionOptions,\n): Promise<AdoptPartitionResult> {\n const { transferKey, destinationStore, vaultName } = opts\n\n const header = readNoydbBundleHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new ValidationError(\n 'adoptPartition requires an extracted-partition bundle with a transfer seal. '\n + 'For ordinary backups use readNoydbBundle + vault.load.',\n )\n }\n\n const { dumpJson } = await readNoydbBundle(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n\n // Validate the transfer key by unsealing in memory; throws\n // TransferSealError on mismatch. DEKs are discarded here — they stay\n // sealed at rest (in _meta/adoption) until #208 wraps them under the\n // recipient's KEK.\n await unsealDeks(seal, transferKey)\n\n // Single-occupancy per vaultName: an `_meta/adoption` marker already present\n // means this slot holds a partition (adopted-and-unowned, or already owned).\n // saveAll below would overwrite its data and replace the marker, stranding the\n // prior adoption's transfer seal. Refuse regardless of sealId — re-adopting the\n // SAME bundle is a redundant call, and adopting a DIFFERENT bundle here would\n // clobber the existing partition. Either way, pick a fresh vaultName.\n const existing = await destinationStore.get(vaultName, '_meta', 'adoption')\n if (existing) {\n const prior = JSON.parse(existing._data) as { sealId?: string }\n if (prior.sealId === seal.sealId) {\n throw new AdoptionStateError(\n `partition (sealId ${seal.sealId}) is already adopted into vault \"${vaultName}\".`,\n )\n }\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds an adopted partition (sealId ${prior.sealId}); `\n + `adopting a different partition (sealId ${seal.sealId}) here would overwrite it. `\n + `Adopt into a fresh vaultName instead.`,\n )\n }\n\n // The marker-only check above misses a worse case: a vaultName already in use\n // by an ORDINARY vault (createNoydb + openVault) carries no `_meta/adoption`,\n // yet `saveAll` below is destructive on SQL adapters (`DELETE FROM ... WHERE\n // vault = ?` followed by upsert) and would wipe the legitimate keyring +\n // data. Refuse adoption into ANY occupied slot — a fresh vaultName is the\n // documented precondition.\n const existingKeyring = await destinationStore.list(vaultName, '_keyring')\n if (existingKeyring.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds a keyring (an unrelated owner exists at this slot); `\n + `adoptPartition requires a fresh vaultName to avoid destructive saveAll on SQL adapters.`,\n )\n }\n\n const backup = JSON.parse(dump) as { collections: VaultSnapshot; _internal?: VaultSnapshot }\n await destinationStore.saveAll(vaultName, backup.collections)\n\n // Import carried internal collections (e.g. _schemas from #204 carrySchemas).\n // saveAll only writes data collections; _internal is written per-record.\n if (backup._internal) {\n for (const [collection, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await destinationStore.put(vaultName, collection, id, envelope)\n }\n }\n }\n\n const adoptedAt = new Date().toISOString()\n const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true as const, transferSeal: seal }\n await destinationStore.put(vaultName, '_meta', 'adoption', {\n _noydb: 1, _v: 1, _ts: adoptedAt, _iv: '', _data: JSON.stringify(adoption),\n })\n\n return { vaultName, needsOwner: true, sealId: seal.sealId }\n}\n\nexport interface CreateOwnerResult {\n readonly vaultName: string\n readonly userId: string\n}\n\n/** Standard-mode owner: recipient supplies the passphrase. */\nexport interface CreateOwnerStandardOptions {\n readonly userId: string\n readonly passphrase: string\n readonly transferKey: Uint8Array\n}\n\n/**\n * Managed-mode owner (#208 follow-up): the passphrase is minted + sealed under\n * a `SealingKeyProvider` (e.g. an `at-*` OS keychain) so the partition\n * auto-unlocks on the recipient's device. Managed mode mandates a strong\n * (Shamir) recovery profile at creation (#195), which needs the\n * `shamirRecovery` provider injected.\n */\nexport interface CreateOwnerManagedOptions {\n readonly userId: string\n readonly passphraseMode: 'managed'\n readonly sealingKey: SealingKeyProvider\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly shamirRecovery: ShamirRecoveryProvider\n readonly transferKey: Uint8Array\n}\n\nexport type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions\n\nfunction isManaged(o: CreateOwnerOptions): o is CreateOwnerManagedOptions {\n return 'passphraseMode' in o && o.passphraseMode === 'managed'\n}\n\n/**\n * Mint the first owner keyring on an adopted-but-unowned partition (#208),\n * then destroy the transfer seal (#209).\n *\n * Standard mode: the recipient supplies a passphrase. Managed mode: the\n * passphrase is minted + sealed under a `SealingKeyProvider` and a strong\n * (Shamir) recovery profile is enrolled (#195) — orchestrated via the existing\n * `openVaultAndEnrollRecovery` ceremony.\n *\n * Either way, reuses `createOwnerKeyring` to derive the KEK + write the base\n * keyring, then wraps the partition's DEKs (recovered from the seal) under that\n * KEK and re-persists the merged keyring file.\n *\n * Idempotent under retry: the seal is destroyed LAST (Stage D), after the\n * keyring (Stage A), the ledger transition (Stage B), and — in managed mode —\n * strong-recovery enrollment (Stage C). A failure in the fallible enrollment\n * step leaves the seal intact, and re-running with the same `userId` +\n * `transferKey` resumes from the first incomplete stage. (Multi-profile recovery\n * arrays may re-enroll an already-enrolled profile on retry; managed mode's\n * mandated single Shamir profile does not.)\n */\nexport async function createOwnerOnAdoptedPartition(\n store: NoydbStore,\n vaultName: string,\n opts: CreateOwnerOptions,\n): Promise<CreateOwnerResult> {\n const { userId, transferKey } = opts\n\n // Managed mode requires a strong (Shamir) recovery profile, validated BEFORE\n // any disk write (#195) — same gate as createNoydb.\n if (isManaged(opts) && !opts.recovery.some((r) => r.profile === 'shamir')) {\n throw new AdoptionStateError(\n 'managed-mode adoption requires at least one strong (shamir) recovery profile in '\n + '`recovery` — paper alone is not strong when there is no user passphrase to fall back on.',\n )\n }\n\n // 1. Verify adopted-unowned state.\n const adoptionEnv = await store.get(vaultName, '_meta', 'adoption')\n if (!adoptionEnv) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" is not an adopted partition (no _meta/adoption). `\n + `createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`,\n )\n }\n const adoption = JSON.parse(adoptionEnv._data) as {\n sealId: string; adoptedAt: string; needsOwner?: boolean\n consumedAt?: string; transferSeal?: TransferSealPayload\n }\n if (adoption.consumedAt !== undefined || adoption.transferSeal === undefined) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`,\n )\n }\n\n // 2. Recover the partition DEKs from the seal (throws on wrong key) BEFORE\n // writing any keyring, so a bad transfer key leaves no trace. Always\n // validated, including when resuming a partial prior call.\n const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey)\n\n // The ceremony below is split into stages so a failure in the fallible\n // managed-enrollment step (network/provider outage) leaves the call RETRYABLE\n // — the seal is destroyed only once everything durable is in place. Each stage\n // detects its own prior completion rather than relying on a single resume bit.\n\n // A keyring present for a DIFFERENT user (with the seal still unconsumed) is a\n // genuine second-owner attempt — refuse it. A same-user keyring is a resumed\n // partial call and is handled by the stage checks below.\n const existingKeyring = await store.get(vaultName, '_keyring', userId)\n const otherOwners = (await store.list(vaultName, '_keyring')).filter((u) => u !== userId)\n if (otherOwners.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has a keyring for a different owner; cannot create owner \"${userId}\".`,\n )\n }\n\n // Stage A — mint the owner keyring + merge the partition DEKs. Considered done\n // only when the keyring already holds every partition DEK. createOwnerKeyring\n // overwrites (fresh KEK + fresh _users DEK), so re-running is safe ONLY while\n // no recovery has been enrolled yet — guaranteed here because enrollment\n // (Stage C) runs strictly after Stage A completes.\n const partitionCollections = [...partitionDeks.keys()]\n const priorDeks = existingKeyring ? (JSON.parse(existingKeyring._data) as KeyringFile).deks : {}\n const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks)\n if (!ownerMinted) {\n // Resolve the owner passphrase. Managed mode mints a random passphrase, seals\n // it under the provider, and persists _meta/sealed-passphrase (so the\n // partition auto-unlocks on the recipient's device); standard mode uses the\n // caller's passphrase. Idempotent under retry — resolveManagedSecret's reopen\n // arm reuses an already-sealed passphrase.\n const passphrase = isManaged(opts)\n ? await resolveManagedSecret(store, vaultName, opts.sealingKey)\n : opts.passphrase\n\n // Mint the owner keyring (KEK + _users DEK + canary, written to disk).\n const unlocked = await createOwnerKeyring(store, vaultName, userId, passphrase)\n\n // Merge the partition DEKs (wrapped under the new KEK) into the keyring.\n const env = await store.get(vaultName, '_keyring', userId)\n if (!env) throw new AdoptionStateError(`keyring write for \"${userId}\" did not persist`)\n const keyringFile = JSON.parse(env._data) as KeyringFile\n const kek = unlocked.kek\n if (!kek) throw new AdoptionStateError(`owner keyring for \"${userId}\" has no KEK to wrap partition DEKs under`)\n const mergedDeks: Record<string, string> = { ...keyringFile.deks }\n for (const [collection, dek] of partitionDeks) {\n mergedDeks[collection] = await wrapKey(dek, kek)\n }\n const mergedFile: KeyringFile = { ...keyringFile, deks: mergedDeks }\n await store.put(vaultName, '_keyring', userId, { ...env, _data: JSON.stringify(mergedFile) })\n }\n\n // Stage B — (#226 destination) record the ownership transition on the carried\n // audit chain (carryLedger sealed the _ledger DEK). No-op without that DEK.\n // Idempotent: appended only if the closing `transfer-seal-consumed` entry is\n // absent, so a retry does not duplicate the pair.\n const ledgerDek = partitionDeks.get(LEDGER_COLLECTION)\n if (ledgerDek) {\n const ledger = new LedgerStore({\n adapter: store,\n vault: vaultName,\n encrypted: true,\n getDEK: async () => ledgerDek,\n actor: userId,\n })\n const creationReason = `creation-of-new-owner:${userId}`\n const consumedReason = `transfer-seal-consumed:${adoption.sealId}`\n // Gate each append on its own presence — a crash or store error strictly\n // between the two adjacent puts would otherwise re-append the first one\n // on retry. The pair is the audit record, not a single transaction.\n const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason))\n if (!recordedReasons.has(creationReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: creationReason })\n }\n if (!recordedReasons.has(consumedReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: consumedReason })\n }\n }\n\n // Stage C — Managed mode (#208 follow-up): enroll the mandatory strong recovery\n // (#195) by orchestrating the existing public ceremony. The partition is\n // now a managed-mode vault on disk (sealed passphrase + keyring), so we\n // open it as a normal client and let openVaultAndEnrollRecovery do the\n // gate-bypass + enroll + re-assert. Dynamic import keeps the Noydb class\n // out of the @noy-db/hub/bundle static graph. Runs BEFORE seal destruction\n // so a failure here leaves the seal intact and the call retryable.\n if (isManaged(opts)) {\n const { createNoydb } = await import('../noydb.js')\n const db = await createNoydb({\n store,\n user: userId,\n passphraseMode: 'managed',\n sealingKey: opts.sealingKey,\n shamirRecovery: opts.shamirRecovery,\n })\n await db.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery })\n }\n\n // Stage D — (#209) Destroy the transfer seal LAST — the commit point. Everything\n // above is either idempotent or resumable, so the seal is only consumed\n // once the owner keyring (and, in managed mode, strong recovery) is\n // durably in place. Retain sealId + consumedAt for audit.\n const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: new Date().toISOString() }\n await store.put(vaultName, '_meta', 'adoption', { ...adoptionEnv, _data: JSON.stringify(consumed) })\n\n return { vaultName, userId }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/bundle/walk-closure.ts","../../src/bundle/describe-extraction.ts","../../src/bundle/extract-partition.ts","../../src/bundle/adopt-partition.ts"],"sourcesContent":["/**\n * Transitive-closure FK walker. Computes the set of\n * (collection, id) tuples reachable from seed predicates, so a\n * partition extraction ships a referentially-complete subset.\n *\n * Two-phase, plaintext, read-only (runs inside the unlocked vault\n * session — see foundation §13.4 / spec invariant 7):\n * 1. INBOUND expansion: from selected records, pull every record\n * that references them (children travel with parents), to a\n * fixed point.\n * 2. OUTBOUND completion: pull every parent the selected set\n * references (no dangling FKs), transitively, WITHOUT\n * re-expanding inbound from those parents (bounds the closure).\n *\n * The FK graph is auto-derived from the vault's existing RefRegistry\n * (the `ref('target')` declarations on collections) — no hand-written\n * edge list. See the design spec §4.1.\n *\n * @module\n */\nimport type { Vault } from '../vault.js'\nimport { PartitionExtractionError } from '../errors.js'\n\n/** Seed predicate per collection. Records that return true become roots. */\nexport interface WalkClosureOptions {\n readonly seeds: Record<\n string,\n (record: Record<string, unknown>) => boolean | Promise<boolean>\n >\n /** Max fixed-point iterations before throwing. Default 16. */\n readonly maxDepth?: number\n}\n\nexport interface ClosureResult {\n /** collection → set of record ids that travel together. */\n readonly closure: Map<string, Set<string>>\n readonly graph: {\n /** Fixed-point iterations the walk needed to converge. */\n readonly depth: number\n /** True if an edge pointed back to an already-selected node. */\n readonly cyclesDetected: boolean\n }\n}\n\nexport async function walkClosure(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ClosureResult> {\n const closure = new Map<string, Set<string>>()\n\n // Records carry a string `id` by construction (Collection.put(id: string)).\n // A non-string id during the walk means a malformed record — fail loud\n // rather than silently dropping it from the closure (which would leave a\n // dangling FK or a missing child in the extracted bundle).\n const requireStringId = (collection: string, record: Record<string, unknown>): string => {\n const id = record['id']\n if (typeof id !== 'string') {\n throw new PartitionExtractionError(\n `walkClosure: record in collection \"${collection}\" has a non-string ` +\n `id (${typeof id}); cannot include it in the partition closure.`,\n )\n }\n return id\n }\n\n const add = (collection: string, id: string): boolean => {\n let set = closure.get(collection)\n if (!set) {\n set = new Set<string>()\n closure.set(collection, set)\n }\n if (set.has(id)) return false\n set.add(id)\n return true\n }\n\n // Phase 0: evaluate seed predicates.\n for (const [collectionName, predicate] of Object.entries(opts.seeds)) {\n const coll = vault.collection<Record<string, unknown>>(collectionName)\n const records = await coll.list()\n for (const record of records) {\n if (await predicate(record)) {\n add(collectionName, requireStringId(collectionName, record))\n }\n }\n }\n\n const { refRegistry } = vault._introspectState()\n const maxDepth = opts.maxDepth ?? 16\n let cyclesDetected = false\n\n // `depth` counts PRODUCTIVE expansion generations (rounds that added at\n // least one new record), taken as the max over the two phases — i.e. the\n // FK hop-distance the closure needed, not the raw loop-iteration count.\n // The terminal draining pass that adds nothing does not count.\n let inboundDepth = 0\n let outboundDepth = 0\n\n // Phase 1 — INBOUND expansion. Worklist of newly-added (collection,id)\n // whose children we still need to pull.\n let frontier: Array<[string, string]> = []\n for (const [c, ids] of closure) for (const id of ids) frontier.push([c, id])\n\n while (frontier.length > 0) {\n const next: Array<[string, string]> = []\n for (const [collectionName, id] of frontier) {\n // Which collections reference THIS collection, and via which field?\n for (const inbound of refRegistry.getInbound(collectionName)) {\n const childColl = vault.collection<Record<string, unknown>>(inbound.collection)\n // TODO(perf): re-scans the full inbound collection on every frontier\n // element. O(frontier · inboundCollections · records) per depth. Fine\n // at consumer-firm scale (foundation §13.4); revisit with an index or\n // pagination if extraction over very large vaults gets slow.\n const childRecords = await childColl.list()\n for (const child of childRecords) {\n const fk = child[inbound.field]\n // Only scalar FK values can match an id; skip null/objects\n // (mirrors checkIntegrity's scalar guard, vault.ts).\n if (typeof fk !== 'string' && typeof fk !== 'number') continue\n if (String(fk) !== id) continue\n const childId = requireStringId(inbound.collection, child)\n if (add(inbound.collection, childId)) {\n next.push([inbound.collection, childId])\n } else {\n cyclesDetected = true\n }\n }\n }\n }\n if (next.length > 0 && ++inboundDepth > maxDepth) {\n throw new PartitionExtractionError(\n `walkClosure exceeded maxDepth=${maxDepth}; the FK graph may be ` +\n `unexpectedly deep or cyclic. Raise maxDepth or narrow the seeds.`,\n )\n }\n frontier = next\n }\n\n // Phase 2 — OUTBOUND completion. Pull referenced parents so no FK\n // dangles. Transitive over outbound edges only; parents are NOT\n // inbound-expanded (that would drag in unrelated siblings).\n let outboundFrontier: Array<[string, string]> = []\n for (const [c, ids] of closure) for (const id of ids) outboundFrontier.push([c, id])\n\n while (outboundFrontier.length > 0) {\n const next: Array<[string, string]> = []\n for (const [collectionName, id] of outboundFrontier) {\n const outbound = refRegistry.getOutbound(collectionName)\n if (Object.keys(outbound).length === 0) continue\n const coll = vault.collection<Record<string, unknown>>(collectionName)\n const record = await coll.get(id)\n if (!record) continue\n for (const [field, descriptor] of Object.entries(outbound)) {\n const rawId = record[field]\n // Only scalar FK values reference a parent id; skip null/objects.\n if (typeof rawId !== 'string' && typeof rawId !== 'number') continue\n const parentId = String(rawId)\n // Reaching an already-selected parent here is normal DAG\n // convergence (a child referencing its in-scope parent), not a\n // cycle — so do NOT flag cyclesDetected in the outbound phase.\n if (add(descriptor.target, parentId)) {\n next.push([descriptor.target, parentId])\n }\n }\n }\n if (next.length > 0 && ++outboundDepth > maxDepth) {\n throw new PartitionExtractionError(\n `walkClosure exceeded maxDepth=${maxDepth} during outbound completion.`,\n )\n }\n outboundFrontier = next\n }\n\n const depth = Math.max(inboundDepth, outboundDepth)\n\n return { closure, graph: { depth, cyclesDetected } }\n}\n","/**\n * Partition-extraction dry-run. Read-only preview of what an\n * `extractPartition` would move: record counts, byte totals, and the\n * timestamp span per collection — computed from raw encrypted\n * envelopes WITHOUT decrypting them. Writes nothing, mutates nothing.\n *\n * @module\n */\nimport type { Vault } from '../vault.js'\nimport { walkClosure, type WalkClosureOptions } from './walk-closure.js'\n\nexport interface ExtractionPreview {\n readonly totalRecords: number\n /** Sum of serialized encrypted-envelope sizes (bytes). */\n readonly totalBytes: number\n readonly byCollection: ReadonlyArray<{\n readonly name: string\n readonly recordCount: number\n readonly bytes: number\n /** Earliest envelope `_ts` in this collection (lexicographic). */\n readonly oldestTs?: string\n readonly newestTs?: string\n }>\n readonly graph: { readonly depth: number; readonly cyclesDetected: boolean }\n /** Records the walk reached but whose envelope couldn't be read. */\n readonly inaccessible: ReadonlyArray<{ readonly collection: string; readonly id: string }>\n}\n\nexport async function describeExtraction(\n vault: Vault,\n opts: WalkClosureOptions,\n): Promise<ExtractionPreview> {\n const { closure, graph } = await walkClosure(vault, opts)\n\n const { name: vaultName, adapter } = vault._introspectState()\n const encoder = new TextEncoder()\n\n const byCollection: Array<{\n name: string; recordCount: number; bytes: number; oldestTs?: string; newestTs?: string\n }> = []\n const inaccessible: Array<{ collection: string; id: string }> = []\n let totalBytes = 0\n let totalRecords = 0\n\n for (const [collectionName, ids] of closure) {\n let bytes = 0\n let oldestTs: string | undefined\n let newestTs: string | undefined\n let recordCount = 0\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) {\n // Walk reached it (via decrypted list) but the raw store read\n // returned nothing — surface rather than miscount.\n inaccessible.push({ collection: collectionName, id })\n continue\n }\n recordCount++\n bytes += encoder.encode(JSON.stringify(env)).length\n const ts = env._ts\n if (oldestTs === undefined || ts < oldestTs) oldestTs = ts\n if (newestTs === undefined || ts > newestTs) newestTs = ts\n }\n\n byCollection.push({\n name: collectionName,\n recordCount,\n bytes,\n // Spread conditionally — exactOptionalPropertyTypes forbids an\n // explicit `undefined` on an optional property.\n ...(oldestTs !== undefined ? { oldestTs } : {}),\n ...(newestTs !== undefined ? { newestTs } : {}),\n })\n totalBytes += bytes\n totalRecords += recordCount\n }\n\n byCollection.sort((a, b) => a.name.localeCompare(b.name))\n\n return Object.freeze({\n totalRecords,\n totalBytes,\n byCollection,\n graph,\n inaccessible,\n })\n}\n","/**\n * Partition extraction. Walks the FK closure, re-encrypts\n * the selected records under fresh per-collection DEKs, seals those DEKs\n * under a one-time transfer key, and serializes an unowned\n * `extracted-partition` bundle.\n *\n * @module\n */\nimport type { Vault } from '../vault.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport { NOYDB_BACKUP_VERSION } from '../types.js'\nimport { decrypt, encrypt, generateDEK, bufferToBase64 } from '../crypto.js'\nimport { unwrapCek, wrapCek } from '../record-keys/index.js'\nimport { PartitionExtractionError } from '../errors.js'\nimport { walkClosure, type WalkClosureOptions } from './walk-closure.js'\nimport { generateULID } from './ulid.js'\nimport { SCHEMAS_COLLECTION } from '../persisted-schemas/storage.js'\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport { LEDGER_COLLECTION } from '../history/ledger/constants.js'\nimport { canonicalJson, hashEntry } from '../history/ledger/entry.js'\nimport type { LedgerEntry } from '../history/ledger/entry.js'\nimport { envelopePayloadHash } from '../history/ledger/hash.js'\nimport {\n assembleBundleContainer,\n buildExtractedPartitionWrapper,\n type TransferSealPayload,\n} from './bundle.js'\n\n/** Re-keyed collections snapshot + the fresh DEKs used. */\nexport interface ReKeyResult {\n readonly collections: Record<string, Record<string, EncryptedEnvelope>>\n readonly deks: Map<string, CryptoKey>\n}\n\n/**\n * Re-encrypt every record in `closure` under a fresh per-collection DEK.\n * Reads raw source envelopes, decrypts under the source DEK, re-encrypts\n * under the new DEK. Plaintext-pipeline: requires an unlocked vault.\n */\nexport async function reKeyClosure(\n vault: Vault,\n closure: Map<string, Set<string>>,\n): Promise<ReKeyResult> {\n const { name: vaultName, adapter, getDEK } = vault._introspectState()\n const collections: Record<string, Record<string, EncryptedEnvelope>> = {}\n const deks = new Map<string, CryptoKey>()\n\n for (const [collectionName, ids] of closure) {\n const srcDek = await getDEK(collectionName)\n const destDek = await generateDEK()\n deks.set(collectionName, destDek)\n const out: Record<string, EncryptedEnvelope> = {}\n\n for (const id of ids) {\n const env = await adapter.get(vaultName, collectionName, id)\n if (!env) continue\n if (env._cek !== undefined) {\n // Per-record CEK: a naive `{ ...env }` spread would carry a\n // SOURCE-DEK-wrapped CEK into a bundle re-keyed under a different\n // destination DEK — silently undecryptable for the recipient.\n // Re-wrap: unwrap the CEK under the source DEK, re-encrypt the body\n // under the SAME CEK (decision 2 — CEK reused on re-key, preserving\n // the history-chain identity), then wrap the CEK under the fresh\n // destination DEK. The recipient gains access transitively once they\n // re-wrap the collection DEK under their KEK on adopt.\n const cek = await unwrapCek(env._cek, srcDek)\n const plaintext = await decrypt(env._iv, env._data, cek)\n const { iv, data } = await encrypt(plaintext, cek)\n const wrapped = await wrapCek(cek, destDek)\n out[id] = { ...env, _iv: iv, _data: data, _cek: wrapped }\n continue\n }\n const plaintext = await decrypt(env._iv, env._data, srcDek)\n const { iv, data } = await encrypt(plaintext, destDek)\n out[id] = { ...env, _iv: iv, _data: data }\n }\n collections[collectionName] = out\n }\n\n return { collections, deks }\n}\n\n/**\n * Re-key the persisted JSON Schemas (`_schemas/<collection>`) for the\n * closure collections under the destination DEKs. Returns a\n * `{ collection: envelope }` map for the carried collections that actually\n * have a schema; collections without one are omitted.\n */\nexport async function reKeySchemas(\n vault: Vault,\n closure: Map<string, Set<string>>,\n destDeks: Map<string, CryptoKey>,\n): Promise<Record<string, EncryptedEnvelope>> {\n const { name: vaultName, adapter, getDEK } = vault._introspectState()\n const out: Record<string, EncryptedEnvelope> = {}\n\n for (const collectionName of closure.keys()) {\n const env = await adapter.get(vaultName, SCHEMAS_COLLECTION, collectionName)\n if (!env) continue // collection has no persisted schema — skip\n const destDek = destDeks.get(collectionName)\n if (!destDek) continue\n const srcDek = await getDEK(collectionName)\n const plaintext = await decrypt(env._iv, env._data, srcDek)\n const { iv, data } = await encrypt(plaintext, destDek)\n out[collectionName] = { ...env, _iv: iv, _data: data }\n }\n return out\n}\n\nconst paddedIndex = (n: number): string => String(n).padStart(10, '0')\n\nexport interface ReKeyLedgerResult {\n /** { paddedIndex: re-encrypted entry envelope } for backup._internal._ledger. */\n readonly entries: Record<string, EncryptedEnvelope>\n /** Recomputed ledgerHead for the carried chain (index -1 when empty). */\n readonly head: { hash: string; index: number; ts: string }\n}\n\n/**\n * Build the carried `_ledger` chain for an extracted partition.\n * Filters source entries to the closure, RE-CHAINS them (fresh index + prevHash),\n * and re-encrypts under `ledgerDek`. The `payloadHash` is recomputed against the\n * re-keyed envelope ONLY for the latest `put` per (collection,id) — the entry\n * `verifyBackupIntegrity` cross-checks; earlier puts + deletes keep their source\n * `payloadHash` verbatim (recomputing an intermediate put would assert a false\n * hash for an older version). Amendments + out-of-closure entries are dropped;\n * `_ledger_deltas`/`_history` are deferred to slice 2.\n */\nexport async function reKeyLedger(\n vault: Vault,\n closure: Map<string, Set<string>>,\n reKeyedCollections: Record<string, Record<string, EncryptedEnvelope>>,\n ledgerDek: CryptoKey,\n): Promise<ReKeyLedgerResult> {\n const { name: vaultName, adapter, getDEK } = vault._introspectState()\n const srcLedgerDek = await getDEK(LEDGER_COLLECTION)\n\n // 1. Load + decrypt source entries in index order.\n const ids = (await adapter.list(vaultName, LEDGER_COLLECTION)).sort()\n const srcEntries: LedgerEntry[] = []\n for (const id of ids) {\n const env = await adapter.get(vaultName, LEDGER_COLLECTION, id)\n if (!env) continue\n srcEntries.push(JSON.parse(await decrypt(env._iv, env._data, srcLedgerDek)) as LedgerEntry)\n }\n\n // 2. Keep closure put/delete entries (drop amendments + out-of-closure).\n const kept = srcEntries.filter(\n (e) => (e.op === 'put' || e.op === 'delete') && (closure.get(e.collection)?.has(e.id) ?? false),\n )\n\n // 3a. Reverse pass: index of the LATEST put per (collection,id).\n const latestPutIndex = new Map<string, number>()\n for (let i = kept.length - 1; i >= 0; i--) {\n const e = kept[i]!\n if (e.op !== 'put') continue\n const key = `${e.collection}/${e.id}`\n if (!latestPutIndex.has(key)) latestPutIndex.set(key, i)\n }\n\n // 3b. Forward re-chain + re-encrypt.\n const entries: Record<string, EncryptedEnvelope> = {}\n let prevHash = ''\n let last: LedgerEntry | undefined\n for (let i = 0; i < kept.length; i++) {\n const src = kept[i]!\n const key = `${src.collection}/${src.id}`\n const isLatestPut = src.op === 'put' && latestPutIndex.get(key) === i\n const reKeyedEnv = reKeyedCollections[src.collection]?.[src.id]\n const payloadHash = isLatestPut && reKeyedEnv\n ? await envelopePayloadHash(reKeyedEnv)\n : src.payloadHash\n const entry: LedgerEntry = {\n index: i,\n prevHash,\n op: src.op,\n collection: src.collection,\n id: src.id,\n version: src.version,\n ts: src.ts,\n actor: src.actor,\n payloadHash,\n ...(src.reason !== undefined ? { reason: src.reason } : {}),\n }\n const { iv, data } = await encrypt(canonicalJson(entry), ledgerDek)\n entries[paddedIndex(i)] = {\n _noydb: NOYDB_FORMAT_VERSION, _v: i + 1, _ts: entry.ts, _iv: iv, _data: data, _by: entry.actor,\n }\n prevHash = await hashEntry(entry)\n last = entry\n }\n\n return {\n entries,\n head: last ? { hash: prevHash, index: last.index, ts: last.ts } : { hash: '', index: -1, ts: '' },\n }\n}\n\n/** A minted transfer key (raw 32 bytes) + the seal carrying the DEK set. */\nexport interface SealResult {\n readonly seal: TransferSealPayload\n readonly transferKey: Uint8Array\n}\n\n/**\n * Mint a random 32-byte transfer key, export each DEK to raw bytes, and\n * AES-256-GCM-seal the `{ collection: base64(rawDEK) }` map under the\n * transfer key. The transfer key is returned to the caller out-of-band;\n * only the sealed bytes travel in the bundle. Layout: iv(12) ‖ ct ‖ tag.\n */\nexport async function sealDeks(deks: Map<string, CryptoKey>): Promise<SealResult> {\n const dekMap: Record<string, string> = {}\n for (const [collection, dek] of deks) {\n const raw = await crypto.subtle.exportKey('raw', dek)\n dekMap[collection] = bufferToBase64(raw)\n }\n\n const transferKey = crypto.getRandomValues(new Uint8Array(32))\n const key = await crypto.subtle.importKey('raw', transferKey, 'AES-GCM', false, ['encrypt'])\n const iv = crypto.getRandomValues(new Uint8Array(12))\n const plaintext = new TextEncoder().encode(JSON.stringify(dekMap))\n const ct = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, plaintext)\n\n const combined = new Uint8Array(iv.byteLength + ct.byteLength)\n combined.set(iv, 0)\n combined.set(new Uint8Array(ct), iv.byteLength)\n\n const sealId = bufferToBase64(crypto.getRandomValues(new Uint8Array(12)))\n return {\n seal: { v: 1, alg: 'aes-256-gcm-pre-shared', sealId, payload: bufferToBase64(combined) },\n transferKey,\n }\n}\n\nexport interface ExtractPartitionResult {\n readonly bundleBytes: Uint8Array\n /** Raw 32-byte transfer key — deliver out-of-band; required to adopt. */\n readonly transferKey: Uint8Array\n readonly sealId: string\n}\n\n/**\n * Extract a re-keyed, transfer-sealed partition. Owner-only\n * (invariant 5): producing a standalone re-keyed vault is an\n * ownership operation. Non-destructive on the source.\n */\nexport async function extractPartition(\n vault: Vault,\n opts: WalkClosureOptions & {\n readonly compression?: 'auto' | 'brotli' | 'gzip' | 'none'\n readonly carrySchemas?: boolean\n readonly carryLedger?: boolean\n },\n): Promise<ExtractPartitionResult> {\n if (vault.role !== 'owner') {\n throw new PartitionExtractionError(\n `extractPartition requires the 'owner' role on the source vault; caller is '${vault.role}'. `\n + `Producing a re-keyed standalone partition is an ownership operation.`,\n )\n }\n\n // Persisted-schema writes (collection({ persistJsonSchema: true })) are fire-\n // and-forget queued onto vault._pendingSchemaWrites — a caller that does\n // `collection() → put() → extractPartition({ carrySchemas: true })` in quick\n // succession can hit a window where _schemas/<col> is not yet on disk and\n // reKeySchemas silently drops the row. Drain BEFORE reKeySchemas reads.\n if (opts.carrySchemas) await vault._drainPendingSchemaWrites()\n\n const { closure } = await walkClosure(vault, opts)\n const { collections, deks } = await reKeyClosure(vault, closure)\n\n // carryLedger: mint a fresh _ledger DEK, build the carried chain, and\n // SEAL the ledger DEK alongside the data DEKs so owner-creation wraps it into the\n // recipient keyring (lets them decrypt + verify the chain). Must run BEFORE\n // sealDeks.\n let ledgerHead: { hash: string; index: number; ts: string } | undefined\n let ledgerEntries: Record<string, EncryptedEnvelope> | undefined\n if (opts.carryLedger && vault._getLedgerOrNull() !== null) {\n // Skip when the source vault has no history strategy: reKeyLedger's first\n // `getDEK(LEDGER_COLLECTION)` would auto-mint and persist a phantom\n // _ledger DEK on the source keyring (contradicting \"non-destructive on\n // the source\"), and there's nothing to carry anyway. Mirrors the same\n // null-guard the source audit-append uses below.\n const ledgerDek = await generateDEK()\n const built = await reKeyLedger(vault, closure, collections, ledgerDek)\n if (built.head.index >= 0) {\n ledgerEntries = built.entries\n ledgerHead = built.head\n deks.set(LEDGER_COLLECTION, ledgerDek)\n }\n }\n\n // Build _internal (schemas + ledger). reKeySchemas reads data-\n // collection DEKs only, so it is unaffected by the _ledger DEK added above.\n const internalSchemas = opts.carrySchemas ? await reKeySchemas(vault, closure, deks) : {}\n const internal: Record<string, Record<string, EncryptedEnvelope>> = {}\n if (Object.keys(internalSchemas).length > 0) internal[SCHEMAS_COLLECTION] = internalSchemas\n if (ledgerEntries) internal[LEDGER_COLLECTION] = ledgerEntries\n const hasInternal = Object.keys(internal).length > 0\n\n const { seal, transferKey } = await sealDeks(deks)\n\n // Source-side audit (spec §4.2 / invariant 4): record that a partition\n // was handed over. Non-destructive — an audit append, no record touched.\n // No-op when the source vault has no history strategy. append() fills\n // index/prevHash/ts and (since actor is '') the ledger's configured actor.\n await vault._getLedgerOrNull()?.append({\n op: 'lifecycle',\n collection: '',\n id: '',\n version: 0,\n actor: '',\n payloadHash: '',\n reason: `partition-handed-over:${seal.sealId}`,\n })\n\n // Build the dump JSON: unowned (empty keyrings), empty ledger (default),\n // re-keyed collections only.\n const { name: vaultName } = vault._introspectState()\n const backup = {\n _noydb_backup: NOYDB_BACKUP_VERSION,\n _compartment: vaultName,\n _exported_at: new Date().toISOString(),\n _exported_by: '', // unowned — no source user travels\n keyrings: {},\n collections,\n ...(hasInternal ? { _internal: internal } : {}),\n ...(ledgerHead ? { ledgerHead: { hash: ledgerHead.hash, index: ledgerHead.index, ts: ledgerHead.ts } } : {}),\n }\n const bodyJsonStr = JSON.stringify(buildExtractedPartitionWrapper(JSON.stringify(backup), seal))\n\n // An extracted partition is a NEW vault, not a re-export of the source —\n // mint a fresh handle rather than reusing the source's stable ULID\n // (which would collide if a recipient imports both source + partition).\n const handle = generateULID()\n const bundleBytes = await assembleBundleContainer({\n handle,\n bodyJsonStr,\n compression: opts.compression,\n headerExtras: {\n bundleKind: 'extracted-partition',\n transferSeal: { v: seal.v, alg: seal.alg, sealId: seal.sealId }, // indicator only\n },\n })\n\n return { bundleBytes, transferKey, sealId: seal.sealId }\n}\n","/**\n * Partition adoption. Recipient side: verify an extracted bundle,\n * validate the transfer key, import the re-keyed collections into a\n * destination store, and record an `_meta/adoption` marker. The bundle\n * stays UNOWNED after adoption — `createOwnerOnAdoptedPartition`\n * mints the owner; the transfer seal is then destroyed.\n *\n * @module\n */\nimport { base64ToBuffer, wrapKey } from '../crypto.js'\nimport { TransferSealError, AdoptionStateError, ValidationError } from '../errors.js'\nimport type { NoydbStore, VaultSnapshot, KeyringFile } from '../types.js'\nimport { createOwnerKeyring } from '../team/keyring.js'\nimport { resolveManagedSecret } from '../team/managed-passphrase.js'\nimport type { SealingKeyProvider } from '../team/managed-passphrase.js'\nimport type { ShamirRecoveryProvider } from '../team/shamir-recovery-provider.js'\nimport type { RecoveryEnrollmentInput } from '../team/rotate-recover.js'\nimport { LedgerStore } from '../history/ledger/store.js'\nimport { LEDGER_COLLECTION } from '../history/ledger/constants.js'\nimport type { TransferSealPayload } from './bundle.js'\nimport { readNoydbBundleHeader, readNoydbBundle, parseExtractedPartitionBody } from './bundle.js'\n\n/**\n * Reverse of `sealDeks`. Imports the transfer key, decrypts the\n * sealed `{ collection: base64(rawDEK) }` map (layout iv(12)‖ct‖tag), and\n * re-imports each DEK as an AES-GCM key. Throws `TransferSealError` on a\n * wrong key (AES-GCM auth-tag failure) or malformed payload.\n */\nexport async function unsealDeks(\n seal: TransferSealPayload,\n transferKey: Uint8Array,\n): Promise<Map<string, CryptoKey>> {\n if (transferKey.byteLength !== 32) {\n throw new TransferSealError(\n `transfer key must be 32 bytes, got ${transferKey.byteLength}.`,\n )\n }\n const key = await crypto.subtle.importKey('raw', transferKey as BufferSource, 'AES-GCM', false, ['decrypt'])\n const raw = base64ToBuffer(seal.payload)\n let plaintext: ArrayBuffer\n try {\n plaintext = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: raw.slice(0, 12) as BufferSource },\n key,\n raw.slice(12) as BufferSource,\n )\n } catch {\n throw new TransferSealError(\n 'transfer seal could not be opened — wrong transfer key (AES-GCM authentication failed).',\n )\n }\n let dekMap: Record<string, string>\n try {\n dekMap = JSON.parse(new TextDecoder().decode(plaintext)) as Record<string, string>\n } catch {\n throw new TransferSealError('transfer seal payload is not valid JSON after decryption.')\n }\n const deks = new Map<string, CryptoKey>()\n for (const [collection, b64] of Object.entries(dekMap)) {\n // Extractable: the recipient must be able to re-wrap these under their\n // own KEK (AES-KW) at owner-creation. Matches generateDEK.\n const dek = await crypto.subtle.importKey('raw', base64ToBuffer(b64) as BufferSource, 'AES-GCM', true, ['encrypt', 'decrypt'])\n deks.set(collection, dek)\n }\n return deks\n}\n\nexport interface AdoptPartitionOptions {\n readonly transferKey: Uint8Array\n readonly destinationStore: NoydbStore\n readonly vaultName: string\n}\n\nexport interface AdoptPartitionResult {\n readonly vaultName: string\n readonly needsOwner: true\n readonly sealId: string\n}\n\nexport async function adoptPartition(\n bundleBytes: Uint8Array,\n opts: AdoptPartitionOptions,\n): Promise<AdoptPartitionResult> {\n const { transferKey, destinationStore, vaultName } = opts\n\n const header = readNoydbBundleHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new ValidationError(\n 'adoptPartition requires an extracted-partition bundle with a transfer seal. '\n + 'For ordinary backups use readNoydbBundle + vault.load.',\n )\n }\n\n const { dumpJson } = await readNoydbBundle(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n\n // Validate the transfer key by unsealing in memory; throws\n // TransferSealError on mismatch. DEKs are discarded here — they stay\n // sealed at rest (in _meta/adoption) until owner-creation wraps them under the\n // recipient's KEK.\n await unsealDeks(seal, transferKey)\n\n // Single-occupancy per vaultName: an `_meta/adoption` marker already present\n // means this slot holds a partition (adopted-and-unowned, or already owned).\n // saveAll below would overwrite its data and replace the marker, stranding the\n // prior adoption's transfer seal. Refuse regardless of sealId — re-adopting the\n // SAME bundle is a redundant call, and adopting a DIFFERENT bundle here would\n // clobber the existing partition. Either way, pick a fresh vaultName.\n const existing = await destinationStore.get(vaultName, '_meta', 'adoption')\n if (existing) {\n const prior = JSON.parse(existing._data) as { sealId?: string }\n if (prior.sealId === seal.sealId) {\n throw new AdoptionStateError(\n `partition (sealId ${seal.sealId}) is already adopted into vault \"${vaultName}\".`,\n )\n }\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds an adopted partition (sealId ${prior.sealId}); `\n + `adopting a different partition (sealId ${seal.sealId}) here would overwrite it. `\n + `Adopt into a fresh vaultName instead.`,\n )\n }\n\n // The marker-only check above misses a worse case: a vaultName already in use\n // by an ORDINARY vault (createNoydb + openVault) carries no `_meta/adoption`,\n // yet `saveAll` below is destructive on SQL adapters (`DELETE FROM ... WHERE\n // vault = ?` followed by upsert) and would wipe the legitimate keyring +\n // data. Refuse adoption into ANY occupied slot — a fresh vaultName is the\n // documented precondition.\n const existingKeyring = await destinationStore.list(vaultName, '_keyring')\n if (existingKeyring.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already holds a keyring (an unrelated owner exists at this slot); `\n + `adoptPartition requires a fresh vaultName to avoid destructive saveAll on SQL adapters.`,\n )\n }\n\n const backup = JSON.parse(dump) as { collections: VaultSnapshot; _internal?: VaultSnapshot }\n await destinationStore.saveAll(vaultName, backup.collections)\n\n // Import carried internal collections (e.g. _schemas from carrySchemas).\n // saveAll only writes data collections; _internal is written per-record.\n if (backup._internal) {\n for (const [collection, records] of Object.entries(backup._internal)) {\n for (const [id, envelope] of Object.entries(records)) {\n await destinationStore.put(vaultName, collection, id, envelope)\n }\n }\n }\n\n const adoptedAt = new Date().toISOString()\n const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true as const, transferSeal: seal }\n await destinationStore.put(vaultName, '_meta', 'adoption', {\n _noydb: 1, _v: 1, _ts: adoptedAt, _iv: '', _data: JSON.stringify(adoption),\n })\n\n return { vaultName, needsOwner: true, sealId: seal.sealId }\n}\n\nexport interface CreateOwnerResult {\n readonly vaultName: string\n readonly userId: string\n}\n\n/** Standard-mode owner: recipient supplies the passphrase. */\nexport interface CreateOwnerStandardOptions {\n readonly userId: string\n readonly passphrase: string\n readonly transferKey: Uint8Array\n}\n\n/**\n * Managed-mode owner: the passphrase is minted + sealed under\n * a `SealingKeyProvider` (e.g. an `at-*` OS keychain) so the partition\n * auto-unlocks on the recipient's device. Managed mode mandates a strong\n * (Shamir) recovery profile at creation, which needs the\n * `shamirRecovery` provider injected.\n */\nexport interface CreateOwnerManagedOptions {\n readonly userId: string\n readonly passphraseMode: 'managed'\n readonly sealingKey: SealingKeyProvider\n readonly recovery: ReadonlyArray<RecoveryEnrollmentInput>\n readonly shamirRecovery: ShamirRecoveryProvider\n readonly transferKey: Uint8Array\n}\n\nexport type CreateOwnerOptions = CreateOwnerStandardOptions | CreateOwnerManagedOptions\n\nfunction isManaged(o: CreateOwnerOptions): o is CreateOwnerManagedOptions {\n return 'passphraseMode' in o && o.passphraseMode === 'managed'\n}\n\n/**\n * Mint the first owner keyring on an adopted-but-unowned partition,\n * then destroy the transfer seal.\n *\n * Standard mode: the recipient supplies a passphrase. Managed mode: the\n * passphrase is minted + sealed under a `SealingKeyProvider` and a strong\n * (Shamir) recovery profile is enrolled — orchestrated via the existing\n * `openVaultAndEnrollRecovery` ceremony.\n *\n * Either way, reuses `createOwnerKeyring` to derive the KEK + write the base\n * keyring, then wraps the partition's DEKs (recovered from the seal) under that\n * KEK and re-persists the merged keyring file.\n *\n * Idempotent under retry: the seal is destroyed LAST (Stage D), after the\n * keyring (Stage A), the ledger transition (Stage B), and — in managed mode —\n * strong-recovery enrollment (Stage C). A failure in the fallible enrollment\n * step leaves the seal intact, and re-running with the same `userId` +\n * `transferKey` resumes from the first incomplete stage. (Multi-profile recovery\n * arrays may re-enroll an already-enrolled profile on retry; managed mode's\n * mandated single Shamir profile does not.)\n */\nexport async function createOwnerOnAdoptedPartition(\n store: NoydbStore,\n vaultName: string,\n opts: CreateOwnerOptions,\n): Promise<CreateOwnerResult> {\n const { userId, transferKey } = opts\n\n // Managed mode requires a strong (Shamir) recovery profile, validated BEFORE\n // any disk write — same gate as createNoydb.\n if (isManaged(opts) && !opts.recovery.some((r) => r.profile === 'shamir')) {\n throw new AdoptionStateError(\n 'managed-mode adoption requires at least one strong (shamir) recovery profile in '\n + '`recovery` — paper alone is not strong when there is no user passphrase to fall back on.',\n )\n }\n\n // 1. Verify adopted-unowned state.\n const adoptionEnv = await store.get(vaultName, '_meta', 'adoption')\n if (!adoptionEnv) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" is not an adopted partition (no _meta/adoption). `\n + `createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`,\n )\n }\n const adoption = JSON.parse(adoptionEnv._data) as {\n sealId: string; adoptedAt: string; needsOwner?: boolean\n consumedAt?: string; transferSeal?: TransferSealPayload\n }\n if (adoption.consumedAt !== undefined || adoption.transferSeal === undefined) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`,\n )\n }\n\n // 2. Recover the partition DEKs from the seal (throws on wrong key) BEFORE\n // writing any keyring, so a bad transfer key leaves no trace. Always\n // validated, including when resuming a partial prior call.\n const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey)\n\n // The ceremony below is split into stages so a failure in the fallible\n // managed-enrollment step (network/provider outage) leaves the call RETRYABLE\n // — the seal is destroyed only once everything durable is in place. Each stage\n // detects its own prior completion rather than relying on a single resume bit.\n\n // A keyring present for a DIFFERENT user (with the seal still unconsumed) is a\n // genuine second-owner attempt — refuse it. A same-user keyring is a resumed\n // partial call and is handled by the stage checks below.\n const existingKeyring = await store.get(vaultName, '_keyring', userId)\n const otherOwners = (await store.list(vaultName, '_keyring')).filter((u) => u !== userId)\n if (otherOwners.length > 0) {\n throw new AdoptionStateError(\n `vault \"${vaultName}\" already has a keyring for a different owner; cannot create owner \"${userId}\".`,\n )\n }\n\n // Stage A — mint the owner keyring + merge the partition DEKs. Considered done\n // only when the keyring already holds every partition DEK. createOwnerKeyring\n // overwrites (fresh KEK + fresh _users DEK), so re-running is safe ONLY while\n // no recovery has been enrolled yet — guaranteed here because enrollment\n // (Stage C) runs strictly after Stage A completes.\n const partitionCollections = [...partitionDeks.keys()]\n const priorDeks = existingKeyring ? (JSON.parse(existingKeyring._data) as KeyringFile).deks : {}\n const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks)\n if (!ownerMinted) {\n // Resolve the owner passphrase. Managed mode mints a random passphrase, seals\n // it under the provider, and persists _meta/sealed-passphrase (so the\n // partition auto-unlocks on the recipient's device); standard mode uses the\n // caller's passphrase. Idempotent under retry — resolveManagedSecret's reopen\n // arm reuses an already-sealed passphrase.\n const passphrase = isManaged(opts)\n ? await resolveManagedSecret(store, vaultName, opts.sealingKey)\n : opts.passphrase\n\n // Mint the owner keyring (KEK + _users DEK + canary, written to disk).\n const unlocked = await createOwnerKeyring(store, vaultName, userId, passphrase)\n\n // Merge the partition DEKs (wrapped under the new KEK) into the keyring.\n const env = await store.get(vaultName, '_keyring', userId)\n if (!env) throw new AdoptionStateError(`keyring write for \"${userId}\" did not persist`)\n const keyringFile = JSON.parse(env._data) as KeyringFile\n const kek = unlocked.kek\n if (!kek) throw new AdoptionStateError(`owner keyring for \"${userId}\" has no KEK to wrap partition DEKs under`)\n const mergedDeks: Record<string, string> = { ...keyringFile.deks }\n for (const [collection, dek] of partitionDeks) {\n mergedDeks[collection] = await wrapKey(dek, kek)\n }\n const mergedFile: KeyringFile = { ...keyringFile, deks: mergedDeks }\n await store.put(vaultName, '_keyring', userId, { ...env, _data: JSON.stringify(mergedFile) })\n }\n\n // Stage B — record the ownership transition on the carried\n // audit chain (carryLedger sealed the _ledger DEK). No-op without that DEK.\n // Idempotent: appended only if the closing `transfer-seal-consumed` entry is\n // absent, so a retry does not duplicate the pair.\n const ledgerDek = partitionDeks.get(LEDGER_COLLECTION)\n if (ledgerDek) {\n const ledger = new LedgerStore({\n adapter: store,\n vault: vaultName,\n encrypted: true,\n getDEK: async () => ledgerDek,\n actor: userId,\n })\n const creationReason = `creation-of-new-owner:${userId}`\n const consumedReason = `transfer-seal-consumed:${adoption.sealId}`\n // Gate each append on its own presence — a crash or store error strictly\n // between the two adjacent puts would otherwise re-append the first one\n // on retry. The pair is the audit record, not a single transaction.\n const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason))\n if (!recordedReasons.has(creationReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: creationReason })\n }\n if (!recordedReasons.has(consumedReason)) {\n await ledger.append({ op: 'lifecycle', collection: '', id: '', version: 0, actor: '', payloadHash: '', reason: consumedReason })\n }\n }\n\n // Stage C — Managed mode: enroll the mandatory strong recovery\n // by orchestrating the existing public ceremony. The partition is\n // now a managed-mode vault on disk (sealed passphrase + keyring), so we\n // open it as a normal client and let openVaultAndEnrollRecovery do the\n // gate-bypass + enroll + re-assert. Dynamic import keeps the Noydb class\n // out of the @noy-db/hub/bundle static graph. Runs BEFORE seal destruction\n // so a failure here leaves the seal intact and the call retryable.\n if (isManaged(opts)) {\n const { createNoydb } = await import('../noydb.js')\n const db = await createNoydb({\n store,\n user: userId,\n passphraseMode: 'managed',\n sealingKey: opts.sealingKey,\n shamirRecovery: opts.shamirRecovery,\n })\n await db.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery })\n }\n\n // Stage D — Destroy the transfer seal LAST — the commit point. Everything\n // above is either idempotent or resumable, so the seal is only consumed\n // once the owner keyring (and, in managed mode, strong recovery) is\n // durably in place. Retain sealId + consumedAt for audit.\n const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: new Date().toISOString() }\n await store.put(vaultName, '_meta', 'adoption', { ...adoptionEnv, _data: JSON.stringify(consumed) })\n\n return { vaultName, userId }\n}\n"],"mappings":"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","names":["plaintext","iv","data"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NOYDB_FORMAT_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TA6HPKWQ.js";
|
|
4
4
|
import {
|
|
5
5
|
encrypt
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-37VGJM3T.js";
|
|
7
7
|
|
|
8
8
|
// src/blobs/export-blobs.ts
|
|
9
9
|
var ExportBlobsAbortedError = class extends Error {
|
|
@@ -118,6 +118,7 @@ async function runCompaction(ctx, options = {}) {
|
|
|
118
118
|
let evicted = 0;
|
|
119
119
|
let records = 0;
|
|
120
120
|
let auditEntries = 0;
|
|
121
|
+
let held = 0;
|
|
121
122
|
let collectionsWithPolicy = 0;
|
|
122
123
|
outer: for (const collectionName of allCollections) {
|
|
123
124
|
if (collectionName.startsWith("_")) continue;
|
|
@@ -141,6 +142,10 @@ async function runCompaction(ctx, options = {}) {
|
|
|
141
142
|
if (!policy) continue;
|
|
142
143
|
const reason = evaluatePolicy(policy, record, slot, now);
|
|
143
144
|
if (!reason) continue;
|
|
145
|
+
if (isHeld(policy, record, now)) {
|
|
146
|
+
held += 1;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
144
149
|
if (!dryRun) {
|
|
145
150
|
await ctx.deleteSlot(collectionName, recordId, slot.name);
|
|
146
151
|
await writeAuditEntry(ctx, {
|
|
@@ -165,9 +170,32 @@ async function runCompaction(ctx, options = {}) {
|
|
|
165
170
|
records,
|
|
166
171
|
collections: collectionsWithPolicy,
|
|
167
172
|
auditEntries,
|
|
173
|
+
held,
|
|
168
174
|
byCollection
|
|
169
175
|
};
|
|
170
176
|
}
|
|
177
|
+
function isHeld(policy, record, now) {
|
|
178
|
+
if (policy.legalHold) {
|
|
179
|
+
try {
|
|
180
|
+
if (policy.legalHold(record)) return true;
|
|
181
|
+
} catch {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (policy.retainUntil) {
|
|
186
|
+
try {
|
|
187
|
+
const until = policy.retainUntil(record);
|
|
188
|
+
if (until !== null && until !== void 0) {
|
|
189
|
+
const t = until instanceof Date ? until.getTime() : typeof until === "number" ? until : Date.parse(String(until));
|
|
190
|
+
if (!Number.isFinite(t)) return true;
|
|
191
|
+
if (t > now.getTime()) return true;
|
|
192
|
+
}
|
|
193
|
+
} catch {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
171
199
|
function evaluatePolicy(policy, record, slot, now) {
|
|
172
200
|
let ttlTriggered = false;
|
|
173
201
|
let predicateTriggered = false;
|
|
@@ -230,4 +258,4 @@ export {
|
|
|
230
258
|
BLOB_EVICTION_AUDIT_COLLECTION,
|
|
231
259
|
runCompaction
|
|
232
260
|
};
|
|
233
|
-
//# sourceMappingURL=chunk-
|
|
261
|
+
//# sourceMappingURL=chunk-2XA2ZML4.js.map
|