@noy-db/hub 0.1.0-pre.9 → 0.2.0-pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aggregate/index.cjs +91 -36
- package/dist/aggregate/index.cjs.map +1 -1
- package/dist/aggregate/index.d.cts +2 -2
- package/dist/aggregate/index.d.ts +2 -2
- package/dist/aggregate/index.js +16 -9
- package/dist/aggregate/index.js.map +1 -1
- package/dist/attestation/index.cjs +305 -0
- package/dist/attestation/index.cjs.map +1 -0
- package/dist/attestation/index.d.cts +52 -0
- package/dist/attestation/index.d.ts +52 -0
- package/dist/attestation/index.js +36 -0
- package/dist/attestation/index.js.map +1 -0
- package/dist/blobs/index.cjs.map +1 -1
- package/dist/blobs/index.d.cts +7 -6
- package/dist/blobs/index.d.ts +7 -6
- package/dist/blobs/index.js +10 -8
- package/dist/blobs/index.js.map +1 -1
- package/dist/bundle/index.cjs +16923 -60
- package/dist/bundle/index.cjs.map +1 -1
- package/dist/bundle/index.d.cts +175 -6
- package/dist/bundle/index.d.ts +175 -6
- package/dist/bundle/index.js +543 -4
- package/dist/bundle/index.js.map +1 -1
- package/dist/{chunk-PTVMYYON.js → chunk-243PNUA6.js} +3 -3
- package/dist/{chunk-MR4424N3.js → chunk-2PAQNPE3.js} +2 -2
- package/dist/chunk-3QAKZ37R.js +83 -0
- package/dist/chunk-3QAKZ37R.js.map +1 -0
- package/dist/chunk-3S4BJX25.js +36 -0
- package/dist/chunk-3S4BJX25.js.map +1 -0
- package/dist/chunk-3XHOCQK4.js +118 -0
- package/dist/chunk-3XHOCQK4.js.map +1 -0
- package/dist/{chunk-AVVPZ4BC.js → chunk-3Y53S2SA.js} +4 -4
- package/dist/chunk-3Z2TPHC4.js +291 -0
- package/dist/chunk-3Z2TPHC4.js.map +1 -0
- package/dist/chunk-4HIL6AHQ.js +57 -0
- package/dist/chunk-4HIL6AHQ.js.map +1 -0
- package/dist/chunk-5ZGZ6HIZ.js +100 -0
- package/dist/chunk-5ZGZ6HIZ.js.map +1 -0
- package/dist/{chunk-ZFKD4QMV.js → chunk-7BRE6EUA.js} +3 -3
- package/dist/chunk-7BUTTVMR.js +34 -0
- package/dist/chunk-7BUTTVMR.js.map +1 -0
- package/dist/{chunk-VQBTTTUN.js → chunk-7Q5PLD5C.js} +4 -4
- package/dist/{chunk-VQBTTTUN.js.map → chunk-7Q5PLD5C.js.map} +1 -1
- package/dist/{chunk-QAVUREFT.js → chunk-7Z23ZFLV.js} +12 -6
- package/dist/chunk-7Z23ZFLV.js.map +1 -0
- package/dist/chunk-AHPFONIL.js +59 -0
- package/dist/chunk-AHPFONIL.js.map +1 -0
- package/dist/chunk-CXSCDO5T.js +51 -0
- package/dist/chunk-CXSCDO5T.js.map +1 -0
- package/dist/chunk-E535SAN4.js +8834 -0
- package/dist/chunk-E535SAN4.js.map +1 -0
- package/dist/chunk-EUYOGYGV.js +830 -0
- package/dist/chunk-EUYOGYGV.js.map +1 -0
- package/dist/chunk-FAQVNJD4.js +61 -0
- package/dist/chunk-FAQVNJD4.js.map +1 -0
- package/dist/{chunk-SCZXXXU4.js → chunk-G6FRSBKK.js} +7 -32
- package/dist/chunk-G6FRSBKK.js.map +1 -0
- package/dist/chunk-GIV6DWBG.js +79 -0
- package/dist/chunk-GIV6DWBG.js.map +1 -0
- package/dist/chunk-HXJXPZRE.js +73 -0
- package/dist/chunk-HXJXPZRE.js.map +1 -0
- package/dist/{chunk-GOUT6DND.js → chunk-J4KLMEUL.js} +173 -91
- package/dist/chunk-J4KLMEUL.js.map +1 -0
- package/dist/{chunk-2CSJGFCB.js → chunk-JYQTXEIO.js} +6 -229
- package/dist/chunk-JYQTXEIO.js.map +1 -0
- package/dist/{chunk-MDDTIZUO.js → chunk-LRAZDV5X.js} +7 -119
- package/dist/chunk-LRAZDV5X.js.map +1 -0
- package/dist/{chunk-M5INGEFC.js → chunk-MRIBLZL3.js} +3 -1
- package/dist/chunk-MRIBLZL3.js.map +1 -0
- package/dist/{chunk-USKYUS74.js → chunk-MUWOSVEP.js} +2 -2
- package/dist/{chunk-4PWAI7Q4.js → chunk-NWZ3I6R6.js} +5 -5
- package/dist/chunk-OVZDFEOR.js +124 -0
- package/dist/chunk-OVZDFEOR.js.map +1 -0
- package/dist/chunk-PEULZC6M.js +118 -0
- package/dist/chunk-PEULZC6M.js.map +1 -0
- package/dist/chunk-PFSNOPBQ.js +233 -0
- package/dist/chunk-PFSNOPBQ.js.map +1 -0
- package/dist/chunk-PLI5TV7N.js +53 -0
- package/dist/chunk-PLI5TV7N.js.map +1 -0
- package/dist/{chunk-WDM5XGGS.js → chunk-Q6W2CMEJ.js} +181 -11
- package/dist/chunk-Q6W2CMEJ.js.map +1 -0
- package/dist/{chunk-QGZRWRSL.js → chunk-QPEXPHJR.js} +4 -4
- package/dist/{chunk-R36SIKES.js → chunk-QXQRKXCU.js} +2 -2
- package/dist/chunk-RTZVQAJ7.js +82 -0
- package/dist/chunk-RTZVQAJ7.js.map +1 -0
- package/dist/chunk-TBKOGSYR.js +296 -0
- package/dist/chunk-TBKOGSYR.js.map +1 -0
- package/dist/chunk-UMLVJTYV.js +20 -0
- package/dist/chunk-UMLVJTYV.js.map +1 -0
- package/dist/chunk-UND4XIB6.js +251 -0
- package/dist/chunk-UND4XIB6.js.map +1 -0
- package/dist/chunk-VCGTOS2A.js +795 -0
- package/dist/chunk-VCGTOS2A.js.map +1 -0
- package/dist/chunk-VE6YVP32.js +19 -0
- package/dist/chunk-VE6YVP32.js.map +1 -0
- package/dist/{chunk-M62XNWRA.js → chunk-VK5EER6C.js} +2 -2
- package/dist/{chunk-NXFEYLVG.js → chunk-VPSUZLOJ.js} +4 -3
- package/dist/{chunk-NXFEYLVG.js.map → chunk-VPSUZLOJ.js.map} +1 -1
- package/dist/{chunk-TDR6T5CJ.js → chunk-VRBCTEKQ.js} +91 -132
- package/dist/chunk-VRBCTEKQ.js.map +1 -0
- package/dist/{chunk-ACLDOTNQ.js → chunk-W3XXT26A.js} +303 -3
- package/dist/chunk-W3XXT26A.js.map +1 -0
- package/dist/{chunk-CIMZBAZB.js → chunk-XG3PTSCD.js} +1 -1
- package/dist/chunk-XG3PTSCD.js.map +1 -0
- package/dist/chunk-Y2RKOPNC.js +145 -0
- package/dist/chunk-Y2RKOPNC.js.map +1 -0
- package/dist/{chunk-NPC4LFV5.js → chunk-YMYK7US4.js} +2 -2
- package/dist/{chunk-RKJ6OL7K.js → chunk-YS3POABP.js} +1 -1
- package/dist/chunk-YS3POABP.js.map +1 -0
- package/dist/chunk-YTXSFG3C.js +179 -0
- package/dist/chunk-YTXSFG3C.js.map +1 -0
- package/dist/consent/index.cjs.map +1 -1
- package/dist/consent/index.d.cts +7 -6
- package/dist/consent/index.d.ts +7 -6
- package/dist/consent/index.js +3 -3
- package/dist/{crypto-IVKU7YTT.js → crypto-5ZDIY3NG.js} +3 -3
- package/dist/{delegation-2DBS2EOH.js → delegation-QYXZW25W.js} +5 -4
- package/dist/derivations/index.cjs +351 -0
- package/dist/derivations/index.cjs.map +1 -0
- package/dist/derivations/index.d.cts +72 -0
- package/dist/derivations/index.d.ts +72 -0
- package/dist/derivations/index.js +27 -0
- package/dist/{dev-unlock-Da1B0TIK.d.cts → dev-unlock-DQCNDfFp.d.cts} +1 -1
- package/dist/{dev-unlock-BdPp68qn.d.ts → dev-unlock-utkybTKb.d.ts} +1 -1
- package/dist/executor-AS2IDHKZ.js +11 -0
- package/dist/executor-HLXFXNFM.js +8 -0
- package/dist/executor-HLXFXNFM.js.map +1 -0
- package/dist/executor-HN6YBHZ5.js +8 -0
- package/dist/executor-HN6YBHZ5.js.map +1 -0
- package/dist/fanout-sidecar-VJ52RIEY.js +51 -0
- package/dist/fanout-sidecar-VJ52RIEY.js.map +1 -0
- package/dist/guards/index.cjs +315 -0
- package/dist/guards/index.cjs.map +1 -0
- package/dist/guards/index.d.cts +31 -0
- package/dist/guards/index.d.ts +31 -0
- package/dist/guards/index.js +29 -0
- package/dist/guards/index.js.map +1 -0
- package/dist/{hash-lsoL3eEW.d.ts → hash-DcoYWfJ_.d.ts} +1 -1
- package/dist/{hash-BEfzPKwo.d.cts → hash-jDowCrK2.d.cts} +1 -1
- package/dist/history/index.cjs +8 -1
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +8 -7
- package/dist/history/index.d.ts +8 -7
- package/dist/history/index.js +6 -6
- package/dist/i18n/index.cjs +81 -0
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.d.cts +7 -6
- package/dist/i18n/index.d.ts +7 -6
- package/dist/i18n/index.js +27 -12
- package/dist/i18n/index.js.map +1 -1
- package/dist/{index-6xNpPsxR.d.cts → index-BCKdioeh.d.ts} +331 -5
- package/dist/{index-DJTf9yxn.d.ts → index-BMjrzNZr.d.cts} +331 -5
- package/dist/index.cjs +6065 -959
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +208 -16
- package/dist/index.d.ts +208 -16
- package/dist/index.js +242 -7392
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.cjs +2 -0
- 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-ORP37MVW.js +12 -0
- package/dist/issue-ORP37MVW.js.map +1 -0
- package/dist/{lazy-builder-CZVLKh0Z.d.cts → lazy-builder-C-rPfWG0.d.cts} +1 -1
- package/dist/{lazy-builder-BwEoBQZ9.d.ts → lazy-builder-Rpd-V3jP.d.ts} +1 -1
- package/dist/{ledger-QZTTHQAQ.js → ledger-3IU5GMXA.js} +6 -6
- package/dist/ledger-3IU5GMXA.js.map +1 -0
- package/dist/materialized-views/index.cjs +837 -0
- package/dist/materialized-views/index.cjs.map +1 -0
- package/dist/materialized-views/index.d.cts +184 -0
- package/dist/materialized-views/index.d.ts +184 -0
- package/dist/materialized-views/index.js +45 -0
- package/dist/materialized-views/index.js.map +1 -0
- package/dist/noydb-5H3C24GG.js +34 -0
- package/dist/noydb-5H3C24GG.js.map +1 -0
- package/dist/overlay-views/index.cjs +359 -0
- package/dist/overlay-views/index.cjs.map +1 -0
- package/dist/overlay-views/index.d.cts +82 -0
- package/dist/overlay-views/index.d.ts +82 -0
- package/dist/overlay-views/index.js +25 -0
- package/dist/overlay-views/index.js.map +1 -0
- package/dist/periods/index.cjs +7 -1
- package/dist/periods/index.cjs.map +1 -1
- package/dist/periods/index.d.cts +7 -6
- package/dist/periods/index.d.ts +7 -6
- package/dist/periods/index.js +6 -6
- package/dist/{predicate-SBHmi6D0.d.cts → predicate-Dnu81tsS.d.cts} +25 -1
- package/dist/{predicate-SBHmi6D0.d.ts → predicate-Dnu81tsS.d.ts} +25 -1
- package/dist/{public-envelope-6JTACYJV.js → public-envelope-U3CMEOMV.js} +4 -4
- package/dist/public-envelope-U3CMEOMV.js.map +1 -0
- package/dist/query/index.cjs +302 -124
- package/dist/query/index.cjs.map +1 -1
- package/dist/query/index.d.cts +3 -3
- package/dist/query/index.d.ts +3 -3
- package/dist/query/index.js +26 -11
- package/dist/read-only-facade-ITU6L7BL.js +7 -0
- package/dist/read-only-facade-ITU6L7BL.js.map +1 -0
- package/dist/registry-3ALP62P6.js +10 -0
- package/dist/registry-3ALP62P6.js.map +1 -0
- package/dist/registry-7HE6VJGC.js +8 -0
- package/dist/registry-7HE6VJGC.js.map +1 -0
- package/dist/registry-PSIPG2QR.js +8 -0
- package/dist/registry-PSIPG2QR.js.map +1 -0
- package/dist/registry-RFGGMVNJ.js +7 -0
- package/dist/registry-RFGGMVNJ.js.map +1 -0
- package/dist/revoke-KY2GB4KP.js +17 -0
- package/dist/revoke-KY2GB4KP.js.map +1 -0
- package/dist/session/index.cjs +7 -1
- package/dist/session/index.cjs.map +1 -1
- package/dist/session/index.d.cts +8 -7
- package/dist/session/index.d.ts +8 -7
- package/dist/session/index.js +10 -3
- package/dist/session/index.js.map +1 -1
- package/dist/shadow/index.cjs.map +1 -1
- package/dist/shadow/index.d.cts +7 -6
- package/dist/shadow/index.d.ts +7 -6
- package/dist/shadow/index.js +2 -2
- package/dist/signer-GRI5TZKH.js +18 -0
- package/dist/signer-GRI5TZKH.js.map +1 -0
- package/dist/stale-OTOF3FH7.js +13 -0
- package/dist/stale-OTOF3FH7.js.map +1 -0
- package/dist/store/index.cjs +14 -0
- package/dist/store/index.cjs.map +1 -1
- package/dist/store/index.d.cts +7 -6
- package/dist/store/index.d.ts +7 -6
- package/dist/store/index.js +5 -2
- package/dist/{strategy-D-SrOLCl.d.cts → strategy-DSTrsZ8t.d.cts} +72 -19
- package/dist/{strategy-D-SrOLCl.d.ts → strategy-DSTrsZ8t.d.ts} +72 -19
- package/dist/sync/index.cjs.map +1 -1
- package/dist/sync/index.d.cts +6 -5
- package/dist/sync/index.d.ts +6 -5
- package/dist/sync/index.js +4 -4
- package/dist/team/index.cjs +1554 -2
- package/dist/team/index.cjs.map +1 -1
- package/dist/team/index.d.cts +7 -6
- package/dist/team/index.d.ts +7 -6
- package/dist/team/index.js +77 -8
- package/dist/tx/index.cjs +296 -44
- package/dist/tx/index.cjs.map +1 -1
- package/dist/tx/index.d.cts +7 -6
- package/dist/tx/index.d.ts +7 -6
- package/dist/tx/index.js +2 -2
- package/dist/{types-Bo7NSXJr.d.ts → types-BoFFiskX.d.ts} +2714 -321
- package/dist/{types-Bnb82f5R.d.cts → types-DJG8HG6F.d.cts} +2714 -321
- package/dist/{index-CywCC1qZ.d.cts → ulid-BmBgooGm.d.ts} +215 -26
- package/dist/{index-8QDuznDr.d.ts → ulid-C7ms9oli.d.cts} +215 -26
- package/dist/util/index.cjs.map +1 -1
- package/dist/util/index.js +1 -1
- package/dist/with-derivation-BKXXa8Vt.d.ts +13 -0
- package/dist/with-derivation-BjQ7q4NE.d.cts +13 -0
- package/dist/with-guard-C25yNjzd.d.ts +18 -0
- package/dist/with-guard-DQme5DKE.d.cts +18 -0
- package/dist/with-materialized-view-BbEPFIIJ.d.cts +27 -0
- package/dist/with-materialized-view-CqnRwI2S.d.ts +27 -0
- package/dist/with-overlayed-view-Ct1fSJt-.d.ts +13 -0
- package/dist/with-overlayed-view-bwlmmFjx.d.cts +13 -0
- package/package.json +65 -2
- package/dist/chunk-2CSJGFCB.js.map +0 -1
- package/dist/chunk-ACLDOTNQ.js.map +0 -1
- package/dist/chunk-BTDCBVJW.js +0 -160
- package/dist/chunk-BTDCBVJW.js.map +0 -1
- package/dist/chunk-CIMZBAZB.js.map +0 -1
- package/dist/chunk-EXHNQEV4.js +0 -392
- package/dist/chunk-EXHNQEV4.js.map +0 -1
- package/dist/chunk-GOUT6DND.js.map +0 -1
- package/dist/chunk-M5INGEFC.js.map +0 -1
- package/dist/chunk-MDDTIZUO.js.map +0 -1
- package/dist/chunk-QAVUREFT.js.map +0 -1
- package/dist/chunk-RKJ6OL7K.js.map +0 -1
- package/dist/chunk-SCZXXXU4.js.map +0 -1
- package/dist/chunk-TDR6T5CJ.js.map +0 -1
- package/dist/chunk-WDM5XGGS.js.map +0 -1
- /package/dist/{chunk-PTVMYYON.js.map → chunk-243PNUA6.js.map} +0 -0
- /package/dist/{chunk-MR4424N3.js.map → chunk-2PAQNPE3.js.map} +0 -0
- /package/dist/{chunk-AVVPZ4BC.js.map → chunk-3Y53S2SA.js.map} +0 -0
- /package/dist/{chunk-ZFKD4QMV.js.map → chunk-7BRE6EUA.js.map} +0 -0
- /package/dist/{chunk-USKYUS74.js.map → chunk-MUWOSVEP.js.map} +0 -0
- /package/dist/{chunk-4PWAI7Q4.js.map → chunk-NWZ3I6R6.js.map} +0 -0
- /package/dist/{chunk-QGZRWRSL.js.map → chunk-QPEXPHJR.js.map} +0 -0
- /package/dist/{chunk-R36SIKES.js.map → chunk-QXQRKXCU.js.map} +0 -0
- /package/dist/{chunk-M62XNWRA.js.map → chunk-VK5EER6C.js.map} +0 -0
- /package/dist/{chunk-NPC4LFV5.js.map → chunk-YMYK7US4.js.map} +0 -0
- /package/dist/{crypto-IVKU7YTT.js.map → crypto-5ZDIY3NG.js.map} +0 -0
- /package/dist/{delegation-2DBS2EOH.js.map → delegation-QYXZW25W.js.map} +0 -0
- /package/dist/{ledger-QZTTHQAQ.js.map → derivations/index.js.map} +0 -0
- /package/dist/{public-envelope-6JTACYJV.js.map → executor-AS2IDHKZ.js.map} +0 -0
package/dist/bundle/index.js
CHANGED
|
@@ -7,21 +7,552 @@ import {
|
|
|
7
7
|
NOYDB_BUNDLE_FORMAT_VERSION,
|
|
8
8
|
NOYDB_BUNDLE_MAGIC,
|
|
9
9
|
NOYDB_BUNDLE_PREFIX_BYTES,
|
|
10
|
+
assembleBundleContainer,
|
|
11
|
+
buildExtractedPartitionWrapper,
|
|
10
12
|
encodeBundleHeader,
|
|
13
|
+
parseExtractedPartitionBody,
|
|
11
14
|
readNoydbBundle,
|
|
12
15
|
readNoydbBundleHeader,
|
|
13
16
|
resetBrotliSupportCache,
|
|
14
17
|
validateBundleHeader,
|
|
15
18
|
writeNoydbBundle
|
|
16
|
-
} from "../chunk-
|
|
17
|
-
import
|
|
19
|
+
} from "../chunk-VCGTOS2A.js";
|
|
20
|
+
import {
|
|
21
|
+
SCHEMAS_COLLECTION,
|
|
22
|
+
resolveManagedSecret
|
|
23
|
+
} from "../chunk-UND4XIB6.js";
|
|
24
|
+
import "../chunk-243PNUA6.js";
|
|
25
|
+
import {
|
|
26
|
+
createOwnerKeyring
|
|
27
|
+
} from "../chunk-Q6W2CMEJ.js";
|
|
18
28
|
import {
|
|
19
29
|
generateULID,
|
|
20
30
|
isULID
|
|
21
31
|
} from "../chunk-FZU343FL.js";
|
|
22
|
-
import
|
|
23
|
-
|
|
32
|
+
import {
|
|
33
|
+
LEDGER_COLLECTION,
|
|
34
|
+
LedgerStore
|
|
35
|
+
} from "../chunk-7Z23ZFLV.js";
|
|
36
|
+
import {
|
|
37
|
+
canonicalJson,
|
|
38
|
+
envelopePayloadHash,
|
|
39
|
+
hashEntry
|
|
40
|
+
} from "../chunk-XG3PTSCD.js";
|
|
41
|
+
import {
|
|
42
|
+
NOYDB_BACKUP_VERSION,
|
|
43
|
+
NOYDB_FORMAT_VERSION
|
|
44
|
+
} from "../chunk-YS3POABP.js";
|
|
45
|
+
import {
|
|
46
|
+
base64ToBuffer,
|
|
47
|
+
bufferToBase64,
|
|
48
|
+
decrypt,
|
|
49
|
+
encrypt,
|
|
50
|
+
generateDEK,
|
|
51
|
+
wrapKey
|
|
52
|
+
} from "../chunk-2PAQNPE3.js";
|
|
53
|
+
import {
|
|
54
|
+
AdoptionStateError,
|
|
55
|
+
BackupCorruptedError,
|
|
56
|
+
BackupLedgerError,
|
|
57
|
+
BundleIntegrityError,
|
|
58
|
+
BundleSealMismatchError,
|
|
59
|
+
BundleVersionConflictError,
|
|
60
|
+
PartitionExtractionError,
|
|
61
|
+
TransferSealError,
|
|
62
|
+
ValidationError
|
|
63
|
+
} from "../chunk-W3XXT26A.js";
|
|
64
|
+
|
|
65
|
+
// src/bundle/walk-closure.ts
|
|
66
|
+
async function walkClosure(vault, opts) {
|
|
67
|
+
const closure = /* @__PURE__ */ new Map();
|
|
68
|
+
const requireStringId = (collection, record) => {
|
|
69
|
+
const id = record["id"];
|
|
70
|
+
if (typeof id !== "string") {
|
|
71
|
+
throw new PartitionExtractionError(
|
|
72
|
+
`walkClosure: record in collection "${collection}" has a non-string id (${typeof id}); cannot include it in the partition closure.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return id;
|
|
76
|
+
};
|
|
77
|
+
const add = (collection, id) => {
|
|
78
|
+
let set = closure.get(collection);
|
|
79
|
+
if (!set) {
|
|
80
|
+
set = /* @__PURE__ */ new Set();
|
|
81
|
+
closure.set(collection, set);
|
|
82
|
+
}
|
|
83
|
+
if (set.has(id)) return false;
|
|
84
|
+
set.add(id);
|
|
85
|
+
return true;
|
|
86
|
+
};
|
|
87
|
+
for (const [collectionName, predicate] of Object.entries(opts.seeds)) {
|
|
88
|
+
const coll = vault.collection(collectionName);
|
|
89
|
+
const records = await coll.list();
|
|
90
|
+
for (const record of records) {
|
|
91
|
+
if (await predicate(record)) {
|
|
92
|
+
add(collectionName, requireStringId(collectionName, record));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const { refRegistry } = vault._introspectState();
|
|
97
|
+
const maxDepth = opts.maxDepth ?? 16;
|
|
98
|
+
let cyclesDetected = false;
|
|
99
|
+
let inboundDepth = 0;
|
|
100
|
+
let outboundDepth = 0;
|
|
101
|
+
let frontier = [];
|
|
102
|
+
for (const [c, ids] of closure) for (const id of ids) frontier.push([c, id]);
|
|
103
|
+
while (frontier.length > 0) {
|
|
104
|
+
const next = [];
|
|
105
|
+
for (const [collectionName, id] of frontier) {
|
|
106
|
+
for (const inbound of refRegistry.getInbound(collectionName)) {
|
|
107
|
+
const childColl = vault.collection(inbound.collection);
|
|
108
|
+
const childRecords = await childColl.list();
|
|
109
|
+
for (const child of childRecords) {
|
|
110
|
+
const fk = child[inbound.field];
|
|
111
|
+
if (typeof fk !== "string" && typeof fk !== "number") continue;
|
|
112
|
+
if (String(fk) !== id) continue;
|
|
113
|
+
const childId = requireStringId(inbound.collection, child);
|
|
114
|
+
if (add(inbound.collection, childId)) {
|
|
115
|
+
next.push([inbound.collection, childId]);
|
|
116
|
+
} else {
|
|
117
|
+
cyclesDetected = true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (next.length > 0 && ++inboundDepth > maxDepth) {
|
|
123
|
+
throw new PartitionExtractionError(
|
|
124
|
+
`walkClosure exceeded maxDepth=${maxDepth}; the FK graph may be unexpectedly deep or cyclic. Raise maxDepth or narrow the seeds.`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
frontier = next;
|
|
128
|
+
}
|
|
129
|
+
let outboundFrontier = [];
|
|
130
|
+
for (const [c, ids] of closure) for (const id of ids) outboundFrontier.push([c, id]);
|
|
131
|
+
while (outboundFrontier.length > 0) {
|
|
132
|
+
const next = [];
|
|
133
|
+
for (const [collectionName, id] of outboundFrontier) {
|
|
134
|
+
const outbound = refRegistry.getOutbound(collectionName);
|
|
135
|
+
if (Object.keys(outbound).length === 0) continue;
|
|
136
|
+
const coll = vault.collection(collectionName);
|
|
137
|
+
const record = await coll.get(id);
|
|
138
|
+
if (!record) continue;
|
|
139
|
+
for (const [field, descriptor] of Object.entries(outbound)) {
|
|
140
|
+
const rawId = record[field];
|
|
141
|
+
if (typeof rawId !== "string" && typeof rawId !== "number") continue;
|
|
142
|
+
const parentId = String(rawId);
|
|
143
|
+
if (add(descriptor.target, parentId)) {
|
|
144
|
+
next.push([descriptor.target, parentId]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (next.length > 0 && ++outboundDepth > maxDepth) {
|
|
149
|
+
throw new PartitionExtractionError(
|
|
150
|
+
`walkClosure exceeded maxDepth=${maxDepth} during outbound completion.`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
outboundFrontier = next;
|
|
154
|
+
}
|
|
155
|
+
const depth = Math.max(inboundDepth, outboundDepth);
|
|
156
|
+
return { closure, graph: { depth, cyclesDetected } };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/bundle/describe-extraction.ts
|
|
160
|
+
async function describeExtraction(vault, opts) {
|
|
161
|
+
const { closure, graph } = await walkClosure(vault, opts);
|
|
162
|
+
const { name: vaultName, adapter } = vault._introspectState();
|
|
163
|
+
const encoder = new TextEncoder();
|
|
164
|
+
const byCollection = [];
|
|
165
|
+
const inaccessible = [];
|
|
166
|
+
let totalBytes = 0;
|
|
167
|
+
let totalRecords = 0;
|
|
168
|
+
for (const [collectionName, ids] of closure) {
|
|
169
|
+
let bytes = 0;
|
|
170
|
+
let oldestTs;
|
|
171
|
+
let newestTs;
|
|
172
|
+
let recordCount = 0;
|
|
173
|
+
for (const id of ids) {
|
|
174
|
+
const env = await adapter.get(vaultName, collectionName, id);
|
|
175
|
+
if (!env) {
|
|
176
|
+
inaccessible.push({ collection: collectionName, id });
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
recordCount++;
|
|
180
|
+
bytes += encoder.encode(JSON.stringify(env)).length;
|
|
181
|
+
const ts = env._ts;
|
|
182
|
+
if (oldestTs === void 0 || ts < oldestTs) oldestTs = ts;
|
|
183
|
+
if (newestTs === void 0 || ts > newestTs) newestTs = ts;
|
|
184
|
+
}
|
|
185
|
+
byCollection.push({
|
|
186
|
+
name: collectionName,
|
|
187
|
+
recordCount,
|
|
188
|
+
bytes,
|
|
189
|
+
// Spread conditionally — exactOptionalPropertyTypes forbids an
|
|
190
|
+
// explicit `undefined` on an optional property.
|
|
191
|
+
...oldestTs !== void 0 ? { oldestTs } : {},
|
|
192
|
+
...newestTs !== void 0 ? { newestTs } : {}
|
|
193
|
+
});
|
|
194
|
+
totalBytes += bytes;
|
|
195
|
+
totalRecords += recordCount;
|
|
196
|
+
}
|
|
197
|
+
byCollection.sort((a, b) => a.name.localeCompare(b.name));
|
|
198
|
+
return Object.freeze({
|
|
199
|
+
totalRecords,
|
|
200
|
+
totalBytes,
|
|
201
|
+
byCollection,
|
|
202
|
+
graph,
|
|
203
|
+
inaccessible
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/bundle/extract-partition.ts
|
|
208
|
+
async function reKeyClosure(vault, closure) {
|
|
209
|
+
const { name: vaultName, adapter, getDEK } = vault._introspectState();
|
|
210
|
+
const collections = {};
|
|
211
|
+
const deks = /* @__PURE__ */ new Map();
|
|
212
|
+
for (const [collectionName, ids] of closure) {
|
|
213
|
+
const srcDek = await getDEK(collectionName);
|
|
214
|
+
const destDek = await generateDEK();
|
|
215
|
+
deks.set(collectionName, destDek);
|
|
216
|
+
const out = {};
|
|
217
|
+
for (const id of ids) {
|
|
218
|
+
const env = await adapter.get(vaultName, collectionName, id);
|
|
219
|
+
if (!env) continue;
|
|
220
|
+
const plaintext = await decrypt(env._iv, env._data, srcDek);
|
|
221
|
+
const { iv, data } = await encrypt(plaintext, destDek);
|
|
222
|
+
out[id] = { ...env, _iv: iv, _data: data };
|
|
223
|
+
}
|
|
224
|
+
collections[collectionName] = out;
|
|
225
|
+
}
|
|
226
|
+
return { collections, deks };
|
|
227
|
+
}
|
|
228
|
+
async function reKeySchemas(vault, closure, destDeks) {
|
|
229
|
+
const { name: vaultName, adapter, getDEK } = vault._introspectState();
|
|
230
|
+
const out = {};
|
|
231
|
+
for (const collectionName of closure.keys()) {
|
|
232
|
+
const env = await adapter.get(vaultName, SCHEMAS_COLLECTION, collectionName);
|
|
233
|
+
if (!env) continue;
|
|
234
|
+
const destDek = destDeks.get(collectionName);
|
|
235
|
+
if (!destDek) continue;
|
|
236
|
+
const srcDek = await getDEK(collectionName);
|
|
237
|
+
const plaintext = await decrypt(env._iv, env._data, srcDek);
|
|
238
|
+
const { iv, data } = await encrypt(plaintext, destDek);
|
|
239
|
+
out[collectionName] = { ...env, _iv: iv, _data: data };
|
|
240
|
+
}
|
|
241
|
+
return out;
|
|
242
|
+
}
|
|
243
|
+
var paddedIndex = (n) => String(n).padStart(10, "0");
|
|
244
|
+
async function reKeyLedger(vault, closure, reKeyedCollections, ledgerDek) {
|
|
245
|
+
const { name: vaultName, adapter, getDEK } = vault._introspectState();
|
|
246
|
+
const srcLedgerDek = await getDEK(LEDGER_COLLECTION);
|
|
247
|
+
const ids = (await adapter.list(vaultName, LEDGER_COLLECTION)).sort();
|
|
248
|
+
const srcEntries = [];
|
|
249
|
+
for (const id of ids) {
|
|
250
|
+
const env = await adapter.get(vaultName, LEDGER_COLLECTION, id);
|
|
251
|
+
if (!env) continue;
|
|
252
|
+
srcEntries.push(JSON.parse(await decrypt(env._iv, env._data, srcLedgerDek)));
|
|
253
|
+
}
|
|
254
|
+
const kept = srcEntries.filter(
|
|
255
|
+
(e) => (e.op === "put" || e.op === "delete") && (closure.get(e.collection)?.has(e.id) ?? false)
|
|
256
|
+
);
|
|
257
|
+
const latestPutIndex = /* @__PURE__ */ new Map();
|
|
258
|
+
for (let i = kept.length - 1; i >= 0; i--) {
|
|
259
|
+
const e = kept[i];
|
|
260
|
+
if (e.op !== "put") continue;
|
|
261
|
+
const key = `${e.collection}/${e.id}`;
|
|
262
|
+
if (!latestPutIndex.has(key)) latestPutIndex.set(key, i);
|
|
263
|
+
}
|
|
264
|
+
const entries = {};
|
|
265
|
+
let prevHash = "";
|
|
266
|
+
let last;
|
|
267
|
+
for (let i = 0; i < kept.length; i++) {
|
|
268
|
+
const src = kept[i];
|
|
269
|
+
const key = `${src.collection}/${src.id}`;
|
|
270
|
+
const isLatestPut = src.op === "put" && latestPutIndex.get(key) === i;
|
|
271
|
+
const reKeyedEnv = reKeyedCollections[src.collection]?.[src.id];
|
|
272
|
+
const payloadHash = isLatestPut && reKeyedEnv ? await envelopePayloadHash(reKeyedEnv) : src.payloadHash;
|
|
273
|
+
const entry = {
|
|
274
|
+
index: i,
|
|
275
|
+
prevHash,
|
|
276
|
+
op: src.op,
|
|
277
|
+
collection: src.collection,
|
|
278
|
+
id: src.id,
|
|
279
|
+
version: src.version,
|
|
280
|
+
ts: src.ts,
|
|
281
|
+
actor: src.actor,
|
|
282
|
+
payloadHash,
|
|
283
|
+
...src.reason !== void 0 ? { reason: src.reason } : {}
|
|
284
|
+
};
|
|
285
|
+
const { iv, data } = await encrypt(canonicalJson(entry), ledgerDek);
|
|
286
|
+
entries[paddedIndex(i)] = {
|
|
287
|
+
_noydb: NOYDB_FORMAT_VERSION,
|
|
288
|
+
_v: i + 1,
|
|
289
|
+
_ts: entry.ts,
|
|
290
|
+
_iv: iv,
|
|
291
|
+
_data: data,
|
|
292
|
+
_by: entry.actor
|
|
293
|
+
};
|
|
294
|
+
prevHash = await hashEntry(entry);
|
|
295
|
+
last = entry;
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
entries,
|
|
299
|
+
head: last ? { hash: prevHash, index: last.index, ts: last.ts } : { hash: "", index: -1, ts: "" }
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
async function sealDeks(deks) {
|
|
303
|
+
const dekMap = {};
|
|
304
|
+
for (const [collection, dek] of deks) {
|
|
305
|
+
const raw = await crypto.subtle.exportKey("raw", dek);
|
|
306
|
+
dekMap[collection] = bufferToBase64(raw);
|
|
307
|
+
}
|
|
308
|
+
const transferKey = crypto.getRandomValues(new Uint8Array(32));
|
|
309
|
+
const key = await crypto.subtle.importKey("raw", transferKey, "AES-GCM", false, ["encrypt"]);
|
|
310
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
311
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(dekMap));
|
|
312
|
+
const ct = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext);
|
|
313
|
+
const combined = new Uint8Array(iv.byteLength + ct.byteLength);
|
|
314
|
+
combined.set(iv, 0);
|
|
315
|
+
combined.set(new Uint8Array(ct), iv.byteLength);
|
|
316
|
+
const sealId = bufferToBase64(crypto.getRandomValues(new Uint8Array(12)));
|
|
317
|
+
return {
|
|
318
|
+
seal: { v: 1, alg: "aes-256-gcm-pre-shared", sealId, payload: bufferToBase64(combined) },
|
|
319
|
+
transferKey
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async function extractPartition(vault, opts) {
|
|
323
|
+
if (vault.role !== "owner") {
|
|
324
|
+
throw new PartitionExtractionError(
|
|
325
|
+
`extractPartition requires the 'owner' role on the source vault; caller is '${vault.role}'. Producing a re-keyed standalone partition is an ownership operation.`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
if (opts.carrySchemas) await vault._drainPendingSchemaWrites();
|
|
329
|
+
const { closure } = await walkClosure(vault, opts);
|
|
330
|
+
const { collections, deks } = await reKeyClosure(vault, closure);
|
|
331
|
+
let ledgerHead;
|
|
332
|
+
let ledgerEntries;
|
|
333
|
+
if (opts.carryLedger && vault._getLedgerOrNull() !== null) {
|
|
334
|
+
const ledgerDek = await generateDEK();
|
|
335
|
+
const built = await reKeyLedger(vault, closure, collections, ledgerDek);
|
|
336
|
+
if (built.head.index >= 0) {
|
|
337
|
+
ledgerEntries = built.entries;
|
|
338
|
+
ledgerHead = built.head;
|
|
339
|
+
deks.set(LEDGER_COLLECTION, ledgerDek);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const internalSchemas = opts.carrySchemas ? await reKeySchemas(vault, closure, deks) : {};
|
|
343
|
+
const internal = {};
|
|
344
|
+
if (Object.keys(internalSchemas).length > 0) internal[SCHEMAS_COLLECTION] = internalSchemas;
|
|
345
|
+
if (ledgerEntries) internal[LEDGER_COLLECTION] = ledgerEntries;
|
|
346
|
+
const hasInternal = Object.keys(internal).length > 0;
|
|
347
|
+
const { seal, transferKey } = await sealDeks(deks);
|
|
348
|
+
await vault._getLedgerOrNull()?.append({
|
|
349
|
+
op: "lifecycle",
|
|
350
|
+
collection: "",
|
|
351
|
+
id: "",
|
|
352
|
+
version: 0,
|
|
353
|
+
actor: "",
|
|
354
|
+
payloadHash: "",
|
|
355
|
+
reason: `partition-handed-over:${seal.sealId}`
|
|
356
|
+
});
|
|
357
|
+
const { name: vaultName } = vault._introspectState();
|
|
358
|
+
const backup = {
|
|
359
|
+
_noydb_backup: NOYDB_BACKUP_VERSION,
|
|
360
|
+
_compartment: vaultName,
|
|
361
|
+
_exported_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
362
|
+
_exported_by: "",
|
|
363
|
+
// unowned — no source user travels
|
|
364
|
+
keyrings: {},
|
|
365
|
+
collections,
|
|
366
|
+
...hasInternal ? { _internal: internal } : {},
|
|
367
|
+
...ledgerHead ? { ledgerHead: { hash: ledgerHead.hash, index: ledgerHead.index, ts: ledgerHead.ts } } : {}
|
|
368
|
+
};
|
|
369
|
+
const bodyJsonStr = JSON.stringify(buildExtractedPartitionWrapper(JSON.stringify(backup), seal));
|
|
370
|
+
const handle = generateULID();
|
|
371
|
+
const bundleBytes = await assembleBundleContainer({
|
|
372
|
+
handle,
|
|
373
|
+
bodyJsonStr,
|
|
374
|
+
compression: opts.compression,
|
|
375
|
+
headerExtras: {
|
|
376
|
+
bundleKind: "extracted-partition",
|
|
377
|
+
transferSeal: { v: seal.v, alg: seal.alg, sealId: seal.sealId }
|
|
378
|
+
// indicator only
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
return { bundleBytes, transferKey, sealId: seal.sealId };
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/bundle/adopt-partition.ts
|
|
385
|
+
async function unsealDeks(seal, transferKey) {
|
|
386
|
+
if (transferKey.byteLength !== 32) {
|
|
387
|
+
throw new TransferSealError(
|
|
388
|
+
`transfer key must be 32 bytes, got ${transferKey.byteLength}.`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
const key = await crypto.subtle.importKey("raw", transferKey, "AES-GCM", false, ["decrypt"]);
|
|
392
|
+
const raw = base64ToBuffer(seal.payload);
|
|
393
|
+
let plaintext;
|
|
394
|
+
try {
|
|
395
|
+
plaintext = await crypto.subtle.decrypt(
|
|
396
|
+
{ name: "AES-GCM", iv: raw.slice(0, 12) },
|
|
397
|
+
key,
|
|
398
|
+
raw.slice(12)
|
|
399
|
+
);
|
|
400
|
+
} catch {
|
|
401
|
+
throw new TransferSealError(
|
|
402
|
+
"transfer seal could not be opened \u2014 wrong transfer key (AES-GCM authentication failed)."
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
let dekMap;
|
|
406
|
+
try {
|
|
407
|
+
dekMap = JSON.parse(new TextDecoder().decode(plaintext));
|
|
408
|
+
} catch {
|
|
409
|
+
throw new TransferSealError("transfer seal payload is not valid JSON after decryption.");
|
|
410
|
+
}
|
|
411
|
+
const deks = /* @__PURE__ */ new Map();
|
|
412
|
+
for (const [collection, b64] of Object.entries(dekMap)) {
|
|
413
|
+
const dek = await crypto.subtle.importKey("raw", base64ToBuffer(b64), "AES-GCM", true, ["encrypt", "decrypt"]);
|
|
414
|
+
deks.set(collection, dek);
|
|
415
|
+
}
|
|
416
|
+
return deks;
|
|
417
|
+
}
|
|
418
|
+
async function adoptPartition(bundleBytes, opts) {
|
|
419
|
+
const { transferKey, destinationStore, vaultName } = opts;
|
|
420
|
+
const header = readNoydbBundleHeader(bundleBytes);
|
|
421
|
+
if (header.bundleKind !== "extracted-partition" || header.transferSeal === void 0) {
|
|
422
|
+
throw new ValidationError(
|
|
423
|
+
"adoptPartition requires an extracted-partition bundle with a transfer seal. For ordinary backups use readNoydbBundle + vault.load."
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
const { dumpJson } = await readNoydbBundle(bundleBytes);
|
|
427
|
+
const { dump, seal } = parseExtractedPartitionBody(dumpJson);
|
|
428
|
+
await unsealDeks(seal, transferKey);
|
|
429
|
+
const existing = await destinationStore.get(vaultName, "_meta", "adoption");
|
|
430
|
+
if (existing) {
|
|
431
|
+
const prior = JSON.parse(existing._data);
|
|
432
|
+
if (prior.sealId === seal.sealId) {
|
|
433
|
+
throw new AdoptionStateError(
|
|
434
|
+
`partition (sealId ${seal.sealId}) is already adopted into vault "${vaultName}".`
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
throw new AdoptionStateError(
|
|
438
|
+
`vault "${vaultName}" already holds an adopted partition (sealId ${prior.sealId}); adopting a different partition (sealId ${seal.sealId}) here would overwrite it. Adopt into a fresh vaultName instead.`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
const existingKeyring = await destinationStore.list(vaultName, "_keyring");
|
|
442
|
+
if (existingKeyring.length > 0) {
|
|
443
|
+
throw new AdoptionStateError(
|
|
444
|
+
`vault "${vaultName}" already holds a keyring (an unrelated owner exists at this slot); adoptPartition requires a fresh vaultName to avoid destructive saveAll on SQL adapters.`
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
const backup = JSON.parse(dump);
|
|
448
|
+
await destinationStore.saveAll(vaultName, backup.collections);
|
|
449
|
+
if (backup._internal) {
|
|
450
|
+
for (const [collection, records] of Object.entries(backup._internal)) {
|
|
451
|
+
for (const [id, envelope] of Object.entries(records)) {
|
|
452
|
+
await destinationStore.put(vaultName, collection, id, envelope);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const adoptedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
457
|
+
const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true, transferSeal: seal };
|
|
458
|
+
await destinationStore.put(vaultName, "_meta", "adoption", {
|
|
459
|
+
_noydb: 1,
|
|
460
|
+
_v: 1,
|
|
461
|
+
_ts: adoptedAt,
|
|
462
|
+
_iv: "",
|
|
463
|
+
_data: JSON.stringify(adoption)
|
|
464
|
+
});
|
|
465
|
+
return { vaultName, needsOwner: true, sealId: seal.sealId };
|
|
466
|
+
}
|
|
467
|
+
function isManaged(o) {
|
|
468
|
+
return "passphraseMode" in o && o.passphraseMode === "managed";
|
|
469
|
+
}
|
|
470
|
+
async function createOwnerOnAdoptedPartition(store, vaultName, opts) {
|
|
471
|
+
const { userId, transferKey } = opts;
|
|
472
|
+
if (isManaged(opts) && !opts.recovery.some((r) => r.profile === "shamir")) {
|
|
473
|
+
throw new AdoptionStateError(
|
|
474
|
+
"managed-mode adoption requires at least one strong (shamir) recovery profile in `recovery` \u2014 paper alone is not strong when there is no user passphrase to fall back on."
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
const adoptionEnv = await store.get(vaultName, "_meta", "adoption");
|
|
478
|
+
if (!adoptionEnv) {
|
|
479
|
+
throw new AdoptionStateError(
|
|
480
|
+
`vault "${vaultName}" is not an adopted partition (no _meta/adoption). createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
const adoption = JSON.parse(adoptionEnv._data);
|
|
484
|
+
if (adoption.consumedAt !== void 0 || adoption.transferSeal === void 0) {
|
|
485
|
+
throw new AdoptionStateError(
|
|
486
|
+
`vault "${vaultName}" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey);
|
|
490
|
+
const existingKeyring = await store.get(vaultName, "_keyring", userId);
|
|
491
|
+
const otherOwners = (await store.list(vaultName, "_keyring")).filter((u) => u !== userId);
|
|
492
|
+
if (otherOwners.length > 0) {
|
|
493
|
+
throw new AdoptionStateError(
|
|
494
|
+
`vault "${vaultName}" already has a keyring for a different owner; cannot create owner "${userId}".`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
const partitionCollections = [...partitionDeks.keys()];
|
|
498
|
+
const priorDeks = existingKeyring ? JSON.parse(existingKeyring._data).deks : {};
|
|
499
|
+
const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks);
|
|
500
|
+
if (!ownerMinted) {
|
|
501
|
+
const passphrase = isManaged(opts) ? await resolveManagedSecret(store, vaultName, opts.sealingKey) : opts.passphrase;
|
|
502
|
+
const unlocked = await createOwnerKeyring(store, vaultName, userId, passphrase);
|
|
503
|
+
const env = await store.get(vaultName, "_keyring", userId);
|
|
504
|
+
if (!env) throw new AdoptionStateError(`keyring write for "${userId}" did not persist`);
|
|
505
|
+
const keyringFile = JSON.parse(env._data);
|
|
506
|
+
const kek = unlocked.kek;
|
|
507
|
+
if (!kek) throw new AdoptionStateError(`owner keyring for "${userId}" has no KEK to wrap partition DEKs under`);
|
|
508
|
+
const mergedDeks = { ...keyringFile.deks };
|
|
509
|
+
for (const [collection, dek] of partitionDeks) {
|
|
510
|
+
mergedDeks[collection] = await wrapKey(dek, kek);
|
|
511
|
+
}
|
|
512
|
+
const mergedFile = { ...keyringFile, deks: mergedDeks };
|
|
513
|
+
await store.put(vaultName, "_keyring", userId, { ...env, _data: JSON.stringify(mergedFile) });
|
|
514
|
+
}
|
|
515
|
+
const ledgerDek = partitionDeks.get(LEDGER_COLLECTION);
|
|
516
|
+
if (ledgerDek) {
|
|
517
|
+
const ledger = new LedgerStore({
|
|
518
|
+
adapter: store,
|
|
519
|
+
vault: vaultName,
|
|
520
|
+
encrypted: true,
|
|
521
|
+
getDEK: async () => ledgerDek,
|
|
522
|
+
actor: userId
|
|
523
|
+
});
|
|
524
|
+
const creationReason = `creation-of-new-owner:${userId}`;
|
|
525
|
+
const consumedReason = `transfer-seal-consumed:${adoption.sealId}`;
|
|
526
|
+
const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason));
|
|
527
|
+
if (!recordedReasons.has(creationReason)) {
|
|
528
|
+
await ledger.append({ op: "lifecycle", collection: "", id: "", version: 0, actor: "", payloadHash: "", reason: creationReason });
|
|
529
|
+
}
|
|
530
|
+
if (!recordedReasons.has(consumedReason)) {
|
|
531
|
+
await ledger.append({ op: "lifecycle", collection: "", id: "", version: 0, actor: "", payloadHash: "", reason: consumedReason });
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (isManaged(opts)) {
|
|
535
|
+
const { createNoydb } = await import("../noydb-5H3C24GG.js");
|
|
536
|
+
const db = await createNoydb({
|
|
537
|
+
store,
|
|
538
|
+
user: userId,
|
|
539
|
+
passphraseMode: "managed",
|
|
540
|
+
sealingKey: opts.sealingKey,
|
|
541
|
+
shamirRecovery: opts.shamirRecovery
|
|
542
|
+
});
|
|
543
|
+
await db.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery });
|
|
544
|
+
}
|
|
545
|
+
const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
546
|
+
await store.put(vaultName, "_meta", "adoption", { ...adoptionEnv, _data: JSON.stringify(consumed) });
|
|
547
|
+
return { vaultName, userId };
|
|
548
|
+
}
|
|
24
549
|
export {
|
|
550
|
+
AdoptionStateError,
|
|
551
|
+
BackupCorruptedError,
|
|
552
|
+
BackupLedgerError,
|
|
553
|
+
BundleIntegrityError,
|
|
554
|
+
BundleSealMismatchError,
|
|
555
|
+
BundleVersionConflictError,
|
|
25
556
|
COMPRESSION_BROTLI,
|
|
26
557
|
COMPRESSION_GZIP,
|
|
27
558
|
COMPRESSION_NONE,
|
|
@@ -30,13 +561,21 @@ export {
|
|
|
30
561
|
NOYDB_BUNDLE_FORMAT_VERSION,
|
|
31
562
|
NOYDB_BUNDLE_MAGIC,
|
|
32
563
|
NOYDB_BUNDLE_PREFIX_BYTES,
|
|
564
|
+
PartitionExtractionError,
|
|
565
|
+
TransferSealError,
|
|
566
|
+
adoptPartition,
|
|
567
|
+
createOwnerOnAdoptedPartition,
|
|
568
|
+
describeExtraction,
|
|
33
569
|
encodeBundleHeader,
|
|
570
|
+
extractPartition,
|
|
34
571
|
generateULID,
|
|
35
572
|
isULID,
|
|
36
573
|
readNoydbBundle,
|
|
37
574
|
readNoydbBundleHeader,
|
|
38
575
|
resetBrotliSupportCache,
|
|
576
|
+
unsealDeks,
|
|
39
577
|
validateBundleHeader,
|
|
578
|
+
walkClosure,
|
|
40
579
|
writeNoydbBundle
|
|
41
580
|
};
|
|
42
581
|
//# sourceMappingURL=index.js.map
|