@noy-db/hub 0.2.0-pre.9 → 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-CJ8RzRrm.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-6CME4UEK.js → chunk-5R5JW2JT.js} +7000 -4827
- 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-B4kDxep_.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-DdpVypUp.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-Df28QFKb.d.ts → index-BzUo1B6n.d.ts} +16270 -8358
- 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 +6 -8
- package/dist/snapshots/index.js +13 -11
- 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-BLkQxoQN.d.ts → with-materialized-view-6p0Fk8bL.d.ts} +1 -1
- package/dist/{with-overlayed-view-CRsSEwHR.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 -19264
- 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-6CME4UEK.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-BIoEFbwm.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-HJqD14vS.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 -24487
- 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-G725ZSZG.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 -937
- package/dist/snapshots/index.cjs.map +0 -1
- package/dist/snapshots/index.d.cts +0 -28
- 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-DyXYr8rE.d.cts +0 -12818
- package/dist/ulid-COREQ2RQ.js +0 -9
- package/dist/ulid-Drr7ykr6.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-DFnFByiQ.d.ts +0 -13
- package/dist/with-derivation-DU3Sjazm.d.cts +0 -13
- package/dist/with-guard-ByyxmEe7.d.cts +0 -18
- package/dist/with-guard-qube6BMI.d.ts +0 -18
- package/dist/with-materialized-view-BmEToIR1.d.cts +0 -27
- package/dist/with-overlayed-view-BMsQQbWm.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-G725ZSZG.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,142 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadFence,
|
|
3
|
+
saveFence
|
|
4
|
+
} from "./chunk-IAGBDSCS.js";
|
|
5
|
+
import {
|
|
6
|
+
NOYDB_FORMAT_VERSION
|
|
7
|
+
} from "./chunk-5TDJ56JE.js";
|
|
8
|
+
import "./chunk-PZ5AY32C.js";
|
|
9
|
+
|
|
10
|
+
// src/with-shape/schema-update/client-registry.ts
|
|
11
|
+
var META_COLLECTION = "_meta";
|
|
12
|
+
var CLIENT_PREFIX = "schema-fence:client:";
|
|
13
|
+
async function writeClientDoc(store, vault, clientId, doc) {
|
|
14
|
+
const envelope = {
|
|
15
|
+
_noydb: NOYDB_FORMAT_VERSION,
|
|
16
|
+
_v: 1,
|
|
17
|
+
_ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18
|
+
_iv: "",
|
|
19
|
+
_data: JSON.stringify({ clientId, ...doc })
|
|
20
|
+
};
|
|
21
|
+
await store.put(vault, META_COLLECTION, `${CLIENT_PREFIX}${clientId}`, envelope);
|
|
22
|
+
}
|
|
23
|
+
async function listClientDocs(store, vault) {
|
|
24
|
+
const ids = await store.list(vault, META_COLLECTION);
|
|
25
|
+
const out = [];
|
|
26
|
+
for (const id of ids) {
|
|
27
|
+
if (!id.startsWith(CLIENT_PREFIX)) continue;
|
|
28
|
+
const env = await store.get(vault, META_COLLECTION, id);
|
|
29
|
+
if (!env) continue;
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(env._data);
|
|
32
|
+
if (isClientDoc(parsed)) out.push(parsed);
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function isClientDoc(x) {
|
|
39
|
+
if (x === null || typeof x !== "object") return false;
|
|
40
|
+
const o = x;
|
|
41
|
+
return typeof o["clientId"] === "string" && typeof o["lastSeen"] === "number" && (o["quiescedAtVersion"] === null || typeof o["quiescedAtVersion"] === "number") && (o["sessionId"] === void 0 || typeof o["sessionId"] === "string");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/with-shape/schema-update/store-coordination-provider.ts
|
|
45
|
+
var DEFAULT_POLL_INTERVAL_MS = 50;
|
|
46
|
+
function toPresence(doc) {
|
|
47
|
+
return {
|
|
48
|
+
writerId: doc.clientId,
|
|
49
|
+
// Legacy docs written without a sessionId (and explicit empty) have no
|
|
50
|
+
// session — fall back to the writerId so every presence is session-addressable.
|
|
51
|
+
sessionId: doc.sessionId && doc.sessionId.length > 0 ? doc.sessionId : doc.clientId,
|
|
52
|
+
lastSeen: doc.lastSeen,
|
|
53
|
+
quiescedAtVersion: doc.quiescedAtVersion
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function fenceEqual(a, b) {
|
|
57
|
+
return a.currentSchemaVersion === b.currentSchemaVersion && a.fenceState === b.fenceState;
|
|
58
|
+
}
|
|
59
|
+
function presenceListEqual(a, b) {
|
|
60
|
+
if (a.length !== b.length) return false;
|
|
61
|
+
const key = (w) => `${w.writerId}\0${w.sessionId}\0${w.lastSeen}\0${String(w.quiescedAtVersion)}`;
|
|
62
|
+
const bk = new Set(b.map(key));
|
|
63
|
+
return a.every((w) => bk.has(key(w)));
|
|
64
|
+
}
|
|
65
|
+
var StoreCoordinationProvider = class {
|
|
66
|
+
#store;
|
|
67
|
+
#pollIntervalMs;
|
|
68
|
+
constructor(store, opts) {
|
|
69
|
+
this.#store = store;
|
|
70
|
+
this.#pollIntervalMs = opts?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
71
|
+
}
|
|
72
|
+
async setFence(vault, fence) {
|
|
73
|
+
await saveFence(this.#store, vault, fence);
|
|
74
|
+
}
|
|
75
|
+
async readFence(vault) {
|
|
76
|
+
return loadFence(this.#store, vault);
|
|
77
|
+
}
|
|
78
|
+
observeFence(vault, onChange) {
|
|
79
|
+
let last = null;
|
|
80
|
+
let busy = false;
|
|
81
|
+
const poll = async () => {
|
|
82
|
+
if (busy) return;
|
|
83
|
+
busy = true;
|
|
84
|
+
try {
|
|
85
|
+
const fence = await loadFence(this.#store, vault);
|
|
86
|
+
if (last === null || !fenceEqual(last, fence)) {
|
|
87
|
+
last = fence;
|
|
88
|
+
onChange(fence);
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
} finally {
|
|
92
|
+
busy = false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
void poll();
|
|
96
|
+
const timer = setInterval(() => void poll(), this.#pollIntervalMs);
|
|
97
|
+
unref(timer);
|
|
98
|
+
return () => clearInterval(timer);
|
|
99
|
+
}
|
|
100
|
+
async reportPresence(vault, p) {
|
|
101
|
+
await writeClientDoc(this.#store, vault, p.writerId, {
|
|
102
|
+
lastSeen: p.lastSeen,
|
|
103
|
+
quiescedAtVersion: p.quiescedAtVersion,
|
|
104
|
+
sessionId: p.sessionId
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
observePresence(vault, onChange) {
|
|
108
|
+
let last = null;
|
|
109
|
+
let busy = false;
|
|
110
|
+
const poll = async () => {
|
|
111
|
+
if (busy) return;
|
|
112
|
+
busy = true;
|
|
113
|
+
try {
|
|
114
|
+
const docs = await listClientDocs(this.#store, vault);
|
|
115
|
+
const writers = docs.map(toPresence);
|
|
116
|
+
if (last === null || !presenceListEqual(last, writers)) {
|
|
117
|
+
last = writers;
|
|
118
|
+
onChange(writers);
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
} finally {
|
|
122
|
+
busy = false;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
void poll();
|
|
126
|
+
const timer = setInterval(() => void poll(), this.#pollIntervalMs);
|
|
127
|
+
unref(timer);
|
|
128
|
+
return () => clearInterval(timer);
|
|
129
|
+
}
|
|
130
|
+
async reachableWriters(vault, o) {
|
|
131
|
+
const docs = await listClientDocs(this.#store, vault);
|
|
132
|
+
return docs.map(toPresence).filter((w) => o.now - w.lastSeen <= o.staleMs);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
function unref(timer) {
|
|
136
|
+
const t = timer;
|
|
137
|
+
if (typeof t.unref === "function") t.unref();
|
|
138
|
+
}
|
|
139
|
+
export {
|
|
140
|
+
StoreCoordinationProvider
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=store-coordination-provider-3I7XWZZK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/with-shape/schema-update/client-registry.ts","../src/with-shape/schema-update/store-coordination-provider.ts"],"sourcesContent":["/**\n * Schema-cutover client registry. Each client keeps a\n * heartbeat doc at `_meta/schema-fence:client:<clientId>` carrying its\n * liveness (`lastSeen`) and the fence generation it has quiesced for\n * (`quiescedAtVersion`). Plaintext envelope, like the fence doc.\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\n\nconst META_COLLECTION = '_meta'\nconst CLIENT_PREFIX = 'schema-fence:client:'\n\nexport interface ClientDoc {\n readonly clientId: string\n readonly lastSeen: number\n readonly quiescedAtVersion: number | null\n /**\n * Session that owns this writer (one user's writers across vaults). Additive\n * and optional so legacy client docs (written without it) keep parsing;\n * readers default it.\n */\n readonly sessionId?: string\n}\n\nexport async function writeClientDoc(\n store: NoydbStore,\n vault: string,\n clientId: string,\n doc: { lastSeen: number; quiescedAtVersion: number | null; sessionId?: string },\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ clientId, ...doc }),\n }\n await store.put(vault, META_COLLECTION, `${CLIENT_PREFIX}${clientId}`, envelope)\n}\n\nexport async function listClientDocs(store: NoydbStore, vault: string): Promise<ClientDoc[]> {\n const ids = await store.list(vault, META_COLLECTION)\n const out: ClientDoc[] = []\n for (const id of ids) {\n if (!id.startsWith(CLIENT_PREFIX)) continue\n const env = await store.get(vault, META_COLLECTION, id)\n if (!env) continue\n try {\n const parsed = JSON.parse(env._data) as unknown\n if (isClientDoc(parsed)) out.push(parsed)\n } catch { /* skip corrupt */ }\n }\n return out\n}\n\n/**\n * True when every *active* client (lastSeen within staleMs of now) has\n * `quiescedAtVersion === generation`. Stale clients are ignored. An empty\n * active set is vacuously quiesced.\n */\nexport async function activeQuiesced(\n store: NoydbStore,\n vault: string,\n opts: { generation: number; now: number; staleMs: number; excludeClientId?: string },\n): Promise<boolean> {\n const docs = await listClientDocs(store, vault)\n const active = docs.filter(\n d => d.lastSeen >= opts.now - opts.staleMs && d.clientId !== opts.excludeClientId,\n )\n return active.every(d => d.quiescedAtVersion === opts.generation)\n}\n\nfunction isClientDoc(x: unknown): x is ClientDoc {\n if (x === null || typeof x !== 'object') return false\n const o = x as Record<string, unknown>\n return typeof o['clientId'] === 'string'\n && typeof o['lastSeen'] === 'number'\n && (o['quiescedAtVersion'] === null || typeof o['quiescedAtVersion'] === 'number')\n && (o['sessionId'] === undefined || typeof o['sessionId'] === 'string')\n}\n","/**\n * Store-backed default {@link CoordinationProvider}.\n *\n * Maps the five coordination-port methods onto today's `_meta/schema-fence`\n * store ops so that, with no `by-*` provider injected, the fence service\n * reproduces its current store-polling behavior byte-for-byte. The `observe*`\n * methods are poll-emit (the legacy {@link FenceWatcher} model); `by-tabs` /\n * `by-peer` override them with real-time push.\n *\n * @module\n */\n\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { Unsubscribe } from '../../port/with/write-hooks.js'\nimport { loadFence, saveFence, type FenceDoc } from './fence.js'\nimport { writeClientDoc, listClientDocs, type ClientDoc } from './client-registry.js'\nimport type { CoordinationProvider, FenceState, WriterPresence } from '../../port/by/types.js'\n\n/**\n * Default poll cadence for the `observe*` fallbacks (ms). Matches the\n * store-poll granularity the fence-controller uses while waiting for quorum\n * (`delay(50)`); the same value the migration cutover falls back to when no\n * real-time provider is injected.\n */\nconst DEFAULT_POLL_INTERVAL_MS = 50\n\n/** Map a stored {@link ClientDoc} to the port's {@link WriterPresence}. */\nfunction toPresence(doc: ClientDoc): WriterPresence {\n return {\n writerId: doc.clientId,\n // Legacy docs written without a sessionId (and explicit empty) have no\n // session — fall back to the writerId so every presence is session-addressable.\n sessionId: doc.sessionId && doc.sessionId.length > 0 ? doc.sessionId : doc.clientId,\n lastSeen: doc.lastSeen,\n quiescedAtVersion: doc.quiescedAtVersion,\n }\n}\n\nfunction fenceEqual(a: FenceState, b: FenceState): boolean {\n return a.currentSchemaVersion === b.currentSchemaVersion && a.fenceState === b.fenceState\n}\n\nfunction presenceListEqual(a: readonly WriterPresence[], b: readonly WriterPresence[]): boolean {\n if (a.length !== b.length) return false\n const key = (w: WriterPresence) => `${w.writerId}\\u0000${w.sessionId}\\u0000${w.lastSeen}\\u0000${String(w.quiescedAtVersion)}`\n const bk = new Set(b.map(key))\n return a.every((w) => bk.has(key(w)))\n}\n\nexport class StoreCoordinationProvider implements CoordinationProvider {\n readonly #store: NoydbStore\n readonly #pollIntervalMs: number\n\n constructor(store: NoydbStore, opts?: { pollIntervalMs?: number }) {\n this.#store = store\n this.#pollIntervalMs = opts?.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS\n }\n\n async setFence(vault: string, fence: FenceState): Promise<void> {\n // FenceState is structurally FenceDoc (currentSchemaVersion + fenceState).\n await saveFence(this.#store, vault, fence as FenceDoc)\n }\n\n async readFence(vault: string): Promise<FenceState> {\n // FenceDoc is structurally FenceState (currentSchemaVersion + fenceState).\n return loadFence(this.#store, vault)\n }\n\n observeFence(vault: string, onChange: (f: FenceState) => void): Unsubscribe {\n let last: FenceState | null = null\n let busy = false\n const poll = async () => {\n if (busy) return\n busy = true\n try {\n const fence = await loadFence(this.#store, vault)\n if (last === null || !fenceEqual(last, fence)) {\n last = fence\n onChange(fence)\n }\n } catch {\n /* transient store error — retry next tick */\n } finally {\n busy = false\n }\n }\n void poll() // emit current state once immediately\n const timer = setInterval(() => void poll(), this.#pollIntervalMs)\n unref(timer)\n return () => clearInterval(timer)\n }\n\n async reportPresence(vault: string, p: WriterPresence): Promise<void> {\n await writeClientDoc(this.#store, vault, p.writerId, {\n lastSeen: p.lastSeen,\n quiescedAtVersion: p.quiescedAtVersion,\n sessionId: p.sessionId,\n })\n }\n\n observePresence(vault: string, onChange: (writers: readonly WriterPresence[]) => void): Unsubscribe {\n let last: readonly WriterPresence[] | null = null\n let busy = false\n const poll = async () => {\n if (busy) return\n busy = true\n try {\n const docs = await listClientDocs(this.#store, vault)\n const writers = docs.map(toPresence)\n if (last === null || !presenceListEqual(last, writers)) {\n last = writers\n onChange(writers)\n }\n } catch {\n /* transient store error — retry next tick */\n } finally {\n busy = false\n }\n }\n void poll() // emit current set once immediately\n const timer = setInterval(() => void poll(), this.#pollIntervalMs)\n unref(timer)\n return () => clearInterval(timer)\n }\n\n async reachableWriters(vault: string, o: { staleMs: number; now: number }): Promise<readonly WriterPresence[]> {\n const docs = await listClientDocs(this.#store, vault)\n return docs.map(toPresence).filter((w) => o.now - w.lastSeen <= o.staleMs)\n }\n}\n\n/** Best-effort `unref` so a poll timer never holds the process open (Node only). */\nfunction unref(timer: ReturnType<typeof setInterval>): void {\n const t = timer as unknown as { unref?: () => void }\n if (typeof t.unref === 'function') t.unref()\n}\n"],"mappings":";;;;;;;;;;AASA,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AActB,eAAsB,eACpB,OACA,OACA,UACA,KACe;AACf,QAAM,WAA8B;AAAA,IAClC,QAAQ;AAAA,IACR,IAAI;AAAA,IACJ,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC5B,KAAK;AAAA,IACL,OAAO,KAAK,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;AAAA,EAC5C;AACA,QAAM,MAAM,IAAI,OAAO,iBAAiB,GAAG,aAAa,GAAG,QAAQ,IAAI,QAAQ;AACjF;AAEA,eAAsB,eAAe,OAAmB,OAAqC;AAC3F,QAAM,MAAM,MAAM,MAAM,KAAK,OAAO,eAAe;AACnD,QAAM,MAAmB,CAAC;AAC1B,aAAW,MAAM,KAAK;AACpB,QAAI,CAAC,GAAG,WAAW,aAAa,EAAG;AACnC,UAAM,MAAM,MAAM,MAAM,IAAI,OAAO,iBAAiB,EAAE;AACtD,QAAI,CAAC,IAAK;AACV,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,IAAI,KAAK;AACnC,UAAI,YAAY,MAAM,EAAG,KAAI,KAAK,MAAM;AAAA,IAC1C,QAAQ;AAAA,IAAqB;AAAA,EAC/B;AACA,SAAO;AACT;AAmBA,SAAS,YAAY,GAA4B;AAC/C,MAAI,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,SAAO,OAAO,EAAE,UAAU,MAAM,YAC3B,OAAO,EAAE,UAAU,MAAM,aACxB,EAAE,mBAAmB,MAAM,QAAQ,OAAO,EAAE,mBAAmB,MAAM,cACrE,EAAE,WAAW,MAAM,UAAa,OAAO,EAAE,WAAW,MAAM;AAClE;;;ACvDA,IAAM,2BAA2B;AAGjC,SAAS,WAAW,KAAgC;AAClD,SAAO;AAAA,IACL,UAAU,IAAI;AAAA;AAAA;AAAA,IAGd,WAAW,IAAI,aAAa,IAAI,UAAU,SAAS,IAAI,IAAI,YAAY,IAAI;AAAA,IAC3E,UAAU,IAAI;AAAA,IACd,mBAAmB,IAAI;AAAA,EACzB;AACF;AAEA,SAAS,WAAW,GAAe,GAAwB;AACzD,SAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,eAAe,EAAE;AACjF;AAEA,SAAS,kBAAkB,GAA8B,GAAuC;AAC9F,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,QAAM,MAAM,CAAC,MAAsB,GAAG,EAAE,QAAQ,KAAS,EAAE,SAAS,KAAS,EAAE,QAAQ,KAAS,OAAO,EAAE,iBAAiB,CAAC;AAC3H,QAAM,KAAK,IAAI,IAAI,EAAE,IAAI,GAAG,CAAC;AAC7B,SAAO,EAAE,MAAM,CAAC,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC;AACtC;AAEO,IAAM,4BAAN,MAAgE;AAAA,EAC5D;AAAA,EACA;AAAA,EAET,YAAY,OAAmB,MAAoC;AACjE,SAAK,SAAS;AACd,SAAK,kBAAkB,MAAM,kBAAkB;AAAA,EACjD;AAAA,EAEA,MAAM,SAAS,OAAe,OAAkC;AAE9D,UAAM,UAAU,KAAK,QAAQ,OAAO,KAAiB;AAAA,EACvD;AAAA,EAEA,MAAM,UAAU,OAAoC;AAElD,WAAO,UAAU,KAAK,QAAQ,KAAK;AAAA,EACrC;AAAA,EAEA,aAAa,OAAe,UAAgD;AAC1E,QAAI,OAA0B;AAC9B,QAAI,OAAO;AACX,UAAM,OAAO,YAAY;AACvB,UAAI,KAAM;AACV,aAAO;AACP,UAAI;AACF,cAAM,QAAQ,MAAM,UAAU,KAAK,QAAQ,KAAK;AAChD,YAAI,SAAS,QAAQ,CAAC,WAAW,MAAM,KAAK,GAAG;AAC7C,iBAAO;AACP,mBAAS,KAAK;AAAA,QAChB;AAAA,MACF,QAAQ;AAAA,MAER,UAAE;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,SAAK,KAAK;AACV,UAAM,QAAQ,YAAY,MAAM,KAAK,KAAK,GAAG,KAAK,eAAe;AACjE,UAAM,KAAK;AACX,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC;AAAA,EAEA,MAAM,eAAe,OAAe,GAAkC;AACpE,UAAM,eAAe,KAAK,QAAQ,OAAO,EAAE,UAAU;AAAA,MACnD,UAAU,EAAE;AAAA,MACZ,mBAAmB,EAAE;AAAA,MACrB,WAAW,EAAE;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB,OAAe,UAAqE;AAClG,QAAI,OAAyC;AAC7C,QAAI,OAAO;AACX,UAAM,OAAO,YAAY;AACvB,UAAI,KAAM;AACV,aAAO;AACP,UAAI;AACF,cAAM,OAAO,MAAM,eAAe,KAAK,QAAQ,KAAK;AACpD,cAAM,UAAU,KAAK,IAAI,UAAU;AACnC,YAAI,SAAS,QAAQ,CAAC,kBAAkB,MAAM,OAAO,GAAG;AACtD,iBAAO;AACP,mBAAS,OAAO;AAAA,QAClB;AAAA,MACF,QAAQ;AAAA,MAER,UAAE;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,SAAK,KAAK;AACV,UAAM,QAAQ,YAAY,MAAM,KAAK,KAAK,GAAG,KAAK,eAAe;AACjE,UAAM,KAAK;AACX,WAAO,MAAM,cAAc,KAAK;AAAA,EAClC;AAAA,EAEA,MAAM,iBAAiB,OAAe,GAAyE;AAC7G,UAAM,OAAO,MAAM,eAAe,KAAK,QAAQ,KAAK;AACpD,WAAO,KAAK,IAAI,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO;AAAA,EAC3E;AACF;AAGA,SAAS,MAAM,OAA6C;AAC1D,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,UAAU,WAAY,GAAE,MAAM;AAC7C;","names":[]}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ledger entry shape + canonical JSON + sha256 helpers.
|
|
3
|
+
*
|
|
4
|
+
* This file holds the PURE primitives used by the hash-chained ledger:
|
|
5
|
+
* the entry type, the deterministic (sort-stable) JSON encoder, and
|
|
6
|
+
* the sha256 hasher that produces `prevHash` and `ledger.head()`.
|
|
7
|
+
*
|
|
8
|
+
* Everything here is validator-free and side-effect free — the only
|
|
9
|
+
* runtime dep is Web Crypto's `subtle.digest` for the sha256 call,
|
|
10
|
+
* which we already use for every other hashing operation in the core.
|
|
11
|
+
*
|
|
12
|
+
* The hash chain property works like this:
|
|
13
|
+
*
|
|
14
|
+
* hash(entry[i]) = sha256(canonicalJSON(entry[i]))
|
|
15
|
+
* entry[i+1].prevHash = hash(entry[i])
|
|
16
|
+
*
|
|
17
|
+
* Any modification to `entry[i]` (field values, field order, whitespace)
|
|
18
|
+
* produces a different `hash(entry[i])`, which means `entry[i+1]`'s
|
|
19
|
+
* stored `prevHash` no longer matches the recomputed hash, which means
|
|
20
|
+
* `verify()` returns `{ ok: false, divergedAt: i + 1 }`. The chain is
|
|
21
|
+
* append-only and tamper-evident without external anchoring.
|
|
22
|
+
*/
|
|
23
|
+
interface LedgerEntry {
|
|
24
|
+
/**
|
|
25
|
+
* Zero-based sequential position of this entry in the chain. The
|
|
26
|
+
* canonical adapter key is this number zero-padded to 10 digits
|
|
27
|
+
* (`"0000000001"`) so lexicographic ordering matches numeric order.
|
|
28
|
+
*/
|
|
29
|
+
readonly index: number;
|
|
30
|
+
/**
|
|
31
|
+
* Hex-encoded sha256 of the canonical JSON of the PREVIOUS entry.
|
|
32
|
+
* The genesis entry (index 0) has `prevHash === ''` — the first
|
|
33
|
+
* entry in a fresh vault has nothing to point back to.
|
|
34
|
+
*/
|
|
35
|
+
readonly prevHash: string;
|
|
36
|
+
/**
|
|
37
|
+
* Which kind of mutation this entry records. only supports
|
|
38
|
+
* data operations (`put`, `delete`, `amendment`). Access-control
|
|
39
|
+
* operations (`grant`, `revoke`, `rotate`) will be added in a
|
|
40
|
+
* follow-up once the keyring write path is instrumented — that's
|
|
41
|
+
* tracked in the epic issue.
|
|
42
|
+
*
|
|
43
|
+
* `'amendment'` is the multi-record audit entry written by the
|
|
44
|
+
* guards service when an admin/owner uses `withTransactions(...)`
|
|
45
|
+
* to repair a constraint-violating state. See `amendment` field
|
|
46
|
+
* below for the structured payload.
|
|
47
|
+
*
|
|
48
|
+
* `'lifecycle'` records a non-data audit event (e.g. partition
|
|
49
|
+
* handover) — `collection`/`id` are empty and the event detail
|
|
50
|
+
* lives in `reason` (e.g. `'partition-handed-over:<sealId>'`). Like
|
|
51
|
+
* `amendment`, it carries no data envelope, so `verifyBackupIntegrity`
|
|
52
|
+
* skips it in the data cross-check (it still participates in the
|
|
53
|
+
* tamper-evident chain).
|
|
54
|
+
*
|
|
55
|
+
* `'forget'` is the single summary entry written by `vault.forget()`
|
|
56
|
+
* (GDPR crypto-shred). `collection`/`id` are empty and `version`
|
|
57
|
+
* is 0 — a forget is not scoped to one record. `payloadHash` carries
|
|
58
|
+
* `sha256Hex(subjectId)` so the ledger PROVES "subject X existed and
|
|
59
|
+
* was erased on date D" without retaining the subject id or any
|
|
60
|
+
* plaintext; `reason` holds a JSON summary of the shred counts. Like
|
|
61
|
+
* `amendment`/`lifecycle` it carries no data envelope and is skipped
|
|
62
|
+
* by the reconstruct walker (it still participates in the chain, so
|
|
63
|
+
* `verify()` passes after a shred).
|
|
64
|
+
*/
|
|
65
|
+
readonly op: 'put' | 'delete' | 'amendment' | 'lifecycle' | 'migration' | 'forget';
|
|
66
|
+
/** The collection the mutation targeted. */
|
|
67
|
+
readonly collection: string;
|
|
68
|
+
/** The record id the mutation targeted. */
|
|
69
|
+
readonly id: string;
|
|
70
|
+
/**
|
|
71
|
+
* The record version AFTER this mutation. For `put` this is the
|
|
72
|
+
* newly assigned version; for `delete` this is the version that
|
|
73
|
+
* was deleted (the last version visible to reads).
|
|
74
|
+
*/
|
|
75
|
+
readonly version: number;
|
|
76
|
+
/** ISO timestamp of the mutation. */
|
|
77
|
+
readonly ts: string;
|
|
78
|
+
/** User id of the actor who performed the mutation. */
|
|
79
|
+
readonly actor: string;
|
|
80
|
+
/**
|
|
81
|
+
* Hex-encoded sha256 over the encrypted envelope's `_data` field, plus its
|
|
82
|
+
* sealed-field ciphertext map (`_sealed`) when the record carries one —
|
|
83
|
+
* so the ledger attests to both the open body and every sealed
|
|
84
|
+
* value. A record with no `_sealed` hashes `_data` alone.
|
|
85
|
+
* For `put`, this is the hash of the new ciphertext. For `delete`,
|
|
86
|
+
* it's the hash of the last visible ciphertext at deletion time, or the empty
|
|
87
|
+
* string if nothing was there to delete. Hashing the ciphertext (not the
|
|
88
|
+
* plaintext) preserves zero-knowledge — see the file docstring. The exact
|
|
89
|
+
* recipe lives in `envelopePayloadHash` (`hash.ts`).
|
|
90
|
+
*/
|
|
91
|
+
readonly payloadHash: string;
|
|
92
|
+
/**
|
|
93
|
+
* Optional human-readable tag describing why this mutation happened.
|
|
94
|
+
* Threaded through `collection.put(_, _, { reason })`. Common
|
|
95
|
+
* values include `'import:csv'`, `'import:json'`, `'import:xlsx'` from
|
|
96
|
+
* `as-*` ImportPlan.apply(), but consumers can use any string for
|
|
97
|
+
* domain-specific audit filtering. Auto-strip via `canonicalJson` —
|
|
98
|
+
* absent on the wire, never serialized as `null`.
|
|
99
|
+
*
|
|
100
|
+
* Audit consumers filter: `entries.filter(e => e.reason?.startsWith('import:'))`.
|
|
101
|
+
*/
|
|
102
|
+
readonly reason?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Optional hex-encoded sha256 of the encrypted JSON Patch delta
|
|
105
|
+
* blob stored alongside this entry in `_ledger_deltas/`. Present
|
|
106
|
+
* only for `put` operations that had a previous version — the
|
|
107
|
+
* genesis put of a new record, and every `delete`, leave this
|
|
108
|
+
* field undefined.
|
|
109
|
+
*
|
|
110
|
+
* The delta payload itself lives in a sibling internal collection
|
|
111
|
+
* (`_ledger_deltas/<paddedIndex>`) and is encrypted with the
|
|
112
|
+
* ledger DEK. Callers use `ledger.loadDelta(index)` to decrypt and
|
|
113
|
+
* deserialize it when reconstructing a historical version.
|
|
114
|
+
*
|
|
115
|
+
* Why optional instead of always-present: the first put of a
|
|
116
|
+
* record has no previous version to diff against, so storing an
|
|
117
|
+
* empty patch would be noise. For deletes there's no "next" state
|
|
118
|
+
* to describe with a delta. Both cases set this field to undefined.
|
|
119
|
+
*
|
|
120
|
+
* Note: the canonical-JSON hasher treats `undefined` as invalid
|
|
121
|
+
* (it's one of the guard rails), so on the wire this field is
|
|
122
|
+
* either `{ deltaHash: '<hex>' }` or absent from the JSON
|
|
123
|
+
* entirely — never `{ deltaHash: undefined }`.
|
|
124
|
+
*/
|
|
125
|
+
readonly deltaHash?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Present only when `op === 'amendment'`. Records the human reason,
|
|
128
|
+
* the role of the actor, the (collection, id, vBefore, vAfter) tuple
|
|
129
|
+
* for every record touched, and which guard invariants passed.
|
|
130
|
+
*
|
|
131
|
+
* See docs/superpowers/specs/2026-05-18-guards-design.md.
|
|
132
|
+
*/
|
|
133
|
+
readonly amendment?: {
|
|
134
|
+
readonly reason: string;
|
|
135
|
+
readonly role: 'admin' | 'owner';
|
|
136
|
+
readonly changes: ReadonlyArray<{
|
|
137
|
+
readonly collection: string;
|
|
138
|
+
readonly id: string;
|
|
139
|
+
readonly vBefore: number;
|
|
140
|
+
readonly vAfter: number;
|
|
141
|
+
}>;
|
|
142
|
+
readonly invariantsPassed: ReadonlyArray<string>;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Canonical (sort-stable) JSON encoder.
|
|
147
|
+
*
|
|
148
|
+
* This function is the load-bearing primitive of the hash chain:
|
|
149
|
+
* `sha256(canonicalJSON(entry))` must produce the same hex string
|
|
150
|
+
* every time, on every machine, for the same logical entry — otherwise
|
|
151
|
+
* `verify()` would return `{ ok: false }` on cross-platform reads.
|
|
152
|
+
*
|
|
153
|
+
* JavaScript's `JSON.stringify` is almost canonical, but NOT quite:
|
|
154
|
+
* it preserves the insertion order of object keys, which means
|
|
155
|
+
* `{a:1,b:2}` and `{b:2,a:1}` serialize differently. We fix this by
|
|
156
|
+
* recursively walking objects and sorting their keys before
|
|
157
|
+
* concatenation.
|
|
158
|
+
*
|
|
159
|
+
* Arrays keep their original order (reordering them would change
|
|
160
|
+
* semantics). Numbers, strings, booleans, and `null` use the default
|
|
161
|
+
* JSON encoding. `undefined` and functions are rejected — ledger
|
|
162
|
+
* entries are plain data, and silently dropping `undefined` would
|
|
163
|
+
* break the "same input → same hash" property if a caller forgot to
|
|
164
|
+
* omit a field.
|
|
165
|
+
*
|
|
166
|
+
* Performance: one pass per nesting level; O(n log n) for key sorting
|
|
167
|
+
* at each object. Entries are small (< 1 KB) so this is negligible
|
|
168
|
+
* compared to the sha256 call.
|
|
169
|
+
*/
|
|
170
|
+
declare function canonicalJson(value: unknown): string;
|
|
171
|
+
/**
|
|
172
|
+
* Compute a hex-encoded sha256 of a string via Web Crypto's subtle API.
|
|
173
|
+
*
|
|
174
|
+
* We use hex (not base64) for hashes because hex is case-insensitive,
|
|
175
|
+
* fixed-length (64 chars), and easier to compare visually in debug
|
|
176
|
+
* output. Base64 would save a few bytes in storage but every encrypted
|
|
177
|
+
* ledger entry is already much larger than the hash itself.
|
|
178
|
+
*/
|
|
179
|
+
declare function sha256Hex(input: string): Promise<string>;
|
|
180
|
+
/**
|
|
181
|
+
* Compute the canonical hash of a ledger entry. Short wrapper around
|
|
182
|
+
* `canonicalJson` + `sha256Hex`; callers use this instead of composing
|
|
183
|
+
* the two functions every time, so any future change to the hashing
|
|
184
|
+
* pipeline (e.g., adding a domain-separation prefix) lives in one place.
|
|
185
|
+
*/
|
|
186
|
+
declare function hashEntry(entry: LedgerEntry): Promise<string>;
|
|
187
|
+
/**
|
|
188
|
+
* Pad an index to the canonical 10-digit form used as the adapter key.
|
|
189
|
+
* Ten digits is enough for ~10 billion ledger entries per vault
|
|
190
|
+
* — far beyond any realistic use case, but cheap enough that the extra
|
|
191
|
+
* digits don't hurt storage.
|
|
192
|
+
*/
|
|
193
|
+
declare function paddedIndex(index: number): string;
|
|
194
|
+
/** Parse a padded adapter key back into a number. Returns NaN on malformed input. */
|
|
195
|
+
declare function parseIndex(key: string): number;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* `withForgetCascade` — declaration surface for GDPR right-to-erasure via
|
|
199
|
+
* per-record CEK crypto-shred.
|
|
200
|
+
*
|
|
201
|
+
* This file holds only the *declaration* shape and the disabled sentinel.
|
|
202
|
+
* The actual erasure machinery lives in:
|
|
203
|
+
* - `subject-index.ts` — the encrypted `_subject_index` reserved collection
|
|
204
|
+
* - `vault.ts` `forget()` — the per-record tombstone + ledger flow
|
|
205
|
+
* - `collection.ts` `_writeTombstone` — the envelope rewrite
|
|
206
|
+
*
|
|
207
|
+
* A `ForgetStrategy` declares which collections carry erasable subject data
|
|
208
|
+
* and the (dotted-path) field on each record that names the data subject.
|
|
209
|
+
* Declaring a collection here ALSO forces `perRecordKeys: true` for it (a
|
|
210
|
+
* shred can only erase a record whose body is keyed off a per-record CEK),
|
|
211
|
+
* so adopters opt into the CEK foundation transitively.
|
|
212
|
+
*
|
|
213
|
+
* @module
|
|
214
|
+
*/
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* User-supplied declaration passed to {@link withForgetCascade}. Maps a
|
|
218
|
+
* collection name to the record field (dotted path supported, e.g.
|
|
219
|
+
* `'billing.buyerId'`) that identifies the data subject for erasure.
|
|
220
|
+
*
|
|
221
|
+
* ```ts
|
|
222
|
+
* withForgetCascade({ subjects: { invoices: 'buyerId', contacts: 'id' } })
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
interface SubjectDeclaration {
|
|
226
|
+
readonly subjects: Record<string, string>;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Resolved forget strategy threaded through Noydb → every Vault. Carries
|
|
230
|
+
* the same `subjects` map the user declared. `NO_FORGET` (empty map) is the
|
|
231
|
+
* off-by-default sentinel; `vault.forget()` throws
|
|
232
|
+
* `ForgetStrategyNotConfiguredError` when the map is empty.
|
|
233
|
+
*/
|
|
234
|
+
interface ForgetStrategy {
|
|
235
|
+
/** Collection → subject-field (dotted path). Empty under `NO_FORGET`. */
|
|
236
|
+
readonly subjects: Readonly<Record<string, string>>;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Disabled sentinel — no collections declare a subject field. `vault.forget()`
|
|
240
|
+
* refuses with `ForgetStrategyNotConfiguredError`; no write hooks register; no
|
|
241
|
+
* collection is forced into `perRecordKeys`. Non-adopters pay nothing.
|
|
242
|
+
*/
|
|
243
|
+
declare const NO_FORGET: ForgetStrategy;
|
|
244
|
+
/**
|
|
245
|
+
* The outcome of a `vault.forget(subjectId)` call.
|
|
246
|
+
*
|
|
247
|
+
* `unmigratedRecords` lists `collection:id` pairs that were tombstoned but
|
|
248
|
+
* whose body had NOT been migrated to a per-record CEK at shred time (legacy
|
|
249
|
+
* body still under the shared collection DEK). Those records are tombstoned
|
|
250
|
+
* (live envelope + history stripped) but their pre-shred ciphertext, if it
|
|
251
|
+
* leaked into a backup before migration, remains decryptable under the
|
|
252
|
+
* collection DEK — so erasure-completeness is NOT guaranteed for them. Run
|
|
253
|
+
* the per-record-CEK migration pass, then re-forget, to close the gap.
|
|
254
|
+
*
|
|
255
|
+
* Blob attachments: a shredded record's **erasable** blobs (on a
|
|
256
|
+
* `perRecordKeys` collection) are crypto-shredded inline — `blobsShredded`
|
|
257
|
+
* counts those taken to refCount 0 (BlobObject deleted → chunks permanently
|
|
258
|
+
* undecryptable), `blobsRetainedShared` counts those still referenced by
|
|
259
|
+
* another record (shared content legitimately persists for its other owner).
|
|
260
|
+
* `blobResidueCollections` now lists only collections with blobs that could
|
|
261
|
+
* NOT be crypto-shredded: **legacy** blobs (no per-blob `_cek`, chunks under
|
|
262
|
+
* the shared `_blob` DEK — migrate them), or a session without the blob
|
|
263
|
+
* service loaded. An all-erasable subject yields an empty residue list.
|
|
264
|
+
*/
|
|
265
|
+
interface ForgetResult {
|
|
266
|
+
/** The subject id passed to `forget()`. Echoed for caller convenience. */
|
|
267
|
+
readonly subject: string;
|
|
268
|
+
/** Count of live records rewritten to a tombstone. */
|
|
269
|
+
readonly recordsShredded: number;
|
|
270
|
+
/** Count of `_history` envelopes tombstoned across all shredded records. */
|
|
271
|
+
readonly historyVersionsShredded: number;
|
|
272
|
+
/** Distinct collections that had at least one record shredded. */
|
|
273
|
+
readonly collections: readonly string[];
|
|
274
|
+
/** `collection:id` pairs shredded while still un-migrated (see type docs). */
|
|
275
|
+
readonly unmigratedRecords: readonly string[];
|
|
276
|
+
/** Count of erasable blobs crypto-shredded (refCount → 0, BlobObject deleted). */
|
|
277
|
+
readonly blobsShredded: number;
|
|
278
|
+
/** Count of erasable blobs retained because still referenced elsewhere (shared). */
|
|
279
|
+
readonly blobsRetainedShared: number;
|
|
280
|
+
/** Collections with blobs that could NOT be crypto-shredded — legacy (no `_cek`) or blobs disabled (see type docs). */
|
|
281
|
+
readonly blobResidueCollections: readonly string[];
|
|
282
|
+
/**
|
|
283
|
+
* Count of persisted `_idx/<field>/<recordId>` index side-cars hard-deleted
|
|
284
|
+
* across the shredded records. These live under the retained
|
|
285
|
+
* collection DEK, so crypto-shred alone would leave the indexed field VALUES
|
|
286
|
+
* readable — `forget()` must delete them.
|
|
287
|
+
*/
|
|
288
|
+
readonly indexPostingsPurged: number;
|
|
289
|
+
/**
|
|
290
|
+
* `collection:id:field` entries whose persisted `_idx` side-car could NOT be
|
|
291
|
+
* deleted — index residue that still leaks the indexed value under the
|
|
292
|
+
* retained collection DEK. Non-empty means erasure is INCOMPLETE: retry, or
|
|
293
|
+
* purge the side-car out of band.
|
|
294
|
+
*/
|
|
295
|
+
readonly indexResidue: readonly string[];
|
|
296
|
+
/**
|
|
297
|
+
* Count of `_sealed[field]` slots dropped from the live store across the
|
|
298
|
+
* shredded records. For slots written under `sensitive` +
|
|
299
|
+
* `perRecordKeys` (the current path), the key derives off the per-record CEK,
|
|
300
|
+
* so tombstoning the record — which drops `_cek` and `_sealed` — also
|
|
301
|
+
* crypto-shreds the value. A legacy slot (written before per-record CEKs) keys
|
|
302
|
+
* off the collection DEK instead, so dropping it removes it from the live store but a
|
|
303
|
+
* pre-forget backup remains recoverable by a DEK holder (same caveat `_data`
|
|
304
|
+
* carries); migrate by re-`put`ting before forgetting for full crypto-shred.
|
|
305
|
+
*/
|
|
306
|
+
readonly sealedFieldsShredded: number;
|
|
307
|
+
/** Count of `_sealed_cek` host-delivery envelopes deleted (#H-1). A record sealed to an
|
|
308
|
+
* at-* host via sealRecordToHost persists its raw CEK there; forget() must destroy them. */
|
|
309
|
+
readonly sealedCekEnvelopesPurged: number;
|
|
310
|
+
/** `collection:id` whose `_sealed_cek` purge failed (residue — the host-recoverable CEK may survive). */
|
|
311
|
+
readonly sealedCekResidue: readonly string[];
|
|
312
|
+
/** `collection:id:field` sealed slots that were DEK-derived (legacy, written before per-record CEKs) and thus NOT crypto-shredded
|
|
313
|
+
* by dropping `_cek` — the collection DEK is retained, so synced/backup copies stay decryptable (#M-1). */
|
|
314
|
+
readonly sealedResidue: readonly string[];
|
|
315
|
+
/** The single `op:'forget'` ledger entry appended for this erasure. */
|
|
316
|
+
readonly ledgerEntry: LedgerEntry;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* The encrypted subject index.
|
|
321
|
+
*
|
|
322
|
+
* GDPR crypto-shred needs to answer "which records belong to data subject
|
|
323
|
+
* X?" portably (the index must travel with the vault/bundle) WITHOUT leaking
|
|
324
|
+
* subject-equivalence to the store. The rejected alternative — an unencrypted
|
|
325
|
+
* subject tag in envelope metadata — would let anyone with store access see
|
|
326
|
+
* which records share a subject. Instead we keep a reserved `_subject_index`
|
|
327
|
+
* collection, encrypted under its OWN DEK (`getDEK('_subject_index')`):
|
|
328
|
+
*
|
|
329
|
+
* - record id = `HMAC-SHA256(indexDEK, subjectId)` (M-2). A bare
|
|
330
|
+
* `sha256Hex(subjectId)` would be offline-computable: an attacker with
|
|
331
|
+
* store access and a candidate list (emails / customer ids are low-entropy)
|
|
332
|
+
* could dictionary the hash to confirm "subject X is present here." Keying
|
|
333
|
+
* the id with the vault-only index DEK removes that capability — without the
|
|
334
|
+
* DEK the id cannot be derived. (Legacy entries written before M-2 used the
|
|
335
|
+
* bare sha256 id; the read/remove paths dual-look-up both forms.)
|
|
336
|
+
* - record body = AES-GCM(JSON `{ r: [{ collection, id }], p }`) under the
|
|
337
|
+
* index DEK, where `p` pads the plaintext to a bucketed length so the
|
|
338
|
+
* ciphertext `_data` length does not leak the approximate record count.
|
|
339
|
+
* Legacy bodies were a bare `[{ collection, id }]` array; reads accept both.
|
|
340
|
+
*
|
|
341
|
+
* ## Concurrency (RISK #3 — known v1 limitation)
|
|
342
|
+
*
|
|
343
|
+
* `addSubjectRef` / `removeSubjectRef` are read-modify-write with no CAS. The
|
|
344
|
+
* design assumes a SINGLE WRITER (the noy-db single-process write model). Two
|
|
345
|
+
* concurrent writers racing on the SAME subject can lose an entry (last-write
|
|
346
|
+
* wins on the ref list). This is documented, not fixed in v1:
|
|
347
|
+
* `rebuildSubjectIndex` performs a full scan to recover a correct index from
|
|
348
|
+
* the canonical records, so a lost ref is recoverable. A CAS-backed index is
|
|
349
|
+
* deferred to a later slice.
|
|
350
|
+
*
|
|
351
|
+
* @module
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
/** Reserved collection holding the encrypted subject → records index. */
|
|
355
|
+
declare const SUBJECT_INDEX_COLLECTION = "_subject_index";
|
|
356
|
+
/** A single record reference held in a subject's index entry. */
|
|
357
|
+
interface SubjectRef {
|
|
358
|
+
readonly collection: string;
|
|
359
|
+
readonly id: string;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export { type ForgetStrategy as F, type LedgerEntry as L, NO_FORGET as N, type SubjectDeclaration as S, type ForgetResult as a, SUBJECT_INDEX_COLLECTION as b, type SubjectRef as c, canonicalJson as d, parseIndex as e, hashEntry as h, paddedIndex as p, sha256Hex as s };
|
package/dist/sync/index.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import '../
|
|
3
|
-
import '../
|
|
4
|
-
import '../
|
|
5
|
-
import '../strategy-BSxFXGzb.js';
|
|
6
|
-
import '../index-D8I_pyJD.js';
|
|
1
|
+
import { cr as SyncStrategy } from '../index-BzUo1B6n.js';
|
|
2
|
+
import '../subject-index-O75wKshW.js';
|
|
3
|
+
import '../describe-aBkJR2sd.js';
|
|
4
|
+
import '../index-B9QdHytu.js';
|
|
7
5
|
import '@noy-db/attestation';
|
|
8
6
|
|
|
9
7
|
/**
|
package/dist/sync/index.js
CHANGED
|
@@ -2,13 +2,14 @@ import {
|
|
|
2
2
|
PresenceHandle,
|
|
3
3
|
SyncEngine,
|
|
4
4
|
SyncTransaction
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-IUEN57TV.js";
|
|
6
|
+
import "../chunk-VQNJ7UZL.js";
|
|
7
|
+
import "../chunk-5O3AOPDT.js";
|
|
8
|
+
import "../chunk-5TDJ56JE.js";
|
|
9
|
+
import "../chunk-ZYUC53LT.js";
|
|
10
|
+
import "../chunk-PZ5AY32C.js";
|
|
10
11
|
|
|
11
|
-
// src/team/sync-active.ts
|
|
12
|
+
// src/with-party/team/sync-active.ts
|
|
12
13
|
function withSync() {
|
|
13
14
|
return {
|
|
14
15
|
buildSyncEngine(opts) {
|
package/dist/sync/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/team/sync-active.ts"],"sourcesContent":["/**\n * Active sync strategy — `withSync()` returns the real implementation\n * that wires the `SyncEngine`, `SyncTransaction`, and `PresenceHandle`\n * constructors into the Noydb / Vault / Collection hot paths.\n *\n * Consumers opt in by:\n *\n * ```ts\n * import { createNoydb } from '@noy-db/hub'\n * import { withSync } from '@noy-db/hub/sync'\n *\n * const db = await createNoydb({\n * store: localStore,\n * sync: remoteStore,\n * user: ...,\n * syncStrategy: withSync(),\n * })\n * ```\n *\n * The factory delegates to the existing `sync.ts`,\n * `sync-transaction.ts`, and `presence.ts` modules. Splitting the\n * import chain through this file is what lets tsup tree-shake the\n * ~856 LOC of replication + presence machinery out of the default\n * bundle when no `withSync()` import is present.\n *\n * Keyring + grant/revoke/magic-link/delegation stay in the always-on\n * core (or tree-shake via direct named imports) — those are required\n * for any multi-user vault, even purely local ones.\n *\n * @public\n */\n\nimport type { SyncStrategy, BuildSyncEngineOptions } from './sync-strategy.js'\nimport type { PresenceHandleOpts } from './presence.js'\nimport type { Vault } from '
|
|
1
|
+
{"version":3,"sources":["../../src/with-party/team/sync-active.ts"],"sourcesContent":["/**\n * Active sync strategy — `withSync()` returns the real implementation\n * that wires the `SyncEngine`, `SyncTransaction`, and `PresenceHandle`\n * constructors into the Noydb / Vault / Collection hot paths.\n *\n * Consumers opt in by:\n *\n * ```ts\n * import { createNoydb } from '@noy-db/hub'\n * import { withSync } from '@noy-db/hub/sync'\n *\n * const db = await createNoydb({\n * store: localStore,\n * sync: remoteStore,\n * user: ...,\n * syncStrategy: withSync(),\n * })\n * ```\n *\n * The factory delegates to the existing `sync.ts`,\n * `sync-transaction.ts`, and `presence.ts` modules. Splitting the\n * import chain through this file is what lets tsup tree-shake the\n * ~856 LOC of replication + presence machinery out of the default\n * bundle when no `withSync()` import is present.\n *\n * Keyring + grant/revoke/magic-link/delegation stay in the always-on\n * core (or tree-shake via direct named imports) — those are required\n * for any multi-user vault, even purely local ones.\n *\n * @public\n */\n\nimport type { SyncStrategy, BuildSyncEngineOptions } from './sync-strategy.js'\nimport type { PresenceHandleOpts } from './presence.js'\nimport type { Vault } from '../../kernel/vault.js'\nimport { SyncEngine } from './sync.js'\nimport { SyncTransaction } from './sync-transaction.js'\nimport { PresenceHandle } from './presence.js'\n\nexport function withSync(): SyncStrategy {\n return {\n buildSyncEngine(opts: BuildSyncEngineOptions): SyncEngine {\n return new SyncEngine(opts)\n },\n buildSyncTransaction(vault: Vault, engine: SyncEngine): SyncTransaction {\n return new SyncTransaction(vault, engine)\n },\n buildPresence<P>(opts: PresenceHandleOpts): PresenceHandle<P> {\n return new PresenceHandle<P>(opts)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;AAuCO,SAAS,WAAyB;AACvC,SAAO;AAAA,IACL,gBAAgB,MAA0C;AACxD,aAAO,IAAI,WAAW,IAAI;AAAA,IAC5B;AAAA,IACA,qBAAqB,OAAc,QAAqC;AACtE,aAAO,IAAI,gBAAgB,OAAO,MAAM;AAAA,IAC1C;AAAA,IACA,cAAiB,MAA6C;AAC5D,aAAO,IAAI,eAAkB,IAAI;AAAA,IACnC;AAAA,EACF;AACF;","names":[]}
|
package/dist/team/index.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import '../
|
|
4
|
-
import '../
|
|
5
|
-
import '../
|
|
6
|
-
import '../strategy-BSxFXGzb.js';
|
|
7
|
-
import '../index-D8I_pyJD.js';
|
|
1
|
+
import { cT as NoydbStore, cF as UnlockedKeyring } from '../index-BzUo1B6n.js';
|
|
2
|
+
export { dM as BundleRecipient, fg as EnrollAuthenticatorOptions, fh as EnrollAuthenticatorWrappingDEKsOptions, fi as EnrollAuthenticatorWrappingKEKOptions, gf as ListUsersOptions, h2 as PaperRecoveryEntry, he as PresenceHandle, hI as RecoverPassphraseInput, hJ as RecoverPassphraseResult, hK as RecoverUserOptions, hN as RecoveryProof, hZ as RotatePassphraseInput, iw as SlotRewrapCeremony, ix as SlotRewrapContext, iG as SyncEngine, iO as SyncTransaction, j6 as UpdateAuthenticatorOptions, jn as WrappedDeksBlob, jy as buildRecipientKeyringFile, jz as burnPaperRecoveryEntry, kO as changeSecret, kP as createOwnerKeyring, jF as deriveMagicLinkContentKey, jJ as enrollAuthenticator, kQ as ensureCollectionDEK, jN as evaluateExportCapability, jP as evaluateImportCapability, jS as findAuthenticator, kR as grant, jT as hasExportCapability, jU as hasImportCapability, jX as isMagicLinkGrantExpired, k4 as listMagicLinkGrants, k5 as listUsers, k6 as listUsersWithEnvelopes, kS as loadKeyring, k9 as loadPaperRecoveryEntries, kc as magicLinkGrantRecordId, kd as mintPaperRecoveryEntry, kf as mintWrappedDeksBlob, kT as persistKeyring, kk as readMagicLinkGrantRecord, k1 as recoverPassphrase, km as recoverUser, kq as removeAuthenticator, kU as revoke, kw as revokeMagicLinkGrant, k2 as rotatePassphrase, ky as savePaperRecoveryEntries, kC as unwrapDeksFromBlob, kD as unwrapDeksFromPaperEntry, kF as unwrapMagicLinkGrant, kV as updateAuthenticator, kW as updateKeyringIdentity, kN as writeMagicLinkGrant } from '../index-BzUo1B6n.js';
|
|
3
|
+
import '../subject-index-O75wKshW.js';
|
|
4
|
+
import '../describe-aBkJR2sd.js';
|
|
5
|
+
import '../index-B9QdHytu.js';
|
|
8
6
|
import '@noy-db/attestation';
|
|
9
7
|
|
|
10
8
|
/**
|