@noy-db/hub 0.6.0-pre.2 → 0.6.0-pre.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5234 -0
- package/codemods/0.4.0-pre.json +699 -0
- package/codemods/0.6.0-pre.json +211 -0
- package/dist/api-EYNT6KGS.js +20 -0
- package/dist/attestation/index.js +19 -19
- package/dist/{backup-YYBE5RPC.js → backup-FSC36VWC.js} +36 -18
- package/dist/backup-FSC36VWC.js.map +1 -0
- package/dist/blobs/index.js +13 -13
- package/dist/broker/index.js +12 -12
- package/dist/cargo/index.js +33 -33
- package/dist/{chunk-35EBKWQU.js → chunk-2LFOMUEA.js} +4 -4
- package/dist/{chunk-OF3L2SD6.js → chunk-32B7VCKU.js} +2 -2
- package/dist/{chunk-MSWYQLMQ.js → chunk-3B6S6RSI.js} +2 -2
- package/dist/{chunk-PJNTR2NV.js → chunk-3ENNPCIW.js} +7 -10
- package/dist/chunk-3ENNPCIW.js.map +1 -0
- package/dist/{chunk-7F4DBNSP.js → chunk-3O72ZD2E.js} +3 -3
- package/dist/{chunk-FNSMZQS4.js → chunk-3PMFMUFX.js} +2 -2
- package/dist/{chunk-WQDTCJ6W.js → chunk-45YHJ3GV.js} +11 -3
- package/dist/{chunk-WQDTCJ6W.js.map → chunk-45YHJ3GV.js.map} +1 -1
- package/dist/{chunk-NIVEDYJZ.js → chunk-4A34KWOU.js} +31 -49
- package/dist/chunk-4A34KWOU.js.map +1 -0
- package/dist/{chunk-ZJADGNYF.js → chunk-4AOERLTV.js} +1 -1
- package/dist/chunk-4AOERLTV.js.map +1 -0
- package/dist/{chunk-EDXAQ6JI.js → chunk-4N5Q23KV.js} +87 -34
- package/dist/chunk-4N5Q23KV.js.map +1 -0
- package/dist/{chunk-VV4NSB7P.js → chunk-4OQZNXQG.js} +15 -24
- package/dist/chunk-4OQZNXQG.js.map +1 -0
- package/dist/{chunk-FAXZQ5UF.js → chunk-4RAS6HN6.js} +2 -2
- package/dist/{chunk-C2OOEM57.js → chunk-4YL2LMXK.js} +92 -35
- package/dist/chunk-4YL2LMXK.js.map +1 -0
- package/dist/{chunk-EP7VPR7Y.js → chunk-5Q7AJ7DN.js} +11 -8
- package/dist/chunk-5Q7AJ7DN.js.map +1 -0
- package/dist/{chunk-VMCCGUQB.js → chunk-6JPGVL7X.js} +2 -2
- package/dist/{chunk-PRDRGL73.js → chunk-6KTVJ5ZZ.js} +17 -14
- package/dist/chunk-6KTVJ5ZZ.js.map +1 -0
- package/dist/{chunk-4MC5JRRX.js → chunk-6WO62AJW.js} +14 -15
- package/dist/chunk-6WO62AJW.js.map +1 -0
- package/dist/{chunk-WLYIROCJ.js → chunk-6YD5SYQS.js} +2 -2
- package/dist/{chunk-YAWK6AWF.js → chunk-7KAE7CQ2.js} +2 -2
- package/dist/{chunk-MWKDOHEF.js → chunk-7LNE2N2V.js} +17 -10
- package/dist/chunk-7LNE2N2V.js.map +1 -0
- package/dist/{chunk-5PR33AC4.js → chunk-7PJ3BKHS.js} +20 -17
- package/dist/chunk-7PJ3BKHS.js.map +1 -0
- package/dist/{chunk-JXIDGFKS.js → chunk-A4TOGAUW.js} +4 -2
- package/dist/chunk-A4TOGAUW.js.map +1 -0
- package/dist/{chunk-VCETL77O.js → chunk-AU3AUJIZ.js} +27 -7
- package/dist/chunk-AU3AUJIZ.js.map +1 -0
- package/dist/{chunk-NKH7GSIH.js → chunk-AUPSEJ7O.js} +4 -4
- package/dist/{chunk-CCZJJ4I2.js → chunk-B6IYATME.js} +4 -4
- package/dist/{chunk-WYZ5MYUA.js → chunk-BAHOV5I5.js} +44 -42
- package/dist/chunk-BAHOV5I5.js.map +1 -0
- package/dist/{chunk-G5APARUV.js → chunk-BEZDLIDG.js} +13 -15
- package/dist/chunk-BEZDLIDG.js.map +1 -0
- package/dist/{chunk-ERB6NDDW.js → chunk-CAGI4LLJ.js} +427 -72
- package/dist/chunk-CAGI4LLJ.js.map +1 -0
- package/dist/{chunk-4UVDI4XE.js → chunk-CLAHBPOI.js} +4 -4
- package/dist/{chunk-HNGSV2YC.js → chunk-CWM4GQD2.js} +39 -10
- package/dist/chunk-CWM4GQD2.js.map +1 -0
- package/dist/{chunk-HVQGCKY4.js → chunk-D3R7Q4QK.js} +2 -2
- package/dist/{chunk-I4F6PKUK.js → chunk-DIZ6HM7Q.js} +16 -17
- package/dist/chunk-DIZ6HM7Q.js.map +1 -0
- package/dist/{chunk-ZNACADFG.js → chunk-DVRZYAGT.js} +4 -4
- package/dist/chunk-DVRZYAGT.js.map +1 -0
- package/dist/{chunk-P7OG2ETF.js → chunk-DXKLLKME.js} +3 -3
- package/dist/{chunk-TDJPS3T2.js → chunk-E5SC6ENM.js} +24 -19
- package/dist/chunk-E5SC6ENM.js.map +1 -0
- package/dist/{chunk-26JMGSSC.js → chunk-EES37S2V.js} +4 -4
- package/dist/chunk-EES37S2V.js.map +1 -0
- package/dist/{chunk-JIUVJ4M7.js → chunk-EKEIEJL6.js} +2 -2
- package/dist/{chunk-GASWQ3XG.js → chunk-ESKIAXO2.js} +15 -16
- package/dist/chunk-ESKIAXO2.js.map +1 -0
- package/dist/{chunk-TOAIYQJR.js → chunk-FFSQFH6D.js} +7 -10
- package/dist/chunk-FFSQFH6D.js.map +1 -0
- package/dist/{chunk-DG27IUVI.js → chunk-FS7NTGCJ.js} +2 -2
- package/dist/{chunk-V5KYPBUR.js → chunk-FW7NGYLT.js} +11 -14
- package/dist/chunk-FW7NGYLT.js.map +1 -0
- package/dist/{chunk-52QYGZHH.js → chunk-GBBDFE6C.js} +2 -2
- package/dist/chunk-GBBDFE6C.js.map +1 -0
- package/dist/{chunk-HXGUIPQB.js → chunk-GQXFOAYZ.js} +3 -3
- package/dist/{chunk-BTVYJWSN.js → chunk-GTHVPVAR.js} +10 -10
- package/dist/{chunk-DMQCLZ4Z.js → chunk-GWO2IDAB.js} +2 -2
- package/dist/{chunk-6HFM7EIT.js → chunk-H3G4I3PN.js} +2 -2
- package/dist/chunk-HK67PX4J.js +27 -0
- package/dist/chunk-HK67PX4J.js.map +1 -0
- package/dist/{chunk-E7OBCBXS.js → chunk-HQSPF5IY.js} +22 -18
- package/dist/chunk-HQSPF5IY.js.map +1 -0
- package/dist/{chunk-VJFMXYKP.js → chunk-HR5R5JOM.js} +2 -2
- package/dist/{chunk-FDX7OWWI.js → chunk-HYYVT2KZ.js} +2 -2
- package/dist/{chunk-JRCYZEHU.js → chunk-I6QKB7MT.js} +2 -2
- package/dist/{chunk-MZ5ZFO2D.js → chunk-ICDHUUMQ.js} +84 -112
- package/dist/chunk-ICDHUUMQ.js.map +1 -0
- package/dist/{chunk-W5W6KHN2.js → chunk-IGNJOJEP.js} +1 -1
- package/dist/chunk-IGNJOJEP.js.map +1 -0
- package/dist/{chunk-KUDZVJKQ.js → chunk-IJ46VCWD.js} +2 -2
- package/dist/{chunk-4HDYQL3J.js → chunk-INMHEMXX.js} +2 -2
- package/dist/{chunk-66W5OOCX.js → chunk-JLYQQNY4.js} +52 -65
- package/dist/chunk-JLYQQNY4.js.map +1 -0
- package/dist/{chunk-UHXCLPGC.js → chunk-JNMTN5D5.js} +2 -2
- package/dist/chunk-JNMTN5D5.js.map +1 -0
- package/dist/{chunk-I4ZAO7F7.js → chunk-JWMBG5S3.js} +7 -11
- package/dist/chunk-JWMBG5S3.js.map +1 -0
- package/dist/chunk-KRVS7YWY.js +123 -0
- package/dist/chunk-KRVS7YWY.js.map +1 -0
- package/dist/{chunk-AR2JDFAE.js → chunk-KV6JM2IA.js} +2 -2
- package/dist/{chunk-PVU7LW5L.js → chunk-KX57HODD.js} +6 -6
- package/dist/{chunk-PY7CI6L5.js → chunk-LGFTOU27.js} +553 -275
- package/dist/chunk-LGFTOU27.js.map +1 -0
- package/dist/chunk-LN7P6MZB.js +190 -0
- package/dist/chunk-LN7P6MZB.js.map +1 -0
- package/dist/{chunk-UIBGXRDD.js → chunk-LX46B56Q.js} +25 -31
- package/dist/chunk-LX46B56Q.js.map +1 -0
- package/dist/{chunk-CEJWMBXO.js → chunk-LXECF2ZR.js} +2 -2
- package/dist/{chunk-7VHY5E3X.js → chunk-MSLPDFK2.js} +7 -7
- package/dist/{chunk-I6SDX7WX.js → chunk-MZTUTEHP.js} +16 -22
- package/dist/chunk-MZTUTEHP.js.map +1 -0
- package/dist/{chunk-VRA4Q7DA.js → chunk-NCCEDL2K.js} +55 -48
- package/dist/chunk-NCCEDL2K.js.map +1 -0
- package/dist/{chunk-HNHCQ556.js → chunk-NR2SUJ3H.js} +2 -2
- package/dist/{chunk-AHLJSVRL.js → chunk-NW4TY6VC.js} +5 -7
- package/dist/chunk-NW4TY6VC.js.map +1 -0
- package/dist/{chunk-RKKORO4M.js → chunk-O742QBZZ.js} +10 -10
- package/dist/chunk-O742QBZZ.js.map +1 -0
- package/dist/{chunk-VN45YLWM.js → chunk-OHOKBMTM.js} +343 -132
- package/dist/chunk-OHOKBMTM.js.map +1 -0
- package/dist/{chunk-W3TVWF6N.js → chunk-OIBEJN5H.js} +2 -2
- package/dist/{chunk-QD724WDJ.js → chunk-OMYCSTXL.js} +4 -4
- package/dist/{chunk-Z45YRGFO.js → chunk-ONVD6GBY.js} +2 -2
- package/dist/{chunk-TAGFGKHP.js → chunk-OTHHO3KI.js} +7 -10
- package/dist/chunk-OTHHO3KI.js.map +1 -0
- package/dist/{chunk-3737A6EA.js → chunk-P2MR5UNE.js} +75 -18
- package/dist/chunk-P2MR5UNE.js.map +1 -0
- package/dist/chunk-PENPHA45.js +66 -0
- package/dist/chunk-PENPHA45.js.map +1 -0
- package/dist/{chunk-3FSX6LDG.js → chunk-PPCOKVFA.js} +8 -3
- package/dist/{chunk-3FSX6LDG.js.map → chunk-PPCOKVFA.js.map} +1 -1
- package/dist/{chunk-VOQW5LAM.js → chunk-QSIEL6TL.js} +102 -71
- package/dist/chunk-QSIEL6TL.js.map +1 -0
- package/dist/chunk-RFO4UXKQ.js +201 -0
- package/dist/chunk-RFO4UXKQ.js.map +1 -0
- package/dist/{chunk-KCQX65FU.js → chunk-RKCRPPNB.js} +3 -3
- package/dist/{chunk-7TSYBD3E.js → chunk-RSXQNFGO.js} +2 -2
- package/dist/{chunk-SZ2K3MHL.js → chunk-S56VYR4Q.js} +8 -11
- package/dist/{chunk-SZ2K3MHL.js.map → chunk-S56VYR4Q.js.map} +1 -1
- package/dist/{chunk-7NXHMW6Y.js → chunk-SYS46BL7.js} +2 -2
- package/dist/{chunk-55LKVALY.js → chunk-T7IR4N2S.js} +1 -3
- package/dist/chunk-T7IR4N2S.js.map +1 -0
- package/dist/{chunk-A67356IR.js → chunk-T7JGWTES.js} +33 -8
- package/dist/chunk-T7JGWTES.js.map +1 -0
- package/dist/{chunk-WHJKIZS7.js → chunk-TDSN2O2V.js} +27 -149
- package/dist/chunk-TDSN2O2V.js.map +1 -0
- package/dist/{chunk-747LRSOO.js → chunk-TMBSPLUG.js} +2 -2
- package/dist/{chunk-LWSJG3LI.js → chunk-TQPASLY4.js} +7 -3
- package/dist/chunk-TQPASLY4.js.map +1 -0
- package/dist/{chunk-WKPJXWKR.js → chunk-TX5MKAHA.js} +3 -3
- package/dist/{chunk-HFQ6LGIO.js → chunk-U27Y4DJZ.js} +12 -10
- package/dist/{chunk-HFQ6LGIO.js.map → chunk-U27Y4DJZ.js.map} +1 -1
- package/dist/{chunk-E6427JU2.js → chunk-VVSOPRUE.js} +18 -2
- package/dist/chunk-VVSOPRUE.js.map +1 -0
- package/dist/{chunk-7G6VDWXB.js → chunk-WVE6YKMX.js} +3 -3
- package/dist/chunk-WVE6YKMX.js.map +1 -0
- package/dist/{chunk-GLKDWWNO.js → chunk-YALD3SST.js} +16 -14
- package/dist/chunk-YALD3SST.js.map +1 -0
- package/dist/{chunk-NJDQ4YSV.js → chunk-YKXZHUOW.js} +4 -4
- package/dist/{chunk-VW6ZZGCG.js → chunk-ZLHHE5XZ.js} +3 -3
- package/dist/{chunk-FUHKW252.js → chunk-ZZXLB6AS.js} +2 -2
- package/dist/classified/index.js +5 -5
- package/dist/{classified-marker-FTOX7Q5L.js → classified-marker-NA6HUV33.js} +3 -3
- package/dist/collection-facade-VBM35WAH.js +45 -0
- package/dist/{computed-6G5M3UPH.js → computed-GSTLWSY5.js} +3 -3
- package/dist/consent/index.js +10 -10
- package/dist/cover/index.js +10 -3
- package/dist/custody/index.js +11 -11
- package/dist/{dead-filter-ENRIOQIE.js → dead-filter-UALP5DJX.js} +2 -2
- package/dist/debug/index.js +1 -1
- package/dist/{delegation-SSEPLXXO.js → delegation-JLNXM7KH.js} +24 -23
- package/dist/delegation-JLNXM7KH.js.map +1 -0
- package/dist/derivations/index.js +12 -12
- package/dist/derive-YUO3TQYN.js +22 -0
- package/dist/directory/index.js +10 -10
- package/dist/{dispatch-RE74SH6L.js → dispatch-4ZHLSFZQ.js} +5 -5
- package/dist/{dispatch-BDVGYC6X.js → dispatch-77CB75KB.js} +18 -18
- package/dist/{enclave-52VUXNRL.js → enclave-O4NOROCJ.js} +27 -9
- package/dist/executor-CZDXBXKE.js +29 -0
- package/dist/executor-DVJAWN3B.js +9 -0
- package/dist/executor-VRLG4TQJ.js +9 -0
- package/dist/export-accessible-UXSMG7AB.js +23 -0
- package/dist/extract-partition-TVY7AMKH.js +38 -0
- package/dist/{fanout-sidecar-DTBIDOWF.js → fanout-sidecar-NLQ7QAYW.js} +18 -27
- package/dist/fanout-sidecar-NLQ7QAYW.js.map +1 -0
- package/dist/find-WSARMJBW.js +11 -0
- package/dist/forget/index.js +9 -9
- package/dist/guards/index.js +7 -7
- package/dist/history/index.js +23 -20
- package/dist/history/index.js.map +1 -1
- package/dist/i18n/index.js +14 -14
- package/dist/index.d.ts +33 -15
- package/dist/index.js +187 -191
- package/dist/index.js.map +1 -1
- package/dist/indexing/index.js +2 -2
- package/dist/introspection/index.js +11 -11
- package/dist/issue-3JNJNPT3.js +19 -0
- package/dist/kernel/constants.d.ts +18 -0
- package/dist/kernel/enclave/crypto.d.ts +24 -4
- package/dist/kernel/enclave/index.d.ts +9 -2
- package/dist/kernel/enclave/record-aad.d.ts +131 -0
- package/dist/kernel/enclave/record-envelope.d.ts +76 -0
- package/dist/kernel/enclave/record-keys/envelope-body.d.ts +34 -2
- package/dist/kernel/enclave/record-keys/lifecycle.d.ts +22 -5
- package/dist/kernel/enclave/record-keys/record-codec.d.ts +47 -14
- package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +88 -0
- package/dist/kernel/enclave/record-keys/rekey.d.ts +68 -0
- package/dist/kernel/enclave/record-keys/tombstone.d.ts +3 -2
- package/dist/kernel/errors.d.ts +71 -12
- package/dist/kernel/merge-authority.d.ts +25 -0
- package/dist/kernel/noydb.d.ts +27 -4
- package/dist/kernel/query/builder.d.ts +15 -2
- package/dist/kernel/query/join.d.ts +27 -0
- package/dist/kernel/sync-policy.d.ts +0 -2
- package/dist/kernel/tier-visibility.d.ts +15 -0
- package/dist/kernel/types.d.ts +145 -12
- package/dist/kernel/vault.d.ts +22 -18
- package/dist/kernel/via/index.d.ts +11 -2
- package/dist/{ledger-4WJL66BW.js → ledger-MVPNG5OS.js} +11 -11
- package/dist/liberate-4LOJOLDT.js +24 -0
- package/dist/{link-set-N4ZPV6E6.js → link-set-3POMQR3I.js} +11 -11
- package/dist/{managed-secret-OTHS64IF.js → managed-secret-IARIJJ7Q.js} +11 -3
- package/dist/materialized-views/index.js +22 -21
- package/dist/migrate-cek-XM2ETTZW.js +19 -0
- package/dist/migrate-cek-XM2ETTZW.js.map +1 -0
- package/dist/money/index.js +12 -8
- package/dist/noydb-IRILUDED.js +84 -0
- package/dist/overlay-views/index.js +4 -4
- package/dist/periods/index.js +22 -12
- package/dist/pod/index.js +75 -86
- package/dist/pod-handle-MELERCKU.js +41 -0
- package/dist/pod-handle-MELERCKU.js.map +1 -0
- package/dist/policy/index.js +11 -4
- package/dist/port/to/index.d.ts +4 -4
- package/dist/port/to/locator.d.ts +54 -8
- package/dist/port/with/i18n-strategy.d.ts +4 -1
- package/dist/port/with/lookup-strategy.d.ts +4 -1
- package/dist/port/with/merge-authority.d.ts +52 -0
- package/dist/port/with/service-bus.d.ts +0 -4
- package/dist/port/with/strategies.d.ts +2 -0
- package/dist/port/with/team-strategy.d.ts +5 -1
- package/dist/portability/index.js +8 -8
- package/dist/{post-register-ZAG2CAIY.js → post-register-Z5T7FY45.js} +6 -6
- package/dist/query/index.js +3 -3
- package/dist/reduce/index.js +4 -4
- package/dist/register-UZ37QPDB.js +32 -0
- package/dist/registry-ETJNA7PO.js +9 -0
- package/dist/registry-F7U6KSLX.js +9 -0
- package/dist/registry-L4ELKX6C.js +18 -0
- package/dist/registry-SDT5LIGO.js +19 -0
- package/dist/request-withdrawal-PVFEYX57.js +31 -0
- package/dist/{reveal-CMOJY4VO.js → reveal-DQ2E3QAZ.js} +6 -6
- package/dist/revoke-YXY6SHUH.js +24 -0
- package/dist/satellites/index.js +1 -1
- package/dist/schema-update/index.js +2 -2
- package/dist/sealed-record/index.js +20 -13
- package/dist/sealed-record/index.js.map +1 -1
- package/dist/search/index.js +4 -4
- package/dist/{seed-UK4QRIUN.js → seed-DZ4ORU5N.js} +19 -22
- package/dist/seed-DZ4ORU5N.js.map +1 -0
- package/dist/sequence/index.js +9 -9
- package/dist/session/index.js +10 -10
- package/dist/shadow/index.js +2 -2
- package/dist/share-link/index.js +1 -1
- package/dist/signer-Q7XQBMPA.js +25 -0
- package/dist/snapshots/index.js +10 -10
- package/dist/snapshots/index.js.map +1 -1
- package/dist/{stale-ZWXSOWJI.js → stale-NI7SAXAZ.js} +10 -10
- package/dist/storage-3VNGSHXS.js +23 -0
- package/dist/{store-coordination-provider-PB6QZ57W.js → store-coordination-provider-TYKNR3OU.js} +18 -12
- package/dist/store-coordination-provider-TYKNR3OU.js.map +1 -0
- package/dist/sync/index.js +11 -11
- package/dist/team/index.js +15 -14
- package/dist/tiers/index.js +11 -10
- package/dist/to/index.js +17 -9
- package/dist/to/index.js.map +1 -1
- package/dist/transactions/index.js +4 -4
- package/dist/{ulid-PTAIMDG4.js → ulid-VQW6ERQN.js} +2 -2
- package/dist/util/index.js +1 -1
- package/dist/vault-head/index.js +115 -0
- package/dist/vault-head/index.js.map +1 -0
- package/dist/{verify-RO5RTZOJ.js → verify-6J2YLKSO.js} +5 -5
- package/dist/via/lookup/handle.d.ts +4 -1
- package/dist/via/money/exact.d.ts +44 -0
- package/dist/via/money/index.d.ts +2 -0
- package/dist/via/money/normalize.d.ts +20 -0
- package/dist/walk-WRA7RAPY.js +21 -0
- package/dist/with-audit/guards/immutable-guard.d.ts +14 -0
- package/dist/with-audit/periods/active.d.ts +28 -1
- package/dist/with-audit/periods/index.d.ts +4 -2
- package/dist/with-audit/periods/periods.d.ts +161 -6
- package/dist/with-audit/periods/strategy.d.ts +14 -5
- package/dist/with-audit/periods/vault-facade.d.ts +89 -10
- package/dist/with-audit/periods/window.d.ts +10 -0
- package/dist/with-audit/sealed-record/index.d.ts +13 -0
- package/dist/with-audit/tiers/index.d.ts +17 -2
- package/dist/with-cargo/adopt-partition.d.ts +1 -1
- package/dist/with-cargo/extract-partition.d.ts +1 -1
- package/dist/with-cargo/index.d.ts +2 -2
- package/dist/with-commit/history/history.d.ts +26 -0
- package/dist/with-commit/history/index.d.ts +2 -1
- package/dist/with-commit/history/ledger/store.d.ts +7 -1
- package/dist/with-commit/history/strategy.d.ts +11 -1
- package/dist/with-commit/numbering/index.d.ts +0 -5
- package/dist/with-commit/vault-head/active.d.ts +2 -0
- package/dist/with-commit/vault-head/head.d.ts +28 -0
- package/dist/with-commit/vault-head/index.d.ts +10 -0
- package/dist/with-commit/vault-head/strategy.d.ts +127 -0
- package/dist/with-commit/vault-head/verify.d.ts +90 -0
- package/dist/with-formula/materialized-views/types.d.ts +52 -0
- package/dist/with-party/directory/cover/storage.d.ts +0 -8
- package/dist/with-party/directory/storage.d.ts +0 -11
- package/dist/with-party/directory/visibility.d.ts +0 -21
- package/dist/with-party/policy/storage.d.ts +0 -10
- package/dist/with-party/team/index.d.ts +1 -1
- package/dist/with-party/team/keyring.d.ts +149 -3
- package/dist/with-party/team/noydb-facade.d.ts +5 -1
- package/dist/with-party/team/roster-tag.d.ts +101 -0
- package/dist/with-party/team/tiers.d.ts +2 -1
- package/dist/with-pod/format.d.ts +10 -12
- package/dist/with-pod/index.d.ts +10 -10
- package/dist/with-pod/open.d.ts +2 -2
- package/dist/with-pod/pod-handle.d.ts +19 -0
- package/dist/with-pod/pod-store.d.ts +0 -8
- package/dist/with-pod/{bundle.d.ts → pod.d.ts} +26 -19
- package/dist/with-pod/ulid.d.ts +1 -1
- package/dist/with-shape/blobs/blob-set.d.ts +2 -2
- package/dist/with-shape/introspection/index.d.ts +1 -0
- package/dist/with-sync/engine.d.ts +54 -5
- package/dist/with-sync/strategy.d.ts +3 -0
- package/dist/withdraw-accessible-4JTDFRFZ.js +28 -0
- package/package.json +13 -5
- package/dist/api-WVY3H3YH.js +0 -20
- package/dist/backup-YYBE5RPC.js.map +0 -1
- package/dist/bundle-handle-JEUWU2SJ.js +0 -36
- package/dist/bundle-handle-JEUWU2SJ.js.map +0 -1
- package/dist/chunk-26JMGSSC.js.map +0 -1
- package/dist/chunk-3737A6EA.js.map +0 -1
- package/dist/chunk-4MC5JRRX.js.map +0 -1
- package/dist/chunk-52QYGZHH.js.map +0 -1
- package/dist/chunk-55LKVALY.js.map +0 -1
- package/dist/chunk-5PR33AC4.js.map +0 -1
- package/dist/chunk-66W5OOCX.js.map +0 -1
- package/dist/chunk-7G6VDWXB.js.map +0 -1
- package/dist/chunk-A67356IR.js.map +0 -1
- package/dist/chunk-AFHQATY4.js +0 -47
- package/dist/chunk-AFHQATY4.js.map +0 -1
- package/dist/chunk-AHLJSVRL.js.map +0 -1
- package/dist/chunk-C2OOEM57.js.map +0 -1
- package/dist/chunk-DIMKRG2E.js +0 -131
- package/dist/chunk-DIMKRG2E.js.map +0 -1
- package/dist/chunk-E6427JU2.js.map +0 -1
- package/dist/chunk-E7OBCBXS.js.map +0 -1
- package/dist/chunk-EDXAQ6JI.js.map +0 -1
- package/dist/chunk-EP7VPR7Y.js.map +0 -1
- package/dist/chunk-ERB6NDDW.js.map +0 -1
- package/dist/chunk-G5APARUV.js.map +0 -1
- package/dist/chunk-GASWQ3XG.js.map +0 -1
- package/dist/chunk-GLKDWWNO.js.map +0 -1
- package/dist/chunk-HNGSV2YC.js.map +0 -1
- package/dist/chunk-I4F6PKUK.js.map +0 -1
- package/dist/chunk-I4ZAO7F7.js.map +0 -1
- package/dist/chunk-I6SDX7WX.js.map +0 -1
- package/dist/chunk-JXIDGFKS.js.map +0 -1
- package/dist/chunk-LWSJG3LI.js.map +0 -1
- package/dist/chunk-MWKDOHEF.js.map +0 -1
- package/dist/chunk-MZ5ZFO2D.js.map +0 -1
- package/dist/chunk-NIVEDYJZ.js.map +0 -1
- package/dist/chunk-NWCGDAV6.js +0 -45
- package/dist/chunk-NWCGDAV6.js.map +0 -1
- package/dist/chunk-PJNTR2NV.js.map +0 -1
- package/dist/chunk-PRDRGL73.js.map +0 -1
- package/dist/chunk-PY7CI6L5.js.map +0 -1
- package/dist/chunk-RKKORO4M.js.map +0 -1
- package/dist/chunk-TAGFGKHP.js.map +0 -1
- package/dist/chunk-TDJPS3T2.js.map +0 -1
- package/dist/chunk-TOAIYQJR.js.map +0 -1
- package/dist/chunk-UHXCLPGC.js.map +0 -1
- package/dist/chunk-UIBGXRDD.js.map +0 -1
- package/dist/chunk-V5KYPBUR.js.map +0 -1
- package/dist/chunk-VCETL77O.js.map +0 -1
- package/dist/chunk-VN45YLWM.js.map +0 -1
- package/dist/chunk-VOQW5LAM.js.map +0 -1
- package/dist/chunk-VRA4Q7DA.js.map +0 -1
- package/dist/chunk-VV4NSB7P.js.map +0 -1
- package/dist/chunk-W5W6KHN2.js.map +0 -1
- package/dist/chunk-WHJKIZS7.js.map +0 -1
- package/dist/chunk-WYZ5MYUA.js.map +0 -1
- package/dist/chunk-ZJADGNYF.js.map +0 -1
- package/dist/chunk-ZNACADFG.js.map +0 -1
- package/dist/collection-facade-QN5ULWYC.js +0 -45
- package/dist/delegation-SSEPLXXO.js.map +0 -1
- package/dist/derive-6V3PIZF7.js +0 -22
- package/dist/executor-CYJQLKKI.js +0 -9
- package/dist/executor-FHHLXO4Y.js +0 -28
- package/dist/executor-S4QIKEHW.js +0 -9
- package/dist/export-accessible-PE5AYKZR.js +0 -23
- package/dist/extract-partition-X2L26O6A.js +0 -38
- package/dist/fanout-sidecar-DTBIDOWF.js.map +0 -1
- package/dist/find-RBBYKXI7.js +0 -11
- package/dist/issue-RNU55YOF.js +0 -19
- package/dist/liberate-PX4CAT5V.js +0 -24
- package/dist/noydb-YPSEGK32.js +0 -83
- package/dist/register-TMD6YRCX.js +0 -32
- package/dist/registry-CZVINVQH.js +0 -9
- package/dist/registry-FVLDWQKT.js +0 -18
- package/dist/registry-IKUR2MXD.js +0 -9
- package/dist/registry-JET4HBLY.js +0 -19
- package/dist/request-withdrawal-RH55LNZL.js +0 -31
- package/dist/revoke-R5TBYVA6.js +0 -24
- package/dist/seed-UK4QRIUN.js.map +0 -1
- package/dist/signer-AGALOXOO.js +0 -25
- package/dist/storage-N7LB275C.js +0 -23
- package/dist/store-coordination-provider-PB6QZ57W.js.map +0 -1
- package/dist/walk-OCUHCYJ6.js +0 -21
- package/dist/with-pod/bundle-handle.d.ts +0 -9
- package/dist/withdraw-accessible-QQNWM5BO.js +0 -28
- /package/dist/{api-WVY3H3YH.js.map → api-EYNT6KGS.js.map} +0 -0
- /package/dist/{chunk-35EBKWQU.js.map → chunk-2LFOMUEA.js.map} +0 -0
- /package/dist/{chunk-OF3L2SD6.js.map → chunk-32B7VCKU.js.map} +0 -0
- /package/dist/{chunk-MSWYQLMQ.js.map → chunk-3B6S6RSI.js.map} +0 -0
- /package/dist/{chunk-7F4DBNSP.js.map → chunk-3O72ZD2E.js.map} +0 -0
- /package/dist/{chunk-FNSMZQS4.js.map → chunk-3PMFMUFX.js.map} +0 -0
- /package/dist/{chunk-FAXZQ5UF.js.map → chunk-4RAS6HN6.js.map} +0 -0
- /package/dist/{chunk-VMCCGUQB.js.map → chunk-6JPGVL7X.js.map} +0 -0
- /package/dist/{chunk-WLYIROCJ.js.map → chunk-6YD5SYQS.js.map} +0 -0
- /package/dist/{chunk-YAWK6AWF.js.map → chunk-7KAE7CQ2.js.map} +0 -0
- /package/dist/{chunk-NKH7GSIH.js.map → chunk-AUPSEJ7O.js.map} +0 -0
- /package/dist/{chunk-CCZJJ4I2.js.map → chunk-B6IYATME.js.map} +0 -0
- /package/dist/{chunk-4UVDI4XE.js.map → chunk-CLAHBPOI.js.map} +0 -0
- /package/dist/{chunk-HVQGCKY4.js.map → chunk-D3R7Q4QK.js.map} +0 -0
- /package/dist/{chunk-P7OG2ETF.js.map → chunk-DXKLLKME.js.map} +0 -0
- /package/dist/{chunk-JIUVJ4M7.js.map → chunk-EKEIEJL6.js.map} +0 -0
- /package/dist/{chunk-DG27IUVI.js.map → chunk-FS7NTGCJ.js.map} +0 -0
- /package/dist/{chunk-HXGUIPQB.js.map → chunk-GQXFOAYZ.js.map} +0 -0
- /package/dist/{chunk-BTVYJWSN.js.map → chunk-GTHVPVAR.js.map} +0 -0
- /package/dist/{chunk-DMQCLZ4Z.js.map → chunk-GWO2IDAB.js.map} +0 -0
- /package/dist/{chunk-6HFM7EIT.js.map → chunk-H3G4I3PN.js.map} +0 -0
- /package/dist/{chunk-VJFMXYKP.js.map → chunk-HR5R5JOM.js.map} +0 -0
- /package/dist/{chunk-FDX7OWWI.js.map → chunk-HYYVT2KZ.js.map} +0 -0
- /package/dist/{chunk-JRCYZEHU.js.map → chunk-I6QKB7MT.js.map} +0 -0
- /package/dist/{chunk-KUDZVJKQ.js.map → chunk-IJ46VCWD.js.map} +0 -0
- /package/dist/{chunk-4HDYQL3J.js.map → chunk-INMHEMXX.js.map} +0 -0
- /package/dist/{chunk-AR2JDFAE.js.map → chunk-KV6JM2IA.js.map} +0 -0
- /package/dist/{chunk-PVU7LW5L.js.map → chunk-KX57HODD.js.map} +0 -0
- /package/dist/{chunk-CEJWMBXO.js.map → chunk-LXECF2ZR.js.map} +0 -0
- /package/dist/{chunk-7VHY5E3X.js.map → chunk-MSLPDFK2.js.map} +0 -0
- /package/dist/{chunk-HNHCQ556.js.map → chunk-NR2SUJ3H.js.map} +0 -0
- /package/dist/{chunk-W3TVWF6N.js.map → chunk-OIBEJN5H.js.map} +0 -0
- /package/dist/{chunk-QD724WDJ.js.map → chunk-OMYCSTXL.js.map} +0 -0
- /package/dist/{chunk-Z45YRGFO.js.map → chunk-ONVD6GBY.js.map} +0 -0
- /package/dist/{chunk-KCQX65FU.js.map → chunk-RKCRPPNB.js.map} +0 -0
- /package/dist/{chunk-7TSYBD3E.js.map → chunk-RSXQNFGO.js.map} +0 -0
- /package/dist/{chunk-7NXHMW6Y.js.map → chunk-SYS46BL7.js.map} +0 -0
- /package/dist/{chunk-747LRSOO.js.map → chunk-TMBSPLUG.js.map} +0 -0
- /package/dist/{chunk-WKPJXWKR.js.map → chunk-TX5MKAHA.js.map} +0 -0
- /package/dist/{chunk-NJDQ4YSV.js.map → chunk-YKXZHUOW.js.map} +0 -0
- /package/dist/{chunk-VW6ZZGCG.js.map → chunk-ZLHHE5XZ.js.map} +0 -0
- /package/dist/{chunk-FUHKW252.js.map → chunk-ZZXLB6AS.js.map} +0 -0
- /package/dist/{classified-marker-FTOX7Q5L.js.map → classified-marker-NA6HUV33.js.map} +0 -0
- /package/dist/{collection-facade-QN5ULWYC.js.map → collection-facade-VBM35WAH.js.map} +0 -0
- /package/dist/{computed-6G5M3UPH.js.map → computed-GSTLWSY5.js.map} +0 -0
- /package/dist/{dead-filter-ENRIOQIE.js.map → dead-filter-UALP5DJX.js.map} +0 -0
- /package/dist/{derive-6V3PIZF7.js.map → derive-YUO3TQYN.js.map} +0 -0
- /package/dist/{dispatch-RE74SH6L.js.map → dispatch-4ZHLSFZQ.js.map} +0 -0
- /package/dist/{dispatch-BDVGYC6X.js.map → dispatch-77CB75KB.js.map} +0 -0
- /package/dist/{enclave-52VUXNRL.js.map → enclave-O4NOROCJ.js.map} +0 -0
- /package/dist/{executor-CYJQLKKI.js.map → executor-CZDXBXKE.js.map} +0 -0
- /package/dist/{executor-FHHLXO4Y.js.map → executor-DVJAWN3B.js.map} +0 -0
- /package/dist/{executor-S4QIKEHW.js.map → executor-VRLG4TQJ.js.map} +0 -0
- /package/dist/{export-accessible-PE5AYKZR.js.map → export-accessible-UXSMG7AB.js.map} +0 -0
- /package/dist/{extract-partition-X2L26O6A.js.map → extract-partition-TVY7AMKH.js.map} +0 -0
- /package/dist/{find-RBBYKXI7.js.map → find-WSARMJBW.js.map} +0 -0
- /package/dist/{issue-RNU55YOF.js.map → issue-3JNJNPT3.js.map} +0 -0
- /package/dist/{ledger-4WJL66BW.js.map → ledger-MVPNG5OS.js.map} +0 -0
- /package/dist/{liberate-PX4CAT5V.js.map → liberate-4LOJOLDT.js.map} +0 -0
- /package/dist/{link-set-N4ZPV6E6.js.map → link-set-3POMQR3I.js.map} +0 -0
- /package/dist/{managed-secret-OTHS64IF.js.map → managed-secret-IARIJJ7Q.js.map} +0 -0
- /package/dist/{noydb-YPSEGK32.js.map → noydb-IRILUDED.js.map} +0 -0
- /package/dist/{post-register-ZAG2CAIY.js.map → post-register-Z5T7FY45.js.map} +0 -0
- /package/dist/{register-TMD6YRCX.js.map → register-UZ37QPDB.js.map} +0 -0
- /package/dist/{registry-CZVINVQH.js.map → registry-ETJNA7PO.js.map} +0 -0
- /package/dist/{registry-FVLDWQKT.js.map → registry-F7U6KSLX.js.map} +0 -0
- /package/dist/{registry-IKUR2MXD.js.map → registry-L4ELKX6C.js.map} +0 -0
- /package/dist/{registry-JET4HBLY.js.map → registry-SDT5LIGO.js.map} +0 -0
- /package/dist/{request-withdrawal-RH55LNZL.js.map → request-withdrawal-PVFEYX57.js.map} +0 -0
- /package/dist/{reveal-CMOJY4VO.js.map → reveal-DQ2E3QAZ.js.map} +0 -0
- /package/dist/{revoke-R5TBYVA6.js.map → revoke-YXY6SHUH.js.map} +0 -0
- /package/dist/{signer-AGALOXOO.js.map → signer-Q7XQBMPA.js.map} +0 -0
- /package/dist/{stale-ZWXSOWJI.js.map → stale-NI7SAXAZ.js.map} +0 -0
- /package/dist/{storage-N7LB275C.js.map → storage-3VNGSHXS.js.map} +0 -0
- /package/dist/{ulid-PTAIMDG4.js.map → ulid-VQW6ERQN.js.map} +0 -0
- /package/dist/{verify-RO5RTZOJ.js.map → verify-6J2YLKSO.js.map} +0 -0
- /package/dist/{walk-OCUHCYJ6.js.map → walk-WRA7RAPY.js.map} +0 -0
- /package/dist/{withdraw-accessible-QQNWM5BO.js.map → withdraw-accessible-4JTDFRFZ.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/kernel/enclave/record-keys/lifecycle.ts","../src/kernel/enclave/record-keys/sealed-slots.ts","../src/kernel/enclave/classify/write.ts","../src/kernel/schema.ts","../src/kernel/enclave/record-keys/record-codec.ts","../src/kernel/enclave/record-keys/sealing.ts","../src/kernel/enclave/record-keys/deterministic.ts","../src/kernel/enclave/record-keys/envelope-body.ts","../src/kernel/enclave/broker/proof.ts"],"sourcesContent":["/**\n * Per-record CEK lifecycle helpers for the WRITE path.\n *\n * These are the collection-coupled CEK operations, lifted off `Collection`\n * behind narrow deps so the kernel file delegates instead of carrying the\n * crypto inline:\n *\n * - {@link resolveStableCek} — the stable-CEK rule: an update or history\n * snapshot reuses the record's existing CEK so a single CEK delete kills\n * the whole version chain; a genuine insert (or legacy record being\n * migrated) mints a fresh one.\n * - {@link rewrapBodyToDek} — move a record body's wrapping from one DEK to\n * another (tier elevate/demote, bundle re-key) WITHOUT changing the body\n * key: unwrap the CEK under the source DEK, re-encrypt the body under the\n * same CEK, re-wrap the CEK under the destination DEK. History-chain\n * identity is preserved because the body key never changes.\n *\n * Both are pure functions over their deps — the `cekCache` ownership stays on\n * the collection (its lifetime is tied to `load()`), so callers cache the\n * returned key themselves.\n */\nimport { encrypt, decrypt, generateDEK, wrapCek, unwrapCek, type EnclaveKey } from '../crypto.js'\nimport type { EncryptedEnvelope } from '../../types.js'\nimport type { Lru } from '../../cache/index.js'\n\n/** Dependencies {@link resolveStableCek} needs from its collection. */\nexport interface StableCekDeps {\n /** The collection's per-record CEK cache (`null` → no caching). */\n readonly cache: Lru<string, EnclaveKey> | null\n /** Read the record's live envelope (to recover an existing `_cek`). */\n getLive(id: string): Promise<EncryptedEnvelope | null>\n /** The DEK the CEK is wrapped under (the collection DEK on the normal path). */\n getDEK(): Promise<EnclaveKey>\n}\n\n/**\n * Resolve the stable CEK for a record on the write path. Caches the resolved\n * key under `id` so an update + its history snapshot share one CEK.\n */\nexport async function resolveStableCek(deps: StableCekDeps, id: string): Promise<EnclaveKey> {\n const cached = deps.cache?.get(id)\n if (cached) return cached\n\n const live = await deps.getLive(id)\n if (live?._cek !== undefined) {\n const cek = await unwrapCek(live._cek, await deps.getDEK())\n deps.cache?.set(id, cek, 1)\n return cek\n }\n\n const fresh = await generateDEK()\n deps.cache?.set(id, fresh, 1)\n return fresh\n}\n\n/** Re-wrapped body bytes + the (optional) CEK to cache. */\nexport interface RewrappedBody {\n readonly _iv: string\n readonly _data: string\n /** Present iff the source envelope carried a CEK (per-record-key record). */\n readonly _cek?: string\n /** The body key when one exists, so the caller can cache it; `null` for a legacy record. */\n readonly cek: EnclaveKey | null\n}\n\n/**\n * Move a record body from `fromDek` to `toDek`.\n *\n * - Per-record-key record (`_cek` present): unwrap the CEK under `fromDek`,\n * re-encrypt the body under the SAME CEK, re-wrap the CEK under `toDek`. The\n * body key is unchanged → history-chain identity preserved.\n * - Legacy record (no `_cek`): decrypt under `fromDek`, re-encrypt under `toDek`\n * directly — byte-for-byte the pre-CEK behaviour.\n */\nexport async function rewrapBodyToDek(\n envelope: Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>,\n fromDek: EnclaveKey,\n toDek: EnclaveKey,\n): Promise<RewrappedBody> {\n if (envelope._cek !== undefined) {\n const cek = await unwrapCek(envelope._cek, fromDek)\n const plaintext = await decrypt(envelope._iv, envelope._data, cek)\n const { iv, data } = await encrypt(plaintext, cek)\n return { _iv: iv, _data: data, _cek: await wrapCek(cek, toDek), cek }\n }\n const plaintext = await decrypt(envelope._iv, envelope._data, fromDek)\n const { iv, data } = await encrypt(plaintext, toDek)\n return { _iv: iv, _data: data, cek: null }\n}\n\n/**\n * Merge an ALREADY-rewrapped {@link RewrappedBody} into `envelope`, keeping\n * every field but the re-keyed body (`_iv`/`_data`/`_cek`) unchanged.\n *\n * Body-field access (`_iv`/`_data`/`_cek`) is sanctioned inside the enclave;\n * this lets callers outside it get back a ready-to-store envelope without\n * reading those fields themselves. Takes a body the caller has ALREADY\n * computed (vs. {@link rewrapEnvelope}, which also runs `rewrapBodyToDek`)\n * so a caller building a SECOND envelope from the same rewrap — a tier\n * move's live write AND its pre-move `_history` snapshot, #728 — pays the\n * unwrap/decrypt/encrypt/wrap crypto once, not twice.\n */\nexport function applyRewrappedBody(envelope: EncryptedEnvelope, body: RewrappedBody): EncryptedEnvelope {\n const next: EncryptedEnvelope = {\n ...envelope,\n _iv: body._iv,\n _data: body._data,\n ...(body._cek !== undefined ? { _cek: body._cek } : {}),\n }\n if (body._cek === undefined && envelope._cek !== undefined) {\n delete (next as { _cek?: string })._cek\n }\n return next\n}\n\n/**\n * Move a FULL stored envelope from `fromDek` to `toDek`, preserving every\n * field other than the re-keyed body (`_iv`/`_data`/`_cek`) unchanged.\n * Mirrors the spread-merge idiom `with-audit/tiers/index.ts`'s\n * `elevate()`/`demote()` use to apply `rewrapBodyToDek`'s result to the live\n * envelope, generalized to any envelope shape (history callers don't bump\n * `_v`/`_ts`/`_tier` the way a tier move does).\n */\nexport async function rewrapEnvelope(\n envelope: EncryptedEnvelope,\n fromDek: EnclaveKey,\n toDek: EnclaveKey,\n): Promise<EncryptedEnvelope> {\n return applyRewrappedBody(envelope, await rewrapBodyToDek(envelope, fromDek, toDek))\n}\n\n/**\n * Is `envelope` ALREADY wrapped under `dek` (a per-record CEK wrapped under\n * `dek`, or — legacy, no `_cek` — the body itself decryptable under `dek`)?\n *\n * A toDek-first idempotency check for retry-safe rewrap loops (#712 crash\n * atomicity, `with-commit/history/history.ts`'s `rewrapHistory`): a crash\n * mid-rewrap can strand some entries already moved to `toDek` while others\n * remain under `fromDek`. Calling this with `toDek` before attempting the\n * `fromDek` rewrap lets the caller skip an already-migrated entry instead of\n * re-wrapping it (a re-wrap would be a correctness no-op but doubles as an\n * unnecessary write) — and, more importantly, tells a retry loop that this\n * entry needs no `fromDek` unwrap attempt at all, so a crash that landed some\n * entries under `toDek` doesn't wedge on those already-moved entries.\n *\n * AES-KW (CEK unwrap) and AES-GCM (direct decrypt) are both authenticated —\n * unwrap/decrypt under the wrong key throws, never silently returns garbage\n * — so a caught error here reliably means \"not wrapped under `dek`\", not a\n * corrupt envelope (a genuinely corrupt envelope also throws under the\n * correct key, but callers that reach this helper only do so as a\n * best-effort probe before their own decisive fromDek attempt, which still\n * surfaces real corruption).\n *\n * Body-field access (`_iv`/`_data`/`_cek`) is sanctioned inside the enclave —\n * this is the sanctioned door so callers outside it (history.ts) never read\n * those fields themselves, preserving the check-architecture body-access\n * ratchet.\n */\nexport async function isRewrappedUnder(\n envelope: Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>,\n dek: EnclaveKey,\n): Promise<boolean> {\n try {\n if (envelope._cek !== undefined) {\n await unwrapCek(envelope._cek, dek)\n } else {\n await decrypt(envelope._iv, envelope._data, dek)\n }\n return true\n } catch {\n return false\n }\n}\n","/**\n * Sealed-slot sub-step — the \"seal these declared fields into their own\n * `iv:data` slots\" mechanism, extracted byte-parity from `RecordCodec`\n * (#629 Task 1; see `.superpowers/sdd/seam-map-classified-blobs.md` §2).\n *\n * This is the ONE genuinely separable sub-step `RecordCodec.encryptRecord`/\n * `decryptRecord` perform (the digest-only `_vdig`/`_bidx` mechanism is NOT\n * separable the same way — it needs write-history `prev` context, see the\n * seam map's separability verdict). `sealFields`/`unsealFields` are the\n * natural shape of a `via` `encodeAtRest`/`decodeAtRest` hook for a \"seal\n * this field\" via-feature, and `makeSealedSlotCapability`/\n * `makeReservedEnvelopes` (below) are the `ViaCryptoCtx` capability\n * factories built on top of them.\n *\n * The capability factories live here (rather than a sibling\n * `kernel/via-crypto.ts`) so they can call `deriveSealedFieldKey`/\n * `deriveSealedFieldKeyFromCek`/`encrypt`/`decrypt` directly — this file IS\n * kernel enclave code (C3), so it is exempt from `enclave-barrel-only` the\n * same way `record-codec.ts`/`sealing.ts` are. A file outside\n * `kernel/enclave/**` would have had to go through the enclave barrel\n * (`kernel/enclave/index.ts`), which does not (yet) export these symbols.\n */\nimport { encrypt, decrypt, deriveSealedFieldKey, deriveSealedFieldKeyFromCek, type EnclaveKey } from '../crypto.js'\nimport { dualReadSealedSlot } from './sealed-slot.js'\nimport { NOYDB_FORMAT_VERSION, SealedHandle, type EncryptedEnvelope } from '../../types.js'\nimport { ValidationError } from '../../errors.js'\nimport type { SealedSlotRef, ViaCryptoCtx } from '../../via/index.js'\n\n/**\n * Key material for one collection's sealed-field derivation. `cek`, when\n * supplied, is preferred (record-scoped); `getDEK` is the fallback (and,\n * for legacy/no-CEK collections, the only key) — mirrors the dual-read\n * `RecordCodec` has always done.\n */\nexport interface SealKeyMaterial {\n readonly collection: string\n readonly cek?: EnclaveKey\n getDEK(): Promise<EnclaveKey>\n}\n\nexport interface SealFieldsResult {\n readonly openRecord: Record<string, unknown>\n readonly sealed: Record<string, string> | undefined\n}\n\n/** Seal one field's value to an `iv:data` slot under its derived per-field key. */\nasync function sealOneFieldWithDek(\n field: string,\n value: unknown,\n dek: EnclaveKey,\n keyMaterial: SealKeyMaterial,\n): Promise<SealedSlotRef> {\n const fieldKey = keyMaterial.cek !== undefined\n ? await deriveSealedFieldKeyFromCek(keyMaterial.cek, keyMaterial.collection, field)\n : await deriveSealedFieldKey(dek, keyMaterial.collection, field)\n return encrypt(JSON.stringify(value), fieldKey)\n}\n\n/**\n * Seal one field's value on demand — fetches the DEK itself. A singular\n * counterpart to {@link sealFields} for callers that seal one field at a\n * time rather than a whole record. Not exported — `makeSealedSlotCapability`\n * is the only caller (#629 Task 11: knip-flagged unused export, dropped;\n * intra-module use only).\n */\nasync function sealOneField(\n field: string,\n value: unknown,\n keyMaterial: SealKeyMaterial,\n): Promise<SealedSlotRef> {\n const dek = await keyMaterial.getDEK()\n return sealOneFieldWithDek(field, value, dek, keyMaterial)\n}\n\n/**\n * Peel declared `sensitiveFields` out of `record` BEFORE building `_data`,\n * sealing each into its own `iv:data` slot. Extracted byte-parity from\n * `RecordCodec.encryptRecord` step 2 (pre-#629 `record-codec.ts:261-288`).\n * Returns `record` untouched (and `sealed: undefined`) when no declared\n * field is present with a defined value — the envelope stays byte-identical\n * to legacy output, exactly as before.\n */\nexport async function sealFields(\n record: Record<string, unknown>,\n sensitiveFields: ReadonlySet<string>,\n keyMaterial: SealKeyMaterial,\n): Promise<SealFieldsResult> {\n const dek = await keyMaterial.getDEK()\n const open: Record<string, unknown> = { ...record }\n const slots: Record<string, string> = {}\n for (const field of sensitiveFields) {\n if (!(field in record)) continue\n const value = record[field]\n if (value === undefined) continue\n const { iv, data } = await sealOneFieldWithDek(field, value, dek, keyMaterial)\n slots[field] = `${iv}:${data}`\n delete open[field]\n }\n if (Object.keys(slots).length === 0) return { openRecord: record, sealed: undefined }\n return { openRecord: open, sealed: slots }\n}\n\n/**\n * Unseal one `_sealed[field]` slot to its plaintext value: dual-read (try\n * the CEK-derived key, fall back to the DEK-derived key for legacy\n * records), AES-GCM-decrypt the `iv:data` blob, and JSON-parse the result.\n * Extracted byte-parity from `RecordCodec.unsealField`\n * (pre-#629 `record-codec.ts:485-493`).\n */\nexport async function unsealOneField(field: string, blob: string, keyMaterial: SealKeyMaterial): Promise<unknown> {\n const dek = await keyMaterial.getDEK()\n return JSON.parse(await dualReadSealedSlot(blob, field, keyMaterial.collection, keyMaterial.cek, dek))\n}\n\n/**\n * Build a non-leaking {@link SealedHandle} producer over sealed key\n * material: each call captures only the ciphertext `blob` and a closure to\n * {@link unsealOneField} — the plaintext is never stored on the handle, and\n * (crucially) the DEK is fetched lazily on `reveal()`, never at handle-\n * construction time. Extracted byte-parity from\n * `RecordCodec.makeSealedHandle` (pre-#629 `record-codec.ts:552-554`).\n */\nexport function makeHandleProducer(keyMaterial: SealKeyMaterial): (field: string, blob: string) => SealedHandle<unknown> {\n return (field, blob) => new SealedHandle(() => unsealOneField(field, blob, keyMaterial))\n}\n\n/**\n * Restore every `[field]: blob` entry in `sealed` onto `record` (mutated in\n * place, matching the original's mutate-then-return shape): eagerly unseal\n * to plaintext (`opts.asHandles` falsy) or wrap each in a\n * {@link SealedHandle} (`opts.asHandles: true`) so the plaintext is never\n * materialised. Extracted byte-parity from `RecordCodec.decryptRecord`'s\n * sealed-handle block (pre-#629 `record-codec.ts:615-623`).\n */\nexport async function unsealFields(\n record: Record<string, unknown>,\n sealed: Record<string, string>,\n keyMaterial: SealKeyMaterial,\n opts?: { asHandles?: boolean },\n): Promise<Record<string, unknown>> {\n const makeHandle = opts?.asHandles === true ? makeHandleProducer(keyMaterial) : undefined\n for (const [field, blob] of Object.entries(sealed)) {\n record[field] = makeHandle !== undefined ? makeHandle(field, blob) : await unsealOneField(field, blob, keyMaterial)\n }\n return record\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ViaCryptoCtx capability factories (#629 Task 1, second commit)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** What {@link makeSealedSlotCapability} needs — a subset of `RecordCodecContext`. */\nexport interface SealedSlotCapabilityCtx {\n readonly name: string\n getDEK(): Promise<EnclaveKey>\n}\n\n/**\n * Build a `ViaCryptoCtx.sealedSlots` capability pre-bound to one\n * `(collection, recordId)`. The key material (`cek`/DEK resolver) is closed\n * over and never placed on the returned object — `Object.keys`/\n * `Object.values` of the capability expose only the three methods, never a\n * key (zero-knowledge: capabilities never expose keys).\n *\n * `delete(field)` is **advisory and capability-instance-local, not real\n * erasure** — it has no store to reach and never will by itself: it just\n * adds `field` to a `Set` closed over by THIS ONE capability object, so a\n * later `unseal` call on that SAME object refuses. No I/O happens. A fresh\n * capability for the same record (e.g. `seal()`'d again, or a new\n * `makeSealedSlotCapability(...)` call) has an empty set and sees no\n * deletion at all — `seal()` on a given field also clears any prior mark\n * for it. Do not build production logic on `delete()` persisting anything.\n * The real erasure guarantee for a forgotten record is `vault.forget()`'s\n * unconditional `_writeTombstone` call, which replaces the whole live\n * envelope with a fresh, `_sealed`-free tombstone — `_sealed` disappears\n * from the store regardless of what any capability's `delete()` marked.\n * (#629 Task 10 traced this end-to-end; see task-10-report.md \"sealedSlots\n * .delete()\" section. Removing/changing this method's shape is a phase-E\n * decision, not implied by this comment.)\n */\nexport function makeSealedSlotCapability(\n ctx: SealedSlotCapabilityCtx,\n recordId: string,\n cek?: EnclaveKey,\n): ViaCryptoCtx['sealedSlots'] {\n const keyMaterial: SealKeyMaterial = {\n collection: ctx.name,\n ...(cek !== undefined ? { cek } : {}),\n getDEK: () => ctx.getDEK(),\n }\n const deletedFields = new Set<string>()\n\n return {\n async seal(field, plaintext) {\n const ref = await sealOneField(field, plaintext, keyMaterial)\n deletedFields.delete(field)\n return ref\n },\n async unseal(field, ref) {\n if (deletedFields.has(field)) {\n throw new ValidationError(`sealedSlots.unseal: field \"${field}\" on record \"${recordId}\" was deleted from this capability`)\n }\n return unsealOneField(field, `${ref.iv}:${ref.data}`, keyMaterial)\n },\n async delete(field) {\n deletedFields.add(field)\n },\n }\n}\n\n/** Resolve the DEK for an arbitrary (possibly synthetic, e.g. `_dict_en`) collection name. */\nexport type ReservedEnvelopeDekResolver = (collection: string) => Promise<EnclaveKey>\n\n/**\n * Build a `ViaCryptoCtx.reservedEnvelopes` capability: a whole-envelope\n * encrypt/decrypt door scoped to collection names under a declared prefix\n * (e.g. `_dict_`) — the shape `via/i18n/dictionary.ts`'s\n * `DictionaryHandle` needs (seam map Part 3): build JSON → encrypt under a\n * DEK → wrap in an `EncryptedEnvelope`; decrypt → JSON text. No per-record\n * CEK — reserved envelopes are whole-DEK-encrypted, same as the dictionary\n * grandfather.\n *\n * `reservedEnvelopes(prefix)` throws `ValidationError` immediately when\n * `prefix` is not in `declaredPrefixes`; each `encrypt`/`decrypt` call\n * throws `ValidationError` when its `collection` argument does not start\n * with `prefix`.\n */\nexport function makeReservedEnvelopes(\n dekResolver: ReservedEnvelopeDekResolver,\n declaredPrefixes: readonly string[],\n): ViaCryptoCtx['reservedEnvelopes'] {\n const declared = new Set(declaredPrefixes)\n\n return (prefix: string) => {\n if (!declared.has(prefix)) {\n throw new ValidationError(`reservedEnvelopes: prefix \"${prefix}\" is not declared by this binding's reservedPrefixes`)\n }\n\n const assertPrefixed = (collection: string, method: 'encrypt' | 'decrypt'): void => {\n if (!collection.startsWith(prefix)) {\n throw new ValidationError(\n `reservedEnvelopes('${prefix}').${method}: collection \"${collection}\" does not start with \"${prefix}\"`,\n )\n }\n }\n\n const encryptForPrefix = async (collection: string, json: string, v: number): Promise<EncryptedEnvelope> => {\n assertPrefixed(collection, 'encrypt')\n const dek = await dekResolver(collection)\n const { iv, data } = await encrypt(json, dek)\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: v,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n }\n }\n\n const decryptForPrefix = async (collection: string, env: EncryptedEnvelope): Promise<string> => {\n assertPrefixed(collection, 'decrypt')\n const dek = await dekResolver(collection)\n return decrypt(env._iv, env._data, dek)\n }\n\n return { encrypt: encryptForPrefix, decrypt: decryptForPrefix }\n }\n}\n","/**\n * Digest-only write engine (C6 rotate branch + notLastN ring, spec §2/§4).\n * Called ONLY by RecordCodec.encryptRecord — both live inside the enclave.\n * @module\n */\nimport { generateSalt, bufferToBase64, base64ToBuffer, type EnclaveKey } from '../crypto.js'\nimport { pbkdf2VerifyDigest, VDIG_ITERATIONS } from './digest.js'\nimport { normalizeForVerify } from './normalize.js'\nimport { blindedEqual } from './compare.js'\nimport { sealVdigPayload, openVdigPayload, type VdigPayload, type VdigDigestEntry } from './vdig.js'\nimport { ClassifiedRotationError, TamperedError } from '../../errors.js'\nimport type { VdigFieldPolicy } from '../../types.js'\n\nexport async function mintVdigSlot(\n rawValue: string,\n policy: VdigFieldPolicy,\n prevBlob: string | undefined,\n cek: EnclaveKey,\n collection: string,\n recordId: string,\n field: string,\n): Promise<string> {\n const normalized = normalizeForVerify(policy.normalize, rawValue)\n\n let prev: VdigPayload | null = null\n if (prevBlob !== undefined) {\n try {\n prev = await openVdigPayload(prevBlob, cek, collection, recordId, field)\n } catch {\n // Any failure opening a prior _vdig slot (auth-tag mismatch, malformed\n // JSON, wrong AAD) is a tamper/false condition — normalize to\n // TamperedError so the write path never sees a distinct error shape.\n throw new TamperedError()\n }\n if (!Number.isInteger(prev.iter) || prev.iter < 1) {\n // A corrupted/tampered iter count would silently weaken (or break)\n // the reuse-check PBKDF2 pass — floor/validate before trusting it.\n throw new TamperedError()\n }\n }\n\n // notLastN reuse refusal: candidate vs cur + every ring entry, each a full\n // PBKDF2 at the payload's own iteration count (n × 600K is the documented\n // write-time cost ceiling, cap 8 — spec Q4).\n if (prev !== null && policy.notLastN > 0) {\n const history: readonly VdigDigestEntry[] = [prev.cur, ...(prev.ring ?? [])]\n for (const entry of history) {\n const digest = await pbkdf2VerifyDigest(normalized, base64ToBuffer(entry.salt), prev.iter)\n if (await blindedEqual(digest, base64ToBuffer(entry.hash))) {\n throw new ClassifiedRotationError(collection, field, 'password was used recently')\n }\n }\n }\n\n const salt = generateSalt()\n const hash = await pbkdf2VerifyDigest(normalized, salt, VDIG_ITERATIONS)\n const ring = prev !== null && policy.notLastN > 0\n ? [...(prev.ring ?? []), { salt: prev.cur.salt, hash: prev.cur.hash }].slice(-policy.notLastN)\n : undefined\n\n const payload: VdigPayload = {\n v: 1,\n alg: 'PBKDF2-SHA256',\n iter: VDIG_ITERATIONS,\n cur: { salt: bufferToBase64(salt), hash: bufferToBase64(hash), at: new Date().toISOString() },\n ...(ring !== undefined && ring.length > 0 ? { ring } : {}),\n }\n return sealVdigPayload(payload, cek, collection, recordId, field)\n}\n","/**\n * Standard Schema v1 integration.\n *\n * This file is the entry point for **schema validation**. Any\n * validator that implements the [Standard Schema v1\n * protocol](https://standardschema.dev) — Zod, Valibot, ArkType, Effect\n * Schema, etc. — can be attached to a `Collection` or `defineNoydbStore`\n * and will:\n *\n * 1. Validate the record BEFORE encryption on `put()` — bad data is\n * rejected at the store boundary with a rich issue list.\n * 2. Validate the record AFTER decryption on `get()`/`list()`/`query()`\n * — stored data that has drifted from the current schema throws\n * loudly instead of silently propagating garbage to the UI.\n *\n * ## Why vendor the types?\n *\n * Standard Schema is a protocol, not a library. The spec is <200 lines of\n * TypeScript and has no runtime. There's an official `@standard-schema/spec`\n * types package on npm, but pulling it in would add a dependency edge\n * purely for type definitions. Vendoring the minimal surface keeps\n * `@noy-db/core` at **zero runtime dependencies** and gives us freedom to\n * evolve the helpers without a version-lock on the spec package.\n *\n * If the spec changes in a breaking way (unlikely — it's frozen at v1),\n * we update this file and bump our minor.\n *\n * ## Why not just run `schema.parse(value)` directly?\n *\n * Because then we'd be locked to whichever validator happens to have\n * `.parse`. Standard Schema's `'~standard'.validate` contract is the same\n * across every implementation and includes a structured issues list,\n * which is much more useful than a thrown error for programmatic error\n * handling (e.g., rendering field-level messages in a Vue component).\n */\n\nimport { SchemaValidationError } from './errors.js'\n\n/**\n * The Standard Schema v1 protocol. A schema is any object that exposes a\n * `'~standard'` property with `version: 1` and a `validate` function.\n *\n * The type parameters are:\n * - `Input` — the type accepted by `validate` (what the user passes in)\n * - `Output` — the type produced by `validate` (what we store/return,\n * may differ from Input if the schema transforms or coerces)\n *\n * In most cases `Input === Output`, but validators that transform\n * (Zod's `.transform`, Valibot's `transform`, etc.) can narrow or widen.\n *\n * We intentionally keep the `types` field `readonly` and optional — the\n * spec marks it as optional because it's only used for inference, and\n * not every implementation bothers populating it at runtime.\n */\nexport interface StandardSchemaV1<Input = unknown, Output = Input> {\n readonly '~standard': {\n readonly version: 1\n readonly vendor: string\n readonly validate: (\n value: unknown,\n ) =>\n | StandardSchemaV1SyncResult<Output>\n | Promise<StandardSchemaV1SyncResult<Output>>\n readonly types?:\n | {\n readonly input: Input\n readonly output: Output\n }\n | undefined\n }\n}\n\n/**\n * The result of a single call to `schema['~standard'].validate`. Either\n * `{ value }` on success or `{ issues }` on failure — never both.\n *\n * The spec allows `issues` to be undefined on success (and some\n * validators leave it that way), so consumers should discriminate on\n * `issues?.length` rather than on truthiness of `value`.\n */\nexport type StandardSchemaV1SyncResult<Output> =\n | { readonly value: Output; readonly issues?: undefined }\n | {\n readonly value?: undefined\n readonly issues: readonly StandardSchemaV1Issue[]\n }\n\n/**\n * A single validation issue. The `message` is always present; the `path`\n * is optional and points at the offending field when the schema tracks\n * it (virtually every validator does for object types).\n *\n * The path is deliberately permissive — both a plain `PropertyKey` and a\n * `{ key }` wrapper are allowed so validators that wrap path segments in\n * objects (Zod does this in some modes) don't need special handling.\n */\nexport interface StandardSchemaV1Issue {\n readonly message: string\n readonly path?:\n | ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>\n | undefined\n}\n\n/**\n * Infer the output type of a Standard Schema. Consumers use this to\n * pull the type out of a schema instance when they want to declare a\n * Collection<T> or defineNoydbStore<T> with `T` derived from the schema.\n *\n * Example:\n * ```ts\n * const InvoiceSchema = z.object({ id: z.string(), amount: z.number() })\n * type Invoice = InferOutput<typeof InvoiceSchema>\n * ```\n */\nexport type InferOutput<T extends StandardSchemaV1> =\n T extends StandardSchemaV1<unknown, infer O> ? O : never\n\n/**\n * Validate an input value against a schema. Throws\n * `SchemaValidationError` if the schema rejects, with the rich issue\n * list attached. Otherwise returns the (possibly transformed) output\n * value.\n *\n * The `context` string is included in the thrown error's message so the\n * caller knows where the failure happened (e.g. `\"put(inv-001)\"`) without\n * every caller having to wrap the throw in a try/catch.\n *\n * This function is ALWAYS async because some validators (notably Effect\n * Schema and Zod's `.refine` with async predicates) can return a\n * Promise. We `await` the result unconditionally to normalize the\n * contract — the extra microtask is free compared to the cost of an\n * encrypt/decrypt round-trip.\n */\nexport async function validateSchemaInput<Output>(\n schema: StandardSchemaV1<unknown, Output>,\n value: unknown,\n context: string,\n): Promise<Output> {\n const result = await schema['~standard'].validate(value)\n if (result.issues !== undefined && result.issues.length > 0) {\n throw new SchemaValidationError(\n `Schema validation failed on ${context}: ${summarizeIssues(result.issues)}`,\n result.issues,\n 'input',\n )\n }\n // Safe: the spec guarantees `value` is present when `issues` is absent.\n return result.value as Output\n}\n\n/**\n * Validate an already-stored value coming OUT of the collection. This\n * is a distinct helper from `validateSchemaInput` because the error\n * semantics differ: an output-validation failure means the data in\n * storage has drifted from the current schema (an unexpected state),\n * whereas an input-validation failure means the user passed bad data\n * (an expected state for a UI that isn't guarding its inputs).\n *\n * We still throw — silently returning bad data would be worse — but\n * the error carries `direction: 'output'` so upstream code (and a\n * potential migrate hook) can distinguish the two cases.\n */\nexport async function validateSchemaOutput<Output>(\n schema: StandardSchemaV1<unknown, Output>,\n value: unknown,\n context: string,\n): Promise<Output> {\n const result = await schema['~standard'].validate(value)\n if (result.issues !== undefined && result.issues.length > 0) {\n throw new SchemaValidationError(\n `Stored data for ${context} does not match the current schema — ` +\n `schema drift? ${summarizeIssues(result.issues)}`,\n result.issues,\n 'output',\n )\n }\n return result.value as Output\n}\n\n/**\n * Produce a short human-readable summary of an issue list for the\n * thrown error's message. The full issue array is still attached to the\n * error as a property — this is only for the `.message` string that\n * shows up in console.error / stack traces.\n *\n * Format: `field: message; field2: message2` (up to 3 issues, then `…`).\n * Issues without a path are shown as `root: message`.\n */\nfunction summarizeIssues(\n issues: readonly StandardSchemaV1Issue[],\n): string {\n const shown = issues.slice(0, 3).map((issue) => {\n const pathStr = formatPath(issue.path)\n return `${pathStr}: ${issue.message}`\n })\n const suffix = issues.length > 3 ? ` (+${issues.length - 3} more)` : ''\n return shown.join('; ') + suffix\n}\n\nfunction formatPath(\n path: StandardSchemaV1Issue['path'],\n): string {\n if (!path || path.length === 0) return 'root'\n return path\n .map((segment) =>\n typeof segment === 'object' && segment !== null\n ? String(segment.key)\n : String(segment),\n )\n .join('.')\n}\n","/**\n * RecordCodec — the per-record envelope build + encrypt/decrypt + per-record-CEK\n * + sealed-field crypto.\n *\n * `Collection` holds one `RecordCodec` instance and delegates the crypto write\n * path (`encryptRecord` / `encryptJsonString` / `buildDebugEnvelope`), the read\n * path (`decryptRecord` / `decryptJsonString` / `resolveEnvelopeCek`), and the\n * sealed-field helpers (`unsealField` / `makeSealedHandle` / `toCacheRecord` /\n * `classifySealedShred`) to it. The codec receives every `this.*` dependency\n * it needs via {@link RecordCodecContext}.\n *\n * The crux is `cekCache`: it is the SAME `Lru` reference `Collection` owns (not\n * a copy). `resolveEnvelopeCek` reads/writes it, and tier methods +\n * `vault.invalidateRecordCaches` keep mutating that same object — a copy would\n * silently break the \"single CEK delete kills the version chain\" invariant.\n *\n * Internal service — not exported as a `@noy-db/hub/*` subpath.\n */\nimport { encrypt, decrypt, encryptDeterministic, deriveDeterministicKey, wrapCek, unwrapCek, deriveSealedFieldKeyFromCek, type EnclaveKey } from '../crypto.js'\nimport { NOYDB_FORMAT_VERSION, type EncryptedEnvelope, type CrdtMode, type CrdtState, type CrdtStrategy, type VdigFieldPolicy, type SealedHandle } from '../../types.js'\nimport { isTombstone, isDeleteMarker } from './tombstone.js'\nimport { parseSealedSlot } from './sealed-slot.js'\nimport { sealFields, unsealOneField, unsealFields, makeHandleProducer, makeSealedSlotCapability, makeReservedEnvelopes, type SealKeyMaterial } from './sealed-slots.js'\nimport { DebugReservedFieldError, ClassifiedConfigError, ValidationError } from '../../errors.js'\nimport { mintVdigSlot } from '../classify/write.js'\nimport { mintBidxTag } from '../classify/bidx.js'\nimport { normalizeForVerify } from '../classify/normalize.js'\nimport { validateSchemaOutput, type StandardSchemaV1 } from '../../schema.js'\nimport type { Lru } from '../../cache/index.js'\nimport type { ViaCryptoCtx, SealedSlotRef } from '../../via/index.js'\nimport type { ViaPipeline } from '../../via/pipeline.js'\n\n/**\n * One classified per-slot verdict from {@link RecordCodec.classifySealedShred}.\n * `shreddable` — CEK-only, tombstone makes it undecryptable. `dekResidue` —\n * collection-DEK-keyed, survives in synced/backup copies. The third class is\n * BOTH: a `_bidx` blind-index tag is live-dropped by the tombstone yet retained\n * under the surviving DEK in any pre-forget backup (honest dual accounting).\n */\nexport type SealedShredSlot = {\n readonly field: string\n readonly class: 'shreddable' | 'dekResidue' | 'live-shreddable+dekResidue-in-backups'\n}\n\n/** Everything the moving crypto methods touched on `this.*`, as a flat context. */\nexport interface RecordCodecContext<T> {\n /** Collection name — the crypto AAD scope and schema-error context. */\n readonly name: string\n /** Actor id stamped on `_by` (the collection's keyring.userId). */\n readonly actor: string\n /** False on plaintext collections — selects the no-ciphertext envelope branch. */\n readonly storeCiphertext: boolean\n /** keyring.debugPlaintext — debug-inline envelope on user collections. */\n readonly debugPlaintext: boolean\n /** Emit `_source`/`_sourceTs` provenance fields when a source is supplied. */\n readonly provenance: boolean\n /** Declared `sensitive` fields → sealed into `_sealed[field]`. */\n readonly sensitiveFields: ReadonlySet<string>\n /** Declared deterministic-index fields, or null. */\n readonly deterministicFields: ReadonlySet<string> | null\n /** Digest-only classified fields → verify policy (stage 2). Null when none. */\n readonly vdigFields: ReadonlyMap<string, VdigFieldPolicy> | null\n /**\n * C-A / R10 config-drift signal: the persisted `x-classified` marker's\n * declared digest-only field set (empty when the collection carries no\n * marker). Lazy, memoized (O(1) per handle after the first call). The R10\n * superset guard refuses whenever a field in this set is absent from\n * `vdigFields`. Consulted once per handle on any encrypted write path — the\n * cross-session, prev-free signal a fully-naive create has no `prev` for.\n * Undefined on codecs with no store access (direct-construction tests).\n */\n classifiedMarkerDigestOnly?(): Promise<readonly string[]>\n /** CRDT mode (decrypt resolves CrdtState→snapshot when set). */\n readonly crdtMode: CrdtMode | undefined\n /** CRDT strategy seam (resolveCrdtSnapshot). */\n readonly crdtStrategy: CrdtStrategy\n /** Output-schema validator, or undefined. */\n readonly schema: StandardSchemaV1<unknown, T> | undefined\n /**\n * Resolve a collection's DEK. Called with no argument for `this.name`'s\n * own DEK (every ordinary codec use); `viaCryptoCtx`'s `reservedEnvelopes`\n * door passes an explicit OTHER collection name (e.g. a reserved\n * `_dict_status` collection) so a binding's at-rest hook can address a\n * different collection's DEK without ever holding the resolver itself.\n */\n getDEK(collection?: string): Promise<EnclaveKey>\n /**\n * The collection's per-record CEK cache (SHARED reference, not a copy).\n * Ownership/lifetime stays on Collection; codec reads+writes it in\n * resolveEnvelopeCek exactly as the inline code did. `null` → no caching.\n */\n readonly cekCache: Lru<string, EnclaveKey> | null\n /**\n * Compiled Via pipeline (money, i18n, …), or undefined for a collection\n * with none declared. `encryptRecord`/`decryptRecord` consult\n * `via?.hasAtRestHooks` at the sealed-slot sub-step to choose between a\n * binding's `encodeAtRest`/`decodeAtRest` hooks and today's inline path.\n * The zero-via fast path (`via` undefined, or no binding declares an\n * at-rest hook) stays byte/behavior-identical (#629 Task 3).\n *\n * Mutable (not `readonly`, #638 Task 3): `Collection.via` can be\n * reassigned post-construction (the taint overlay, `via/graph-wiring.ts#\n * applyTaintOverlay`) — `RecordCodec.setVia` below keeps this in sync so\n * at-rest hooks read the LIVE pipeline, not a stale construction-time\n * snapshot.\n */\n via: ViaPipeline | undefined\n}\n\nexport class RecordCodec<T> {\n constructor(private readonly ctx: RecordCodecContext<T>) {}\n\n /**\n * @internal Update the live Via pipeline this codec's at-rest hooks read\n * (#638 Task 3) — called by `via/graph-wiring.ts#applyTaintOverlay` right\n * after it reassigns `Collection.via`, so `hasAtRestHooks`/`encodeAtRest`/\n * `decodeAtRest` see the newly-added `taint` binding instead of the\n * pipeline snapshot captured when this codec was constructed.\n */\n setVia(via: ViaPipeline | undefined): void {\n this.ctx.via = via\n }\n\n /** Sealed-slot key material for this codec's collection, for a given per-record CEK (or none). */\n private sealKeyMaterial(cek: EnclaveKey | undefined): SealKeyMaterial {\n return {\n collection: this.ctx.name,\n ...(cek !== undefined ? { cek } : {}),\n getDEK: () => this.ctx.getDEK(),\n }\n }\n\n /**\n * Build the `ViaCryptoCtx` handed to a binding's `encodeAtRest`/\n * `decodeAtRest` hook: `sealedSlots` pre-bound to `(this.ctx.name,\n * recordId)` — always threading `cek` when the caller has one, so the\n * capability's record-binding stays cryptographic rather than degrading\n * to collection-scope. `reservedEnvelopes`'s DEK resolver forwards its\n * `collection` argument straight to `this.ctx.getDEK` (#629 Task 4) — it\n * resolves the RESERVED collection's own DEK (e.g. `_dict_status`), never\n * `this.ctx.name`'s, matching `Vault.getDEK`'s per-collection-name\n * resolution (the same resolver `DictionaryHandle` used pre-cutover).\n */\n private viaCryptoCtx(recordId: string, cek: EnclaveKey | undefined): ViaCryptoCtx {\n const declaredPrefixes = this.ctx.via?.bindings.flatMap((b) => b.reservedPrefixes ?? []) ?? []\n return {\n sealedSlots: makeSealedSlotCapability(this.ctx, recordId, cek),\n reservedEnvelopes: makeReservedEnvelopes((collection) => this.ctx.getDEK(collection), declaredPrefixes),\n }\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // Low-level literal builders\n // ──────────────────────────────────────────────────────────────────────\n\n /**\n * Assemble a canonical ciphertext body envelope literal from already-computed\n * parts. Pure, no crypto. Each call stamps its own `_ts` — provenance carries\n * a SEPARATE timestamp (computed by the caller), so the two never share one.\n */\n static buildEnvelope(p: {\n version: number\n iv: string\n data: string\n by?: string\n cek?: string\n provenance?: { source: string; sourceTs: string } | undefined\n extra?: Partial<Pick<EncryptedEnvelope, '_tier' | '_det' | '_sealed'>>\n }): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: p.version,\n _ts: new Date().toISOString(),\n _iv: p.iv,\n _data: p.data,\n ...(p.by !== undefined ? { _by: p.by } : {}),\n ...(p.cek !== undefined ? { _cek: p.cek } : {}),\n ...(p.provenance !== undefined ? { _source: p.provenance.source, _sourceTs: p.provenance.sourceTs } : {}),\n ...(p.extra ?? {}),\n }\n }\n\n /** Plaintext (`_iv:''`) body envelope — the `!storeCiphertext` shape. */\n static buildPlaintextEnvelope(p: {\n version: number\n data: string\n by?: string\n provenance?: { source: string; sourceTs: string } | undefined\n }): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: p.version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: p.data,\n ...(p.by !== undefined ? { _by: p.by } : {}),\n ...(p.provenance !== undefined ? { _source: p.provenance.source, _sourceTs: p.provenance.sourceTs } : {}),\n }\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // Write path\n // ──────────────────────────────────────────────────────────────────────\n\n /**\n * Build a debug-plaintext envelope: the record's own fields inlined as\n * top-level keys beside the reserved `_`-metadata, with `_debug: 1` and an\n * empty `_data`. Lets native store tooling read the record without\n * unwrapping. Only reached for user collections under `debugPlaintext`\n * (see {@link encryptRecord}). Rejects `_`-prefixed record fields, which\n * would collide with the reserved metadata namespace.\n */\n buildDebugEnvelope(record: T, version: number, source?: string, sourceTs?: string): EncryptedEnvelope {\n const rec = record as unknown as Record<string, unknown>\n for (const key of Object.keys(rec)) {\n if (key.startsWith('_')) throw new DebugReservedFieldError(this.ctx.name, key)\n }\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: '',\n _by: this.ctx.actor,\n _debug: NOYDB_FORMAT_VERSION,\n ...(this.ctx.provenance && source !== undefined ? { _source: source, _sourceTs: sourceTs ?? new Date().toISOString() } : {}),\n ...rec,\n } as unknown as EncryptedEnvelope\n }\n\n /**\n * Encrypt a JSON body into an envelope.\n *\n * When `cek` is supplied (per-record CEK collections), the body is\n * encrypted under the CEK and the CEK is AES-KW-wrapped under the\n * collection DEK and stamped on `_cek`. When `cek` is omitted, the legacy\n * path encrypts the body directly under the collection DEK — byte-identical\n * to pre-CEK behaviour, so non-adopting collections pay nothing.\n */\n async encryptJsonString(\n json: string,\n version: number,\n cek?: EnclaveKey,\n source?: string,\n sourceTs?: string,\n ): Promise<EncryptedEnvelope> {\n const by = this.ctx.actor\n const provenance = this.ctx.provenance && source !== undefined\n ? { source, sourceTs: sourceTs ?? new Date().toISOString() }\n : undefined\n\n if (!this.ctx.storeCiphertext) {\n return RecordCodec.buildPlaintextEnvelope({ version, data: json, by, provenance })\n }\n\n const dek = await this.ctx.getDEK()\n\n if (cek !== undefined) {\n const { iv, data } = await encrypt(json, cek)\n const wrapped = await wrapCek(cek, dek)\n return RecordCodec.buildEnvelope({ version, iv, data, by, cek: wrapped, provenance })\n }\n\n const { iv, data } = await encrypt(json, dek)\n return RecordCodec.buildEnvelope({ version, iv, data, by, provenance })\n }\n\n async encryptRecord(\n record: T,\n version: number,\n cek?: EnclaveKey,\n source?: string,\n sourceTs?: string,\n vdig?: { readonly id: string; readonly prev: EncryptedEnvelope | null },\n id?: string,\n ): Promise<EncryptedEnvelope> {\n // Debug-plaintext: write user-collection records with their fields inlined\n // beside the envelope metadata so native store tools read them directly.\n // Internal (`_`-prefixed) collections keep the classic shape — some store\n // `_`-prefixed fields that the inline layout would collide with.\n if (!this.ctx.storeCiphertext && this.ctx.debugPlaintext && !this.ctx.name.startsWith('_')) {\n return this.buildDebugEnvelope(record, version, source, sourceTs)\n }\n\n // ── C-A / R10 config-drift guard (superset) ────────────────────────\n // A handle may write a classified collection only if its DECLARED\n // digest-only set is a SUPERSET of the collection's stored/marked\n // classified set. Any classified field this handle does NOT declare is a\n // field it cannot maintain: the `_vdig` loop below iterates only declared\n // fields, so an undeclared classified field is neither stripped nor tagged —\n // its value would be serialized into `_data` as DEK-recoverable plaintext\n // (the C-A leak), or its stored tag silently dropped. Fail loud.\n //\n // This subsumes the old naive-only guard (a fully-naive handle has an empty\n // declared set, so ANY stored classified field violates the superset) AND\n // closes the partial-handle door (declares Y, not X, over a record carrying\n // `_vdig[X]`/`_bidx[X]`): the narrow `vdigFields === null || size === 0`\n // gate skipped that entire case. The stored/marked set is the union of:\n // 1. the persisted `x-classified` marker's declared digest-only set\n // (cross-session, prev-free — the only signal a fully-naive create has);\n // 2. the keys the target `prev` already carries in `_vdig`/`_bidx` (the\n // overwrite arm; a classified-declaring handle DOES pass `prev`).\n // Only encrypted collections can be classified, so plaintext collections skip.\n if (this.ctx.storeCiphertext) {\n const declared = this.ctx.vdigFields\n const storedClassified = new Set<string>()\n if (vdig?.prev?._vdig) for (const k of Object.keys(vdig.prev._vdig)) storedClassified.add(k)\n if (vdig?.prev?._bidx) for (const k of Object.keys(vdig.prev._bidx)) storedClassified.add(k)\n if (this.ctx.classifiedMarkerDigestOnly !== undefined) {\n for (const k of await this.ctx.classifiedMarkerDigestOnly()) storedClassified.add(k)\n }\n let undeclared: string | undefined\n for (const field of storedClassified) {\n if (declared === null || !declared.has(field)) { undeclared = field; break }\n }\n if (undeclared !== undefined) {\n throw new ClassifiedConfigError(\n this.ctx.name,\n `this collection has classified digest-only field \"${undeclared}\" but this handle does not declare it — ` +\n 'refusing to write (would drop its tag or serialize the secret as plaintext)',\n )\n }\n }\n\n // Structural group-encryption: peel declared sensitive fields out\n // of the record BEFORE building `_data`, sealing each into its own\n // `_sealed[field]` slot under a per-field key. Default-off — with no\n // sensitive fields the open record is unchanged and no `_sealed` is\n // emitted, so the envelope stays byte-identical to legacy output.\n // A collection whose via pipeline declares at-rest hooks (#629 Task 3)\n // seals through THOSE instead — the inline `sensitiveFields` path and\n // the hook path are mutually exclusive per collection, gated on\n // `hasAtRestHooks` (the inline path now serves only the plain\n // `sensitive: [...]` collection option; since #629, `classifiedFields`-\n // declared fields seal through their own via-binding hook, and since\n // #638 so does any field the taint graph seals — `via/classified/\n // binding.ts` and `kernel/via/taint-binding.ts`, respectively). The\n // zero-via fast path (no `via`, or a pipeline with no at-rest hooks,\n // e.g. money-only) always takes the `else if` branch, unchanged.\n let openRecord = record\n let sealed: Record<string, string> | undefined\n if (this.ctx.storeCiphertext && this.ctx.via?.hasAtRestHooks) {\n if (id === undefined) {\n throw new Error(\n `RecordCodec.encryptRecord: collection \"${this.ctx.name}\" has via at-rest hooks but this write ` +\n 'path supplied no record id (needed to scope the sealed-slot capability) — caller bug.',\n )\n }\n const src = record as unknown as Record<string, unknown>\n const result = await this.ctx.via.encodeAtRest(src, this.viaCryptoCtx(id, cek))\n openRecord = result.record as unknown as T\n if (result.sealed !== undefined) {\n sealed = {}\n for (const [field, ref] of Object.entries(result.sealed)) sealed[field] = `${ref.iv}:${ref.data}`\n }\n } else if (this.ctx.storeCiphertext && this.ctx.sensitiveFields.size > 0) {\n const src = record as unknown as Record<string, unknown>\n const result = await sealFields(src, this.ctx.sensitiveFields, this.sealKeyMaterial(cek))\n if (result.sealed !== undefined) {\n sealed = result.sealed\n openRecord = result.openRecord as unknown as T\n }\n }\n\n // ── Digest-only classified fields (stage 2, C6) ────────────────────\n // Per field, exactly one of: carry-forward (absent) / rotate (string) /\n // clear (null) / loud error (anything else). Runs on a CLONE so the\n // caller's record object is never mutated.\n let vdigOut: Record<string, string> | undefined\n let bidxOutMap: Record<string, string> | undefined\n if (this.ctx.vdigFields !== null && this.ctx.vdigFields.size > 0 && this.ctx.storeCiphertext) {\n if (vdig === undefined) {\n throw new Error(\n `RecordCodec.encryptRecord: collection \"${this.ctx.name}\" declares digest-only classified ` +\n `fields but this write path supplied no { id, prev } context — it would silently destroy _vdig (C6). Caller bug.`,\n )\n }\n if (cek === undefined) {\n throw new Error(\n `RecordCodec.encryptRecord: digest-only fields require a per-record CEK (R1 invariant) — ` +\n `collection \"${this.ctx.name}\" wrote without one. Caller bug.`,\n )\n }\n const open: Record<string, unknown> = { ...(openRecord as unknown as Record<string, unknown>) }\n const out: Record<string, string> = {}\n // _bidx (blind-index equality tags) rides the SAME iteration as _vdig,\n // so the structural invariant _bidx[field] ⇒ _vdig[field] holds by\n // construction: a tag is only ever written where the _vdig slot is\n // written/carried. DEK is fetched lazily — only an equatable rotate needs it.\n const bidxOut: Record<string, string> = {}\n let bidxDek: EnclaveKey | undefined\n for (const [field, policy] of this.ctx.vdigFields) {\n const value = open[field]\n const prevBlob = vdig.prev?._vdig?.[field]\n if (vdig.prev?._sealed?.[field] !== undefined) {\n // R6 transition evidence: never silently delete recoverable\n // plaintext. Checked BEFORE the value-type dispatch so the\n // carry-forward (absent) and clear (null) branches refuse too —\n // both would otherwise drop the `_sealed` slot from the new\n // envelope, silently destroying the recoverable ciphertext.\n throw new ClassifiedConfigError(\n this.ctx.name,\n `field \"${field}\" carries a recoverable _sealed slot from a previous storage form — ` +\n `recoverable ↔ digest-only transitions are refused (R6); migrate explicitly`,\n )\n }\n if (value === undefined) {\n // 1. carry-forward: verbatim bytes (CEK version-stable, AAD _v-free;\n // byte-identity keeps the ledger payload hash deterministic).\n // I-3 monotonic carry: whenever the _vdig slot is carried, ALSO copy\n // prev._bidx[field] verbatim — regardless of THIS handle's equatable\n // knob. An unrelated put by a handle with equatable removed must not\n // drop another handle's tag (anti-flip-flop). If prev has no tag,\n // there is nothing to mint from (no plaintext) → stays uncovered.\n if (prevBlob !== undefined) {\n out[field] = prevBlob\n const prevTag = vdig.prev?._bidx?.[field]\n if (prevTag !== undefined) bidxOut[field] = prevTag\n }\n continue\n }\n if (value === null) {\n // 3. clear: the defined deletion short of forget().\n delete open[field]\n continue\n }\n if (typeof value !== 'string') {\n // 4. caller bug, fail-loud.\n throw new ValidationError(\n `digest-only classified field \"${field}\" in \"${this.ctx.name}\" must be a string (rotate) or null (clear), got ${typeof value}`,\n )\n }\n // 2. rotate: validate ran in the stage-1 write seam; digest + ring here.\n out[field] = await mintVdigSlot(value, policy, prevBlob, cek, this.ctx.name, vdig.id, field)\n // _bidx branch 2: if this handle is equatable, mint a fresh tag through\n // the SAME normalization pipeline mintVdigSlot uses (normalizeForVerify)\n // — the tag provably equals computeBidxTarget for this value. If the\n // knob is OFF, emit nothing: the stale prev tag points at the now-\n // superseded value (carrying it would be wrong) and minting is disallowed\n // (knob off) → the tag is dropped. Confirm-by-verify keeps this sound.\n if (policy.equatable === true) {\n if (bidxDek === undefined) bidxDek = await this.ctx.getDEK()\n const normalized = normalizeForVerify(policy.normalize, value)\n bidxOut[field] = await mintBidxTag(normalized, bidxDek, this.ctx.name, field)\n }\n delete open[field] // strip from _data — digest-only never persists plaintext\n }\n openRecord = open as unknown as T\n if (Object.keys(out).length > 0) vdigOut = out\n if (Object.keys(bidxOut).length > 0) bidxOutMap = bidxOut\n }\n\n const base = await this.encryptJsonString(JSON.stringify(openRecord), version, cek, source, sourceTs)\n const withSealed = sealed ? { ...base, _sealed: sealed } : base\n const withVdig = vdigOut ? { ...withSealed, _vdig: vdigOut } : withSealed\n const withBidx = bidxOutMap ? { ...withVdig, _bidx: bidxOutMap } : withVdig\n if (!this.ctx.deterministicFields || !this.ctx.storeCiphertext) return withBidx\n\n // compute deterministic-ciphertext slots for every\n // declared field. Non-primitive values are JSON-stringified so\n // objects/arrays still dedupe on structural equality. Sealed fields are\n // excluded — they live only in `_sealed`, never the `_det` index.\n // L-1: `_det` encrypts under a dedicated HKDF-derived key (salt\n // `noydb-det`), never the raw DEK — the DEK's randomized-IV `_data`\n // regime and `_det`'s deterministic-IV regime must not share a key.\n const dek = await this.ctx.getDEK()\n const detKey = await deriveDeterministicKey(dek)\n const rec = record as unknown as Record<string, unknown>\n const det: Record<string, string> = {}\n for (const field of this.ctx.deterministicFields) {\n if (this.ctx.sensitiveFields.has(field)) continue\n if (this.ctx.vdigFields?.has(field)) continue // I5: digest-only never equality-correlatable\n const value = rec[field]\n if (value === undefined || value === null) continue\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const { iv, data } = await encryptDeterministic(plaintext, detKey, `${this.ctx.name}/${field}`)\n det[field] = `${iv}:${data}`\n }\n if (Object.keys(det).length === 0) return withBidx\n return { ...withBidx, _det: det }\n }\n\n // ──────────────────────────────────────────────────────────────────────\n // Read path\n // ──────────────────────────────────────────────────────────────────────\n\n /**\n * Resolve the per-record CEK for a stored envelope, or `undefined` for a\n * legacy (`_cek`-absent) envelope. Unwraps `_cek` under the collection DEK and\n * memoises it in the CEK cache under `id` (when supplied) so repeated reads of\n * the same record skip the unwrap. Shared by the body-decrypt path\n * ({@link decryptJsonString}) and the sealed-field path ({@link decryptRecord}\n * / {@link toCacheRecord}) so both agree on the record's key.\n */\n async resolveEnvelopeCek(envelope: EncryptedEnvelope, id?: string): Promise<EnclaveKey | undefined> {\n if (envelope._cek === undefined) return undefined\n const cached = id !== undefined ? this.ctx.cekCache?.get(id) : undefined\n if (cached !== undefined) return cached\n const dek = await this.ctx.getDEK()\n const cek = await unwrapCek(envelope._cek, dek)\n if (id !== undefined) this.ctx.cekCache?.set(id, cek, 1)\n return cek\n }\n\n /**\n * Low-level: decrypt an envelope and return the raw JSON string.\n *\n * `_cek` presence is the format discriminant (NOT `this.perRecordCek`),\n * so a mixed vault — and a recipient that never opted into\n * `perRecordKeys` — decrypts both legacy and CEK records:\n * - `_cek` present → unwrap the CEK under the collection DEK, decrypt the\n * body under the CEK (cache the unwrapped CEK so repeated reads skip it).\n * - `_cek` absent → legacy path, body decrypts directly under the\n * collection DEK.\n *\n * The optional `id` lets reads populate the CEK cache; it is omitted by\n * callers (history, conflict merge) that have only the envelope.\n */\n async decryptJsonString(envelope: EncryptedEnvelope, id?: string): Promise<string | null> {\n // RISK #1 (forget cascade): a shred tombstone carries `_data: ''` and no\n // `_cek`. Decrypting it would call `decrypt('', '', dek)` → AES-GCM\n // OperationError → TamperedError. Return null so every read callsite\n // treats it as \"absent / skip\", matching how get()/list already drop\n // tombstones. Legacy plaintext collections (`!this.storeCiphertext`) legitimately\n // have empty `_iv`/`_data`, so `isTombstone` is false for them — preserved.\n if (isTombstone(envelope, this.ctx.storeCiphertext) || isDeleteMarker(envelope)) return null\n if (!this.ctx.storeCiphertext) {\n // Debug-plaintext layout: record fields were inlined as top-level keys\n // (see buildDebugEnvelope). Reconstruct the record from the non-`_`\n // keys. Self-describing via `_debug`, so a classic plaintext reader\n // handles debug-written envelopes too.\n if (envelope._debug !== undefined) {\n const rec: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(envelope)) {\n if (!key.startsWith('_')) rec[key] = value\n }\n return JSON.stringify(rec)\n }\n // #598: a real record never serializes to '' (JSON.stringify's floor is\n // '{}'), so an empty `_data` here is the sync engine's shape-only\n // tombstone (`isTombstoneShape` in team/sync.ts) landing on an\n // unencrypted collection, where the encryption-gated `isTombstone()`\n // check above doesn't fire. Treat it the same as an encrypted\n // tombstone: null, not a `JSON.parse('')` crash.\n return envelope._data === '' ? null : envelope._data\n }\n const cek = await this.resolveEnvelopeCek(envelope, id)\n if (cek !== undefined) return decrypt(envelope._iv, envelope._data, cek)\n const dek = await this.ctx.getDEK()\n return decrypt(envelope._iv, envelope._data, dek)\n }\n\n /**\n * Unseal a single `_sealed[field]` slot to its plaintext value: derive the\n * per-field key off the collection DEK, AES-GCM-decrypt the `iv:data` blob,\n * and JSON-parse the result. Shared by both the inline-decrypt path and a\n * {@link Sealed} handle's `reveal()` — so the on-demand reveal and the eager\n * materialisation always agree byte-for-byte.\n */\n async unsealField(field: string, blob: string, cek?: EnclaveKey): Promise<unknown> {\n // Dual-read. Current writes seal under a key derived from the record's\n // per-record CEK; legacy records (even ones whose body is\n // CEK-encrypted) are sealed under the collection-DEK key. Try the CEK key\n // first; on its AES-GCM auth failure, fall back to the DEK key. Without this\n // fallback every legacy `_sealed` record would throw TamperedError (data loss).\n return unsealOneField(field, blob, this.sealKeyMaterial(cek))\n }\n\n /**\n * Build the `ViaCryptoCtx` for forget()'s per-ref via-erase fold (#629\n * Task 10) — resolves the live envelope's CEK exactly like\n * `decryptRecord` does, then delegates to the same capability factory\n * `encodeAtRest`/`decodeAtRest` use.\n */\n async eraseCryptoCtx(id: string, live: EncryptedEnvelope): Promise<ViaCryptoCtx> {\n return this.viaCryptoCtx(id, await this.resolveEnvelopeCek(live, id))\n }\n\n /**\n * Classify a live envelope's `_sealed` slots for crypto-shred completeness.\n * `forget()` drops `_cek`/`_sealed` but\n * RETAINS the collection DEK, so only a slot keyed off the per-record CEK is\n * genuinely shredded by the tombstone; a legacy slot keyed off the\n * collection DEK survives in any synced/backup copy.\n *\n * Mirrors {@link unsealField}'s dual-read split: try the CEK-derived key per\n * slot — success → `shreddable`, AES-GCM auth failure → `dekResidue`. With no\n * `_cek` (pure legacy collection-DEK sealing) ALL slots are residue.\n */\n async classifySealedShred(\n live: EncryptedEnvelope,\n ): Promise<{ readonly slots: readonly SealedShredSlot[] }> {\n const slots: SealedShredSlot[] = []\n // Verify-digest slots are CEK-only by construction (I3): dropping `_cek`\n // makes every `_vdig[field]` permanently undecryptable — shreddable\n // unconditionally, no vdig-dekResidue class (spec §2 forget()). Same\n // honesty caveats as #306 D5 for synced/backup copies of the ciphertext.\n // A `_vdig` field ALSO carrying a `_bidx` tag is the third category: the\n // tombstone drops it from the live store, but a pre-forget backup retains\n // the blind-index tag under the surviving collection DEK — live-shreddable\n // yet dekResidue-in-backups. `_bidx[field] ⇒ _vdig[field]` (I4), so we\n // decide per vdig field and emit exactly one slot each (count-preserving).\n if (live._vdig !== undefined && live._cek !== undefined) {\n for (const field of Object.keys(live._vdig)) {\n slots.push({\n field,\n class: live._bidx?.[field] !== undefined\n ? 'live-shreddable+dekResidue-in-backups'\n : 'shreddable',\n })\n }\n }\n const sealed = live._sealed\n if (sealed === undefined) return { slots }\n const cek = await this.resolveEnvelopeCek(live)\n for (const [field, blob] of Object.entries(sealed)) {\n if (cek === undefined) { slots.push({ field, class: 'dekResidue' }); continue }\n const { iv, data } = parseSealedSlot(blob)\n try {\n await decrypt(iv, data, await deriveSealedFieldKeyFromCek(cek, this.ctx.name, field))\n slots.push({ field, class: 'shreddable' })\n } catch {\n slots.push({ field, class: 'dekResidue' })\n }\n }\n return { slots }\n }\n\n /**\n * Build a non-leaking {@link Sealed} handle over a sealed field's ciphertext.\n * The handle captures only the ciphertext `blob` and a closure to\n * {@link unsealField}; the plaintext is never stored on it — so the handle\n * may sit in the working-set cache (or be logged/serialised) without\n * exposing the value, which decrypts only on `reveal()`.\n */\n makeSealedHandle(field: string, blob: string, cek?: EnclaveKey): SealedHandle<unknown> {\n return makeHandleProducer(this.sealKeyMaterial(cek))(field, blob)\n }\n\n /**\n * Replace every field the just-written envelope actually sealed with a\n * {@link Sealed} handle, leaving every other field as its plaintext value.\n * Used to populate the cache on the write path without ever materialising\n * sealed plaintext into it. Returns `record` untouched when nothing was\n * sealed. Keys off `envelope._sealed` itself (#642 fix) — NOT\n * `this.ctx.sensitiveFields`, which only names the inline `sensitive:[...]`/\n * classified-recoverable field set: a collection whose sealing comes\n * entirely from the `taint` via-binding (a derivation/MV output or rollup\n * target folded sealed from a classified SOURCE collection, #642) declares\n * no local `sensitiveFields` at all, so that stale gate skipped this\n * conversion and left a just-written taint-sealed field as cached\n * plaintext — read back correctly ONLY after a cold cache miss (`get()`'s\n * own `decodeAtRest` call, unaffected by this gate) forced a fresh decrypt.\n */\n async toCacheRecord(record: T, envelope: EncryptedEnvelope, id?: string): Promise<T> {\n const sealed = envelope._sealed\n if (sealed === undefined || !this.ctx.storeCiphertext) {\n return record\n }\n const cek = await this.resolveEnvelopeCek(envelope, id)\n const clone = { ...(record as unknown as Record<string, unknown>) }\n for (const [field, blob] of Object.entries(sealed)) {\n clone[field] = this.makeSealedHandle(field, blob, cek)\n }\n return clone as unknown as T\n }\n\n /**\n * Apply `_sealed`-slot post-processing to an ALREADY-DECRYPTED `record`:\n * restore each `_sealed[field]` blob inline (`sealedAsHandles` falsy) or\n * as an opaque {@link Sealed} handle (`sealedAsHandles: true`), routing\n * through a via pipeline's `decodeAtRest` hook when one is declared.\n * Extracted byte-parity from `decryptRecord`'s inline block (#635) so a\n * caller that resolves its OWN per-record CEK under a DIFFERENT DEK than\n * this codec's `this.ctx.getDEK()` — namely the tier>0 `getAtTier` leg in\n * `with-audit/tiers/index.ts`, whose `_cek` is wrapped under the TIER DEK,\n * not the collection DEK `decryptRecord`/`resolveEnvelopeCek` always\n * unwrap under — can still get correct sealed-slot handling without\n * routing its whole read through `decryptRecord` (which would resolve the\n * wrong DEK for it).\n *\n * Zero-knowledge: takes only the already-resolved per-record `cek` (or\n * `undefined` for a legacy/no-CEK record) — the same shape `makeSealedHandle`\n * already takes above. Never the keyring, never a raw DEK: the legacy\n * fallback key stays fully internal to `sealKeyMaterial`/`viaCryptoCtx`,\n * which close over THIS codec's own `getDEK` (permanently bound to\n * `this.ctx.name`'s tier-0 DEK at construction) — so even when called from\n * a tier>0 context, the legacy-fallback key resolution is correct: sealed\n * fields are always sealed under the CEK or the collection's tier-0 DEK,\n * never a tier DEK (tier writes don't seal fields; `_sealed` reaches a\n * tiered envelope only via a tier-0 write later elevated).\n */\n async applySealedSlots(\n record: T,\n sealed: Record<string, string>,\n cek: EnclaveKey | undefined,\n opts: { id?: string; sealedAsHandles?: boolean } = {},\n ): Promise<T> {\n if (this.ctx.via?.hasAtRestHooks) {\n if (opts.id === undefined) {\n throw new Error(\n `RecordCodec.decryptRecord: collection \"${this.ctx.name}\" has via at-rest hooks but this read ` +\n 'path supplied no record id (needed to scope the sealed-slot capability) — caller bug.',\n )\n }\n const sealedRefs: Record<string, SealedSlotRef> = {}\n for (const [field, blob] of Object.entries(sealed)) {\n const { iv, data } = parseSealedSlot(blob)\n sealedRefs[field] = { iv, data }\n }\n return await this.ctx.via.decodeAtRest(\n record as unknown as Record<string, unknown>,\n sealedRefs,\n this.viaCryptoCtx(opts.id, cek),\n { asHandles: opts.sealedAsHandles === true },\n ) as unknown as T\n }\n return await unsealFields(\n record as unknown as Record<string, unknown>,\n sealed,\n this.sealKeyMaterial(cek),\n { asHandles: opts.sealedAsHandles === true },\n ) as unknown as T\n }\n\n /**\n * Decrypt an envelope under an EXPLICIT `dek` instead of this codec's own\n * `ctx.getDEK()` / cekCache resolution — for a from-tier>0 pre-move decode\n * (`with-audit/tiers/index.ts`'s `putAtTier`/`elevate`/`demote` sites,\n * #722 whole-branch review). Mirrors the manual unwrap-then-decrypt\n * `getAtTier`'s own tier>0 leg performs there (same primitives, same\n * `applySealedSlots` extraction point #635 built for exactly this caller).\n *\n * `decryptRecord` is tier-UNAWARE: `resolveEnvelopeCek` reads the cekCache\n * or falls back to `ctx.getDEK()` — this codec's DEFAULT (tier-0/\n * collection) DEK — never the envelope's OWN tier. That only happens to\n * decrypt a from-tier>0 envelope correctly when some other call in the\n * SAME op already primed the cekCache with this record's CEK (true for an\n * ordinary put()-then-elevate(0→1); NOT true for a `putAtTier`-origin\n * envelope, whose body is encrypted directly under its tier DEK with no\n * `_cek` ever minted, or a non-`perRecordKeys` collection, which has no\n * `_cek` at all) — those throw `TamperedError`. Decrypting under the\n * caller-resolved `dek` is correct regardless of cache state or\n * `perRecordKeys`.\n *\n * No CRDT resolution, no schema validation — same scope as `getAtTier`'s\n * tier>0 branch (the established precedent for a tier-aware read), which\n * skips both for the same reason: a tier>0 read is an internal/derived-\n * output-recompute path, not the public per-record read surface schema\n * validation guards.\n */\n async decryptRecordAtDek(envelope: EncryptedEnvelope, dek: EnclaveKey, id?: string): Promise<T | null> {\n if (isTombstone(envelope, this.ctx.storeCiphertext) || isDeleteMarker(envelope)) return null\n let plaintext: string\n let cek: EnclaveKey | undefined\n if (envelope._cek !== undefined) {\n cek = await unwrapCek(envelope._cek, dek)\n plaintext = await decrypt(envelope._iv, envelope._data, cek)\n } else {\n plaintext = await decrypt(envelope._iv, envelope._data, dek)\n }\n let record = JSON.parse(plaintext) as T\n if (envelope._sealed !== undefined && this.ctx.storeCiphertext) {\n record = await this.applySealedSlots(record, envelope._sealed, cek, { ...(id !== undefined ? { id } : {}), sealedAsHandles: true })\n }\n return record\n }\n\n /**\n * Decrypt an envelope into a record of type `T`.\n *\n * When a schema is attached, the decrypted value is validated before\n * being returned. A divergence between the stored bytes and the\n * current schema throws `SchemaValidationError` with\n * `direction: 'output'` — silently returning drifted data would\n * propagate garbage into the UI and break the whole point of having\n * a schema.\n *\n * `skipValidation` exists for history reads: when calling\n * `getVersion()` the caller is explicitly asking for an old snapshot\n * that may predate a schema change, so validating it would be a\n * false positive. Every non-history read leaves this flag `false`.\n */\n async decryptRecord(\n envelope: EncryptedEnvelope,\n opts: { skipValidation?: boolean; id?: string; sealedAsHandles?: boolean } = {},\n ): Promise<T | null> {\n const json = await this.decryptJsonString(envelope, opts.id)\n // Tombstone (shredded record) → null, propagated from decryptJsonString.\n // Callers skip null exactly as they already skip a tombstone envelope.\n if (json === null) return null\n let parsed: unknown = JSON.parse(json)\n\n // CRDT resolution: if this collection is in CRDT mode, the\n // stored JSON is a CrdtState, not T directly. Resolve to the snapshot.\n if (this.ctx.crdtMode && parsed !== null && typeof parsed === 'object' && '_crdt' in parsed) {\n parsed = this.ctx.crdtStrategy.resolveCrdtSnapshot(parsed as CrdtState)\n }\n\n let record = parsed as T\n\n // Structural group-encryption + sealed access gate.\n // Each `_sealed[field]` slot is restored under its own per-field key.\n // `sealedAsHandles: false` (default — internal callers that compute on\n // real values) inline-decrypts to the plaintext value; `true` (the\n // public / cache path) yields an opaque {@link Sealed} handle so the\n // plaintext is never materialised into the working-set cache. A\n // collection whose via pipeline declares at-rest hooks (#629 Task 3)\n // decodes through THOSE instead of the inline dual-read below — the\n // zero-via fast path (no `via`, or a pipeline with no at-rest hooks)\n // always takes the `else` branch, unchanged.\n if (envelope._sealed !== undefined && this.ctx.storeCiphertext) {\n const sealedCek = await this.resolveEnvelopeCek(envelope, opts.id)\n record = await this.applySealedSlots(record, envelope._sealed, sealedCek, {\n ...(opts.id !== undefined ? { id: opts.id } : {}),\n ...(opts.sealedAsHandles !== undefined ? { sealedAsHandles: opts.sealedAsHandles } : {}),\n })\n }\n\n // Skip output validation when sealed fields are returned as handles:\n // the record carries opaque `Sealed` handles in place of the declared\n // values, so a whole-record schema check would false-positive on them.\n // (The values were validated on input/write; the open fields are\n // unchanged from the validated body.) The inline-value path below still\n // validates fully.\n const sealedAsHandles = opts.sealedAsHandles === true && envelope._sealed !== undefined\n if (this.ctx.schema !== undefined && !opts.skipValidation && !sealedAsHandles) {\n // Context string deliberately avoids leaking the record id — the\n // envelope only carries the version, not the id (the id lives in\n // the adapter-side key). `<collection>@v<n>` is enough for the\n // developer to find the offending record.\n record = await validateSchemaOutput(\n this.ctx.schema,\n record,\n `${this.ctx.name}@v${envelope._v}`,\n )\n }\n\n return record\n }\n}\n","/**\n * Record-scoped CEK sealing — grantor side.\n *\n * The **grantor** holds the collection DEK and seals ONE record's CEK to an\n * `at-*` host so that host — and only that host — can decrypt exactly that\n * record, with no access to the vault DEK and no ability to read any other\n * record. This is the counterpart to the host-side `openSealedRecord`\n * (`@noy-db/hub/sealed-record`), which holds no DEK.\n *\n * These functions are the orchestration behind `vault.sealRecordToHost` /\n * `vault.revokeSealedRecord` / `vault.rotateRecordCek`, lifted off `Vault`\n * behind a narrow {@link SealingContext} so the kernel file delegates. They\n * live in `record-keys/` (the vault-side CEK policy layer), NOT in\n * `sealed-record/`, so the host-side subpath stays DEK-free — the wire\n * *types* they share are spine-owned (`kernel/types.ts`), not imported from\n * `sealed-record/` directly.\n */\nimport { encrypt, decrypt, generateDEK, wrapCek, unwrapCek, bufferToBase64, deriveSealedFieldKeyFromCek, type EnclaveKey } from '../crypto.js'\nimport {\n NOYDB_FORMAT_VERSION,\n type EncryptedEnvelope,\n type NoydbStore,\n type RecipientSealer,\n type SealedCekBinding,\n type SealedCekDeliveryEnvelope,\n} from '../../types.js'\nimport { dualReadSealedSlot } from './sealed-slot.js'\nimport { openVdigPayload, sealVdigPayload } from '../classify/vdig.js'\nimport { RecordCekNotFoundError, ValidationError } from '../../errors.js'\n\nconst subtle = globalThis.crypto.subtle\n\n/** The `_sealed_cek` delivery namespace (one envelope per `collection/id/pid`). */\nexport const SEALED_CEK_NS = '_sealed_cek'\n\n/** What the grantor functions need from their `Vault`. */\nexport interface SealingContext {\n readonly adapter: NoydbStore\n /** Vault id (the adapter's first coordinate). */\n readonly vault: string\n /** Resolve the DEK a record's CEK is wrapped under. */\n getDEK(collection: string): Promise<EnclaveKey>\n /** Actor id stamped on `_by` (empty string → omit). */\n readonly actor: string\n /** Evict the per-record CEK cache + decrypted-record cache after a rotation. */\n invalidateRecordCaches(collection: string, id: string): Promise<void>\n}\n\n/**\n * Seal a record's CEK to a host. See `vault.sealRecordToHost` for the contract.\n * Returns `{ pid, envelopeKey }`.\n */\nexport async function sealRecordToHost(\n ctx: SealingContext,\n collection: string,\n id: string,\n hostSealer: RecipientSealer,\n opts: { expiresAt: string },\n): Promise<{ pid: string; envelopeKey: string }> {\n // Guard separators: the `_sealed_cek` id is `collection/id/pid`, so a `/` in\n // any component would make the prefix-delete in rotateRecordCek() (which\n // matches `${collection}/${id}/`) ambiguous and could over- or under-match.\n if (collection.includes('/')) throw new ValidationError(`sealRecordToHost: collection \"${collection}\" must not contain \"/\"`)\n if (id.includes('/')) throw new ValidationError(`sealRecordToHost: id \"${id}\" must not contain \"/\"`)\n // M-4: reject a malformed/empty expiry at seal time. `Date.parse('')` (and any\n // non-ISO string) is NaN, and the open-time check `NaN <= now` is `false` — so\n // a malformed expiry would silently mint an ETERNAL grant. A *past* (but valid)\n // timestamp is still allowed: it seals, then fails closed at open time.\n if (Number.isNaN(Date.parse(opts.expiresAt))) {\n throw new ValidationError(`sealRecordToHost: expiresAt \"${opts.expiresAt}\" is not a valid ISO 8601 timestamp`)\n }\n\n const live = await ctx.adapter.get(ctx.vault, collection, id)\n if (!live || live._cek === undefined) {\n throw new RecordCekNotFoundError(collection, id)\n }\n\n const dek = await ctx.getDEK(collection)\n const cek = await unwrapCek(live._cek, dek)\n const rawCek = await subtle.exportKey('raw', cek)\n const cekB64 = bufferToBase64(rawCek)\n\n const hint = await hostSealer.publishRecipientHint()\n if (hint.pid.includes('/')) throw new ValidationError(`sealRecordToHost: recipient pid \"${hint.pid}\" must not contain \"/\"`)\n\n const binding: SealedCekBinding = {\n collection,\n id,\n cek: cekB64,\n expiresAt: opts.expiresAt,\n }\n const sealed = await hostSealer.sealForRecipient(\n new TextEncoder().encode(JSON.stringify(binding)),\n hint,\n )\n\n const delivery: SealedCekDeliveryEnvelope = {\n v: 1,\n _noydb_sealed_cek: 1,\n pid: hint.pid,\n payload: bufferToBase64(sealed),\n expiresAt: opts.expiresAt,\n }\n\n const envelopeKey = `${collection}/${id}/${hint.pid}`\n const prior = await ctx.adapter.get(ctx.vault, SEALED_CEK_NS, envelopeKey)\n const env: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: (prior?._v ?? 0) + 1,\n _ts: new Date().toISOString(),\n // AES-GCM bypassed — the sealing layer is the security boundary, exactly\n // like the managed-secret `_meta/sealed-secret` envelope.\n _iv: '',\n _data: JSON.stringify(delivery),\n ...(ctx.actor ? { _by: ctx.actor } : {}),\n }\n await ctx.adapter.put(ctx.vault, SEALED_CEK_NS, envelopeKey, env)\n\n return { pid: hint.pid, envelopeKey }\n}\n\n/**\n * Revoke one sealed-CEK grant.\n *\n * **Default (`{ hard: false }`) is SOFT** — it only deletes the delivery\n * envelope from the store. A host that already fetched (or cached the unsealed\n * CEK from) that envelope KEEPS decrypt capability for the record; soft revoke\n * is a \"stop new fetches\" control, not a cryptographic cutoff.\n *\n * **`{ hard: true }`** additionally rotates the record's CEK (via\n * {@link rotateRecordCek}): the live body is re-encrypted under a fresh CEK and\n * EVERY sealed-CEK delivery envelope for the record (all pids) is deleted, so\n * any previously-sealed CEK fails the AES-GCM auth tag on the rotated body —\n * future opens are cryptographically denied. (PRE-rotation history versions,\n * which keep their old `_cek`, remain openable — same semantics as\n * `rotateRecordCek`.)\n */\nexport async function revokeSealedRecord(\n ctx: SealingContext,\n collection: string,\n id: string,\n pid: string,\n opts?: { hard?: boolean },\n): Promise<void> {\n if (opts?.hard === true) {\n // Hard revocation supersedes the single-pid soft delete: rotateRecordCek\n // re-keys the record and drops every delivery envelope for it.\n await rotateRecordCek(ctx, collection, id)\n return\n }\n await ctx.adapter.delete(ctx.vault, SEALED_CEK_NS, `${collection}/${id}/${pid}`)\n}\n\n/**\n * HARD-rotate a record's CEK: re-encrypt the live body under a fresh CEK, evict\n * caches, and delete EVERY sealed-CEK delivery envelope for the record. See\n * `vault.rotateRecordCek` for why this bypasses `Collection.put` (no guards, no\n * history bump — a key rotation must not re-encrypt prior history under the new\n * CEK).\n */\nexport async function rotateRecordCek(\n ctx: SealingContext,\n collection: string,\n id: string,\n): Promise<void> {\n const live = await ctx.adapter.get(ctx.vault, collection, id)\n if (!live || live._cek === undefined) {\n throw new RecordCekNotFoundError(collection, id)\n }\n\n const dek = await ctx.getDEK(collection)\n const oldCek = await unwrapCek(live._cek, dek)\n const json = await decrypt(live._iv, live._data, oldCek)\n\n const newCek = await generateDEK()\n const { iv, data } = await encrypt(json, newCek)\n\n // Sealed fields are keyed off the per-record CEK, so a rotation\n // must RE-ENCRYPT each `_sealed[field]` under the new CEK (carrying the old\n // slots forward would orphan them — the old CEK is gone after this rotate).\n // Dual-read the old slot: try the old-CEK-derived key, fall\n // back to the collection-DEK key (legacy), then re-seal under newCek.\n let sealedOut: Record<string, string> | undefined\n if (live._sealed !== undefined) {\n const out: Record<string, string> = {}\n for (const [field, slot] of Object.entries(live._sealed)) {\n const plaintext = await dualReadSealedSlot(slot, field, collection, oldCek, dek)\n const resealed = await encrypt(plaintext, await deriveSealedFieldKeyFromCek(newCek, collection, field))\n out[field] = `${resealed.iv}:${resealed.data}`\n }\n sealedOut = out\n }\n\n // Verify-digest slots are keyed off the per-record CEK too (I3: CEK-only,\n // no DEK fallback → single read, not a dual-read). Rotation must re-seal\n // each `_vdig[field]` under the new CEK with the SAME reconstructed AAD, or\n // the correct password would false-reject forever (C3).\n let vdigOut: Record<string, string> | undefined\n if (live._vdig !== undefined) {\n const out: Record<string, string> = {}\n for (const [field, blob] of Object.entries(live._vdig)) {\n const payload = await openVdigPayload(blob, oldCek, collection, id, field)\n out[field] = await sealVdigPayload(payload, newCek, collection, id, field)\n }\n vdigOut = out\n }\n\n const env: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: live._v + 1,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _cek: await wrapCek(newCek, dek),\n ...(ctx.actor ? { _by: ctx.actor } : {}),\n ...(live._tier !== undefined ? { _tier: live._tier } : {}),\n ...(live._det !== undefined ? { _det: live._det } : {}),\n // `_bidx` (equality-index tag) is DEK-rooted and CEK-independent, so it is\n // carried forward VERBATIM — not recomputed — unlike `_vdig`/`_sealed`\n // below, which are CEK-bound and must be re-sealed under the new CEK.\n // Dropping this line would silently orphan the equality index on rotation\n // (the #306 Slice-A data-loss bug, replayed on the index).\n ...(live._bidx !== undefined ? { _bidx: live._bidx } : {}),\n // Re-encrypt sealed (`sensitive`) fields under the new CEK. Sealed\n // keys derive off the per-record CEK, so the rotated record's old CEK is\n // destroyed here — carrying the old `_sealed` slots forward verbatim would\n // orphan them (unreadable under the new CEK). `sealedOut` holds the slots\n // dual-read from the old CEK (or the legacy DEK) and re-sealed under newCek.\n ...(sealedOut !== undefined ? { _sealed: sealedOut } : {}),\n ...(vdigOut !== undefined ? { _vdig: vdigOut } : {}),\n }\n await ctx.adapter.put(ctx.vault, collection, id, env)\n\n // Evict BOTH caches synchronously so no read returns the stale old-CEK record.\n await ctx.invalidateRecordCaches(collection, id)\n\n // Delete every sealed-CEK delivery envelope for this record — all pids.\n const prefix = `${collection}/${id}/`\n const keys = await ctx.adapter.list(ctx.vault, SEALED_CEK_NS)\n for (const key of keys) {\n if (key.startsWith(prefix)) {\n await ctx.adapter.delete(ctx.vault, SEALED_CEK_NS, key)\n }\n }\n}\n","/**\n * Deterministic-index lookups (`findByDet` / `queryByDet`).\n *\n * A collection that declares `deterministicFields` stamps a deterministic\n * AES-GCM ciphertext for each such field on the envelope's `_det` slot at write\n * time (the encrypt side lives in {@link RecordCodec.encryptRecord}). These\n * helpers are the READ side: recompute the deterministic ciphertext for a query\n * value and scan the adapter for envelopes whose `_det[field]` matches — no\n * record bodies are decrypted during the scan, which is the whole point of a\n * deterministic index.\n *\n * Both functions take a small {@link DeterministicContext} (the exact `this.*`\n * the moving methods touched) instead of `this`, mirroring the `record-keys/`\n * siblings. Behaviour is byte-identical to the inline code they replaced.\n * Elevated records (_tier > 0) are skipped: invisible to tier-0 scans (#691).\n *\n * Internal service — not exported as a `@noy-db/hub/*` subpath.\n */\nimport { encryptDeterministic, deriveDeterministicKey, type EnclaveKey } from '../crypto.js'\nimport type { NoydbStore } from '../../types.js'\nimport type { RecordCodec } from './record-codec.js'\n\n/** Everything the moving deterministic-index methods touched on `this.*`. */\nexport interface DeterministicContext<T> {\n /** Collection name — the deterministic-encryption AAD scope. */\n readonly name: string\n /** Vault namespace the records live under. */\n readonly vault: string\n /** The ciphertext store (scanned envelope-by-envelope). */\n readonly adapter: NoydbStore\n /** Declared deterministic-index fields, or null when the feature is off. */\n readonly deterministicFields: ReadonlySet<string> | null\n /** False on plaintext collections — det lookups are encrypted-only. */\n readonly storeCiphertext: boolean\n /** The collection DEK resolver. */\n getDEK(): Promise<EnclaveKey>\n /** The record codec — decrypts a matched envelope to T. */\n readonly codec: RecordCodec<T>\n}\n\n/**\n * Recompute the deterministic ciphertext targets for a query value.\n *\n * L-1: _det migrated to a dedicated HKDF key (salt noydb-det); dual-query\n * keeps pre-migration envelopes findable — they self-heal to the new key on\n * their next write. Index 0 is the current (derived-key) target, index 1 the\n * legacy raw-DEK target. Both are derived once per query call, not per\n * envelope, so the extra derivation is a fixed cost.\n */\nasync function detTargets<T>(ctx: DeterministicContext<T>, field: string, value: unknown): Promise<[string, string]> {\n const dek = await ctx.getDEK()\n const detKey = await deriveDeterministicKey(dek)\n const plaintext = typeof value === 'string' ? value : JSON.stringify(value)\n const context = `${ctx.name}/${field}`\n const [current, legacy] = await Promise.all([\n encryptDeterministic(plaintext, detKey, context),\n encryptDeterministic(plaintext, dek, context),\n ])\n return [`${current.iv}:${current.data}`, `${legacy.iv}:${legacy.data}`]\n}\n\nfunction assertDetField<T>(ctx: DeterministicContext<T>, field: string, method: string): void {\n if (!ctx.deterministicFields || !ctx.deterministicFields.has(field)) {\n throw new Error(\n `Collection \"${ctx.name}\": field \"${field}\" is not declared in deterministicFields`,\n )\n }\n if (!ctx.storeCiphertext) {\n throw new Error(\n `Collection \"${ctx.name}\": ${method} is only meaningful on encrypted collections`,\n )\n }\n}\n\n/**\n * Find the first record whose deterministic field matches the given plaintext.\n * Returns `null` when no match exists.\n *\n * Reads every envelope via the adapter and compares the stored `_det[field]` to\n * a freshly computed deterministic ciphertext — no record bodies are decrypted\n * during the search.\n *\n * Throws when the field is not declared in `deterministicFields`, so a typo\n * fails loudly at the call site rather than silently returning null forever.\n */\nexport async function findByDet<T>(ctx: DeterministicContext<T>, field: string, value: unknown): Promise<T | null> {\n assertDetField(ctx, field, 'findByDet')\n const [target, legacyTarget] = await detTargets(ctx, field, value)\n\n const ids = await ctx.adapter.list(ctx.vault, ctx.name)\n for (const id of ids) {\n const env = await ctx.adapter.get(ctx.vault, ctx.name, id)\n // #691: an elevated record's _det slot is tier-independent (#662 carries\n // it), so it MATCHES — but its key material is tier-wrapped. Skip it\n // explicitly: invisible to tier-0 det scans regardless of cekCache state\n // (a catch-based fix would still leak plaintext, audit-free, in the\n // session that performed the elevate).\n if (!env || !env._det || (env._tier ?? 0) > 0) continue\n if (env._det[field] === target || env._det[field] === legacyTarget) {\n return ctx.codec.decryptRecord(env, { id })\n }\n }\n return null\n}\n\n/**\n * Return every record whose deterministic field matches. Same semantics as\n * {@link findByDet} but without the short-circuit.\n */\nexport async function queryByDet<T>(ctx: DeterministicContext<T>, field: string, value: unknown): Promise<T[]> {\n assertDetField(ctx, field, 'queryByDet')\n const [target, legacyTarget] = await detTargets(ctx, field, value)\n\n const ids = await ctx.adapter.list(ctx.vault, ctx.name)\n const matches: T[] = []\n for (const id of ids) {\n const env = await ctx.adapter.get(ctx.vault, ctx.name, id)\n // #691: skip elevated — see findByDet above\n if (!env || !env._det || (env._tier ?? 0) > 0) continue\n if (env._det[field] === target || env._det[field] === legacyTarget) {\n const rec = await ctx.codec.decryptRecord(env, { id })\n if (rec !== null) matches.push(rec) // skip tombstone (defensive)\n }\n }\n return matches\n}\n","/**\n * Enclave body helpers — the C1 protected-body access contract.\n *\n * `EncryptedEnvelope` splits into a protocol header (family-owned; `_noydb`,\n * `_v`, `_ts`, `_by`, `_source`, `_sourceTs`, `_tier`, `_elevatedBy`) and a\n * protected body (enclave-owned; `_iv`, `_data`, `_cek`, `_det`, `_sealed`,\n * `_debug`). The four helpers below are the ONLY sanctioned way for code\n * outside `kernel/enclave/**` to read or construct the protected body —\n * later migration batches move the ~121 direct `_iv`/`_data`/`_cek`/`_sealed`\n * access sites in `with-*` services onto these.\n *\n * Each helper reproduces an EXISTING behavior byte-for-byte (see the\n * per-function doc for its oracle call site) — this file introduces no new\n * crypto or semantics, only a narrower door onto what already runs.\n */\nimport { encrypt, decrypt, generateDEK, wrapCek, unwrapCek, type EnclaveKey } from '../crypto.js'\nimport type { EncryptedEnvelope } from '../../types.js'\n\n/**\n * Open an envelope's protected body to its JSON text.\n *\n * Mirrors the dominant direct-decrypt call-site shape (e.g.\n * `with-audit/consent/consent.ts`'s `decryptEntry`):\n * - `opts.encrypted === false` (default `true`) → plaintext collection;\n * returns `env._data` as-is, `key` untouched.\n * - `env._cek` present → per-record-key envelope (mirrors\n * `record-codec.ts`'s `resolveEnvelopeCek`): unwrap the CEK under `key`\n * (the collection DEK), decrypt the body under the unwrapped CEK.\n * - `env._cek` absent → legacy path, decrypt the body directly under `key`.\n */\nexport async function openEnvelopeJson(\n env: EncryptedEnvelope,\n key: EnclaveKey,\n opts?: { encrypted?: boolean },\n): Promise<string> {\n if (opts?.encrypted === false) return env._data\n if (env._cek !== undefined) {\n const cek = await unwrapCek(env._cek, key)\n return decrypt(env._iv, env._data, cek)\n }\n return decrypt(env._iv, env._data, key)\n}\n\n/**\n * Produce the protected-body fields (`_iv`/`_data`/`_cek`) for an envelope a\n * caller is assembling.\n *\n * - `opts.encrypted === false` (default `true`) → plaintext collection;\n * emits `{ _iv: '', _data: json }` (today's `buildPlaintextEnvelope`\n * shape), `key` untouched.\n * - `opts.perRecordKey === true` → mints a fresh per-record CEK, encrypts\n * the body under it, and AES-KW-wraps the CEK under `key` (mirrors\n * `encryptJsonString`'s `cek !== undefined` branch, except the CEK is\n * generated here rather than supplied by the caller).\n * - otherwise → legacy path, body encrypted directly under `key`.\n */\nexport async function writeEnvelopeBody(\n json: string,\n key: EnclaveKey,\n opts?: { encrypted?: boolean; perRecordKey?: boolean },\n): Promise<Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>> {\n if (opts?.encrypted === false) return { _iv: '', _data: json }\n\n if (opts?.perRecordKey === true) {\n const cek = await generateDEK()\n const { iv, data } = await encrypt(json, cek)\n const wrapped = await wrapCek(cek, key)\n return { _iv: iv, _data: data, _cek: wrapped }\n }\n\n const { iv, data } = await encrypt(json, key)\n return { _iv: iv, _data: data }\n}\n\n/**\n * Approximate protected-body payload size for KPI/telemetry (#807's\n * period-scoped pull download counters): `_data` + `_iv` string length —\n * ≈ ciphertext bytes for base64 payloads, exact for plaintext (`_iv: ''`)\n * collections. A measuring door, not a crypto one: callers get a size\n * without touching the protected fields directly.\n */\nexport function envelopeBodySize(env: EncryptedEnvelope): number {\n return env._data.length + env._iv.length\n}\n\n/**\n * Discriminant: does this envelope carry a per-record key?\n *\n * Replaces raw `envelope._cek !== undefined` checks scattered across\n * services — `_cek` presence is the format discriminant (see\n * `record-codec.ts`'s `resolveEnvelopeCek` doc).\n */\nexport function hasPerRecordKey(env: EncryptedEnvelope): boolean {\n return env._cek !== undefined\n}\n\n/**\n * Canonical body string for the ledger hash chain — the exact bytes\n * `with-commit/history/ledger/hash.ts`'s `envelopePayloadHash` derives from\n * `_data` + `_sealed` + `_vdig` + `_bidx` before hashing:\n * - no `_sealed`, no `_vdig`, no `_bidx` → `_data` alone (back-compat: every\n * pre-existing ledger entry and non-sealed backup hashes byte-identically).\n * - any map present → canonical JSON of `{ _data, _sealed?, _vdig?, _bidx? }`\n * with sorted keys at every level, each map bound ONLY when present, so\n * the result is independent of the maps' field-insertion / store-\n * serialization order. `_bidx` is always the LAST segment, so a legacy\n * `_vdig`-only / `_bidx`-absent envelope hashes byte-identically to its\n * stage-2 value.\n *\n * Deliberately reimplements the two-key-object canonicalization inline\n * rather than importing `with-commit/history/ledger/entry.ts`'s general\n * `canonicalJson` — `kernel/enclave/**` may import only spine types (C3),\n * never a `with-*` service. For this fixed `{ _data: string; _sealed:\n * Record<string, string> }` shape the two produce byte-identical output\n * (verified against that exact call site's oracle expression in\n * `envelope-body.test.ts`).\n */\nexport function envelopeBodyForHash(env: EncryptedEnvelope): string {\n // Conditional widen (stage 2): bind `_vdig` exactly the way `_sealed` is\n // bound — only when present. No existing envelope carries `_vdig`, so this\n // ships with no flag-day PROVIDED it lands in the same slice as the first\n // `_vdig` writer (it does — Tasks 7/8/11 are one branch). This binding is\n // the temporal-rollback detector completing C1: AAD stops cross-record/\n // cross-field splices; the ledger hash catches same-slot rollbacks.\n //\n // Conditional widen (slice 2b, SM #5): bind `_bidx` the same way, appended\n // LAST (after `_vdig`) so a `_bidx`-absent envelope keeps its stage-2\n // byte-identical hash.\n if (env._sealed === undefined && env._vdig === undefined && env._bidx === undefined) return env._data\n const mapPart = (key: '_sealed' | '_vdig' | '_bidx', map: Record<string, string>): string => {\n const parts = Object.keys(map).sort().map(\n (k) => `${JSON.stringify(k)}:${JSON.stringify(map[k])}`,\n )\n return `${JSON.stringify(key)}:{${parts.join(',')}}`\n }\n const segments = [`\"_data\":${JSON.stringify(env._data)}`]\n if (env._sealed !== undefined) segments.push(mapPart('_sealed', env._sealed))\n if (env._vdig !== undefined) segments.push(mapPart('_vdig', env._vdig))\n if (env._bidx !== undefined) segments.push(mapPart('_bidx', env._bidx))\n return `{${segments.join(',')}}`\n}\n","/**\n * Credential-broker proof crypto (#479, credential-broker spec §3).\n *\n * The `_broker` seed (32 random bytes, decrypted from `_broker/<brokerId>` by\n * the party layer) is never transmitted. Instead, a **proof key** is\n * HKDF-derived from it, domain-separated per `(vaultId, brokerId)`, and the\n * derived bits are registered with the broker host once at enrol. Steady\n * state, the client re-derives the same key from the seed and signs a\n * **canonical** string binding the request's identity/context, so the broker\n * can verify a fresh HMAC on every mint without ever holding the seed itself.\n *\n * ## Derivation (spec §3, follow verbatim)\n *\n * ```\n * hkdf = importKey('raw', seed, 'HKDF', false, ['deriveBits'])\n * proofBits = deriveBits({ name:'HKDF', hash:'SHA-256',\n * salt: utf8(BROKER_PROOF_DOMAIN),\n * info: utf8(JSON.stringify([BROKER_PROOF_DOMAIN, vaultId, brokerId])) },\n * hkdf, 256)\n * proofKey = importKey('raw', proofBits, { name:'HMAC', hash:'SHA-256' }, false, ['sign'])\n * proof = base64(sign('HMAC', proofKey, utf8(canonical)))\n * ```\n *\n * `BROKER_PROOF_DOMAIN` is both the HKDF salt and the first `info` array\n * element (the injective-JSON-array convention `deriveClassifyIndexKey`\n * established — see `classify/bidx.ts`). `BROKER_PROOF_VERSION` is the\n * separate MAC version tag, the first element of the `canonical` array.\n *\n * ## Canonical (spec §2 step 3)\n *\n * `JSON.stringify([BROKER_PROOF_VERSION, vaultId, endpointOrigin, brokerId,\n * profile ?? '', instancePid ?? '', challenge, expiresAt])` — every binding\n * field folded into ONE MAC input:\n * - `vaultId` (V1), `challenge` (V3), `expiresAt` (V4) — verbatim strings,\n * never reparsed/reformatted (F8): a byte-identical ISO string is\n * required, so e.g. `Z` vs `+00:00` for the same instant fails.\n * - `profile ?? ''` (F1) — a proof captured at one profile cannot be\n * replayed at another.\n * - `endpointOrigin` (F4) — a proof cannot be relayed to a different broker\n * endpoint reusing the same `brokerId`.\n * - `instancePid ?? ''` (F7) — an EMPTY STRING `instancePid` is forbidden in\n * both {@link computeBrokerProof} and {@link verifyBrokerProof}: absent\n * (the field omitted) and `''` must stay distinguishable, or `?? ''`\n * would alias \"no instance\" onto a real registered instance.\n *\n * ## Verify order (spec §3, non-negotiable, F2/F6)\n *\n * {@link verifyBrokerProof} MUST, in this exact order: (1) burn the challenge\n * via `consumeChallenge` FIRST and short-circuit `false` before any MAC work\n * (F2 — burn-on-presentation, not burn-on-success); (2) recompute the\n * canonical and compare with `crypto.subtle.verify('HMAC', …)` — portable,\n * constant-time, never a manual byte compare or Node `timingSafeEqual` (F6);\n * (3) assert `now < expiresAt` — the client clock is never trusted, so this\n * check only matters once the MAC (which covers `expiresAt`) has verified.\n *\n * ## Zeroing (F5)\n *\n * `seed` and the transient HKDF output are raw, durable secret material —\n * the `recovery.ts:276-307` `try{}finally{secret.fill(0)}` discipline, not\n * the ephemeral-CEK happy-path zeroing elsewhere. {@link computeBrokerProof}\n * zeroes the `seed` argument in a `finally` on every path including a throw;\n * {@link deriveBrokerProofKey} zeroes its own transient HKDF-output bytes the\n * same way. {@link deriveBrokerProofBits} does not zero `seed` — it exists\n * so the party layer can register the raw bits at one-time enrol (the value\n * that must survive the call to be base64-encoded and POSTed).\n *\n * @module\n */\nimport type { EnclaveKey } from '../crypto.js'\nimport { base64ToBuffer, bufferToBase64 } from '../crypto.js'\nimport { ValidationError } from '../../errors.js'\n\nconst subtle = globalThis.crypto.subtle\n\n/** HKDF salt domain for the broker proof key — also the first `info` array element. */\nexport const BROKER_PROOF_DOMAIN = 'noydb-broker-proof'\n\n/** MAC version tag — the first element of the `canonical` array signed/verified. */\nexport const BROKER_PROOF_VERSION = 'noydb-broker-proof-v1'\n\n/** Default challenge TTL (spec §2 step 2: \"TTL ≤ 60 s\"). */\nconst DEFAULT_CHALLENGE_TTL_MS = 60_000\n\n/** The canonical-binding fields a client supplies alongside `vaultId`/`brokerId` (spec §2 step 3). */\nexport interface BrokerProofCanonicalParts {\n readonly endpointOrigin: string\n readonly profile?: string | undefined\n readonly instancePid?: string | undefined\n readonly challenge: string\n readonly expiresAt: string\n}\n\n/** A freshly-minted, server-random single-use challenge (spec §2 step 2). */\nexport interface IssuedChallenge {\n readonly challenge: string\n readonly expiresAt: string\n}\n\n/** Arguments the broker host passes to verify a submitted proof (spec §3). */\nexport interface VerifyBrokerProofArgs {\n /**\n * Atomically test-and-delete the challenge, returning whether it was still\n * fresh (unconsumed and unexpired-from-the-store's-perspective). MUST burn\n * on presentation, not on successful verification (F2).\n */\n readonly consumeChallenge: (challenge: string) => Promise<boolean>\n /** The registered proof key's raw bytes, already KMS-unwrapped by the host (§7). */\n readonly registeredProofKey: Uint8Array\n readonly vaultId: string\n readonly endpointOrigin: string\n readonly brokerId: string\n readonly profile?: string | undefined\n readonly instancePid?: string | undefined\n readonly challenge: string\n readonly expiresAt: string\n /** base64(HMAC-SHA-256(proofKey, canonical)), as submitted by the client. */\n readonly proof: string\n}\n\n/** Build the canonical MAC input verbatim — never reparses/reformats a field (F8). */\nfunction buildCanonical(vaultId: string, brokerId: string, parts: BrokerProofCanonicalParts): string {\n return JSON.stringify([\n BROKER_PROOF_VERSION,\n vaultId,\n parts.endpointOrigin,\n brokerId,\n parts.profile ?? '',\n parts.instancePid ?? '',\n parts.challenge,\n parts.expiresAt,\n ])\n}\n\n/**\n * The HKDF step: derive the 256-bit proof bits from the `_broker` seed,\n * domain-separated per `(vaultId, brokerId)`. Returns the raw bits — the\n * value registered with the broker host once at enrol (spec §2 step 2/3).\n * Does not mutate or zero `seed`; the caller owns the seed's lifecycle.\n */\nexport async function deriveBrokerProofBits(\n seed: Uint8Array,\n vaultId: string,\n brokerId: string,\n): Promise<Uint8Array> {\n const hkdfKey = await subtle.importKey('raw', seed as BufferSource, 'HKDF', false, ['deriveBits'])\n const salt = new TextEncoder().encode(BROKER_PROOF_DOMAIN)\n const info = new TextEncoder().encode(JSON.stringify([BROKER_PROOF_DOMAIN, vaultId, brokerId]))\n const bits = await subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt, info }, hkdfKey, 256)\n return new Uint8Array(bits)\n}\n\n/**\n * Derive the steady-state, non-extractable `['sign']` HMAC proof key from\n * the `_broker` seed. Zeroes the transient HKDF-output bytes in a `finally`\n * once the key has been imported (F5) — the raw bits never leave this\n * function in usable form after import.\n */\nexport async function deriveBrokerProofKey(\n seed: Uint8Array,\n vaultId: string,\n brokerId: string,\n): Promise<EnclaveKey> {\n const proofBits = await deriveBrokerProofBits(seed, vaultId, brokerId)\n try {\n return await subtle.importKey('raw', proofBits as BufferSource, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign'])\n } finally {\n proofBits.fill(0)\n }\n}\n\n/**\n * Compose derive + sign for the client: re-derive the proof key from the\n * seed and sign the canonical over `canonicalParts` (spec §2 step 3).\n *\n * Rejects an empty-string `instancePid` (F7 — absent is fine, `''` is not).\n * Zeroes the `seed` argument in a `finally` on EVERY path including a throw\n * (F5, durable-secret discipline) — the transient HKDF bits are zeroed one\n * layer down, inside {@link deriveBrokerProofKey}.\n */\nexport async function computeBrokerProof(\n seed: Uint8Array,\n vaultId: string,\n brokerId: string,\n canonicalParts: BrokerProofCanonicalParts,\n): Promise<string> {\n try {\n if (canonicalParts.instancePid === '') {\n throw new ValidationError(\n \"computeBrokerProof: instancePid must not be an empty string — omit the field entirely for \" +\n \"'no instance' (F7); '' would alias onto a registered instance.\",\n )\n }\n const canonical = buildCanonical(vaultId, brokerId, canonicalParts)\n const key = await deriveBrokerProofKey(seed, vaultId, brokerId)\n const mac = await subtle.sign('HMAC', key, new TextEncoder().encode(canonical) as BufferSource)\n return bufferToBase64(new Uint8Array(mac))\n } finally {\n seed.fill(0)\n }\n}\n\n/**\n * Host-side nonce mint: 32 random bytes, base64-encoded, plus an ISO\n * `expiresAt` at most `ttlMs` (default 60 s) in the future. The caller\n * (the broker host) persists both returned strings **verbatim** and MACs\n * those exact bytes on verify — never a reparsed/reformatted copy (F8).\n */\nexport function issueChallenge(opts?: { ttlMs?: number }): IssuedChallenge {\n const ttlMs = opts?.ttlMs ?? DEFAULT_CHALLENGE_TTL_MS\n const bytes = globalThis.crypto.getRandomValues(new Uint8Array(32))\n return {\n challenge: bufferToBase64(bytes),\n expiresAt: new Date(Date.now() + ttlMs).toISOString(),\n }\n}\n\n/**\n * Verify a submitted broker proof. Order is NON-NEGOTIABLE (spec §3):\n *\n * 1. `await consumeChallenge(challenge)` FIRST — burn-and-check-fresh; a\n * not-fresh (already-consumed or unknown) challenge short-circuits to\n * `false` before any MAC work (F2).\n * 2. Empty-string `instancePid` is rejected (F7), then the canonical is\n * recomputed over the verbatim `endpointOrigin`/`brokerId`/`profile`/\n * `instancePid`/`challenge`/`expiresAt` and compared via\n * `crypto.subtle.verify('HMAC', …)` — portable, constant-time, never a\n * manual compare or Node `timingSafeEqual` (F6).\n * 3. `now < expiresAt` — the client clock is never trusted; `expiresAt`\n * rides inside the already-verified MAC (F4/F8).\n */\nexport async function verifyBrokerProof(args: VerifyBrokerProofArgs): Promise<boolean> {\n const fresh = await args.consumeChallenge(args.challenge)\n if (!fresh) return false\n\n if (args.instancePid === '') return false\n\n const canonical = buildCanonical(args.vaultId, args.brokerId, {\n endpointOrigin: args.endpointOrigin,\n profile: args.profile,\n instancePid: args.instancePid,\n challenge: args.challenge,\n expiresAt: args.expiresAt,\n })\n const key = await subtle.importKey(\n 'raw',\n args.registeredProofKey as BufferSource,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['verify'],\n )\n const ok = await subtle.verify(\n 'HMAC',\n key,\n base64ToBuffer(args.proof) as BufferSource,\n new TextEncoder().encode(canonical) as BufferSource,\n )\n if (!ok) return false\n\n return Date.now() < Date.parse(args.expiresAt)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,eAAsB,iBAAiB,MAAqB,IAAiC;AAC3F,QAAM,SAAS,KAAK,OAAO,IAAI,EAAE;AACjC,MAAI,OAAQ,QAAO;AAEnB,QAAM,OAAO,MAAM,KAAK,QAAQ,EAAE;AAClC,MAAI,MAAM,SAAS,QAAW;AAC5B,UAAM,MAAM,MAAM,UAAU,KAAK,MAAM,MAAM,KAAK,OAAO,CAAC;AAC1D,SAAK,OAAO,IAAI,IAAI,KAAK,CAAC;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,YAAY;AAChC,OAAK,OAAO,IAAI,IAAI,OAAO,CAAC;AAC5B,SAAO;AACT;AAqBA,eAAsB,gBACpB,UACA,SACA,OACwB;AACxB,MAAI,SAAS,SAAS,QAAW;AAC/B,UAAM,MAAM,MAAM,UAAU,SAAS,MAAM,OAAO;AAClD,UAAMA,aAAY,MAAM,QAAQ,SAAS,KAAK,SAAS,OAAO,GAAG;AACjE,UAAM,EAAE,IAAAC,KAAI,MAAAC,MAAK,IAAI,MAAM,QAAQF,YAAW,GAAG;AACjD,WAAO,EAAE,KAAKC,KAAI,OAAOC,OAAM,MAAM,MAAM,QAAQ,KAAK,KAAK,GAAG,IAAI;AAAA,EACtE;AACA,QAAM,YAAY,MAAM,QAAQ,SAAS,KAAK,SAAS,OAAO,OAAO;AACrE,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,WAAW,KAAK;AACnD,SAAO,EAAE,KAAK,IAAI,OAAO,MAAM,KAAK,KAAK;AAC3C;AAcO,SAAS,mBAAmB,UAA6B,MAAwC;AACtG,QAAM,OAA0B;AAAA,IAC9B,GAAG;AAAA,IACH,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,EACvD;AACA,MAAI,KAAK,SAAS,UAAa,SAAS,SAAS,QAAW;AAC1D,WAAQ,KAA2B;AAAA,EACrC;AACA,SAAO;AACT;AAUA,eAAsB,eACpB,UACA,SACA,OAC4B;AAC5B,SAAO,mBAAmB,UAAU,MAAM,gBAAgB,UAAU,SAAS,KAAK,CAAC;AACrF;AA6BA,eAAsB,iBACpB,UACA,KACkB;AAClB,MAAI;AACF,QAAI,SAAS,SAAS,QAAW;AAC/B,YAAM,UAAU,SAAS,MAAM,GAAG;AAAA,IACpC,OAAO;AACL,YAAM,QAAQ,SAAS,KAAK,SAAS,OAAO,GAAG;AAAA,IACjD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC9HA,eAAe,oBACb,OACA,OACA,KACA,aACwB;AACxB,QAAM,WAAW,YAAY,QAAQ,SACjC,MAAM,4BAA4B,YAAY,KAAK,YAAY,YAAY,KAAK,IAChF,MAAM,qBAAqB,KAAK,YAAY,YAAY,KAAK;AACjE,SAAO,QAAQ,KAAK,UAAU,KAAK,GAAG,QAAQ;AAChD;AASA,eAAe,aACb,OACA,OACA,aACwB;AACxB,QAAM,MAAM,MAAM,YAAY,OAAO;AACrC,SAAO,oBAAoB,OAAO,OAAO,KAAK,WAAW;AAC3D;AAUA,eAAsB,WACpB,QACA,iBACA,aAC2B;AAC3B,QAAM,MAAM,MAAM,YAAY,OAAO;AACrC,QAAM,OAAgC,EAAE,GAAG,OAAO;AAClD,QAAM,QAAgC,CAAC;AACvC,aAAW,SAAS,iBAAiB;AACnC,QAAI,EAAE,SAAS,QAAS;AACxB,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,UAAU,OAAW;AACzB,UAAM,EAAE,IAAI,KAAK,IAAI,MAAM,oBAAoB,OAAO,OAAO,KAAK,WAAW;AAC7E,UAAM,KAAK,IAAI,GAAG,EAAE,IAAI,IAAI;AAC5B,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,MAAI,OAAO,KAAK,KAAK,EAAE,WAAW,EAAG,QAAO,EAAE,YAAY,QAAQ,QAAQ,OAAU;AACpF,SAAO,EAAE,YAAY,MAAM,QAAQ,MAAM;AAC3C;AASA,eAAsB,eAAe,OAAe,MAAc,aAAgD;AAChH,QAAM,MAAM,MAAM,YAAY,OAAO;AACrC,SAAO,KAAK,MAAM,MAAM,mBAAmB,MAAM,OAAO,YAAY,YAAY,YAAY,KAAK,GAAG,CAAC;AACvG;AAUO,SAAS,mBAAmB,aAAsF;AACvH,SAAO,CAAC,OAAO,SAAS,IAAI,aAAa,MAAM,eAAe,OAAO,MAAM,WAAW,CAAC;AACzF;AAUA,eAAsB,aACpB,QACA,QACA,aACA,MACkC;AAClC,QAAM,aAAa,MAAM,cAAc,OAAO,mBAAmB,WAAW,IAAI;AAChF,aAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,WAAO,KAAK,IAAI,eAAe,SAAY,WAAW,OAAO,IAAI,IAAI,MAAM,eAAe,OAAO,MAAM,WAAW;AAAA,EACpH;AACA,SAAO;AACT;AAmCO,SAAS,yBACd,KACA,UACA,KAC6B;AAC7B,QAAM,cAA+B;AAAA,IACnC,YAAY,IAAI;AAAA,IAChB,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC;AAAA,IACnC,QAAQ,MAAM,IAAI,OAAO;AAAA,EAC3B;AACA,QAAM,gBAAgB,oBAAI,IAAY;AAEtC,SAAO;AAAA,IACL,MAAM,KAAK,OAAO,WAAW;AAC3B,YAAM,MAAM,MAAM,aAAa,OAAO,WAAW,WAAW;AAC5D,oBAAc,OAAO,KAAK;AAC1B,aAAO;AAAA,IACT;AAAA,IACA,MAAM,OAAO,OAAO,KAAK;AACvB,UAAI,cAAc,IAAI,KAAK,GAAG;AAC5B,cAAM,IAAI,gBAAgB,8BAA8B,KAAK,gBAAgB,QAAQ,oCAAoC;AAAA,MAC3H;AACA,aAAO,eAAe,OAAO,GAAG,IAAI,EAAE,IAAI,IAAI,IAAI,IAAI,WAAW;AAAA,IACnE;AAAA,IACA,MAAM,OAAO,OAAO;AAClB,oBAAc,IAAI,KAAK;AAAA,IACzB;AAAA,EACF;AACF;AAmBO,SAAS,sBACd,aACA,kBACmC;AACnC,QAAM,WAAW,IAAI,IAAI,gBAAgB;AAEzC,SAAO,CAAC,WAAmB;AACzB,QAAI,CAAC,SAAS,IAAI,MAAM,GAAG;AACzB,YAAM,IAAI,gBAAgB,8BAA8B,MAAM,sDAAsD;AAAA,IACtH;AAEA,UAAM,iBAAiB,CAAC,YAAoB,WAAwC;AAClF,UAAI,CAAC,WAAW,WAAW,MAAM,GAAG;AAClC,cAAM,IAAI;AAAA,UACR,sBAAsB,MAAM,MAAM,MAAM,iBAAiB,UAAU,0BAA0B,MAAM;AAAA,QACrG;AAAA,MACF;AAAA,IACF;AAEA,UAAM,mBAAmB,OAAO,YAAoB,MAAc,MAA0C;AAC1G,qBAAe,YAAY,SAAS;AACpC,YAAM,MAAM,MAAM,YAAY,UAAU;AACxC,YAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,MAAM,GAAG;AAC5C,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,IAAI;AAAA,QACJ,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,QAC5B,KAAK;AAAA,QACL,OAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,mBAAmB,OAAO,YAAoB,QAA4C;AAC9F,qBAAe,YAAY,SAAS;AACpC,YAAM,MAAM,MAAM,YAAY,UAAU;AACxC,aAAO,QAAQ,IAAI,KAAK,IAAI,OAAO,GAAG;AAAA,IACxC;AAEA,WAAO,EAAE,SAAS,kBAAkB,SAAS,iBAAiB;AAAA,EAChE;AACF;;;AC9PA,eAAsB,aACpB,UACA,QACA,UACA,KACA,YACA,UACA,OACiB;AACjB,QAAM,aAAa,mBAAmB,OAAO,WAAW,QAAQ;AAEhE,MAAI,OAA2B;AAC/B,MAAI,aAAa,QAAW;AAC1B,QAAI;AACF,aAAO,MAAM,gBAAgB,UAAU,KAAK,YAAY,UAAU,KAAK;AAAA,IACzE,QAAQ;AAIN,YAAM,IAAI,cAAc;AAAA,IAC1B;AACA,QAAI,CAAC,OAAO,UAAU,KAAK,IAAI,KAAK,KAAK,OAAO,GAAG;AAGjD,YAAM,IAAI,cAAc;AAAA,IAC1B;AAAA,EACF;AAKA,MAAI,SAAS,QAAQ,OAAO,WAAW,GAAG;AACxC,UAAM,UAAsC,CAAC,KAAK,KAAK,GAAI,KAAK,QAAQ,CAAC,CAAE;AAC3E,eAAW,SAAS,SAAS;AAC3B,YAAM,SAAS,MAAM,mBAAmB,YAAY,eAAe,MAAM,IAAI,GAAG,KAAK,IAAI;AACzF,UAAI,MAAM,aAAa,QAAQ,eAAe,MAAM,IAAI,CAAC,GAAG;AAC1D,cAAM,IAAI,wBAAwB,YAAY,OAAO,4BAA4B;AAAA,MACnF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO,aAAa;AAC1B,QAAM,OAAO,MAAM,mBAAmB,YAAY,MAAM,eAAe;AACvE,QAAM,OAAO,SAAS,QAAQ,OAAO,WAAW,IAC5C,CAAC,GAAI,KAAK,QAAQ,CAAC,GAAI,EAAE,MAAM,KAAK,IAAI,MAAM,MAAM,KAAK,IAAI,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,QAAQ,IAC3F;AAEJ,QAAM,UAAuB;AAAA,IAC3B,GAAG;AAAA,IACH,KAAK;AAAA,IACL,MAAM;AAAA,IACN,KAAK,EAAE,MAAM,eAAe,IAAI,GAAG,MAAM,eAAe,IAAI,GAAG,KAAI,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,IAC5F,GAAI,SAAS,UAAa,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,EAC1D;AACA,SAAO,gBAAgB,SAAS,KAAK,YAAY,UAAU,KAAK;AAClE;;;ACiEA,eAAsB,oBACpB,QACA,OACA,SACiB;AACjB,QAAM,SAAS,MAAM,OAAO,WAAW,EAAE,SAAS,KAAK;AACvD,MAAI,OAAO,WAAW,UAAa,OAAO,OAAO,SAAS,GAAG;AAC3D,UAAM,IAAI;AAAA,MACR,+BAA+B,OAAO,KAAK,gBAAgB,OAAO,MAAM,CAAC;AAAA,MACzE,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO;AAChB;AAcA,eAAsB,qBACpB,QACA,OACA,SACiB;AACjB,QAAM,SAAS,MAAM,OAAO,WAAW,EAAE,SAAS,KAAK;AACvD,MAAI,OAAO,WAAW,UAAa,OAAO,OAAO,SAAS,GAAG;AAC3D,UAAM,IAAI;AAAA,MACR,mBAAmB,OAAO,2DACP,gBAAgB,OAAO,MAAM,CAAC;AAAA,MACjD,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO;AAChB;AAWA,SAAS,gBACP,QACQ;AACR,QAAM,QAAQ,OAAO,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU;AAC9C,UAAM,UAAU,WAAW,MAAM,IAAI;AACrC,WAAO,GAAG,OAAO,KAAK,MAAM,OAAO;AAAA,EACrC,CAAC;AACD,QAAM,SAAS,OAAO,SAAS,IAAI,MAAM,OAAO,SAAS,CAAC,WAAW;AACrE,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAEA,SAAS,WACP,MACQ;AACR,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AACvC,SAAO,KACJ;AAAA,IAAI,CAAC,YACJ,OAAO,YAAY,YAAY,YAAY,OACvC,OAAO,QAAQ,GAAG,IAClB,OAAO,OAAO;AAAA,EACpB,EACC,KAAK,GAAG;AACb;;;ACrGO,IAAM,cAAN,MAAM,aAAe;AAAA,EAC1B,YAA6B,KAA4B;AAA5B;AAAA,EAA6B;AAAA,EAA7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS7B,OAAO,KAAoC;AACzC,SAAK,IAAI,MAAM;AAAA,EACjB;AAAA;AAAA,EAGQ,gBAAgB,KAA8C;AACpE,WAAO;AAAA,MACL,YAAY,KAAK,IAAI;AAAA,MACrB,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC;AAAA,MACnC,QAAQ,MAAM,KAAK,IAAI,OAAO;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaQ,aAAa,UAAkB,KAA2C;AAChF,UAAM,mBAAmB,KAAK,IAAI,KAAK,SAAS,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,KAAK,CAAC;AAC7F,WAAO;AAAA,MACL,aAAa,yBAAyB,KAAK,KAAK,UAAU,GAAG;AAAA,MAC7D,mBAAmB,sBAAsB,CAAC,eAAe,KAAK,IAAI,OAAO,UAAU,GAAG,gBAAgB;AAAA,IACxG;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,cAAc,GAQC;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,IAAI,EAAE;AAAA,MACN,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC5B,KAAK,EAAE;AAAA,MACP,OAAO,EAAE;AAAA,MACT,GAAI,EAAE,OAAO,SAAY,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MAC1C,GAAI,EAAE,QAAQ,SAAY,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC;AAAA,MAC7C,GAAI,EAAE,eAAe,SAAY,EAAE,SAAS,EAAE,WAAW,QAAQ,WAAW,EAAE,WAAW,SAAS,IAAI,CAAC;AAAA,MACvG,GAAI,EAAE,SAAS,CAAC;AAAA,IAClB;AAAA,EACF;AAAA;AAAA,EAGA,OAAO,uBAAuB,GAKR;AACpB,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,IAAI,EAAE;AAAA,MACN,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC5B,KAAK;AAAA,MACL,OAAO,EAAE;AAAA,MACT,GAAI,EAAE,OAAO,SAAY,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;AAAA,MAC1C,GAAI,EAAE,eAAe,SAAY,EAAE,SAAS,EAAE,WAAW,QAAQ,WAAW,EAAE,WAAW,SAAS,IAAI,CAAC;AAAA,IACzG;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,mBAAmB,QAAW,SAAiB,QAAiB,UAAsC;AACpG,UAAM,MAAM;AACZ,eAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAClC,UAAI,IAAI,WAAW,GAAG,EAAG,OAAM,IAAI,wBAAwB,KAAK,IAAI,MAAM,GAAG;AAAA,IAC/E;AACA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,IAAI;AAAA,MACJ,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC5B,KAAK;AAAA,MACL,OAAO;AAAA,MACP,KAAK,KAAK,IAAI;AAAA,MACd,QAAQ;AAAA,MACR,GAAI,KAAK,IAAI,cAAc,WAAW,SAAY,EAAE,SAAS,QAAQ,WAAW,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE,IAAI,CAAC;AAAA,MAC1H,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,kBACJ,MACA,SACA,KACA,QACA,UAC4B;AAC5B,UAAM,KAAK,KAAK,IAAI;AACpB,UAAM,aAAa,KAAK,IAAI,cAAc,WAAW,SACjD,EAAE,QAAQ,UAAU,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE,IACzD;AAEJ,QAAI,CAAC,KAAK,IAAI,iBAAiB;AAC7B,aAAO,aAAY,uBAAuB,EAAE,SAAS,MAAM,MAAM,IAAI,WAAW,CAAC;AAAA,IACnF;AAEA,UAAM,MAAM,MAAM,KAAK,IAAI,OAAO;AAElC,QAAI,QAAQ,QAAW;AACrB,YAAM,EAAE,IAAAC,KAAI,MAAAC,MAAK,IAAI,MAAM,QAAQ,MAAM,GAAG;AAC5C,YAAM,UAAU,MAAM,QAAQ,KAAK,GAAG;AACtC,aAAO,aAAY,cAAc,EAAE,SAAS,IAAAD,KAAI,MAAAC,OAAM,IAAI,KAAK,SAAS,WAAW,CAAC;AAAA,IACtF;AAEA,UAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,MAAM,GAAG;AAC5C,WAAO,aAAY,cAAc,EAAE,SAAS,IAAI,MAAM,IAAI,WAAW,CAAC;AAAA,EACxE;AAAA,EAEA,MAAM,cACJ,QACA,SACA,KACA,QACA,UACA,MACA,IAC4B;AAK5B,QAAI,CAAC,KAAK,IAAI,mBAAmB,KAAK,IAAI,kBAAkB,CAAC,KAAK,IAAI,KAAK,WAAW,GAAG,GAAG;AAC1F,aAAO,KAAK,mBAAmB,QAAQ,SAAS,QAAQ,QAAQ;AAAA,IAClE;AAqBA,QAAI,KAAK,IAAI,iBAAiB;AAC5B,YAAM,WAAW,KAAK,IAAI;AAC1B,YAAM,mBAAmB,oBAAI,IAAY;AACzC,UAAI,MAAM,MAAM,MAAO,YAAW,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK,EAAG,kBAAiB,IAAI,CAAC;AAC3F,UAAI,MAAM,MAAM,MAAO,YAAW,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK,EAAG,kBAAiB,IAAI,CAAC;AAC3F,UAAI,KAAK,IAAI,+BAA+B,QAAW;AACrD,mBAAW,KAAK,MAAM,KAAK,IAAI,2BAA2B,EAAG,kBAAiB,IAAI,CAAC;AAAA,MACrF;AACA,UAAI;AACJ,iBAAW,SAAS,kBAAkB;AACpC,YAAI,aAAa,QAAQ,CAAC,SAAS,IAAI,KAAK,GAAG;AAAE,uBAAa;AAAO;AAAA,QAAM;AAAA,MAC7E;AACA,UAAI,eAAe,QAAW;AAC5B,cAAM,IAAI;AAAA,UACR,KAAK,IAAI;AAAA,UACT,qDAAqD,UAAU;AAAA,QAEjE;AAAA,MACF;AAAA,IACF;AAiBA,QAAI,aAAa;AACjB,QAAI;AACJ,QAAI,KAAK,IAAI,mBAAmB,KAAK,IAAI,KAAK,gBAAgB;AAC5D,UAAI,OAAO,QAAW;AACpB,cAAM,IAAI;AAAA,UACR,0CAA0C,KAAK,IAAI,IAAI;AAAA,QAEzD;AAAA,MACF;AACA,YAAM,MAAM;AACZ,YAAM,SAAS,MAAM,KAAK,IAAI,IAAI,aAAa,KAAK,KAAK,aAAa,IAAI,GAAG,CAAC;AAC9E,mBAAa,OAAO;AACpB,UAAI,OAAO,WAAW,QAAW;AAC/B,iBAAS,CAAC;AACV,mBAAW,CAAC,OAAO,GAAG,KAAK,OAAO,QAAQ,OAAO,MAAM,EAAG,QAAO,KAAK,IAAI,GAAG,IAAI,EAAE,IAAI,IAAI,IAAI;AAAA,MACjG;AAAA,IACF,WAAW,KAAK,IAAI,mBAAmB,KAAK,IAAI,gBAAgB,OAAO,GAAG;AACxE,YAAM,MAAM;AACZ,YAAM,SAAS,MAAM,WAAW,KAAK,KAAK,IAAI,iBAAiB,KAAK,gBAAgB,GAAG,CAAC;AACxF,UAAI,OAAO,WAAW,QAAW;AAC/B,iBAAS,OAAO;AAChB,qBAAa,OAAO;AAAA,MACtB;AAAA,IACF;AAMA,QAAI;AACJ,QAAI;AACJ,QAAI,KAAK,IAAI,eAAe,QAAQ,KAAK,IAAI,WAAW,OAAO,KAAK,KAAK,IAAI,iBAAiB;AAC5F,UAAI,SAAS,QAAW;AACtB,cAAM,IAAI;AAAA,UACR,0CAA0C,KAAK,IAAI,IAAI;AAAA,QAEzD;AAAA,MACF;AACA,UAAI,QAAQ,QAAW;AACrB,cAAM,IAAI;AAAA,UACR,4GACe,KAAK,IAAI,IAAI;AAAA,QAC9B;AAAA,MACF;AACA,YAAM,OAAgC,EAAE,GAAI,WAAkD;AAC9F,YAAM,MAA8B,CAAC;AAKrC,YAAM,UAAkC,CAAC;AACzC,UAAI;AACJ,iBAAW,CAAC,OAAO,MAAM,KAAK,KAAK,IAAI,YAAY;AACjD,cAAM,QAAQ,KAAK,KAAK;AACxB,cAAM,WAAW,KAAK,MAAM,QAAQ,KAAK;AACzC,YAAI,KAAK,MAAM,UAAU,KAAK,MAAM,QAAW;AAM7C,gBAAM,IAAI;AAAA,YACR,KAAK,IAAI;AAAA,YACT,UAAU,KAAK;AAAA,UAEjB;AAAA,QACF;AACA,YAAI,UAAU,QAAW;AAQvB,cAAI,aAAa,QAAW;AAC1B,gBAAI,KAAK,IAAI;AACb,kBAAM,UAAU,KAAK,MAAM,QAAQ,KAAK;AACxC,gBAAI,YAAY,OAAW,SAAQ,KAAK,IAAI;AAAA,UAC9C;AACA;AAAA,QACF;AACA,YAAI,UAAU,MAAM;AAElB,iBAAO,KAAK,KAAK;AACjB;AAAA,QACF;AACA,YAAI,OAAO,UAAU,UAAU;AAE7B,gBAAM,IAAI;AAAA,YACR,iCAAiC,KAAK,SAAS,KAAK,IAAI,IAAI,oDAAoD,OAAO,KAAK;AAAA,UAC9H;AAAA,QACF;AAEA,YAAI,KAAK,IAAI,MAAM,aAAa,OAAO,QAAQ,UAAU,KAAK,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK;AAO3F,YAAI,OAAO,cAAc,MAAM;AAC7B,cAAI,YAAY,OAAW,WAAU,MAAM,KAAK,IAAI,OAAO;AAC3D,gBAAM,aAAa,mBAAmB,OAAO,WAAW,KAAK;AAC7D,kBAAQ,KAAK,IAAI,MAAM,YAAY,YAAY,SAAS,KAAK,IAAI,MAAM,KAAK;AAAA,QAC9E;AACA,eAAO,KAAK,KAAK;AAAA,MACnB;AACA,mBAAa;AACb,UAAI,OAAO,KAAK,GAAG,EAAE,SAAS,EAAG,WAAU;AAC3C,UAAI,OAAO,KAAK,OAAO,EAAE,SAAS,EAAG,cAAa;AAAA,IACpD;AAEA,UAAM,OAAO,MAAM,KAAK,kBAAkB,KAAK,UAAU,UAAU,GAAG,SAAS,KAAK,QAAQ,QAAQ;AACpG,UAAM,aAAa,SAAS,EAAE,GAAG,MAAM,SAAS,OAAO,IAAI;AAC3D,UAAM,WAAW,UAAU,EAAE,GAAG,YAAY,OAAO,QAAQ,IAAI;AAC/D,UAAM,WAAW,aAAa,EAAE,GAAG,UAAU,OAAO,WAAW,IAAI;AACnE,QAAI,CAAC,KAAK,IAAI,uBAAuB,CAAC,KAAK,IAAI,gBAAiB,QAAO;AASvE,UAAM,MAAM,MAAM,KAAK,IAAI,OAAO;AAClC,UAAM,SAAS,MAAM,uBAAuB,GAAG;AAC/C,UAAM,MAAM;AACZ,UAAM,MAA8B,CAAC;AACrC,eAAW,SAAS,KAAK,IAAI,qBAAqB;AAChD,UAAI,KAAK,IAAI,gBAAgB,IAAI,KAAK,EAAG;AACzC,UAAI,KAAK,IAAI,YAAY,IAAI,KAAK,EAAG;AACrC,YAAM,QAAQ,IAAI,KAAK;AACvB,UAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,YAAM,YAAY,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AAC1E,YAAM,EAAE,IAAI,KAAK,IAAI,MAAM,qBAAqB,WAAW,QAAQ,GAAG,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE;AAC9F,UAAI,KAAK,IAAI,GAAG,EAAE,IAAI,IAAI;AAAA,IAC5B;AACA,QAAI,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG,QAAO;AAC1C,WAAO,EAAE,GAAG,UAAU,MAAM,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,mBAAmB,UAA6B,IAA8C;AAClG,QAAI,SAAS,SAAS,OAAW,QAAO;AACxC,UAAM,SAAS,OAAO,SAAY,KAAK,IAAI,UAAU,IAAI,EAAE,IAAI;AAC/D,QAAI,WAAW,OAAW,QAAO;AACjC,UAAM,MAAM,MAAM,KAAK,IAAI,OAAO;AAClC,UAAM,MAAM,MAAM,UAAU,SAAS,MAAM,GAAG;AAC9C,QAAI,OAAO,OAAW,MAAK,IAAI,UAAU,IAAI,IAAI,KAAK,CAAC;AACvD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,MAAM,kBAAkB,UAA6B,IAAqC;AAOxF,QAAI,YAAY,UAAU,KAAK,IAAI,eAAe,KAAK,eAAe,QAAQ,EAAG,QAAO;AACxF,QAAI,CAAC,KAAK,IAAI,iBAAiB;AAK7B,UAAI,SAAS,WAAW,QAAW;AACjC,cAAM,MAA+B,CAAC;AACtC,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,cAAI,CAAC,IAAI,WAAW,GAAG,EAAG,KAAI,GAAG,IAAI;AAAA,QACvC;AACA,eAAO,KAAK,UAAU,GAAG;AAAA,MAC3B;AAOA,aAAO,SAAS,UAAU,KAAK,OAAO,SAAS;AAAA,IACjD;AACA,UAAM,MAAM,MAAM,KAAK,mBAAmB,UAAU,EAAE;AACtD,QAAI,QAAQ,OAAW,QAAO,QAAQ,SAAS,KAAK,SAAS,OAAO,GAAG;AACvE,UAAM,MAAM,MAAM,KAAK,IAAI,OAAO;AAClC,WAAO,QAAQ,SAAS,KAAK,SAAS,OAAO,GAAG;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,YAAY,OAAe,MAAc,KAAoC;AAMjF,WAAO,eAAe,OAAO,MAAM,KAAK,gBAAgB,GAAG,CAAC;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,eAAe,IAAY,MAAgD;AAC/E,WAAO,KAAK,aAAa,IAAI,MAAM,KAAK,mBAAmB,MAAM,EAAE,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,oBACJ,MACyD;AACzD,UAAM,QAA2B,CAAC;AAUlC,QAAI,KAAK,UAAU,UAAa,KAAK,SAAS,QAAW;AACvD,iBAAW,SAAS,OAAO,KAAK,KAAK,KAAK,GAAG;AAC3C,cAAM,KAAK;AAAA,UACT;AAAA,UACA,OAAO,KAAK,QAAQ,KAAK,MAAM,SAC3B,0CACA;AAAA,QACN,CAAC;AAAA,MACH;AAAA,IACF;AACA,UAAM,SAAS,KAAK;AACpB,QAAI,WAAW,OAAW,QAAO,EAAE,MAAM;AACzC,UAAM,MAAM,MAAM,KAAK,mBAAmB,IAAI;AAC9C,eAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,UAAI,QAAQ,QAAW;AAAE,cAAM,KAAK,EAAE,OAAO,OAAO,aAAa,CAAC;AAAG;AAAA,MAAS;AAC9E,YAAM,EAAE,IAAI,KAAK,IAAI,gBAAgB,IAAI;AACzC,UAAI;AACF,cAAM,QAAQ,IAAI,MAAM,MAAM,4BAA4B,KAAK,KAAK,IAAI,MAAM,KAAK,CAAC;AACpF,cAAM,KAAK,EAAE,OAAO,OAAO,aAAa,CAAC;AAAA,MAC3C,QAAQ;AACN,cAAM,KAAK,EAAE,OAAO,OAAO,aAAa,CAAC;AAAA,MAC3C;AAAA,IACF;AACA,WAAO,EAAE,MAAM;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,iBAAiB,OAAe,MAAc,KAAyC;AACrF,WAAO,mBAAmB,KAAK,gBAAgB,GAAG,CAAC,EAAE,OAAO,IAAI;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,cAAc,QAAW,UAA6B,IAAyB;AACnF,UAAM,SAAS,SAAS;AACxB,QAAI,WAAW,UAAa,CAAC,KAAK,IAAI,iBAAiB;AACrD,aAAO;AAAA,IACT;AACA,UAAM,MAAM,MAAM,KAAK,mBAAmB,UAAU,EAAE;AACtD,UAAM,QAAQ,EAAE,GAAI,OAA8C;AAClE,eAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,YAAM,KAAK,IAAI,KAAK,iBAAiB,OAAO,MAAM,GAAG;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2BA,MAAM,iBACJ,QACA,QACA,KACA,OAAmD,CAAC,GACxC;AACZ,QAAI,KAAK,IAAI,KAAK,gBAAgB;AAChC,UAAI,KAAK,OAAO,QAAW;AACzB,cAAM,IAAI;AAAA,UACR,0CAA0C,KAAK,IAAI,IAAI;AAAA,QAEzD;AAAA,MACF;AACA,YAAM,aAA4C,CAAC;AACnD,iBAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,cAAM,EAAE,IAAI,KAAK,IAAI,gBAAgB,IAAI;AACzC,mBAAW,KAAK,IAAI,EAAE,IAAI,KAAK;AAAA,MACjC;AACA,aAAO,MAAM,KAAK,IAAI,IAAI;AAAA,QACxB;AAAA,QACA;AAAA,QACA,KAAK,aAAa,KAAK,IAAI,GAAG;AAAA,QAC9B,EAAE,WAAW,KAAK,oBAAoB,KAAK;AAAA,MAC7C;AAAA,IACF;AACA,WAAO,MAAM;AAAA,MACX;AAAA,MACA;AAAA,MACA,KAAK,gBAAgB,GAAG;AAAA,MACxB,EAAE,WAAW,KAAK,oBAAoB,KAAK;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BA,MAAM,mBAAmB,UAA6B,KAAiB,IAAgC;AACrG,QAAI,YAAY,UAAU,KAAK,IAAI,eAAe,KAAK,eAAe,QAAQ,EAAG,QAAO;AACxF,QAAI;AACJ,QAAI;AACJ,QAAI,SAAS,SAAS,QAAW;AAC/B,YAAM,MAAM,UAAU,SAAS,MAAM,GAAG;AACxC,kBAAY,MAAM,QAAQ,SAAS,KAAK,SAAS,OAAO,GAAG;AAAA,IAC7D,OAAO;AACL,kBAAY,MAAM,QAAQ,SAAS,KAAK,SAAS,OAAO,GAAG;AAAA,IAC7D;AACA,QAAI,SAAS,KAAK,MAAM,SAAS;AACjC,QAAI,SAAS,YAAY,UAAa,KAAK,IAAI,iBAAiB;AAC9D,eAAS,MAAM,KAAK,iBAAiB,QAAQ,SAAS,SAAS,KAAK,EAAE,GAAI,OAAO,SAAY,EAAE,GAAG,IAAI,CAAC,GAAI,iBAAiB,KAAK,CAAC;AAAA,IACpI;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MAAM,cACJ,UACA,OAA6E,CAAC,GAC3D;AACnB,UAAM,OAAO,MAAM,KAAK,kBAAkB,UAAU,KAAK,EAAE;AAG3D,QAAI,SAAS,KAAM,QAAO;AAC1B,QAAI,SAAkB,KAAK,MAAM,IAAI;AAIrC,QAAI,KAAK,IAAI,YAAY,WAAW,QAAQ,OAAO,WAAW,YAAY,WAAW,QAAQ;AAC3F,eAAS,KAAK,IAAI,aAAa,oBAAoB,MAAmB;AAAA,IACxE;AAEA,QAAI,SAAS;AAYb,QAAI,SAAS,YAAY,UAAa,KAAK,IAAI,iBAAiB;AAC9D,YAAM,YAAY,MAAM,KAAK,mBAAmB,UAAU,KAAK,EAAE;AACjE,eAAS,MAAM,KAAK,iBAAiB,QAAQ,SAAS,SAAS,WAAW;AAAA,QACxE,GAAI,KAAK,OAAO,SAAY,EAAE,IAAI,KAAK,GAAG,IAAI,CAAC;AAAA,QAC/C,GAAI,KAAK,oBAAoB,SAAY,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;AAAA,MACxF,CAAC;AAAA,IACH;AAQA,UAAM,kBAAkB,KAAK,oBAAoB,QAAQ,SAAS,YAAY;AAC9E,QAAI,KAAK,IAAI,WAAW,UAAa,CAAC,KAAK,kBAAkB,CAAC,iBAAiB;AAK7E,eAAS,MAAM;AAAA,QACb,KAAK,IAAI;AAAA,QACT;AAAA,QACA,GAAG,KAAK,IAAI,IAAI,KAAK,SAAS,EAAE;AAAA,MAClC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC1yBA,IAAM,SAAS,WAAW,OAAO;AAG1B,IAAM,gBAAgB;AAmB7B,eAAsB,iBACpB,KACA,YACA,IACA,YACA,MAC+C;AAI/C,MAAI,WAAW,SAAS,GAAG,EAAG,OAAM,IAAI,gBAAgB,iCAAiC,UAAU,wBAAwB;AAC3H,MAAI,GAAG,SAAS,GAAG,EAAG,OAAM,IAAI,gBAAgB,yBAAyB,EAAE,wBAAwB;AAKnG,MAAI,OAAO,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC,GAAG;AAC5C,UAAM,IAAI,gBAAgB,gCAAgC,KAAK,SAAS,qCAAqC;AAAA,EAC/G;AAEA,QAAM,OAAO,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,EAAE;AAC5D,MAAI,CAAC,QAAQ,KAAK,SAAS,QAAW;AACpC,UAAM,IAAI,uBAAuB,YAAY,EAAE;AAAA,EACjD;AAEA,QAAM,MAAM,MAAM,IAAI,OAAO,UAAU;AACvC,QAAM,MAAM,MAAM,UAAU,KAAK,MAAM,GAAG;AAC1C,QAAM,SAAS,MAAM,OAAO,UAAU,OAAO,GAAG;AAChD,QAAM,SAAS,eAAe,MAAM;AAEpC,QAAM,OAAO,MAAM,WAAW,qBAAqB;AACnD,MAAI,KAAK,IAAI,SAAS,GAAG,EAAG,OAAM,IAAI,gBAAgB,oCAAoC,KAAK,GAAG,wBAAwB;AAE1H,QAAM,UAA4B;AAAA,IAChC;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,WAAW,KAAK;AAAA,EAClB;AACA,QAAM,SAAS,MAAM,WAAW;AAAA,IAC9B,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,OAAO,CAAC;AAAA,IAChD;AAAA,EACF;AAEA,QAAM,WAAsC;AAAA,IAC1C,GAAG;AAAA,IACH,mBAAmB;AAAA,IACnB,KAAK,KAAK;AAAA,IACV,SAAS,eAAe,MAAM;AAAA,IAC9B,WAAW,KAAK;AAAA,EAClB;AAEA,QAAM,cAAc,GAAG,UAAU,IAAI,EAAE,IAAI,KAAK,GAAG;AACnD,QAAM,QAAQ,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,eAAe,WAAW;AACzE,QAAM,MAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,KAAK,OAAO,MAAM,KAAK;AAAA,IACvB,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA;AAAA;AAAA,IAG5B,KAAK;AAAA,IACL,OAAO,KAAK,UAAU,QAAQ;AAAA,IAC9B,GAAI,IAAI,QAAQ,EAAE,KAAK,IAAI,MAAM,IAAI,CAAC;AAAA,EACxC;AACA,QAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,eAAe,aAAa,GAAG;AAEhE,SAAO,EAAE,KAAK,KAAK,KAAK,YAAY;AACtC;AAkBA,eAAsB,mBACpB,KACA,YACA,IACA,KACA,MACe;AACf,MAAI,MAAM,SAAS,MAAM;AAGvB,UAAM,gBAAgB,KAAK,YAAY,EAAE;AACzC;AAAA,EACF;AACA,QAAM,IAAI,QAAQ,OAAO,IAAI,OAAO,eAAe,GAAG,UAAU,IAAI,EAAE,IAAI,GAAG,EAAE;AACjF;AASA,eAAsB,gBACpB,KACA,YACA,IACe;AACf,QAAM,OAAO,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,EAAE;AAC5D,MAAI,CAAC,QAAQ,KAAK,SAAS,QAAW;AACpC,UAAM,IAAI,uBAAuB,YAAY,EAAE;AAAA,EACjD;AAEA,QAAM,MAAM,MAAM,IAAI,OAAO,UAAU;AACvC,QAAM,SAAS,MAAM,UAAU,KAAK,MAAM,GAAG;AAC7C,QAAM,OAAO,MAAM,QAAQ,KAAK,KAAK,KAAK,OAAO,MAAM;AAEvD,QAAM,SAAS,MAAM,YAAY;AACjC,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,MAAM,MAAM;AAO/C,MAAI;AACJ,MAAI,KAAK,YAAY,QAAW;AAC9B,UAAM,MAA8B,CAAC;AACrC,eAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,KAAK,OAAO,GAAG;AACxD,YAAM,YAAY,MAAM,mBAAmB,MAAM,OAAO,YAAY,QAAQ,GAAG;AAC/E,YAAM,WAAW,MAAM,QAAQ,WAAW,MAAM,4BAA4B,QAAQ,YAAY,KAAK,CAAC;AACtG,UAAI,KAAK,IAAI,GAAG,SAAS,EAAE,IAAI,SAAS,IAAI;AAAA,IAC9C;AACA,gBAAY;AAAA,EACd;AAMA,MAAI;AACJ,MAAI,KAAK,UAAU,QAAW;AAC5B,UAAM,MAA8B,CAAC;AACrC,eAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACtD,YAAM,UAAU,MAAM,gBAAgB,MAAM,QAAQ,YAAY,IAAI,KAAK;AACzE,UAAI,KAAK,IAAI,MAAM,gBAAgB,SAAS,QAAQ,YAAY,IAAI,KAAK;AAAA,IAC3E;AACA,cAAU;AAAA,EACZ;AAEA,QAAM,MAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,IAAI,KAAK,KAAK;AAAA,IACd,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC5B,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MAAM,MAAM,QAAQ,QAAQ,GAAG;AAAA,IAC/B,GAAI,IAAI,QAAQ,EAAE,KAAK,IAAI,MAAM,IAAI,CAAC;AAAA,IACtC,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA,IACxD,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMrD,GAAI,KAAK,UAAU,SAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMxD,GAAI,cAAc,SAAY,EAAE,SAAS,UAAU,IAAI,CAAC;AAAA,IACxD,GAAI,YAAY,SAAY,EAAE,OAAO,QAAQ,IAAI,CAAC;AAAA,EACpD;AACA,QAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,YAAY,IAAI,GAAG;AAGpD,QAAM,IAAI,uBAAuB,YAAY,EAAE;AAG/C,QAAM,SAAS,GAAG,UAAU,IAAI,EAAE;AAClC,QAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,aAAa;AAC5D,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,WAAW,MAAM,GAAG;AAC1B,YAAM,IAAI,QAAQ,OAAO,IAAI,OAAO,eAAe,GAAG;AAAA,IACxD;AAAA,EACF;AACF;;;ACnMA,eAAe,WAAc,KAA8B,OAAe,OAA2C;AACnH,QAAM,MAAM,MAAM,IAAI,OAAO;AAC7B,QAAM,SAAS,MAAM,uBAAuB,GAAG;AAC/C,QAAM,YAAY,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AAC1E,QAAM,UAAU,GAAG,IAAI,IAAI,IAAI,KAAK;AACpC,QAAM,CAAC,SAAS,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC1C,qBAAqB,WAAW,QAAQ,OAAO;AAAA,IAC/C,qBAAqB,WAAW,KAAK,OAAO;AAAA,EAC9C,CAAC;AACD,SAAO,CAAC,GAAG,QAAQ,EAAE,IAAI,QAAQ,IAAI,IAAI,GAAG,OAAO,EAAE,IAAI,OAAO,IAAI,EAAE;AACxE;AAEA,SAAS,eAAkB,KAA8B,OAAe,QAAsB;AAC5F,MAAI,CAAC,IAAI,uBAAuB,CAAC,IAAI,oBAAoB,IAAI,KAAK,GAAG;AACnE,UAAM,IAAI;AAAA,MACR,eAAe,IAAI,IAAI,aAAa,KAAK;AAAA,IAC3C;AAAA,EACF;AACA,MAAI,CAAC,IAAI,iBAAiB;AACxB,UAAM,IAAI;AAAA,MACR,eAAe,IAAI,IAAI,MAAM,MAAM;AAAA,IACrC;AAAA,EACF;AACF;AAaA,eAAsB,UAAa,KAA8B,OAAe,OAAmC;AACjH,iBAAe,KAAK,OAAO,WAAW;AACtC,QAAM,CAAC,QAAQ,YAAY,IAAI,MAAM,WAAW,KAAK,OAAO,KAAK;AAEjE,QAAM,MAAM,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,IAAI,IAAI;AACtD,aAAW,MAAM,KAAK;AACpB,UAAM,MAAM,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,IAAI,MAAM,EAAE;AAMzD,QAAI,CAAC,OAAO,CAAC,IAAI,SAAS,IAAI,SAAS,KAAK,EAAG;AAC/C,QAAI,IAAI,KAAK,KAAK,MAAM,UAAU,IAAI,KAAK,KAAK,MAAM,cAAc;AAClE,aAAO,IAAI,MAAM,cAAc,KAAK,EAAE,GAAG,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,SAAO;AACT;AAMA,eAAsB,WAAc,KAA8B,OAAe,OAA8B;AAC7G,iBAAe,KAAK,OAAO,YAAY;AACvC,QAAM,CAAC,QAAQ,YAAY,IAAI,MAAM,WAAW,KAAK,OAAO,KAAK;AAEjE,QAAM,MAAM,MAAM,IAAI,QAAQ,KAAK,IAAI,OAAO,IAAI,IAAI;AACtD,QAAM,UAAe,CAAC;AACtB,aAAW,MAAM,KAAK;AACpB,UAAM,MAAM,MAAM,IAAI,QAAQ,IAAI,IAAI,OAAO,IAAI,MAAM,EAAE;AAEzD,QAAI,CAAC,OAAO,CAAC,IAAI,SAAS,IAAI,SAAS,KAAK,EAAG;AAC/C,QAAI,IAAI,KAAK,KAAK,MAAM,UAAU,IAAI,KAAK,KAAK,MAAM,cAAc;AAClE,YAAM,MAAM,MAAM,IAAI,MAAM,cAAc,KAAK,EAAE,GAAG,CAAC;AACrD,UAAI,QAAQ,KAAM,SAAQ,KAAK,GAAG;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;;;AC/FA,eAAsB,iBACpB,KACA,KACA,MACiB;AACjB,MAAI,MAAM,cAAc,MAAO,QAAO,IAAI;AAC1C,MAAI,IAAI,SAAS,QAAW;AAC1B,UAAM,MAAM,MAAM,UAAU,IAAI,MAAM,GAAG;AACzC,WAAO,QAAQ,IAAI,KAAK,IAAI,OAAO,GAAG;AAAA,EACxC;AACA,SAAO,QAAQ,IAAI,KAAK,IAAI,OAAO,GAAG;AACxC;AAeA,eAAsB,kBACpB,MACA,KACA,MAC4D;AAC5D,MAAI,MAAM,cAAc,MAAO,QAAO,EAAE,KAAK,IAAI,OAAO,KAAK;AAE7D,MAAI,MAAM,iBAAiB,MAAM;AAC/B,UAAM,MAAM,MAAM,YAAY;AAC9B,UAAM,EAAE,IAAAC,KAAI,MAAAC,MAAK,IAAI,MAAM,QAAQ,MAAM,GAAG;AAC5C,UAAM,UAAU,MAAM,QAAQ,KAAK,GAAG;AACtC,WAAO,EAAE,KAAKD,KAAI,OAAOC,OAAM,MAAM,QAAQ;AAAA,EAC/C;AAEA,QAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,MAAM,GAAG;AAC5C,SAAO,EAAE,KAAK,IAAI,OAAO,KAAK;AAChC;AASO,SAAS,iBAAiB,KAAgC;AAC/D,SAAO,IAAI,MAAM,SAAS,IAAI,IAAI;AACpC;AASO,SAAS,gBAAgB,KAAiC;AAC/D,SAAO,IAAI,SAAS;AACtB;AAuBO,SAAS,oBAAoB,KAAgC;AAWlE,MAAI,IAAI,YAAY,UAAa,IAAI,UAAU,UAAa,IAAI,UAAU,OAAW,QAAO,IAAI;AAChG,QAAM,UAAU,CAAC,KAAoC,QAAwC;AAC3F,UAAM,QAAQ,OAAO,KAAK,GAAG,EAAE,KAAK,EAAE;AAAA,MACpC,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,CAAC;AAAA,IACvD;AACA,WAAO,GAAG,KAAK,UAAU,GAAG,CAAC,KAAK,MAAM,KAAK,GAAG,CAAC;AAAA,EACnD;AACA,QAAM,WAAW,CAAC,WAAW,KAAK,UAAU,IAAI,KAAK,CAAC,EAAE;AACxD,MAAI,IAAI,YAAY,OAAW,UAAS,KAAK,QAAQ,WAAW,IAAI,OAAO,CAAC;AAC5E,MAAI,IAAI,UAAU,OAAW,UAAS,KAAK,QAAQ,SAAS,IAAI,KAAK,CAAC;AACtE,MAAI,IAAI,UAAU,OAAW,UAAS,KAAK,QAAQ,SAAS,IAAI,KAAK,CAAC;AACtE,SAAO,IAAI,SAAS,KAAK,GAAG,CAAC;AAC/B;;;ACpEA,IAAMC,UAAS,WAAW,OAAO;AAG1B,IAAM,sBAAsB;AAG5B,IAAM,uBAAuB;AAGpC,IAAM,2BAA2B;AAuCjC,SAAS,eAAe,SAAiB,UAAkB,OAA0C;AACnG,SAAO,KAAK,UAAU;AAAA,IACpB;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,MAAM,WAAW;AAAA,IACjB,MAAM,eAAe;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,EACR,CAAC;AACH;AAQA,eAAsB,sBACpB,MACA,SACA,UACqB;AACrB,QAAM,UAAU,MAAMA,QAAO,UAAU,OAAO,MAAsB,QAAQ,OAAO,CAAC,YAAY,CAAC;AACjG,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,mBAAmB;AACzD,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,CAAC,qBAAqB,SAAS,QAAQ,CAAC,CAAC;AAC9F,QAAM,OAAO,MAAMA,QAAO,WAAW,EAAE,MAAM,QAAQ,MAAM,WAAW,MAAM,KAAK,GAAG,SAAS,GAAG;AAChG,SAAO,IAAI,WAAW,IAAI;AAC5B;AAQA,eAAsB,qBACpB,MACA,SACA,UACqB;AACrB,QAAM,YAAY,MAAM,sBAAsB,MAAM,SAAS,QAAQ;AACrE,MAAI;AACF,WAAO,MAAMA,QAAO,UAAU,OAAO,WAA2B,EAAE,MAAM,QAAQ,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;AAAA,EACpH,UAAE;AACA,cAAU,KAAK,CAAC;AAAA,EAClB;AACF;AAWA,eAAsB,mBACpB,MACA,SACA,UACA,gBACiB;AACjB,MAAI;AACF,QAAI,eAAe,gBAAgB,IAAI;AACrC,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,UAAM,YAAY,eAAe,SAAS,UAAU,cAAc;AAClE,UAAM,MAAM,MAAM,qBAAqB,MAAM,SAAS,QAAQ;AAC9D,UAAM,MAAM,MAAMA,QAAO,KAAK,QAAQ,KAAK,IAAI,YAAY,EAAE,OAAO,SAAS,CAAiB;AAC9F,WAAO,eAAe,IAAI,WAAW,GAAG,CAAC;AAAA,EAC3C,UAAE;AACA,SAAK,KAAK,CAAC;AAAA,EACb;AACF;AAQO,SAAS,eAAe,MAA4C;AACzE,QAAM,QAAQ,MAAM,SAAS;AAC7B,QAAM,QAAQ,WAAW,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC;AAClE,SAAO;AAAA,IACL,WAAW,eAAe,KAAK;AAAA,IAC/B,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,EAAE,YAAY;AAAA,EACtD;AACF;AAgBA,eAAsB,kBAAkB,MAA+C;AACrF,QAAM,QAAQ,MAAM,KAAK,iBAAiB,KAAK,SAAS;AACxD,MAAI,CAAC,MAAO,QAAO;AAEnB,MAAI,KAAK,gBAAgB,GAAI,QAAO;AAEpC,QAAM,YAAY,eAAe,KAAK,SAAS,KAAK,UAAU;AAAA,IAC5D,gBAAgB,KAAK;AAAA,IACrB,SAAS,KAAK;AAAA,IACd,aAAa,KAAK;AAAA,IAClB,WAAW,KAAK;AAAA,IAChB,WAAW,KAAK;AAAA,EAClB,CAAC;AACD,QAAM,MAAM,MAAMA,QAAO;AAAA,IACvB;AAAA,IACA,KAAK;AAAA,IACL,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AACA,QAAM,KAAK,MAAMA,QAAO;AAAA,IACtB;AAAA,IACA;AAAA,IACA,eAAe,KAAK,KAAK;AAAA,IACzB,IAAI,YAAY,EAAE,OAAO,SAAS;AAAA,EACpC;AACA,MAAI,CAAC,GAAI,QAAO;AAEhB,SAAO,KAAK,IAAI,IAAI,KAAK,MAAM,KAAK,SAAS;AAC/C;","names":["plaintext","iv","data","iv","data","iv","data","subtle"]}
|