@noy-db/hub 0.6.0-pre.8 → 0.6.0

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.
Files changed (512) hide show
  1. package/CHANGELOG.md +7079 -0
  2. package/codemods/0.6.0-pre.json +211 -0
  3. package/dist/api-6X2VLZ7J.js +20 -0
  4. package/dist/attestation/index.js +19 -19
  5. package/dist/{backup-KULFZ2T4.js → backup-VL4GRIEW.js} +36 -18
  6. package/dist/backup-VL4GRIEW.js.map +1 -0
  7. package/dist/blobs/index.js +22 -20
  8. package/dist/blobs/index.js.map +1 -1
  9. package/dist/broker/index.js +12 -12
  10. package/dist/cargo/index.js +35 -35
  11. package/dist/{chunk-KUDZVJKQ.js → chunk-22GR3O4J.js} +2 -2
  12. package/dist/{chunk-CCZJJ4I2.js → chunk-2CBFYXJX.js} +6 -6
  13. package/dist/{chunk-JJNOLSG5.js → chunk-2J5IT37K.js} +15 -16
  14. package/dist/chunk-2J5IT37K.js.map +1 -0
  15. package/dist/{chunk-PNKHAKQ7.js → chunk-2ZCWHCLF.js} +17 -10
  16. package/dist/chunk-2ZCWHCLF.js.map +1 -0
  17. package/dist/{chunk-2BMRJ6LQ.js → chunk-2ZT4INZ4.js} +8 -11
  18. package/dist/{chunk-2BMRJ6LQ.js.map → chunk-2ZT4INZ4.js.map} +1 -1
  19. package/dist/{chunk-FAXZQ5UF.js → chunk-323MN67Z.js} +2 -2
  20. package/dist/{chunk-VMCCGUQB.js → chunk-36CEG6CM.js} +2 -2
  21. package/dist/{chunk-PDLLCOGD.js → chunk-3OE2QNSM.js} +20 -17
  22. package/dist/chunk-3OE2QNSM.js.map +1 -0
  23. package/dist/{chunk-AHLJSVRL.js → chunk-3YGUHUJA.js} +5 -7
  24. package/dist/chunk-3YGUHUJA.js.map +1 -0
  25. package/dist/{chunk-ZJADGNYF.js → chunk-4AOERLTV.js} +1 -1
  26. package/dist/chunk-4AOERLTV.js.map +1 -0
  27. package/dist/{chunk-J7FM3RAU.js → chunk-4ATF4BLF.js} +87 -34
  28. package/dist/chunk-4ATF4BLF.js.map +1 -0
  29. package/dist/{chunk-747LRSOO.js → chunk-4K6BIMLF.js} +2 -2
  30. package/dist/{chunk-PXCBVDFY.js → chunk-5ATC6UT4.js} +40 -7
  31. package/dist/chunk-5ATC6UT4.js.map +1 -0
  32. package/dist/{chunk-4GZ6XOVW.js → chunk-5F7BZAGV.js} +44 -42
  33. package/dist/chunk-5F7BZAGV.js.map +1 -0
  34. package/dist/{chunk-FNSMZQS4.js → chunk-5IHGJHWC.js} +2 -2
  35. package/dist/{chunk-4I72F5DF.js → chunk-5LZZQMIC.js} +11 -14
  36. package/dist/chunk-5LZZQMIC.js.map +1 -0
  37. package/dist/{chunk-JXIDGFKS.js → chunk-5O5ZSW7N.js} +4 -2
  38. package/dist/chunk-5O5ZSW7N.js.map +1 -0
  39. package/dist/{chunk-CEJWMBXO.js → chunk-5OT4G5N5.js} +6 -2
  40. package/dist/chunk-5OT4G5N5.js.map +1 -0
  41. package/dist/{chunk-GAG7QOVO.js → chunk-64WHKBMP.js} +53 -18
  42. package/dist/chunk-64WHKBMP.js.map +1 -0
  43. package/dist/{chunk-7TSYBD3E.js → chunk-65JXA63J.js} +2 -2
  44. package/dist/{chunk-Z45YRGFO.js → chunk-6NR36UNB.js} +2 -2
  45. package/dist/{chunk-W77KZHCW.js → chunk-6RH7PRTL.js} +16 -17
  46. package/dist/chunk-6RH7PRTL.js.map +1 -0
  47. package/dist/{chunk-3JVXVJ7L.js → chunk-7OBIBPCV.js} +10 -10
  48. package/dist/{chunk-AR2JDFAE.js → chunk-7Q3RHOA5.js} +2 -2
  49. package/dist/chunk-7ZGPQOFV.js +190 -0
  50. package/dist/chunk-7ZGPQOFV.js.map +1 -0
  51. package/dist/{chunk-QULVCV3M.js → chunk-AJGGBXWA.js} +4 -4
  52. package/dist/{chunk-CADUYBQD.js → chunk-ATL3ZVXT.js} +2 -2
  53. package/dist/{chunk-DMQCLZ4Z.js → chunk-ATY3ZASK.js} +2 -2
  54. package/dist/{chunk-4HDYQL3J.js → chunk-B4CRUZPR.js} +2 -2
  55. package/dist/{chunk-IMZLOJTK.js → chunk-BMU2DS3S.js} +30 -21
  56. package/dist/chunk-BMU2DS3S.js.map +1 -0
  57. package/dist/{chunk-6SAFL5YE.js → chunk-BZ3WMOYX.js} +3 -3
  58. package/dist/{chunk-UHXCLPGC.js → chunk-C3XWJCG7.js} +2 -2
  59. package/dist/chunk-C3XWJCG7.js.map +1 -0
  60. package/dist/{chunk-HXGUIPQB.js → chunk-CKKN25P2.js} +3 -3
  61. package/dist/{chunk-3URQC7EH.js → chunk-CXPOG3ZY.js} +355 -132
  62. package/dist/chunk-CXPOG3ZY.js.map +1 -0
  63. package/dist/{chunk-3FSX6LDG.js → chunk-D2YFQ7XG.js} +18 -3
  64. package/dist/{chunk-3FSX6LDG.js.map → chunk-D2YFQ7XG.js.map} +1 -1
  65. package/dist/{chunk-52JPHN5N.js → chunk-D6SXRMZZ.js} +27 -149
  66. package/dist/chunk-D6SXRMZZ.js.map +1 -0
  67. package/dist/{chunk-2DHSSLOD.js → chunk-DECNV4QK.js} +13 -15
  68. package/dist/chunk-DECNV4QK.js.map +1 -0
  69. package/dist/{chunk-6BU3L4UE.js → chunk-DNKVKO7K.js} +7 -10
  70. package/dist/chunk-DNKVKO7K.js.map +1 -0
  71. package/dist/{chunk-6HFM7EIT.js → chunk-EHRIDNZX.js} +2 -2
  72. package/dist/{chunk-3737A6EA.js → chunk-EHW7NLGD.js} +127 -31
  73. package/dist/chunk-EHW7NLGD.js.map +1 -0
  74. package/dist/{chunk-BEFVYAR5.js → chunk-EQOTJL76.js} +4 -4
  75. package/dist/chunk-EQOTJL76.js.map +1 -0
  76. package/dist/{chunk-E6427JU2.js → chunk-EV2TDHQZ.js} +19 -3
  77. package/dist/chunk-EV2TDHQZ.js.map +1 -0
  78. package/dist/{chunk-WFUIE565.js → chunk-FNYCT27B.js} +17 -14
  79. package/dist/chunk-FNYCT27B.js.map +1 -0
  80. package/dist/{chunk-RTAMLDWP.js → chunk-FU5VYEYK.js} +2 -2
  81. package/dist/chunk-FX3UIDCS.js +66 -0
  82. package/dist/chunk-FX3UIDCS.js.map +1 -0
  83. package/dist/{chunk-7F4DBNSP.js → chunk-GANFIM2M.js} +135 -18
  84. package/dist/chunk-GANFIM2M.js.map +1 -0
  85. package/dist/{chunk-4VUPLMZ6.js → chunk-GCU42IG7.js} +66 -71
  86. package/dist/chunk-GCU42IG7.js.map +1 -0
  87. package/dist/{chunk-RXYYFSBB.js → chunk-GKTW3KLV.js} +4 -4
  88. package/dist/chunk-HK67PX4J.js +27 -0
  89. package/dist/chunk-HK67PX4J.js.map +1 -0
  90. package/dist/{chunk-OF3L2SD6.js → chunk-HOPNIR5R.js} +2 -2
  91. package/dist/{chunk-WLZ47GSL.js → chunk-HSJBJIB2.js} +12 -10
  92. package/dist/{chunk-WLZ47GSL.js.map → chunk-HSJBJIB2.js.map} +1 -1
  93. package/dist/{chunk-ADW22QSB.js → chunk-HWI7GHJZ.js} +4 -4
  94. package/dist/{chunk-GQ3BX5EA.js → chunk-I3ISCYT7.js} +2 -2
  95. package/dist/{chunk-YJ6IONGA.js → chunk-IWKCJCLP.js} +11 -3
  96. package/dist/{chunk-YJ6IONGA.js.map → chunk-IWKCJCLP.js.map} +1 -1
  97. package/dist/{chunk-NJDQ4YSV.js → chunk-IWQPYT6S.js} +4 -4
  98. package/dist/{chunk-JRKZTEZZ.js → chunk-J6I5VR6P.js} +444 -73
  99. package/dist/chunk-J6I5VR6P.js.map +1 -0
  100. package/dist/{chunk-2Z3NCLNX.js → chunk-JHYKSMVX.js} +7 -7
  101. package/dist/{chunk-6FJWSWFT.js → chunk-JIHWBKMQ.js} +3 -3
  102. package/dist/{chunk-YAWK6AWF.js → chunk-JKATP6OE.js} +2 -2
  103. package/dist/{chunk-PL2GHSCM.js → chunk-JMJSCI7U.js} +157 -90
  104. package/dist/chunk-JMJSCI7U.js.map +1 -0
  105. package/dist/{chunk-Q6TEJXBX.js → chunk-JXHNUYQO.js} +31 -49
  106. package/dist/chunk-JXHNUYQO.js.map +1 -0
  107. package/dist/{chunk-WK5XUYYF.js → chunk-JYPRZWCZ.js} +473 -231
  108. package/dist/chunk-JYPRZWCZ.js.map +1 -0
  109. package/dist/{chunk-5ZKS6ZE2.js → chunk-K6CPIK3R.js} +4 -4
  110. package/dist/chunk-K6CPIK3R.js.map +1 -0
  111. package/dist/{chunk-CDB2HVQW.js → chunk-KM6ZXG7U.js} +14 -15
  112. package/dist/chunk-KM6ZXG7U.js.map +1 -0
  113. package/dist/{chunk-DG27IUVI.js → chunk-LC6NE4IQ.js} +2 -2
  114. package/dist/{chunk-WASHZV34.js → chunk-LIR2DJWP.js} +63 -25
  115. package/dist/chunk-LIR2DJWP.js.map +1 -0
  116. package/dist/{chunk-VZ3XFUQ7.js → chunk-LUYPYCHY.js} +16 -22
  117. package/dist/chunk-LUYPYCHY.js.map +1 -0
  118. package/dist/{chunk-G6S5VVHP.js → chunk-M7WBE3OR.js} +10 -10
  119. package/dist/chunk-M7WBE3OR.js.map +1 -0
  120. package/dist/{chunk-VJFMXYKP.js → chunk-MPKP6L5E.js} +2 -2
  121. package/dist/{chunk-IGJCYUT5.js → chunk-NSITFOCJ.js} +1 -1
  122. package/dist/chunk-NSITFOCJ.js.map +1 -0
  123. package/dist/{chunk-FUHKW252.js → chunk-OCJ3JA4O.js} +2 -2
  124. package/dist/{chunk-VCETL77O.js → chunk-ONPVHX2Y.js} +36 -7
  125. package/dist/chunk-ONPVHX2Y.js.map +1 -0
  126. package/dist/{chunk-WLYIROCJ.js → chunk-OQMCFHUX.js} +2 -2
  127. package/dist/{chunk-JRCYZEHU.js → chunk-OR2FYRYR.js} +2 -2
  128. package/dist/{chunk-HNHCQ556.js → chunk-PFWE7FJG.js} +2 -2
  129. package/dist/{chunk-NPP5R7FF.js → chunk-PJX72ICF.js} +22 -18
  130. package/dist/chunk-PJX72ICF.js.map +1 -0
  131. package/dist/{chunk-U5O6GIWZ.js → chunk-POFYIGQ2.js} +3 -3
  132. package/dist/{chunk-35EBKWQU.js → chunk-QH47SQLD.js} +4 -4
  133. package/dist/{chunk-FZ6NYJ7L.js → chunk-QQRRKO7W.js} +11 -8
  134. package/dist/chunk-QQRRKO7W.js.map +1 -0
  135. package/dist/{chunk-HVQGCKY4.js → chunk-QVXZFJBU.js} +2 -2
  136. package/dist/{chunk-FMQJZH4R.js → chunk-RDB66EKD.js} +6 -6
  137. package/dist/{chunk-X56RTUK3.js → chunk-RJZQ2PVD.js} +3 -3
  138. package/dist/{chunk-SUFG5E73.js → chunk-RPRASGEY.js} +2 -2
  139. package/dist/{chunk-XWX7GL56.js → chunk-S2I5MYSA.js} +7 -10
  140. package/dist/chunk-S2I5MYSA.js.map +1 -0
  141. package/dist/{chunk-FFDNKRCY.js → chunk-S6PJ6ZKE.js} +2 -2
  142. package/dist/chunk-S6PJ6ZKE.js.map +1 -0
  143. package/dist/{chunk-JIUVJ4M7.js → chunk-S7PM7Z4K.js} +3 -3
  144. package/dist/{chunk-55LKVALY.js → chunk-T7IR4N2S.js} +1 -3
  145. package/dist/chunk-T7IR4N2S.js.map +1 -0
  146. package/dist/{chunk-N35NC4JH.js → chunk-TKBB62DN.js} +2 -2
  147. package/dist/{chunk-YPYHVOXP.js → chunk-UJ4Z67UQ.js} +2 -2
  148. package/dist/chunk-UJ4Z67UQ.js.map +1 -0
  149. package/dist/{chunk-7MNBICB5.js → chunk-W3HAIN6U.js} +16 -14
  150. package/dist/chunk-W3HAIN6U.js.map +1 -0
  151. package/dist/{chunk-4UVDI4XE.js → chunk-WPZ5FVAS.js} +4 -4
  152. package/dist/{chunk-MSWYQLMQ.js → chunk-XINT4VJA.js} +2 -2
  153. package/dist/{chunk-7G6VDWXB.js → chunk-XPEPMK4Y.js} +3 -3
  154. package/dist/chunk-XPEPMK4Y.js.map +1 -0
  155. package/dist/{chunk-W3TVWF6N.js → chunk-YCGLAANM.js} +2 -2
  156. package/dist/{chunk-O2ERS4UJ.js → chunk-YTUFV7U7.js} +80 -51
  157. package/dist/chunk-YTUFV7U7.js.map +1 -0
  158. package/dist/{chunk-FDX7OWWI.js → chunk-YYV53EHO.js} +2 -2
  159. package/dist/{chunk-HNGSV2YC.js → chunk-Z3BZXPRO.js} +67 -10
  160. package/dist/chunk-Z3BZXPRO.js.map +1 -0
  161. package/dist/{chunk-6NVPFKN3.js → chunk-ZIMQDXTQ.js} +92 -35
  162. package/dist/chunk-ZIMQDXTQ.js.map +1 -0
  163. package/dist/{chunk-5JY5TSVY.js → chunk-ZJUZOJVW.js} +25 -31
  164. package/dist/chunk-ZJUZOJVW.js.map +1 -0
  165. package/dist/{chunk-3IXIU6FP.js → chunk-ZY6P7M52.js} +7 -10
  166. package/dist/chunk-ZY6P7M52.js.map +1 -0
  167. package/dist/{chunk-H73G4XF4.js → chunk-ZYZJLYNS.js} +7 -11
  168. package/dist/chunk-ZYZJLYNS.js.map +1 -0
  169. package/dist/classified/index.js +5 -5
  170. package/dist/{classified-marker-2KJAXRRO.js → classified-marker-AZDSDG6V.js} +3 -3
  171. package/dist/collection-facade-WSUAYFJ4.js +45 -0
  172. package/dist/{computed-6G5M3UPH.js → computed-VG2PCM4L.js} +3 -3
  173. package/dist/consent/index.js +10 -10
  174. package/dist/cover/index.js +10 -3
  175. package/dist/custody/index.js +12 -11
  176. package/dist/{dead-filter-DCB62VWW.js → dead-filter-JNQNB3TA.js} +2 -2
  177. package/dist/debug/index.js +1 -1
  178. package/dist/{delegation-MO7YZYJS.js → delegation-5F36DRDH.js} +24 -23
  179. package/dist/delegation-5F36DRDH.js.map +1 -0
  180. package/dist/derivations/index.js +12 -12
  181. package/dist/derive-MPOGZ4NR.js +22 -0
  182. package/dist/directory/index.js +10 -10
  183. package/dist/{dispatch-MJ6SHB3Y.js → dispatch-3ZA733EY.js} +18 -18
  184. package/dist/{dispatch-FZEAWKVM.js → dispatch-TNM5CRLZ.js} +9 -6
  185. package/dist/dispatch-TNM5CRLZ.js.map +1 -0
  186. package/dist/{enclave-JU4YIEPB.js → enclave-Y2ALNDRD.js} +31 -9
  187. package/dist/executor-BBEEUFO3.js +9 -0
  188. package/dist/executor-G6G3YEWR.js +9 -0
  189. package/dist/executor-ZUTUMTPA.js +29 -0
  190. package/dist/export-accessible-S3KEB763.js +23 -0
  191. package/dist/extract-partition-KVCTSUVE.js +38 -0
  192. package/dist/{fanout-sidecar-NNAJQXMX.js → fanout-sidecar-3QZU7ZZX.js} +18 -27
  193. package/dist/fanout-sidecar-3QZU7ZZX.js.map +1 -0
  194. package/dist/find-V4FN5ITT.js +11 -0
  195. package/dist/forget/index.js +9 -9
  196. package/dist/guards/index.js +7 -7
  197. package/dist/history/index.js +23 -20
  198. package/dist/history/index.js.map +1 -1
  199. package/dist/i18n/index.js +14 -14
  200. package/dist/index.d.ts +30 -13
  201. package/dist/index.js +180 -188
  202. package/dist/index.js.map +1 -1
  203. package/dist/indexing/index.js +4 -4
  204. package/dist/introspection/index.js +11 -11
  205. package/dist/issue-5CFBWBRX.js +19 -0
  206. package/dist/kernel/collection.d.ts +8 -2
  207. package/dist/kernel/constants.d.ts +36 -0
  208. package/dist/kernel/enclave/crypto.d.ts +52 -4
  209. package/dist/kernel/enclave/index.d.ts +10 -3
  210. package/dist/kernel/enclave/record-aad.d.ts +131 -0
  211. package/dist/kernel/enclave/record-envelope.d.ts +76 -0
  212. package/dist/kernel/enclave/record-keys/envelope-body.d.ts +34 -2
  213. package/dist/kernel/enclave/record-keys/lifecycle.d.ts +22 -5
  214. package/dist/kernel/enclave/record-keys/record-codec.d.ts +47 -14
  215. package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +88 -0
  216. package/dist/kernel/enclave/record-keys/rekey.d.ts +91 -0
  217. package/dist/kernel/enclave/record-keys/tombstone.d.ts +3 -2
  218. package/dist/kernel/errors.d.ts +132 -12
  219. package/dist/kernel/merge-authority.d.ts +25 -0
  220. package/dist/kernel/noydb.d.ts +27 -4
  221. package/dist/kernel/query/builder.d.ts +51 -4
  222. package/dist/kernel/query/join.d.ts +27 -0
  223. package/dist/kernel/query/live.d.ts +31 -9
  224. package/dist/kernel/query/predicate.d.ts +9 -0
  225. package/dist/kernel/refs.d.ts +3 -1
  226. package/dist/kernel/sync-policy.d.ts +0 -2
  227. package/dist/kernel/tier-visibility.d.ts +34 -0
  228. package/dist/kernel/types.d.ts +111 -13
  229. package/dist/kernel/vault.d.ts +14 -8
  230. package/dist/kernel/via/index.d.ts +11 -2
  231. package/dist/kernel/via/reconcile.d.ts +12 -0
  232. package/dist/{ledger-AETNF4OM.js → ledger-MQIIOTZB.js} +11 -11
  233. package/dist/liberate-LW7OKVBH.js +25 -0
  234. package/dist/{link-set-E5HNY67I.js → link-set-5PJBBR63.js} +11 -11
  235. package/dist/{managed-secret-CWQ6PND5.js → managed-secret-ETDG6AAE.js} +11 -3
  236. package/dist/materialized-views/index.js +24 -24
  237. package/dist/migrate-cek-V3VDRV24.js +19 -0
  238. package/dist/migrate-cek-V3VDRV24.js.map +1 -0
  239. package/dist/money/index.js +5 -5
  240. package/dist/noydb-LFDRMYZ5.js +85 -0
  241. package/dist/overlay-views/index.js +4 -4
  242. package/dist/periods/index.js +18 -12
  243. package/dist/pod/index.js +79 -89
  244. package/dist/pod-handle-AZ3CXY5Y.js +41 -0
  245. package/dist/pod-handle-AZ3CXY5Y.js.map +1 -0
  246. package/dist/policy/index.js +11 -4
  247. package/dist/port/to/index.d.ts +4 -4
  248. package/dist/port/to/locator.d.ts +54 -8
  249. package/dist/port/with/i18n-strategy.d.ts +4 -1
  250. package/dist/port/with/lookup-strategy.d.ts +4 -1
  251. package/dist/port/with/merge-authority.d.ts +52 -0
  252. package/dist/port/with/service-bus.d.ts +0 -4
  253. package/dist/port/with/strategies.d.ts +2 -0
  254. package/dist/port/with/team-strategy.d.ts +5 -1
  255. package/dist/portability/index.js +8 -8
  256. package/dist/{post-register-2XSSMGEQ.js → post-register-QCJYRMIK.js} +6 -6
  257. package/dist/query/index.js +6 -6
  258. package/dist/reduce/index.js +6 -6
  259. package/dist/register-JBOEHTVX.js +32 -0
  260. package/dist/registry-5DYHQFJS.js +9 -0
  261. package/dist/registry-EANV44W2.js +9 -0
  262. package/dist/registry-J25H6VB4.js +19 -0
  263. package/dist/registry-R23SQUQH.js +18 -0
  264. package/dist/request-withdrawal-KQ4W4UT5.js +31 -0
  265. package/dist/{reveal-BW36KCOQ.js → reveal-W7BKZSUP.js} +6 -6
  266. package/dist/revoke-H3VSTAIE.js +24 -0
  267. package/dist/satellites/index.js +1 -1
  268. package/dist/schema-update/index.js +2 -2
  269. package/dist/sealed-record/index.js +20 -13
  270. package/dist/sealed-record/index.js.map +1 -1
  271. package/dist/search/index.js +4 -4
  272. package/dist/{seed-GDV5PT4R.js → seed-55FPOMYP.js} +20 -22
  273. package/dist/seed-55FPOMYP.js.map +1 -0
  274. package/dist/sequence/index.js +9 -9
  275. package/dist/session/index.js +10 -10
  276. package/dist/shadow/index.js +2 -2
  277. package/dist/share-link/index.js +1 -1
  278. package/dist/signer-53AQ3BU2.js +25 -0
  279. package/dist/snapshots/index.js +10 -10
  280. package/dist/snapshots/index.js.map +1 -1
  281. package/dist/{stale-ARHFVL5U.js → stale-TH7SSVRV.js} +10 -10
  282. package/dist/storage-WSF7ZKTL.js +23 -0
  283. package/dist/{store-coordination-provider-GFCUOBR6.js → store-coordination-provider-R27VRD6K.js} +18 -12
  284. package/dist/store-coordination-provider-R27VRD6K.js.map +1 -0
  285. package/dist/sync/index.js +11 -11
  286. package/dist/team/index.js +15 -14
  287. package/dist/tiers/index.js +11 -10
  288. package/dist/to/index.js +17 -9
  289. package/dist/to/index.js.map +1 -1
  290. package/dist/transactions/index.js +4 -4
  291. package/dist/{ulid-PTAIMDG4.js → ulid-VQW6ERQN.js} +2 -2
  292. package/dist/util/index.js +1 -1
  293. package/dist/vault-head/index.js +115 -0
  294. package/dist/vault-head/index.js.map +1 -0
  295. package/dist/{verify-RO5RTZOJ.js → verify-M5LQH43C.js} +5 -5
  296. package/dist/via/blob/index.d.ts +3 -0
  297. package/dist/via/lookup/handle.d.ts +4 -1
  298. package/dist/walk-NABCHDZN.js +21 -0
  299. package/dist/with-audit/periods/index.d.ts +3 -3
  300. package/dist/with-audit/periods/periods.d.ts +82 -2
  301. package/dist/with-audit/periods/strategy.d.ts +1 -1
  302. package/dist/with-audit/periods/vault-facade.d.ts +54 -1
  303. package/dist/with-audit/periods/window.d.ts +10 -0
  304. package/dist/with-audit/sealed-record/index.d.ts +13 -0
  305. package/dist/with-audit/tiers/index.d.ts +17 -2
  306. package/dist/with-cargo/adopt-partition.d.ts +1 -1
  307. package/dist/with-cargo/extract-partition.d.ts +1 -1
  308. package/dist/with-cargo/index.d.ts +1 -1
  309. package/dist/with-commit/history/history.d.ts +26 -0
  310. package/dist/with-commit/history/index.d.ts +2 -1
  311. package/dist/with-commit/history/ledger/store.d.ts +7 -1
  312. package/dist/with-commit/history/strategy.d.ts +11 -1
  313. package/dist/with-commit/numbering/index.d.ts +0 -5
  314. package/dist/with-commit/vault-head/active.d.ts +2 -0
  315. package/dist/with-commit/vault-head/head.d.ts +28 -0
  316. package/dist/with-commit/vault-head/index.d.ts +10 -0
  317. package/dist/with-commit/vault-head/strategy.d.ts +127 -0
  318. package/dist/with-commit/vault-head/verify.d.ts +90 -0
  319. package/dist/with-formula/materialized-views/dependency-analyzer.d.ts +4 -0
  320. package/dist/with-formula/materialized-views/projection-legs.d.ts +59 -0
  321. package/dist/with-formula/materialized-views/registry.d.ts +50 -0
  322. package/dist/with-formula/materialized-views/types.d.ts +68 -10
  323. package/dist/with-party/directory/cover/storage.d.ts +0 -8
  324. package/dist/with-party/directory/storage.d.ts +0 -11
  325. package/dist/with-party/directory/visibility.d.ts +0 -21
  326. package/dist/with-party/policy/storage.d.ts +0 -10
  327. package/dist/with-party/team/index.d.ts +1 -1
  328. package/dist/with-party/team/keyring.d.ts +139 -2
  329. package/dist/with-party/team/noydb-facade.d.ts +5 -1
  330. package/dist/with-party/team/roster-tag.d.ts +101 -0
  331. package/dist/with-party/team/tiers.d.ts +2 -1
  332. package/dist/with-pod/format.d.ts +10 -12
  333. package/dist/with-pod/index.d.ts +10 -10
  334. package/dist/with-pod/open.d.ts +2 -2
  335. package/dist/with-pod/pod-handle.d.ts +19 -0
  336. package/dist/with-pod/pod-store.d.ts +0 -8
  337. package/dist/with-pod/{bundle.d.ts → pod.d.ts} +11 -19
  338. package/dist/with-pod/ulid.d.ts +1 -1
  339. package/dist/with-shape/blobs/blob-compaction.d.ts +13 -0
  340. package/dist/with-shape/blobs/blob-set.d.ts +83 -11
  341. package/dist/with-shape/blobs/orphan-report.d.ts +62 -0
  342. package/dist/with-shape/introspection/index.d.ts +1 -0
  343. package/dist/with-sync/engine.d.ts +54 -5
  344. package/dist/with-sync/strategy.d.ts +3 -0
  345. package/dist/withdraw-accessible-VCINIG6V.js +28 -0
  346. package/package.json +10 -4
  347. package/dist/api-RXUMEKT3.js +0 -20
  348. package/dist/backup-KULFZ2T4.js.map +0 -1
  349. package/dist/bundle-handle-GFNHT52M.js +0 -36
  350. package/dist/bundle-handle-GFNHT52M.js.map +0 -1
  351. package/dist/chunk-2DHSSLOD.js.map +0 -1
  352. package/dist/chunk-3737A6EA.js.map +0 -1
  353. package/dist/chunk-3IXIU6FP.js.map +0 -1
  354. package/dist/chunk-3URQC7EH.js.map +0 -1
  355. package/dist/chunk-4GZ6XOVW.js.map +0 -1
  356. package/dist/chunk-4I72F5DF.js.map +0 -1
  357. package/dist/chunk-4VUPLMZ6.js.map +0 -1
  358. package/dist/chunk-52JPHN5N.js.map +0 -1
  359. package/dist/chunk-55LKVALY.js.map +0 -1
  360. package/dist/chunk-5JY5TSVY.js.map +0 -1
  361. package/dist/chunk-5ZKS6ZE2.js.map +0 -1
  362. package/dist/chunk-6BU3L4UE.js.map +0 -1
  363. package/dist/chunk-6NVPFKN3.js.map +0 -1
  364. package/dist/chunk-7F4DBNSP.js.map +0 -1
  365. package/dist/chunk-7G6VDWXB.js.map +0 -1
  366. package/dist/chunk-7H73RIE3.js +0 -45
  367. package/dist/chunk-7H73RIE3.js.map +0 -1
  368. package/dist/chunk-7MNBICB5.js.map +0 -1
  369. package/dist/chunk-AFHQATY4.js +0 -47
  370. package/dist/chunk-AFHQATY4.js.map +0 -1
  371. package/dist/chunk-AHLJSVRL.js.map +0 -1
  372. package/dist/chunk-BEFVYAR5.js.map +0 -1
  373. package/dist/chunk-CDB2HVQW.js.map +0 -1
  374. package/dist/chunk-CEJWMBXO.js.map +0 -1
  375. package/dist/chunk-E6427JU2.js.map +0 -1
  376. package/dist/chunk-FFDNKRCY.js.map +0 -1
  377. package/dist/chunk-FZ6NYJ7L.js.map +0 -1
  378. package/dist/chunk-G6S5VVHP.js.map +0 -1
  379. package/dist/chunk-GAG7QOVO.js.map +0 -1
  380. package/dist/chunk-H73G4XF4.js.map +0 -1
  381. package/dist/chunk-HNGSV2YC.js.map +0 -1
  382. package/dist/chunk-IGJCYUT5.js.map +0 -1
  383. package/dist/chunk-IMZLOJTK.js.map +0 -1
  384. package/dist/chunk-J7FM3RAU.js.map +0 -1
  385. package/dist/chunk-JJNOLSG5.js.map +0 -1
  386. package/dist/chunk-JRKZTEZZ.js.map +0 -1
  387. package/dist/chunk-JXIDGFKS.js.map +0 -1
  388. package/dist/chunk-NPP5R7FF.js.map +0 -1
  389. package/dist/chunk-O2ERS4UJ.js.map +0 -1
  390. package/dist/chunk-PDLLCOGD.js.map +0 -1
  391. package/dist/chunk-PL2GHSCM.js.map +0 -1
  392. package/dist/chunk-PNKHAKQ7.js.map +0 -1
  393. package/dist/chunk-PXCBVDFY.js.map +0 -1
  394. package/dist/chunk-Q6TEJXBX.js.map +0 -1
  395. package/dist/chunk-UHXCLPGC.js.map +0 -1
  396. package/dist/chunk-VCETL77O.js.map +0 -1
  397. package/dist/chunk-VZ3XFUQ7.js.map +0 -1
  398. package/dist/chunk-W77KZHCW.js.map +0 -1
  399. package/dist/chunk-WASHZV34.js.map +0 -1
  400. package/dist/chunk-WFUIE565.js.map +0 -1
  401. package/dist/chunk-WK5XUYYF.js.map +0 -1
  402. package/dist/chunk-XWX7GL56.js.map +0 -1
  403. package/dist/chunk-YPYHVOXP.js.map +0 -1
  404. package/dist/chunk-ZJADGNYF.js.map +0 -1
  405. package/dist/collection-facade-QEJIM6BC.js +0 -45
  406. package/dist/delegation-MO7YZYJS.js.map +0 -1
  407. package/dist/derive-IUA6JFLB.js +0 -22
  408. package/dist/dispatch-FZEAWKVM.js.map +0 -1
  409. package/dist/executor-CYJQLKKI.js +0 -9
  410. package/dist/executor-S4QIKEHW.js +0 -9
  411. package/dist/executor-YIQB2S6N.js +0 -29
  412. package/dist/export-accessible-4S36PQNR.js +0 -23
  413. package/dist/extract-partition-IO7FDZ2P.js +0 -38
  414. package/dist/fanout-sidecar-NNAJQXMX.js.map +0 -1
  415. package/dist/find-RBBYKXI7.js +0 -11
  416. package/dist/issue-RIVHSY2S.js +0 -19
  417. package/dist/liberate-GFN4C7RR.js +0 -24
  418. package/dist/noydb-3MT74MZS.js +0 -83
  419. package/dist/register-4EFJCVYD.js +0 -32
  420. package/dist/registry-4SDHHOJ7.js +0 -18
  421. package/dist/registry-CZVINVQH.js +0 -9
  422. package/dist/registry-IKUR2MXD.js +0 -9
  423. package/dist/registry-OYTFGWVK.js +0 -19
  424. package/dist/request-withdrawal-KGXGDPVQ.js +0 -31
  425. package/dist/revoke-JFN773KF.js +0 -24
  426. package/dist/seed-GDV5PT4R.js.map +0 -1
  427. package/dist/signer-TA55QB6R.js +0 -25
  428. package/dist/storage-V7MTFAQJ.js +0 -23
  429. package/dist/store-coordination-provider-GFCUOBR6.js.map +0 -1
  430. package/dist/walk-3ZECBFDA.js +0 -21
  431. package/dist/with-pod/bundle-handle.d.ts +0 -9
  432. package/dist/withdraw-accessible-7PG4DYQK.js +0 -28
  433. /package/dist/{api-RXUMEKT3.js.map → api-6X2VLZ7J.js.map} +0 -0
  434. /package/dist/{chunk-KUDZVJKQ.js.map → chunk-22GR3O4J.js.map} +0 -0
  435. /package/dist/{chunk-CCZJJ4I2.js.map → chunk-2CBFYXJX.js.map} +0 -0
  436. /package/dist/{chunk-FAXZQ5UF.js.map → chunk-323MN67Z.js.map} +0 -0
  437. /package/dist/{chunk-VMCCGUQB.js.map → chunk-36CEG6CM.js.map} +0 -0
  438. /package/dist/{chunk-747LRSOO.js.map → chunk-4K6BIMLF.js.map} +0 -0
  439. /package/dist/{chunk-FNSMZQS4.js.map → chunk-5IHGJHWC.js.map} +0 -0
  440. /package/dist/{chunk-7TSYBD3E.js.map → chunk-65JXA63J.js.map} +0 -0
  441. /package/dist/{chunk-Z45YRGFO.js.map → chunk-6NR36UNB.js.map} +0 -0
  442. /package/dist/{chunk-3JVXVJ7L.js.map → chunk-7OBIBPCV.js.map} +0 -0
  443. /package/dist/{chunk-AR2JDFAE.js.map → chunk-7Q3RHOA5.js.map} +0 -0
  444. /package/dist/{chunk-QULVCV3M.js.map → chunk-AJGGBXWA.js.map} +0 -0
  445. /package/dist/{chunk-CADUYBQD.js.map → chunk-ATL3ZVXT.js.map} +0 -0
  446. /package/dist/{chunk-DMQCLZ4Z.js.map → chunk-ATY3ZASK.js.map} +0 -0
  447. /package/dist/{chunk-4HDYQL3J.js.map → chunk-B4CRUZPR.js.map} +0 -0
  448. /package/dist/{chunk-6SAFL5YE.js.map → chunk-BZ3WMOYX.js.map} +0 -0
  449. /package/dist/{chunk-HXGUIPQB.js.map → chunk-CKKN25P2.js.map} +0 -0
  450. /package/dist/{chunk-6HFM7EIT.js.map → chunk-EHRIDNZX.js.map} +0 -0
  451. /package/dist/{chunk-RTAMLDWP.js.map → chunk-FU5VYEYK.js.map} +0 -0
  452. /package/dist/{chunk-RXYYFSBB.js.map → chunk-GKTW3KLV.js.map} +0 -0
  453. /package/dist/{chunk-OF3L2SD6.js.map → chunk-HOPNIR5R.js.map} +0 -0
  454. /package/dist/{chunk-ADW22QSB.js.map → chunk-HWI7GHJZ.js.map} +0 -0
  455. /package/dist/{chunk-GQ3BX5EA.js.map → chunk-I3ISCYT7.js.map} +0 -0
  456. /package/dist/{chunk-NJDQ4YSV.js.map → chunk-IWQPYT6S.js.map} +0 -0
  457. /package/dist/{chunk-2Z3NCLNX.js.map → chunk-JHYKSMVX.js.map} +0 -0
  458. /package/dist/{chunk-6FJWSWFT.js.map → chunk-JIHWBKMQ.js.map} +0 -0
  459. /package/dist/{chunk-YAWK6AWF.js.map → chunk-JKATP6OE.js.map} +0 -0
  460. /package/dist/{chunk-DG27IUVI.js.map → chunk-LC6NE4IQ.js.map} +0 -0
  461. /package/dist/{chunk-VJFMXYKP.js.map → chunk-MPKP6L5E.js.map} +0 -0
  462. /package/dist/{chunk-FUHKW252.js.map → chunk-OCJ3JA4O.js.map} +0 -0
  463. /package/dist/{chunk-WLYIROCJ.js.map → chunk-OQMCFHUX.js.map} +0 -0
  464. /package/dist/{chunk-JRCYZEHU.js.map → chunk-OR2FYRYR.js.map} +0 -0
  465. /package/dist/{chunk-HNHCQ556.js.map → chunk-PFWE7FJG.js.map} +0 -0
  466. /package/dist/{chunk-U5O6GIWZ.js.map → chunk-POFYIGQ2.js.map} +0 -0
  467. /package/dist/{chunk-35EBKWQU.js.map → chunk-QH47SQLD.js.map} +0 -0
  468. /package/dist/{chunk-HVQGCKY4.js.map → chunk-QVXZFJBU.js.map} +0 -0
  469. /package/dist/{chunk-FMQJZH4R.js.map → chunk-RDB66EKD.js.map} +0 -0
  470. /package/dist/{chunk-X56RTUK3.js.map → chunk-RJZQ2PVD.js.map} +0 -0
  471. /package/dist/{chunk-SUFG5E73.js.map → chunk-RPRASGEY.js.map} +0 -0
  472. /package/dist/{chunk-JIUVJ4M7.js.map → chunk-S7PM7Z4K.js.map} +0 -0
  473. /package/dist/{chunk-N35NC4JH.js.map → chunk-TKBB62DN.js.map} +0 -0
  474. /package/dist/{chunk-4UVDI4XE.js.map → chunk-WPZ5FVAS.js.map} +0 -0
  475. /package/dist/{chunk-MSWYQLMQ.js.map → chunk-XINT4VJA.js.map} +0 -0
  476. /package/dist/{chunk-W3TVWF6N.js.map → chunk-YCGLAANM.js.map} +0 -0
  477. /package/dist/{chunk-FDX7OWWI.js.map → chunk-YYV53EHO.js.map} +0 -0
  478. /package/dist/{classified-marker-2KJAXRRO.js.map → classified-marker-AZDSDG6V.js.map} +0 -0
  479. /package/dist/{collection-facade-QEJIM6BC.js.map → collection-facade-WSUAYFJ4.js.map} +0 -0
  480. /package/dist/{computed-6G5M3UPH.js.map → computed-VG2PCM4L.js.map} +0 -0
  481. /package/dist/{dead-filter-DCB62VWW.js.map → dead-filter-JNQNB3TA.js.map} +0 -0
  482. /package/dist/{derive-IUA6JFLB.js.map → derive-MPOGZ4NR.js.map} +0 -0
  483. /package/dist/{dispatch-MJ6SHB3Y.js.map → dispatch-3ZA733EY.js.map} +0 -0
  484. /package/dist/{enclave-JU4YIEPB.js.map → enclave-Y2ALNDRD.js.map} +0 -0
  485. /package/dist/{executor-CYJQLKKI.js.map → executor-BBEEUFO3.js.map} +0 -0
  486. /package/dist/{executor-S4QIKEHW.js.map → executor-G6G3YEWR.js.map} +0 -0
  487. /package/dist/{executor-YIQB2S6N.js.map → executor-ZUTUMTPA.js.map} +0 -0
  488. /package/dist/{export-accessible-4S36PQNR.js.map → export-accessible-S3KEB763.js.map} +0 -0
  489. /package/dist/{extract-partition-IO7FDZ2P.js.map → extract-partition-KVCTSUVE.js.map} +0 -0
  490. /package/dist/{find-RBBYKXI7.js.map → find-V4FN5ITT.js.map} +0 -0
  491. /package/dist/{issue-RIVHSY2S.js.map → issue-5CFBWBRX.js.map} +0 -0
  492. /package/dist/{ledger-AETNF4OM.js.map → ledger-MQIIOTZB.js.map} +0 -0
  493. /package/dist/{liberate-GFN4C7RR.js.map → liberate-LW7OKVBH.js.map} +0 -0
  494. /package/dist/{link-set-E5HNY67I.js.map → link-set-5PJBBR63.js.map} +0 -0
  495. /package/dist/{managed-secret-CWQ6PND5.js.map → managed-secret-ETDG6AAE.js.map} +0 -0
  496. /package/dist/{noydb-3MT74MZS.js.map → noydb-LFDRMYZ5.js.map} +0 -0
  497. /package/dist/{post-register-2XSSMGEQ.js.map → post-register-QCJYRMIK.js.map} +0 -0
  498. /package/dist/{register-4EFJCVYD.js.map → register-JBOEHTVX.js.map} +0 -0
  499. /package/dist/{registry-4SDHHOJ7.js.map → registry-5DYHQFJS.js.map} +0 -0
  500. /package/dist/{registry-CZVINVQH.js.map → registry-EANV44W2.js.map} +0 -0
  501. /package/dist/{registry-IKUR2MXD.js.map → registry-J25H6VB4.js.map} +0 -0
  502. /package/dist/{registry-OYTFGWVK.js.map → registry-R23SQUQH.js.map} +0 -0
  503. /package/dist/{request-withdrawal-KGXGDPVQ.js.map → request-withdrawal-KQ4W4UT5.js.map} +0 -0
  504. /package/dist/{reveal-BW36KCOQ.js.map → reveal-W7BKZSUP.js.map} +0 -0
  505. /package/dist/{revoke-JFN773KF.js.map → revoke-H3VSTAIE.js.map} +0 -0
  506. /package/dist/{signer-TA55QB6R.js.map → signer-53AQ3BU2.js.map} +0 -0
  507. /package/dist/{stale-ARHFVL5U.js.map → stale-TH7SSVRV.js.map} +0 -0
  508. /package/dist/{storage-V7MTFAQJ.js.map → storage-WSF7ZKTL.js.map} +0 -0
  509. /package/dist/{ulid-PTAIMDG4.js.map → ulid-VQW6ERQN.js.map} +0 -0
  510. /package/dist/{verify-RO5RTZOJ.js.map → verify-M5LQH43C.js.map} +0 -0
  511. /package/dist/{walk-3ZECBFDA.js.map → walk-NABCHDZN.js.map} +0 -0
  512. /package/dist/{withdraw-accessible-7PG4DYQK.js.map → withdraw-accessible-VCINIG6V.js.map} +0 -0
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  envelopePayloadHash
3
- } from "./chunk-6SAFL5YE.js";
3
+ } from "./chunk-BZ3WMOYX.js";
4
4
  import {
5
5
  NOYDB_FORMAT_VERSION
6
- } from "./chunk-YPYHVOXP.js";
6
+ } from "./chunk-UJ4Z67UQ.js";
7
7
  import {
8
8
  DictKeyMissingError,
9
9
  PermissionDeniedError
10
- } from "./chunk-HNGSV2YC.js";
10
+ } from "./chunk-Z3BZXPRO.js";
11
11
 
12
12
  // src/via/lookup/handle.ts
13
13
  function isDeleteMarker(envelope) {
@@ -102,14 +102,17 @@ var LookupHandle = class {
102
102
  _by: this.keyring.userId
103
103
  };
104
104
  }
105
- const envelope = await this.reservedEnvelopes.encrypt(this.collName, JSON.stringify(entry), version);
106
- return { ...envelope, _by: this.keyring.userId };
105
+ return this.reservedEnvelopes.encrypt(
106
+ { collection: this.collName, id: entry.key, by: this.keyring.userId },
107
+ JSON.stringify(entry),
108
+ version
109
+ );
107
110
  }
108
- async decryptEntry(envelope) {
111
+ async decryptEntry(key, envelope) {
109
112
  if (!this.encrypted) {
110
113
  return JSON.parse(envelope._data);
111
114
  }
112
- const json = await this.reservedEnvelopes.decrypt(this.collName, envelope);
115
+ const json = await this.reservedEnvelopes.decrypt(this.collName, key, envelope);
113
116
  return JSON.parse(json);
114
117
  }
115
118
  /** @internal #650 Task 4 — re-read `key`'s CURRENT adapter truth into `_syncCache` (delete the
@@ -123,7 +126,7 @@ var LookupHandle = class {
123
126
  this._syncCache.delete(key);
124
127
  return;
125
128
  }
126
- this._syncCache.set(key, await this.decryptEntry(envelope));
129
+ this._syncCache.set(key, await this.decryptEntry(key, envelope));
127
130
  }
128
131
  // ─── Public API ───────────────────────────────────────────────────
129
132
  /**
@@ -194,7 +197,7 @@ var LookupHandle = class {
194
197
  key
195
198
  );
196
199
  if (!envelope || isDeleteMarker(envelope)) return null;
197
- const entry = await this.decryptEntry(envelope);
200
+ const entry = await this.decryptEntry(key, envelope);
198
201
  return entry.labels;
199
202
  }
200
203
  /**
@@ -224,7 +227,7 @@ var LookupHandle = class {
224
227
  }
225
228
  const nextVersion = existing._v + 1;
226
229
  if (this.onDirty) {
227
- await this.adapter.put(this.compartmentName, this.collName, key, this.buildDeleteMarker(nextVersion, this.keyring.userId));
230
+ await this.adapter.put(this.compartmentName, this.collName, key, this.buildDeleteMarker({ collection: this.collName, id: key }, nextVersion, this.keyring.userId));
228
231
  } else {
229
232
  await this.adapter.delete(this.compartmentName, this.collName, key);
230
233
  }
@@ -280,7 +283,7 @@ var LookupHandle = class {
280
283
  if (!existing || isDeleteMarker(existing)) {
281
284
  throw new DictKeyMissingError(this.dictionaryName, oldKey);
282
285
  }
283
- const oldEntry = await this.decryptEntry(existing);
286
+ const oldEntry = await this.decryptEntry(oldKey, existing);
284
287
  const newEntry = { key: newKey, labels: oldEntry.labels };
285
288
  const newEnvelope = await this.encryptEntry(newEntry, 1);
286
289
  await this.adapter.put(
@@ -295,7 +298,7 @@ var LookupHandle = class {
295
298
  }
296
299
  const oldKeyNextVersion = existing._v + 1;
297
300
  if (this.onDirty) {
298
- await this.adapter.put(this.compartmentName, this.collName, oldKey, this.buildDeleteMarker(oldKeyNextVersion, this.keyring.userId));
301
+ await this.adapter.put(this.compartmentName, this.collName, oldKey, this.buildDeleteMarker({ collection: this.collName, id: oldKey }, oldKeyNextVersion, this.keyring.userId));
299
302
  } else {
300
303
  await this.adapter.delete(this.compartmentName, this.collName, oldKey);
301
304
  }
@@ -353,7 +356,7 @@ var LookupHandle = class {
353
356
  this._syncCache.delete(key);
354
357
  continue;
355
358
  }
356
- const entry = await this.decryptEntry(envelope);
359
+ const entry = await this.decryptEntry(key, envelope);
357
360
  entries.push(entry);
358
361
  this._syncCache.set(key, entry);
359
362
  }
@@ -389,4 +392,4 @@ export {
389
392
  dictCollectionName,
390
393
  LookupHandle
391
394
  };
392
- //# sourceMappingURL=chunk-WFUIE565.js.map
395
+ //# sourceMappingURL=chunk-FNYCT27B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/via/lookup/handle.ts"],"sourcesContent":["/**\n * `_dict_*` reserved-collection storage engine — `LookupHandle`.\n *\n * Verbatim move of `DictionaryHandle` out of `via/i18n/dictionary.ts`\n * (#650 Task 1 — via-lookup extraction, phase D). The class is renamed to\n * `LookupHandle` (the dict tier is one backing kind the eventual lookup\n * layer supports); `via/i18n/dictionary.ts` re-exports it as\n * `DictionaryHandle` for one release so existing importers compile\n * unchanged. `DictEntry` / `DictionaryOptions` / `DICT_COLLECTION_PREFIX` /\n * `dictCollectionName` move with it — they were exclusively consumed by\n * this class's constructor/methods.\n *\n * No behavior change from the pre-move class: same encryption door\n * (`reservedEnvelopes('_dict_')`, #629 Task 4), same ACL, same ledger\n * shape, same sync-cache/snapshot contract for dict joins.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport { envelopePayloadHash } from '../../with-commit/history/ledger/hash.js'\nimport {\n PermissionDeniedError,\n DictKeyMissingError,\n} from '../../kernel/errors.js'\n\n/**\n * Delete-marker predicate, duplicated (not imported) from\n * `kernel/enclave/record-keys/tombstone.ts`'s `isDeleteMarker` (#647 fix wave 1).\n * `via/lookup/**` may not statically import `kernel/enclave/` — not even the barrel\n * (Check 15, `via-enclave-isolation`) — and this predicate carries zero crypto/protected-body\n * surface (just the `_del` protocol-header field, not `_iv`/`_data`), so duplicating it here\n * mirrors the same call `port/with/i18n-strategy.ts` already makes for `isDictCollectionName`\n * (see its doc comment). Keep the two in sync if the marker shape ever changes.\n *\n * `buildDeleteMarker` (which DOES construct the protected `_iv`/`_data` body fields — Check 11,\n * `enclave-body-only`) can't be duplicated the same way; it's injected via the constructor\n * instead, built from the real `kernel/enclave` function at the Vault call site.\n */\nfunction isDeleteMarker(envelope: EncryptedEnvelope): boolean {\n return envelope._del === true\n}\n\n/** Reserved collection name prefix. Never collides with user collections. */\nexport const DICT_COLLECTION_PREFIX = '_dict_'\n\n/** Return the adapter collection name for a named dictionary. */\nexport function dictCollectionName(dictionaryName: string): string {\n return `${DICT_COLLECTION_PREFIX}${dictionaryName}`\n}\n\n// ─── Dictionary entry shape ────────────────────────────────────────────\n\n/**\n * One entry in a `_dict_*` collection. The record `id` (adapter-side\n * key) IS the stable dictionary key (e.g. `'paid'`). The `labels`\n * record maps locale codes to display strings.\n */\nexport interface DictEntry {\n /** Stable key — same as the record id in the adapter. */\n readonly key: string\n /** Locale → label map, e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`. */\n readonly labels: Record<string, string>\n}\n\n// ─── Per-dictionary options ────────────────────────────────────────────\n\n/**\n * Options for `vault.dictionary(name, options?)`.\n *\n * `writableBy` controls the minimum role for write operations (put,\n * putAll, delete, rename). Defaults to `'admin'` to match the standard\n * \"dictionary contents are owned by admins\" convention; set to\n * `'operator'` for user-editable dictionaries like custom tags.\n */\nexport interface DictionaryOptions {\n /** Minimum role allowed to write dictionary entries. Default: `'admin'`. */\n readonly writableBy?: 'owner' | 'admin' | 'operator'\n}\n\n// ─── LookupHandle ───────────────────────────────────────────────────────\n\n/**\n * Handle to a named dictionary within a vault.\n *\n * Obtained via `vault.dictionary(name)`. Provides strongly-typed\n * CRUD for dictionary entries, plus the `rename()` operation that is the\n * only sanctioned mass-mutation path for dictKey fields.\n *\n * All writes are encrypted under the compartment's DEK for the\n * `_dict_<name>` collection. Adapters never see plaintext.\n */\nexport class LookupHandle<Keys extends string = string> {\n private readonly collName: string\n\n /**\n * Synchronous write-through cache for dict-join support.\n * Populated on every `put()`, `delete()`, and `rename()`. The snapshot\n * is built from this cache by `snapshotEntries()` — the query executor\n * calls this synchronously inside `.toArray()`.\n *\n * `null` means \"not yet initialized\" — callers should use `list()`\n * to warm the cache before using dict joins on pre-existing data.\n */\n private readonly _syncCache = new Map<string, DictEntry>()\n\n /**\n * Return all cached entries as `{ key, labels, ...labels }` records —\n * usable synchronously by the join executor's `snapshot()` call.\n * Returns an empty array when the cache has never been populated.\n */\n snapshotEntries(): readonly Record<string, unknown>[] {\n return Array.from(this._syncCache.values()).map((e) => ({\n key: e.key,\n labels: e.labels,\n ...e.labels,\n }))\n }\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly compartmentName: string,\n private readonly dictionaryName: string,\n private readonly keyring: UnlockedKeyring,\n /**\n * The `reservedEnvelopes('_dict_')` capability — this handle's sanctioned\n * crypto door onto its `_dict_<name>` collection (#629 Task 4). Bound by\n * the Vault; never a keyring, raw DEK, or enclave import.\n */\n private readonly reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>,\n private readonly encrypted: boolean,\n private readonly ledger: LedgerStore | undefined,\n private readonly options: DictionaryOptions,\n /**\n * Callback provided by the Vault to find and rewrite records\n * in any registered collection that has a dictKeyField pointing at\n * this dictionary, used by `rename()`.\n */\n private readonly findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined,\n private readonly emitter: NoydbEventEmitter,\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope (the reserved-tier\n * mirror of #589's ordinary-collection delete marker). Injected rather than imported:\n * `buildDeleteMarker` constructs the envelope's protected-body fields (`_iv`/`_data`), and\n * `via/lookup/**` may not reach `kernel/enclave/` directly (Check 11\n * `enclave-body-only` / Check 15 `via-enclave-isolation`) — the Vault binds the real\n * `kernel/enclave` function at construction time, same pattern as `reservedEnvelopes` above.\n */\n private readonly buildDeleteMarker: (identity: { collection: string; id: string }, version: number, actor: string) => EncryptedEnvelope,\n /** #650 Task 4 (#647) — dirty-log participation hook (origin `local-write`), threaded from `BuildLookupHandleOptions`. */\n private readonly onDirty?: (collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>,\n /** #650 Task 4 — thin `graphDispatch.collect`-equivalent; opens/collects/flushes a one-shot wave for this touch. */\n private readonly onRecordMutated?: (collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>,\n /** #650 Task 5 (#648) — the real reference check `delete()`'s strict branch calls: restrict\n * throws `DictKeyInUseError`, cascade/nullify apply their propagation. Vault-bound; a no-op\n * when the dimension has no declared lookup-referencing edges. */\n private readonly checkReferencesOnDelete?: (key: string) => Promise<unknown>,\n ) {\n this.collName = dictCollectionName(dictionaryName)\n }\n\n // ─── Access checks ────────────────────────────────────────────────\n\n private requireWriteAccess(): void {\n const minRole = this.options.writableBy ?? 'admin'\n const roleRank: Record<string, number> = {\n client: 1,\n viewer: 2,\n operator: 3,\n admin: 4,\n owner: 5,\n }\n const callerRank = roleRank[this.keyring.role] ?? 0\n const requiredRank = roleRank[minRole] ?? 4\n if (callerRank < requiredRank) {\n throw new PermissionDeniedError(\n `Dictionary \"${this.dictionaryName}\" writes require \"${minRole}\" role or above. ` +\n `Current role: \"${this.keyring.role}\".`,\n )\n }\n }\n\n // ─── Internal helpers ─────────────────────────────────────────────\n\n private async encryptEntry(entry: DictEntry, version: number): Promise<EncryptedEnvelope> {\n if (!this.encrypted) {\n // Plaintext/debug vault: no AEAD, therefore no AAD to bind — this literal\n // has nothing `buildRecordEnvelope` could authenticate, and `via/lookup/**`\n // may not import `kernel/enclave/` to reach it anyway (Check 15,\n // `via-enclave-isolation`). The ENCRYPTED branch below is the one that\n // matters, and it is bound: `reservedEnvelopes.encrypt` holds the DEK, so\n // it is where identity AAD is applied (#1051).\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(entry),\n _by: this.keyring.userId,\n }\n }\n // `entry.key` IS the record id this envelope is stored under. `_by` goes\n // IN, not on afterwards: stamping it on the returned envelope would leave\n // it outside the AAD the door just sealed (#1041).\n return this.reservedEnvelopes.encrypt(\n { collection: this.collName, id: entry.key, by: this.keyring.userId },\n JSON.stringify(entry),\n version,\n )\n }\n\n private async decryptEntry(key: string, envelope: EncryptedEnvelope): Promise<DictEntry> {\n if (!this.encrypted) {\n return JSON.parse(envelope._data) as DictEntry\n }\n // `key` IS the record id this envelope is stored under, and the identity the\n // writer sealed it against (#1041).\n const json = await this.reservedEnvelopes.decrypt(this.collName, key, envelope)\n return JSON.parse(json) as DictEntry\n }\n\n /** @internal #650 Task 4 — re-read `key`'s CURRENT adapter truth into `_syncCache` (delete the\n * cache entry when the key is now gone). Called by `Vault._invalidateSyncApplied` after a\n * reserved-lookup row applies via sync, so an already-warmed snapshot/membership/altIndex read\n * never sees a stale verdict for a pulled vocabulary edit — the same invalidation a local\n * put()/delete()/rename() already triggers via `_syncCache.set`/`delete` above. */\n async _refreshSyncCache(key: string): Promise<void> {\n const envelope = await this.adapter.get(this.compartmentName, this.collName, key)\n if (!envelope || isDeleteMarker(envelope)) { this._syncCache.delete(key); return }\n this._syncCache.set(key, await this.decryptEntry(key, envelope))\n }\n\n // ─── Public API ───────────────────────────────────────────────────\n\n /**\n * Add or overwrite a single dictionary entry.\n *\n * @param key The stable key to store (e.g. `'paid'`).\n * @param labels Locale → label map (e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`).\n */\n async put(key: Keys, labels: Record<string, string>): Promise<void> {\n this.requireWriteAccess()\n\n const entry: DictEntry = { key, labels }\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n const version = existing ? existing._v + 1 : 1\n const envelope = await this.encryptEntry(entry, version)\n\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n key,\n envelope,\n existing ? existing._v : undefined,\n )\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.set(key, entry)\n\n // #650 Task 4 (#647) — choke-point participation: dirty-log tracking BEFORE the emit (mirrors\n // Collection._onRecordMutated's local-write order), then the wave-open hook AFTER.\n await this.onDirty?.(this.collName, key, 'put', version)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'put',\n })\n\n await this.onRecordMutated?.(this.collName, key, 'put', version)\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: key,\n version,\n actor: this.keyring.userId,\n // — must be the real envelope hash so\n // vault.verifyBackupIntegrity()'s data-cross-check matches.\n payloadHash: await envelopePayloadHash(envelope),\n })\n }\n }\n\n /**\n * Batch-add or overwrite multiple dictionary entries in one call.\n *\n * @param entries `{ key: { locale: label } }` map.\n */\n async putAll(entries: Record<Keys, Record<string, string>>): Promise<void> {\n this.requireWriteAccess()\n for (const [key, labels] of Object.entries(entries) as [Keys, Record<string, string>][]) {\n await this.put(key, labels)\n }\n }\n\n /**\n * Load the label map for a single key.\n *\n * @returns The label map, or `null` if the key doesn't exist.\n */\n async get(key: Keys): Promise<Record<string, string> | null> {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!envelope || isDeleteMarker(envelope)) return null\n const entry = await this.decryptEntry(key, envelope)\n return entry.labels\n }\n\n /**\n * Delete a dictionary key.\n *\n * Default mode is `'strict'` — throws `DictKeyInUseError` if any\n * registered collection has a record referencing this key. Pass\n * `{ mode: 'warn' }` to skip the check (dev-mode cleanup only).\n *\n * Under sync, deletion writes a version-ordered delete-marker row rather than removing the\n * adapter key outright (#647 fix wave 1) — markers accumulate over time; GC is future work,\n * acceptable for vocabulary-scale data.\n */\n async delete(key: Keys, opts: { mode?: 'strict' | 'warn' } = {}): Promise<void> {\n this.requireWriteAccess()\n\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!existing || isDeleteMarker(existing)) {\n throw new DictKeyMissingError(this.dictionaryName, key)\n }\n\n // #650 Task 5 (#648) — the real reference check: restrict throws `DictKeyInUseError` naming\n // the referencing collection, cascade/nullify apply their propagation. `mode: 'warn'` skips\n // this entirely (today's dev-mode-cleanup escape hatch, unconditional delete). A dimension\n // with no declared lookup-referencing edges is a no-op (undeclared refs keep dangling).\n const mode = opts.mode ?? 'strict'\n if (mode === 'strict') {\n await this.checkReferencesOnDelete?.(key)\n }\n\n // #647 fix wave 1 — mirrors Collection._doDelete's identical `this.onDirty`-gated branch\n // (#589): under sync, a raw adapter.delete() is invisible to a peer's next pull (the key\n // simply stops appearing in remote.list()) — a deleted key never propagates and can be\n // silently resurrected by a later edit. Write a version-ordered DELETE-MARKER instead, so\n // the removal round-trips like any other row. No-op (plain adapter.delete) when sync isn't wired.\n const nextVersion = existing._v + 1\n if (this.onDirty) {\n await this.adapter.put(this.compartmentName, this.collName, key, this.buildDeleteMarker({ collection: this.collName, id: key }, nextVersion, this.keyring.userId))\n } else {\n await this.adapter.delete(this.compartmentName, this.collName, key)\n }\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.delete(key)\n\n // #650 Task 4 (#647) — same choke-point ordering as put() above.\n // #647 fix wave 1: the dirty entry's ACTION is 'put' (not 'delete') — mirrors\n // Collection._onRecordMutated's 'local-delete' case exactly: the marker rides push's\n // CAS-put path, not push's raw remote.delete() path (which would strip the marker off the\n // remote too and reopen this same hole). The version is the MARKER's version, so push's CAS\n // (expectedVersion = entry.version - 1) matches the pre-delete remote copy.\n await this.onDirty?.(this.collName, key, 'put', nextVersion)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'delete',\n })\n\n await this.onRecordMutated?.(this.collName, key, 'delete', nextVersion)\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: key,\n version: existing._v,\n actor: this.keyring.userId,\n // — for delete the prior envelope is what was just\n // removed; we hash it so the chain captures intent. The\n // verifyBackupIntegrity data-cross-check skips delete\n // entries entirely (the live record is gone), but the\n // chain still benefits from a stable non-empty hash.\n payloadHash: await envelopePayloadHash(existing),\n })\n }\n }\n\n /**\n * Rename a dictionary key — the only sanctioned mass-mutation path.\n *\n * Atomically:\n * 1. Adds the new key with the same labels as the old key.\n * 2. Updates every registered record that stores the old key to\n * store the new key instead.\n * 3. Deletes the old key.\n * 4. Appends a single ledger entry recording the rename.\n *\n * Respects ACL: throws `PermissionDeniedError` before any mutation\n * if the caller can't write. The cascade is best-effort atomic\n * within this call — no two-phase commit across adapter calls.\n *\n * Cascade-on-delete is NOT supported. Use `rename()` when you need\n * to change a key that records reference.\n */\n async rename(oldKey: Keys, newKey: string): Promise<void> {\n this.requireWriteAccess()\n\n // 1. Load old entry\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n oldKey,\n )\n if (!existing || isDeleteMarker(existing)) {\n throw new DictKeyMissingError(this.dictionaryName, oldKey)\n }\n const oldEntry = await this.decryptEntry(oldKey, existing)\n\n // 2. Write new key\n const newEntry: DictEntry = { key: newKey, labels: oldEntry.labels }\n const newEnvelope = await this.encryptEntry(newEntry, 1)\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n newKey,\n newEnvelope,\n )\n\n // #670 — publish newKey to the sync cache BEFORE step 3 rewrites referencing records: a\n // vocabulary:'closed' referencing field's enforceWrite reads checkLookupMembership ->\n // snapshotEntries() -> this._syncCache, so if newKey isn't a member yet, step 3's own write of\n // newKey into those records self-refuses with UnknownLookupKeyError. Transition semantics:\n // mid-rename BOTH oldKey and newKey are legitimately members (records are transitioning\n // old->new during the rewrite) — oldKey stays a member until its removal completes below.\n this._syncCache.set(newKey, newEntry)\n\n // 3. Update all referencing records in registered collections\n if (this.findAndUpdateReferences) {\n await this.findAndUpdateReferences(this.dictionaryName, oldKey, newKey)\n }\n\n // 4. Remove old key — #647 fix wave 1: same delete-marker convention as delete() above, so\n // the old key's removal propagates on sync instead of leaving a phantom stale row on a peer\n // that only observes the new key arriving.\n const oldKeyNextVersion = existing._v + 1\n if (this.onDirty) {\n await this.adapter.put(this.compartmentName, this.collName, oldKey, this.buildDeleteMarker({ collection: this.collName, id: oldKey }, oldKeyNextVersion, this.keyring.userId))\n } else {\n await this.adapter.delete(this.compartmentName, this.collName, oldKey)\n }\n\n // Maintain synchronous cache for dict-join snapshot — oldKey's removal from the cache lands\n // here (after step 3), completing the old->new membership transition begun above.\n this._syncCache.delete(oldKey)\n\n // #650 Task 4 (#647) — same choke-point ordering as put()/delete() above, for BOTH touches.\n // #647 fix wave 1: oldKey's dirty action is 'put' (not 'delete') — see delete()'s comment\n // above for why the marker must ride push's CAS-put path, at the marker's version.\n await this.onDirty?.(this.collName, oldKey, 'put', oldKeyNextVersion)\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: oldKey,\n action: 'delete',\n })\n await this.onRecordMutated?.(this.collName, oldKey, 'delete', oldKeyNextVersion)\n\n await this.onDirty?.(this.collName, newKey, 'put', 1)\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: newKey,\n action: 'put',\n })\n await this.onRecordMutated?.(this.collName, newKey, 'put', 1)\n\n // 5. Ledger — record the rename as delete(oldKey) + put(newKey)\n // so verifyBackupIntegrity()'s data-cross-check matches reality\n // (the oldKey envelope is gone; the newKey envelope is what was\n // just written). Two entries instead of one — the chain still\n // captures the rename intent via the matching ts + actor.\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: oldKey,\n version: existing._v,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(existing),\n })\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: newKey,\n version: 1,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(newEnvelope),\n })\n }\n }\n\n /**\n * List all entries in this dictionary.\n *\n * @returns Array of `{ key, labels }` objects.\n */\n async list(): Promise<DictEntry[]> {\n const keys = await this.adapter.list(this.compartmentName, this.collName)\n const entries: DictEntry[] = []\n for (const key of keys) {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n // #647 fix wave 1 — a delete-marker row is a removed key, not a live entry: exclude it\n // from the listing and drop any stale cache entry a prior warm may have left under it.\n if (!envelope || isDeleteMarker(envelope)) { this._syncCache.delete(key); continue }\n const entry = await this.decryptEntry(key, envelope)\n entries.push(entry)\n // Warm the synchronous cache\n this._syncCache.set(key, entry)\n }\n return entries\n }\n\n /**\n * Resolve a key to its label for the given locale.\n *\n * Used by the collection's locale-aware read path to populate\n * `<field>Label` virtual fields. Returns `undefined` when the\n * key doesn't exist or has no label for the requested locale\n * (after exhausting the fallback chain).\n */\n async resolveLabel(\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ): Promise<string | undefined> {\n const labels = await this.get(key as Keys)\n if (!labels) return undefined\n\n // Try primary locale\n if (labels[locale] !== undefined) return labels[locale]\n\n // Try fallback chain\n const chain = Array.isArray(fallback) ? (fallback as readonly string[]) : fallback ? [fallback as string] : []\n for (const fb of chain) {\n if (fb === 'any') {\n // Return any available label\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n\n return undefined\n }\n}\n\n// Compat alias — existing importers of `DictionaryHandle` (the pre-#650\n// name) keep compiling unchanged. `via/i18n/dictionary.ts` re-exports\n// this same binding for one release.\nexport { LookupHandle as DictionaryHandle }\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@ import {
2
2
  IllegalTransitionError,
3
3
  RecordLockedError,
4
4
  ValidationError
5
- } from "./chunk-HNGSV2YC.js";
5
+ } from "./chunk-Z3BZXPRO.js";
6
6
 
7
7
  // src/with-audit/guards/with-guard.ts
8
8
  function withGuard(strategy) {
@@ -124,4 +124,4 @@ export {
124
124
  immutableGuard,
125
125
  transitionGuard
126
126
  };
127
- //# sourceMappingURL=chunk-RTAMLDWP.js.map
127
+ //# sourceMappingURL=chunk-FU5VYEYK.js.map
@@ -0,0 +1,66 @@
1
+ import {
2
+ NOYDB_FORMAT_VERSION
3
+ } from "./chunk-UJ4Z67UQ.js";
4
+
5
+ // src/kernel/enclave/record-envelope.ts
6
+ function buildRecordEnvelope(identity, body) {
7
+ return {
8
+ _noydb: NOYDB_FORMAT_VERSION,
9
+ _v: identity.version,
10
+ _ts: body.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
11
+ _iv: body.iv,
12
+ _data: body.data,
13
+ ...identity.by !== void 0 ? { _by: identity.by } : {},
14
+ ...identity.tier !== void 0 && identity.tier > 0 ? { _tier: identity.tier } : {},
15
+ ...body.cek !== void 0 ? { _cek: body.cek } : {},
16
+ ...body.provenance !== void 0 ? { _source: body.provenance.source, _sourceTs: body.provenance.sourceTs } : {},
17
+ ...body.extra ?? {}
18
+ };
19
+ }
20
+ async function buildSealedRecordEnvelope(identity, seal, body) {
21
+ const sealed = await seal(identity);
22
+ return buildRecordEnvelope(identity, {
23
+ ...body,
24
+ iv: sealed._iv,
25
+ data: sealed._data,
26
+ cek: sealed._cek
27
+ });
28
+ }
29
+
30
+ // src/kernel/enclave/record-keys/tombstone.ts
31
+ function isTombstoneShape(envelope) {
32
+ return envelope._data === "" && envelope._cek === void 0 && envelope._del !== true;
33
+ }
34
+ function isTombstone(envelope, encrypted) {
35
+ if (!encrypted) return false;
36
+ return isTombstoneShape(envelope);
37
+ }
38
+ function buildTombstone(ref, version, actor) {
39
+ return buildRecordEnvelope(
40
+ { ...ref, version, ...actor ? { by: actor } : {} },
41
+ { iv: "", data: "" }
42
+ );
43
+ }
44
+ function isDeleteMarker(envelope) {
45
+ return envelope._del === true;
46
+ }
47
+ function buildDeleteMarker(ref, version, actor) {
48
+ return {
49
+ ...buildRecordEnvelope(
50
+ { ...ref, version, ...actor ? { by: actor } : {} },
51
+ { iv: "", data: "" }
52
+ ),
53
+ _del: true
54
+ };
55
+ }
56
+
57
+ export {
58
+ buildRecordEnvelope,
59
+ buildSealedRecordEnvelope,
60
+ isTombstoneShape,
61
+ isTombstone,
62
+ buildTombstone,
63
+ isDeleteMarker,
64
+ buildDeleteMarker
65
+ };
66
+ //# sourceMappingURL=chunk-FX3UIDCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kernel/enclave/record-envelope.ts","../src/kernel/enclave/record-keys/tombstone.ts"],"sourcesContent":["/**\n * The one place an `EncryptedEnvelope` is constructed (#1051).\n *\n * ## Why this exists\n *\n * 49 files built envelopes with an object literal, bypassing\n * `RecordCodec.buildEnvelope` (which had 4 callers). That is **writer\n * fan-out**: N independent places each had to know the envelope contract, and\n * nothing checked that they agreed.\n *\n * It only became load-bearing with #1041. Binding a record's identity into the\n * AEAD requires every writer to supply that identity — and a writer that\n * doesn't produces data the reader rejects. Reader fan-out you fix by threading\n * an argument through call sites; **writer fan-out cannot be migrated\n * incrementally**, because the first migrated writer emits envelopes the\n * unmigrated readers refuse.\n *\n * ## Why adopting it is safe\n *\n * `identity` is **required but not yet used**. Output is byte-identical to the\n * literals it replaces, so every producer can migrate independently and the\n * existing suite verifies each step. The behaviour change happens **once**,\n * when AAD is switched on here — by which point every writer already supplies\n * identity, and the compiler proved it.\n *\n * That ordering is deliberate: a required-but-unused parameter converts \"did\n * we find every writer?\" from a question into a compile error, the same trick\n * that made the `NOYDB_FORMAT_VERSION` single-sourcing safe in #1048.\n *\n * @packageDocumentation\n */\nimport { NOYDB_FORMAT_VERSION } from '../types.js'\nimport type { EncryptedEnvelope } from '../types.js'\nimport type { RecordIdentity } from './record-aad.js'\n\n/** The body an envelope carries, independent of who is writing it. */\nexport interface RecordEnvelopeBody {\n /** AES-GCM IV, base64. Empty string for a plaintext or tombstone envelope. */\n readonly iv: string\n /** Ciphertext (or plaintext JSON when the collection stores plaintext). */\n readonly data: string\n /** ISO timestamp. Defaults to now — pass it when the caller has a real one. */\n readonly ts?: string | undefined\n /** Wrapped per-record CEK, when the record has one. */\n readonly cek?: string | undefined\n readonly provenance?: { readonly source: string; readonly sourceTs: string } | undefined\n /**\n * Slots the envelope may additionally carry.\n *\n * `_tier`, `_by` and `_v` are deliberately NOT here — they come from\n * `identity`, which is the single source for all three. See\n * {@link buildRecordEnvelope}.\n */\n readonly extra?: Partial<Pick<EncryptedEnvelope, '_det' | '_sealed' | '_vdig' | '_bidx'>> | undefined\n}\n\n/**\n * Build an envelope for `identity`.\n *\n * ## `identity` is the SINGLE SOURCE for `_by`, `_tier` and `_v`\n *\n * All three are stamped from it, and `RecordEnvelopeBody` deliberately cannot\n * carry them. That is not tidiness — it is what makes the AAD binding safe.\n *\n * The caller encrypts the body under AAD derived from `{collection, id, tier,\n * by, version}`. A reader recomputes that AAD from the address it fetched from\n * plus `_tier`/`_by`/`_v` read back **off the envelope** (`recordAadFor`). So if the\n * identity a writer *declares* could differ from the fields it *stamps*, the\n * AAD would not reproduce and the record would be undecryptable — silently, at\n * write time, discoverable only on the next read, and invisible to every gate\n * because the envelope is perfectly well-formed.\n *\n * An earlier draft took both and asserted they agreed. The assertion fired 230\n * times on the existing tree, which is the argument against it: a rule that can\n * be violated is a rule someone must remember. Taking one source removes the\n * violation instead of reporting it.\n */\nexport function buildRecordEnvelope(\n identity: RecordIdentity,\n body: RecordEnvelopeBody,\n): EncryptedEnvelope {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: identity.version,\n _ts: body.ts ?? new Date().toISOString(),\n _iv: body.iv,\n _data: body.data,\n ...(identity.by !== undefined ? { _by: identity.by } : {}),\n ...(identity.tier !== undefined && identity.tier > 0 ? { _tier: identity.tier } : {}),\n ...(body.cek !== undefined ? { _cek: body.cek } : {}),\n ...(body.provenance !== undefined\n ? { _source: body.provenance.source, _sourceTs: body.provenance.sourceTs }\n : {}),\n ...(body.extra ?? {}),\n }\n}\n\n/**\n * Build an envelope from an already-sealed body — the output of\n * `writeEnvelopeBody` — **without the caller ever naming `_iv`/`_data`/`_cek`**.\n *\n * This exists because of a guard, and the guard was right. Migrating\n * `writeEnvelopeBody` callers to {@link buildRecordEnvelope} meant rewriting\n * `...body` (a spread, which names nothing) into `iv: body._iv, data:\n * body._data, cek: body._cek` — and `enclave-body-only` failed it: three new\n * protected-body accesses in files that previously had zero.\n *\n * That is the correct outcome rather than an obstacle. #1051 exists to move\n * knowledge of the envelope's shape *inward*; a migration that spreads the\n * protected field names outward to every caller would have defeated its own\n * purpose while looking like progress. The pairing belongs here.\n *\n * ## It takes a SEALER, not a sealed body — and that is load-bearing (#1041)\n *\n * The obvious shape is `(identity, alreadySealedBody, rest)`. That requires the\n * caller to name the identity TWICE — once for `writeEnvelopeBody` and once\n * here — and the two must agree byte for byte or the record is sealed under\n * AAD no reader can reproduce.\n *\n * They did not agree. `with-party/broker/seed.ts` sealed against\n * `{collection, id}` and stamped `{collection, id, by}`, so every broker seed\n * became unreadable the moment AAD switched on. Taking the sealer means the\n * identity is written once and handed to both — divergence stops being\n * possible rather than being something to remember.\n */\nexport async function buildSealedRecordEnvelope(\n identity: RecordIdentity,\n seal: (identity: RecordIdentity) => Promise<Pick<EncryptedEnvelope, '_iv' | '_data' | '_cek'>>,\n body: Omit<RecordEnvelopeBody, 'iv' | 'data' | 'cek'>,\n): Promise<EncryptedEnvelope> {\n const sealed = await seal(identity)\n return buildRecordEnvelope(identity, {\n ...body,\n iv: sealed._iv,\n data: sealed._data,\n cek: sealed._cek,\n })\n}\n","/**\n * Tombstone shape + predicate for the per-record-key (CEK) layer.\n *\n * A *tombstone* is the residue a GDPR crypto-shred (`vault.forget()`)\n * leaves on disk: the live envelope rewritten to `{ _noydb, _v, _ts, _by,\n * _iv:'', _data:'' }`, dropping `_iv`/`_data`/`_cek`/`_det`. With the wrapped\n * per-record CEK gone, the body — and every history version under the same\n * CEK — is permanently undecryptable, while the record KEY survives so the\n * version counter and \"record existed and was erased\" persist for the audit\n * ledger.\n *\n * These two helpers are the pure, collection-independent core of that\n * contract: {@link buildTombstone} mints the shape, {@link isTombstone}\n * recognises it on the read path. The orchestration that *writes* a tombstone\n * (`_writeTombstone`) and drives `vault.forget()` lives with the collection /\n * vault; it calls into these.\n */\nimport { type EncryptedEnvelope } from '../../types.js'\nimport { buildRecordEnvelope } from '../record-envelope.js'\nimport type { RecordRef } from '../record-aad.js'\n\n/**\n * Shape-only tombstone recognition for layers that have no per-collection\n * context (the sync engine, #590): a tombstone carries an empty `_data` and\n * no wrapped CEK. No live envelope can match — record bodies never serialize\n * to the empty string (the `_sync` meta envelope carries non-empty `_data`,\n * and legacy migration envelopes carry non-empty `_iv`/`_data`).\n */\nexport function isTombstoneShape(envelope: EncryptedEnvelope): boolean {\n return envelope._data === '' && envelope._cek === undefined && envelope._del !== true\n}\n\n/**\n * Is this envelope a crypto-shred tombstone?\n *\n * A tombstone carries no body (`_data` empty) and no wrapped CEK (`_cek`\n * absent) — decrypting it would call `decrypt('', '', dek)` → an AES-GCM\n * throw, so every read choke point must short-circuit to `null` instead.\n *\n * `encrypted` is the collection's encryption flag: on an unencrypted\n * collection there are no envelopes to shred, so nothing is ever a tombstone.\n * (Legacy migration envelopes carry non-empty `_iv`/`_data`, so they are not\n * tombstones and stay readable.)\n */\nexport function isTombstone(envelope: EncryptedEnvelope, encrypted: boolean): boolean {\n if (!encrypted) return false\n return isTombstoneShape(envelope)\n}\n\n/**\n * Mint a tombstone envelope from a record's live version + actor.\n *\n * Keeps `_v` (the displaced version) so the counter is monotonic across the\n * shred, stamps a fresh `_ts`, and records `_by` when an actor is supplied.\n * Deliberately omits `_iv`/`_data`/`_cek`/`_det` — that omission *is* the\n * erasure.\n */\nexport function buildTombstone(\n ref: RecordRef,\n version: number,\n actor: string,\n): EncryptedEnvelope {\n // `actor` rides on the IDENTITY, not the body — it is stamped as `_by` and\n // bound into the AAD from that one source (#1041).\n return buildRecordEnvelope(\n { ...ref, version, ...(actor ? { by: actor } : {}) },\n { iv: '', data: '' },\n )\n}\n\n/** #589: is this envelope an ordinary-delete marker (version-ordered, reads as absent)? */\nexport function isDeleteMarker(envelope: EncryptedEnvelope): boolean {\n return envelope._del === true\n}\n\n/**\n * Mint a delete marker from the deleted record's next version + actor (#589).\n * Minted at the NEXT version (`existing._v + 1`) — unlike `buildTombstone`, which\n * keeps the displaced `_v` — so it wins convergence over the pre-delete copy and a\n * re-create can still win over it at a higher version.\n */\nexport function buildDeleteMarker(\n ref: RecordRef,\n version: number,\n actor: string,\n): EncryptedEnvelope {\n // `_del` is not one of buildRecordEnvelope's declared slots — a delete marker\n // is a distinct envelope class, not a record body — so it is stamped here.\n return {\n ...buildRecordEnvelope(\n { ...ref, version, ...(actor ? { by: actor } : {}) },\n { iv: '', data: '' },\n ),\n _del: true,\n }\n}\n"],"mappings":";;;;;AA6EO,SAAS,oBACd,UACA,MACmB;AACnB,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,IAAI,SAAS;AAAA,IACb,KAAK,KAAK,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvC,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,GAAI,SAAS,OAAO,SAAY,EAAE,KAAK,SAAS,GAAG,IAAI,CAAC;AAAA,IACxD,GAAI,SAAS,SAAS,UAAa,SAAS,OAAO,IAAI,EAAE,OAAO,SAAS,KAAK,IAAI,CAAC;AAAA,IACnF,GAAI,KAAK,QAAQ,SAAY,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC;AAAA,IACnD,GAAI,KAAK,eAAe,SACpB,EAAE,SAAS,KAAK,WAAW,QAAQ,WAAW,KAAK,WAAW,SAAS,IACvE,CAAC;AAAA,IACL,GAAI,KAAK,SAAS,CAAC;AAAA,EACrB;AACF;AA8BA,eAAsB,0BACpB,UACA,MACA,MAC4B;AAC5B,QAAM,SAAS,MAAM,KAAK,QAAQ;AAClC,SAAO,oBAAoB,UAAU;AAAA,IACnC,GAAG;AAAA,IACH,IAAI,OAAO;AAAA,IACX,MAAM,OAAO;AAAA,IACb,KAAK,OAAO;AAAA,EACd,CAAC;AACH;;;AC7GO,SAAS,iBAAiB,UAAsC;AACrE,SAAO,SAAS,UAAU,MAAM,SAAS,SAAS,UAAa,SAAS,SAAS;AACnF;AAcO,SAAS,YAAY,UAA6B,WAA6B;AACpF,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,iBAAiB,QAAQ;AAClC;AAUO,SAAS,eACd,KACA,SACA,OACmB;AAGnB,SAAO;AAAA,IACL,EAAE,GAAG,KAAK,SAAS,GAAI,QAAQ,EAAE,IAAI,MAAM,IAAI,CAAC,EAAG;AAAA,IACnD,EAAE,IAAI,IAAI,MAAM,GAAG;AAAA,EACrB;AACF;AAGO,SAAS,eAAe,UAAsC;AACnE,SAAO,SAAS,SAAS;AAC3B;AAQO,SAAS,kBACd,KACA,SACA,OACmB;AAGnB,SAAO;AAAA,IACL,GAAG;AAAA,MACD,EAAE,GAAG,KAAK,SAAS,GAAI,QAAQ,EAAE,IAAI,MAAM,IAAI,CAAC,EAAG;AAAA,MACnD,EAAE,IAAI,IAAI,MAAM,GAAG;AAAA,IACrB;AAAA,IACA,MAAM;AAAA,EACR;AACF;","names":[]}
@@ -1,9 +1,11 @@
1
1
  import {
2
2
  sha256Hex
3
- } from "./chunk-VCETL77O.js";
3
+ } from "./chunk-ONPVHX2Y.js";
4
4
  import {
5
- MaterializedViewSourceUnknownError
6
- } from "./chunk-HNGSV2YC.js";
5
+ MaterializedViewConfigError,
6
+ MaterializedViewSourceUnknownError,
7
+ RefNotDeclaredError
8
+ } from "./chunk-Z3BZXPRO.js";
7
9
 
8
10
  // src/with-formula/materialized-views/dependency-analyzer.ts
9
11
  function analyzeDependencies(query) {
@@ -44,7 +46,10 @@ function summarizeQueryPlan(query) {
44
46
  as: c.as,
45
47
  // Inline on: callback: use sentinel — drift detection disabled for this MV
46
48
  onPredicateName: c.onPredicateName ?? (c.on ? "[inline]" : null),
47
- maxRows: c.maxRows ?? null
49
+ maxRows: c.maxRows ?? null,
50
+ // `outer` changes the row set, so it is part of the plan's identity
51
+ // for drift detection, not decoration (#1130).
52
+ outer: c.outer ?? false
48
53
  };
49
54
  }
50
55
  return c;
@@ -60,9 +65,10 @@ function summarizeUnionPlan(spec) {
60
65
  }
61
66
  function summarizeProjectionPlan(spec) {
62
67
  const projection = spec.projection;
63
- const legs = projection.joins.map(
64
- (leg) => "collect" in leg ? `collect:${leg.collect}.${leg.on}\u2192${leg.as}` : `field:${leg.field}\u2192${leg.as}`
65
- ).sort();
68
+ const legs = projection.joins.map((leg) => {
69
+ const at = leg.from !== void 0 ? `@${leg.from}` : "";
70
+ return "collect" in leg ? `collect${at}:${leg.collect}.${leg.on}\u2192${leg.as}` : `field${at}:${leg.field}\u2192${leg.as}`;
71
+ }).sort();
66
72
  const body = JSON.stringify({ source: projection.source, legs });
67
73
  return `projection(${body})${summarizeGroupingTail(spec)}`;
68
74
  }
@@ -102,6 +108,44 @@ function canonicalizeQueryPlan(plan) {
102
108
  });
103
109
  }
104
110
 
111
+ // src/with-formula/materialized-views/projection-legs.ts
112
+ function isCollectLeg(leg) {
113
+ return "collect" in leg;
114
+ }
115
+ function validateProjectionLegs(mvName, projection) {
116
+ const seen = /* @__PURE__ */ new Map();
117
+ for (const leg of projection.joins) {
118
+ if (leg.from !== void 0) {
119
+ const parent = seen.get(leg.from);
120
+ if (!parent) {
121
+ throw new MaterializedViewConfigError(
122
+ `"${mvName}": projection leg "${leg.as}" declares from: "${leg.from}", which is not an alias declared EARLIER in \`joins\`. A leg may only attach to the primary row or to a preceding leg \u2014 that ordering rule is what makes a cycle impossible. Known so far: ${[...seen.keys()].map((a) => `"${a}"`).join(", ") || "(none)"}`
123
+ );
124
+ }
125
+ if (isCollectLeg(parent)) {
126
+ throw new MaterializedViewConfigError(
127
+ `"${mvName}": projection leg "${leg.as}" declares from: "${leg.from}", but "${leg.from}" is a collect leg and holds an ARRAY of rows, not one record. A leg can only hang off a forward leg (record | null). Attach it to the primary row instead, or collect the far side directly if its ref() reaches "${projection.source}".`
128
+ );
129
+ }
130
+ }
131
+ seen.set(leg.as, leg);
132
+ }
133
+ }
134
+ function resolveLegOwner(leg, joins, source, resolveRef) {
135
+ if (leg.from === void 0) return source;
136
+ const parent = joins.find((l) => l.as === leg.from);
137
+ if (!parent) return null;
138
+ if (isCollectLeg(parent)) return parent.collect;
139
+ const parentOwner = resolveLegOwner(parent, joins, source, resolveRef);
140
+ if (parentOwner === null) return null;
141
+ return resolveRef(parentOwner, parent.field)?.target ?? null;
142
+ }
143
+ function resolveForwardLegTarget(leg, joins, source, resolveRef) {
144
+ const owner = resolveLegOwner(leg, joins, source, resolveRef);
145
+ if (owner === null) return null;
146
+ return resolveRef(owner, leg.field)?.target ?? null;
147
+ }
148
+
105
149
  // src/with-formula/materialized-views/registry.ts
106
150
  var WHOLE_RECORD = "*";
107
151
  var MaterializedViewRegistry = class {
@@ -123,6 +167,33 @@ var MaterializedViewRegistry = class {
123
167
  * target has resolved (see `_resolvePendingForwardDeps`).
124
168
  */
125
169
  _pendingForwardDeps = [];
170
+ /**
171
+ * Query-form strategies whose `query()` callback could not be planned at
172
+ * registration time because a `.join()` names a field whose `ref()` is not
173
+ * declared YET (#1139).
174
+ *
175
+ * Registration runs inside `openVault()`; a collection's refs can only be
176
+ * declared afterwards, so for a query-form MV that joins a declared FK there
177
+ * is NO call ordering the consumer can choose — the plan is simply built too
178
+ * early. Rather than failing the vault open, the strategy is parked here and
179
+ * replanned from {@link resolvePendingPlans}, which every write dispatch and
180
+ * `vault.refreshView()` call runs first. This is the query-form counterpart
181
+ * of `_pendingForwardDeps`, one level up: that defers a leg's TARGET, this
182
+ * defers the whole plan.
183
+ *
184
+ * Only `RefNotDeclaredError` parks a strategy. Every other planning failure
185
+ * still throws out of `openVault()` exactly as before, so a typo'd source or
186
+ * a malformed spec keeps its loud, early error.
187
+ *
188
+ * A parked strategy is invisible until it resolves: it contributes no
189
+ * `_bySource` entries and no cycle-detection edges (same caveat as a
190
+ * late-resolved forward target — `edges()` runs once at vault open). It also
191
+ * cannot be dispatched, which is why {@link hasPendingPlans} forces the
192
+ * conservative branch in `Collection._txAtomicSafe`: the atomic write path
193
+ * skips MV dispatch, and skipping it here would mean the write that was
194
+ * supposed to trigger the first replan is the one that gets missed.
195
+ */
196
+ _pendingPlans = [];
126
197
  /**
127
198
  * Register an MV. Invokes `spec.query()` once at registration time to
128
199
  * read the plan + join context; the resulting `Query<T>` is discarded
@@ -149,13 +220,20 @@ var MaterializedViewRegistry = class {
149
220
  const projection = spec.projection;
150
221
  dependencies = /* @__PURE__ */ new Set([projection.source]);
151
222
  for (const leg of projection.joins) {
152
- if ("collect" in leg) dependencies.add(leg.collect);
153
- else pendingForwardFields.push(leg.field);
223
+ if (isCollectLeg(leg)) dependencies.add(leg.collect);
224
+ else pendingForwardFields.push(leg.as);
154
225
  }
155
226
  if (spec.sources) for (const s of spec.sources) dependencies.add(s);
156
227
  queryPlanSummary = summarizeProjectionPlan(spec);
157
228
  } else {
158
- const q = spec.query(dbForQuery);
229
+ let q;
230
+ try {
231
+ q = spec.query(dbForQuery);
232
+ } catch (e) {
233
+ if (!(e instanceof RefNotDeclaredError)) throw e;
234
+ this._pendingPlans.push({ spec, db, ...options !== void 0 ? { options } : {} });
235
+ return;
236
+ }
159
237
  qAny = q;
160
238
  isQuery = typeof qAny._plan === "function";
161
239
  if (isQuery) {
@@ -203,15 +281,51 @@ var MaterializedViewRegistry = class {
203
281
  }
204
282
  if (pendingForwardFields.length > 0) {
205
283
  const refRegistry = db.refRegistry;
206
- const source = spec.projection.source;
284
+ const projectionSpec = spec.projection;
285
+ const resolveRef = (c, f) => refRegistry?.getOutbound(c)[f] ?? null;
207
286
  this._pendingForwardDeps.push({
208
287
  reg,
209
- fields: new Set(pendingForwardFields),
210
- resolveTarget: (field) => refRegistry?.getOutbound(source)[field]?.target ?? null
288
+ aliases: new Set(pendingForwardFields),
289
+ resolveTarget: (alias) => {
290
+ const leg = projectionSpec.joins.find((l) => l.as === alias);
291
+ if (!leg || isCollectLeg(leg)) return null;
292
+ return resolveForwardLegTarget(leg, projectionSpec.joins, projectionSpec.source, resolveRef);
293
+ }
211
294
  });
212
295
  this._resolvePendingForwardDeps();
213
296
  }
214
297
  }
298
+ /**
299
+ * `true` while any query-form strategy is still unplanned (#1139). Read by
300
+ * `Collection._txAtomicSafe`, which must refuse the atomic write path while
301
+ * this holds — see the `_pendingPlans` doc comment for why.
302
+ */
303
+ hasPendingPlans() {
304
+ return this._pendingPlans.length > 0;
305
+ }
306
+ /**
307
+ * Replan every parked query-form strategy (#1139). Called at the head of both
308
+ * write dispatchers and of `vault.refreshView()`, so a strategy resolves on the
309
+ * first write or refresh after its source collection's refs are declared —
310
+ * which is the earliest moment it could produce a correct plan, and strictly
311
+ * before the first moment it could have any output to produce.
312
+ *
313
+ * Each entry is handed straight back to {@link register}, so a strategy that
314
+ * is STILL unplannable simply re-parks itself and the next dispatch tries
315
+ * again. Idempotent and cheap: the array empties as strategies resolve, and
316
+ * both callers skip the await entirely once it is empty.
317
+ *
318
+ * A late-resolved strategy does NOT retro-feed `edges()` — the unified cycle
319
+ * pass runs once at vault open, before refs exist. Same caveat, and the same
320
+ * reason, as a late-resolved forward-leg target.
321
+ */
322
+ async resolvePendingPlans() {
323
+ if (this._pendingPlans.length === 0) return;
324
+ const parked = this._pendingPlans.splice(0);
325
+ for (const entry of parked) {
326
+ await this.register(entry.spec, entry.db, entry.options);
327
+ }
328
+ }
215
329
  /** All MVs that depend on `source`, in registration order. */
216
330
  mvsForSource(source) {
217
331
  if (this._pendingForwardDeps.length > 0) this._resolvePendingForwardDeps();
@@ -234,17 +348,17 @@ var MaterializedViewRegistry = class {
234
348
  _resolvePendingForwardDeps() {
235
349
  for (let i = this._pendingForwardDeps.length - 1; i >= 0; i--) {
236
350
  const entry = this._pendingForwardDeps[i];
237
- for (const field of [...entry.fields]) {
238
- const target = entry.resolveTarget(field);
351
+ for (const alias of [...entry.aliases]) {
352
+ const target = entry.resolveTarget(alias);
239
353
  if (target === null) continue;
240
- entry.fields.delete(field);
354
+ entry.aliases.delete(alias);
241
355
  if (entry.reg.dependencies.has(target)) continue;
242
356
  entry.reg.dependencies.add(target);
243
357
  const arr = this._bySource.get(target);
244
358
  if (arr) arr.push(entry.reg);
245
359
  else this._bySource.set(target, [entry.reg]);
246
360
  }
247
- if (entry.fields.size === 0) this._pendingForwardDeps.splice(i, 1);
361
+ if (entry.aliases.size === 0) this._pendingForwardDeps.splice(i, 1);
248
362
  }
249
363
  }
250
364
  /** Single MV by name, or `undefined`. */
@@ -363,7 +477,10 @@ export {
363
477
  summarizeQueryPlan,
364
478
  computeQueryHash,
365
479
  canonicalizeQueryPlan,
480
+ isCollectLeg,
481
+ validateProjectionLegs,
482
+ resolveLegOwner,
366
483
  MaterializedViewRegistry,
367
484
  wrapDbWithPredicates
368
485
  };
369
- //# sourceMappingURL=chunk-7F4DBNSP.js.map
486
+ //# sourceMappingURL=chunk-GANFIM2M.js.map