@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.
Files changed (499) hide show
  1. package/CHANGELOG.md +5234 -0
  2. package/codemods/0.4.0-pre.json +699 -0
  3. package/codemods/0.6.0-pre.json +211 -0
  4. package/dist/api-EYNT6KGS.js +20 -0
  5. package/dist/attestation/index.js +19 -19
  6. package/dist/{backup-YYBE5RPC.js → backup-FSC36VWC.js} +36 -18
  7. package/dist/backup-FSC36VWC.js.map +1 -0
  8. package/dist/blobs/index.js +13 -13
  9. package/dist/broker/index.js +12 -12
  10. package/dist/cargo/index.js +33 -33
  11. package/dist/{chunk-35EBKWQU.js → chunk-2LFOMUEA.js} +4 -4
  12. package/dist/{chunk-OF3L2SD6.js → chunk-32B7VCKU.js} +2 -2
  13. package/dist/{chunk-MSWYQLMQ.js → chunk-3B6S6RSI.js} +2 -2
  14. package/dist/{chunk-PJNTR2NV.js → chunk-3ENNPCIW.js} +7 -10
  15. package/dist/chunk-3ENNPCIW.js.map +1 -0
  16. package/dist/{chunk-7F4DBNSP.js → chunk-3O72ZD2E.js} +3 -3
  17. package/dist/{chunk-FNSMZQS4.js → chunk-3PMFMUFX.js} +2 -2
  18. package/dist/{chunk-WQDTCJ6W.js → chunk-45YHJ3GV.js} +11 -3
  19. package/dist/{chunk-WQDTCJ6W.js.map → chunk-45YHJ3GV.js.map} +1 -1
  20. package/dist/{chunk-NIVEDYJZ.js → chunk-4A34KWOU.js} +31 -49
  21. package/dist/chunk-4A34KWOU.js.map +1 -0
  22. package/dist/{chunk-ZJADGNYF.js → chunk-4AOERLTV.js} +1 -1
  23. package/dist/chunk-4AOERLTV.js.map +1 -0
  24. package/dist/{chunk-EDXAQ6JI.js → chunk-4N5Q23KV.js} +87 -34
  25. package/dist/chunk-4N5Q23KV.js.map +1 -0
  26. package/dist/{chunk-VV4NSB7P.js → chunk-4OQZNXQG.js} +15 -24
  27. package/dist/chunk-4OQZNXQG.js.map +1 -0
  28. package/dist/{chunk-FAXZQ5UF.js → chunk-4RAS6HN6.js} +2 -2
  29. package/dist/{chunk-C2OOEM57.js → chunk-4YL2LMXK.js} +92 -35
  30. package/dist/chunk-4YL2LMXK.js.map +1 -0
  31. package/dist/{chunk-EP7VPR7Y.js → chunk-5Q7AJ7DN.js} +11 -8
  32. package/dist/chunk-5Q7AJ7DN.js.map +1 -0
  33. package/dist/{chunk-VMCCGUQB.js → chunk-6JPGVL7X.js} +2 -2
  34. package/dist/{chunk-PRDRGL73.js → chunk-6KTVJ5ZZ.js} +17 -14
  35. package/dist/chunk-6KTVJ5ZZ.js.map +1 -0
  36. package/dist/{chunk-4MC5JRRX.js → chunk-6WO62AJW.js} +14 -15
  37. package/dist/chunk-6WO62AJW.js.map +1 -0
  38. package/dist/{chunk-WLYIROCJ.js → chunk-6YD5SYQS.js} +2 -2
  39. package/dist/{chunk-YAWK6AWF.js → chunk-7KAE7CQ2.js} +2 -2
  40. package/dist/{chunk-MWKDOHEF.js → chunk-7LNE2N2V.js} +17 -10
  41. package/dist/chunk-7LNE2N2V.js.map +1 -0
  42. package/dist/{chunk-5PR33AC4.js → chunk-7PJ3BKHS.js} +20 -17
  43. package/dist/chunk-7PJ3BKHS.js.map +1 -0
  44. package/dist/{chunk-JXIDGFKS.js → chunk-A4TOGAUW.js} +4 -2
  45. package/dist/chunk-A4TOGAUW.js.map +1 -0
  46. package/dist/{chunk-VCETL77O.js → chunk-AU3AUJIZ.js} +27 -7
  47. package/dist/chunk-AU3AUJIZ.js.map +1 -0
  48. package/dist/{chunk-NKH7GSIH.js → chunk-AUPSEJ7O.js} +4 -4
  49. package/dist/{chunk-CCZJJ4I2.js → chunk-B6IYATME.js} +4 -4
  50. package/dist/{chunk-WYZ5MYUA.js → chunk-BAHOV5I5.js} +44 -42
  51. package/dist/chunk-BAHOV5I5.js.map +1 -0
  52. package/dist/{chunk-G5APARUV.js → chunk-BEZDLIDG.js} +13 -15
  53. package/dist/chunk-BEZDLIDG.js.map +1 -0
  54. package/dist/{chunk-ERB6NDDW.js → chunk-CAGI4LLJ.js} +427 -72
  55. package/dist/chunk-CAGI4LLJ.js.map +1 -0
  56. package/dist/{chunk-4UVDI4XE.js → chunk-CLAHBPOI.js} +4 -4
  57. package/dist/{chunk-HNGSV2YC.js → chunk-CWM4GQD2.js} +39 -10
  58. package/dist/chunk-CWM4GQD2.js.map +1 -0
  59. package/dist/{chunk-HVQGCKY4.js → chunk-D3R7Q4QK.js} +2 -2
  60. package/dist/{chunk-I4F6PKUK.js → chunk-DIZ6HM7Q.js} +16 -17
  61. package/dist/chunk-DIZ6HM7Q.js.map +1 -0
  62. package/dist/{chunk-ZNACADFG.js → chunk-DVRZYAGT.js} +4 -4
  63. package/dist/chunk-DVRZYAGT.js.map +1 -0
  64. package/dist/{chunk-P7OG2ETF.js → chunk-DXKLLKME.js} +3 -3
  65. package/dist/{chunk-TDJPS3T2.js → chunk-E5SC6ENM.js} +24 -19
  66. package/dist/chunk-E5SC6ENM.js.map +1 -0
  67. package/dist/{chunk-26JMGSSC.js → chunk-EES37S2V.js} +4 -4
  68. package/dist/chunk-EES37S2V.js.map +1 -0
  69. package/dist/{chunk-JIUVJ4M7.js → chunk-EKEIEJL6.js} +2 -2
  70. package/dist/{chunk-GASWQ3XG.js → chunk-ESKIAXO2.js} +15 -16
  71. package/dist/chunk-ESKIAXO2.js.map +1 -0
  72. package/dist/{chunk-TOAIYQJR.js → chunk-FFSQFH6D.js} +7 -10
  73. package/dist/chunk-FFSQFH6D.js.map +1 -0
  74. package/dist/{chunk-DG27IUVI.js → chunk-FS7NTGCJ.js} +2 -2
  75. package/dist/{chunk-V5KYPBUR.js → chunk-FW7NGYLT.js} +11 -14
  76. package/dist/chunk-FW7NGYLT.js.map +1 -0
  77. package/dist/{chunk-52QYGZHH.js → chunk-GBBDFE6C.js} +2 -2
  78. package/dist/chunk-GBBDFE6C.js.map +1 -0
  79. package/dist/{chunk-HXGUIPQB.js → chunk-GQXFOAYZ.js} +3 -3
  80. package/dist/{chunk-BTVYJWSN.js → chunk-GTHVPVAR.js} +10 -10
  81. package/dist/{chunk-DMQCLZ4Z.js → chunk-GWO2IDAB.js} +2 -2
  82. package/dist/{chunk-6HFM7EIT.js → chunk-H3G4I3PN.js} +2 -2
  83. package/dist/chunk-HK67PX4J.js +27 -0
  84. package/dist/chunk-HK67PX4J.js.map +1 -0
  85. package/dist/{chunk-E7OBCBXS.js → chunk-HQSPF5IY.js} +22 -18
  86. package/dist/chunk-HQSPF5IY.js.map +1 -0
  87. package/dist/{chunk-VJFMXYKP.js → chunk-HR5R5JOM.js} +2 -2
  88. package/dist/{chunk-FDX7OWWI.js → chunk-HYYVT2KZ.js} +2 -2
  89. package/dist/{chunk-JRCYZEHU.js → chunk-I6QKB7MT.js} +2 -2
  90. package/dist/{chunk-MZ5ZFO2D.js → chunk-ICDHUUMQ.js} +84 -112
  91. package/dist/chunk-ICDHUUMQ.js.map +1 -0
  92. package/dist/{chunk-W5W6KHN2.js → chunk-IGNJOJEP.js} +1 -1
  93. package/dist/chunk-IGNJOJEP.js.map +1 -0
  94. package/dist/{chunk-KUDZVJKQ.js → chunk-IJ46VCWD.js} +2 -2
  95. package/dist/{chunk-4HDYQL3J.js → chunk-INMHEMXX.js} +2 -2
  96. package/dist/{chunk-66W5OOCX.js → chunk-JLYQQNY4.js} +52 -65
  97. package/dist/chunk-JLYQQNY4.js.map +1 -0
  98. package/dist/{chunk-UHXCLPGC.js → chunk-JNMTN5D5.js} +2 -2
  99. package/dist/chunk-JNMTN5D5.js.map +1 -0
  100. package/dist/{chunk-I4ZAO7F7.js → chunk-JWMBG5S3.js} +7 -11
  101. package/dist/chunk-JWMBG5S3.js.map +1 -0
  102. package/dist/chunk-KRVS7YWY.js +123 -0
  103. package/dist/chunk-KRVS7YWY.js.map +1 -0
  104. package/dist/{chunk-AR2JDFAE.js → chunk-KV6JM2IA.js} +2 -2
  105. package/dist/{chunk-PVU7LW5L.js → chunk-KX57HODD.js} +6 -6
  106. package/dist/{chunk-PY7CI6L5.js → chunk-LGFTOU27.js} +553 -275
  107. package/dist/chunk-LGFTOU27.js.map +1 -0
  108. package/dist/chunk-LN7P6MZB.js +190 -0
  109. package/dist/chunk-LN7P6MZB.js.map +1 -0
  110. package/dist/{chunk-UIBGXRDD.js → chunk-LX46B56Q.js} +25 -31
  111. package/dist/chunk-LX46B56Q.js.map +1 -0
  112. package/dist/{chunk-CEJWMBXO.js → chunk-LXECF2ZR.js} +2 -2
  113. package/dist/{chunk-7VHY5E3X.js → chunk-MSLPDFK2.js} +7 -7
  114. package/dist/{chunk-I6SDX7WX.js → chunk-MZTUTEHP.js} +16 -22
  115. package/dist/chunk-MZTUTEHP.js.map +1 -0
  116. package/dist/{chunk-VRA4Q7DA.js → chunk-NCCEDL2K.js} +55 -48
  117. package/dist/chunk-NCCEDL2K.js.map +1 -0
  118. package/dist/{chunk-HNHCQ556.js → chunk-NR2SUJ3H.js} +2 -2
  119. package/dist/{chunk-AHLJSVRL.js → chunk-NW4TY6VC.js} +5 -7
  120. package/dist/chunk-NW4TY6VC.js.map +1 -0
  121. package/dist/{chunk-RKKORO4M.js → chunk-O742QBZZ.js} +10 -10
  122. package/dist/chunk-O742QBZZ.js.map +1 -0
  123. package/dist/{chunk-VN45YLWM.js → chunk-OHOKBMTM.js} +343 -132
  124. package/dist/chunk-OHOKBMTM.js.map +1 -0
  125. package/dist/{chunk-W3TVWF6N.js → chunk-OIBEJN5H.js} +2 -2
  126. package/dist/{chunk-QD724WDJ.js → chunk-OMYCSTXL.js} +4 -4
  127. package/dist/{chunk-Z45YRGFO.js → chunk-ONVD6GBY.js} +2 -2
  128. package/dist/{chunk-TAGFGKHP.js → chunk-OTHHO3KI.js} +7 -10
  129. package/dist/chunk-OTHHO3KI.js.map +1 -0
  130. package/dist/{chunk-3737A6EA.js → chunk-P2MR5UNE.js} +75 -18
  131. package/dist/chunk-P2MR5UNE.js.map +1 -0
  132. package/dist/chunk-PENPHA45.js +66 -0
  133. package/dist/chunk-PENPHA45.js.map +1 -0
  134. package/dist/{chunk-3FSX6LDG.js → chunk-PPCOKVFA.js} +8 -3
  135. package/dist/{chunk-3FSX6LDG.js.map → chunk-PPCOKVFA.js.map} +1 -1
  136. package/dist/{chunk-VOQW5LAM.js → chunk-QSIEL6TL.js} +102 -71
  137. package/dist/chunk-QSIEL6TL.js.map +1 -0
  138. package/dist/chunk-RFO4UXKQ.js +201 -0
  139. package/dist/chunk-RFO4UXKQ.js.map +1 -0
  140. package/dist/{chunk-KCQX65FU.js → chunk-RKCRPPNB.js} +3 -3
  141. package/dist/{chunk-7TSYBD3E.js → chunk-RSXQNFGO.js} +2 -2
  142. package/dist/{chunk-SZ2K3MHL.js → chunk-S56VYR4Q.js} +8 -11
  143. package/dist/{chunk-SZ2K3MHL.js.map → chunk-S56VYR4Q.js.map} +1 -1
  144. package/dist/{chunk-7NXHMW6Y.js → chunk-SYS46BL7.js} +2 -2
  145. package/dist/{chunk-55LKVALY.js → chunk-T7IR4N2S.js} +1 -3
  146. package/dist/chunk-T7IR4N2S.js.map +1 -0
  147. package/dist/{chunk-A67356IR.js → chunk-T7JGWTES.js} +33 -8
  148. package/dist/chunk-T7JGWTES.js.map +1 -0
  149. package/dist/{chunk-WHJKIZS7.js → chunk-TDSN2O2V.js} +27 -149
  150. package/dist/chunk-TDSN2O2V.js.map +1 -0
  151. package/dist/{chunk-747LRSOO.js → chunk-TMBSPLUG.js} +2 -2
  152. package/dist/{chunk-LWSJG3LI.js → chunk-TQPASLY4.js} +7 -3
  153. package/dist/chunk-TQPASLY4.js.map +1 -0
  154. package/dist/{chunk-WKPJXWKR.js → chunk-TX5MKAHA.js} +3 -3
  155. package/dist/{chunk-HFQ6LGIO.js → chunk-U27Y4DJZ.js} +12 -10
  156. package/dist/{chunk-HFQ6LGIO.js.map → chunk-U27Y4DJZ.js.map} +1 -1
  157. package/dist/{chunk-E6427JU2.js → chunk-VVSOPRUE.js} +18 -2
  158. package/dist/chunk-VVSOPRUE.js.map +1 -0
  159. package/dist/{chunk-7G6VDWXB.js → chunk-WVE6YKMX.js} +3 -3
  160. package/dist/chunk-WVE6YKMX.js.map +1 -0
  161. package/dist/{chunk-GLKDWWNO.js → chunk-YALD3SST.js} +16 -14
  162. package/dist/chunk-YALD3SST.js.map +1 -0
  163. package/dist/{chunk-NJDQ4YSV.js → chunk-YKXZHUOW.js} +4 -4
  164. package/dist/{chunk-VW6ZZGCG.js → chunk-ZLHHE5XZ.js} +3 -3
  165. package/dist/{chunk-FUHKW252.js → chunk-ZZXLB6AS.js} +2 -2
  166. package/dist/classified/index.js +5 -5
  167. package/dist/{classified-marker-FTOX7Q5L.js → classified-marker-NA6HUV33.js} +3 -3
  168. package/dist/collection-facade-VBM35WAH.js +45 -0
  169. package/dist/{computed-6G5M3UPH.js → computed-GSTLWSY5.js} +3 -3
  170. package/dist/consent/index.js +10 -10
  171. package/dist/cover/index.js +10 -3
  172. package/dist/custody/index.js +11 -11
  173. package/dist/{dead-filter-ENRIOQIE.js → dead-filter-UALP5DJX.js} +2 -2
  174. package/dist/debug/index.js +1 -1
  175. package/dist/{delegation-SSEPLXXO.js → delegation-JLNXM7KH.js} +24 -23
  176. package/dist/delegation-JLNXM7KH.js.map +1 -0
  177. package/dist/derivations/index.js +12 -12
  178. package/dist/derive-YUO3TQYN.js +22 -0
  179. package/dist/directory/index.js +10 -10
  180. package/dist/{dispatch-RE74SH6L.js → dispatch-4ZHLSFZQ.js} +5 -5
  181. package/dist/{dispatch-BDVGYC6X.js → dispatch-77CB75KB.js} +18 -18
  182. package/dist/{enclave-52VUXNRL.js → enclave-O4NOROCJ.js} +27 -9
  183. package/dist/executor-CZDXBXKE.js +29 -0
  184. package/dist/executor-DVJAWN3B.js +9 -0
  185. package/dist/executor-VRLG4TQJ.js +9 -0
  186. package/dist/export-accessible-UXSMG7AB.js +23 -0
  187. package/dist/extract-partition-TVY7AMKH.js +38 -0
  188. package/dist/{fanout-sidecar-DTBIDOWF.js → fanout-sidecar-NLQ7QAYW.js} +18 -27
  189. package/dist/fanout-sidecar-NLQ7QAYW.js.map +1 -0
  190. package/dist/find-WSARMJBW.js +11 -0
  191. package/dist/forget/index.js +9 -9
  192. package/dist/guards/index.js +7 -7
  193. package/dist/history/index.js +23 -20
  194. package/dist/history/index.js.map +1 -1
  195. package/dist/i18n/index.js +14 -14
  196. package/dist/index.d.ts +33 -15
  197. package/dist/index.js +187 -191
  198. package/dist/index.js.map +1 -1
  199. package/dist/indexing/index.js +2 -2
  200. package/dist/introspection/index.js +11 -11
  201. package/dist/issue-3JNJNPT3.js +19 -0
  202. package/dist/kernel/constants.d.ts +18 -0
  203. package/dist/kernel/enclave/crypto.d.ts +24 -4
  204. package/dist/kernel/enclave/index.d.ts +9 -2
  205. package/dist/kernel/enclave/record-aad.d.ts +131 -0
  206. package/dist/kernel/enclave/record-envelope.d.ts +76 -0
  207. package/dist/kernel/enclave/record-keys/envelope-body.d.ts +34 -2
  208. package/dist/kernel/enclave/record-keys/lifecycle.d.ts +22 -5
  209. package/dist/kernel/enclave/record-keys/record-codec.d.ts +47 -14
  210. package/dist/kernel/enclave/record-keys/rekey-blob.d.ts +88 -0
  211. package/dist/kernel/enclave/record-keys/rekey.d.ts +68 -0
  212. package/dist/kernel/enclave/record-keys/tombstone.d.ts +3 -2
  213. package/dist/kernel/errors.d.ts +71 -12
  214. package/dist/kernel/merge-authority.d.ts +25 -0
  215. package/dist/kernel/noydb.d.ts +27 -4
  216. package/dist/kernel/query/builder.d.ts +15 -2
  217. package/dist/kernel/query/join.d.ts +27 -0
  218. package/dist/kernel/sync-policy.d.ts +0 -2
  219. package/dist/kernel/tier-visibility.d.ts +15 -0
  220. package/dist/kernel/types.d.ts +145 -12
  221. package/dist/kernel/vault.d.ts +22 -18
  222. package/dist/kernel/via/index.d.ts +11 -2
  223. package/dist/{ledger-4WJL66BW.js → ledger-MVPNG5OS.js} +11 -11
  224. package/dist/liberate-4LOJOLDT.js +24 -0
  225. package/dist/{link-set-N4ZPV6E6.js → link-set-3POMQR3I.js} +11 -11
  226. package/dist/{managed-secret-OTHS64IF.js → managed-secret-IARIJJ7Q.js} +11 -3
  227. package/dist/materialized-views/index.js +22 -21
  228. package/dist/migrate-cek-XM2ETTZW.js +19 -0
  229. package/dist/migrate-cek-XM2ETTZW.js.map +1 -0
  230. package/dist/money/index.js +12 -8
  231. package/dist/noydb-IRILUDED.js +84 -0
  232. package/dist/overlay-views/index.js +4 -4
  233. package/dist/periods/index.js +22 -12
  234. package/dist/pod/index.js +75 -86
  235. package/dist/pod-handle-MELERCKU.js +41 -0
  236. package/dist/pod-handle-MELERCKU.js.map +1 -0
  237. package/dist/policy/index.js +11 -4
  238. package/dist/port/to/index.d.ts +4 -4
  239. package/dist/port/to/locator.d.ts +54 -8
  240. package/dist/port/with/i18n-strategy.d.ts +4 -1
  241. package/dist/port/with/lookup-strategy.d.ts +4 -1
  242. package/dist/port/with/merge-authority.d.ts +52 -0
  243. package/dist/port/with/service-bus.d.ts +0 -4
  244. package/dist/port/with/strategies.d.ts +2 -0
  245. package/dist/port/with/team-strategy.d.ts +5 -1
  246. package/dist/portability/index.js +8 -8
  247. package/dist/{post-register-ZAG2CAIY.js → post-register-Z5T7FY45.js} +6 -6
  248. package/dist/query/index.js +3 -3
  249. package/dist/reduce/index.js +4 -4
  250. package/dist/register-UZ37QPDB.js +32 -0
  251. package/dist/registry-ETJNA7PO.js +9 -0
  252. package/dist/registry-F7U6KSLX.js +9 -0
  253. package/dist/registry-L4ELKX6C.js +18 -0
  254. package/dist/registry-SDT5LIGO.js +19 -0
  255. package/dist/request-withdrawal-PVFEYX57.js +31 -0
  256. package/dist/{reveal-CMOJY4VO.js → reveal-DQ2E3QAZ.js} +6 -6
  257. package/dist/revoke-YXY6SHUH.js +24 -0
  258. package/dist/satellites/index.js +1 -1
  259. package/dist/schema-update/index.js +2 -2
  260. package/dist/sealed-record/index.js +20 -13
  261. package/dist/sealed-record/index.js.map +1 -1
  262. package/dist/search/index.js +4 -4
  263. package/dist/{seed-UK4QRIUN.js → seed-DZ4ORU5N.js} +19 -22
  264. package/dist/seed-DZ4ORU5N.js.map +1 -0
  265. package/dist/sequence/index.js +9 -9
  266. package/dist/session/index.js +10 -10
  267. package/dist/shadow/index.js +2 -2
  268. package/dist/share-link/index.js +1 -1
  269. package/dist/signer-Q7XQBMPA.js +25 -0
  270. package/dist/snapshots/index.js +10 -10
  271. package/dist/snapshots/index.js.map +1 -1
  272. package/dist/{stale-ZWXSOWJI.js → stale-NI7SAXAZ.js} +10 -10
  273. package/dist/storage-3VNGSHXS.js +23 -0
  274. package/dist/{store-coordination-provider-PB6QZ57W.js → store-coordination-provider-TYKNR3OU.js} +18 -12
  275. package/dist/store-coordination-provider-TYKNR3OU.js.map +1 -0
  276. package/dist/sync/index.js +11 -11
  277. package/dist/team/index.js +15 -14
  278. package/dist/tiers/index.js +11 -10
  279. package/dist/to/index.js +17 -9
  280. package/dist/to/index.js.map +1 -1
  281. package/dist/transactions/index.js +4 -4
  282. package/dist/{ulid-PTAIMDG4.js → ulid-VQW6ERQN.js} +2 -2
  283. package/dist/util/index.js +1 -1
  284. package/dist/vault-head/index.js +115 -0
  285. package/dist/vault-head/index.js.map +1 -0
  286. package/dist/{verify-RO5RTZOJ.js → verify-6J2YLKSO.js} +5 -5
  287. package/dist/via/lookup/handle.d.ts +4 -1
  288. package/dist/via/money/exact.d.ts +44 -0
  289. package/dist/via/money/index.d.ts +2 -0
  290. package/dist/via/money/normalize.d.ts +20 -0
  291. package/dist/walk-WRA7RAPY.js +21 -0
  292. package/dist/with-audit/guards/immutable-guard.d.ts +14 -0
  293. package/dist/with-audit/periods/active.d.ts +28 -1
  294. package/dist/with-audit/periods/index.d.ts +4 -2
  295. package/dist/with-audit/periods/periods.d.ts +161 -6
  296. package/dist/with-audit/periods/strategy.d.ts +14 -5
  297. package/dist/with-audit/periods/vault-facade.d.ts +89 -10
  298. package/dist/with-audit/periods/window.d.ts +10 -0
  299. package/dist/with-audit/sealed-record/index.d.ts +13 -0
  300. package/dist/with-audit/tiers/index.d.ts +17 -2
  301. package/dist/with-cargo/adopt-partition.d.ts +1 -1
  302. package/dist/with-cargo/extract-partition.d.ts +1 -1
  303. package/dist/with-cargo/index.d.ts +2 -2
  304. package/dist/with-commit/history/history.d.ts +26 -0
  305. package/dist/with-commit/history/index.d.ts +2 -1
  306. package/dist/with-commit/history/ledger/store.d.ts +7 -1
  307. package/dist/with-commit/history/strategy.d.ts +11 -1
  308. package/dist/with-commit/numbering/index.d.ts +0 -5
  309. package/dist/with-commit/vault-head/active.d.ts +2 -0
  310. package/dist/with-commit/vault-head/head.d.ts +28 -0
  311. package/dist/with-commit/vault-head/index.d.ts +10 -0
  312. package/dist/with-commit/vault-head/strategy.d.ts +127 -0
  313. package/dist/with-commit/vault-head/verify.d.ts +90 -0
  314. package/dist/with-formula/materialized-views/types.d.ts +52 -0
  315. package/dist/with-party/directory/cover/storage.d.ts +0 -8
  316. package/dist/with-party/directory/storage.d.ts +0 -11
  317. package/dist/with-party/directory/visibility.d.ts +0 -21
  318. package/dist/with-party/policy/storage.d.ts +0 -10
  319. package/dist/with-party/team/index.d.ts +1 -1
  320. package/dist/with-party/team/keyring.d.ts +149 -3
  321. package/dist/with-party/team/noydb-facade.d.ts +5 -1
  322. package/dist/with-party/team/roster-tag.d.ts +101 -0
  323. package/dist/with-party/team/tiers.d.ts +2 -1
  324. package/dist/with-pod/format.d.ts +10 -12
  325. package/dist/with-pod/index.d.ts +10 -10
  326. package/dist/with-pod/open.d.ts +2 -2
  327. package/dist/with-pod/pod-handle.d.ts +19 -0
  328. package/dist/with-pod/pod-store.d.ts +0 -8
  329. package/dist/with-pod/{bundle.d.ts → pod.d.ts} +26 -19
  330. package/dist/with-pod/ulid.d.ts +1 -1
  331. package/dist/with-shape/blobs/blob-set.d.ts +2 -2
  332. package/dist/with-shape/introspection/index.d.ts +1 -0
  333. package/dist/with-sync/engine.d.ts +54 -5
  334. package/dist/with-sync/strategy.d.ts +3 -0
  335. package/dist/withdraw-accessible-4JTDFRFZ.js +28 -0
  336. package/package.json +13 -5
  337. package/dist/api-WVY3H3YH.js +0 -20
  338. package/dist/backup-YYBE5RPC.js.map +0 -1
  339. package/dist/bundle-handle-JEUWU2SJ.js +0 -36
  340. package/dist/bundle-handle-JEUWU2SJ.js.map +0 -1
  341. package/dist/chunk-26JMGSSC.js.map +0 -1
  342. package/dist/chunk-3737A6EA.js.map +0 -1
  343. package/dist/chunk-4MC5JRRX.js.map +0 -1
  344. package/dist/chunk-52QYGZHH.js.map +0 -1
  345. package/dist/chunk-55LKVALY.js.map +0 -1
  346. package/dist/chunk-5PR33AC4.js.map +0 -1
  347. package/dist/chunk-66W5OOCX.js.map +0 -1
  348. package/dist/chunk-7G6VDWXB.js.map +0 -1
  349. package/dist/chunk-A67356IR.js.map +0 -1
  350. package/dist/chunk-AFHQATY4.js +0 -47
  351. package/dist/chunk-AFHQATY4.js.map +0 -1
  352. package/dist/chunk-AHLJSVRL.js.map +0 -1
  353. package/dist/chunk-C2OOEM57.js.map +0 -1
  354. package/dist/chunk-DIMKRG2E.js +0 -131
  355. package/dist/chunk-DIMKRG2E.js.map +0 -1
  356. package/dist/chunk-E6427JU2.js.map +0 -1
  357. package/dist/chunk-E7OBCBXS.js.map +0 -1
  358. package/dist/chunk-EDXAQ6JI.js.map +0 -1
  359. package/dist/chunk-EP7VPR7Y.js.map +0 -1
  360. package/dist/chunk-ERB6NDDW.js.map +0 -1
  361. package/dist/chunk-G5APARUV.js.map +0 -1
  362. package/dist/chunk-GASWQ3XG.js.map +0 -1
  363. package/dist/chunk-GLKDWWNO.js.map +0 -1
  364. package/dist/chunk-HNGSV2YC.js.map +0 -1
  365. package/dist/chunk-I4F6PKUK.js.map +0 -1
  366. package/dist/chunk-I4ZAO7F7.js.map +0 -1
  367. package/dist/chunk-I6SDX7WX.js.map +0 -1
  368. package/dist/chunk-JXIDGFKS.js.map +0 -1
  369. package/dist/chunk-LWSJG3LI.js.map +0 -1
  370. package/dist/chunk-MWKDOHEF.js.map +0 -1
  371. package/dist/chunk-MZ5ZFO2D.js.map +0 -1
  372. package/dist/chunk-NIVEDYJZ.js.map +0 -1
  373. package/dist/chunk-NWCGDAV6.js +0 -45
  374. package/dist/chunk-NWCGDAV6.js.map +0 -1
  375. package/dist/chunk-PJNTR2NV.js.map +0 -1
  376. package/dist/chunk-PRDRGL73.js.map +0 -1
  377. package/dist/chunk-PY7CI6L5.js.map +0 -1
  378. package/dist/chunk-RKKORO4M.js.map +0 -1
  379. package/dist/chunk-TAGFGKHP.js.map +0 -1
  380. package/dist/chunk-TDJPS3T2.js.map +0 -1
  381. package/dist/chunk-TOAIYQJR.js.map +0 -1
  382. package/dist/chunk-UHXCLPGC.js.map +0 -1
  383. package/dist/chunk-UIBGXRDD.js.map +0 -1
  384. package/dist/chunk-V5KYPBUR.js.map +0 -1
  385. package/dist/chunk-VCETL77O.js.map +0 -1
  386. package/dist/chunk-VN45YLWM.js.map +0 -1
  387. package/dist/chunk-VOQW5LAM.js.map +0 -1
  388. package/dist/chunk-VRA4Q7DA.js.map +0 -1
  389. package/dist/chunk-VV4NSB7P.js.map +0 -1
  390. package/dist/chunk-W5W6KHN2.js.map +0 -1
  391. package/dist/chunk-WHJKIZS7.js.map +0 -1
  392. package/dist/chunk-WYZ5MYUA.js.map +0 -1
  393. package/dist/chunk-ZJADGNYF.js.map +0 -1
  394. package/dist/chunk-ZNACADFG.js.map +0 -1
  395. package/dist/collection-facade-QN5ULWYC.js +0 -45
  396. package/dist/delegation-SSEPLXXO.js.map +0 -1
  397. package/dist/derive-6V3PIZF7.js +0 -22
  398. package/dist/executor-CYJQLKKI.js +0 -9
  399. package/dist/executor-FHHLXO4Y.js +0 -28
  400. package/dist/executor-S4QIKEHW.js +0 -9
  401. package/dist/export-accessible-PE5AYKZR.js +0 -23
  402. package/dist/extract-partition-X2L26O6A.js +0 -38
  403. package/dist/fanout-sidecar-DTBIDOWF.js.map +0 -1
  404. package/dist/find-RBBYKXI7.js +0 -11
  405. package/dist/issue-RNU55YOF.js +0 -19
  406. package/dist/liberate-PX4CAT5V.js +0 -24
  407. package/dist/noydb-YPSEGK32.js +0 -83
  408. package/dist/register-TMD6YRCX.js +0 -32
  409. package/dist/registry-CZVINVQH.js +0 -9
  410. package/dist/registry-FVLDWQKT.js +0 -18
  411. package/dist/registry-IKUR2MXD.js +0 -9
  412. package/dist/registry-JET4HBLY.js +0 -19
  413. package/dist/request-withdrawal-RH55LNZL.js +0 -31
  414. package/dist/revoke-R5TBYVA6.js +0 -24
  415. package/dist/seed-UK4QRIUN.js.map +0 -1
  416. package/dist/signer-AGALOXOO.js +0 -25
  417. package/dist/storage-N7LB275C.js +0 -23
  418. package/dist/store-coordination-provider-PB6QZ57W.js.map +0 -1
  419. package/dist/walk-OCUHCYJ6.js +0 -21
  420. package/dist/with-pod/bundle-handle.d.ts +0 -9
  421. package/dist/withdraw-accessible-QQNWM5BO.js +0 -28
  422. /package/dist/{api-WVY3H3YH.js.map → api-EYNT6KGS.js.map} +0 -0
  423. /package/dist/{chunk-35EBKWQU.js.map → chunk-2LFOMUEA.js.map} +0 -0
  424. /package/dist/{chunk-OF3L2SD6.js.map → chunk-32B7VCKU.js.map} +0 -0
  425. /package/dist/{chunk-MSWYQLMQ.js.map → chunk-3B6S6RSI.js.map} +0 -0
  426. /package/dist/{chunk-7F4DBNSP.js.map → chunk-3O72ZD2E.js.map} +0 -0
  427. /package/dist/{chunk-FNSMZQS4.js.map → chunk-3PMFMUFX.js.map} +0 -0
  428. /package/dist/{chunk-FAXZQ5UF.js.map → chunk-4RAS6HN6.js.map} +0 -0
  429. /package/dist/{chunk-VMCCGUQB.js.map → chunk-6JPGVL7X.js.map} +0 -0
  430. /package/dist/{chunk-WLYIROCJ.js.map → chunk-6YD5SYQS.js.map} +0 -0
  431. /package/dist/{chunk-YAWK6AWF.js.map → chunk-7KAE7CQ2.js.map} +0 -0
  432. /package/dist/{chunk-NKH7GSIH.js.map → chunk-AUPSEJ7O.js.map} +0 -0
  433. /package/dist/{chunk-CCZJJ4I2.js.map → chunk-B6IYATME.js.map} +0 -0
  434. /package/dist/{chunk-4UVDI4XE.js.map → chunk-CLAHBPOI.js.map} +0 -0
  435. /package/dist/{chunk-HVQGCKY4.js.map → chunk-D3R7Q4QK.js.map} +0 -0
  436. /package/dist/{chunk-P7OG2ETF.js.map → chunk-DXKLLKME.js.map} +0 -0
  437. /package/dist/{chunk-JIUVJ4M7.js.map → chunk-EKEIEJL6.js.map} +0 -0
  438. /package/dist/{chunk-DG27IUVI.js.map → chunk-FS7NTGCJ.js.map} +0 -0
  439. /package/dist/{chunk-HXGUIPQB.js.map → chunk-GQXFOAYZ.js.map} +0 -0
  440. /package/dist/{chunk-BTVYJWSN.js.map → chunk-GTHVPVAR.js.map} +0 -0
  441. /package/dist/{chunk-DMQCLZ4Z.js.map → chunk-GWO2IDAB.js.map} +0 -0
  442. /package/dist/{chunk-6HFM7EIT.js.map → chunk-H3G4I3PN.js.map} +0 -0
  443. /package/dist/{chunk-VJFMXYKP.js.map → chunk-HR5R5JOM.js.map} +0 -0
  444. /package/dist/{chunk-FDX7OWWI.js.map → chunk-HYYVT2KZ.js.map} +0 -0
  445. /package/dist/{chunk-JRCYZEHU.js.map → chunk-I6QKB7MT.js.map} +0 -0
  446. /package/dist/{chunk-KUDZVJKQ.js.map → chunk-IJ46VCWD.js.map} +0 -0
  447. /package/dist/{chunk-4HDYQL3J.js.map → chunk-INMHEMXX.js.map} +0 -0
  448. /package/dist/{chunk-AR2JDFAE.js.map → chunk-KV6JM2IA.js.map} +0 -0
  449. /package/dist/{chunk-PVU7LW5L.js.map → chunk-KX57HODD.js.map} +0 -0
  450. /package/dist/{chunk-CEJWMBXO.js.map → chunk-LXECF2ZR.js.map} +0 -0
  451. /package/dist/{chunk-7VHY5E3X.js.map → chunk-MSLPDFK2.js.map} +0 -0
  452. /package/dist/{chunk-HNHCQ556.js.map → chunk-NR2SUJ3H.js.map} +0 -0
  453. /package/dist/{chunk-W3TVWF6N.js.map → chunk-OIBEJN5H.js.map} +0 -0
  454. /package/dist/{chunk-QD724WDJ.js.map → chunk-OMYCSTXL.js.map} +0 -0
  455. /package/dist/{chunk-Z45YRGFO.js.map → chunk-ONVD6GBY.js.map} +0 -0
  456. /package/dist/{chunk-KCQX65FU.js.map → chunk-RKCRPPNB.js.map} +0 -0
  457. /package/dist/{chunk-7TSYBD3E.js.map → chunk-RSXQNFGO.js.map} +0 -0
  458. /package/dist/{chunk-7NXHMW6Y.js.map → chunk-SYS46BL7.js.map} +0 -0
  459. /package/dist/{chunk-747LRSOO.js.map → chunk-TMBSPLUG.js.map} +0 -0
  460. /package/dist/{chunk-WKPJXWKR.js.map → chunk-TX5MKAHA.js.map} +0 -0
  461. /package/dist/{chunk-NJDQ4YSV.js.map → chunk-YKXZHUOW.js.map} +0 -0
  462. /package/dist/{chunk-VW6ZZGCG.js.map → chunk-ZLHHE5XZ.js.map} +0 -0
  463. /package/dist/{chunk-FUHKW252.js.map → chunk-ZZXLB6AS.js.map} +0 -0
  464. /package/dist/{classified-marker-FTOX7Q5L.js.map → classified-marker-NA6HUV33.js.map} +0 -0
  465. /package/dist/{collection-facade-QN5ULWYC.js.map → collection-facade-VBM35WAH.js.map} +0 -0
  466. /package/dist/{computed-6G5M3UPH.js.map → computed-GSTLWSY5.js.map} +0 -0
  467. /package/dist/{dead-filter-ENRIOQIE.js.map → dead-filter-UALP5DJX.js.map} +0 -0
  468. /package/dist/{derive-6V3PIZF7.js.map → derive-YUO3TQYN.js.map} +0 -0
  469. /package/dist/{dispatch-RE74SH6L.js.map → dispatch-4ZHLSFZQ.js.map} +0 -0
  470. /package/dist/{dispatch-BDVGYC6X.js.map → dispatch-77CB75KB.js.map} +0 -0
  471. /package/dist/{enclave-52VUXNRL.js.map → enclave-O4NOROCJ.js.map} +0 -0
  472. /package/dist/{executor-CYJQLKKI.js.map → executor-CZDXBXKE.js.map} +0 -0
  473. /package/dist/{executor-FHHLXO4Y.js.map → executor-DVJAWN3B.js.map} +0 -0
  474. /package/dist/{executor-S4QIKEHW.js.map → executor-VRLG4TQJ.js.map} +0 -0
  475. /package/dist/{export-accessible-PE5AYKZR.js.map → export-accessible-UXSMG7AB.js.map} +0 -0
  476. /package/dist/{extract-partition-X2L26O6A.js.map → extract-partition-TVY7AMKH.js.map} +0 -0
  477. /package/dist/{find-RBBYKXI7.js.map → find-WSARMJBW.js.map} +0 -0
  478. /package/dist/{issue-RNU55YOF.js.map → issue-3JNJNPT3.js.map} +0 -0
  479. /package/dist/{ledger-4WJL66BW.js.map → ledger-MVPNG5OS.js.map} +0 -0
  480. /package/dist/{liberate-PX4CAT5V.js.map → liberate-4LOJOLDT.js.map} +0 -0
  481. /package/dist/{link-set-N4ZPV6E6.js.map → link-set-3POMQR3I.js.map} +0 -0
  482. /package/dist/{managed-secret-OTHS64IF.js.map → managed-secret-IARIJJ7Q.js.map} +0 -0
  483. /package/dist/{noydb-YPSEGK32.js.map → noydb-IRILUDED.js.map} +0 -0
  484. /package/dist/{post-register-ZAG2CAIY.js.map → post-register-Z5T7FY45.js.map} +0 -0
  485. /package/dist/{register-TMD6YRCX.js.map → register-UZ37QPDB.js.map} +0 -0
  486. /package/dist/{registry-CZVINVQH.js.map → registry-ETJNA7PO.js.map} +0 -0
  487. /package/dist/{registry-FVLDWQKT.js.map → registry-F7U6KSLX.js.map} +0 -0
  488. /package/dist/{registry-IKUR2MXD.js.map → registry-L4ELKX6C.js.map} +0 -0
  489. /package/dist/{registry-JET4HBLY.js.map → registry-SDT5LIGO.js.map} +0 -0
  490. /package/dist/{request-withdrawal-RH55LNZL.js.map → request-withdrawal-PVFEYX57.js.map} +0 -0
  491. /package/dist/{reveal-CMOJY4VO.js.map → reveal-DQ2E3QAZ.js.map} +0 -0
  492. /package/dist/{revoke-R5TBYVA6.js.map → revoke-YXY6SHUH.js.map} +0 -0
  493. /package/dist/{signer-AGALOXOO.js.map → signer-Q7XQBMPA.js.map} +0 -0
  494. /package/dist/{stale-ZWXSOWJI.js.map → stale-NI7SAXAZ.js.map} +0 -0
  495. /package/dist/{storage-N7LB275C.js.map → storage-3VNGSHXS.js.map} +0 -0
  496. /package/dist/{ulid-PTAIMDG4.js.map → ulid-VQW6ERQN.js.map} +0 -0
  497. /package/dist/{verify-RO5RTZOJ.js.map → verify-6J2YLKSO.js.map} +0 -0
  498. /package/dist/{walk-OCUHCYJ6.js.map → walk-WRA7RAPY.js.map} +0 -0
  499. /package/dist/{withdraw-accessible-QQNWM5BO.js.map → withdraw-accessible-4JTDFRFZ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kernel/query/join.ts"],"sourcesContent":["/**\n * Query DSL `.join()` — eager, single-FK, intra-vault joins.\n *\n * resolves a ref()-declared foreign key into an attached\n * right-side record under an alias, using one of two planner paths\n * selected automatically:\n *\n * - **nested-loop** — right-side source exposes `lookupById`, so\n * each left row costs O(1). This is the common path for joins\n * against a Collection, which backs `lookupById` with a Map\n * lookup.\n * - **hash** — right-side has only `snapshot()`. Build a\n * `Map<id, record>` once, probe per left row. Same asymptotic\n * cost for our collections, but the path exists as a fallback\n * for custom QuerySource implementations and as an explicit\n * test-only override via `{ strategy: 'hash' }`.\n *\n * Scope:\n *\n * - Equi-joins on declared `ref()` fields only. Joins on\n * undeclared fields throw at plan time with an actionable error\n * naming the field and collection.\n * - Same-vault only. Cross-vault correlation goes\n * through `queryAcross`; this is an architectural\n * invariant, not a limitation we plan to lift.\n * - Hard row ceiling via `JoinTooLargeError` — default 50k per\n * side, override via `{ maxRows }`. Warns at 80% of the ceiling\n * on the existing warn channel.\n * - Three ref-mode behaviors on dangling refs:\n * strict → `DanglingReferenceError`,\n * warn → attach `null` with a one-shot warning,\n * cascade → attach `null` silently (cascade is a delete-time\n * mode; any dangling refs still present at read time are\n * mid-flight cascades or orphans from earlier, not a DSL error).\n *\n * Partition-awareness seam:\n *\n * Every `JoinLeg` carries a `partitionScope` field that is always\n * `'all'` in. The executor never reads this field.\n * partition-aware joins will start populating it from `where()`\n * predicates on the partition key without changing the planner's\n * external shape — this is the whole reason it exists now.\n *\n * Joins stay OUT of the ledger: reads don't touch `_ledger/`,\n * including joined reads.\n */\n\nimport type { RefDescriptor, RefMode } from '../refs.js'\nimport type { Clause } from './predicate.js'\nimport { readPath } from './predicate.js'\nimport { JoinTooLargeError, DanglingReferenceError } from '../errors.js'\n\n/** Planner strategy for a single join leg. Auto-selected unless overridden. */\nexport type JoinStrategy = 'hash' | 'nested'\n\n/** Default per-side row ceiling before `.join()` throws `JoinTooLargeError`. */\nexport const DEFAULT_JOIN_MAX_ROWS = 50_000\n\n/**\n * Fraction of the row ceiling at which a one-shot warning is emitted.\n * At 80% we warn; at 100% we throw. The warn gives consumers a\n * heads-up before the hard error so they can raise the ceiling or\n * filter further without first hitting a broken query.\n */\nconst JOIN_WARN_FRACTION = 0.8\n\n/**\n * Internal representation of a single join leg in the query plan.\n *\n * This is the primary place where constraint #1 is honored:\n * every leg carries a `partitionScope` field that is always `'all'`\n * in and is never read by the executor. partition-aware\n * joins will start populating it from `where()` predicates on the\n * partition key without changing the planner's external shape.\n */\nexport interface JoinLeg {\n /** Field on the left-side record holding the foreign key value. */\n readonly field: string\n /** Alias key under which the joined right-side record attaches. */\n readonly as: string\n /** Target collection name, resolved from the `ref()` declaration. */\n readonly target: string\n /** Ref mode controlling behavior on dangling refs at read time. */\n readonly mode: RefMode\n /** Manual planner strategy override. `undefined` → auto-select. */\n readonly strategy: JoinStrategy | undefined\n /** Per-side row ceiling override. `undefined` → DEFAULT_JOIN_MAX_ROWS. */\n readonly maxRows: number | undefined\n /**\n * Partition scope for future partition-aware joins. Always `'all'`\n * today — the executor never reads this field. Future versions will\n * populate it from `where()` predicates without breaking the\n * planner's external shape. Do not remove even though it looks\n * unused today — that's the whole point of having it.\n */\n readonly partitionScope: 'all' | readonly string[]\n /**\n * When `true`, this is a dictionary join. The executor\n * resolves the left-field value against the dict snapshot and\n * attaches `{ ...labels, key }` rather than a right-side record.\n * `target` holds the dictionary name (not a collection name).\n */\n readonly isDictJoin?: true\n}\n\n/**\n * Minimal shape of a joinable right-side record source.\n *\n * Collections implement this structurally via their `QuerySource`;\n * sources without `lookupById` force the hash-join fallback. Kept as\n * a thin interface so tests can wire up plain-object sources without\n * pulling in the full Collection class.\n *\n * The optional `subscribe` is used by `Query.live()` to merge\n * right-side change streams into the live re-run trigger. Sources\n * that omit `subscribe` still work for live joins — they just\n * don't drive re-fires when their right side mutates. Collection\n * implements `subscribe` by hooking into the existing per-\n * vault event emitter.\n */\nexport interface JoinableSource {\n snapshot(): readonly unknown[]\n lookupById?(id: string): unknown\n /**\n * Default locale a label-resolving query falls back to when the query\n * itself is locale-less. Set by a `staticDict()`-backed source from its\n * `displayLocale` so `{ by: 'label' }` resolves under a locale-less read.\n * Plain `_dict_*`-backed sources omit it.\n */\n readonly displayLocale?: string\n /**\n * Sync present-for-join dressing (#626 retirement, #650 Task 6) — when\n * present and the query carries a locale, each joined right-side record\n * is passed through this hook (built by the right-side `Collection` from\n * its own i18n-text + lookup-label bindings) BEFORE it is attached under\n * the leg's alias — so a joined `i18nText` field resolves to a string\n * (not a raw `{ locale }` map) and a joined lookup field gains its\n * `<field>Label`. Locale-less queries leave joined fields raw\n * (consistent with a locale-less read). Replaces the old `i18nFields`\n * data field — the join executor no longer resolves i18n locale itself,\n * it just calls this hook.\n */\n readonly presentForJoin?: (record: unknown, locale: string) => unknown\n /**\n * Subscribe to mutations on this source. The callback fires\n * AFTER the underlying record set has been updated. Returns an\n * unsubscribe function. Optional — sources without this method\n * cannot trigger live-join re-fires from their side.\n */\n subscribe?(cb: () => void): () => void\n}\n\n/**\n * Join resolution context attached to a `Query` when it's constructed\n * from a `Collection`. Holds everything the `.join()` method needs to\n * translate a field name into a target collection + ref mode, and\n * everything the executor needs to read the right side.\n *\n * Kept as a structural interface so `Vault` can implement it\n * without `Query` needing to import `Vault` (circular-import\n * avoid). The Collection wires this up in its `query()` method using\n * the `joinResolver` back-reference the Vault passes in.\n */\nexport interface JoinContext {\n /** Name of the left-side (owning) collection. */\n readonly leftCollection: string\n /**\n * The owning collection's default locale. Used to resolve joined\n * i18n fields at the `join` layer when a terminal call doesn't pass an\n * explicit locale — so `openVault({ locale })` flows to joins like it does\n * to `get`/`list`. A per-call `toArray({ locale })` overrides it.\n */\n readonly defaultLocale?: string\n /** Look up a `RefDescriptor` by field name on the left collection. */\n resolveRef(field: string): RefDescriptor | null\n /** Resolve a right-side source by target collection name. */\n resolveSource(collectionName: string): JoinableSource | null\n /**\n * Resolve a dictKey join source. Returns a `JoinableSource`\n * whose snapshot exposes `{ key, ...labels }` records, keyed by the\n * stable dictionary key. `null` when the field is not a dictKey.\n *\n * The source is built from the compartment's in-memory dictionary\n * snapshot — same data as `DictionaryHandle.list()`, O(1) per lookup.\n */\n resolveDictSource?(field: string): JoinableSource | null\n}\n\n/**\n * Does this clause address a field that only exists once join legs are\n * attached — i.e. is its path rooted at a join alias?\n *\n * Only `FieldClause` is inspectable. A `FilterClause` carries an opaque\n * function and a `WherePredicateClause` a named one, so neither can be\n * classified; both stay on the pre-join side, which is where they have\n * always run. See `splitAroundJoins`.\n */\nfunction referencesJoinAlias(clause: Clause, aliases: ReadonlySet<string>): boolean {\n if (clause.type !== 'field') return false\n // `where('client.name', …)` addresses the alias; so does the anti-join\n // form `where('client', '==', null)`, where the path IS the alias.\n return aliases.has(clause.field.split('.')[0]!)\n}\n\n/**\n * Split a plan's clauses into those evaluable before the join legs run and\n * those that need the joined shape (#1030).\n *\n * Join legs attach after `where` so the left set can be narrowed (and\n * index-driven) first. That is the right default, but it silently broke any\n * predicate addressing a joined alias: the field did not exist yet, so\n * `readPath` returned `undefined`, nothing matched, and the query returned an\n * empty result with no error.\n *\n * The split is deliberately narrow. When no clause addresses an alias — every\n * query written against the previous behaviour — `postJoin` is empty and the\n * caller takes its original path unchanged. The reordered pipeline therefore\n * only ever runs for queries that match nothing today.\n *\n * KNOWN RESIDUAL: `.filter(r => r.client?.name === 'Ann')` cannot be\n * classified (the predicate is a closure), so it still runs pre-join and still\n * sees no alias. Prefer `.where()` for anything addressing a joined field.\n *\n * Shared by the eager `Query` and the streaming `ScanBuilder` so the two\n * cannot drift on which side a clause belongs to.\n */\nexport function splitAroundJoins(\n clauses: readonly Clause[],\n joins: readonly JoinLeg[],\n): { readonly preJoin: readonly Clause[]; readonly postJoin: readonly Clause[] } {\n if (joins.length === 0 || clauses.length === 0) return { preJoin: clauses, postJoin: [] }\n const aliases = new Set(joins.map(leg => leg.as))\n const preJoin: Clause[] = []\n const postJoin: Clause[] = []\n for (const clause of clauses) {\n ;(referencesJoinAlias(clause, aliases) ? postJoin : preJoin).push(clause)\n }\n return { preJoin, postJoin }\n}\n\n/**\n * Coerce an unknown FK value into a lookup key string.\n *\n * Legitimate ref values are strings or numbers — the same narrowing\n * the write-time `enforceRefsOnPut` path applies. Anything else\n * (objects, arrays, booleans, null, undefined) is treated as \"no\n * ref\" and returns `null`, so the join attaches `null` instead of\n * running `String({})` and producing `'[object Object]'` as a\n * bucket key. This matches the lint rule guidance and keeps\n * bizarre FK values from producing silently-wrong lookups.\n */\nfunction coerceRefKey(value: unknown): string | null {\n if (value === null || value === undefined) return null\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'bigint') return String(value)\n return null\n}\n\n/**\n * Warn-channel deduplication for dangling-ref `'warn'` mode. Keyed\n * by `field → target:refId` so the same dangling ref only produces\n * one warning even across many rows or repeated queries.\n */\nconst warnedDanglingKeys = new Set<string>()\nfunction warnOnceDangling(field: string, target: string, refId: string): void {\n const key = `${field}→${target}:${refId}`\n if (warnedDanglingKeys.has(key)) return\n warnedDanglingKeys.add(key)\n console.warn(\n `[noy-db] .join() encountered dangling ref in 'warn' mode: ` +\n `field \"${field}\" → \"${target}:${refId}\" not found. Attaching null.`,\n )\n}\n\n/**\n * Track row-ceiling warnings to fire only once per (target, side).\n * Prevents per-query spam when a consumer is running the same query\n * repeatedly (e.g. in a reactive loop).\n */\nconst warnedCeilingKeys = new Set<string>()\nfunction warnCeilingApproaching(\n target: string,\n side: 'left' | 'right',\n rows: number,\n maxRows: number,\n): void {\n const key = `${target}:${side}`\n if (warnedCeilingKeys.has(key)) return\n warnedCeilingKeys.add(key)\n const pct = Math.round((rows / maxRows) * 100)\n console.warn(\n `[noy-db] .join() ${side} side is at ${pct}% of the ${maxRows}-row ` +\n `ceiling for target \"${target}\" (${rows} rows). Streaming joins over ` +\n `scan() are not yet supported for collections that need to exceed this.`,\n )\n}\n\n/**\n * Apply every join leg in the plan against a base set of left-side\n * rows. Called by the query executor after `where` / `orderBy` /\n * `offset` / `limit` have narrowed the left set.\n *\n * Each leg attaches a `leg.as` field to every row. Returns a new\n * array of plain objects — the original left rows are not mutated\n * (structural sharing is fine for the inner fields, but the\n * top-level object is a fresh clone so consumers can further mutate\n * safely).\n *\n * **Ordering:** joins run AFTER orderBy / limit / offset in v1.\n * This keeps the planner simple and means queries like \"top 10\n * invoices with client\" sort and paginate the left side first, then\n * join. Sorting *by* a joined field is out of scope for — users\n * can post-sort the result array in userland or wait for \n * (multi-FK chaining) which can be layered on top.\n *\n * **Multi-FK chaining:** each leg's `maxRows` is enforced\n * against the current left-row count independently. Because\n * joins are equi-joins on the target's primary key (one-to-one or\n * one-to-null), the left row count is constant across legs — no\n * cartesian blowup. The per-leg left-side check is still necessary\n * so that a later leg with a tighter ceiling correctly fires on a\n * query like `.join('a', { maxRows: 100_000 }).join('b', { maxRows: 50 })`,\n * which should throw on the second leg if the left set exceeds 50.\n */\nexport function applyJoins(\n rows: readonly unknown[],\n joins: readonly JoinLeg[],\n context: JoinContext,\n locale?: string,\n): unknown[] {\n if (joins.length === 0) return [...rows]\n\n let result: unknown[] = [...rows]\n for (const leg of joins) {\n result = applyOneJoin(result, leg, context, locale)\n }\n return result\n}\n\nfunction applyOneJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n context: JoinContext,\n locale?: string,\n): unknown[] {\n // Dict join path — resolve left-field value against the\n // dictionary snapshot and attach { key, ...labels } under leg.as.\n if (leg.isDictJoin) {\n const dictSource = context.resolveDictSource?.(leg.field)\n if (!dictSource) {\n throw new Error(\n `.join() field \"${leg.field}\" on \"${context.leftCollection}\" is declared as a ` +\n `dictKey join but the dict source could not be resolved. ` +\n `Ensure the dictionary has at least one entry.`,\n )\n }\n const out: unknown[] = []\n const snapshot = dictSource.snapshot()\n const dictMap = new Map<string, unknown>()\n for (const entry of snapshot) {\n const k = readPath(entry, 'key')\n if (typeof k === 'string') dictMap.set(k, entry)\n }\n for (const left of leftRows) {\n const rawId = readPath(left, leg.field)\n const key = coerceRefKey(rawId)\n const dictEntry = key === null ? undefined : dictMap.get(key)\n out.push({ ...(left as Record<string, unknown>), [leg.as]: dictEntry ?? null })\n }\n return out\n }\n\n const source = context.resolveSource(leg.target)\n if (!source) {\n throw new Error(\n `.join() cannot resolve target collection \"${leg.target}\" ` +\n `(referenced from field \"${leg.field}\" on \"${context.leftCollection}\"). ` +\n `Make sure the target collection has been opened via vault.collection() ` +\n `at least once before running the query.`,\n )\n }\n\n const maxRows = leg.maxRows ?? DEFAULT_JOIN_MAX_ROWS\n\n // Per-leg left-side ceiling check. In a\n // multi-FK chain, each leg's `maxRows` is enforced independently\n // against the current left-row count, so\n // `.join('a', { maxRows: 100_000 }).join('b', { maxRows: 50 })`\n // correctly throws on the second leg if the left set exceeds 50.\n if (leftRows.length > maxRows) {\n throw new JoinTooLargeError({\n leftRows: leftRows.length,\n rightRows: -1,\n maxRows,\n side: 'left',\n message:\n `.join() left side has ${leftRows.length} rows, exceeding the ${maxRows}-row ` +\n `ceiling for target \"${leg.target}\". Filter the left side further with ` +\n `where()/limit() before joining, or raise the ceiling via { maxRows }. ` +\n `Streaming joins over scan() are not yet supported.`,\n })\n }\n if (leftRows.length > maxRows * JOIN_WARN_FRACTION) {\n warnCeilingApproaching(leg.target, 'left', leftRows.length, maxRows)\n }\n\n const rightSnapshot = source.snapshot()\n if (rightSnapshot.length > maxRows) {\n throw new JoinTooLargeError({\n leftRows: leftRows.length,\n rightRows: rightSnapshot.length,\n maxRows,\n side: 'right',\n message:\n `.join() right side \"${leg.target}\" has ${rightSnapshot.length} rows, ` +\n `exceeding the ${maxRows}-row ceiling. Raise the ceiling via { maxRows } ` +\n `if the data genuinely fits in memory, or track for streaming joins.`,\n })\n }\n if (rightSnapshot.length > maxRows * JOIN_WARN_FRACTION) {\n warnCeilingApproaching(leg.target, 'right', rightSnapshot.length, maxRows)\n }\n\n // `join`-layer dressing (#650 Task 6, #626 retirement). When the query\n // carries a locale (per-call or the owning collection's default) and the\n // right side declares a `presentForJoin` hook, resolve each matched right\n // record through it before it's attached. Locale-less → leave raw.\n const effLocale = locale ?? context.defaultLocale\n const presentResolve: ((right: unknown) => unknown) | undefined =\n effLocale !== undefined && source.presentForJoin !== undefined\n ? (right) =>\n right !== null && typeof right === 'object'\n ? source.presentForJoin!(right, effLocale)\n : right\n : undefined\n\n // Strategy selection: explicit override wins; otherwise prefer\n // nested-loop when the source exposes lookupById (O(1) per row),\n // falling back to hash join when it doesn't.\n const strategy: JoinStrategy =\n leg.strategy ?? (source.lookupById ? 'nested' : 'hash')\n\n if (strategy === 'nested' && source.lookupById) {\n // Bind through an arrow so the `this` context of lookupById\n // doesn't drift — same pattern as the existing candidateRecords\n // helper in builder.ts.\n const lookup = (id: string): unknown => source.lookupById?.(id)\n return nestedLoopJoin(leftRows, leg, lookup, presentResolve)\n }\n return hashJoin(leftRows, leg, rightSnapshot, presentResolve)\n}\n\nfunction nestedLoopJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n lookupById: (id: string) => unknown,\n presentResolve?: (right: unknown) => unknown,\n): unknown[] {\n const out: unknown[] = []\n for (const left of leftRows) {\n const rawId = readPath(left, leg.field)\n const key = coerceRefKey(rawId)\n let right = key === null ? undefined : lookupById(key)\n if (presentResolve && right !== undefined) right = presentResolve(right)\n out.push(attachJoin(left, leg, right, rawId))\n }\n return out\n}\n\nfunction hashJoin(\n leftRows: readonly unknown[],\n leg: JoinLeg,\n rightSnapshot: readonly unknown[],\n presentResolve?: (right: unknown) => unknown,\n): unknown[] {\n // Build the right-side hash once per query execution. We key on\n // the `id` field because ref() always points to a target's primary\n // key — non-equi and non-id joins are out of scope for.\n const rightMap = new Map<string, unknown>()\n for (const record of rightSnapshot) {\n const rawId = readPath(record, 'id')\n const key = coerceRefKey(rawId)\n if (key !== null) {\n rightMap.set(key, record)\n }\n }\n const out: unknown[] = []\n for (const left of leftRows) {\n const rawId = readPath(left, leg.field)\n const key = coerceRefKey(rawId)\n let right = key === null ? undefined : rightMap.get(key)\n if (presentResolve && right !== undefined) right = presentResolve(right)\n out.push(attachJoin(left, leg, right, rawId))\n }\n return out\n}\n\n/**\n * Attach the resolved right-side record (or null) to the left row\n * under the alias, applying ref-mode semantics for the dangling\n * case.\n *\n * A left-side record whose FK field is null/undefined is NOT a\n * dangling ref — it's \"no reference at all\", which is always\n * allowed regardless of mode. This matches the write-time\n * `enforceRefsOnPut` behavior: \"Nullish ref values are allowed —\n * treat them as 'no reference'.\"\n *\n * Only non-null FKs pointing at non-existent targets trigger the\n * mode behavior.\n */\nfunction attachJoin(\n left: unknown,\n leg: JoinLeg,\n right: unknown,\n rawId: unknown,\n): unknown {\n if (left === null || typeof left !== 'object') {\n // Pathological input — return as-is. Shouldn't happen in\n // practice because QuerySource yields objects, but defensive\n // because plan execution is untyped at this layer.\n return left\n }\n const merged: Record<string, unknown> = { ...(left as Record<string, unknown>) }\n\n // \"No ref at all\" — null/undefined FK value, or a non-string/non-\n // number FK that coerceRefKey treated as no-ref. Never throws\n // regardless of mode; matches the write-time policy that nullish\n // refs are allowed.\n const refKey = coerceRefKey(rawId)\n if (right === undefined) {\n if (refKey !== null && leg.mode === 'strict') {\n throw new DanglingReferenceError({\n field: leg.field,\n target: leg.target,\n refId: refKey,\n message:\n `.join() strict dangling: record references \"${leg.target}:${refKey}\" ` +\n `via field \"${leg.field}\", but no such record exists. Use ref() mode 'warn' ` +\n `or 'cascade' if dangling refs are acceptable, or run ` +\n `vault.checkIntegrity() to find and fix the orphans.`,\n })\n }\n if (refKey !== null && leg.mode === 'warn') {\n warnOnceDangling(leg.field, leg.target, refKey)\n }\n // For 'cascade' and null refs we attach null silently. Cascade\n // is a delete-time mode; any dangling refs visible at read time\n // are either mid-flight or pre-existing orphans, not a DSL error.\n merged[leg.as] = null\n } else {\n merged[leg.as] = right\n }\n return merged\n}\n\n/**\n * Test-only: reset the join warning deduplication state between\n * tests. Production code never calls this — the dedup state is\n * intentionally process-scoped so a noisy query doesn't spam the\n * console once per component render.\n */\nexport function resetJoinWarnings(): void {\n warnedDanglingKeys.clear()\n warnedCeilingKeys.clear()\n}\n"],"mappings":"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","names":[]}
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  installViaBinder
3
- } from "./chunk-UHXCLPGC.js";
3
+ } from "./chunk-JNMTN5D5.js";
4
4
  import {
5
5
  LocaleNotSpecifiedError,
6
6
  MissingTranslationError,
7
7
  ScriptViolationError,
8
8
  TranslatorNotConfiguredError
9
- } from "./chunk-HNGSV2YC.js";
9
+ } from "./chunk-CWM4GQD2.js";
10
10
 
11
11
  // src/port/with/i18n-strategy.ts
12
12
  function notEnabled(op) {
@@ -618,4 +618,4 @@ export {
618
618
  presentI18nForJoin,
619
619
  stripI18nFilled
620
620
  };
621
- //# sourceMappingURL=chunk-7G6VDWXB.js.map
621
+ //# sourceMappingURL=chunk-WVE6YKMX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/port/with/i18n-strategy.ts","../src/kernel/paths.ts","../src/via/i18n/policy.ts","../src/via/i18n/script.ts","../src/via/i18n/binding.ts","../src/via/i18n/core.ts"],"sourcesContent":["/**\n * i18n strategy seam (#623 Task 7 — moved out of `via/i18n/strategy.ts`\n * and `via/i18n/dictionary.ts`, precedent: `port/with/lazy-strategy.ts`).\n * Lives on the `/with` port (the one seam the kernel spine may import\n * statically) so `Collection`/`Vault` can hold the `NO_I18N` default and the\n * two reserved-name/brand predicates without a spine→service static import.\n *\n * Core imports `I18nStrategy` type-only + `NO_I18N` stub; real\n * `applyI18nLocale` / `validateI18nTextValue` / `DictionaryHandle` are only\n * reachable via `withI18n()` in `via/i18n/active.ts`.\n *\n * Solo apps that don't use `i18nText()` fields, don't declare `dictKey()`\n * fields, and don't open a `vault.dictionary(...)` handle ship none of the\n * ~854 LOC behind this seam.\n *\n * Behavior under NO_I18N:\n *\n * - **applyI18nLocale** — returns the record unchanged. Apps without\n * any i18n descriptors never observe a difference; apps that\n * *did* declare i18nText/dictKey fields without opting into the\n * strategy still get raw values back (locale resolution silently\n * skipped). The validators below ensure the misconfiguration is\n * caught at write time instead.\n * - **validateI18nTextValue** — throws when called. Only fires when\n * a collection declared `i18nFields`; if you declared the field,\n * you must opt in.\n * - **buildDictionaryHandle** — throws when called. Only fires when\n * user code calls `vault.dictionary(...)`.\n *\n * #650 Task 1 (via-lookup extraction, phase D): the real\n * `buildDictionaryHandle` (in `via/i18n/active.ts`) now delegates to\n * `withLookup().buildLookupHandle` (`via/lookup/active.ts`) — same\n * handle (`LookupHandle`, aliased as `DictionaryHandle`), new home. This\n * interface's shape is unchanged.\n *\n * @internal\n */\n\nimport type { NoydbStore } from '../../kernel/types.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport type { I18nTextDescriptor } from '../../via/i18n/core.js'\nimport type { Layer } from '../../via/i18n/policy.js'\nimport type { ScriptWarning } from '../../via/i18n/script.js'\nimport type { DictKeyDescriptor, DictionaryHandle, DictionaryOptions, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\nimport type { ViaCryptoCtx } from '../../kernel/via/index.js'\nimport type { EncryptedEnvelope } from '../../kernel/types.js'\n\n/**\n * Options accepted by `I18nStrategy.buildDictionaryHandle`. Mirrors\n * the `DictionaryHandle` constructor verbatim — kept here so core\n * code never imports the dictionary module at runtime.\n *\n * @internal\n */\nexport interface BuildDictionaryHandleOptions<Keys extends string = string> {\n adapter: NoydbStore\n compartmentName: string\n dictionaryName: string\n keyring: UnlockedKeyring\n /**\n * The `reservedEnvelopes('_dict_')` capability (#629 Task 4) — DictionaryHandle's\n * sanctioned crypto door onto its `_dict_<name>` collection. Bound by the\n * Vault to its own `getDEK`, the same per-collection-name DEK resolver\n * every other collection uses.\n */\n reservedEnvelopes: ReturnType<ViaCryptoCtx['reservedEnvelopes']>\n encrypted: boolean\n ledger: LedgerStore | undefined\n options: DictionaryOptions\n findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined\n emitter: NoydbEventEmitter\n /**\n * Used by the active strategy to satisfy the generic-key parameter\n * on the returned handle. The NO_I18N stub never reads it.\n */\n // marker generic — runtime sees no value\n _keyMarker?: Keys\n /** #650 Task 4 (#647) — choke-point participation hooks, passed through to `buildLookupHandle`. */\n onDirty?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n onRecordMutated?: ((collection: string, id: string, action: 'put' | 'delete', version: number) => Promise<void>) | undefined\n /**\n * #647 fix wave 1 — mints a version-ordered delete-marker envelope, passed through to\n * `buildLookupHandle`. See `port/with/lookup-strategy.ts`'s `BuildLookupHandleOptions` doc\n * comment for why this is injected rather than imported by the handle itself.\n */\n buildDeleteMarker: (identity: { collection: string; id: string }, version: number, actor: string) => EncryptedEnvelope\n /** #650 Task 5 (#648) — the real reference check, passed through to `buildLookupHandle`. */\n checkReferencesOnDelete?: ((key: string) => Promise<unknown>) | undefined\n}\n\n/**\n * @internal\n */\nexport interface I18nStrategy {\n /**\n * Resolve `i18nText` fields on a record to the requested locale and\n * return a new object. Returns the input unchanged under\n * `NO_I18N`.\n */\n applyI18nLocale(\n record: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n locale: string,\n fallback?: string | readonly string[],\n layer?: Layer,\n ): Record<string, unknown>\n\n /**\n * Validate that an i18nText field's value satisfies its descriptor\n * (required locales present, etc.). Throws under `NO_I18N` —\n * declaring i18nFields without opting in is a misconfiguration.\n */\n validateI18nTextValue(\n value: unknown,\n field: string,\n descriptor: I18nTextDescriptor,\n ): void\n\n /**\n * Enforce per-locale script constraints over an i18nText value map\n * (write-time). Returns the (possibly filtered) value plus any\n * non-fatal warnings. Returns the value unchanged when the field has\n * no `script` option, or under `NO_I18N`.\n */\n enforceScript(\n value: Record<string, unknown>,\n field: string,\n descriptor: I18nTextDescriptor,\n exempt?: ReadonlySet<string>,\n ): { value: Record<string, unknown>; warnings: ScriptWarning[] }\n\n /**\n * Per-field locales that are unchanged round-tripped densify fills (exempt\n * from write-time script enforcement). Empty under NO_I18N.\n */\n computeExemptFills(\n prior: Record<string, unknown> | undefined,\n incoming: Record<string, unknown>,\n fields: Record<string, I18nTextDescriptor>,\n ): Map<string, Set<string>>\n\n /**\n * Eager-fill empty i18n slots from each field's substitute chain and record\n * provenance in `record['_i18nFilled']`. Mutates `record`. No-op under\n * NO_I18N.\n */\n densify(\n record: Record<string, unknown>,\n prior: Record<string, unknown> | undefined,\n fields: Record<string, I18nTextDescriptor>,\n ): void\n\n /**\n * Construct a typed `DictionaryHandle` for the named dictionary.\n * Throws under `NO_I18N`.\n */\n buildDictionaryHandle<Keys extends string = string>(\n opts: BuildDictionaryHandleOptions<Keys>,\n ): DictionaryHandle<Keys>\n}\n\nfunction notEnabled(op: string): Error {\n return new Error(\n `${op} requires the i18n strategy. Import ` +\n '`{ withI18n }` from \"@noy-db/hub/i18n\" and pass it to ' +\n '`createNoydb({ i18nStrategy: withI18n() })`.',\n )\n}\n\n/**\n * No-i18n stub. Locale resolution is the identity; validation and\n * dictionary construction throw with an actionable pointer.\n *\n * @internal\n */\nexport const NO_I18N: I18nStrategy = {\n applyI18nLocale(record) { return record },\n validateI18nTextValue() { throw notEnabled('i18nText field validation') },\n enforceScript(value) { return { value, warnings: [] } },\n computeExemptFills() { return new Map<string, Set<string>>() },\n densify() {},\n buildDictionaryHandle() { throw notEnabled('vault.dictionary()') },\n}\n\n/**\n * Return true when a collection name is a reserved dictionary collection\n * (the `_dict_*` prefix). Mirrors `DICT_COLLECTION_PREFIX` — now on\n * `via/lookup/handle.ts` (#650 Task 1), re-exported from\n * `via/i18n/dictionary.ts` for compat — duplicated here (not\n * imported) so this port has no VALUE dependency back on the feature; keep\n * the two in sync if the prefix ever changes.\n */\nexport function isDictCollectionName(name: string): boolean {\n return name.startsWith('_dict_')\n}\n\n/** Runtime predicate for detecting a StaticDictDescriptor. */\nexport function isStaticDictDescriptor(x: unknown): x is StaticDictDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbStaticDict?: unknown })._noydbStaticDict === true\n )\n}\n\n/**\n * Runtime predicate for detecting an I18nTextDescriptor. Pure tag check —\n * moved here (#623 Task 11) alongside `isStaticDictDescriptor` so\n * `kernel/via/compose.ts` (`mergeViaFields`'s descriptor-shape classification)\n * can reach it through the port instead of importing `via/i18n/core.js`\n * directly. Re-exported from that module for compat with existing importers.\n */\nexport function isI18nTextDescriptor(x: unknown): x is I18nTextDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbI18nText?: unknown })._noydbI18nText === true\n )\n}\n\n/**\n * Runtime predicate for detecting a DictKeyDescriptor. Pure tag check —\n * moved here (#623 Task 11) for the same reason as `isI18nTextDescriptor`\n * above. Re-exported from `via/i18n/dictionary.js` for compat with\n * existing importers.\n */\nexport function isDictKeyDescriptor(x: unknown): x is DictKeyDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbDictKey?: unknown })._noydbDictKey === true\n )\n}\n\n/**\n * Type-only re-exports (#623 Task 8) — the kernel spine (collection.ts,\n * collection-config.ts, vault.ts, types.ts) imports these descriptor/handle\n * types through the port instead of reaching into `via/i18n/*`\n * directly, so `src/kernel/**` carries no via-i18n specifier at all.\n * `isolatedModules: true` erases these at build time — no runtime coupling.\n */\nexport type { I18nTextDescriptor } from '../../via/i18n/core.js'\nexport type { DictKeyDescriptor, DictionaryHandle, DictionaryOptions, StaticDictDescriptor } from '../../via/i18n/dictionary.js'\nexport type { Layer } from '../../via/i18n/policy.js'\nexport type { ScriptWarning } from '../../via/i18n/script.js'\n","/**\n * Generic dotted-path / `[]`-wildcard record helpers. Kernel-owned:\n * these carry zero i18n logic — they were extracted out of\n * `via/i18n/core.ts` (Task 7, #623) so kernel call-sites (put-time\n * validation, densify) can import them without a spine→service edge.\n *\n * @internal\n */\n\n/**\n * Return all leaf values at `path`, expanding `[].` array wildcards.\n *\n * - `'name'` → `[obj.name]`\n * - `'address.lineOne'` → `[obj.address.lineOne]`\n * - `'contacts[].title'` → `[obj.contacts[0].title, obj.contacts[1].title, …]`\n *\n * Returns an empty array when the path does not resolve (missing key,\n * wrong type, etc.). Used by `enforceI18nOnPut` to validate nested fields.\n */\nexport function getAtPath(obj: Record<string, unknown>, path: string): unknown[] {\n const arrayIdx = path.indexOf('[].')\n if (arrayIdx !== -1) {\n const arrayKey = path.slice(0, arrayIdx)\n const restPath = path.slice(arrayIdx + 3)\n const arr = obj[arrayKey]\n if (!Array.isArray(arr)) return []\n return arr.flatMap(item => {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return []\n return getAtPath(item as Record<string, unknown>, restPath)\n })\n }\n const dotIdx = path.indexOf('.')\n if (dotIdx !== -1) {\n const head = path.slice(0, dotIdx)\n const rest = path.slice(dotIdx + 1)\n const nested = obj[head]\n if (!nested || typeof nested !== 'object' || Array.isArray(nested)) return []\n return getAtPath(nested as Record<string, unknown>, rest)\n }\n const val = obj[path]\n return val !== undefined ? [val] : []\n}\n\n/**\n * Mutate `obj` in-place, setting `value` at the nested `path`.\n * Supports dot notation (`'address.lineOne'`) but not array wildcards —\n * auto-translate on `contacts[].title` style paths is not supported.\n */\nexport function setAtPathInPlace(\n obj: Record<string, unknown>,\n path: string,\n value: unknown,\n): void {\n const dotIdx = path.indexOf('.')\n if (dotIdx !== -1) {\n const head = path.slice(0, dotIdx)\n const rest = path.slice(dotIdx + 1)\n const nested = obj[head]\n if (!nested || typeof nested !== 'object' || Array.isArray(nested)) return\n setAtPathInPlace(nested as Record<string, unknown>, rest, value)\n return\n }\n obj[path] = value\n}\n","/**\n * Per-layer i18n resolution policy.\n *\n * `onMissing` governs what happens when a multilingual field is resolved\n * to a target locale that is absent. It may be a single scalar policy or\n * a per-layer map, so a field can be lenient at the app read boundary but\n * strict inside a materialized view.\n *\n * Effective policy for layer `λ`:\n *\n * ```\n * explicit(λ) = typeof onMissing === 'object' ? onMissing[λ] : undefined\n * scalar = typeof onMissing === 'string' ? onMissing : undefined\n * policy(λ) = explicit(λ) ?? layerDefault(λ) ?? scalar ?? 'throw'\n * ```\n *\n * - `layerDefault('guard') = 'substitute'` — guards are lenient unless\n * EXPLICITLY overridden; they never inherit a scalar policy (a guard\n * reading a display value must not hard-fail on a missing locale).\n * - every other layer has no default, so it inherits the scalar, else\n * falls back to `'throw'` (today's behavior — zero breaking change).\n *\n * @public\n */\nexport type OnMissing = 'substitute' | 'null' | 'throw'\n\n/**\n * The contexts in which a multilingual field is resolved. Each can carry\n * its own `onMissing` policy.\n *\n * - `read` — ordinary app reads (`get`/`list`/query projection).\n * - `guard` — a guard callback reading a value.\n * - `join` — a joined record expanded onto a row.\n * - `mv` — materialized-view input.\n * - `derivation` — derivation input.\n * - `export` — bundle/cover export.\n */\nexport type Layer = 'read' | 'guard' | 'join' | 'mv' | 'derivation' | 'export'\n\n/** Field-level policy: a single scalar, or a per-layer map. */\nexport type OnMissingPolicy = OnMissing | Partial<Record<Layer, OnMissing>>\n\n/**\n * Resolve the effective `OnMissing` for a layer from a field's declared\n * policy. See module docs for the resolution rule.\n */\nexport function resolvePolicy(\n onMissing: OnMissingPolicy | undefined,\n layer: Layer,\n): OnMissing {\n const explicit =\n onMissing && typeof onMissing === 'object' ? onMissing[layer] : undefined\n const scalar = typeof onMissing === 'string' ? onMissing : undefined\n const layerDefault: OnMissing | undefined =\n layer === 'guard' ? 'substitute' : undefined\n return explicit ?? layerDefault ?? scalar ?? 'throw'\n}\n","/**\n * Per-locale script enforcement for `i18nText` fields (write-time).\n *\n * Each locale slot's string is validated against an allowed set of\n * Unicode scripts. `'auto'` infers the set from the locale code with\n * **asymmetric Latin tolerance**: every non-Latin-script locale\n * also allows `Latin`, because proper names and addresses in those\n * locales routinely embed Latin brand/building/technical names — while\n * Latin-script locales do NOT allow other scripts, so the common error\n * (e.g. Thai text dumped into an `en` slot) is still caught.\n *\n * The always-on baseline is `Common` (digits, punctuation), `Inherited`\n * and `Mark` (combining diacritics, joiners, harakat, tone marks), and\n * whitespace — so Latin digits and in-script combining marks never\n * false-reject.\n *\n * @public\n */\nimport { ScriptViolationError } from '../../kernel/errors.js'\nimport type { I18nTextDescriptor } from './core.js'\n\n/** Locales whose base language is written in the Latin script. */\nconst LATIN_BASE = new Set([\n 'en', 'fr', 'de', 'es', 'it', 'pt', 'nl', 'sv', 'no', 'da', 'fi', 'is',\n 'pl', 'cs', 'sk', 'hu', 'ro', 'hr', 'sl', 'et', 'lv', 'lt', 'tr', 'vi',\n 'id', 'ms', 'tl', 'sw', 'af', 'ca', 'gl', 'eu', 'cy', 'ga',\n])\n\n/** Base-language → primary (non-Latin) scripts. Latin is appended by inferScripts. */\nconst SCRIPT_TABLE: Record<string, readonly string[]> = {\n th: ['Thai'],\n ko: ['Hangul', 'Han'],\n ja: ['Han', 'Hiragana', 'Katakana'],\n zh: ['Han'],\n ar: ['Arabic'],\n fa: ['Arabic'],\n ur: ['Arabic'],\n ru: ['Cyrillic'],\n uk: ['Cyrillic'],\n bg: ['Cyrillic'],\n sr: ['Cyrillic'],\n he: ['Hebrew'],\n el: ['Greek'],\n hi: ['Devanagari'],\n ta: ['Tamil'],\n km: ['Khmer'],\n lo: ['Lao'],\n my: ['Myanmar'],\n}\n\n/** Map a BCP-47 script subtag (e.g. `Latn`, `Cyrl`) to allowed scripts. */\nconst SUBTAG_SCRIPTS: Record<string, readonly string[]> = {\n Latn: ['Latin'],\n Cyrl: ['Cyrillic', 'Latin'],\n Hans: ['Han', 'Latin'],\n Hant: ['Han', 'Latin'],\n Thai: ['Thai', 'Latin'],\n Arab: ['Arabic', 'Latin'],\n}\n\n/**\n * Infer the allowed Unicode scripts for a BCP-47 locale, with asymmetric\n * Latin tolerance. A script subtag (`th-Latn`) wins over the base\n * language. Unknown locales default to `['Latin']`.\n */\nexport function inferScripts(locale: string): readonly string[] {\n const parts = locale.split('-')\n const subtag = parts.find((t) => /^[A-Z][a-z]{3}$/.test(t))\n if (subtag && SUBTAG_SCRIPTS[subtag]) return SUBTAG_SCRIPTS[subtag]\n\n const base = (parts[0] ?? '').toLowerCase()\n if (LATIN_BASE.has(base)) return ['Latin']\n const primary = SCRIPT_TABLE[base]\n if (primary) return [...primary, 'Latin'] // asymmetric Latin tolerance\n return ['Latin']\n}\n\n/** Resolve the allowed scripts for a field's locale slot. */\nfunction allowedFor(descriptor: I18nTextDescriptor, locale: string): readonly string[] {\n const script = descriptor.options.script\n if (script && script !== 'auto') {\n const explicit = script[locale]\n if (explicit) return explicit\n }\n return inferScripts(locale)\n}\n\n/** Always-allowed baseline character classes (besides the named scripts). */\nconst BASELINE = String.raw`\\p{White_Space}\\p{Script=Common}\\p{Script=Inherited}\\p{Mark}`\n\n/** Build a whole-string matcher for the allowed scripts. */\nfunction fullMatcher(scripts: readonly string[]): RegExp {\n const cls = scripts.map((s) => `\\\\p{Script=${s}}`).join('')\n return new RegExp(`^[${BASELINE}${cls}]*$`, 'u')\n}\n\n/** Build a single-character matcher (for sampling / stripping). */\nfunction charMatcher(scripts: readonly string[]): RegExp {\n const cls = scripts.map((s) => `\\\\p{Script=${s}}`).join('')\n return new RegExp(`[${BASELINE}${cls}]`, 'u')\n}\n\n/** Collect a short sample of characters that violate the allowed scripts. */\nfunction offendingSample(str: string, scripts: readonly string[]): string {\n const ok = charMatcher(scripts)\n const bad: string[] = []\n for (const ch of str) {\n if (!ok.test(ch)) bad.push(ch)\n if (bad.length >= 8) break\n }\n return bad.join('')\n}\n\n/** Remove characters that violate the allowed scripts. */\nfunction stripDisallowed(str: string, scripts: readonly string[]): string {\n const ok = charMatcher(scripts)\n let out = ''\n for (const ch of str) if (ok.test(ch)) out += ch\n return out\n}\n\n/** A non-fatal script violation recorded under `'filter'`/`'warn'` modes. */\nexport interface ScriptWarning {\n readonly field: string\n readonly locale: string\n readonly expected: readonly string[]\n readonly sample: string\n}\n\n/**\n * Enforce a field's script constraint over an i18nText value map.\n *\n * - No `script` option ⇒ returns the value unchanged.\n * - `onScriptViolation: 'reject'` (default) ⇒ throws {@link ScriptViolationError}.\n * - `'filter'` ⇒ returns a copy with disallowed characters stripped + warnings.\n * - `'warn'` ⇒ returns the value unchanged + warnings.\n */\nexport function enforceScript(\n value: Record<string, unknown>,\n field: string,\n descriptor: I18nTextDescriptor,\n exempt?: ReadonlySet<string>,\n): { value: Record<string, unknown>; warnings: ScriptWarning[] } {\n const opt = descriptor.options\n if (!opt.script) return { value, warnings: [] }\n\n const mode = opt.onScriptViolation ?? 'reject'\n const warnings: ScriptWarning[] = []\n let out = value\n\n for (const [locale, raw] of Object.entries(value)) {\n if (exempt?.has(locale)) continue\n if (typeof raw !== 'string') continue\n const allowed = allowedFor(descriptor, locale)\n if (fullMatcher(allowed).test(raw)) continue\n\n const sample = offendingSample(raw, allowed)\n if (mode === 'reject') {\n throw new ScriptViolationError(field, locale, allowed, sample)\n }\n warnings.push({ field, locale, expected: allowed, sample })\n if (mode === 'filter') {\n if (out === value) out = { ...value }\n out[locale] = stripDisallowed(raw, allowed)\n }\n }\n\n return { value: out, warnings }\n}\n","/**\n * The i18n `ViaBinding` — wires the i18n engine (auto-translate/script\n * enforcement/validation/densify on write; locale + dict-label presentation\n * on read) into the kernel's generic Via port. Mirrors\n * `via/money/binding.ts`'s #553 static-link pattern.\n *\n * LIVE (#623 Task 8 wired the cutover): `i18nBinding()`/`linkI18nVia()` are\n * the real put/read path for every i18n-declaring collection —\n * `collection.ts`'s `_putInternal`/`applyLocaleToRecord` (the call sites\n * this file's bodies were moved/adapted from) now delegate their i18n\n * stages to `this.via.encodeWrite`/`this.via.present` instead of running\n * the hand-wired i18n logic inline.\n *\n * `i18nText()`, `dictKey()`, `staticDict()` each call {@link linkI18nVia}\n * first — the same #553 pattern `money()` uses.\n */\nimport type { ViaBinding, ViaWriteCtx, ViaReadCtx } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport type { I18nTextDescriptor } from './core.js'\nimport { stripI18nFilled } from './core.js'\nimport type { DictKeyDescriptor, StaticDictDescriptor } from './dictionary.js'\nimport type { I18nStrategy } from '../../port/with/i18n-strategy.js'\nimport { isStaticDictDescriptor } from '../../port/with/i18n-strategy.js'\nimport { resolvePolicy, type Layer } from './policy.js'\nimport { getAtPath, setAtPathInPlace } from '../../kernel/paths.js'\nimport { TranslatorNotConfiguredError, LocaleNotSpecifiedError } from '../../kernel/errors.js'\n\n/**\n * Config a collection's i18n declarations resolve to — the binding's\n * construction input. Fields are loosely typed (`unknown`) at this seam\n * because the kernel's `ViaBinder` contract is opaque-config-in; the\n * concrete i18n types are applied inside the binding's own functions.\n */\nexport interface I18nViaConfig {\n i18nFields?: Record<string, unknown> // I18nTextDescriptor map\n dictKeyFields?: Record<string, unknown> // DictKeyDescriptor | StaticDictDescriptor map\n i18nDensifyFields?: Record<string, unknown> // I18nTextDescriptor subset (densifyOnWrite: true)\n strategy: unknown // I18nStrategy (real or NO_I18N)\n defaultLocale?: string\n autoTranslateHook?: (...args: unknown[]) => Promise<string>\n dictLabelResolver?: (...args: unknown[]) => Promise<string | undefined>\n i18nPutValidator?: (record: unknown) => void // the vault-built closure (unchanged wiring)\n collectionName: string\n}\n\n// ─── write pipeline ─────────────────────────────────────────────────────\n\n/**\n * Auto-translate missing i18nText translations. Runs BEFORE i18n\n * validation so translated values satisfy the required-locale constraint.\n * Throws `TranslatorNotConfiguredError` when a field has\n * `autoTranslate: true` but no hook was configured. Mutates `record`\n * in place (mirrors `collection.ts:1830-1874`).\n */\nasync function runI18nAutoTranslate(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n cfg: I18nViaConfig,\n): Promise<void> {\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n if (!descriptor.options.autoTranslate) continue\n // getAtPath returns [] for array-wildcard paths — auto-translate on\n // 'contacts[].field' style paths is not supported; skip silently.\n const leafValues = getAtPath(record, field)\n if (leafValues.length !== 1) continue\n const value = leafValues[0]\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue\n const map = value as Record<string, string>\n // Determine which locales need translation. For 'all', translate all\n // declared languages that are missing. For 'any', only translate if\n // none are present. For string[], translate the listed required ones.\n const { languages, required } = descriptor.options\n const missing: string[] = languages.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length === 0) continue\n // Find a source locale (first present non-empty value)\n const sourceLocale = languages.find((l) => l in map && map[l] !== '')\n if (!sourceLocale) continue\n if (!cfg.autoTranslateHook) {\n throw new TranslatorNotConfiguredError(field, cfg.collectionName)\n }\n // Only translate locales that are actually needed\n const toTranslate =\n required === 'any'\n ? [] // 'any' is already satisfied since sourceLocale exists\n : required === 'all'\n ? missing\n : missing.filter((l) => required.includes(l))\n const translated = { ...map }\n for (const targetLocale of toTranslate) {\n translated[targetLocale] = await cfg.autoTranslateHook(\n map[sourceLocale]!,\n sourceLocale,\n targetLocale,\n field,\n cfg.collectionName,\n )\n }\n setAtPathInPlace(record, field, translated)\n }\n}\n\n/**\n * i18nText script enforcement — runs AFTER auto-translate (so generated\n * values are checked too). Throws `ScriptViolationError` (from inside\n * `strategy.enforceScript`) under the default 'reject'; 'filter' strips\n * disallowed chars in place; 'warn' leaves the value unchanged. Mirrors\n * `collection.ts:1896-1927`.\n */\nfunction runI18nScriptEnforcement(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n strategy: I18nStrategy,\n exemptFills: Map<string, Set<string>> | undefined,\n ctx: ViaWriteCtx,\n cfg: I18nViaConfig,\n): void {\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n if (!descriptor.options.script) continue\n for (const leaf of getAtPath(record, field)) {\n if (!leaf || typeof leaf !== 'object' || Array.isArray(leaf)) continue\n const leafMap = leaf as Record<string, unknown>\n const { value: cleaned, warnings } = strategy.enforceScript(\n leafMap,\n field,\n descriptor,\n exemptFills?.get(field),\n )\n if (cleaned !== leafMap) Object.assign(leafMap, cleaned)\n // enforceScript only returns warnings under 'warn'/'filter' ('reject'\n // throws first), so this guard never fires — it makes that invariant\n // explicit and keeps `mode` off the optional-undefined type.\n const mode = descriptor.options.onScriptViolation\n if (mode === 'warn' || mode === 'filter') {\n for (const w of warnings) {\n // Exact original payload shape (collection.ts:1916-1922 pre-cutover).\n ctx.emit('i18n:script-violation', {\n vault: ctx.vault,\n collection: cfg.collectionName,\n id: ctx.id,\n mode,\n warning: w,\n })\n }\n }\n }\n }\n}\n\n/**\n * `encodeWrite` — translate → script → validate → densify, in the EXACT\n * order `_putInternal` runs them today (seam-map Part 2, stages 7-11).\n */\nasync function runI18nWriteStages(\n record: Record<string, unknown>,\n ctx: ViaWriteCtx,\n cfg: I18nViaConfig,\n): Promise<Record<string, unknown>> {\n const i18nFields = cfg.i18nFields as Record<string, I18nTextDescriptor> | undefined\n const i18nDensifyFields = cfg.i18nDensifyFields as Record<string, I18nTextDescriptor> | undefined\n const strategy = cfg.strategy as I18nStrategy\n\n // 1. Auto-translate.\n if (i18nFields) {\n await runI18nAutoTranslate(record, i18nFields, cfg)\n }\n\n // 2. densifyOnWrite: read prior fills so a round-tripped derived copy is\n // exempt from script enforcement and can be refreshed. Read once here,\n // reused by densify() below. `ctx.prior()` resolves the real prior\n // record (collection.ts wires it to `resolveDensifyPrior`, #623 Task 8).\n let densifyPrior: Record<string, unknown> | undefined\n let exemptFills: Map<string, Set<string>> | undefined\n if (i18nDensifyFields) {\n densifyPrior = (await ctx.prior()) ?? undefined\n exemptFills = strategy.computeExemptFills(densifyPrior, record, i18nDensifyFields)\n }\n\n // 3. Script enforcement.\n if (i18nFields) {\n runI18nScriptEnforcement(record, i18nFields, strategy, exemptFills, ctx, cfg)\n }\n\n // 4. i18nText validation — AFTER auto-translate + script so the record is\n // trustworthy. Throws MissingTranslationError when required translations\n // are absent. The vault-built closure (unchanged wiring).\n cfg.i18nPutValidator?.(record)\n\n // 5. Eager-fill empty slots + record provenance. Runs AFTER the authored\n // gates (required + script) so only authored slots are validated.\n if (i18nDensifyFields) {\n strategy.densify(record, densifyPrior, i18nDensifyFields)\n }\n\n return record\n}\n\n// ─── read pipeline ──────────────────────────────────────────────────────\n\n/**\n * `present` — i18nText locale resolution + dictKey/staticDict label\n * resolution + `_i18nFilled` stripping. Adapted from\n * `applyLocaleToRecord`'s i18n+dict+strip portions (`collection.ts:4184-\n * 4301`) — the money-decode portion of that method is a separate binding\n * (`via/money`) and is NOT this function's concern.\n */\nasync function runI18nPresent(\n record: Record<string, unknown>,\n ctx: ViaReadCtx,\n cfg: I18nViaConfig,\n): Promise<Record<string, unknown>> {\n const i18nFields = cfg.i18nFields as Record<string, I18nTextDescriptor> | undefined\n const dictKeyFields = cfg.dictKeyFields as Record<string, DictKeyDescriptor | StaticDictDescriptor> | undefined\n const strategy = cfg.strategy as I18nStrategy\n const hasI18n = i18nFields !== undefined && Object.keys(i18nFields).length > 0\n const hasDict = dictKeyFields !== undefined && Object.keys(dictKeyFields).length > 0\n if (!hasI18n && !hasDict) return record\n\n const locale = typeof ctx.locale === 'string' ? ctx.locale : undefined\n const fallback = ctx.fallback as string | readonly string[] | undefined\n const layer = ctx.layer as Layer\n\n let result = record\n\n // i18nText / dictKey resolution require an active locale — EXCEPT a\n // static dict declaring a `displayLocale`, which resolves its\n // `<field>Label` even under a locale-less read (the hybrid hinge). Only\n // this second gate relaxes, and ONLY for static-display fields — folding\n // `hasI18n` in here would let an i18nText-only collection fall through to\n // applyI18nLocale(…, undefined) on a locale-less read, breaking the\n // raw-{th,en}-map invariant.\n const hasStaticDisplay =\n hasDict &&\n dictKeyFields !== undefined &&\n Object.values(dictKeyFields).some(\n (d) => isStaticDictDescriptor(d) && d.displayLocale !== undefined,\n )\n\n // Strip the internal densify marker even when no locale is active\n // (applyI18nLocale, which normally strips it, is skipped on this path).\n // Non-mutating: never touches the cached/stored record object.\n if (!locale && !hasStaticDisplay) return stripI18nFilled(result)\n\n // 1. i18nText resolution — guarded on `locale`, because the relaxed gate\n // above can now be entered with `locale === undefined` (static-display).\n // The layer selects the field's per-layer `onMissing` policy inside\n // applyI18nLocale.\n if (locale && hasI18n && i18nFields) {\n result = strategy.applyI18nLocale(result, i18nFields, locale, fallback, layer)\n }\n\n // 2. dictKey / staticDict label resolution\n if (hasDict && dictKeyFields && cfg.dictLabelResolver && locale !== 'raw') {\n const withLabels = { ...result }\n const resolver = cfg.dictLabelResolver\n for (const [field, desc] of Object.entries(dictKeyFields)) {\n // dictKey default policy is 'null' (omit/null on miss) — today's\n // behavior — unless the field declares onMissing. 'substitute'\n // walks the declared substitute chain (passed as the resolver's\n // fallback); 'throw' raises LocaleNotSpecifiedError.\n const policy = desc.onMissing ? resolvePolicy(desc.onMissing, layer) : 'null'\n const fieldFallback =\n policy === 'substitute'\n ? (fallback ?? desc.substitute)\n : fallback\n // Per-field effective locale: a static dict falls back to its\n // `displayLocale` when no locale is active (the hybrid hinge); a\n // plain dictKey with no displayLocale gets `undefined` → its\n // <field>Label is omitted on a locale-less read (today's behavior).\n const effLocale =\n locale ??\n (isStaticDictDescriptor(desc) ? desc.displayLocale : undefined)\n // Resolve one key → label | null, honoring the policy. With no\n // effective locale there is nothing to resolve against.\n const resolveKey = async (key: string): Promise<string | null> => {\n if (!effLocale) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field,\n `dictKey \"${field}\": no locale active to resolve key \"${key}\".`,\n )\n }\n return null\n }\n const label = await resolver(desc.name, key, effLocale, fieldFallback)\n if (label === undefined) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field,\n `dictKey \"${field}\": no label for key \"${key}\" in locale \"${effLocale}\".`,\n )\n }\n return null\n }\n return label\n }\n\n if (field.includes('[].')) {\n // Wildcard path `arrayKey[].leaf`: add a per-element sibling\n // `<leaf>Label`. Single level + simple leaf.\n const parts = field.split('[].')\n const arrayKey = parts[0]!\n const leaf = parts[1]\n if (!leaf || leaf.includes('.')) continue\n const arr = (withLabels as Record<string, unknown>)[arrayKey]\n if (!Array.isArray(arr)) continue\n const labelKey = `${leaf}Label`\n ;(withLabels as Record<string, unknown>)[arrayKey] = await Promise.all(\n arr.map(async (el) => {\n if (!el || typeof el !== 'object' || Array.isArray(el)) return el\n const k = (el as Record<string, unknown>)[leaf]\n if (typeof k !== 'string') return el\n return { ...(el as Record<string, unknown>), [labelKey]: await resolveKey(k) }\n }),\n )\n continue\n }\n\n const val = result[field]\n if (Array.isArray(val)) {\n // Array-of-keys → [{ key, label }] pair objects (key preserved).\n withLabels[`${field}Label`] = await Promise.all(\n val.map(async (k) => ({\n key: k,\n label: typeof k === 'string' ? await resolveKey(k) : null,\n })),\n )\n } else if (typeof val === 'string') {\n const label = await resolveKey(val)\n // Scalar under 'null'/default omits the label key (today's\n // behavior); 'substitute' returns a value; 'throw' threw above.\n if (label !== null) withLabels[`${field}Label`] = label\n }\n }\n result = withLabels\n }\n\n // Final guard: the locale-less static-display path skips\n // applyI18nLocale's strip, so ensure the densify marker never leaks here\n // either. Non-mutating (no-op when absent or already stripped above).\n return stripI18nFilled(result)\n}\n\n// ─── introspection ──────────────────────────────────────────────────────\n\nfunction buildI18nDescribeFragment(cfg: I18nViaConfig): Record<string, unknown> {\n return {\n i18nFields: cfg.i18nFields ? Object.keys(cfg.i18nFields) : [],\n dictKeyFields: cfg.dictKeyFields ? Object.keys(cfg.dictKeyFields) : [],\n ...(cfg.defaultLocale !== undefined ? { defaultLocale: cfg.defaultLocale } : {}),\n }\n}\n\n// ─── binding ────────────────────────────────────────────────────────────\n\nexport function i18nBinding(cfg: I18nViaConfig): ViaBinding {\n return {\n brand: 'i18n',\n posture: { encryptedAtRest: 'envelope', queryable: 'full', exportable: true, forgettable: true },\n // DictionaryHandle's `_dict_*` reserved collections (#629 Task 4) — the\n // codec boundary's `reservedEnvelopes` door may address any collection\n // name under this prefix.\n reservedPrefixes: ['_dict_'],\n covers: (field) =>\n (cfg.i18nFields !== undefined && field in cfg.i18nFields)\n || (cfg.dictKeyFields !== undefined && field in cfg.dictKeyFields),\n encodeWrite: async (record, ctx) => runI18nWriteStages(record, ctx, cfg),\n present: async (record, ctx) => runI18nPresent(record, ctx, cfg),\n describeFragment: () => buildI18nDescribeFragment(cfg),\n }\n}\n\nexport function linkI18nVia(): void {\n installViaBinder('i18n', (c) => i18nBinding(c as I18nViaConfig))\n}\n","/**\n * i18nText schema type —\n *\n * `i18nText({ languages, required })` creates a descriptor for a\n * multi-language content field whose value is stored as a\n * `{ [locale]: string }` map (e.g. `{ en: 'Consulting', th: 'ที่ปรึกษา' }`).\n *\n * On put, the descriptor validates that required languages are present.\n * On read (when a `locale` option is passed), the map is collapsed to the\n * caller's locale string via the fallback chain.\n *\n * Design decisions\n * ────────────────\n *\n * **Descriptor pattern (not a Zod type).**\n * `i18nText()` returns a plain descriptor object used in the collection's\n * `i18nFields` option — same pattern as `ref()` / `dictKey()`. This keeps\n * `@noy-db/core` at zero runtime dependencies and avoids Zod v3 field-type\n * constraints. TypeScript inference is handled via the descriptor's type.\n *\n * **Enforcement at the collection boundary.**\n * The `required` option is checked by `Collection.put()` via the compartment's\n * registered `i18nFields`. Failed validation throws `MissingTranslationError`\n * — a distinct class from `SchemaValidationError` so callers can tell\n * \"wrong shape\" from \"missing translations\".\n *\n * **Resolution is post-decryption.**\n * Locale resolution happens AFTER `decryptRecord()`, as a pure in-memory\n * transform. No additional crypto work is needed. The resolved record is\n * returned in place of the stored one, with i18nText fields replaced by\n * their locale-resolved strings.\n *\n * **`locale: 'raw'`.**\n * Passing `{ locale: 'raw' }` skips resolution and returns the full\n * `{ [locale]: string }` map — useful for bilingual exports, admin UIs,\n * and any context where all translations must be visible at once.\n *\n * **Out of scope.**\n * Pluralization, RTL rendering, date/number formatting, per-locale CRDT\n * merging.\n */\n\nimport { MissingTranslationError, LocaleNotSpecifiedError } from '../../kernel/errors.js'\nimport type { OnMissing, OnMissingPolicy, Layer } from './policy.js'\nimport { resolvePolicy } from './policy.js'\nimport { inferScripts } from './script.js'\nimport { linkI18nVia } from './binding.js'\n\n// ─── I18nMap type helper ───────────────────────────────────────────────\n\n/** Flatten an intersection into a single object literal for nicer hovers. */\ntype Prettify<T> = { [K in keyof T]: T[K] } & {}\n\n/**\n * The stored shape of a multilingual field, inferred from its `required`\n * mode — so the compiler forces you to handle an absent optional locale\n * (`string | undefined`) instead of silently yielding `undefined`.\n *\n * Mirrors `i18nText({ languages, required })`:\n * - `'all'` (default) — every locale required: `{ th: string; en: string }`\n * - `'any'` — every locale optional: `{ th?: string; en?: string }`\n * (the \"at least one present\" guarantee is runtime-only — not expressible\n * in TypeScript — so each key is optional)\n * - `readonly L[]` — listed locales required, the rest optional:\n * `I18nMap<'th'|'en', ['th']>` → `{ th: string; en?: string }`\n *\n * @example\n * ```ts\n * type Lang = 'th' | 'en'\n * interface Contact {\n * name: I18nMap<Lang, 'any'> // { th?: string; en?: string }\n * legalName: I18nMap<Lang, ['th']> // { th: string; en?: string }\n * slug: I18nMap<Lang> // { th: string; en: string }\n * }\n * ```\n *\n * @public\n */\nexport type I18nMap<\n Langs extends string,\n Required extends 'all' | 'any' | readonly Langs[] = 'all',\n> = Required extends 'all'\n ? Record<Langs, string>\n : Required extends 'any'\n ? Partial<Record<Langs, string>>\n : Required extends readonly (infer R extends Langs)[]\n ? Prettify<Record<R, string> & Partial<Record<Exclude<Langs, R>, string>>>\n : never\n\n// ─── i18nText descriptor ───────────────────────────────────────────────\n\n/**\n * Options for `i18nText()`.\n *\n * `languages` declares the full set of supported locales. `required`\n * controls which must be present on every `put()`.\n *\n * `autoTranslate` is the per-field opt-in for the `plaintextTranslator`\n * hook. When `true` and a `plaintextTranslator` is configured\n * on `createNoydb()`, missing translations are generated before `put()`.\n * Default: `false`.\n */\nexport interface I18nTextOptions {\n /** All supported locale codes (BCP 47). */\n readonly languages: readonly string[]\n /**\n * Which locales must be present on every `put()`.\n *\n * - `'all'` — every declared language must be present.\n * - `'any'` — at least one declared language must be present.\n * - `string[]` — listed locales are required; others are optional.\n */\n readonly required: 'all' | 'any' | readonly string[]\n /**\n * Per-field opt-in for the `plaintextTranslator` hook.\n * When `true`, missing required translations are auto-generated\n * before `put()` if a translator is configured. Default: `false`.\n */\n readonly autoTranslate?: boolean\n /**\n * What to do when this field is resolved to a locale that is absent.\n * A single policy, or a per-layer map (read/guard/join/mv/derivation/\n * export). Default `'throw'` — today's behavior, zero breaking change.\n * See {@link OnMissingPolicy}.\n *\n * NOTE (current wiring): ALL layers are enforced — `read` (`get`/`list`),\n * `guard`, `derivation`, `mv`, `join`, `export`. Guard / derivation\n * `ctx.vault` reads resolve under their own layer policy (`guard` defaults to\n * the lenient `'substitute'`). The `mv` layer fires for materialized views\n * that declare `{ i18nLocale, i18nFields }` — UNION (group-key i18n fields\n * resolve before the unified-row bucketing) and query-form (resolved in\n * `GroupedReduction.run` before `groupAndReduce`); grouping a raw i18n field\n * without a locale throws. The `join` layer resolves a joined right-side i18n\n * field to the query locale (`toArray({ locale })` or the vault default; raw\n * when locale-less). The `export` layer fires for\n * `exportStream`/`exportJSON({ resolveLabels })` — records collapse to the\n * export locale.\n */\n readonly onMissing?: OnMissingPolicy\n /**\n * Ordered preferred-substitute locales used when `onMissing` resolves\n * to `'substitute'` and the target locale is absent. `'any'` as an\n * element means \"first non-empty value\". A caller-supplied `fallback`\n * at read time takes precedence over this declared list.\n */\n readonly substitute?: readonly string[]\n /**\n * Smart-substitute. When `true`, a missing-locale `substitute` walk that\n * misses the explicit chain prefers the available locale whose script is\n * nearest the target (same script, then Latin) rather than an arbitrary value\n * — e.g. a missing Thai label prefers another Thai (or Latin) translation over\n * an unreadable script. Default `false` (legacy first-non-empty behavior).\n */\n readonly smartSubstitute?: boolean\n /**\n * Per-locale script enforcement (write-time). `'auto'` infers the\n * allowed Unicode scripts per locale (asymmetric Latin tolerance); an\n * object overrides per slot. Absent ⇒ no check. See `./script.ts`.\n */\n readonly script?: 'auto' | Partial<Record<string, readonly string[]>>\n /**\n * What to do when a slot's value contains characters outside its\n * allowed script set. Default `'reject'`.\n */\n readonly onScriptViolation?: 'reject' | 'filter' | 'warn'\n /**\n * Eager-fill empty locale slots from the substitute chain at\n * write time, recording provenance in the internal `_i18nFilled` marker.\n * Mutually exclusive with an EXPLICIT `'throw'` onMissing policy (densify\n * fills every hole, so a throw would be unreachable). Without an explicit\n * `substitute`, fills from `'any'` (first non-empty). Default absent.\n */\n readonly densifyOnWrite?: boolean\n}\n\n/**\n * Descriptor returned by `i18nText()`. Attach to the collection's\n * `i18nFields` option:\n *\n * ```ts\n * const lineItems = company.collection<LineItem>('line-items', {\n * i18nFields: {\n * description: i18nText({ languages: ['en', 'th'], required: 'all' }),\n * },\n * })\n * ```\n */\nexport interface I18nTextDescriptor {\n readonly _noydbI18nText: true\n /** Via port brand marker — lets an `I18nTextDescriptor` satisfy the kernel's opaque `ViaDescriptor` (#623 Task 9). */\n readonly _viaBrand: 'i18n'\n readonly options: I18nTextOptions\n}\n\n/**\n * Create an `I18nTextDescriptor` for a multi-language content field.\n *\n * @param options Language list + enforcement mode.\n *\n * @example\n * ```ts\n * i18nText({ languages: ['en', 'th'], required: 'all' })\n * i18nText({ languages: ['en', 'th'], required: ['th'], autoTranslate: true })\n * ```\n */\nexport function i18nText(options: I18nTextOptions): I18nTextDescriptor {\n // The declaration is the Via binding's opt-in unit (#553): constructing\n // a descriptor statically links the i18n binding into the kernel's Via\n // port, so every later kernel consultation finds it already installed.\n linkI18nVia()\n if (options.densifyOnWrite === true && hasThrowPolicy(options.onMissing)) {\n throw new Error(\n `i18nText: densifyOnWrite cannot be combined with an explicit onMissing 'throw' ` +\n `policy — densify fills every empty slot, so a 'throw' would be unreachable. ` +\n `Remove the 'throw' policy or disable densifyOnWrite.`,\n )\n }\n return { _noydbI18nText: true, _viaBrand: 'i18n', options }\n}\n\n/** True when `onMissing` declares `'throw'` for any layer (scalar or per-layer). */\nfunction hasThrowPolicy(onMissing: OnMissingPolicy | undefined): boolean {\n if (onMissing === undefined) return false\n if (typeof onMissing === 'string') return onMissing === 'throw'\n return Object.values(onMissing).includes('throw')\n}\n\n// `isI18nTextDescriptor` now lives on the kernel port (#623 Task 11,\n// port/with/i18n-strategy.ts, alongside `isStaticDictDescriptor`) —\n// re-exported here for compat with existing importers of this module.\nexport { isI18nTextDescriptor } from '../../port/with/i18n-strategy.js'\n\n// ─── Validation helpers ────────────────────────────────────────────────\n\n/**\n * Validate that a value is a valid `{ [locale]: string }` map and that\n * all required locales are present. Throws `MissingTranslationError`\n * when the required constraint is violated.\n *\n * Called by `Collection.put()` for each registered `i18nField`.\n *\n * @param value The raw field value from the record being put.\n * @param field The field name (used in the thrown error message).\n * @param descriptor The `i18nText()` descriptor for this field.\n */\nexport function validateI18nTextValue(\n value: unknown,\n field: string,\n descriptor: I18nTextDescriptor,\n): void {\n const { options } = descriptor\n\n // Must be a non-null object\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new MissingTranslationError(\n field,\n options.languages,\n `Field \"${field}\" must be a { [locale]: string } map, got ${typeof value}.`,\n )\n }\n\n const map = value as Record<string, unknown>\n\n // All values must be strings\n for (const [locale, v] of Object.entries(map)) {\n if (typeof v !== 'string') {\n throw new MissingTranslationError(\n field,\n [locale],\n `Field \"${field}\": locale \"${locale}\" must be a string, got ${typeof v}.`,\n )\n }\n }\n\n // Check required constraint\n const { required } = options\n if (required === 'all') {\n const missing = options.languages.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length > 0) {\n throw new MissingTranslationError(\n field,\n missing,\n `Field \"${field}\" requires all declared languages. Missing: ${missing.join(', ')}.`,\n )\n }\n } else if (required === 'any') {\n const present = options.languages.some(\n (lang) => lang in map && map[lang] !== '',\n )\n if (!present) {\n throw new MissingTranslationError(\n field,\n options.languages,\n `Field \"${field}\" requires at least one declared language. None present.`,\n )\n }\n } else {\n // string[] — named required locales; TypeScript narrows required to readonly string[]\n const requiredList = required\n const missing = requiredList.filter(\n (lang) => !(lang in map) || map[lang] === '',\n )\n if (missing.length > 0) {\n throw new MissingTranslationError(\n field,\n missing,\n `Field \"${field}\" requires: ${requiredList.join(', ')}. Missing: ${missing.join(', ')}.`,\n )\n }\n }\n}\n\n// ─── Locale resolution ─────────────────────────────────────────────────\n\n/**\n * Resolve an i18nText value (`{ [locale]: string }` map) to a string\n * for the given locale.\n *\n * @param value The stored locale map.\n * @param locale The requested locale code, or `'raw'` to return the map.\n * @param fallback Single locale or ordered list; use `'any'` as the last\n * element to fall back to any available translation.\n * @param field Field name used in `LocaleNotSpecifiedError` messages.\n * @returns The resolved string, OR the original map when `locale === 'raw'`.\n */\n/** Options for the policy-aware form of {@link resolveI18nText}. */\nexport interface ResolveI18nOptions {\n /** Effective policy for the resolution layer. Default `'throw'`. */\n readonly policy?: OnMissing\n /** Declared substitute chain; applied only under policy `'substitute'`. */\n readonly substitute?: readonly string[]\n /**\n * Smart-substitute. When `true` and policy is `'substitute'`, after the\n * explicit chain misses, pick the available locale whose script is nearest the\n * target (same script first, then Latin's broad readability) instead of an\n * arbitrary value. Default `false`.\n */\n readonly smartSubstitute?: boolean\n}\n\n/** Normalize a single-or-list fallback into an array. */\nfunction toChain(fallback: string | readonly string[] | undefined): readonly string[] {\n return Array.isArray(fallback) ? fallback : fallback ? [fallback as string] : []\n}\n\n/** Walk a chain, returning the first non-empty value (or `'any'` match). */\nfunction pickFromChain(\n value: Record<string, string>,\n chain: readonly string[],\n): string | undefined {\n for (const fb of chain) {\n if (fb === 'any') {\n const any = Object.values(value).find((v) => v !== '')\n if (any !== undefined) return any\n } else if (value[fb] !== undefined && value[fb] !== '') {\n return value[fb]\n }\n }\n return undefined\n}\n\n// Legacy 4-arg form: can only throw or return — never null. Keeps every\n// existing call site's type unchanged (default policy is 'throw').\nexport function resolveI18nText(\n value: Record<string, string>,\n locale: string,\n fallback?: string | readonly string[],\n field?: string,\n): string | Record<string, string>\n// Policy-aware form: may return null under 'null'/'substitute' policies.\nexport function resolveI18nText(\n value: Record<string, string>,\n locale: string,\n fallback: string | readonly string[] | undefined,\n field: string | undefined,\n opts: ResolveI18nOptions,\n): string | Record<string, string> | null\nexport function resolveI18nText(\n value: Record<string, string>,\n locale: string,\n fallback?: string | readonly string[],\n field?: string,\n opts?: ResolveI18nOptions,\n): string | Record<string, string> | null {\n if (locale === 'raw') {\n return value\n }\n\n if (!locale) {\n throw new LocaleNotSpecifiedError(field ?? '<unknown>')\n }\n\n // Primary locale\n if (value[locale] !== undefined && value[locale] !== '') {\n return value[locale]\n }\n\n const policy: OnMissing = opts?.policy ?? 'throw'\n\n // Caller-supplied fallback ALWAYS applies first (backward compat +\n // explicit read-time override), regardless of policy.\n const callerChain = toChain(fallback)\n const callerHit = pickFromChain(value, callerChain)\n if (callerHit !== undefined) return callerHit\n\n // Declared substitute applies ONLY under policy 'substitute'.\n if (policy === 'substitute') {\n const subHit = pickFromChain(value, toChain(opts?.substitute))\n if (subHit !== undefined) return subHit\n // Smart-substitute: after the explicit chain, prefer the script-nearest\n // available locale over an arbitrary first-non-empty value.\n if (opts?.smartSubstitute) {\n const smartHit = pickNearestScript(value, locale)\n if (smartHit !== undefined) return smartHit\n }\n }\n\n // Exhausted.\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(\n field ?? '<unknown>',\n `No translation available for locale \"${locale}\"` +\n (callerChain.length > 0 ? ` or fallback chain [${callerChain.join(', ')}]` : '') +\n '.',\n )\n }\n return null\n}\n\n/**\n * Smart-substitute: among the non-empty locales in `value`, pick the one\n * whose primary script is nearest the target `locale` — same script first, then\n * Latin (broadly readable), then any other — so a missing Thai label falls back\n * to another Thai (or Latin) value rather than, say, an Arabic one. First-seen\n * wins on ties. Returns the value string, or `undefined` when `value` has no\n * non-empty entry.\n */\nfunction pickNearestScript(value: Record<string, string>, target: string): string | undefined {\n const targetScript = inferScripts(target)[0] ?? 'Latin'\n let best: { score: number; v: string } | undefined\n for (const [loc, v] of Object.entries(value)) {\n if (typeof v !== 'string' || v === '') continue\n const s = inferScripts(loc)[0] ?? 'Latin'\n const score = s === targetScript ? 0 : s === 'Latin' ? 1 : 2\n if (best === undefined || score < best.score) best = { score, v }\n if (score === 0) break // nothing beats a same-script match\n }\n return best?.v\n}\n\n// ─── Path helpers (nested i18nFields like 'address.lineOne') ──────────\n\n// `getAtPath`/`setAtPathInPlace` are generic dotted-path/[]-wildcard record\n// helpers, not i18n logic — moved to `kernel/paths.ts` (Task 7, #623).\n// `getAtPath` re-exported here for compat with existing importers of this\n// module (embeddings/descriptor.ts, search/build-docs.ts); `setAtPathInPlace`\n// is not re-exported — its only consumer (via-i18n/binding.ts) imports it\n// directly from kernel/paths.ts.\nexport { getAtPath } from '../../kernel/paths.js'\n\n/** Recursively resolve i18nText at a single path within a record copy. */\nfunction applyAtPath(\n obj: Record<string, unknown>,\n path: string,\n locale: string,\n fallback: string | readonly string[] | undefined,\n opts: ResolveI18nOptions,\n): Record<string, unknown> {\n const arrayIdx = path.indexOf('[].')\n if (arrayIdx !== -1) {\n const arrayKey = path.slice(0, arrayIdx)\n const restPath = path.slice(arrayIdx + 3)\n const arr = obj[arrayKey]\n if (!Array.isArray(arr)) return obj\n return {\n ...obj,\n [arrayKey]: arr.map(item => {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return item\n return applyAtPath(item as Record<string, unknown>, restPath, locale, fallback, opts)\n }),\n }\n }\n const dotIdx = path.indexOf('.')\n if (dotIdx !== -1) {\n const head = path.slice(0, dotIdx)\n const rest = path.slice(dotIdx + 1)\n const nested = obj[head]\n if (!nested || typeof nested !== 'object' || Array.isArray(nested)) return obj\n return {\n ...obj,\n [head]: applyAtPath(nested as Record<string, unknown>, rest, locale, fallback, opts),\n }\n }\n const raw = obj[path]\n if (raw === undefined || raw === null) return obj\n if (typeof raw !== 'object' || Array.isArray(raw)) return obj\n return {\n ...obj,\n [path]: resolveI18nText(raw as Record<string, string>, locale, fallback, path, opts),\n }\n}\n\n/**\n * Apply locale resolution to a single record, returning a new copy.\n *\n * For each field registered as an `i18nText` descriptor:\n * - If `locale === 'raw'`, the field value is left as the stored map.\n * - Otherwise, the field value is replaced with the resolved string.\n *\n * Field paths support dot notation (`'address.lineOne'`) and array\n * wildcards (`'contacts[].title'`). Top-level fields work as before.\n *\n * @param record The decrypted record.\n * @param i18nFields Map of field path → `I18nTextDescriptor`.\n * @param locale The requested locale (or `'raw'`).\n * @param fallback Fallback chain (optional).\n * @param layer Resolution layer (default `'read'`). Each field's\n * `onMissing` policy is resolved for this layer, so the\n * same record resolves leniently on a get but strictly\n * inside an mv/derivation.\n */\nexport function applyI18nLocale(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n locale: string,\n fallback?: string | readonly string[],\n layer: Layer = 'read',\n): Record<string, unknown> {\n const fieldNames = Object.keys(i18nFields)\n if (fieldNames.length === 0) return record\n\n let result = record\n\n for (const [field, descriptor] of Object.entries(i18nFields)) {\n const { onMissing, substitute, smartSubstitute } = descriptor.options\n const opts: ResolveI18nOptions = {\n policy: resolvePolicy(onMissing, layer),\n ...(substitute !== undefined ? { substitute } : {}),\n ...(smartSubstitute ? { smartSubstitute } : {}),\n }\n result = applyAtPath(result, field, locale, fallback, opts)\n }\n\n // The internal densify provenance marker never leaves the store.\n result = stripI18nFilled(result)\n\n return result\n}\n\n/**\n * Sync i18n-text-only present-for-join dressing — the exact `join`-layer\n * partial application `kernel/query/join.ts` used to import and call\n * directly before #626's retirement (#650 Task 6): fixes `fallback`\n * `undefined` and `layer` `'join'`. `via/lookup/snapshot.ts`'s\n * `buildPresentForJoin` composes this with the lookup-label half to build\n * the `JoinableSource.presentForJoin` hook the join executor now calls\n * instead of reaching into this module.\n */\nexport function presentI18nForJoin(\n record: Record<string, unknown>,\n i18nFields: Record<string, I18nTextDescriptor>,\n locale: string,\n): Record<string, unknown> {\n return applyI18nLocale(record, i18nFields, locale, undefined, 'join')\n}\n\n/**\n * Remove the internal densify provenance marker (`_i18nFilled`) from a\n * read-facing record. NON-mutating: returns the same object when the\n * marker is absent, otherwise a shallow copy without the marker.\n *\n * MUST be applied on every user-facing read return — even locale-less ones,\n * which bypass {@link applyI18nLocale}. MUST NOT be applied on the internal\n * prior-read path (decryptRecord / resolveDensifyPrior), where densify needs\n * the marker.\n */\nexport function stripI18nFilled<T extends Record<string, unknown>>(record: T): T {\n if (!Object.prototype.hasOwnProperty.call(record, '_i18nFilled')) return record\n const rest: T = { ...record }\n delete (rest as Record<string, unknown>)._i18nFilled\n return rest\n}\n"],"mappings":"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","names":[]}
@@ -1,19 +1,20 @@
1
1
  import {
2
+ buildRecordAad,
2
3
  openEnvelopeJson
3
- } from "./chunk-VN45YLWM.js";
4
+ } from "./chunk-OHOKBMTM.js";
4
5
  import {
5
- encrypt
6
- } from "./chunk-VCETL77O.js";
6
+ buildRecordEnvelope
7
+ } from "./chunk-PENPHA45.js";
7
8
  import {
8
- NOYDB_FORMAT_VERSION
9
- } from "./chunk-W5W6KHN2.js";
9
+ encrypt
10
+ } from "./chunk-AU3AUJIZ.js";
10
11
  import {
11
12
  SequenceContentionError,
12
13
  SequenceNotEnabledError,
13
14
  SequenceOfflineError,
14
15
  ValidationError,
15
16
  isConflictError
16
- } from "./chunk-HNGSV2YC.js";
17
+ } from "./chunk-CWM4GQD2.js";
17
18
 
18
19
  // src/with-commit/sequence/active.ts
19
20
  function withSequence() {
@@ -127,17 +128,18 @@ var SequenceStore = class {
127
128
  async read(name) {
128
129
  const env = await this.adapter.get(this.vault, SEQUENCE_COLLECTION, name);
129
130
  if (!env) return { env: null, value: 0 };
130
- const json = this.encrypted ? await openEnvelopeJson(env, await this.dek()) : env._data;
131
+ const json = this.encrypted ? await openEnvelopeJson({ collection: SEQUENCE_COLLECTION, id: name }, env, await this.dek()) : env._data;
131
132
  const state = JSON.parse(json);
132
133
  return { env, value: state.value };
133
134
  }
134
- async encryptState(state, version) {
135
+ async encryptState(name, state, version) {
135
136
  const json = JSON.stringify(state);
136
137
  if (!this.encrypted) {
137
- return { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: (/* @__PURE__ */ new Date()).toISOString(), _iv: "", _data: json, _by: this.actor };
138
+ return buildRecordEnvelope({ collection: SEQUENCE_COLLECTION, id: name, version }, { iv: "", data: json });
138
139
  }
139
- const { iv, data } = await encrypt(json, await this.dek());
140
- return { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: (/* @__PURE__ */ new Date()).toISOString(), _iv: iv, _data: data, _by: this.actor };
140
+ const identity = { collection: SEQUENCE_COLLECTION, id: name, version };
141
+ const { iv, data } = await encrypt(json, await this.dek(), buildRecordAad(identity));
142
+ return buildRecordEnvelope(identity, { iv, data });
141
143
  }
142
144
  async peek(name) {
143
145
  return (await this.read(name)).value;
@@ -149,7 +151,7 @@ var SequenceStore = class {
149
151
  const { env, value } = await this.read(name);
150
152
  const nextValue = value + 1;
151
153
  const expectedVersion = env?._v ?? 0;
152
- const envelope = await this.encryptState({ value: nextValue }, expectedVersion + 1);
154
+ const envelope = await this.encryptState(name, { value: nextValue }, expectedVersion + 1);
153
155
  try {
154
156
  await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion);
155
157
  return nextValue;
@@ -173,7 +175,7 @@ var SequenceStore = class {
173
175
  const { env, value } = await this.read(name);
174
176
  if (value >= n) return;
175
177
  const expectedVersion = env?._v ?? 0;
176
- const envelope = await this.encryptState({ value: n }, expectedVersion + 1);
178
+ const envelope = await this.encryptState(name, { value: n }, expectedVersion + 1);
177
179
  try {
178
180
  await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion);
179
181
  return;
@@ -199,4 +201,4 @@ export {
199
201
  resolveSequenceKey,
200
202
  SequenceStore
201
203
  };
202
- //# sourceMappingURL=chunk-GLKDWWNO.js.map
204
+ //# sourceMappingURL=chunk-YALD3SST.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-commit/sequence/active.ts","../src/with-commit/sequence/strategy.ts","../src/with-commit/sequence/index.ts"],"sourcesContent":["/**\n * Enable the atomic-sequence capability.\n * Pass to `createNoydb({ sequenceStrategy: withSequence() })` to make\n * `vault.sequence('name').next()` / `.peek()` / `.seedTo()` live. The\n * {@link SequenceStore} CAS engine is statically imported here, so it is pulled\n * into the bundle only when `withSequence()` is referenced (the floor never\n * imports it).\n */\nimport type { SequenceStrategy } from './strategy.js'\nimport { SequenceStore } from './index.js'\n\nexport function withSequence(): SequenceStrategy {\n return {\n createStore(opts) {\n return new SequenceStore(opts)\n },\n }\n}\n","/**\n * Sequence capability strategy — the single on-demand factory the vault routes\n * `vault.sequence()` through to build its atomic-CAS {@link SequenceStore}. The\n * active engine ({@link withSequence}) constructs the real store (kept out of\n * the floor bundle — the store class is reached only via the opt-in\n * `active.ts` chunk); {@link NO_SEQUENCE} throws. The vault always assembles the\n * per-call {@link SequenceStoreOptions} and delegates here, so an un-opted-in\n * caller hits `NO_SEQUENCE`'s throw at `vault.sequence()`.\n *\n * Note: `vault.sequence()` is synchronous, so the factory is a plain (sync)\n * constructor — the engine is tree-shaken by reachability (only `withSequence()`\n * pulls `active.ts`, which statically imports the store), not by a dynamic\n * import. Deferred-numbering series (`withDeferredNumbering`) are a distinct\n * capability and are NOT routed through this strategy.\n * @internal\n */\nimport type { SequenceStore, SequenceStoreOptions } from './index.js'\nimport { SequenceNotEnabledError } from '../../kernel/errors.js'\n\nexport interface SequenceStrategy {\n createStore(opts: SequenceStoreOptions): SequenceStore\n}\n\n/**\n * No-op stub — the floor default. The capability factory throws\n * {@link SequenceNotEnabledError}; opt in with `sequenceStrategy: withSequence()`\n * in createNoydb. @internal\n */\nexport const NO_SEQUENCE: SequenceStrategy = {\n createStore(): SequenceStore {\n throw new SequenceNotEnabledError()\n },\n}\n","/**\n * Atomic sequence primitive — online-coordinated gap-free numbering.\n *\n * `vault.sequence('invoice-2026').next()` returns 1, 2, 3, … with no\n * gaps and no duplicates, even under concurrent callers. Each named\n * sequence is an independent counter record at `_sequences/<name>`,\n * incremented with an optimistic compare-and-swap retry loop — the same\n * proven pattern as the ledger head (`history/ledger/store.ts`).\n *\n * **Explicitly online-only.** Gap-free numbering requires single-authority\n * serialization, which an offline / non-CAS store cannot provide. `next()`\n * throws {@link SequenceOfflineError} unless the backing store advertises\n * `capabilities.casAtomic`. This is a deliberate, honest wall — an offline\n * writer cannot safely allocate a global sequence number.\n *\n * Note on \"gap-free\": the *sequence* is gap-free (each `next()` yields a\n * unique, +1 value). If a caller discards a value without using it, that\n * is a gap in *usage*, not in the sequence — assign each `next()` result\n * to its record in the same operation.\n */\n\nimport { buildRecordAad, buildRecordEnvelope } from '../../kernel/enclave/index.js'\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport type { ConflictError} from '../../kernel/errors.js';\nimport { isConflictError, SequenceContentionError, SequenceOfflineError, ValidationError } from '../../kernel/errors.js'\n\n// Capability opt-in seam (S4): `vault.sequence()` builds its CAS store through\n// the sequenceStrategy, so it throws SequenceNotEnabledError unless opted in.\nexport { withSequence } from './active.js'\nexport { NO_SEQUENCE, type SequenceStrategy } from './strategy.js'\nexport { SequenceNotEnabledError } from '../../kernel/errors.js'\n\nexport const SEQUENCE_COLLECTION = '_sequences'\n// A sequence is a single hot CAS row — higher contention than a ledger\n// append. A larger budget + jittered backoff absorbs moderate concurrency;\n// a genuine burst beyond this surfaces SequenceContentionError so the\n// caller can retry / queue (the honest online-only contract).\nconst MAX_NEXT_ATTEMPTS = 16\n\ninterface SequenceState {\n value: number\n}\n\n/** Options for `SequenceHandle.next`. Deferred-numbering series use `for`; the CAS counter ignores all of these. */\nexport interface NextOptions {\n /** Deferred mode: the record id to number. Ignored by the CAS counter. */\n readonly for?: string\n /** Deferred mode: reject after this many ms if still unsealed (reserved; not yet enforced in this slice). */\n readonly timeoutMs?: number\n}\n\n/**\n * Partitioning for a CAS sequence. A partitioned sequence is an\n * independent counter scoped to one tuple of values — e.g.\n * `sequence('invoice', { partition: [2026, 'EU'] })` numbers EU-2026 invoices\n * separately from `[2026, 'US']` and from the bare `invoice` series.\n *\n * Partition components are URI-encoded (so `/`, null bytes and other\n * separators in a value can never collide with the structural separators) and\n * `'/'`-joined, then appended to the series with a null-byte (`\\x00`)\n * separator. The null byte is illegal in a plain series name, which guarantees\n * a partitioned key is always disjoint from any unpartitioned series.\n */\nexport interface SequenceOptions {\n /** Partition tuple. Each component is URI-encoded and `'/'`-joined. */\n readonly partition?: readonly (string | number)[]\n /**\n * Render template for the serial string. When set, `vault.sequence`\n * returns a {@link FormattedSequenceHandle} whose `next()` resolves to\n * `{ serial, formatted }`. Tokens:\n * - `{seq}` — the allocated integer\n * - `{seq:0N}` — zero-padded to width N (e.g. `{seq:04}` → `0001`)\n * - `{partition.i}` — the i-th `partition` component (original value)\n *\n * Any other token, or a `{partition.i}` index beyond the supplied\n * `partition`, throws `ValidationError` at `vault.sequence()` construction.\n * Per-partition reset is inherent: a new partition tuple starts at 1.\n */\n readonly format?: string\n}\n\n/**\n * A formatted sequence handle. Identical to {@link SequenceHandle}\n * except `next()` also returns the rendered `formatted` string. `peek()` /\n * `seedTo()` operate on the underlying integer counter, unchanged.\n */\nexport interface FormattedSequenceHandle {\n /** Allocate the next value and return it with its rendered serial string. */\n next(opts?: NextOptions): Promise<{ serial: number; formatted: string }>\n /** Read the current integer value without allocating. Returns 0 if never used. */\n peek(): Promise<number>\n /** Set-if-greater on the underlying integer counter. See {@link SequenceHandle.seedTo}. */\n seedTo(n: number): Promise<void>\n}\n\n// Matches a single `{...}` token with no nested braces.\nconst SEQ_FORMAT_TOKEN = /\\{([^{}]*)\\}/g\nconst SEQ_PAD_TOKEN = /^seq:0(\\d+)$/\nconst SEQ_PARTITION_TOKEN = /^partition\\.(\\d+)$/\n\n/**\n * Validate a sequence `format` against the supplied partition and return a\n * pure `(serial) => string` renderer. Eager validation: every token is\n * checked now, so a bad pattern throws `ValidationError` at construction —\n * never at `next()` time.\n */\nexport function compileSequenceFormat(\n format: string,\n series: string,\n partition: readonly (string | number)[] | undefined,\n): (serial: number) => string {\n const parts = partition ?? []\n for (const m of format.matchAll(SEQ_FORMAT_TOKEN)) {\n const token = m[1] ?? ''\n if (token === 'seq') continue\n if (SEQ_PAD_TOKEN.test(token)) continue\n const partMatch = SEQ_PARTITION_TOKEN.exec(token)\n if (partMatch) {\n const idx = Number(partMatch[1])\n if (idx >= parts.length) {\n throw new ValidationError(\n `sequence(\"${series}\"): format token \"{${token}}\" references partition index ${idx}, ` +\n `but only ${parts.length} partition component(s) were supplied.`,\n )\n }\n continue\n }\n throw new ValidationError(\n `sequence(\"${series}\"): format contains unknown token \"{${token}}\". ` +\n `Accepted tokens: {seq}, {seq:0N}, {partition.i}.`,\n )\n }\n return (serial: number): string =>\n format.replace(SEQ_FORMAT_TOKEN, (full, token: string) => {\n if (token === 'seq') return String(serial)\n const padMatch = SEQ_PAD_TOKEN.exec(token)\n if (padMatch) return String(serial).padStart(Number(padMatch[1]), '0')\n const partMatch = SEQ_PARTITION_TOKEN.exec(token)\n if (partMatch) return String(parts[Number(partMatch[1])])\n return full // unreachable — validated above\n })\n}\n\n/**\n * Resolve the CAS storage key for a (series, partition) pair.\n *\n * With no partition the key is `series` verbatim. With a partition the key is\n * `${series}\\x00${parts}` where `parts` is each component passed through\n * `encodeURIComponent(String(part))` and `'/'`-joined. The null-byte separator\n * is illegal in a plain series name, so partitioned keys never collide with\n * unpartitioned ones; URI-encoding keeps any component containing `/` distinct\n * from a multi-component partition.\n *\n * @throws {ValidationError} if any partition component is empty after `String()`\n * or is a non-finite number (`NaN`, `±Infinity`).\n */\nexport function resolveSequenceKey(series: string, opts?: SequenceOptions): string {\n const partition = opts?.partition\n if (!partition || partition.length === 0) return series\n const parts = partition.map((p) => {\n if (typeof p === 'number' && !Number.isFinite(p)) {\n throw new ValidationError(`sequence partition component must be a finite number, got ${p}`)\n }\n const s = String(p)\n if (s === '') {\n throw new ValidationError('sequence partition component must not be empty')\n }\n return encodeURIComponent(s)\n })\n return `${series}\\x00${parts.join('/')}`\n}\n\nexport interface SequenceHandle {\n /** Atomically allocate and return the next value (1, 2, 3, …). Deferred series resolve at the next pass. */\n next(opts?: NextOptions): Promise<number>\n /** Read the current value without allocating. Returns 0 if never used. */\n peek(): Promise<number>\n /**\n * Set-if-greater: advance the counter to at least `n`. A no-op if the\n * current value is already `>= n` (so it never rewinds), and `seedTo(0)` is\n * a no-op. Idempotent and CAS-safe under concurrent `next()` / `seedTo()`.\n *\n * Use after a bundle / CSV import to fast-forward the counter past the\n * highest imported serial, so subsequent `next()` calls cannot re-use a\n * number that is already on a record.\n *\n * Online-only: throws {@link SequenceOfflineError} on a non-CAS store.\n */\n seedTo(n: number): Promise<void>\n}\n\nasync function sleepBackoff(attempt: number): Promise<void> {\n // Exponential backoff with full jitter to break the thundering herd\n // when many writers contend on the same counter row.\n const ceil = Math.min(2 ** attempt, 32)\n const ms = Math.floor(Math.random() * ceil)\n await new Promise((r) => setTimeout(r, ms))\n}\n\n/** Per-call context the vault assembles to build a {@link SequenceStore}. */\nexport interface SequenceStoreOptions {\n adapter: NoydbStore\n vault: string\n encrypted: boolean\n getDEK: (collectionName: string) => Promise<EnclaveKey>\n actor: string\n}\n\nexport class SequenceStore {\n private readonly adapter: NoydbStore\n private readonly vault: string\n private readonly encrypted: boolean\n private readonly getDEK: (collectionName: string) => Promise<EnclaveKey>\n private readonly actor: string\n /**\n * Memoized DEK promise. The `_sequences` collection DEK is created on\n * first access; without sharing one promise, a burst of concurrent\n * `next()` calls would each trigger DEK creation and diverge (one\n * writer's ciphertext unreadable by another). One shared promise → one\n * DEK.\n */\n private dekPromise: Promise<EnclaveKey> | null = null\n\n constructor(opts: SequenceStoreOptions) {\n this.adapter = opts.adapter\n this.vault = opts.vault\n this.encrypted = opts.encrypted\n this.getDEK = opts.getDEK\n this.actor = opts.actor\n }\n\n /** A handle bound to one sequence name. */\n handle(name: string): SequenceHandle {\n return {\n next: () => this.next(name),\n peek: () => this.peek(name),\n seedTo: (n) => this.seedTo(name, n),\n }\n }\n\n private assertOnline(): void {\n if (this.adapter.capabilities?.casAtomic !== true) {\n throw new SequenceOfflineError()\n }\n }\n\n private dek(): Promise<EnclaveKey> {\n if (!this.dekPromise) this.dekPromise = this.getDEK(SEQUENCE_COLLECTION)\n return this.dekPromise\n }\n\n private async read(name: string): Promise<{ env: EncryptedEnvelope | null; value: number }> {\n const env = await this.adapter.get(this.vault, SEQUENCE_COLLECTION, name)\n if (!env) return { env: null, value: 0 }\n const json = this.encrypted ? await openEnvelopeJson({ collection: SEQUENCE_COLLECTION, id: name }, env, await this.dek()) : env._data\n const state = JSON.parse(json) as SequenceState\n return { env, value: state.value }\n }\n\n private async encryptState(name: string, state: SequenceState, version: number): Promise<EncryptedEnvelope> {\n const json = JSON.stringify(state)\n if (!this.encrypted) {\n return buildRecordEnvelope({ collection: SEQUENCE_COLLECTION, id: name, version }, { iv: '', data: json})\n }\n const identity = { collection: SEQUENCE_COLLECTION, id: name, version }\n const { iv, data } = await encrypt(json, await this.dek(), buildRecordAad(identity))\n return buildRecordEnvelope(identity, { iv, data})\n }\n\n async peek(name: string): Promise<number> {\n return (await this.read(name)).value\n }\n\n async next(name: string): Promise<number> {\n this.assertOnline()\n let lastConflict: ConflictError | undefined\n for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {\n const { env, value } = await this.read(name)\n const nextValue = value + 1\n const expectedVersion = env?._v ?? 0 // 0 ≡ \"must not yet exist\" (create)\n const envelope = await this.encryptState(name, { value: nextValue }, expectedVersion + 1)\n try {\n await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion)\n return nextValue\n } catch (err) {\n if (isConflictError(err)) {\n lastConflict = err\n if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt)\n continue\n }\n throw err\n }\n }\n void lastConflict\n throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS)\n }\n\n async seedTo(name: string, n: number): Promise<void> {\n this.assertOnline()\n if (n <= 0) return // set-if-greater: 0 (and any non-positive seed) is a no-op\n let lastConflict: ConflictError | undefined\n for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {\n const { env, value } = await this.read(name)\n if (value >= n) return // already at or past the floor — no write, idempotent\n const expectedVersion = env?._v ?? 0 // 0 ≡ \"must not yet exist\" (create)\n const envelope = await this.encryptState(name, { value: n }, expectedVersion + 1)\n try {\n await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion)\n return\n } catch (err) {\n if (isConflictError(err)) {\n lastConflict = err\n if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt)\n continue\n }\n throw err\n }\n }\n void lastConflict\n throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS)\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  ViaGraph
3
- } from "./chunk-7TSYBD3E.js";
3
+ } from "./chunk-RSXQNFGO.js";
4
4
  import {
5
5
  sha256Hex
6
- } from "./chunk-VCETL77O.js";
6
+ } from "./chunk-AU3AUJIZ.js";
7
7
  import {
8
8
  DerivationCycleError,
9
9
  DuplicateBehaviorNameError
10
- } from "./chunk-HNGSV2YC.js";
10
+ } from "./chunk-CWM4GQD2.js";
11
11
 
12
12
  // src/with-formula/derivations/strategy-hash.ts
13
13
  async function computeStrategyHash(source, outputKeys, derive, sources) {
@@ -172,4 +172,4 @@ var DerivationRegistry = class {
172
172
  export {
173
173
  DerivationRegistry
174
174
  };
175
- //# sourceMappingURL=chunk-NJDQ4YSV.js.map
175
+ //# sourceMappingURL=chunk-YKXZHUOW.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  envelopeBodyForHash
3
- } from "./chunk-VN45YLWM.js";
3
+ } from "./chunk-OHOKBMTM.js";
4
4
  import {
5
5
  sha256Hex
6
- } from "./chunk-VCETL77O.js";
6
+ } from "./chunk-AU3AUJIZ.js";
7
7
 
8
8
  // src/with-commit/history/ledger/entry.ts
9
9
  function canonicalJson(value) {
@@ -67,4 +67,4 @@ export {
67
67
  parseIndex,
68
68
  envelopePayloadHash
69
69
  };
70
- //# sourceMappingURL=chunk-VW6ZZGCG.js.map
70
+ //# sourceMappingURL=chunk-ZLHHE5XZ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PortabilityNotEnabledError
3
- } from "./chunk-HNGSV2YC.js";
3
+ } from "./chunk-CWM4GQD2.js";
4
4
 
5
5
  // src/with-audit/portability/strategy.ts
6
6
  var NO_PORTABILITY = {
@@ -27,4 +27,4 @@ var NO_PORTABILITY = {
27
27
  export {
28
28
  NO_PORTABILITY
29
29
  };
30
- //# sourceMappingURL=chunk-FUHKW252.js.map
30
+ //# sourceMappingURL=chunk-ZZXLB6AS.js.map
@@ -2,7 +2,7 @@ import {
2
2
  classified,
3
3
  luhnCheck,
4
4
  withClassified
5
- } from "../chunk-PVU7LW5L.js";
5
+ } from "../chunk-KX57HODD.js";
6
6
  import {
7
7
  ClassifiedNeverStoredError,
8
8
  ClassifiedValidationError,
@@ -11,15 +11,15 @@ import {
11
11
  isClassifiedFieldSpec,
12
12
  isClassifiedGroup,
13
13
  resolveClassifiedFields
14
- } from "../chunk-QD724WDJ.js";
15
- import "../chunk-UHXCLPGC.js";
16
- import "../chunk-W5W6KHN2.js";
14
+ } from "../chunk-OMYCSTXL.js";
15
+ import "../chunk-JNMTN5D5.js";
16
+ import "../chunk-IGNJOJEP.js";
17
17
  import {
18
18
  ClassifiedConfigError,
19
19
  ClassifiedRevealError,
20
20
  ClassifiedRotationError,
21
21
  ClassifiedVerifyError
22
- } from "../chunk-HNGSV2YC.js";
22
+ } from "../chunk-CWM4GQD2.js";
23
23
  import "../chunk-PZ5AY32C.js";
24
24
  export {
25
25
  ClassifiedConfigError,
@@ -13,11 +13,11 @@ function markerForFields(vdigFields) {
13
13
  async function persistClassifiedMarkerForFields(store, vault, collectionName, vdigFields, dek) {
14
14
  const marker = markerForFields(vdigFields);
15
15
  if (marker === null) return;
16
- const { persistClassifiedMarker } = await import("./register-TMD6YRCX.js");
16
+ const { persistClassifiedMarker } = await import("./register-UZ37QPDB.js");
17
17
  await persistClassifiedMarker({ store, vault, collectionName, dek, marker });
18
18
  }
19
19
  async function readClassifiedMarkerDigestOnly(store, vault, collectionName, dek) {
20
- const { loadPersistedSchema } = await import("./storage-N7LB275C.js");
20
+ const { loadPersistedSchema } = await import("./storage-3VNGSHXS.js");
21
21
  const persisted = await loadPersistedSchema(store, vault, collectionName, dek);
22
22
  return persisted?.classified?.digestOnly ?? [];
23
23
  }
@@ -25,4 +25,4 @@ export {
25
25
  persistClassifiedMarkerForFields,
26
26
  readClassifiedMarkerDigestOnly
27
27
  };
28
- //# sourceMappingURL=classified-marker-FTOX7Q5L.js.map
28
+ //# sourceMappingURL=classified-marker-NA6HUV33.js.map
@@ -0,0 +1,45 @@
1
+ import {
2
+ buildPersistedIndexCallbacks,
3
+ buildRetrievalDocs,
4
+ embedOnWrite,
5
+ flushIndex,
6
+ hasIndexedBlobFields,
7
+ rebuildEmbeddings,
8
+ retrieve,
9
+ search,
10
+ similarTo,
11
+ syncTierSearch,
12
+ warmIndex
13
+ } from "./chunk-O742QBZZ.js";
14
+ import "./chunk-GTHVPVAR.js";
15
+ import "./chunk-AURFOK3D.js";
16
+ import "./chunk-3B6S6RSI.js";
17
+ import "./chunk-6KTVJ5ZZ.js";
18
+ import "./chunk-WVE6YKMX.js";
19
+ import "./chunk-JNMTN5D5.js";
20
+ import "./chunk-ZLHHE5XZ.js";
21
+ import "./chunk-PPCOKVFA.js";
22
+ import "./chunk-OHOKBMTM.js";
23
+ import "./chunk-PENPHA45.js";
24
+ import "./chunk-GQXFOAYZ.js";
25
+ import "./chunk-KV6JM2IA.js";
26
+ import "./chunk-TMBSPLUG.js";
27
+ import "./chunk-LP7BEXCT.js";
28
+ import "./chunk-AU3AUJIZ.js";
29
+ import "./chunk-IGNJOJEP.js";
30
+ import "./chunk-CWM4GQD2.js";
31
+ import "./chunk-PZ5AY32C.js";
32
+ export {
33
+ buildPersistedIndexCallbacks,
34
+ buildRetrievalDocs,
35
+ embedOnWrite,
36
+ flushIndex,
37
+ hasIndexedBlobFields,
38
+ rebuildEmbeddings,
39
+ retrieve,
40
+ search,
41
+ similarTo,
42
+ syncTierSearch,
43
+ warmIndex
44
+ };
45
+ //# sourceMappingURL=collection-facade-VBM35WAH.js.map
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  ComputedFieldError,
3
3
  evalComputedFields
4
- } from "./chunk-VMCCGUQB.js";
5
- import "./chunk-HNGSV2YC.js";
4
+ } from "./chunk-6JPGVL7X.js";
5
+ import "./chunk-CWM4GQD2.js";
6
6
  import "./chunk-PZ5AY32C.js";
7
7
  export {
8
8
  ComputedFieldError,
9
9
  evalComputedFields
10
10
  };
11
- //# sourceMappingURL=computed-6G5M3UPH.js.map
11
+ //# sourceMappingURL=computed-GSTLWSY5.js.map
@@ -2,20 +2,20 @@ import {
2
2
  CONSENT_AUDIT_COLLECTION,
3
3
  loadConsentEntries,
4
4
  writeConsentEntry
5
- } from "../chunk-I6SDX7WX.js";
5
+ } from "../chunk-MZTUTEHP.js";
6
6
  import {
7
7
  NO_CONSENT
8
8
  } from "../chunk-PEOZ34EM.js";
9
- import "../chunk-ZJADGNYF.js";
10
- import "../chunk-VN45YLWM.js";
11
- import "../chunk-NWCGDAV6.js";
12
- import "../chunk-HXGUIPQB.js";
13
- import "../chunk-AR2JDFAE.js";
14
- import "../chunk-747LRSOO.js";
9
+ import "../chunk-4AOERLTV.js";
10
+ import "../chunk-OHOKBMTM.js";
11
+ import "../chunk-PENPHA45.js";
12
+ import "../chunk-GQXFOAYZ.js";
13
+ import "../chunk-KV6JM2IA.js";
14
+ import "../chunk-TMBSPLUG.js";
15
15
  import "../chunk-LP7BEXCT.js";
16
- import "../chunk-VCETL77O.js";
17
- import "../chunk-W5W6KHN2.js";
18
- import "../chunk-HNGSV2YC.js";
16
+ import "../chunk-AU3AUJIZ.js";
17
+ import "../chunk-IGNJOJEP.js";
18
+ import "../chunk-CWM4GQD2.js";
19
19
  import "../chunk-PZ5AY32C.js";
20
20
 
21
21
  // src/with-audit/consent/active.ts