@noy-db/hub 0.2.0-pre.8 → 0.3.0-pre.1
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 +129 -3
- package/dist/adapter/index.d.ts +5 -0
- package/dist/adapter/index.js +15 -0
- package/dist/aggregate/index.d.ts +6 -2
- package/dist/aggregate/index.js +24 -16
- package/dist/aggregate/index.js.map +1 -1
- package/dist/api-RW3KP7WU.js +14 -0
- package/dist/as/index.d.ts +7 -0
- package/dist/as/index.js +24 -0
- package/dist/at/index.d.ts +5 -0
- package/dist/at/index.js +1 -0
- package/dist/attestation/index.d.ts +15 -47
- package/dist/attestation/index.js +54 -10
- package/dist/attestation/index.js.map +1 -1
- package/dist/backup-XV3IOEGB.js +217 -0
- package/dist/backup-XV3IOEGB.js.map +1 -0
- package/dist/blobs/index.d.ts +6 -8
- package/dist/blobs/index.js +19 -12
- package/dist/blobs/index.js.map +1 -1
- package/dist/bundle/index.d.ts +16 -70
- package/dist/bundle/index.js +39 -476
- package/dist/bundle/index.js.map +1 -1
- package/dist/{ulid-BFJkYRRW.d.ts → bundle-CH-H06dp.d.ts} +31 -86
- package/dist/by/index.d.ts +1 -0
- package/dist/by/index.js +11 -0
- package/dist/cargo/index.d.ts +9 -0
- package/dist/cargo/index.js +89 -0
- package/dist/chunk-26LGBE4T.js +42 -0
- package/dist/chunk-26LGBE4T.js.map +1 -0
- package/dist/chunk-2P2HZEXU.js +233 -0
- package/dist/chunk-2P2HZEXU.js.map +1 -0
- package/dist/{chunk-K3DK3NU5.js → chunk-3YFXJ3ZP.js} +20 -5
- package/dist/chunk-3YFXJ3ZP.js.map +1 -0
- package/dist/chunk-4Q6HSHHL.js +90 -0
- package/dist/chunk-4Q6HSHHL.js.map +1 -0
- package/dist/chunk-5LUY7UTV.js +380 -0
- package/dist/chunk-5LUY7UTV.js.map +1 -0
- package/dist/chunk-5N6CZTCY.js +367 -0
- package/dist/chunk-5N6CZTCY.js.map +1 -0
- package/dist/chunk-5O3AOPDT.js +992 -0
- package/dist/chunk-5O3AOPDT.js.map +1 -0
- package/dist/chunk-5R3ERCDH.js +239 -0
- package/dist/chunk-5R3ERCDH.js.map +1 -0
- package/dist/{chunk-6774ZOQ7.js → chunk-5R5JW2JT.js} +7095 -4769
- package/dist/chunk-5R5JW2JT.js.map +1 -0
- package/dist/chunk-5TDJ56JE.js +32 -0
- package/dist/chunk-5TDJ56JE.js.map +1 -0
- package/dist/{chunk-T7JEBOGN.js → chunk-62QYRORB.js} +18 -11
- package/dist/chunk-62QYRORB.js.map +1 -0
- package/dist/{chunk-J66GRPNH.js → chunk-6S7T6WC4.js} +2 -2
- package/dist/chunk-6S7T6WC4.js.map +1 -0
- package/dist/chunk-76722EBH.js +451 -0
- package/dist/chunk-76722EBH.js.map +1 -0
- package/dist/{chunk-Z6FNBOTC.js → chunk-AIWULCUO.js} +13 -17
- package/dist/chunk-AIWULCUO.js.map +1 -0
- package/dist/{chunk-O3VZPBZG.js → chunk-AQTBSL7R.js} +47 -11
- package/dist/chunk-AQTBSL7R.js.map +1 -0
- package/dist/chunk-AURFOK3D.js +35 -0
- package/dist/chunk-AURFOK3D.js.map +1 -0
- package/dist/{chunk-53XBRIRT.js → chunk-AXRXJTE2.js} +9 -9
- package/dist/chunk-AXRXJTE2.js.map +1 -0
- package/dist/chunk-AZAOEIKW.js +155 -0
- package/dist/chunk-AZAOEIKW.js.map +1 -0
- package/dist/{chunk-HNRHLRDC.js → chunk-BG3SPSR4.js} +3 -3
- package/dist/chunk-BG3SPSR4.js.map +1 -0
- package/dist/chunk-BGIZAFY7.js +1 -0
- package/dist/chunk-CHFZDSE4.js +1 -0
- package/dist/{chunk-DJHHA6XH.js → chunk-CMGR4ZEW.js} +50 -20
- package/dist/chunk-CMGR4ZEW.js.map +1 -0
- package/dist/chunk-CWPPNPOH.js +23 -0
- package/dist/chunk-CWPPNPOH.js.map +1 -0
- package/dist/{chunk-QODLLGQ7.js → chunk-DFEMTNPJ.js} +371 -38
- package/dist/chunk-DFEMTNPJ.js.map +1 -0
- package/dist/{chunk-ZYWZWG6G.js → chunk-DGDI2D4M.js} +10 -10
- package/dist/chunk-DGDI2D4M.js.map +1 -0
- package/dist/{chunk-SYMWGEET.js → chunk-EIZUR2XW.js} +3 -3
- package/dist/chunk-EIZUR2XW.js.map +1 -0
- package/dist/{chunk-BVRYKATC.js → chunk-FISN7WE4.js} +36 -33
- package/dist/chunk-FISN7WE4.js.map +1 -0
- package/dist/chunk-GHVIKOHT.js +1 -0
- package/dist/chunk-GYGWYIOZ.js +200 -0
- package/dist/chunk-GYGWYIOZ.js.map +1 -0
- package/dist/chunk-HCIPRAGS.js +45 -0
- package/dist/chunk-HCIPRAGS.js.map +1 -0
- package/dist/{chunk-PX35GA7L.js → chunk-I2NOIW44.js} +10 -10
- package/dist/chunk-I2NOIW44.js.map +1 -0
- package/dist/{chunk-OIF6LZUR.js → chunk-I3TIKTJO.js} +3 -3
- package/dist/chunk-I3TIKTJO.js.map +1 -0
- package/dist/chunk-I7FD46FF.js +9 -0
- package/dist/chunk-I7FD46FF.js.map +1 -0
- package/dist/chunk-IAGBDSCS.js +40 -0
- package/dist/chunk-IAGBDSCS.js.map +1 -0
- package/dist/{chunk-JWRVQKRZ.js → chunk-IELYAOGG.js} +6 -18
- package/dist/chunk-IELYAOGG.js.map +1 -0
- package/dist/chunk-IGUYVGGI.js +205 -0
- package/dist/chunk-IGUYVGGI.js.map +1 -0
- package/dist/{chunk-U26HQ6KJ.js → chunk-IO6GRPT6.js} +4 -4
- package/dist/chunk-IO6GRPT6.js.map +1 -0
- package/dist/chunk-IPB7FTQX.js +273 -0
- package/dist/chunk-IPB7FTQX.js.map +1 -0
- package/dist/chunk-ITNUCOXM.js +148 -0
- package/dist/chunk-ITNUCOXM.js.map +1 -0
- package/dist/{chunk-WPLVTJ5D.js → chunk-IUEN57TV.js} +10 -10
- package/dist/chunk-IUEN57TV.js.map +1 -0
- package/dist/{chunk-DL3HWOQ5.js → chunk-JNUWZ6D3.js} +9 -9
- package/dist/chunk-JNUWZ6D3.js.map +1 -0
- package/dist/chunk-K2WCO3NX.js +1 -0
- package/dist/chunk-KVOXU4T5.js +30 -0
- package/dist/chunk-KVOXU4T5.js.map +1 -0
- package/dist/chunk-KXGNJJXB.js +135 -0
- package/dist/chunk-KXGNJJXB.js.map +1 -0
- package/dist/chunk-LB7FD65R.js +163 -0
- package/dist/chunk-LB7FD65R.js.map +1 -0
- package/dist/{chunk-22DWZL57.js → chunk-LFLXAY2W.js} +43 -218
- package/dist/chunk-LFLXAY2W.js.map +1 -0
- package/dist/chunk-LMTH2RM6.js +129 -0
- package/dist/chunk-LMTH2RM6.js.map +1 -0
- package/dist/{aggregate/index.cjs → chunk-LV7M27WM.js} +390 -219
- package/dist/chunk-LV7M27WM.js.map +1 -0
- package/dist/{chunk-PE2FR4J3.js → chunk-LXQT4WMP.js} +16 -18
- package/dist/chunk-LXQT4WMP.js.map +1 -0
- package/dist/chunk-M2YKN37S.js +524 -0
- package/dist/chunk-M2YKN37S.js.map +1 -0
- package/dist/chunk-M6OST55S.js +14 -0
- package/dist/chunk-M6OST55S.js.map +1 -0
- package/dist/{chunk-F3GDRNUT.js → chunk-MD3Y6J3L.js} +35 -69
- package/dist/chunk-MD3Y6J3L.js.map +1 -0
- package/dist/{chunk-XJFLDA7A.js → chunk-MTMJVJ5W.js} +8 -7
- package/dist/chunk-MTMJVJ5W.js.map +1 -0
- package/dist/{chunk-DFMLEQZB.js → chunk-NF5JWERG.js} +5 -10
- package/dist/chunk-NF5JWERG.js.map +1 -0
- package/dist/{chunk-DO7C2TOG.js → chunk-PKHL44ER.js} +3 -3
- package/dist/{chunk-DO7C2TOG.js.map → chunk-PKHL44ER.js.map} +1 -1
- package/dist/chunk-PSMV73A5.js +117 -0
- package/dist/chunk-PSMV73A5.js.map +1 -0
- package/dist/chunk-PY4KJPYU.js +9 -0
- package/dist/chunk-PY4KJPYU.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/{chunk-DE6GKS6G.js → chunk-Q7SS3IME.js} +50 -9
- package/dist/chunk-Q7SS3IME.js.map +1 -0
- package/dist/chunk-QHJW5EXU.js +54 -0
- package/dist/chunk-QHJW5EXU.js.map +1 -0
- package/dist/{chunk-NONAAENK.js → chunk-RUEKROOS.js} +11 -4
- package/dist/chunk-RUEKROOS.js.map +1 -0
- package/dist/chunk-RUIMKQTA.js +23 -0
- package/dist/chunk-RUIMKQTA.js.map +1 -0
- package/dist/{chunk-TFBP23BX.js → chunk-SKF73JOP.js} +66 -7
- package/dist/chunk-SKF73JOP.js.map +1 -0
- package/dist/chunk-SM3AVUHC.js +42 -0
- package/dist/chunk-SM3AVUHC.js.map +1 -0
- package/dist/{chunk-ML236QKC.js → chunk-SMXWYP24.js} +5 -5
- package/dist/chunk-SMXWYP24.js.map +1 -0
- package/dist/chunk-SRB2XEWB.js +148 -0
- package/dist/chunk-SRB2XEWB.js.map +1 -0
- package/dist/chunk-SVLR4POP.js +64 -0
- package/dist/chunk-SVLR4POP.js.map +1 -0
- package/dist/chunk-TA66UMI4.js +123 -0
- package/dist/chunk-TA66UMI4.js.map +1 -0
- package/dist/chunk-TEILUWOI.js +664 -0
- package/dist/chunk-TEILUWOI.js.map +1 -0
- package/dist/chunk-TJYQIGAP.js +82 -0
- package/dist/chunk-TJYQIGAP.js.map +1 -0
- package/dist/{chunk-H2X3ISXG.js → chunk-UAG5KWVA.js} +7 -7
- package/dist/chunk-UAG5KWVA.js.map +1 -0
- package/dist/chunk-UDRIWL7A.js +382 -0
- package/dist/chunk-UDRIWL7A.js.map +1 -0
- package/dist/{chunk-2GLDA55J.js → chunk-UIU2THRG.js} +498 -133
- package/dist/chunk-UIU2THRG.js.map +1 -0
- package/dist/{chunk-3YPCK6JX.js → chunk-UPJNJGGA.js} +165 -423
- package/dist/chunk-UPJNJGGA.js.map +1 -0
- package/dist/chunk-UV5MFVO3.js +21 -0
- package/dist/chunk-UV5MFVO3.js.map +1 -0
- package/dist/{chunk-2WUSG3IT.js → chunk-V7RWQRG7.js} +5 -5
- package/dist/chunk-V7RWQRG7.js.map +1 -0
- package/dist/{chunk-VTKGMEPP.js → chunk-VCTFO5CO.js} +13 -3
- package/dist/chunk-VCTFO5CO.js.map +1 -0
- package/dist/{chunk-5T22KDPN.js → chunk-VFQGRQIH.js} +8 -8
- package/dist/chunk-VFQGRQIH.js.map +1 -0
- package/dist/{chunk-2QR2PQTT.js → chunk-VQNJ7UZL.js} +5 -3
- package/dist/chunk-VQNJ7UZL.js.map +1 -0
- package/dist/{chunk-DONMZAD2.js → chunk-WWGT2MDV.js} +43 -165
- package/dist/chunk-WWGT2MDV.js.map +1 -0
- package/dist/{chunk-EMIGCR7X.js → chunk-WXSYDNBT.js} +2 -2
- package/dist/chunk-WXSYDNBT.js.map +1 -0
- package/dist/chunk-WYSO2NIH.js +30 -0
- package/dist/chunk-WYSO2NIH.js.map +1 -0
- package/dist/chunk-XXYIOFUB.js +164 -0
- package/dist/chunk-XXYIOFUB.js.map +1 -0
- package/dist/{chunk-3BFJOWSU.js → chunk-Y22T3KQE.js} +35 -7
- package/dist/chunk-Y22T3KQE.js.map +1 -0
- package/dist/{chunk-A3JMGXPG.js → chunk-YMUGBZN2.js} +2 -2
- package/dist/chunk-YMUGBZN2.js.map +1 -0
- package/dist/{chunk-I5FOWO4J.js → chunk-ZCGAHGUS.js} +52 -73
- package/dist/chunk-ZCGAHGUS.js.map +1 -0
- package/dist/{chunk-FZU343FL.js → chunk-ZJADGNYF.js} +2 -2
- package/dist/chunk-ZJADGNYF.js.map +1 -0
- package/dist/{chunk-B6PB7JLN.js → chunk-ZYUC53LT.js} +427 -6
- package/dist/chunk-ZYUC53LT.js.map +1 -0
- package/dist/collection-facade-GQAOGJP2.js +33 -0
- package/dist/consent/index.d.ts +5 -7
- package/dist/consent/index.js +7 -5
- package/dist/consent/index.js.map +1 -1
- package/dist/crdt/index.d.ts +6 -2
- package/dist/crdt/index.js +3 -2
- package/dist/crdt/index.js.map +1 -1
- package/dist/decrypt-partition-IHtxEnTi.d.ts +21 -0
- package/dist/delegation-UL5HKLER.js +19 -0
- package/dist/derivations/index.d.ts +7 -9
- package/dist/derivations/index.js +11 -6
- package/dist/describe/index.d.ts +1 -0
- package/dist/describe/index.js +1 -0
- package/dist/describe-aBkJR2sd.d.ts +131 -0
- package/dist/{dev-unlock-p3ysikWP.d.ts → dev-unlock-C9Ro3v_O.d.ts} +1 -1
- package/dist/discriminant-BN9REW3o.d.ts +60 -0
- package/dist/enclave-UL5LW66V.js +88 -0
- package/dist/executor-2FWQRLMG.js +15 -0
- package/dist/executor-QZ7BXICW.js +9 -0
- package/dist/executor-Z5ZLJVTV.js +9 -0
- package/dist/export-accessible-KRV5W4GH.js +17 -0
- package/dist/extract-partition-GLKBOXFQ.js +30 -0
- package/dist/{fanout-sidecar-OKPMMPLG.js → fanout-sidecar-GF3DJ6KR.js} +34 -14
- package/dist/fanout-sidecar-GF3DJ6KR.js.map +1 -0
- package/dist/forget/index.d.ts +36 -0
- package/dist/forget/index.js +19 -0
- package/dist/forget/index.js.map +1 -0
- package/dist/guards/index.d.ts +13 -9
- package/dist/guards/index.js +12 -5
- package/dist/{hash-BPsYPcv_.d.cts → hash-Cp5uwiox.d.ts} +5 -1
- package/dist/history/index.d.ts +6 -8
- package/dist/history/index.js +19 -12
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.d.ts +5 -7
- package/dist/i18n/index.js +104 -15
- package/dist/i18n/index.js.map +1 -1
- package/dist/in/index.d.ts +5 -0
- package/dist/in/index.js +1 -0
- package/dist/in/index.js.map +1 -0
- package/dist/index-B9QdHytu.d.ts +123 -0
- package/dist/index-BF9_96A5.d.ts +123 -0
- package/dist/{types-DGU60JDt.d.ts → index-BzUo1B6n.d.ts} +16306 -8352
- package/dist/index.d.ts +1088 -450
- package/dist/index.js +1165 -293
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.d.ts +6 -3
- package/dist/indexing/index.js +6 -5
- package/dist/indexing/index.js.map +1 -1
- package/dist/issue-Y6UVIR43.js +13 -0
- package/dist/issue-Y6UVIR43.js.map +1 -0
- package/dist/kernel/index.d.ts +32 -0
- package/dist/kernel/index.js +53 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/{ledger-TMRZYNVJ.js → ledger-RYI35CDS.js} +12 -9
- package/dist/ledger-RYI35CDS.js.map +1 -0
- package/dist/liberate-CRPZEV7O.js +18 -0
- package/dist/liberate-CRPZEV7O.js.map +1 -0
- package/dist/materialized-views/index.d.ts +6 -19
- package/dist/materialized-views/index.js +16 -12
- package/dist/mime-magic-CGhw37_E.d.ts +103 -0
- package/dist/noydb-367AM4HT.js +50 -0
- package/dist/noydb-367AM4HT.js.map +1 -0
- package/dist/on/index.d.ts +5 -0
- package/dist/on/index.js +11 -0
- package/dist/on/index.js.map +1 -0
- package/dist/overlay-views/index.d.ts +27 -11
- package/dist/overlay-views/index.js +7 -6
- package/dist/periods/index.d.ts +5 -7
- package/dist/periods/index.js +13 -9
- package/dist/pod/index.d.ts +63 -0
- package/dist/pod/index.js +61 -0
- package/dist/pod/index.js.map +1 -0
- package/dist/policy-IXK4FVXP.js +41 -0
- package/dist/policy-IXK4FVXP.js.map +1 -0
- package/dist/portability/index.d.ts +20 -0
- package/dist/portability/index.js +43 -0
- package/dist/portability/index.js.map +1 -0
- package/dist/{public-envelope-BW6OXORV.js → public-envelope-JHDQCPSX.js} +6 -5
- package/dist/public-envelope-JHDQCPSX.js.map +1 -0
- package/dist/query/index.d.ts +5 -3
- package/dist/query/index.js +21 -13
- package/dist/read-only-facade-5ADRJVTM.js +8 -0
- package/dist/read-only-facade-5ADRJVTM.js.map +1 -0
- package/dist/registry-45RJNWGU.js +9 -0
- package/dist/registry-45RJNWGU.js.map +1 -0
- package/dist/registry-5GRV5VXI.js +13 -0
- package/dist/registry-5GRV5VXI.js.map +1 -0
- package/dist/registry-VW6P6A3J.js +8 -0
- package/dist/registry-VW6P6A3J.js.map +1 -0
- package/dist/registry-WEUCHBO4.js +11 -0
- package/dist/registry-WEUCHBO4.js.map +1 -0
- package/dist/request-withdrawal-GBPH2FDY.js +25 -0
- package/dist/request-withdrawal-GBPH2FDY.js.map +1 -0
- package/dist/revoke-TUFRGI6S.js +18 -0
- package/dist/revoke-TUFRGI6S.js.map +1 -0
- package/dist/sealed-record/index.d.ts +69 -0
- package/dist/sealed-record/index.js +65 -0
- package/dist/sealed-record/index.js.map +1 -0
- package/dist/session/index.d.ts +6 -8
- package/dist/session/index.js +7 -5
- package/dist/session/index.js.map +1 -1
- package/dist/shadow/index.d.ts +5 -7
- package/dist/shadow/index.js +4 -3
- package/dist/shadow/index.js.map +1 -1
- package/dist/{signer-72QAUSVW.js → signer-PNKTBVF7.js} +6 -5
- package/dist/signer-PNKTBVF7.js.map +1 -0
- package/dist/snapshots/index.d.ts +16 -11
- package/dist/snapshots/index.js +49 -13
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-6ZDBTQT7.js → stale-3JWHNDIY.js} +3 -2
- package/dist/stale-3JWHNDIY.js.map +1 -0
- package/dist/store-coordination-provider-3I7XWZZK.js +142 -0
- package/dist/store-coordination-provider-3I7XWZZK.js.map +1 -0
- package/dist/subject-index-O75wKshW.d.ts +362 -0
- package/dist/sync/index.d.ts +4 -6
- package/dist/sync/index.js +7 -6
- package/dist/sync/index.js.map +1 -1
- package/dist/team/index.d.ts +5 -7
- package/dist/team/index.js +20 -16
- package/dist/tiers/index.d.ts +5 -0
- package/dist/tiers/index.js +33 -0
- package/dist/tiers/index.js.map +1 -0
- package/dist/to/index.d.ts +5 -0
- package/dist/to/index.js +17 -0
- package/dist/to/index.js.map +1 -0
- package/dist/transition-guard-C7ol6oPw.d.ts +165 -0
- package/dist/tx/index.d.ts +23 -9
- package/dist/tx/index.js +13 -8
- package/dist/tx/index.js.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ulid-DRH25k3y.d.ts +66 -0
- package/dist/ulid-PTAIMDG4.js +10 -0
- package/dist/ulid-PTAIMDG4.js.map +1 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.js +7 -2
- package/dist/util/index.js.map +1 -1
- package/dist/vault-diff-B5fYNBL7.d.ts +147 -0
- package/dist/with/index.d.ts +38 -0
- package/dist/with/index.js +25 -0
- package/dist/with/index.js.map +1 -0
- package/dist/{with-materialized-view-BiasFcYx.d.ts → with-materialized-view-6p0Fk8bL.d.ts} +1 -1
- package/dist/{with-overlayed-view-CQViuko_.d.ts → with-overlayed-view-BJ6mXGMd.d.ts} +2 -3
- package/dist/with-rollup-BvQo3ROo.d.ts +47 -0
- package/dist/withdraw-accessible-FFS46EOD.js +22 -0
- package/dist/withdraw-accessible-FFS46EOD.js.map +1 -0
- package/dist/zod-HAJM7LMS.js +14763 -0
- package/dist/zod-HAJM7LMS.js.map +1 -0
- package/package.json +121 -201
- package/dist/aggregate/index.cjs.map +0 -1
- package/dist/aggregate/index.d.cts +0 -38
- package/dist/attestation/index.cjs +0 -305
- package/dist/attestation/index.cjs.map +0 -1
- package/dist/attestation/index.d.cts +0 -52
- package/dist/blobs/index.cjs +0 -1480
- package/dist/blobs/index.cjs.map +0 -1
- package/dist/blobs/index.d.cts +0 -46
- package/dist/bundle/index.cjs +0 -19104
- package/dist/bundle/index.cjs.map +0 -1
- package/dist/bundle/index.d.cts +0 -176
- package/dist/chunk-22DWZL57.js.map +0 -1
- package/dist/chunk-2GLDA55J.js.map +0 -1
- package/dist/chunk-2QR2PQTT.js.map +0 -1
- package/dist/chunk-2WUSG3IT.js.map +0 -1
- package/dist/chunk-3BFJOWSU.js.map +0 -1
- package/dist/chunk-3YPCK6JX.js.map +0 -1
- package/dist/chunk-53XBRIRT.js.map +0 -1
- package/dist/chunk-5T22KDPN.js.map +0 -1
- package/dist/chunk-5XHKQ56N.js +0 -340
- package/dist/chunk-5XHKQ56N.js.map +0 -1
- package/dist/chunk-6774ZOQ7.js.map +0 -1
- package/dist/chunk-6STK5TQP.js +0 -139
- package/dist/chunk-6STK5TQP.js.map +0 -1
- package/dist/chunk-A3JMGXPG.js.map +0 -1
- package/dist/chunk-B6PB7JLN.js.map +0 -1
- package/dist/chunk-BVRYKATC.js.map +0 -1
- package/dist/chunk-DE6GKS6G.js.map +0 -1
- package/dist/chunk-DFMLEQZB.js.map +0 -1
- package/dist/chunk-DJHHA6XH.js.map +0 -1
- package/dist/chunk-DL3HWOQ5.js.map +0 -1
- package/dist/chunk-DONMZAD2.js.map +0 -1
- package/dist/chunk-EMIGCR7X.js.map +0 -1
- package/dist/chunk-F3GDRNUT.js.map +0 -1
- package/dist/chunk-FZU343FL.js.map +0 -1
- package/dist/chunk-H2X3ISXG.js.map +0 -1
- package/dist/chunk-HNRHLRDC.js.map +0 -1
- package/dist/chunk-I5FOWO4J.js.map +0 -1
- package/dist/chunk-J66GRPNH.js.map +0 -1
- package/dist/chunk-JWRVQKRZ.js.map +0 -1
- package/dist/chunk-K3DK3NU5.js.map +0 -1
- package/dist/chunk-ML236QKC.js.map +0 -1
- package/dist/chunk-NONAAENK.js.map +0 -1
- package/dist/chunk-O3VZPBZG.js.map +0 -1
- package/dist/chunk-OIF6LZUR.js.map +0 -1
- package/dist/chunk-OQ6PIGHA.js +0 -19
- package/dist/chunk-OQ6PIGHA.js.map +0 -1
- package/dist/chunk-PE2FR4J3.js.map +0 -1
- package/dist/chunk-PP6W64Y3.js +0 -275
- package/dist/chunk-PP6W64Y3.js.map +0 -1
- package/dist/chunk-PX35GA7L.js.map +0 -1
- package/dist/chunk-QEILDE6R.js +0 -793
- package/dist/chunk-QEILDE6R.js.map +0 -1
- package/dist/chunk-QODLLGQ7.js.map +0 -1
- package/dist/chunk-RAZ4OVLL.js +0 -51
- package/dist/chunk-RAZ4OVLL.js.map +0 -1
- package/dist/chunk-SYMWGEET.js.map +0 -1
- package/dist/chunk-T7JEBOGN.js.map +0 -1
- package/dist/chunk-TFBP23BX.js.map +0 -1
- package/dist/chunk-TV3YZ35S.js +0 -90
- package/dist/chunk-TV3YZ35S.js.map +0 -1
- package/dist/chunk-U26HQ6KJ.js.map +0 -1
- package/dist/chunk-UF3BUNQZ.js +0 -1
- package/dist/chunk-UMLVJTYV.js +0 -20
- package/dist/chunk-UMLVJTYV.js.map +0 -1
- package/dist/chunk-VTKGMEPP.js.map +0 -1
- package/dist/chunk-W6EQLGMB.js +0 -100
- package/dist/chunk-W6EQLGMB.js.map +0 -1
- package/dist/chunk-WIRRPTFH.js +0 -17
- package/dist/chunk-WIRRPTFH.js.map +0 -1
- package/dist/chunk-WPLVTJ5D.js.map +0 -1
- package/dist/chunk-XJFLDA7A.js.map +0 -1
- package/dist/chunk-Z6FNBOTC.js.map +0 -1
- package/dist/chunk-ZYWZWG6G.js.map +0 -1
- package/dist/consent/index.cjs +0 -204
- package/dist/consent/index.cjs.map +0 -1
- package/dist/consent/index.d.cts +0 -25
- package/dist/crdt/index.cjs +0 -152
- package/dist/crdt/index.cjs.map +0 -1
- package/dist/crdt/index.d.cts +0 -30
- package/dist/crypto-HTZ4FJOP.js +0 -44
- package/dist/delegation-RI54P6I5.js +0 -17
- package/dist/derivations/index.cjs +0 -351
- package/dist/derivations/index.cjs.map +0 -1
- package/dist/derivations/index.d.cts +0 -72
- package/dist/dev-unlock-M4VAWNq_.d.cts +0 -263
- package/dist/executor-5PNY7LGW.js +0 -8
- package/dist/executor-B4QIYGZX.js +0 -8
- package/dist/executor-BWXXDQ7K.js +0 -11
- package/dist/fanout-sidecar-OKPMMPLG.js.map +0 -1
- package/dist/guards/index.cjs +0 -322
- package/dist/guards/index.cjs.map +0 -1
- package/dist/guards/index.d.cts +0 -31
- package/dist/hash-C1GtiOhR.d.ts +0 -63
- package/dist/history/index.cjs +0 -1222
- package/dist/history/index.cjs.map +0 -1
- package/dist/history/index.d.cts +0 -63
- package/dist/i18n/index.cjs +0 -1100
- package/dist/i18n/index.cjs.map +0 -1
- package/dist/i18n/index.d.cts +0 -39
- package/dist/index-4fBVt8j9.d.cts +0 -2387
- package/dist/index-D8I_pyJD.d.ts +0 -2387
- package/dist/index.cjs +0 -24334
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -776
- package/dist/indexing/index.cjs +0 -742
- package/dist/indexing/index.cjs.map +0 -1
- package/dist/indexing/index.d.cts +0 -36
- package/dist/issue-VGDPP4B5.js +0 -12
- package/dist/lazy-builder-7tIpFyWN.d.ts +0 -304
- package/dist/lazy-builder-wY4pMCEe.d.cts +0 -304
- package/dist/materialized-views/index.cjs +0 -854
- package/dist/materialized-views/index.cjs.map +0 -1
- package/dist/materialized-views/index.d.cts +0 -186
- package/dist/mime-magic-CBBSOkjm.d.cts +0 -50
- package/dist/mime-magic-CBBSOkjm.d.ts +0 -50
- package/dist/noydb-LZBH3XDK.js +0 -34
- package/dist/overlay-views/index.cjs +0 -359
- package/dist/overlay-views/index.cjs.map +0 -1
- package/dist/overlay-views/index.d.cts +0 -82
- package/dist/periods/index.cjs +0 -1041
- package/dist/periods/index.cjs.map +0 -1
- package/dist/periods/index.d.cts +0 -22
- package/dist/predicate-BSAGEyu5.d.cts +0 -209
- package/dist/predicate-BSAGEyu5.d.ts +0 -209
- package/dist/query/index.cjs +0 -2375
- package/dist/query/index.cjs.map +0 -1
- package/dist/query/index.d.cts +0 -3
- package/dist/read-only-facade-ITU6L7BL.js +0 -7
- package/dist/registry-3QP3YKQS.js +0 -8
- package/dist/registry-DKEXOJVO.js +0 -7
- package/dist/registry-OJIOSBV6.js +0 -10
- package/dist/registry-USRVT6YF.js +0 -8
- package/dist/revoke-JCC7N56X.js +0 -17
- package/dist/session/index.cjs +0 -495
- package/dist/session/index.cjs.map +0 -1
- package/dist/session/index.d.cts +0 -46
- package/dist/shadow/index.cjs +0 -133
- package/dist/shadow/index.cjs.map +0 -1
- package/dist/shadow/index.d.cts +0 -17
- package/dist/snapshots/index.cjs +0 -903
- package/dist/snapshots/index.cjs.map +0 -1
- package/dist/snapshots/index.d.cts +0 -21
- package/dist/store/index.cjs +0 -1083
- package/dist/store/index.cjs.map +0 -1
- package/dist/store/index.d.cts +0 -492
- package/dist/store/index.d.ts +0 -492
- package/dist/store/index.js +0 -37
- package/dist/strategy-BSxFXGzb.d.cts +0 -110
- package/dist/strategy-BSxFXGzb.d.ts +0 -110
- package/dist/strategy-DSTrsZ8t.d.cts +0 -601
- package/dist/strategy-DSTrsZ8t.d.ts +0 -601
- package/dist/sync/index.cjs +0 -1062
- package/dist/sync/index.cjs.map +0 -1
- package/dist/sync/index.d.cts +0 -43
- package/dist/team/index.cjs +0 -2798
- package/dist/team/index.cjs.map +0 -1
- package/dist/team/index.d.cts +0 -118
- package/dist/tx/index.cjs +0 -544
- package/dist/tx/index.cjs.map +0 -1
- package/dist/tx/index.d.cts +0 -21
- package/dist/types-DjunxzJa.d.cts +0 -12776
- package/dist/ulid-COREQ2RQ.js +0 -9
- package/dist/ulid-DPeuPgi3.d.cts +0 -603
- package/dist/util/index.cjs +0 -230
- package/dist/util/index.cjs.map +0 -1
- package/dist/util/index.d.cts +0 -77
- package/dist/with-derivation-Df0kMlED.d.cts +0 -13
- package/dist/with-derivation-DfOpKjFw.d.ts +0 -13
- package/dist/with-guard-0KksDtSR.d.ts +0 -18
- package/dist/with-guard-C6W5RVrH.d.cts +0 -18
- package/dist/with-materialized-view-BmDKyHrm.d.cts +0 -27
- package/dist/with-overlayed-view-CA66vhHz.d.cts +0 -13
- /package/dist/{store → adapter}/index.js.map +0 -0
- /package/dist/{chunk-UF3BUNQZ.js.map → api-RW3KP7WU.js.map} +0 -0
- /package/dist/{crypto-HTZ4FJOP.js.map → as/index.js.map} +0 -0
- /package/dist/{delegation-RI54P6I5.js.map → at/index.js.map} +0 -0
- /package/dist/{executor-5PNY7LGW.js.map → by/index.js.map} +0 -0
- /package/dist/{executor-B4QIYGZX.js.map → cargo/index.js.map} +0 -0
- /package/dist/{executor-BWXXDQ7K.js.map → chunk-BGIZAFY7.js.map} +0 -0
- /package/dist/{issue-VGDPP4B5.js.map → chunk-CHFZDSE4.js.map} +0 -0
- /package/dist/{ledger-TMRZYNVJ.js.map → chunk-GHVIKOHT.js.map} +0 -0
- /package/dist/{noydb-LZBH3XDK.js.map → chunk-K2WCO3NX.js.map} +0 -0
- /package/dist/{public-envelope-BW6OXORV.js.map → chunk-PZ5AY32C.js.map} +0 -0
- /package/dist/{read-only-facade-ITU6L7BL.js.map → collection-facade-GQAOGJP2.js.map} +0 -0
- /package/dist/{registry-3QP3YKQS.js.map → delegation-UL5HKLER.js.map} +0 -0
- /package/dist/{registry-DKEXOJVO.js.map → describe/index.js.map} +0 -0
- /package/dist/{registry-OJIOSBV6.js.map → enclave-UL5LW66V.js.map} +0 -0
- /package/dist/{registry-USRVT6YF.js.map → executor-2FWQRLMG.js.map} +0 -0
- /package/dist/{revoke-JCC7N56X.js.map → executor-QZ7BXICW.js.map} +0 -0
- /package/dist/{signer-72QAUSVW.js.map → executor-Z5ZLJVTV.js.map} +0 -0
- /package/dist/{stale-6ZDBTQT7.js.map → export-accessible-KRV5W4GH.js.map} +0 -0
- /package/dist/{ulid-COREQ2RQ.js.map → extract-partition-GLKBOXFQ.js.map} +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveManagedSecret
|
|
3
|
+
} from "./chunk-ZCGAHGUS.js";
|
|
4
|
+
import {
|
|
5
|
+
parseExtractedPartitionBody,
|
|
6
|
+
readPod,
|
|
7
|
+
readPodHeader
|
|
8
|
+
} from "./chunk-FISN7WE4.js";
|
|
9
|
+
import {
|
|
10
|
+
createOwnerKeyring
|
|
11
|
+
} from "./chunk-WWGT2MDV.js";
|
|
12
|
+
import {
|
|
13
|
+
LedgerStore
|
|
14
|
+
} from "./chunk-LXQT4WMP.js";
|
|
15
|
+
import {
|
|
16
|
+
LEDGER_COLLECTION
|
|
17
|
+
} from "./chunk-I7FD46FF.js";
|
|
18
|
+
import {
|
|
19
|
+
base64ToBuffer,
|
|
20
|
+
openEnvelopeJson,
|
|
21
|
+
wrapKey
|
|
22
|
+
} from "./chunk-5O3AOPDT.js";
|
|
23
|
+
import {
|
|
24
|
+
AdoptionStateError,
|
|
25
|
+
TransferSealError,
|
|
26
|
+
ValidationError
|
|
27
|
+
} from "./chunk-ZYUC53LT.js";
|
|
28
|
+
|
|
29
|
+
// src/with-cargo/adopt-partition.ts
|
|
30
|
+
async function unsealDeks(seal, transferKey) {
|
|
31
|
+
if (transferKey.byteLength !== 32) {
|
|
32
|
+
throw new TransferSealError(
|
|
33
|
+
`transfer key must be 32 bytes, got ${transferKey.byteLength}.`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
const key = await crypto.subtle.importKey("raw", transferKey, "AES-GCM", false, ["decrypt"]);
|
|
37
|
+
const raw = base64ToBuffer(seal.payload);
|
|
38
|
+
let plaintext;
|
|
39
|
+
try {
|
|
40
|
+
plaintext = await crypto.subtle.decrypt(
|
|
41
|
+
{ name: "AES-GCM", iv: raw.slice(0, 12) },
|
|
42
|
+
key,
|
|
43
|
+
raw.slice(12)
|
|
44
|
+
);
|
|
45
|
+
} catch {
|
|
46
|
+
throw new TransferSealError(
|
|
47
|
+
"transfer seal could not be opened \u2014 wrong transfer key (AES-GCM authentication failed)."
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
let dekMap;
|
|
51
|
+
try {
|
|
52
|
+
dekMap = JSON.parse(new TextDecoder().decode(plaintext));
|
|
53
|
+
} catch {
|
|
54
|
+
throw new TransferSealError("transfer seal payload is not valid JSON after decryption.");
|
|
55
|
+
}
|
|
56
|
+
const deks = /* @__PURE__ */ new Map();
|
|
57
|
+
for (const [collection, b64] of Object.entries(dekMap)) {
|
|
58
|
+
const dek = await crypto.subtle.importKey("raw", base64ToBuffer(b64), "AES-GCM", true, ["encrypt", "decrypt"]);
|
|
59
|
+
deks.set(collection, dek);
|
|
60
|
+
}
|
|
61
|
+
return deks;
|
|
62
|
+
}
|
|
63
|
+
async function adoptPartition(bundleBytes, opts) {
|
|
64
|
+
const { transferKey, destinationStore, vaultName } = opts;
|
|
65
|
+
const header = readPodHeader(bundleBytes);
|
|
66
|
+
if (header.bundleKind !== "extracted-partition" || header.transferSeal === void 0) {
|
|
67
|
+
throw new ValidationError(
|
|
68
|
+
"adoptPartition requires an extracted-partition bundle with a transfer seal. For ordinary backups use readPod + vault.load."
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const { dumpJson } = await readPod(bundleBytes);
|
|
72
|
+
const { dump, seal } = parseExtractedPartitionBody(dumpJson);
|
|
73
|
+
await unsealDeks(seal, transferKey);
|
|
74
|
+
const existing = await destinationStore.get(vaultName, "_meta", "adoption");
|
|
75
|
+
if (existing) {
|
|
76
|
+
const prior = JSON.parse(existing._data);
|
|
77
|
+
if (prior.sealId === seal.sealId) {
|
|
78
|
+
throw new AdoptionStateError(
|
|
79
|
+
`partition (sealId ${seal.sealId}) is already adopted into vault "${vaultName}".`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
throw new AdoptionStateError(
|
|
83
|
+
`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.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const existingKeyring = await destinationStore.list(vaultName, "_keyring");
|
|
87
|
+
if (existingKeyring.length > 0) {
|
|
88
|
+
throw new AdoptionStateError(
|
|
89
|
+
`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.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const backup = JSON.parse(dump);
|
|
93
|
+
await destinationStore.saveAll(vaultName, backup.collections);
|
|
94
|
+
if (backup._internal) {
|
|
95
|
+
for (const [collection, records] of Object.entries(backup._internal)) {
|
|
96
|
+
for (const [id, envelope] of Object.entries(records)) {
|
|
97
|
+
await destinationStore.put(vaultName, collection, id, envelope);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const adoptedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
102
|
+
const adoption = { sealId: seal.sealId, adoptedAt, needsOwner: true, transferSeal: seal };
|
|
103
|
+
await destinationStore.put(vaultName, "_meta", "adoption", {
|
|
104
|
+
_noydb: 1,
|
|
105
|
+
_v: 1,
|
|
106
|
+
_ts: adoptedAt,
|
|
107
|
+
_iv: "",
|
|
108
|
+
_data: JSON.stringify(adoption)
|
|
109
|
+
});
|
|
110
|
+
return { vaultName, needsOwner: true, sealId: seal.sealId };
|
|
111
|
+
}
|
|
112
|
+
function isManaged(o) {
|
|
113
|
+
return "passphraseMode" in o && o.passphraseMode === "managed";
|
|
114
|
+
}
|
|
115
|
+
async function createOwnerOnAdoptedPartition(store, vaultName, opts) {
|
|
116
|
+
const { userId, transferKey } = opts;
|
|
117
|
+
if (isManaged(opts) && !opts.recovery.some((r) => r.profile === "shamir")) {
|
|
118
|
+
throw new AdoptionStateError(
|
|
119
|
+
"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."
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const adoptionEnv = await store.get(vaultName, "_meta", "adoption");
|
|
123
|
+
if (!adoptionEnv) {
|
|
124
|
+
throw new AdoptionStateError(
|
|
125
|
+
`vault "${vaultName}" is not an adopted partition (no _meta/adoption). createOwnerOnAdoptedPartition only applies to vaults created via adoptPartition.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const adoption = JSON.parse(adoptionEnv._data);
|
|
129
|
+
if (adoption.consumedAt !== void 0 || adoption.transferSeal === void 0) {
|
|
130
|
+
throw new AdoptionStateError(
|
|
131
|
+
`vault "${vaultName}" already has an owner (transfer seal consumed at ${adoption.consumedAt}).`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
const partitionDeks = await unsealDeks(adoption.transferSeal, transferKey);
|
|
135
|
+
const existingKeyring = await store.get(vaultName, "_keyring", userId);
|
|
136
|
+
const otherOwners = (await store.list(vaultName, "_keyring")).filter((u) => u !== userId);
|
|
137
|
+
if (otherOwners.length > 0) {
|
|
138
|
+
throw new AdoptionStateError(
|
|
139
|
+
`vault "${vaultName}" already has a keyring for a different owner; cannot create owner "${userId}".`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const partitionCollections = [...partitionDeks.keys()];
|
|
143
|
+
const priorDeks = existingKeyring ? JSON.parse(existingKeyring._data).deks : {};
|
|
144
|
+
const ownerMinted = existingKeyring !== null && partitionCollections.every((c) => c in priorDeks);
|
|
145
|
+
if (!ownerMinted) {
|
|
146
|
+
const passphrase = isManaged(opts) ? await resolveManagedSecret(store, vaultName, opts.sealingKey) : opts.passphrase;
|
|
147
|
+
const unlocked = await createOwnerKeyring(store, vaultName, userId, passphrase);
|
|
148
|
+
const env = await store.get(vaultName, "_keyring", userId);
|
|
149
|
+
if (!env) throw new AdoptionStateError(`keyring write for "${userId}" did not persist`);
|
|
150
|
+
const keyringFile = JSON.parse(env._data);
|
|
151
|
+
const kek = unlocked.kek;
|
|
152
|
+
if (!kek) throw new AdoptionStateError(`owner keyring for "${userId}" has no KEK to wrap partition DEKs under`);
|
|
153
|
+
const mergedDeks = { ...keyringFile.deks };
|
|
154
|
+
for (const [collection, dek] of partitionDeks) {
|
|
155
|
+
mergedDeks[collection] = await wrapKey(dek, kek);
|
|
156
|
+
}
|
|
157
|
+
const mergedFile = { ...keyringFile, deks: mergedDeks };
|
|
158
|
+
await store.put(vaultName, "_keyring", userId, { ...env, _data: JSON.stringify(mergedFile) });
|
|
159
|
+
}
|
|
160
|
+
const ledgerDek = partitionDeks.get(LEDGER_COLLECTION);
|
|
161
|
+
if (ledgerDek) {
|
|
162
|
+
const ledger = new LedgerStore({
|
|
163
|
+
adapter: store,
|
|
164
|
+
vault: vaultName,
|
|
165
|
+
encrypted: true,
|
|
166
|
+
getDEK: async () => ledgerDek,
|
|
167
|
+
actor: userId
|
|
168
|
+
});
|
|
169
|
+
const creationReason = `creation-of-new-owner:${userId}`;
|
|
170
|
+
const consumedReason = `transfer-seal-consumed:${adoption.sealId}`;
|
|
171
|
+
const recordedReasons = new Set((await ledger.loadAllEntries()).map((e) => e.reason));
|
|
172
|
+
if (!recordedReasons.has(creationReason)) {
|
|
173
|
+
await ledger.append({ op: "lifecycle", collection: "", id: "", version: 0, actor: "", payloadHash: "", reason: creationReason });
|
|
174
|
+
}
|
|
175
|
+
if (!recordedReasons.has(consumedReason)) {
|
|
176
|
+
await ledger.append({ op: "lifecycle", collection: "", id: "", version: 0, actor: "", payloadHash: "", reason: consumedReason });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (isManaged(opts)) {
|
|
180
|
+
const { createNoydb } = await import("./noydb-367AM4HT.js");
|
|
181
|
+
const db = await createNoydb({
|
|
182
|
+
store,
|
|
183
|
+
user: userId,
|
|
184
|
+
passphraseMode: "managed",
|
|
185
|
+
sealingKey: opts.sealingKey,
|
|
186
|
+
shamirRecovery: opts.shamirRecovery
|
|
187
|
+
});
|
|
188
|
+
await db.openVaultAndEnrollRecovery(vaultName, { recovery: opts.recovery });
|
|
189
|
+
}
|
|
190
|
+
const consumed = { sealId: adoption.sealId, adoptedAt: adoption.adoptedAt, consumedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
191
|
+
await store.put(vaultName, "_meta", "adoption", { ...adoptionEnv, _data: JSON.stringify(consumed) });
|
|
192
|
+
return { vaultName, userId };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// src/with-cargo/decrypt-partition.ts
|
|
196
|
+
async function decryptExtractedPartition(bundleBytes, transferKey) {
|
|
197
|
+
const header = readPodHeader(bundleBytes);
|
|
198
|
+
if (header.bundleKind !== "extracted-partition" || header.transferSeal === void 0) {
|
|
199
|
+
throw new Error("decryptExtractedPartition: bundle is not an extracted-partition.");
|
|
200
|
+
}
|
|
201
|
+
const { dumpJson } = await readPod(bundleBytes);
|
|
202
|
+
const { dump, seal } = parseExtractedPartitionBody(dumpJson);
|
|
203
|
+
const deks = await unsealDeks(seal, transferKey);
|
|
204
|
+
const backup = JSON.parse(dump);
|
|
205
|
+
const out = {};
|
|
206
|
+
for (const [collection, byId] of Object.entries(backup.collections)) {
|
|
207
|
+
const dek = deks.get(collection);
|
|
208
|
+
if (dek === void 0) continue;
|
|
209
|
+
const recs = [];
|
|
210
|
+
for (const [id, env] of Object.entries(byId)) {
|
|
211
|
+
const plaintext = await openEnvelopeJson(env, dek);
|
|
212
|
+
const body = JSON.parse(plaintext);
|
|
213
|
+
recs.push({
|
|
214
|
+
id,
|
|
215
|
+
record: { ...body, id },
|
|
216
|
+
ts: env._ts,
|
|
217
|
+
version: env._v,
|
|
218
|
+
...env._source !== void 0 ? { source: env._source } : {},
|
|
219
|
+
...env._sourceTs !== void 0 ? { sourceTs: env._sourceTs } : {}
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
out[collection] = recs;
|
|
223
|
+
}
|
|
224
|
+
return out;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export {
|
|
228
|
+
unsealDeks,
|
|
229
|
+
adoptPartition,
|
|
230
|
+
createOwnerOnAdoptedPartition,
|
|
231
|
+
decryptExtractedPartition
|
|
232
|
+
};
|
|
233
|
+
//# sourceMappingURL=chunk-2P2HZEXU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-cargo/adopt-partition.ts","../src/with-cargo/decrypt-partition.ts"],"sourcesContent":["/**\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, type EnclaveKey } from '../kernel/enclave/index.js'\nimport { TransferSealError, AdoptionStateError, ValidationError } from '../kernel/errors.js'\nimport type { NoydbStore, VaultSnapshot, KeyringFile } from '../kernel/types.js'\nimport { createOwnerKeyring } from '../with-party/team/keyring.js'\nimport { resolveManagedSecret } from '../with-party/team/managed-passphrase.js'\nimport type { SealingKeyProvider } from '../with-party/team/managed-passphrase.js'\nimport type { ShamirRecoveryProvider } from '../with-party/team/shamir-recovery-provider.js'\nimport type { RecoveryEnrollmentInput } from '../with-party/team/rotate-recover.js'\nimport { LedgerStore } from '../with-commit/history/ledger/store.js'\nimport { LEDGER_COLLECTION } from '../with-commit/history/ledger/constants.js'\nimport type { TransferSealPayload } from '../with-pod/bundle.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/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, EnclaveKey>> {\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, EnclaveKey>()\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 = readPodHeader(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 readPod + vault.load.',\n )\n }\n\n const { dumpJson } = await readPod(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('../kernel/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","/**\n * Read-side counterpart to `extractPartition`: decrypt an\n * extracted-partition bundle's records to plaintext using its transfer\n * key, WITHOUT adopting it into a vault. Used by an outward\n * orchestration layer's reconcile/merge and field-authority flows to\n * compare incoming records against a receiver. The transfer key validates the bundle\n * (wrong key throws).\n * @module\n */\nimport type { EncryptedEnvelope } from '../kernel/types.js'\nimport { openEnvelopeJson } from '../kernel/enclave/index.js'\nimport { readPodHeader, readPod, parseExtractedPartitionBody } from '../with-pod/bundle.js'\nimport { unsealDeks } from './adopt-partition.js'\n\n/** One decrypted record from an extracted-partition compartment. */\nexport interface DecryptedRecord {\n readonly id: string\n readonly record: Record<string, unknown>\n /** Source envelope write timestamp (ISO) — for last-write-wins merges. */\n readonly ts: string\n /** Source envelope version. */\n readonly version: number\n /** Provenance source id (FR-5). Present only when the source collection had provenance:true and a source was supplied on put. */\n readonly source?: string\n /** ISO-8601 timestamp the provenance source was recorded (FR-5). */\n readonly sourceTs?: string\n}\n\n/**\n * Decrypt every record of an extracted-partition bundle to plaintext,\n * grouped by collection. Throws if the bundle isn't an\n * extracted-partition or the transfer key is wrong.\n */\nexport async function decryptExtractedPartition(\n bundleBytes: Uint8Array,\n transferKey: Uint8Array,\n): Promise<Record<string, DecryptedRecord[]>> {\n const header = readPodHeader(bundleBytes)\n if (header.bundleKind !== 'extracted-partition' || header.transferSeal === undefined) {\n throw new Error('decryptExtractedPartition: bundle is not an extracted-partition.')\n }\n const { dumpJson } = await readPod(bundleBytes)\n const { dump, seal } = parseExtractedPartitionBody(dumpJson)\n const deks = await unsealDeks(seal, transferKey) // throws TransferSealError on wrong key\n const backup = JSON.parse(dump) as { collections: Record<string, Record<string, EncryptedEnvelope>> }\n const out: Record<string, DecryptedRecord[]> = {}\n for (const [collection, byId] of Object.entries(backup.collections)) {\n const dek = deks.get(collection)\n if (dek === undefined) continue // no DEK sealed for this collection — skip\n const recs: DecryptedRecord[] = []\n for (const [id, env] of Object.entries(byId)) {\n const plaintext = await openEnvelopeJson(env, dek)\n const body = JSON.parse(plaintext) as Record<string, unknown>\n recs.push({\n id,\n record: { ...body, id },\n ts: env._ts,\n version: env._v,\n ...(env._source !== undefined ? { source: env._source } : {}),\n ...(env._sourceTs !== undefined ? { sourceTs: env._sourceTs } : {}),\n })\n }\n out[collection] = recs\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MaterializedViewConfigError,
|
|
3
3
|
ValidationError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZYUC53LT.js";
|
|
5
5
|
|
|
6
|
-
// src/materialized-views/with-materialized-view.ts
|
|
6
|
+
// src/with-formula/materialized-views/with-materialized-view.ts
|
|
7
7
|
function withMaterializedView(spec) {
|
|
8
8
|
if (!spec.name || spec.name.length === 0) {
|
|
9
9
|
throw new ValidationError("withMaterializedView: name is required");
|
|
@@ -22,9 +22,9 @@ function withMaterializedView(spec) {
|
|
|
22
22
|
throw new ValidationError("withMaterializedView: query must be a function returning a Query<T>");
|
|
23
23
|
}
|
|
24
24
|
if (spec.unionSources) {
|
|
25
|
-
if (spec.unionSources.length <
|
|
25
|
+
if (spec.unionSources.length < 1) {
|
|
26
26
|
throw new MaterializedViewConfigError(
|
|
27
|
-
"unionSources requires at least
|
|
27
|
+
"unionSources requires at least 1 source collection"
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -56,12 +56,27 @@ function withMaterializedView(spec) {
|
|
|
56
56
|
`withMaterializedView "${spec.name}": UNION strategy with aggregate requires groupBy \u2014 use groupBy to declare the bucketing keys, or remove aggregate for a pure dedup MV`
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
|
+
if (spec.moneyFields && !spec.aggregate) {
|
|
60
|
+
throw new MaterializedViewConfigError(
|
|
61
|
+
`withMaterializedView "${spec.name}": moneyFields requires aggregate \u2014 moneyFields rewrites sum/min/max reducers over money output fields, so it is meaningless without an aggregate spec`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (spec.unionSources.some((s) => s.join && s.join.length > 0) && (!spec.sources || spec.sources.length === 0)) {
|
|
65
|
+
throw new MaterializedViewConfigError(
|
|
66
|
+
`withMaterializedView "${spec.name}": a unionSources arm declares join(s) but no \`sources\` are listed \u2014 declare sources: [...] with the right-side (join-target) collection names so writes to them trigger MV refresh`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
59
69
|
if (spec.predicates) {
|
|
60
70
|
throw new MaterializedViewConfigError(
|
|
61
71
|
`withMaterializedView "${spec.name}": predicates are not supported on UNION strategies \u2014 UNION mode does not use a Query<T> chain, so .wherePredicate() cannot fire. Use the query() form, or open an issue if per-arm predicates are needed`
|
|
62
72
|
);
|
|
63
73
|
}
|
|
64
74
|
}
|
|
75
|
+
if (spec.i18nLocale !== void 0 && spec.i18nFields === void 0) {
|
|
76
|
+
throw new MaterializedViewConfigError(
|
|
77
|
+
`withMaterializedView "${spec.name}": i18nLocale requires i18nFields \u2014 declare the i18nText descriptors of the group-key fields so they can be resolved at the mv layer before bucketing.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
65
80
|
if (typeof spec.rowKey !== "function") {
|
|
66
81
|
throw new ValidationError("withMaterializedView: rowKey is required (no default; see spec \xA7 Type surface)");
|
|
67
82
|
}
|
|
@@ -79,4 +94,4 @@ function withMaterializedView(spec) {
|
|
|
79
94
|
export {
|
|
80
95
|
withMaterializedView
|
|
81
96
|
};
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
97
|
+
//# sourceMappingURL=chunk-3YFXJ3ZP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-formula/materialized-views/with-materialized-view.ts"],"sourcesContent":["import { MaterializedViewConfigError, ValidationError } from '../../kernel/errors.js'\nimport type { MaterializedViewStrategy, MaterializedViewStrategyHandle } from './types.js'\n\n/**\n * Register a materialized view: a declared query whose result is\n * persisted as a queryable collection and kept fresh as sources\n * change. Writes go through the standard `Collection.put` pipeline;\n * refresh-driven deletes route through `Collection._internalDelete` so\n * user `onDelete` guards on the output collection aren't tripped by\n * housekeeping.\n *\n * Two registration modes:\n * - **single-source** — declare `query: (db) => Query<TRow>`; the\n * dependency analyzer derives source collections from the plan.\n * - **UNION** — declare `unionSources: [{ collection, map }, ...]`\n * plus optional `groupBy` + `aggregate`; the executor reads each\n * arm, maps to the unified row shape, concatenates, then groups\n * and aggregates.\n *\n * The two modes are mutually exclusive — exactly one of `query` /\n * `unionSources` must be set at registration time.\n *\n * See docs/superpowers/specs/2026-05-20-dim14-mv-v2-design.md (single-source v2)\n * and docs/superpowers/specs/2026-05-21-dim14-mv-multikey-and-union.md (UNION).\n */\nexport function withMaterializedView<TRow extends Record<string, unknown>>(\n spec: MaterializedViewStrategy<TRow>,\n): MaterializedViewStrategyHandle {\n if (!spec.name || spec.name.length === 0) {\n throw new ValidationError('withMaterializedView: name is required')\n }\n // Mutual exclusion: query and unionSources cannot coexist.\n if (spec.query && spec.unionSources) {\n throw new MaterializedViewConfigError(\n 'query and unionSources are mutually exclusive — pick one',\n )\n }\n // Strategy must declare one of the two.\n if (!spec.query && !spec.unionSources) {\n throw new MaterializedViewConfigError(\n 'strategy must declare either query or unionSources',\n )\n }\n if (spec.query !== undefined && typeof spec.query !== 'function') {\n throw new ValidationError('withMaterializedView: query must be a function returning a Query<T>')\n }\n // UNION-form invariants.\n if (spec.unionSources) {\n // A single arm is a deliberate shape: map→group→aggregate over\n // ONE collection with a COMPUTED bucket key (e.g. month sliced from a\n // date field) — something the query form's stored-field groupBy cannot\n // express. The executor and dependency analyzer are arm-count-agnostic.\n if (spec.unionSources.length < 1) {\n throw new MaterializedViewConfigError(\n 'unionSources requires at least 1 source collection',\n )\n }\n const seen = new Set<string>()\n for (const s of spec.unionSources) {\n if (typeof s?.collection !== 'string' || s.collection.length === 0) {\n throw new MaterializedViewConfigError(\n 'each unionSources entry must declare a non-empty `collection` string',\n )\n }\n if (typeof s.map !== 'function') {\n throw new MaterializedViewConfigError(\n `unionSources entry for \"${s.collection}\" is missing a \\`map\\` function`,\n )\n }\n if (seen.has(s.collection)) {\n throw new MaterializedViewConfigError(\n `unionSources must reference distinct collections (duplicate: \"${s.collection}\")`,\n )\n }\n seen.add(s.collection)\n }\n if (Array.isArray(spec.groupBy) && spec.groupBy.length === 0) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": groupBy must not be an empty array — omit it or provide at least one field name`,\n )\n }\n if (spec.aggregate && !spec.groupBy) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": UNION strategy with aggregate requires groupBy — `\n + `use groupBy to declare the bucketing keys, or remove aggregate for a pure dedup MV`,\n )\n }\n // `moneyFields` only has meaning when there's an aggregate to\n // money-rewrite — it keys reducer outputs, so declaring it without\n // `aggregate` is a no-op config mistake.\n if (spec.moneyFields && !spec.aggregate) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": moneyFields requires aggregate — `\n + `moneyFields rewrites sum/min/max reducers over money output fields, `\n + `so it is meaningless without an aggregate spec`,\n )\n }\n // Per-arm joins resolve right-side collections that the union\n // dependency set (built from arm `collection`s alone) does NOT\n // include. The consumer must list those right-side collections in\n // `sources` so writes to them trigger MV refresh.\n if (spec.unionSources.some(s => s.join && s.join.length > 0) && (!spec.sources || spec.sources.length === 0)) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": a unionSources arm declares join(s) but `\n + `no \\`sources\\` are listed — declare sources: [...] with the right-side `\n + `(join-target) collection names so writes to them trigger MV refresh`,\n )\n }\n if (spec.predicates) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": predicates are not supported on UNION strategies — `\n + `UNION mode does not use a Query<T> chain, so .wherePredicate() cannot fire. `\n + `Use the query() form, or open an issue if per-arm predicates are needed`,\n )\n }\n }\n // i18nLocale + i18nFields drive compute-time i18n resolution of group-key\n // i18nText fields before bucketing — UNION mode (resolved on the unified rows)\n // AND query mode (resolved in GroupedAggregation.run before groupAndReduce).\n // i18nLocale without i18nFields cannot resolve anything, so reject it early.\n if (spec.i18nLocale !== undefined && spec.i18nFields === undefined) {\n throw new MaterializedViewConfigError(\n `withMaterializedView \"${spec.name}\": i18nLocale requires i18nFields — `\n + `declare the i18nText descriptors of the group-key fields so they can be `\n + `resolved at the mv layer before bucketing.`,\n )\n }\n if (typeof spec.rowKey !== 'function') {\n throw new ValidationError('withMaterializedView: rowKey is required (no default; see spec § Type surface)')\n }\n if (spec.refresh !== 'eager' && spec.refresh !== 'lazy' && spec.refresh !== 'manual') {\n throw new ValidationError(\n `withMaterializedView: refresh must be 'eager' | 'lazy' | 'manual', got \"${String(spec.refresh)}\"`,\n )\n }\n return {\n __noydb_strategy: 'materialized-view',\n spec,\n }\n}\n"],"mappings":";;;;;;AAyBO,SAAS,qBACd,MACgC;AAChC,MAAI,CAAC,KAAK,QAAQ,KAAK,KAAK,WAAW,GAAG;AACxC,UAAM,IAAI,gBAAgB,wCAAwC;AAAA,EACpE;AAEA,MAAI,KAAK,SAAS,KAAK,cAAc;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,SAAS,CAAC,KAAK,cAAc;AACrC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,MAAI,KAAK,UAAU,UAAa,OAAO,KAAK,UAAU,YAAY;AAChE,UAAM,IAAI,gBAAgB,qEAAqE;AAAA,EACjG;AAEA,MAAI,KAAK,cAAc;AAKrB,QAAI,KAAK,aAAa,SAAS,GAAG;AAChC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,OAAO,oBAAI,IAAY;AAC7B,eAAW,KAAK,KAAK,cAAc;AACjC,UAAI,OAAO,GAAG,eAAe,YAAY,EAAE,WAAW,WAAW,GAAG;AAClE,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,UAAI,OAAO,EAAE,QAAQ,YAAY;AAC/B,cAAM,IAAI;AAAA,UACR,2BAA2B,EAAE,UAAU;AAAA,QACzC;AAAA,MACF;AACA,UAAI,KAAK,IAAI,EAAE,UAAU,GAAG;AAC1B,cAAM,IAAI;AAAA,UACR,iEAAiE,EAAE,UAAU;AAAA,QAC/E;AAAA,MACF;AACA,WAAK,IAAI,EAAE,UAAU;AAAA,IACvB;AACA,QAAI,MAAM,QAAQ,KAAK,OAAO,KAAK,KAAK,QAAQ,WAAW,GAAG;AAC5D,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MACpC;AAAA,IACF;AACA,QAAI,KAAK,aAAa,CAAC,KAAK,SAAS;AACnC,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MAEpC;AAAA,IACF;AAIA,QAAI,KAAK,eAAe,CAAC,KAAK,WAAW;AACvC,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MAGpC;AAAA,IACF;AAKA,QAAI,KAAK,aAAa,KAAK,OAAK,EAAE,QAAQ,EAAE,KAAK,SAAS,CAAC,MAAM,CAAC,KAAK,WAAW,KAAK,QAAQ,WAAW,IAAI;AAC5G,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MAGpC;AAAA,IACF;AACA,QAAI,KAAK,YAAY;AACnB,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,IAAI;AAAA,MAGpC;AAAA,IACF;AAAA,EACF;AAKA,MAAI,KAAK,eAAe,UAAa,KAAK,eAAe,QAAW;AAClE,UAAM,IAAI;AAAA,MACR,yBAAyB,KAAK,IAAI;AAAA,IAGpC;AAAA,EACF;AACA,MAAI,OAAO,KAAK,WAAW,YAAY;AACrC,UAAM,IAAI,gBAAgB,mFAAgF;AAAA,EAC5G;AACA,MAAI,KAAK,YAAY,WAAW,KAAK,YAAY,UAAU,KAAK,YAAY,UAAU;AACpF,UAAM,IAAI;AAAA,MACR,2EAA2E,OAAO,KAAK,OAAO,CAAC;AAAA,IACjG;AAAA,EACF;AACA,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/with-shape/blobs/object-projection.ts
|
|
2
|
+
function memoryObjectProjection(opts = {}) {
|
|
3
|
+
const base = opts.baseUrl ?? "memory://objects";
|
|
4
|
+
const store = /* @__PURE__ */ new Map();
|
|
5
|
+
return {
|
|
6
|
+
name: "memory",
|
|
7
|
+
async putObject(key, bytes, o) {
|
|
8
|
+
store.set(key, {
|
|
9
|
+
bytes,
|
|
10
|
+
contentType: o.contentType,
|
|
11
|
+
public: o.public === true,
|
|
12
|
+
...o.userMeta ? { userMeta: o.userMeta } : {}
|
|
13
|
+
});
|
|
14
|
+
},
|
|
15
|
+
async getObject(key) {
|
|
16
|
+
return store.get(key)?.bytes ?? null;
|
|
17
|
+
},
|
|
18
|
+
async deleteObject(key) {
|
|
19
|
+
store.delete(key);
|
|
20
|
+
},
|
|
21
|
+
async headObject(key) {
|
|
22
|
+
const e = store.get(key);
|
|
23
|
+
if (!e) return null;
|
|
24
|
+
return {
|
|
25
|
+
size: e.bytes.byteLength,
|
|
26
|
+
contentType: e.contentType,
|
|
27
|
+
...e.userMeta ? { userMeta: e.userMeta } : {}
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
async objectUrl(key, o) {
|
|
31
|
+
const e = store.get(key);
|
|
32
|
+
if (e?.public) return `${base}/${key}`;
|
|
33
|
+
return `${base}/${key}?sig=memory&expires=${o?.expiresInSeconds ?? 900}`;
|
|
34
|
+
},
|
|
35
|
+
async putUrl(key, o) {
|
|
36
|
+
return `${base}/${key}?upload=memory&ct=${encodeURIComponent(o.contentType)}`;
|
|
37
|
+
},
|
|
38
|
+
async listPrefix(prefix) {
|
|
39
|
+
const out = [];
|
|
40
|
+
for (const [key, e] of store) {
|
|
41
|
+
if (!key.startsWith(prefix)) continue;
|
|
42
|
+
out.push({
|
|
43
|
+
key,
|
|
44
|
+
meta: { size: e.bytes.byteLength, contentType: e.contentType, ...e.userMeta ? { userMeta: e.userMeta } : {} }
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/with-shape/blobs/import-external.ts
|
|
53
|
+
function defaultDeriveRecordId(key) {
|
|
54
|
+
const parts = key.split("/");
|
|
55
|
+
return parts.length >= 2 ? parts[parts.length - 2] ?? null : null;
|
|
56
|
+
}
|
|
57
|
+
async function importExternalObjects(args) {
|
|
58
|
+
const { collection, objectStore, field } = args;
|
|
59
|
+
const opts = args.options ?? {};
|
|
60
|
+
const derive = opts.deriveRecordId ?? defaultDeriveRecordId;
|
|
61
|
+
const makeRecord = opts.makeRecord ?? ((id) => ({ id }));
|
|
62
|
+
const objects = await objectStore.listPrefix(opts.prefix ?? "");
|
|
63
|
+
const recordIds = [];
|
|
64
|
+
let imported = 0;
|
|
65
|
+
let skipped = 0;
|
|
66
|
+
for (const { key, meta } of objects) {
|
|
67
|
+
const recordId = derive(key);
|
|
68
|
+
if (!recordId) {
|
|
69
|
+
skipped++;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (await collection.get(recordId) == null) {
|
|
73
|
+
await collection.put(recordId, makeRecord(recordId));
|
|
74
|
+
}
|
|
75
|
+
await collection.blob(recordId).adoptExternal(field, {
|
|
76
|
+
key,
|
|
77
|
+
...meta.size !== void 0 ? { size: meta.size } : {},
|
|
78
|
+
...meta.contentType ? { contentType: meta.contentType } : {}
|
|
79
|
+
});
|
|
80
|
+
recordIds.push(recordId);
|
|
81
|
+
imported++;
|
|
82
|
+
}
|
|
83
|
+
return { imported, skipped, recordIds };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
memoryObjectProjection,
|
|
88
|
+
importExternalObjects
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=chunk-4Q6HSHHL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-shape/blobs/object-projection.ts","../src/with-shape/blobs/import-external.ts"],"sourcesContent":["/**\n * `ObjectProjection` — the capability an `as-*` projection store implements to\n * hold blob bytes as native, directly-consumable objects (e.g. servable S3\n * objects) rather than the encrypted-envelope chunks a `NoydbStore` holds.\n *\n * This is the shared seam behind **direct-serve blobs** and the\n * **debug raw-object path**: \"write these bytes as one real object and\n * give me a URL to it.\" See the as-aws-s3 design spec.\n *\n * Unlike `NoydbStore` (ciphertext in / ciphertext out), an `ObjectProjection`\n * sees **raw bytes** — it is `as-*`, not `to-*`, and lives **outside** the\n * zero-knowledge guarantee. Wiring it up is a deliberate, per-field opt-in.\n */\n\n/** Metadata about a stored object, without its body. */\nexport interface ObjectMeta {\n readonly size: number\n readonly contentType?: string\n readonly etag?: string\n readonly lastModified?: string\n /** S3-style user metadata (`x-amz-meta-*`). Small; see the design's\n * plain / encrypted / opaque-token modes. */\n readonly userMeta?: Record<string, string>\n}\n\nexport interface PutObjectOptions {\n readonly contentType: string\n /** World-readable object (CDN origin) vs private (presigned-only). Default false. */\n readonly public?: boolean\n /** User metadata mirrored onto the object (the \"secondary store\"). */\n readonly userMeta?: Record<string, string>\n}\n\nexport interface ObjectUrlOptions {\n /** TTL for a presigned URL (ignored for a public object). */\n readonly expiresInSeconds?: number\n}\n\nexport interface PutUrlOptions {\n readonly contentType: string\n readonly expiresInSeconds?: number\n}\n\n/** One entry returned by {@link ObjectProjection.listPrefix}. */\nexport interface ObjectListEntry {\n readonly key: string\n readonly meta: ObjectMeta\n}\n\nexport interface ObjectProjection {\n /** Diagnostic name (e.g. `'aws-s3'`, `'memory'`). */\n readonly name?: string\n /** Write raw bytes as a single native object with a real content type. */\n putObject(key: string, bytes: Uint8Array, opts: PutObjectOptions): Promise<void>\n /** Read the raw bytes back; `null` if absent. */\n getObject(key: string): Promise<Uint8Array | null>\n /** Delete the object. Idempotent — absent is not an error. */\n deleteObject(key: string): Promise<void>\n /** Object metadata without the body; `null` if absent. */\n headObject(key: string): Promise<ObjectMeta | null>\n /** A URL to GET the object — presigned (time-limited) or stable public. */\n objectUrl(key: string, opts?: ObjectUrlOptions): Promise<string>\n /** A presigned URL the client PUTs bytes to directly (large-file upload,\n * bytes bypass the hub). */\n putUrl(key: string, opts: PutUrlOptions): Promise<string>\n /** List objects under a key prefix — for import / reconcile. */\n listPrefix(prefix: string): Promise<ObjectListEntry[]>\n}\n\n/**\n * In-memory {@link ObjectProjection} — a reference implementation for tests,\n * local development, and the hub's blob-wiring conformance. Holds bytes in a\n * `Map`; URLs are synthetic (`memory://…`). Not for production.\n */\nexport function memoryObjectProjection(opts: { baseUrl?: string } = {}): ObjectProjection {\n const base = opts.baseUrl ?? 'memory://objects'\n const store = new Map<\n string,\n { bytes: Uint8Array; contentType: string; userMeta?: Record<string, string>; public: boolean }\n >()\n return {\n name: 'memory',\n async putObject(key, bytes, o) {\n store.set(key, {\n bytes,\n contentType: o.contentType,\n public: o.public === true,\n ...(o.userMeta ? { userMeta: o.userMeta } : {}),\n })\n },\n async getObject(key) {\n return store.get(key)?.bytes ?? null\n },\n async deleteObject(key) {\n store.delete(key)\n },\n async headObject(key) {\n const e = store.get(key)\n if (!e) return null\n return {\n size: e.bytes.byteLength,\n contentType: e.contentType,\n ...(e.userMeta ? { userMeta: e.userMeta } : {}),\n }\n },\n async objectUrl(key, o) {\n const e = store.get(key)\n if (e?.public) return `${base}/${key}`\n return `${base}/${key}?sig=memory&expires=${o?.expiresInSeconds ?? 900}`\n },\n async putUrl(key, o) {\n return `${base}/${key}?upload=memory&ct=${encodeURIComponent(o.contentType)}`\n },\n async listPrefix(prefix) {\n const out: ObjectListEntry[] = []\n for (const [key, e] of store) {\n if (!key.startsWith(prefix)) continue\n out.push({\n key,\n meta: { size: e.bytes.byteLength, contentType: e.contentType, ...(e.userMeta ? { userMeta: e.userMeta } : {}) },\n })\n }\n return out\n },\n }\n}\n","/**\n * Import / bootstrap (reverse projection) — walk an existing bucket/prefix in an\n * {@link ObjectProjection} and build a master collection where each record\n * anchors one object, restoring the record-anchoring invariant for objects that\n * pre-date noy-db (or were written by another system). See as-aws-s3 §3.8.\n *\n * Idempotent: re-running re-adopts the same objects under the same record ids.\n */\nimport type { ObjectProjection } from './object-projection.js'\n\n/** Minimal collection surface this utility needs (avoids importing the kernel). */\nexport interface ImportableCollection {\n get(id: string): Promise<unknown>\n put(id: string, record: unknown): Promise<unknown>\n blob(id: string): {\n adoptExternal(\n slot: string,\n ref: { key: string; size?: number; contentType?: string; public?: boolean; backlink?: string },\n ): Promise<void>\n }\n}\n\nexport interface ImportExternalOptions {\n /** Only consider objects under this key prefix. Default `''` (all). */\n prefix?: string\n /**\n * Derive the record id for an object key. Default: the path segment before\n * the last — i.e. `{collection}/{recordId}/{field}` → `recordId`. Return\n * `null` to skip the object.\n */\n deriveRecordId?: (key: string) => string | null\n /** Build the anchor record for a new id. Default `{ id }`. */\n makeRecord?: (id: string) => unknown\n}\n\nexport interface ImportExternalResult {\n imported: number\n skipped: number\n recordIds: string[]\n}\n\nfunction defaultDeriveRecordId(key: string): string | null {\n const parts = key.split('/')\n return parts.length >= 2 ? (parts[parts.length - 2] ?? null) : null\n}\n\n/**\n * Build/extend `collection` from the objects under `prefix` in `objectStore`,\n * adopting each as the `field` blob on its derived record.\n */\nexport async function importExternalObjects(args: {\n collection: ImportableCollection\n objectStore: ObjectProjection\n field: string\n options?: ImportExternalOptions\n}): Promise<ImportExternalResult> {\n const { collection, objectStore, field } = args\n const opts = args.options ?? {}\n const derive = opts.deriveRecordId ?? defaultDeriveRecordId\n const makeRecord = opts.makeRecord ?? ((id: string) => ({ id }))\n\n const objects = await objectStore.listPrefix(opts.prefix ?? '')\n const recordIds: string[] = []\n let imported = 0\n let skipped = 0\n\n for (const { key, meta } of objects) {\n const recordId = derive(key)\n if (!recordId) {\n skipped++\n continue\n }\n if ((await collection.get(recordId)) == null) {\n await collection.put(recordId, makeRecord(recordId))\n }\n await collection.blob(recordId).adoptExternal(field, {\n key,\n ...(meta.size !== undefined ? { size: meta.size } : {}),\n ...(meta.contentType ? { contentType: meta.contentType } : {}),\n })\n recordIds.push(recordId)\n imported++\n }\n\n return { imported, skipped, recordIds }\n}\n"],"mappings":"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","names":[]}
|