@noy-db/hub 0.2.0-pre.18 → 0.2.0-pre.19

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 (283) hide show
  1. package/dist/aggregate/index.cjs +227 -3
  2. package/dist/aggregate/index.cjs.map +1 -1
  3. package/dist/aggregate/index.d.cts +3 -3
  4. package/dist/aggregate/index.d.ts +3 -3
  5. package/dist/aggregate/index.js +5 -4
  6. package/dist/aggregate/index.js.map +1 -1
  7. package/dist/attestation/index.cjs.map +1 -1
  8. package/dist/attestation/index.d.cts +5 -5
  9. package/dist/attestation/index.d.ts +5 -5
  10. package/dist/attestation/index.js +6 -6
  11. package/dist/blobs/index.cjs +4 -10
  12. package/dist/blobs/index.cjs.map +1 -1
  13. package/dist/blobs/index.d.cts +6 -6
  14. package/dist/blobs/index.d.ts +6 -6
  15. package/dist/blobs/index.js +6 -6
  16. package/dist/bundle/index.cjs +520 -46
  17. package/dist/bundle/index.cjs.map +1 -1
  18. package/dist/bundle/index.d.cts +7 -7
  19. package/dist/bundle/index.d.ts +7 -7
  20. package/dist/bundle/index.js +10 -10
  21. package/dist/{chunk-6Q5XRLKG.js → chunk-3FSMVWBN.js} +4 -4
  22. package/dist/{chunk-647TFNYL.js → chunk-3Q2AOPLT.js} +76 -28
  23. package/dist/chunk-3Q2AOPLT.js.map +1 -0
  24. package/dist/{chunk-2U226RDC.js → chunk-4ULLGYPA.js} +3 -3
  25. package/dist/{chunk-6FHCU3QO.js → chunk-5IGWRMEC.js} +5 -5
  26. package/dist/{chunk-Y5XVB75E.js → chunk-6KESZO5D.js} +35 -7
  27. package/dist/chunk-6KESZO5D.js.map +1 -0
  28. package/dist/{chunk-KQ523X3A.js → chunk-6OSOE6BY.js} +2 -2
  29. package/dist/{chunk-HWK75CYX.js → chunk-7C6VFNIY.js} +2 -2
  30. package/dist/{chunk-33DAO2XG.js → chunk-7HD67R6U.js} +2 -2
  31. package/dist/{chunk-RQFG2YSV.js → chunk-B6E5IRPJ.js} +3 -3
  32. package/dist/{chunk-YWYW2YNO.js → chunk-CYNTFU2D.js} +2 -2
  33. package/dist/{chunk-HMFC6M2G.js → chunk-DJF3FXW5.js} +17 -1
  34. package/dist/{chunk-HMFC6M2G.js.map → chunk-DJF3FXW5.js.map} +1 -1
  35. package/dist/{chunk-KTZ2MHQK.js → chunk-DY3EOJEN.js} +2 -2
  36. package/dist/{chunk-PGVEL5IZ.js → chunk-E66DSTJP.js} +3 -3
  37. package/dist/{chunk-6YEC7LLO.js → chunk-FBLAWK6A.js} +2 -2
  38. package/dist/{chunk-LQ3GD5LL.js → chunk-FPHRTW2Z.js} +5 -5
  39. package/dist/{chunk-ZJ67TB4S.js → chunk-G4PYA575.js} +2 -2
  40. package/dist/{chunk-45643PAU.js → chunk-GKQAU52M.js} +4 -4
  41. package/dist/{chunk-5KKNBDCT.js → chunk-GYAWXHFO.js} +2 -2
  42. package/dist/{chunk-KOURQXIU.js → chunk-H42KZXNV.js} +5 -210
  43. package/dist/chunk-H42KZXNV.js.map +1 -0
  44. package/dist/{chunk-6XEGHIBA.js → chunk-IBVTH4JR.js} +4 -4
  45. package/dist/{chunk-AB7JF2KF.js → chunk-IVP5IVON.js} +2 -2
  46. package/dist/{chunk-T4T5I5L6.js → chunk-KEDJDWWQ.js} +3 -3
  47. package/dist/{chunk-C2OYWD5S.js → chunk-KNKNOJFS.js} +3 -3
  48. package/dist/chunk-KNKNOJFS.js.map +1 -0
  49. package/dist/{chunk-F2IJ2HGD.js → chunk-KYGGXXT6.js} +228 -69
  50. package/dist/chunk-KYGGXXT6.js.map +1 -0
  51. package/dist/{chunk-RZWQNMMP.js → chunk-LSIIPKYT.js} +2 -2
  52. package/dist/{chunk-FQRAYDS4.js → chunk-M3FPNTO2.js} +4 -4
  53. package/dist/{chunk-DR5I7Q6N.js → chunk-MI36HL5G.js} +4 -4
  54. package/dist/{chunk-Z3I2WNGF.js → chunk-NN6IISZO.js} +2 -2
  55. package/dist/{chunk-32XVU2LT.js → chunk-OBMYMKGO.js} +29 -6
  56. package/dist/{chunk-32XVU2LT.js.map → chunk-OBMYMKGO.js.map} +1 -1
  57. package/dist/{chunk-QJKZ5WUP.js → chunk-OKOKPYWH.js} +2 -2
  58. package/dist/{chunk-CMISAJAE.js → chunk-OY7RX2VL.js} +9 -15
  59. package/dist/chunk-OY7RX2VL.js.map +1 -0
  60. package/dist/{chunk-Z3BE5BRK.js → chunk-PTGQPWMV.js} +2 -2
  61. package/dist/{chunk-QPJ7Z4L3.js → chunk-PWFTQHYX.js} +2 -2
  62. package/dist/{chunk-K3NYRK7U.js → chunk-Q5MCHUXZ.js} +2 -2
  63. package/dist/{chunk-IQ4GMEYZ.js → chunk-S22UOMHM.js} +6 -6
  64. package/dist/{chunk-WZCG3EZ6.js → chunk-S3XA7G35.js} +2 -2
  65. package/dist/{chunk-LGPSCKWZ.js → chunk-SHIUFIPW.js} +1 -1
  66. package/dist/chunk-SHIUFIPW.js.map +1 -0
  67. package/dist/{chunk-BUBJYIZ7.js → chunk-U7JNBSS3.js} +3 -3
  68. package/dist/{chunk-TFAN3NFD.js → chunk-V3VIRTTE.js} +3 -3
  69. package/dist/{chunk-VVDSDOVV.js → chunk-V5FZWQNN.js} +4 -4
  70. package/dist/chunk-VEIVAYJ7.js +361 -0
  71. package/dist/chunk-VEIVAYJ7.js.map +1 -0
  72. package/dist/{chunk-P57D4KBG.js → chunk-VNUE6FHP.js} +3 -3
  73. package/dist/{chunk-TPOHMOGX.js → chunk-WFK2EVYU.js} +10 -2
  74. package/dist/chunk-WFK2EVYU.js.map +1 -0
  75. package/dist/{chunk-TTS3RWL5.js → chunk-X7FJMKT3.js} +2 -2
  76. package/dist/{chunk-HZOEBM67.js → chunk-XPH3FWME.js} +7 -2
  77. package/dist/{chunk-HZOEBM67.js.map → chunk-XPH3FWME.js.map} +1 -1
  78. package/dist/{chunk-DKMPR76W.js → chunk-Y5J63SMF.js} +5 -5
  79. package/dist/{chunk-HOO5I3VG.js → chunk-YLRRU72W.js} +2 -2
  80. package/dist/{chunk-MGB67HKX.js → chunk-YX333DPS.js} +4 -4
  81. package/dist/{chunk-4UI5T3K7.js → chunk-YZE6C3TQ.js} +3 -3
  82. package/dist/consent/index.cjs.map +1 -1
  83. package/dist/consent/index.d.cts +6 -6
  84. package/dist/consent/index.d.ts +6 -6
  85. package/dist/consent/index.js +3 -3
  86. package/dist/{crypto-FNK3XPCS.js → crypto-B46VNH6X.js} +3 -3
  87. package/dist/{delegation-FMXNUWE6.js → delegation-5HON72PV.js} +5 -5
  88. package/dist/derivations/index.cjs.map +1 -1
  89. package/dist/derivations/index.d.cts +7 -7
  90. package/dist/derivations/index.d.ts +7 -7
  91. package/dist/derivations/index.js +4 -4
  92. package/dist/{dev-unlock-3_2b_vo6.d.cts → dev-unlock-BR1rMOS-.d.cts} +1 -1
  93. package/dist/{dev-unlock-BMvwPr_E.d.ts → dev-unlock-whL49sxV.d.ts} +1 -1
  94. package/dist/{errors-DUTlAt3Y.d.ts → errors-DL-zTrrF.d.cts} +14 -1
  95. package/dist/{errors-DUTlAt3Y.d.cts → errors-DL-zTrrF.d.ts} +14 -1
  96. package/dist/executor-44R5CUS2.js +12 -0
  97. package/dist/executor-AOACUK7Z.js +8 -0
  98. package/dist/executor-OKFLQCDW.js +8 -0
  99. package/dist/{fanout-sidecar-JGHXAJO5.js → fanout-sidecar-DCQWJQ6S.js} +2 -2
  100. package/dist/forget/index.cjs.map +1 -1
  101. package/dist/forget/index.d.cts +1 -1
  102. package/dist/forget/index.d.ts +1 -1
  103. package/dist/forget/index.js +4 -4
  104. package/dist/guards/index.cjs.map +1 -1
  105. package/dist/guards/index.d.cts +7 -7
  106. package/dist/guards/index.d.ts +7 -7
  107. package/dist/guards/index.js +3 -3
  108. package/dist/{hash-BnWnL9bQ.d.cts → hash-BEUBmmI4.d.cts} +1 -1
  109. package/dist/{hash-BThBJFO1.d.ts → hash-Dtb7FwWd.d.ts} +1 -1
  110. package/dist/history/index.cjs.map +1 -1
  111. package/dist/history/index.d.cts +7 -7
  112. package/dist/history/index.d.ts +7 -7
  113. package/dist/history/index.js +5 -5
  114. package/dist/i18n/index.cjs +149 -132
  115. package/dist/i18n/index.cjs.map +1 -1
  116. package/dist/i18n/index.d.cts +6 -6
  117. package/dist/i18n/index.d.ts +6 -6
  118. package/dist/i18n/index.js +14 -14
  119. package/dist/{index-C6lgoUhK.d.cts → index-BM7O48Ur.d.cts} +47 -8
  120. package/dist/{index-C-SSRIxP.d.ts → index-BMmajblo.d.cts} +14 -0
  121. package/dist/{index-C-SSRIxP.d.cts → index-BMmajblo.d.ts} +14 -0
  122. package/dist/{index-DP1JTWHZ.d.ts → index-BelbyUwz.d.ts} +47 -8
  123. package/dist/index.cjs +799 -465
  124. package/dist/index.cjs.map +1 -1
  125. package/dist/index.d.cts +29 -16
  126. package/dist/index.d.ts +29 -16
  127. package/dist/index.js +56 -52
  128. package/dist/index.js.map +1 -1
  129. package/dist/indexing/index.cjs.map +1 -1
  130. package/dist/indexing/index.js +4 -4
  131. package/dist/issue-EPA2PSWP.js +12 -0
  132. package/dist/{ledger-GXC2YA3A.js → ledger-LS6GXCBP.js} +5 -5
  133. package/dist/materialized-views/index.cjs +257 -4
  134. package/dist/materialized-views/index.cjs.map +1 -1
  135. package/dist/materialized-views/index.d.cts +7 -7
  136. package/dist/materialized-views/index.d.ts +7 -7
  137. package/dist/materialized-views/index.js +8 -7
  138. package/dist/noydb-BVKFP74P.js +38 -0
  139. package/dist/overlay-views/index.cjs.map +1 -1
  140. package/dist/overlay-views/index.d.cts +7 -7
  141. package/dist/overlay-views/index.d.ts +7 -7
  142. package/dist/overlay-views/index.js +4 -4
  143. package/dist/periods/index.cjs.map +1 -1
  144. package/dist/periods/index.d.cts +6 -6
  145. package/dist/periods/index.d.ts +6 -6
  146. package/dist/periods/index.js +5 -5
  147. package/dist/{public-envelope-HXOFHY4N.js → public-envelope-AGU6SS4Z.js} +4 -4
  148. package/dist/query/index.cjs +296 -27
  149. package/dist/query/index.cjs.map +1 -1
  150. package/dist/query/index.d.cts +3 -3
  151. package/dist/query/index.d.ts +3 -3
  152. package/dist/query/index.js +7 -6
  153. package/dist/registry-ERNAMRDE.js +8 -0
  154. package/dist/registry-EXTHSXQW.js +8 -0
  155. package/dist/{registry-WVXO6NH5.js → registry-RDPTFXQ7.js} +3 -3
  156. package/dist/{revoke-7LCWE2AH.js → revoke-IFLXEZA5.js} +6 -6
  157. package/dist/sealed-record/index.cjs.map +1 -1
  158. package/dist/sealed-record/index.d.cts +1 -1
  159. package/dist/sealed-record/index.d.ts +1 -1
  160. package/dist/sealed-record/index.js +2 -2
  161. package/dist/session/index.cjs.map +1 -1
  162. package/dist/session/index.d.cts +7 -7
  163. package/dist/session/index.d.ts +7 -7
  164. package/dist/session/index.js +3 -3
  165. package/dist/shadow/index.cjs.map +1 -1
  166. package/dist/shadow/index.d.cts +6 -6
  167. package/dist/shadow/index.d.ts +6 -6
  168. package/dist/shadow/index.js +2 -2
  169. package/dist/{signer-HAVDLGOK.js → signer-UNWOUJAK.js} +5 -5
  170. package/dist/snapshots/index.cjs.map +1 -1
  171. package/dist/snapshots/index.d.cts +6 -6
  172. package/dist/snapshots/index.d.ts +6 -6
  173. package/dist/snapshots/index.js +4 -4
  174. package/dist/{stale-PGTEGJDI.js → stale-NTEV5SLX.js} +2 -2
  175. package/dist/{state-vault-QKQKN3H3.js → state-vault-TUTFRTOA.js} +4 -4
  176. package/dist/store/index.cjs +8 -0
  177. package/dist/store/index.cjs.map +1 -1
  178. package/dist/store/index.d.cts +13 -6
  179. package/dist/store/index.d.ts +13 -6
  180. package/dist/store/index.js +2 -2
  181. package/dist/{strategy-Diwh5lzS.d.ts → strategy-BDxQnnTX.d.ts} +315 -4
  182. package/dist/{strategy-nuyN8K5N.d.cts → strategy-C5ol6NdV.d.cts} +315 -4
  183. package/dist/sync/index.cjs.map +1 -1
  184. package/dist/sync/index.d.cts +5 -5
  185. package/dist/sync/index.d.ts +5 -5
  186. package/dist/sync/index.js +4 -4
  187. package/dist/team/index.cjs.map +1 -1
  188. package/dist/team/index.d.cts +6 -6
  189. package/dist/team/index.d.ts +6 -6
  190. package/dist/team/index.js +8 -8
  191. package/dist/{transition-guard--t3exQHF.d.cts → transition-guard-B1N82hMf.d.cts} +1 -1
  192. package/dist/{transition-guard-BlI9Oy5K.d.ts → transition-guard-C__YeF3_.d.ts} +1 -1
  193. package/dist/tx/index.cjs.map +1 -1
  194. package/dist/tx/index.d.cts +6 -6
  195. package/dist/tx/index.d.ts +6 -6
  196. package/dist/tx/index.js +3 -3
  197. package/dist/{types-Diqc2caK.d.ts → types-CraiZOyO.d.ts} +134 -292
  198. package/dist/{types-BpLPqyaO.d.cts → types-D-gr5t0G.d.cts} +134 -292
  199. package/dist/{ulid-DNiRB4Mx.d.cts → ulid-DQnSAP5W.d.cts} +1 -1
  200. package/dist/{ulid-B1zNV8r9.d.ts → ulid-FFRRHkVf.d.ts} +1 -1
  201. package/dist/util/index.cjs.map +1 -1
  202. package/dist/util/index.js +1 -1
  203. package/dist/{vault-group-DPZVFRI5.js → vault-group-27EV7KB4.js} +29 -8
  204. package/dist/vault-group-27EV7KB4.js.map +1 -0
  205. package/dist/{with-materialized-view-BdH_A_r6.d.cts → with-materialized-view-BboqxyV3.d.cts} +1 -1
  206. package/dist/{with-materialized-view-CzAgp_HJ.d.ts → with-materialized-view-CguCeVcT.d.ts} +1 -1
  207. package/dist/{with-overlayed-view-BJbqQnsR.d.ts → with-overlayed-view-DO08u_tx.d.ts} +1 -1
  208. package/dist/{with-overlayed-view-C40rDPlu.d.cts → with-overlayed-view-mmsg5Of3.d.cts} +1 -1
  209. package/dist/{with-rollup-DrlGkxiE.d.ts → with-rollup-_TyBzz3T.d.ts} +1 -1
  210. package/dist/{with-rollup-Bopu5UDZ.d.cts → with-rollup-aaxOZcIb.d.cts} +1 -1
  211. package/package.json +3 -3
  212. package/dist/chunk-647TFNYL.js.map +0 -1
  213. package/dist/chunk-C2OYWD5S.js.map +0 -1
  214. package/dist/chunk-CMISAJAE.js.map +0 -1
  215. package/dist/chunk-F2IJ2HGD.js.map +0 -1
  216. package/dist/chunk-KOURQXIU.js.map +0 -1
  217. package/dist/chunk-LGPSCKWZ.js.map +0 -1
  218. package/dist/chunk-M3H7VSRV.js +0 -139
  219. package/dist/chunk-M3H7VSRV.js.map +0 -1
  220. package/dist/chunk-TPOHMOGX.js.map +0 -1
  221. package/dist/chunk-Y5XVB75E.js.map +0 -1
  222. package/dist/executor-IZ2NVXCY.js +0 -11
  223. package/dist/executor-THSEYEJG.js +0 -8
  224. package/dist/executor-WLFDUTOM.js +0 -8
  225. package/dist/issue-R2MWQO6K.js +0 -12
  226. package/dist/noydb-RJL6FQ4B.js +0 -37
  227. package/dist/registry-3T2RZC5A.js +0 -8
  228. package/dist/registry-DMS7OKBM.js +0 -8
  229. package/dist/vault-group-DPZVFRI5.js.map +0 -1
  230. /package/dist/{chunk-6Q5XRLKG.js.map → chunk-3FSMVWBN.js.map} +0 -0
  231. /package/dist/{chunk-2U226RDC.js.map → chunk-4ULLGYPA.js.map} +0 -0
  232. /package/dist/{chunk-6FHCU3QO.js.map → chunk-5IGWRMEC.js.map} +0 -0
  233. /package/dist/{chunk-KQ523X3A.js.map → chunk-6OSOE6BY.js.map} +0 -0
  234. /package/dist/{chunk-HWK75CYX.js.map → chunk-7C6VFNIY.js.map} +0 -0
  235. /package/dist/{chunk-33DAO2XG.js.map → chunk-7HD67R6U.js.map} +0 -0
  236. /package/dist/{chunk-RQFG2YSV.js.map → chunk-B6E5IRPJ.js.map} +0 -0
  237. /package/dist/{chunk-YWYW2YNO.js.map → chunk-CYNTFU2D.js.map} +0 -0
  238. /package/dist/{chunk-KTZ2MHQK.js.map → chunk-DY3EOJEN.js.map} +0 -0
  239. /package/dist/{chunk-PGVEL5IZ.js.map → chunk-E66DSTJP.js.map} +0 -0
  240. /package/dist/{chunk-6YEC7LLO.js.map → chunk-FBLAWK6A.js.map} +0 -0
  241. /package/dist/{chunk-LQ3GD5LL.js.map → chunk-FPHRTW2Z.js.map} +0 -0
  242. /package/dist/{chunk-ZJ67TB4S.js.map → chunk-G4PYA575.js.map} +0 -0
  243. /package/dist/{chunk-45643PAU.js.map → chunk-GKQAU52M.js.map} +0 -0
  244. /package/dist/{chunk-5KKNBDCT.js.map → chunk-GYAWXHFO.js.map} +0 -0
  245. /package/dist/{chunk-6XEGHIBA.js.map → chunk-IBVTH4JR.js.map} +0 -0
  246. /package/dist/{chunk-AB7JF2KF.js.map → chunk-IVP5IVON.js.map} +0 -0
  247. /package/dist/{chunk-T4T5I5L6.js.map → chunk-KEDJDWWQ.js.map} +0 -0
  248. /package/dist/{chunk-RZWQNMMP.js.map → chunk-LSIIPKYT.js.map} +0 -0
  249. /package/dist/{chunk-FQRAYDS4.js.map → chunk-M3FPNTO2.js.map} +0 -0
  250. /package/dist/{chunk-DR5I7Q6N.js.map → chunk-MI36HL5G.js.map} +0 -0
  251. /package/dist/{chunk-Z3I2WNGF.js.map → chunk-NN6IISZO.js.map} +0 -0
  252. /package/dist/{chunk-QJKZ5WUP.js.map → chunk-OKOKPYWH.js.map} +0 -0
  253. /package/dist/{chunk-Z3BE5BRK.js.map → chunk-PTGQPWMV.js.map} +0 -0
  254. /package/dist/{chunk-QPJ7Z4L3.js.map → chunk-PWFTQHYX.js.map} +0 -0
  255. /package/dist/{chunk-K3NYRK7U.js.map → chunk-Q5MCHUXZ.js.map} +0 -0
  256. /package/dist/{chunk-IQ4GMEYZ.js.map → chunk-S22UOMHM.js.map} +0 -0
  257. /package/dist/{chunk-WZCG3EZ6.js.map → chunk-S3XA7G35.js.map} +0 -0
  258. /package/dist/{chunk-BUBJYIZ7.js.map → chunk-U7JNBSS3.js.map} +0 -0
  259. /package/dist/{chunk-TFAN3NFD.js.map → chunk-V3VIRTTE.js.map} +0 -0
  260. /package/dist/{chunk-VVDSDOVV.js.map → chunk-V5FZWQNN.js.map} +0 -0
  261. /package/dist/{chunk-P57D4KBG.js.map → chunk-VNUE6FHP.js.map} +0 -0
  262. /package/dist/{chunk-TTS3RWL5.js.map → chunk-X7FJMKT3.js.map} +0 -0
  263. /package/dist/{chunk-DKMPR76W.js.map → chunk-Y5J63SMF.js.map} +0 -0
  264. /package/dist/{chunk-HOO5I3VG.js.map → chunk-YLRRU72W.js.map} +0 -0
  265. /package/dist/{chunk-MGB67HKX.js.map → chunk-YX333DPS.js.map} +0 -0
  266. /package/dist/{chunk-4UI5T3K7.js.map → chunk-YZE6C3TQ.js.map} +0 -0
  267. /package/dist/{crypto-FNK3XPCS.js.map → crypto-B46VNH6X.js.map} +0 -0
  268. /package/dist/{delegation-FMXNUWE6.js.map → delegation-5HON72PV.js.map} +0 -0
  269. /package/dist/{executor-IZ2NVXCY.js.map → executor-44R5CUS2.js.map} +0 -0
  270. /package/dist/{executor-THSEYEJG.js.map → executor-AOACUK7Z.js.map} +0 -0
  271. /package/dist/{executor-WLFDUTOM.js.map → executor-OKFLQCDW.js.map} +0 -0
  272. /package/dist/{fanout-sidecar-JGHXAJO5.js.map → fanout-sidecar-DCQWJQ6S.js.map} +0 -0
  273. /package/dist/{issue-R2MWQO6K.js.map → issue-EPA2PSWP.js.map} +0 -0
  274. /package/dist/{ledger-GXC2YA3A.js.map → ledger-LS6GXCBP.js.map} +0 -0
  275. /package/dist/{noydb-RJL6FQ4B.js.map → noydb-BVKFP74P.js.map} +0 -0
  276. /package/dist/{public-envelope-HXOFHY4N.js.map → public-envelope-AGU6SS4Z.js.map} +0 -0
  277. /package/dist/{registry-3T2RZC5A.js.map → registry-ERNAMRDE.js.map} +0 -0
  278. /package/dist/{registry-DMS7OKBM.js.map → registry-EXTHSXQW.js.map} +0 -0
  279. /package/dist/{registry-WVXO6NH5.js.map → registry-RDPTFXQ7.js.map} +0 -0
  280. /package/dist/{revoke-7LCWE2AH.js.map → revoke-IFLXEZA5.js.map} +0 -0
  281. /package/dist/{signer-HAVDLGOK.js.map → signer-UNWOUJAK.js.map} +0 -0
  282. /package/dist/{stale-PGTEGJDI.js.map → stale-NTEV5SLX.js.map} +0 -0
  283. /package/dist/{state-vault-QKQKN3H3.js.map → state-vault-TUTFRTOA.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -46,7 +46,7 @@ var init_types = __esm({
46
46
  });
47
47
 
48
48
  // src/errors.ts
49
- var NoydbError, DecryptionError, TamperedError, InvalidKeyError, KeyringCorruptError, NoAccessError, ReadOnlyError, ReadOnlyAtInstantError, ReadOnlyFrameError, PermissionDeniedError, ExportCapabilityError, KeyringExpiredError, ImportCapabilityError, StoreCapabilityError, PrivilegeEscalationError, ReservedVaultNameError, PeriodClosedError, RecordLockedError, FieldFrozenError, IllegalTransitionError, InvariantError, AmendmentForbiddenError, DirectoryDisabledError, TierNotGrantedError, ElevationExpiredError, AlreadyElevatedError, TierDemoteDeniedError, DelegationTargetMissingError, ConflictError, LedgerContentionError, SequenceContentionError, SequenceOfflineError, NumberingUncertaintyError, BundleVersionConflictError, NetworkError, NotFoundError, ValidationError, SchemaValidationError, SchemaUpdateError, NonAdditiveSchemaChangeError, SchemaLockedError, SchemaFenceError, MigrationRequiredError, QuiesceTimeoutError, GroupCardinalityError, IndexRequiredError, UniqueConstraintError, UnsupportedIndexOptionError, IndexWriteFailureError, BundleIntegrityError, BundleSealMismatchError, ReservedCollectionNameError, DictKeyMissingError, DictKeyInUseError, MissingTranslationError, LocaleNotSpecifiedError, ScriptViolationError, StaticDictReadonlyError, UnknownDictCodeError, TranslatorNotConfiguredError, BackupLedgerError, BackupCorruptedError, AttestationError, SessionExpiredError, SessionNotFoundError, SessionPolicyError, JoinTooLargeError, CrossJoinTooLargeError, CrossJoinSourceUnknownError, DanglingReferenceError, FilenameSanitizationError, PathEscapeError, DerivationCycleError, DerivationDepthError, DerivationOutputUnknownError, DerivationOutputShapeError, DerivationCapExceededError, MaterializedViewCycleError, MaterializedViewSourceUnknownError, MaterializedViewTooLargeError, MaterializedViewConfigError, OverlayBaseIsVirtualError, OverlayCollectionUnavailableError, OverlayNameCollisionError, OverlayIdMismatchError, SnapshotNotFoundError, UnknownShardError, ShardProvisioningError, CrossShardJoinError, VaultTemplateNotFoundError, ForgetStrategyNotConfiguredError, SealedRecordExpiredError, SealedRecordMismatchError, RecordCekNotFoundError;
49
+ var NoydbError, DecryptionError, TamperedError, InvalidKeyError, KeyringCorruptError, NoAccessError, ReadOnlyError, ReadOnlyAtInstantError, ReadOnlyFrameError, PermissionDeniedError, ExportCapabilityError, KeyringExpiredError, ImportCapabilityError, StoreCapabilityError, PrivilegeEscalationError, ReservedVaultNameError, PeriodClosedError, RecordLockedError, FieldFrozenError, IllegalTransitionError, InvariantError, AmendmentForbiddenError, DirectoryDisabledError, TierNotGrantedError, ElevationExpiredError, AlreadyElevatedError, TierDemoteDeniedError, DelegationTargetMissingError, ConflictError, LedgerContentionError, SequenceContentionError, SequenceOfflineError, NumberingUncertaintyError, BundleVersionConflictError, NetworkError, NotFoundError, ValidationError, SchemaValidationError, SchemaUpdateError, NonAdditiveSchemaChangeError, SchemaLockedError, SchemaFenceError, MigrationRequiredError, QuiesceTimeoutError, GroupCardinalityError, IndexRequiredError, UniqueConstraintError, UnsupportedIndexOptionError, IndexWriteFailureError, BundleIntegrityError, BundleSealMismatchError, ReservedCollectionNameError, DictKeyMissingError, DictKeyInUseError, MissingTranslationError, LocaleNotSpecifiedError, ScriptViolationError, StaticDictReadonlyError, UnknownDictCodeError, TranslatorNotConfiguredError, BackupLedgerError, BackupCorruptedError, AttestationError, SessionExpiredError, SessionNotFoundError, SessionPolicyError, JoinTooLargeError, CrossJoinTooLargeError, CrossJoinSourceUnknownError, DanglingReferenceError, FilenameSanitizationError, PathEscapeError, DerivationCycleError, DerivationDepthError, DerivationOutputUnknownError, DerivationOutputShapeError, DerivationCapExceededError, MaterializedViewCycleError, MaterializedViewSourceUnknownError, MaterializedViewTooLargeError, MaterializedViewConfigError, OverlayBaseIsVirtualError, OverlayCollectionUnavailableError, OverlayNameCollisionError, OverlayIdMismatchError, SnapshotNotFoundError, UnknownShardError, ShardProvisioningError, DataResidencyError, CrossShardJoinError, VaultTemplateNotFoundError, ForgetStrategyNotConfiguredError, SealedRecordExpiredError, SealedRecordMismatchError, RecordCekNotFoundError;
50
50
  var init_errors = __esm({
51
51
  "src/errors.ts"() {
52
52
  "use strict";
@@ -1035,6 +1035,21 @@ Resolutions:
1035
1035
  this.vaultId = vaultId;
1036
1036
  }
1037
1037
  };
1038
+ DataResidencyError = class extends NoydbError {
1039
+ vaultId;
1040
+ requiredRegion;
1041
+ backendRegion;
1042
+ constructor(vaultId, requiredRegion, backendRegion) {
1043
+ super(
1044
+ "DATA_RESIDENCY",
1045
+ `Shard "${vaultId}" requires region "${requiredRegion}" but its placement backend declares region ${backendRegion === void 0 ? "(none)" : `"${backendRegion}"`}. Refusing to provision \u2014 route this shard to a region-correct backend via routeStore({ vaultRoutes }) (e.g. a region-encoded partition key) before retrying.`
1046
+ );
1047
+ this.name = "DataResidencyError";
1048
+ this.vaultId = vaultId;
1049
+ this.requiredRegion = requiredRegion;
1050
+ this.backendRegion = backendRegion;
1051
+ }
1052
+ };
1038
1053
  CrossShardJoinError = class extends NoydbError {
1039
1054
  constructor(message) {
1040
1055
  super("CROSS_SHARD_JOIN", message);
@@ -2433,9 +2448,371 @@ __export(public_envelope_exports, {
2433
2448
  var init_public_envelope = __esm({
2434
2449
  "src/meta/public-envelope/index.ts"() {
2435
2450
  "use strict";
2436
- init_types2();
2437
- init_schema();
2438
- init_storage();
2451
+ init_types2();
2452
+ init_schema();
2453
+ init_storage();
2454
+ }
2455
+ });
2456
+
2457
+ // src/i18n/policy.ts
2458
+ function resolvePolicy(onMissing, layer) {
2459
+ const explicit = onMissing && typeof onMissing === "object" ? onMissing[layer] : void 0;
2460
+ const scalar = typeof onMissing === "string" ? onMissing : void 0;
2461
+ const layerDefault = layer === "guard" ? "substitute" : void 0;
2462
+ return explicit ?? layerDefault ?? scalar ?? "throw";
2463
+ }
2464
+ var init_policy = __esm({
2465
+ "src/i18n/policy.ts"() {
2466
+ "use strict";
2467
+ }
2468
+ });
2469
+
2470
+ // src/i18n/script.ts
2471
+ function inferScripts(locale) {
2472
+ const parts = locale.split("-");
2473
+ const subtag = parts.find((t) => /^[A-Z][a-z]{3}$/.test(t));
2474
+ if (subtag && SUBTAG_SCRIPTS[subtag]) return SUBTAG_SCRIPTS[subtag];
2475
+ const base = (parts[0] ?? "").toLowerCase();
2476
+ if (LATIN_BASE.has(base)) return ["Latin"];
2477
+ const primary = SCRIPT_TABLE[base];
2478
+ if (primary) return [...primary, "Latin"];
2479
+ return ["Latin"];
2480
+ }
2481
+ function allowedFor(descriptor, locale) {
2482
+ const script = descriptor.options.script;
2483
+ if (script && script !== "auto") {
2484
+ const explicit = script[locale];
2485
+ if (explicit) return explicit;
2486
+ }
2487
+ return inferScripts(locale);
2488
+ }
2489
+ function fullMatcher(scripts) {
2490
+ const cls = scripts.map((s) => `\\p{Script=${s}}`).join("");
2491
+ return new RegExp(`^[${BASELINE}${cls}]*$`, "u");
2492
+ }
2493
+ function charMatcher(scripts) {
2494
+ const cls = scripts.map((s) => `\\p{Script=${s}}`).join("");
2495
+ return new RegExp(`[${BASELINE}${cls}]`, "u");
2496
+ }
2497
+ function offendingSample(str, scripts) {
2498
+ const ok = charMatcher(scripts);
2499
+ const bad = [];
2500
+ for (const ch of str) {
2501
+ if (!ok.test(ch)) bad.push(ch);
2502
+ if (bad.length >= 8) break;
2503
+ }
2504
+ return bad.join("");
2505
+ }
2506
+ function stripDisallowed(str, scripts) {
2507
+ const ok = charMatcher(scripts);
2508
+ let out = "";
2509
+ for (const ch of str) if (ok.test(ch)) out += ch;
2510
+ return out;
2511
+ }
2512
+ function enforceScript(value, field, descriptor) {
2513
+ const opt = descriptor.options;
2514
+ if (!opt.script) return { value, warnings: [] };
2515
+ const mode = opt.onScriptViolation ?? "reject";
2516
+ const warnings = [];
2517
+ let out = value;
2518
+ for (const [locale, raw] of Object.entries(value)) {
2519
+ if (typeof raw !== "string") continue;
2520
+ const allowed = allowedFor(descriptor, locale);
2521
+ if (fullMatcher(allowed).test(raw)) continue;
2522
+ const sample = offendingSample(raw, allowed);
2523
+ if (mode === "reject") {
2524
+ throw new ScriptViolationError(field, locale, allowed, sample);
2525
+ }
2526
+ warnings.push({ field, locale, expected: allowed, sample });
2527
+ if (mode === "filter") {
2528
+ if (out === value) out = { ...value };
2529
+ out[locale] = stripDisallowed(raw, allowed);
2530
+ }
2531
+ }
2532
+ return { value: out, warnings };
2533
+ }
2534
+ var LATIN_BASE, SCRIPT_TABLE, SUBTAG_SCRIPTS, BASELINE;
2535
+ var init_script = __esm({
2536
+ "src/i18n/script.ts"() {
2537
+ "use strict";
2538
+ init_errors();
2539
+ LATIN_BASE = /* @__PURE__ */ new Set([
2540
+ "en",
2541
+ "fr",
2542
+ "de",
2543
+ "es",
2544
+ "it",
2545
+ "pt",
2546
+ "nl",
2547
+ "sv",
2548
+ "no",
2549
+ "da",
2550
+ "fi",
2551
+ "is",
2552
+ "pl",
2553
+ "cs",
2554
+ "sk",
2555
+ "hu",
2556
+ "ro",
2557
+ "hr",
2558
+ "sl",
2559
+ "et",
2560
+ "lv",
2561
+ "lt",
2562
+ "tr",
2563
+ "vi",
2564
+ "id",
2565
+ "ms",
2566
+ "tl",
2567
+ "sw",
2568
+ "af",
2569
+ "ca",
2570
+ "gl",
2571
+ "eu",
2572
+ "cy",
2573
+ "ga"
2574
+ ]);
2575
+ SCRIPT_TABLE = {
2576
+ th: ["Thai"],
2577
+ ko: ["Hangul", "Han"],
2578
+ ja: ["Han", "Hiragana", "Katakana"],
2579
+ zh: ["Han"],
2580
+ ar: ["Arabic"],
2581
+ fa: ["Arabic"],
2582
+ ur: ["Arabic"],
2583
+ ru: ["Cyrillic"],
2584
+ uk: ["Cyrillic"],
2585
+ bg: ["Cyrillic"],
2586
+ sr: ["Cyrillic"],
2587
+ he: ["Hebrew"],
2588
+ el: ["Greek"],
2589
+ hi: ["Devanagari"],
2590
+ ta: ["Tamil"],
2591
+ km: ["Khmer"],
2592
+ lo: ["Lao"],
2593
+ my: ["Myanmar"]
2594
+ };
2595
+ SUBTAG_SCRIPTS = {
2596
+ Latn: ["Latin"],
2597
+ Cyrl: ["Cyrillic", "Latin"],
2598
+ Hans: ["Han", "Latin"],
2599
+ Hant: ["Han", "Latin"],
2600
+ Thai: ["Thai", "Latin"],
2601
+ Arab: ["Arabic", "Latin"]
2602
+ };
2603
+ BASELINE = String.raw`\p{White_Space}\p{Script=Common}\p{Script=Inherited}\p{Mark}`;
2604
+ }
2605
+ });
2606
+
2607
+ // src/i18n/core.ts
2608
+ function i18nText(options) {
2609
+ return { _noydbI18nText: true, options };
2610
+ }
2611
+ function isI18nTextDescriptor(x) {
2612
+ return typeof x === "object" && x !== null && x._noydbI18nText === true;
2613
+ }
2614
+ function validateI18nTextValue(value, field, descriptor) {
2615
+ const { options } = descriptor;
2616
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
2617
+ throw new MissingTranslationError(
2618
+ field,
2619
+ options.languages,
2620
+ `Field "${field}" must be a { [locale]: string } map, got ${typeof value}.`
2621
+ );
2622
+ }
2623
+ const map = value;
2624
+ for (const [locale, v] of Object.entries(map)) {
2625
+ if (typeof v !== "string") {
2626
+ throw new MissingTranslationError(
2627
+ field,
2628
+ [locale],
2629
+ `Field "${field}": locale "${locale}" must be a string, got ${typeof v}.`
2630
+ );
2631
+ }
2632
+ }
2633
+ const { required } = options;
2634
+ if (required === "all") {
2635
+ const missing = options.languages.filter(
2636
+ (lang) => !(lang in map) || map[lang] === ""
2637
+ );
2638
+ if (missing.length > 0) {
2639
+ throw new MissingTranslationError(
2640
+ field,
2641
+ missing,
2642
+ `Field "${field}" requires all declared languages. Missing: ${missing.join(", ")}.`
2643
+ );
2644
+ }
2645
+ } else if (required === "any") {
2646
+ const present = options.languages.some(
2647
+ (lang) => lang in map && map[lang] !== ""
2648
+ );
2649
+ if (!present) {
2650
+ throw new MissingTranslationError(
2651
+ field,
2652
+ options.languages,
2653
+ `Field "${field}" requires at least one declared language. None present.`
2654
+ );
2655
+ }
2656
+ } else {
2657
+ const requiredList = required;
2658
+ const missing = requiredList.filter(
2659
+ (lang) => !(lang in map) || map[lang] === ""
2660
+ );
2661
+ if (missing.length > 0) {
2662
+ throw new MissingTranslationError(
2663
+ field,
2664
+ missing,
2665
+ `Field "${field}" requires: ${requiredList.join(", ")}. Missing: ${missing.join(", ")}.`
2666
+ );
2667
+ }
2668
+ }
2669
+ }
2670
+ function toChain(fallback) {
2671
+ return Array.isArray(fallback) ? fallback : fallback ? [fallback] : [];
2672
+ }
2673
+ function pickFromChain(value, chain) {
2674
+ for (const fb of chain) {
2675
+ if (fb === "any") {
2676
+ const any = Object.values(value).find((v) => v !== "");
2677
+ if (any !== void 0) return any;
2678
+ } else if (value[fb] !== void 0 && value[fb] !== "") {
2679
+ return value[fb];
2680
+ }
2681
+ }
2682
+ return void 0;
2683
+ }
2684
+ function resolveI18nText(value, locale, fallback, field, opts) {
2685
+ if (locale === "raw") {
2686
+ return value;
2687
+ }
2688
+ if (!locale) {
2689
+ throw new LocaleNotSpecifiedError(field ?? "<unknown>");
2690
+ }
2691
+ if (value[locale] !== void 0 && value[locale] !== "") {
2692
+ return value[locale];
2693
+ }
2694
+ const policy = opts?.policy ?? "throw";
2695
+ const callerChain = toChain(fallback);
2696
+ const callerHit = pickFromChain(value, callerChain);
2697
+ if (callerHit !== void 0) return callerHit;
2698
+ if (policy === "substitute") {
2699
+ const subHit = pickFromChain(value, toChain(opts?.substitute));
2700
+ if (subHit !== void 0) return subHit;
2701
+ if (opts?.smartSubstitute) {
2702
+ const smartHit = pickNearestScript(value, locale);
2703
+ if (smartHit !== void 0) return smartHit;
2704
+ }
2705
+ }
2706
+ if (policy === "throw") {
2707
+ throw new LocaleNotSpecifiedError(
2708
+ field ?? "<unknown>",
2709
+ `No translation available for locale "${locale}"` + (callerChain.length > 0 ? ` or fallback chain [${callerChain.join(", ")}]` : "") + "."
2710
+ );
2711
+ }
2712
+ return null;
2713
+ }
2714
+ function pickNearestScript(value, target) {
2715
+ const targetScript = inferScripts(target)[0] ?? "Latin";
2716
+ let best;
2717
+ for (const [loc, v] of Object.entries(value)) {
2718
+ if (typeof v !== "string" || v === "") continue;
2719
+ const s = inferScripts(loc)[0] ?? "Latin";
2720
+ const score = s === targetScript ? 0 : s === "Latin" ? 1 : 2;
2721
+ if (best === void 0 || score < best.score) best = { score, v };
2722
+ if (score === 0) break;
2723
+ }
2724
+ return best?.v;
2725
+ }
2726
+ function getAtPath(obj, path) {
2727
+ const arrayIdx = path.indexOf("[].");
2728
+ if (arrayIdx !== -1) {
2729
+ const arrayKey = path.slice(0, arrayIdx);
2730
+ const restPath = path.slice(arrayIdx + 3);
2731
+ const arr = obj[arrayKey];
2732
+ if (!Array.isArray(arr)) return [];
2733
+ return arr.flatMap((item) => {
2734
+ if (!item || typeof item !== "object" || Array.isArray(item)) return [];
2735
+ return getAtPath(item, restPath);
2736
+ });
2737
+ }
2738
+ const dotIdx = path.indexOf(".");
2739
+ if (dotIdx !== -1) {
2740
+ const head = path.slice(0, dotIdx);
2741
+ const rest = path.slice(dotIdx + 1);
2742
+ const nested = obj[head];
2743
+ if (!nested || typeof nested !== "object" || Array.isArray(nested)) return [];
2744
+ return getAtPath(nested, rest);
2745
+ }
2746
+ const val = obj[path];
2747
+ return val !== void 0 ? [val] : [];
2748
+ }
2749
+ function setAtPathInPlace(obj, path, value) {
2750
+ const dotIdx = path.indexOf(".");
2751
+ if (dotIdx !== -1) {
2752
+ const head = path.slice(0, dotIdx);
2753
+ const rest = path.slice(dotIdx + 1);
2754
+ const nested = obj[head];
2755
+ if (!nested || typeof nested !== "object" || Array.isArray(nested)) return;
2756
+ setAtPathInPlace(nested, rest, value);
2757
+ return;
2758
+ }
2759
+ obj[path] = value;
2760
+ }
2761
+ function applyAtPath(obj, path, locale, fallback, opts) {
2762
+ const arrayIdx = path.indexOf("[].");
2763
+ if (arrayIdx !== -1) {
2764
+ const arrayKey = path.slice(0, arrayIdx);
2765
+ const restPath = path.slice(arrayIdx + 3);
2766
+ const arr = obj[arrayKey];
2767
+ if (!Array.isArray(arr)) return obj;
2768
+ return {
2769
+ ...obj,
2770
+ [arrayKey]: arr.map((item) => {
2771
+ if (!item || typeof item !== "object" || Array.isArray(item)) return item;
2772
+ return applyAtPath(item, restPath, locale, fallback, opts);
2773
+ })
2774
+ };
2775
+ }
2776
+ const dotIdx = path.indexOf(".");
2777
+ if (dotIdx !== -1) {
2778
+ const head = path.slice(0, dotIdx);
2779
+ const rest = path.slice(dotIdx + 1);
2780
+ const nested = obj[head];
2781
+ if (!nested || typeof nested !== "object" || Array.isArray(nested)) return obj;
2782
+ return {
2783
+ ...obj,
2784
+ [head]: applyAtPath(nested, rest, locale, fallback, opts)
2785
+ };
2786
+ }
2787
+ const raw = obj[path];
2788
+ if (raw === void 0 || raw === null) return obj;
2789
+ if (typeof raw !== "object" || Array.isArray(raw)) return obj;
2790
+ return {
2791
+ ...obj,
2792
+ [path]: resolveI18nText(raw, locale, fallback, path, opts)
2793
+ };
2794
+ }
2795
+ function applyI18nLocale(record, i18nFields, locale, fallback, layer = "read") {
2796
+ const fieldNames = Object.keys(i18nFields);
2797
+ if (fieldNames.length === 0) return record;
2798
+ let result = record;
2799
+ for (const [field, descriptor] of Object.entries(i18nFields)) {
2800
+ const { onMissing, substitute, smartSubstitute } = descriptor.options;
2801
+ const opts = {
2802
+ policy: resolvePolicy(onMissing, layer),
2803
+ ...substitute !== void 0 ? { substitute } : {},
2804
+ ...smartSubstitute ? { smartSubstitute } : {}
2805
+ };
2806
+ result = applyAtPath(result, field, locale, fallback, opts);
2807
+ }
2808
+ return result;
2809
+ }
2810
+ var init_core = __esm({
2811
+ "src/i18n/core.ts"() {
2812
+ "use strict";
2813
+ init_errors();
2814
+ init_policy();
2815
+ init_script();
2439
2816
  }
2440
2817
  });
2441
2818
 
@@ -3418,6 +3795,7 @@ var init_groupby = __esm({
3418
3795
  init_canonical_key();
3419
3796
  init_errors();
3420
3797
  init_money_reducer();
3798
+ init_core();
3421
3799
  GROUPBY_WARN_CARDINALITY = 1e4;
3422
3800
  GROUPBY_MAX_CARDINALITY = 1e5;
3423
3801
  warnedCardinalityFields = /* @__PURE__ */ new Set();
@@ -3486,9 +3864,29 @@ var init_groupby = __esm({
3486
3864
  upstreams;
3487
3865
  dictLabelResolver;
3488
3866
  fields;
3489
- /** Execute the query, group, reduce, and return an array of rows. */
3490
- run() {
3491
- return groupAndReduce(this.executeRecords(), this.fields, this.spec);
3867
+ /**
3868
+ * Execute the query, group, reduce, and return an array of rows.
3869
+ *
3870
+ * `opts` (#285 query-form MV grouping): when a `locale` + `i18nFields` are
3871
+ * given, the declared group-key `i18nText` fields are resolved to that locale
3872
+ * at the `mv` layer BEFORE bucketing — so an i18n group key is a stable string
3873
+ * instead of a raw `{locale}` map. The MV executor passes the MV's
3874
+ * `i18nLocale`/`i18nFields`; ordinary `.run()` callers pass nothing and are
3875
+ * unaffected.
3876
+ */
3877
+ run(opts) {
3878
+ let records = this.executeRecords();
3879
+ if (opts?.locale !== void 0 && opts.i18nFields !== void 0) {
3880
+ const groupI18n = {};
3881
+ for (const f of this.fields) {
3882
+ const d = opts.i18nFields[f];
3883
+ if (d !== void 0) groupI18n[f] = d;
3884
+ }
3885
+ if (Object.keys(groupI18n).length > 0) {
3886
+ records = records.map((r) => applyI18nLocale(r, groupI18n, opts.locale, void 0, "mv"));
3887
+ }
3888
+ }
3889
+ return groupAndReduce(records, this.fields, this.spec);
3492
3890
  }
3493
3891
  /**
3494
3892
  * Execute the query, group, reduce, and resolve `<field>Label` for
@@ -4073,12 +4471,13 @@ var executor_exports3 = {};
4073
4471
  __export(executor_exports3, {
4074
4472
  MaterializedViewExecutor: () => MaterializedViewExecutor
4075
4473
  });
4076
- async function materializeQueryResult(q, mvName) {
4474
+ async function materializeQueryResult(q, mvName, i18nLocale, i18nFields) {
4077
4475
  if (typeof q?.toArray === "function") {
4078
4476
  return await q.toArray();
4079
4477
  }
4080
4478
  if (typeof q?.run === "function") {
4081
- const result = await Promise.resolve(q.run());
4479
+ const runOpts = i18nLocale !== void 0 ? { locale: i18nLocale, i18nFields } : void 0;
4480
+ const result = await Promise.resolve(q.run(runOpts));
4082
4481
  if (Array.isArray(result)) {
4083
4482
  return result;
4084
4483
  }
@@ -4107,6 +4506,29 @@ async function materializeUnionResult(spec, db) {
4107
4506
  }
4108
4507
  if (!spec.groupBy) return unified;
4109
4508
  const groupFields = typeof spec.groupBy === "string" ? [spec.groupBy] : spec.groupBy;
4509
+ if (spec.i18nLocale !== void 0 && spec.i18nFields !== void 0) {
4510
+ const groupI18n = {};
4511
+ for (const f of groupFields) {
4512
+ const d = spec.i18nFields[f];
4513
+ if (d !== void 0) groupI18n[f] = d;
4514
+ }
4515
+ if (Object.keys(groupI18n).length > 0) {
4516
+ for (let i = 0; i < unified.length; i++) {
4517
+ unified[i] = applyI18nLocale(unified[i], groupI18n, spec.i18nLocale, void 0, "mv");
4518
+ }
4519
+ }
4520
+ }
4521
+ for (const f of groupFields) {
4522
+ for (const row of unified) {
4523
+ const v = row[f];
4524
+ if (v !== null && typeof v === "object") {
4525
+ throw new LocaleNotSpecifiedError(
4526
+ f,
4527
+ `Materialized view "${spec.name}" groups by "${f}", whose value is a raw i18n locale map \u2014 an unstable object group key. Declare { i18nLocale, i18nFields } on the MV to resolve it at the 'mv' layer, or group by a dictKey/staticDict code (the stable key) and resolve the label at read time.`
4528
+ );
4529
+ }
4530
+ }
4531
+ }
4110
4532
  if (!spec.aggregate) {
4111
4533
  const seen = /* @__PURE__ */ new Map();
4112
4534
  for (const row of unified) {
@@ -4138,6 +4560,7 @@ var init_executor3 = __esm({
4138
4560
  init_registry();
4139
4561
  init_groupby();
4140
4562
  init_canonical_key();
4563
+ init_core();
4141
4564
  DEFAULT_MAX_ROWS = 1e5;
4142
4565
  MaterializedViewExecutor = {
4143
4566
  async refresh(reg, accessor) {
@@ -4153,7 +4576,7 @@ var init_executor3 = __esm({
4153
4576
  rows = await materializeUnionResult(spec, ctxForQuery);
4154
4577
  } else {
4155
4578
  const q = spec.query(ctxForQuery);
4156
- rows = await materializeQueryResult(q, spec.name);
4579
+ rows = await materializeQueryResult(q, spec.name, spec.i18nLocale, spec.i18nFields);
4157
4580
  }
4158
4581
  if (rows.length > maxRows) {
4159
4582
  throw new MaterializedViewTooLargeError(spec.name, rows.length, maxRows);
@@ -5506,13 +5929,21 @@ var init_vault_group = __esm({
5506
5929
  * - row + vault present → no-op, return handle
5507
5930
  * - row present, vault gone → ShardProvisioningError
5508
5931
  * - row absent (vault present or not) → open-or-create, configure, write row
5932
+ *
5933
+ * When `region` is given (the routing `put` passes `sharding.regionOf(record)`),
5934
+ * the candidate backend's `capabilities.region` must match or this throws
5935
+ * `DataResidencyError` BEFORE provisioning (#271 data-residency guard).
5509
5936
  */
5510
- async createShard(partitionKey) {
5937
+ async createShard(partitionKey, region) {
5511
5938
  const vaultId = this.shardVaultId(partitionKey);
5512
5939
  const row = await this.registry.get(this.registryId(partitionKey));
5513
5940
  const provisioned = await this.db._shardVaultProvisioned(vaultId);
5514
5941
  if (row && !provisioned) throw new ShardProvisioningError(vaultId, partitionKey);
5515
5942
  if (row && provisioned) return this.openShard(partitionKey);
5943
+ if (region !== void 0) {
5944
+ const backendRegion = this.db._resolveBackend(vaultId).capabilities?.region;
5945
+ if (backendRegion !== region) throw new DataResidencyError(vaultId, region, backendRegion);
5946
+ }
5516
5947
  const vault = await this.db.openVault(vaultId);
5517
5948
  this.template.configure(vault);
5518
5949
  await this.registry.put(this.registryId(partitionKey), {
@@ -5594,8 +6025,19 @@ var init_vault_group = __esm({
5594
6025
  *
5595
6026
  * v1 is explicit-refresh (no write-path push); call `refreshInsights()`
5596
6027
  * after a batch of writes, or on a schedule.
6028
+ *
6029
+ * The `target.vault` must NOT be the group itself or one of its shards —
6030
+ * a summary writing back into client-shard data would breach the Insight
6031
+ * Vault's separate-DEK-boundary contract. Such a target throws a
6032
+ * `ValidationError` at registration (#271 Insight-write isolation).
5597
6033
  */
5598
6034
  withCrossVaultDerivation(spec) {
6035
+ const target = spec.target.vault;
6036
+ if (target === this.name || target.startsWith(`${this.name}${SHARD_SEPARATOR}`)) {
6037
+ throw new ValidationError(
6038
+ `withCrossVaultDerivation: target.vault "${target}" is the "${this.name}" group itself or one of its shards \u2014 an Insight summary must target a SEPARATE analytics vault, never write back into client-shard data (it would breach the per-shard DEK boundary). Use a distinct vault name.`
6039
+ );
6040
+ }
5599
6041
  this.crossVaultDerivations.push(spec);
5600
6042
  }
5601
6043
  /**
@@ -5744,7 +6186,7 @@ var init_vault_group = __esm({
5744
6186
  if (this.group.sharding.autoCreate === false) {
5745
6187
  throw new UnknownShardError(key, this.group.name);
5746
6188
  }
5747
- vault = await this.group.createShard(key);
6189
+ vault = await this.group.createShard(key, this.group.sharding.regionOf?.(record));
5748
6190
  } else {
5749
6191
  vault = await this.group.openShard(key);
5750
6192
  }
@@ -5971,6 +6413,7 @@ __export(src_exports, {
5971
6413
  DICT_COLLECTION_PREFIX: () => DICT_COLLECTION_PREFIX,
5972
6414
  DIRECTORY_RECORD_ID: () => DIRECTORY_RECORD_ID,
5973
6415
  DanglingReferenceError: () => DanglingReferenceError,
6416
+ DataResidencyError: () => DataResidencyError,
5974
6417
  DecryptionError: () => DecryptionError,
5975
6418
  DelegationTargetMissingError: () => DelegationTargetMissingError,
5976
6419
  DerivationCapExceededError: () => DerivationCapExceededError,
@@ -6293,6 +6736,7 @@ __export(src_exports, {
6293
6736
  sha256Hex: () => sha256Hex3,
6294
6737
  staticDict: () => staticDict,
6295
6738
  sum: () => sum,
6739
+ tokenize: () => tokenize,
6296
6740
  transitionGuard: () => transitionGuard,
6297
6741
  unwrapDeksFromBlob: () => unwrapDeksFromBlob,
6298
6742
  unwrapDeksFromPaperEntry: () => unwrapDeksFromPaperEntry,
@@ -6691,11 +7135,8 @@ async function compressBytes(data) {
6691
7135
  if (typeof CompressionStream === "undefined") {
6692
7136
  return { bytes: data, algorithm: "none" };
6693
7137
  }
6694
- const cs = new CompressionStream("gzip");
6695
- const writer = cs.writable.getWriter();
6696
- await writer.write(data);
6697
- await writer.close();
6698
- const buf = await new Response(cs.readable).arrayBuffer();
7138
+ const piped = new Response(data).body.pipeThrough(new CompressionStream("gzip"));
7139
+ const buf = await new Response(piped).arrayBuffer();
6699
7140
  return { bytes: new Uint8Array(buf), algorithm: "gzip" };
6700
7141
  }
6701
7142
  async function decompressBytes(data) {
@@ -6704,11 +7145,8 @@ async function decompressBytes(data) {
6704
7145
  "[noy-db] DecompressionStream not available \u2014 cannot decompress blob chunk"
6705
7146
  );
6706
7147
  }
6707
- const ds = new DecompressionStream("gzip");
6708
- const writer = ds.writable.getWriter();
6709
- await writer.write(data);
6710
- await writer.close();
6711
- const buf = await new Response(ds.readable).arrayBuffer();
7148
+ const piped = new Response(data).body.pipeThrough(new DecompressionStream("gzip"));
7149
+ const buf = await new Response(piped).arrayBuffer();
6712
7150
  return new Uint8Array(buf);
6713
7151
  }
6714
7152
  function concatChunks(chunks) {
@@ -8240,6 +8678,14 @@ function routeStore(opts) {
8240
8678
  const q = {};
8241
8679
  for (const [k, v] of writeQueues) q[k] = v.writes.length;
8242
8680
  return { overrides: ov, suspended: [...suspended], queued: q };
8681
+ },
8682
+ resolveBackend(vaultId) {
8683
+ if (opts.vaultRoutes) {
8684
+ for (const [prefix, s] of Object.entries(opts.vaultRoutes)) {
8685
+ if (vaultId.startsWith(prefix)) return s;
8686
+ }
8687
+ }
8688
+ return primary;
8243
8689
  }
8244
8690
  };
8245
8691
  if (anyHas("listVaults")) {
@@ -12406,286 +12852,91 @@ async function recoverUser(store, vault, callerKeyring, options) {
12406
12852
  const target = JSON.parse(env._data);
12407
12853
  const targetRole = options.role ?? target.role;
12408
12854
  if (!canRecover(callerKeyring.role, targetRole)) {
12409
- throw new PermissionDeniedError(
12410
- `Role "${callerKeyring.role}" cannot recover role "${targetRole}"`
12411
- );
12412
- }
12413
- if (!canRecover(callerKeyring.role, target.role)) {
12414
- throw new PermissionDeniedError(
12415
- `Role "${callerKeyring.role}" cannot recover role "${target.role}"`
12416
- );
12417
- }
12418
- for (const coll of Object.keys(target.deks)) {
12419
- if (!callerKeyring.deks.has(coll)) {
12420
- throw new PrivilegeEscalationError(coll);
12421
- }
12422
- }
12423
- if (options.validatePassphrase && !options.allowWeakPassphrase) {
12424
- assertStrongPassphrase(options.passphrase, options.passphrasePolicy);
12425
- }
12426
- const newSalt = generateSalt();
12427
- const newKek = await deriveKey(options.passphrase, newSalt);
12428
- const wrappedDeks = {};
12429
- for (const coll of Object.keys(target.deks)) {
12430
- const callerDek = callerKeyring.deks.get(coll);
12431
- if (!callerDek) {
12432
- throw new PrivilegeEscalationError(coll);
12433
- }
12434
- wrappedDeks[coll] = await wrapKey(callerDek, newKek);
12435
- }
12436
- const canary = await mintKeyringCanary(newKek);
12437
- const next = {
12438
- ...target,
12439
- _noydb_keyring: NOYDB_KEYRING_VERSION,
12440
- role: targetRole,
12441
- display_name: options.displayName ?? target.display_name,
12442
- deks: wrappedDeks,
12443
- salt: bufferToBase64(newSalt),
12444
- granted_by: callerKeyring.userId,
12445
- authenticators: [],
12446
- canary
12447
- };
12448
- const envelope = {
12449
- _noydb: 1,
12450
- _v: 1,
12451
- _ts: (/* @__PURE__ */ new Date()).toISOString(),
12452
- _iv: "",
12453
- _data: JSON.stringify(next)
12454
- };
12455
- await store.put(vault, "_keyring", options.userId, envelope);
12456
- }
12457
-
12458
- // src/index.ts
12459
- init_errors();
12460
-
12461
- // src/noydb.ts
12462
- init_errors();
12463
- init_constants();
12464
- init_ulid();
12465
- init_public_envelope();
12466
-
12467
- // src/vault.ts
12468
- init_types();
12469
-
12470
- // src/collection.ts
12471
- init_types();
12472
-
12473
- // src/crdt/strategy.ts
12474
- var NOT_ENABLED = new Error(
12475
- 'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from "@noy-db/hub/crdt" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.'
12476
- );
12477
- var NO_CRDT = {
12478
- buildLwwMapState() {
12479
- throw NOT_ENABLED;
12480
- },
12481
- buildRgaState() {
12482
- throw NOT_ENABLED;
12483
- },
12484
- mergeCrdtStates() {
12485
- throw NOT_ENABLED;
12486
- },
12487
- resolveCrdtSnapshot() {
12488
- throw NOT_ENABLED;
12489
- }
12490
- };
12491
-
12492
- // src/i18n/core.ts
12493
- init_errors();
12494
-
12495
- // src/i18n/policy.ts
12496
- function resolvePolicy(onMissing, layer) {
12497
- const explicit = onMissing && typeof onMissing === "object" ? onMissing[layer] : void 0;
12498
- const scalar = typeof onMissing === "string" ? onMissing : void 0;
12499
- const layerDefault = layer === "guard" ? "substitute" : void 0;
12500
- return explicit ?? layerDefault ?? scalar ?? "throw";
12501
- }
12502
-
12503
- // src/i18n/core.ts
12504
- function i18nText(options) {
12505
- return { _noydbI18nText: true, options };
12506
- }
12507
- function isI18nTextDescriptor(x) {
12508
- return typeof x === "object" && x !== null && x._noydbI18nText === true;
12509
- }
12510
- function validateI18nTextValue(value, field, descriptor) {
12511
- const { options } = descriptor;
12512
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
12513
- throw new MissingTranslationError(
12514
- field,
12515
- options.languages,
12516
- `Field "${field}" must be a { [locale]: string } map, got ${typeof value}.`
12517
- );
12518
- }
12519
- const map = value;
12520
- for (const [locale, v] of Object.entries(map)) {
12521
- if (typeof v !== "string") {
12522
- throw new MissingTranslationError(
12523
- field,
12524
- [locale],
12525
- `Field "${field}": locale "${locale}" must be a string, got ${typeof v}.`
12526
- );
12527
- }
12528
- }
12529
- const { required } = options;
12530
- if (required === "all") {
12531
- const missing = options.languages.filter(
12532
- (lang) => !(lang in map) || map[lang] === ""
12533
- );
12534
- if (missing.length > 0) {
12535
- throw new MissingTranslationError(
12536
- field,
12537
- missing,
12538
- `Field "${field}" requires all declared languages. Missing: ${missing.join(", ")}.`
12539
- );
12540
- }
12541
- } else if (required === "any") {
12542
- const present = options.languages.some(
12543
- (lang) => lang in map && map[lang] !== ""
12544
- );
12545
- if (!present) {
12546
- throw new MissingTranslationError(
12547
- field,
12548
- options.languages,
12549
- `Field "${field}" requires at least one declared language. None present.`
12550
- );
12551
- }
12552
- } else {
12553
- const requiredList = required;
12554
- const missing = requiredList.filter(
12555
- (lang) => !(lang in map) || map[lang] === ""
12556
- );
12557
- if (missing.length > 0) {
12558
- throw new MissingTranslationError(
12559
- field,
12560
- missing,
12561
- `Field "${field}" requires: ${requiredList.join(", ")}. Missing: ${missing.join(", ")}.`
12562
- );
12563
- }
12564
- }
12565
- }
12566
- function toChain(fallback) {
12567
- return Array.isArray(fallback) ? fallback : fallback ? [fallback] : [];
12568
- }
12569
- function pickFromChain(value, chain) {
12570
- for (const fb of chain) {
12571
- if (fb === "any") {
12572
- const any = Object.values(value).find((v) => v !== "");
12573
- if (any !== void 0) return any;
12574
- } else if (value[fb] !== void 0 && value[fb] !== "") {
12575
- return value[fb];
12576
- }
12577
- }
12578
- return void 0;
12579
- }
12580
- function resolveI18nText(value, locale, fallback, field, opts) {
12581
- if (locale === "raw") {
12582
- return value;
12583
- }
12584
- if (!locale) {
12585
- throw new LocaleNotSpecifiedError(field ?? "<unknown>");
12586
- }
12587
- if (value[locale] !== void 0 && value[locale] !== "") {
12588
- return value[locale];
12589
- }
12590
- const policy = opts?.policy ?? "throw";
12591
- const callerChain = toChain(fallback);
12592
- const callerHit = pickFromChain(value, callerChain);
12593
- if (callerHit !== void 0) return callerHit;
12594
- if (policy === "substitute") {
12595
- const subHit = pickFromChain(value, toChain(opts?.substitute));
12596
- if (subHit !== void 0) return subHit;
12597
- }
12598
- if (policy === "throw") {
12599
- throw new LocaleNotSpecifiedError(
12600
- field ?? "<unknown>",
12601
- `No translation available for locale "${locale}"` + (callerChain.length > 0 ? ` or fallback chain [${callerChain.join(", ")}]` : "") + "."
12602
- );
12603
- }
12604
- return null;
12605
- }
12606
- function getAtPath(obj, path) {
12607
- const arrayIdx = path.indexOf("[].");
12608
- if (arrayIdx !== -1) {
12609
- const arrayKey = path.slice(0, arrayIdx);
12610
- const restPath = path.slice(arrayIdx + 3);
12611
- const arr = obj[arrayKey];
12612
- if (!Array.isArray(arr)) return [];
12613
- return arr.flatMap((item) => {
12614
- if (!item || typeof item !== "object" || Array.isArray(item)) return [];
12615
- return getAtPath(item, restPath);
12616
- });
12855
+ throw new PermissionDeniedError(
12856
+ `Role "${callerKeyring.role}" cannot recover role "${targetRole}"`
12857
+ );
12617
12858
  }
12618
- const dotIdx = path.indexOf(".");
12619
- if (dotIdx !== -1) {
12620
- const head = path.slice(0, dotIdx);
12621
- const rest = path.slice(dotIdx + 1);
12622
- const nested = obj[head];
12623
- if (!nested || typeof nested !== "object" || Array.isArray(nested)) return [];
12624
- return getAtPath(nested, rest);
12859
+ if (!canRecover(callerKeyring.role, target.role)) {
12860
+ throw new PermissionDeniedError(
12861
+ `Role "${callerKeyring.role}" cannot recover role "${target.role}"`
12862
+ );
12625
12863
  }
12626
- const val = obj[path];
12627
- return val !== void 0 ? [val] : [];
12628
- }
12629
- function setAtPathInPlace(obj, path, value) {
12630
- const dotIdx = path.indexOf(".");
12631
- if (dotIdx !== -1) {
12632
- const head = path.slice(0, dotIdx);
12633
- const rest = path.slice(dotIdx + 1);
12634
- const nested = obj[head];
12635
- if (!nested || typeof nested !== "object" || Array.isArray(nested)) return;
12636
- setAtPathInPlace(nested, rest, value);
12637
- return;
12864
+ for (const coll of Object.keys(target.deks)) {
12865
+ if (!callerKeyring.deks.has(coll)) {
12866
+ throw new PrivilegeEscalationError(coll);
12867
+ }
12638
12868
  }
12639
- obj[path] = value;
12640
- }
12641
- function applyAtPath(obj, path, locale, fallback, opts) {
12642
- const arrayIdx = path.indexOf("[].");
12643
- if (arrayIdx !== -1) {
12644
- const arrayKey = path.slice(0, arrayIdx);
12645
- const restPath = path.slice(arrayIdx + 3);
12646
- const arr = obj[arrayKey];
12647
- if (!Array.isArray(arr)) return obj;
12648
- return {
12649
- ...obj,
12650
- [arrayKey]: arr.map((item) => {
12651
- if (!item || typeof item !== "object" || Array.isArray(item)) return item;
12652
- return applyAtPath(item, restPath, locale, fallback, opts);
12653
- })
12654
- };
12869
+ if (options.validatePassphrase && !options.allowWeakPassphrase) {
12870
+ assertStrongPassphrase(options.passphrase, options.passphrasePolicy);
12655
12871
  }
12656
- const dotIdx = path.indexOf(".");
12657
- if (dotIdx !== -1) {
12658
- const head = path.slice(0, dotIdx);
12659
- const rest = path.slice(dotIdx + 1);
12660
- const nested = obj[head];
12661
- if (!nested || typeof nested !== "object" || Array.isArray(nested)) return obj;
12662
- return {
12663
- ...obj,
12664
- [head]: applyAtPath(nested, rest, locale, fallback, opts)
12665
- };
12872
+ const newSalt = generateSalt();
12873
+ const newKek = await deriveKey(options.passphrase, newSalt);
12874
+ const wrappedDeks = {};
12875
+ for (const coll of Object.keys(target.deks)) {
12876
+ const callerDek = callerKeyring.deks.get(coll);
12877
+ if (!callerDek) {
12878
+ throw new PrivilegeEscalationError(coll);
12879
+ }
12880
+ wrappedDeks[coll] = await wrapKey(callerDek, newKek);
12666
12881
  }
12667
- const raw = obj[path];
12668
- if (raw === void 0 || raw === null) return obj;
12669
- if (typeof raw !== "object" || Array.isArray(raw)) return obj;
12670
- return {
12671
- ...obj,
12672
- [path]: resolveI18nText(raw, locale, fallback, path, opts)
12882
+ const canary = await mintKeyringCanary(newKek);
12883
+ const next = {
12884
+ ...target,
12885
+ _noydb_keyring: NOYDB_KEYRING_VERSION,
12886
+ role: targetRole,
12887
+ display_name: options.displayName ?? target.display_name,
12888
+ deks: wrappedDeks,
12889
+ salt: bufferToBase64(newSalt),
12890
+ granted_by: callerKeyring.userId,
12891
+ authenticators: [],
12892
+ canary
12893
+ };
12894
+ const envelope = {
12895
+ _noydb: 1,
12896
+ _v: 1,
12897
+ _ts: (/* @__PURE__ */ new Date()).toISOString(),
12898
+ _iv: "",
12899
+ _data: JSON.stringify(next)
12673
12900
  };
12901
+ await store.put(vault, "_keyring", options.userId, envelope);
12674
12902
  }
12675
- function applyI18nLocale(record, i18nFields, locale, fallback, layer = "read") {
12676
- const fieldNames = Object.keys(i18nFields);
12677
- if (fieldNames.length === 0) return record;
12678
- let result = record;
12679
- for (const [field, descriptor] of Object.entries(i18nFields)) {
12680
- const { onMissing, substitute } = descriptor.options;
12681
- const opts = {
12682
- policy: resolvePolicy(onMissing, layer),
12683
- ...substitute !== void 0 ? { substitute } : {}
12684
- };
12685
- result = applyAtPath(result, field, locale, fallback, opts);
12903
+
12904
+ // src/index.ts
12905
+ init_errors();
12906
+
12907
+ // src/noydb.ts
12908
+ init_errors();
12909
+ init_constants();
12910
+ init_ulid();
12911
+ init_public_envelope();
12912
+
12913
+ // src/vault.ts
12914
+ init_types();
12915
+
12916
+ // src/collection.ts
12917
+ init_types();
12918
+
12919
+ // src/crdt/strategy.ts
12920
+ var NOT_ENABLED = new Error(
12921
+ 'CRDT mode requires the CRDT strategy. Import `{ withCrdt }` from "@noy-db/hub/crdt" and pass it to `createNoydb({ crdtStrategy: withCrdt() })`.'
12922
+ );
12923
+ var NO_CRDT = {
12924
+ buildLwwMapState() {
12925
+ throw NOT_ENABLED;
12926
+ },
12927
+ buildRgaState() {
12928
+ throw NOT_ENABLED;
12929
+ },
12930
+ mergeCrdtStates() {
12931
+ throw NOT_ENABLED;
12932
+ },
12933
+ resolveCrdtSnapshot() {
12934
+ throw NOT_ENABLED;
12686
12935
  }
12687
- return result;
12688
- }
12936
+ };
12937
+
12938
+ // src/collection.ts
12939
+ init_core();
12689
12940
 
12690
12941
  // src/i18n/dictionary.ts
12691
12942
  init_types();
@@ -13390,6 +13641,7 @@ var NO_I18N = {
13390
13641
  };
13391
13642
 
13392
13643
  // src/collection.ts
13644
+ init_policy();
13393
13645
  init_crypto();
13394
13646
  init_errors();
13395
13647
  init_tiers();
@@ -13441,6 +13693,7 @@ init_predicate();
13441
13693
  // src/query/join.ts
13442
13694
  init_predicate();
13443
13695
  init_errors();
13696
+ init_core();
13444
13697
  var DEFAULT_JOIN_MAX_ROWS = 5e4;
13445
13698
  var JOIN_WARN_FRACTION = 0.8;
13446
13699
  function coerceRefKey(value) {
@@ -13468,15 +13721,15 @@ function warnCeilingApproaching(target, side, rows, maxRows) {
13468
13721
  `[noy-db] .join() ${side} side is at ${pct}% of the ${maxRows}-row ceiling for target "${target}" (${rows} rows). Streaming joins over scan() are not yet supported for collections that need to exceed this.`
13469
13722
  );
13470
13723
  }
13471
- function applyJoins(rows, joins, context) {
13724
+ function applyJoins(rows, joins, context, locale) {
13472
13725
  if (joins.length === 0) return [...rows];
13473
13726
  let result = [...rows];
13474
13727
  for (const leg of joins) {
13475
- result = applyOneJoin(result, leg, context);
13728
+ result = applyOneJoin(result, leg, context, locale);
13476
13729
  }
13477
13730
  return result;
13478
13731
  }
13479
- function applyOneJoin(leftRows, leg, context) {
13732
+ function applyOneJoin(leftRows, leg, context, locale) {
13480
13733
  if (leg.isDictJoin) {
13481
13734
  const dictSource = context.resolveDictSource?.(leg.field);
13482
13735
  if (!dictSource) {
@@ -13531,24 +13784,27 @@ function applyOneJoin(leftRows, leg, context) {
13531
13784
  if (rightSnapshot.length > maxRows * JOIN_WARN_FRACTION) {
13532
13785
  warnCeilingApproaching(leg.target, "right", rightSnapshot.length, maxRows);
13533
13786
  }
13787
+ const effLocale = locale ?? context.defaultLocale;
13788
+ const i18nResolve = effLocale !== void 0 && source.i18nFields !== void 0 ? (right) => right !== null && typeof right === "object" ? applyI18nLocale(right, source.i18nFields, effLocale, void 0, "join") : right : void 0;
13534
13789
  const strategy = leg.strategy ?? (source.lookupById ? "nested" : "hash");
13535
13790
  if (strategy === "nested" && source.lookupById) {
13536
13791
  const lookup = (id) => source.lookupById?.(id);
13537
- return nestedLoopJoin(leftRows, leg, lookup);
13792
+ return nestedLoopJoin(leftRows, leg, lookup, i18nResolve);
13538
13793
  }
13539
- return hashJoin(leftRows, leg, rightSnapshot);
13794
+ return hashJoin(leftRows, leg, rightSnapshot, i18nResolve);
13540
13795
  }
13541
- function nestedLoopJoin(leftRows, leg, lookupById) {
13796
+ function nestedLoopJoin(leftRows, leg, lookupById, i18nResolve) {
13542
13797
  const out = [];
13543
13798
  for (const left of leftRows) {
13544
13799
  const rawId = readPath(left, leg.field);
13545
13800
  const key = coerceRefKey(rawId);
13546
- const right = key === null ? void 0 : lookupById(key);
13801
+ let right = key === null ? void 0 : lookupById(key);
13802
+ if (i18nResolve && right !== void 0) right = i18nResolve(right);
13547
13803
  out.push(attachJoin(left, leg, right, rawId));
13548
13804
  }
13549
13805
  return out;
13550
13806
  }
13551
- function hashJoin(leftRows, leg, rightSnapshot) {
13807
+ function hashJoin(leftRows, leg, rightSnapshot, i18nResolve) {
13552
13808
  const rightMap = /* @__PURE__ */ new Map();
13553
13809
  for (const record of rightSnapshot) {
13554
13810
  const rawId = readPath(record, "id");
@@ -13561,7 +13817,8 @@ function hashJoin(leftRows, leg, rightSnapshot) {
13561
13817
  for (const left of leftRows) {
13562
13818
  const rawId = readPath(left, leg.field);
13563
13819
  const key = coerceRefKey(rawId);
13564
- const right = key === null ? void 0 : rightMap.get(key);
13820
+ let right = key === null ? void 0 : rightMap.get(key);
13821
+ if (i18nResolve && right !== void 0) right = i18nResolve(right);
13565
13822
  out.push(attachJoin(left, leg, right, rawId));
13566
13823
  }
13567
13824
  return out;
@@ -13859,11 +14116,16 @@ var Query = class _Query {
13859
14116
  this.predicates
13860
14117
  );
13861
14118
  }
13862
- /** Sort by a field. Subsequent calls are tie-breakers. */
13863
- orderBy(field, direction = "asc") {
14119
+ /**
14120
+ * Sort by a field. Subsequent calls are tie-breakers. Pass
14121
+ * `{ by: 'label' }` to sort a `dictKey`/`staticDict` field by its resolved
14122
+ * label at the query locale instead of the stored code (#285).
14123
+ */
14124
+ orderBy(field, direction = "asc", opts) {
14125
+ const entry = opts?.by === "label" ? { field, direction, by: "label" } : { field, direction };
13864
14126
  return new _Query(
13865
14127
  this.source,
13866
- { ...this.plan, orderBy: [...this.plan.orderBy, { field, direction }] },
14128
+ { ...this.plan, orderBy: [...this.plan.orderBy, entry] },
13867
14129
  this.joinContext,
13868
14130
  this.aggregateStrategy,
13869
14131
  this.predicates
@@ -14066,16 +14328,21 @@ var Query = class _Query {
14066
14328
  * carries any join legs, they are applied after `where` / `orderBy`
14067
14329
  * / `limit` / `offset` narrow the left set. See the `.join()` doc
14068
14330
  * for the ordering rationale.
14331
+ *
14332
+ * `opts.locale` (#285 §3) resolves JOINED right-side i18n fields at the
14333
+ * `join` layer to that locale; without it, the owning collection's default
14334
+ * locale applies, and a locale-less query leaves joined i18n fields raw.
14335
+ * (Left/base i18n fields are resolved by `get`/`list`, not here.)
14069
14336
  */
14070
- toArray() {
14071
- const base = this.decodeMoney(executePlanWithSource(this.source, this.plan, this.joinContext));
14337
+ toArray(opts) {
14338
+ const base = this.decodeMoney(executePlanWithSource(this.source, this.plan, this.joinContext, opts?.locale));
14072
14339
  if (this.plan.joins.length === 0) return base;
14073
14340
  if (!this.joinContext) {
14074
14341
  throw new Error(
14075
14342
  `Query.toArray(): plan carries ${this.plan.joins.length} join leg(s) but no JoinContext is attached. This usually means the Query was constructed via the raw Query constructor with a plan that had joins pre-populated. Use collection.query().join(...) instead.`
14076
14343
  );
14077
14344
  }
14078
- return applyJoins(base, this.plan.joins, this.joinContext);
14345
+ return applyJoins(base, this.plan.joins, this.joinContext, opts?.locale);
14079
14346
  }
14080
14347
  /**
14081
14348
  * Decode this source's money fields on read (stored scaled-int → canonical
@@ -14094,9 +14361,9 @@ var Query = class _Query {
14094
14361
  if (!moneyFields || Object.keys(moneyFields).length === 0) return records;
14095
14362
  return records.map((r) => decodeMoneyFields(r, moneyFields, "raw"));
14096
14363
  }
14097
- /** Return the first matching record, or null. Joins are applied. */
14098
- first() {
14099
- const arr = this.limit(1).toArray();
14364
+ /** Return the first matching record, or null. Joins are applied. `opts.locale` resolves joined i18n fields (#285 §3). */
14365
+ first(opts) {
14366
+ const arr = this.limit(1).toArray(opts);
14100
14367
  return arr[0] ?? null;
14101
14368
  }
14102
14369
  /**
@@ -14339,7 +14606,7 @@ var Query = class _Query {
14339
14606
  return serializePlan(this.plan);
14340
14607
  }
14341
14608
  };
14342
- function executePlanWithSource(source, plan, joinContext) {
14609
+ function executePlanWithSource(source, plan, joinContext, locale) {
14343
14610
  const hasCrossJoins = plan.clauses.some((c) => c.type === "crossJoin");
14344
14611
  let result;
14345
14612
  if (hasCrossJoins) {
@@ -14354,7 +14621,8 @@ function executePlanWithSource(source, plan, joinContext) {
14354
14621
  result = remainingClauses.length === 0 ? [...candidates] : filterRecords(candidates, remainingClauses, fnViewDecoder(source));
14355
14622
  }
14356
14623
  if (plan.orderBy.length > 0) {
14357
- result = sortRecords(result, plan.orderBy, source.moneyFields);
14624
+ const labelMaps = buildOrderLabelMaps(plan.orderBy, joinContext, locale);
14625
+ result = sortRecords(result, plan.orderBy, source.moneyFields, labelMaps);
14358
14626
  }
14359
14627
  if (plan.offset > 0) {
14360
14628
  result = result.slice(plan.offset);
@@ -14511,11 +14779,19 @@ function applyCrossJoin(leftRel, clause, rightSource) {
14511
14779
  }
14512
14780
  return expanded;
14513
14781
  }
14514
- function sortRecords(records, orderBy, moneyFields) {
14782
+ function sortRecords(records, orderBy, moneyFields, labelMaps) {
14515
14783
  return [...records].sort((a, b) => {
14516
- for (const { field, direction } of orderBy) {
14517
- const av = readField(a, field);
14518
- const bv = readField(b, field);
14784
+ for (const { field, direction, by } of orderBy) {
14785
+ let av = readField(a, field);
14786
+ let bv = readField(b, field);
14787
+ const labelMap = by === "label" ? labelMaps?.get(field) : void 0;
14788
+ if (labelMap) {
14789
+ av = (typeof av === "string" ? labelMap.get(av) : void 0) ?? av;
14790
+ bv = (typeof bv === "string" ? labelMap.get(bv) : void 0) ?? bv;
14791
+ const cmp2 = compareValues(av, bv);
14792
+ if (cmp2 !== 0) return direction === "asc" ? cmp2 : -cmp2;
14793
+ continue;
14794
+ }
14519
14795
  const desc = moneyFields?.[field];
14520
14796
  const cmp = desc ? compareMoney(av, bv, desc) : compareValues(av, bv);
14521
14797
  if (cmp !== 0) return direction === "asc" ? cmp : -cmp;
@@ -14523,6 +14799,28 @@ function sortRecords(records, orderBy, moneyFields) {
14523
14799
  return 0;
14524
14800
  });
14525
14801
  }
14802
+ function buildOrderLabelMaps(orderBy, joinContext, locale) {
14803
+ if (!joinContext?.resolveDictSource) return void 0;
14804
+ const resolveDict = joinContext.resolveDictSource.bind(joinContext);
14805
+ let maps;
14806
+ for (const { field, by } of orderBy) {
14807
+ if (by !== "label") continue;
14808
+ const dictSource = resolveDict(field);
14809
+ if (!dictSource) continue;
14810
+ const loc = locale ?? dictSource.displayLocale;
14811
+ if (loc === void 0) continue;
14812
+ const codeToLabel = /* @__PURE__ */ new Map();
14813
+ for (const entry of dictSource.snapshot()) {
14814
+ const k = entry["key"];
14815
+ const labels = entry["labels"];
14816
+ const label = labels?.[loc];
14817
+ if (typeof k === "string" && typeof label === "string") codeToLabel.set(k, label);
14818
+ }
14819
+ ;
14820
+ (maps ??= /* @__PURE__ */ new Map()).set(field, codeToLabel);
14821
+ }
14822
+ return maps;
14823
+ }
14526
14824
  function compareMoney(a, b, desc) {
14527
14825
  const av = moneyScaledValue(a, desc);
14528
14826
  const bv = moneyScaledValue(b, desc);
@@ -15502,6 +15800,74 @@ var DISABLED_STATE = {
15502
15800
  getPersistedIndexes: () => null
15503
15801
  };
15504
15802
 
15803
+ // src/search/tokenize.ts
15804
+ var WORD = /[\p{L}\p{N}]+/gu;
15805
+ var tokenize = (text) => {
15806
+ if (!text) return [];
15807
+ return text.normalize("NFKC").toLowerCase().match(WORD) ?? [];
15808
+ };
15809
+
15810
+ // src/search/scan.ts
15811
+ var K1 = 1.2;
15812
+ var B = 0.75;
15813
+ function fieldText(record, field) {
15814
+ const v = record[field];
15815
+ if (typeof v === "string") return v;
15816
+ if (v === null || v === void 0) return "";
15817
+ if (typeof v === "number" || typeof v === "boolean") return String(v);
15818
+ return "";
15819
+ }
15820
+ function searchScan(entries, field, query, opts = {}, tokenizer = tokenize) {
15821
+ const queryTerms = tokenizer(query);
15822
+ if (queryTerms.length === 0) return [];
15823
+ const match = opts.match ?? "any";
15824
+ const usePrefix = opts.prefix ?? false;
15825
+ const exactTerms = usePrefix ? queryTerms.slice(0, -1) : queryTerms;
15826
+ const prefixTerm = usePrefix ? queryTerms[queryTerms.length - 1] : void 0;
15827
+ const docs = entries.map((e) => ({ id: e.id, record: e.record, terms: tokenizer(fieldText(e.record, field)) }));
15828
+ const N = docs.length || 1;
15829
+ const df = /* @__PURE__ */ new Map();
15830
+ let totalLen = 0;
15831
+ for (const d of docs) {
15832
+ totalLen += d.terms.length;
15833
+ for (const t of new Set(d.terms)) df.set(t, (df.get(t) ?? 0) + 1);
15834
+ }
15835
+ const avgdl = totalLen / N || 1;
15836
+ let prefixDf = 0;
15837
+ if (prefixTerm !== void 0) {
15838
+ for (const d of docs) {
15839
+ if (d.terms.some((t) => t.startsWith(prefixTerm))) prefixDf++;
15840
+ }
15841
+ }
15842
+ const requiredCount = exactTerms.length + (prefixTerm !== void 0 ? 1 : 0);
15843
+ const results = [];
15844
+ for (const d of docs) {
15845
+ const tf = /* @__PURE__ */ new Map();
15846
+ for (const t of d.terms) tf.set(t, (tf.get(t) ?? 0) + 1);
15847
+ const matched = [];
15848
+ for (const qt of exactTerms) {
15849
+ const c = tf.get(qt) ?? 0;
15850
+ if (c > 0) matched.push({ tf: c, df: df.get(qt) ?? 0 });
15851
+ }
15852
+ if (prefixTerm !== void 0) {
15853
+ let ptf = 0;
15854
+ for (const [t, c] of tf) if (t.startsWith(prefixTerm)) ptf += c;
15855
+ if (ptf > 0) matched.push({ tf: ptf, df: prefixDf });
15856
+ }
15857
+ if (matched.length === 0) continue;
15858
+ if (match === "all" && matched.length < requiredCount) continue;
15859
+ let score = 0;
15860
+ for (const m of matched) {
15861
+ const idf = Math.log(1 + (N - m.df + 0.5) / (m.df + 0.5));
15862
+ const denom = m.tf + K1 * (1 - B + B * (d.terms.length / avgdl));
15863
+ score += idf * (m.tf * (K1 + 1) / (denom || 1));
15864
+ }
15865
+ results.push({ id: d.id, score, record: d.record });
15866
+ }
15867
+ results.sort((a, b) => b.score - a.score);
15868
+ return opts.limit !== void 0 ? results.slice(0, opts.limit) : results;
15869
+ }
15870
+
15505
15871
  // src/collection.ts
15506
15872
  init_errors();
15507
15873
 
@@ -17789,6 +18155,29 @@ var Collection = class {
17789
18155
  hasReadTransforms() {
17790
18156
  return this.moneyFields !== void 0 && Object.keys(this.moneyFields).length > 0 || this.i18nFields !== void 0 && Object.keys(this.i18nFields).length > 0 || this.dictKeyFields !== void 0 && Object.keys(this.dictKeyFields).length > 0;
17791
18157
  }
18158
+ /**
18159
+ * Scan-mode full-text search over a plain-text `field` (#308). Decrypts the
18160
+ * collection in memory and ranks records by BM25 against the tokenized query.
18161
+ * **Zero added store leakage** — pure client-side scan; nothing searchable is
18162
+ * written to the store. (A store-usable blind index for at-scale search is a
18163
+ * separate, gated opt-in — see the #308 design note.) Eager mode only.
18164
+ *
18165
+ * `opts.match` (`'any'` default | `'all'`), `opts.prefix` (last query term as
18166
+ * a prefix → typeahead), `opts.limit` (top-N). Returns `{ id, score, record }`
18167
+ * ranked by descending score. The default tokenizer is word-boundary based —
18168
+ * see `src/search/tokenize.ts` for the Thai/CJK caveat.
18169
+ */
18170
+ async search(field, query, opts = {}) {
18171
+ if (this.lazy) {
18172
+ throw new Error(
18173
+ `Collection "${this.name}": search() (scan mode) requires eager mode (prefetch: true). A store-usable blind index for lazy / at-scale search is a separate gated opt-in (#308).`
18174
+ );
18175
+ }
18176
+ await this.ensureHydrated();
18177
+ const entries = [];
18178
+ for (const [id, e] of this.cache) entries.push({ id, record: e.record });
18179
+ return searchScan(entries, field, query, opts);
18180
+ }
17792
18181
  // ─── Bulk operations ─────────────────────────────────────
17793
18182
  /**
17794
18183
  * Put many records in one call. Each item is processed sequentially
@@ -17966,6 +18355,10 @@ var Collection = class {
17966
18355
  leftCollection,
17967
18356
  resolveRef: (field) => resolver.resolveRef(leftCollection, field),
17968
18357
  resolveSource: (collectionName) => resolver.resolveSource(collectionName),
18358
+ // #285 §3 — flow the vault/collection default locale to joins so a
18359
+ // joined i18n field resolves like get()/list() when no per-call
18360
+ // locale is given; toArray({ locale }) overrides it.
18361
+ ...this.defaultLocale !== void 0 ? { defaultLocale: this.defaultLocale } : {},
17969
18362
  ...resolver.resolveDictSource ? { resolveDictSource: (field) => resolver.resolveDictSource(leftCollection, field) } : {}
17970
18363
  } : void 0;
17971
18364
  return new Query(source, void 0, joinContext, this.aggregateStrategy);
@@ -18054,7 +18447,10 @@ var Collection = class {
18054
18447
  };
18055
18448
  this.emitter.on("change", handler);
18056
18449
  return () => this.emitter.off("change", handler);
18057
- }
18450
+ },
18451
+ // #285 §3 — expose this (right-side) collection's i18nText descriptors so
18452
+ // the join executor can resolve joined i18n fields at the `join` layer.
18453
+ ...this.i18nFields !== void 0 ? { i18nFields: this.i18nFields } : {}
18058
18454
  };
18059
18455
  }
18060
18456
  /**
@@ -18287,6 +18683,10 @@ var Collection = class {
18287
18683
  leftCollection,
18288
18684
  resolveRef: (field) => resolver.resolveRef(leftCollection, field),
18289
18685
  resolveSource: (collectionName) => resolver.resolveSource(collectionName),
18686
+ // #285 §3 — flow the vault/collection default locale to joins so a
18687
+ // joined i18n field resolves like get()/list() when no per-call
18688
+ // locale is given; toArray({ locale }) overrides it.
18689
+ ...this.defaultLocale !== void 0 ? { defaultLocale: this.defaultLocale } : {},
18290
18690
  ...resolver.resolveDictSource ? { resolveDictSource: (field) => resolver.resolveDictSource(leftCollection, field) } : {}
18291
18691
  } : void 0;
18292
18692
  return new ScanBuilder(
@@ -18844,6 +19244,34 @@ var Collection = class {
18844
19244
  }
18845
19245
  }
18846
19246
  }
19247
+ /**
19248
+ * @internal — hard-delete this record's persisted `_idx/<field>/<recordId>`
19249
+ * side-cars for the erasure path (#401). `forget()` crypto-shreds the body but
19250
+ * keeps the collection DEK, under which these side-cars are encrypted — so
19251
+ * without this they leave the indexed field VALUES readable after a "forget".
19252
+ *
19253
+ * Content-free: the side-car id is `encodeIdxId(def.key, id)`, so it needs no
19254
+ * body decode (the body is being shredded). Eager mode has no durable side-car
19255
+ * → no-op. The in-memory mirror is left as-is: it is ephemeral (rebuilt from
19256
+ * the now-deleted side-cars on reopen) and live reads skip the tombstone, so a
19257
+ * stale mirror hit cannot surface the erased record. Returns the count deleted
19258
+ * + the `def.key`s whose delete FAILED (residue that still leaks the value).
19259
+ */
19260
+ async _purgePersistedIndexes(id) {
19261
+ const persisted = this.persistedIndexes;
19262
+ if (!persisted) return { purged: 0, residue: [] };
19263
+ let purged = 0;
19264
+ const residue = [];
19265
+ for (const def of persisted.definitions()) {
19266
+ try {
19267
+ await this.adapter.delete(this.vault, this.name, encodeIdxId(def.key, id));
19268
+ purged++;
19269
+ } catch {
19270
+ residue.push(def.key);
19271
+ }
19272
+ }
19273
+ return { purged, residue };
19274
+ }
18847
19275
  /**
18848
19276
  * Bulk-load the persisted-index mirror from `_idx/<field>/*` side-cars
18849
19277
  * on first lazy-mode query. Idempotent — subsequent calls short-circuit
@@ -19976,6 +20404,7 @@ var NO_PERIODS = {
19976
20404
  };
19977
20405
 
19978
20406
  // src/vault.ts
20407
+ init_core();
19979
20408
  init_errors();
19980
20409
 
19981
20410
  // src/periods/periods.ts
@@ -22586,6 +23015,8 @@ var Vault = class {
22586
23015
  const blobResidueCollections = /* @__PURE__ */ new Set();
22587
23016
  let blobsShredded = 0;
22588
23017
  let blobsRetainedShared = 0;
23018
+ let indexPostingsPurged = 0;
23019
+ const indexResidue = [];
22589
23020
  const blobsEnabled = this.blobStrategy !== void 0;
22590
23021
  const actor = this.keyring.userId;
22591
23022
  for (const ref2 of refs) {
@@ -22607,6 +23038,9 @@ var Vault = class {
22607
23038
  ref2.id,
22608
23039
  actor
22609
23040
  );
23041
+ const idxPurge = await coll._purgePersistedIndexes(ref2.id);
23042
+ indexPostingsPurged += idxPurge.purged;
23043
+ for (const field of idxPurge.residue) indexResidue.push(`${ref2.collection}:${ref2.id}:${field}`);
22610
23044
  if (blobsEnabled) {
22611
23045
  const r = await this.collection(ref2.collection).blob(ref2.id).shredAllForRecord();
22612
23046
  blobsShredded += r.shredded.length;
@@ -22642,7 +23076,9 @@ var Vault = class {
22642
23076
  unmigratedCount: unmigratedRecords.length,
22643
23077
  blobsShredded,
22644
23078
  blobsRetainedShared,
22645
- blobResidueCollections: [...blobResidueCollections]
23079
+ blobResidueCollections: [...blobResidueCollections],
23080
+ indexPostingsPurged,
23081
+ indexResidueCount: indexResidue.length
22646
23082
  })
22647
23083
  });
22648
23084
  return {
@@ -22654,6 +23090,8 @@ var Vault = class {
22654
23090
  blobsShredded,
22655
23091
  blobsRetainedShared,
22656
23092
  blobResidueCollections: [...blobResidueCollections],
23093
+ indexPostingsPurged,
23094
+ indexResidue,
22657
23095
  ledgerEntry
22658
23096
  };
22659
23097
  }
@@ -23916,6 +24354,8 @@ var Vault = class {
23916
24354
  */
23917
24355
  async *exportStream(opts = {}) {
23918
24356
  const granularity = opts.granularity ?? "collection";
24357
+ const exportLocale = opts.resolveLabels;
24358
+ const localeOpts = exportLocale !== void 0 ? { locale: exportLocale, _layer: "export" } : void 0;
23919
24359
  const snapshot = await this.adapter.loadAll(this.name);
23920
24360
  const collectionNames = Object.keys(snapshot).sort();
23921
24361
  const ledgerHead = opts.withLedgerHead ? await (async () => {
@@ -23925,19 +24365,21 @@ var Vault = class {
23925
24365
  return head ? { hash: head.hash, index: head.entry.index, ts: head.entry.ts } : void 0;
23926
24366
  })() : void 0;
23927
24367
  const dictSnapshotCache = /* @__PURE__ */ new Map();
23928
- for (const collectionName of collectionNames) {
23929
- const dictFields = this.dictKeyFieldRegistry.get(collectionName);
23930
- if (dictFields && Object.keys(dictFields).length > 0) {
23931
- const snap = {};
23932
- for (const [fieldName, dictName] of Object.entries(dictFields)) {
23933
- const entries = await this.dictionary(dictName).list();
23934
- const keyMap = {};
23935
- for (const entry of entries) {
23936
- keyMap[entry.key] = entry.labels;
24368
+ if (exportLocale === void 0) {
24369
+ for (const collectionName of collectionNames) {
24370
+ const dictFields = this.dictKeyFieldRegistry.get(collectionName);
24371
+ if (dictFields && Object.keys(dictFields).length > 0) {
24372
+ const snap = {};
24373
+ for (const [fieldName, dictName] of Object.entries(dictFields)) {
24374
+ const entries = await this.dictionary(dictName).list();
24375
+ const keyMap = {};
24376
+ for (const entry of entries) {
24377
+ keyMap[entry.key] = entry.labels;
24378
+ }
24379
+ snap[fieldName] = keyMap;
23937
24380
  }
23938
- snap[fieldName] = keyMap;
24381
+ dictSnapshotCache.set(collectionName, snap);
23939
24382
  }
23940
- dictSnapshotCache.set(collectionName, snap);
23941
24383
  }
23942
24384
  }
23943
24385
  for (const collectionName of collectionNames) {
@@ -23950,7 +24392,7 @@ var Vault = class {
23950
24392
  if (granularity === "collection") {
23951
24393
  const records = [];
23952
24394
  for (const id of ids) {
23953
- const record = await coll.get(id);
24395
+ const record = await coll.get(id, localeOpts);
23954
24396
  if (record !== null) records.push(record);
23955
24397
  }
23956
24398
  const chunk = {
@@ -23964,7 +24406,7 @@ var Vault = class {
23964
24406
  yield chunk;
23965
24407
  } else {
23966
24408
  for (const id of ids) {
23967
- const record = await coll.get(id);
24409
+ const record = await coll.get(id, localeOpts);
23968
24410
  if (record === null) continue;
23969
24411
  const chunk = {
23970
24412
  collection: collectionName,
@@ -24068,7 +24510,10 @@ var Vault = class {
24068
24510
  const allDictionaries = {};
24069
24511
  for await (const chunk of this.exportStream({
24070
24512
  granularity: "collection",
24071
- withLedgerHead: opts.withLedgerHead === true
24513
+ withLedgerHead: opts.withLedgerHead === true,
24514
+ // #285 export layer: thread the export locale so records are read at the
24515
+ // `export` layer (i18nText collapsed + dictKey/staticDict labels resolved).
24516
+ ...opts.resolveLabels !== void 0 ? { resolveLabels: opts.resolveLabels } : {}
24072
24517
  })) {
24073
24518
  collections[chunk.collection] = {
24074
24519
  schema: null,
@@ -25902,6 +26347,16 @@ var Noydb = class {
25902
26347
  async _shardVaultProvisioned(vaultId) {
25903
26348
  return (await this.options.store.list(vaultId, "_keyring")).length > 0;
25904
26349
  }
26350
+ /**
26351
+ * @internal — the physical backend store a vault id maps to. A
26352
+ * `routeStore` resolves the vault-prefix route via its `resolveBackend`;
26353
+ * a plain store is its own backend. Used by the federation data-residency
26354
+ * guard to read the placement backend's `capabilities.region` (#271).
26355
+ */
26356
+ _resolveBackend(vaultId) {
26357
+ const store = this.options.store;
26358
+ return store.resolveBackend ? store.resolveBackend(vaultId) : this.options.store;
26359
+ }
25905
26360
  /**
25906
26361
  * Change the current user's passphrase for a vault.
25907
26362
  *
@@ -28461,6 +28916,11 @@ function withMaterializedView(spec) {
28461
28916
  );
28462
28917
  }
28463
28918
  }
28919
+ if (spec.i18nLocale !== void 0 && spec.i18nFields === void 0) {
28920
+ throw new MaterializedViewConfigError(
28921
+ `withMaterializedView "${spec.name}": i18nLocale requires i18nFields \u2014 declare the i18nText descriptors of the group-key fields so they can be resolved at the mv layer before bucketing.`
28922
+ );
28923
+ }
28464
28924
  if (typeof spec.rowKey !== "function") {
28465
28925
  throw new ValidationError("withMaterializedView: rowKey is required (no default; see spec \xA7 Type surface)");
28466
28926
  }
@@ -28510,6 +28970,7 @@ function withOverlayedView(spec) {
28510
28970
  // src/index.ts
28511
28971
  init_errors();
28512
28972
  init_errors();
28973
+ init_core();
28513
28974
 
28514
28975
  // src/money/index.ts
28515
28976
  init_descriptor();
@@ -28626,138 +29087,9 @@ function isMoneyLike(value) {
28626
29087
  return decimalScaleOf(value) !== null;
28627
29088
  }
28628
29089
 
28629
- // src/i18n/script.ts
28630
- init_errors();
28631
- var LATIN_BASE = /* @__PURE__ */ new Set([
28632
- "en",
28633
- "fr",
28634
- "de",
28635
- "es",
28636
- "it",
28637
- "pt",
28638
- "nl",
28639
- "sv",
28640
- "no",
28641
- "da",
28642
- "fi",
28643
- "is",
28644
- "pl",
28645
- "cs",
28646
- "sk",
28647
- "hu",
28648
- "ro",
28649
- "hr",
28650
- "sl",
28651
- "et",
28652
- "lv",
28653
- "lt",
28654
- "tr",
28655
- "vi",
28656
- "id",
28657
- "ms",
28658
- "tl",
28659
- "sw",
28660
- "af",
28661
- "ca",
28662
- "gl",
28663
- "eu",
28664
- "cy",
28665
- "ga"
28666
- ]);
28667
- var SCRIPT_TABLE = {
28668
- th: ["Thai"],
28669
- ko: ["Hangul", "Han"],
28670
- ja: ["Han", "Hiragana", "Katakana"],
28671
- zh: ["Han"],
28672
- ar: ["Arabic"],
28673
- fa: ["Arabic"],
28674
- ur: ["Arabic"],
28675
- ru: ["Cyrillic"],
28676
- uk: ["Cyrillic"],
28677
- bg: ["Cyrillic"],
28678
- sr: ["Cyrillic"],
28679
- he: ["Hebrew"],
28680
- el: ["Greek"],
28681
- hi: ["Devanagari"],
28682
- ta: ["Tamil"],
28683
- km: ["Khmer"],
28684
- lo: ["Lao"],
28685
- my: ["Myanmar"]
28686
- };
28687
- var SUBTAG_SCRIPTS = {
28688
- Latn: ["Latin"],
28689
- Cyrl: ["Cyrillic", "Latin"],
28690
- Hans: ["Han", "Latin"],
28691
- Hant: ["Han", "Latin"],
28692
- Thai: ["Thai", "Latin"],
28693
- Arab: ["Arabic", "Latin"]
28694
- };
28695
- function inferScripts(locale) {
28696
- const parts = locale.split("-");
28697
- const subtag = parts.find((t) => /^[A-Z][a-z]{3}$/.test(t));
28698
- if (subtag && SUBTAG_SCRIPTS[subtag]) return SUBTAG_SCRIPTS[subtag];
28699
- const base = (parts[0] ?? "").toLowerCase();
28700
- if (LATIN_BASE.has(base)) return ["Latin"];
28701
- const primary = SCRIPT_TABLE[base];
28702
- if (primary) return [...primary, "Latin"];
28703
- return ["Latin"];
28704
- }
28705
- function allowedFor(descriptor, locale) {
28706
- const script = descriptor.options.script;
28707
- if (script && script !== "auto") {
28708
- const explicit = script[locale];
28709
- if (explicit) return explicit;
28710
- }
28711
- return inferScripts(locale);
28712
- }
28713
- var BASELINE = String.raw`\p{White_Space}\p{Script=Common}\p{Script=Inherited}\p{Mark}`;
28714
- function fullMatcher(scripts) {
28715
- const cls = scripts.map((s) => `\\p{Script=${s}}`).join("");
28716
- return new RegExp(`^[${BASELINE}${cls}]*$`, "u");
28717
- }
28718
- function charMatcher(scripts) {
28719
- const cls = scripts.map((s) => `\\p{Script=${s}}`).join("");
28720
- return new RegExp(`[${BASELINE}${cls}]`, "u");
28721
- }
28722
- function offendingSample(str, scripts) {
28723
- const ok = charMatcher(scripts);
28724
- const bad = [];
28725
- for (const ch of str) {
28726
- if (!ok.test(ch)) bad.push(ch);
28727
- if (bad.length >= 8) break;
28728
- }
28729
- return bad.join("");
28730
- }
28731
- function stripDisallowed(str, scripts) {
28732
- const ok = charMatcher(scripts);
28733
- let out = "";
28734
- for (const ch of str) if (ok.test(ch)) out += ch;
28735
- return out;
28736
- }
28737
- function enforceScript(value, field, descriptor) {
28738
- const opt = descriptor.options;
28739
- if (!opt.script) return { value, warnings: [] };
28740
- const mode = opt.onScriptViolation ?? "reject";
28741
- const warnings = [];
28742
- let out = value;
28743
- for (const [locale, raw] of Object.entries(value)) {
28744
- if (typeof raw !== "string") continue;
28745
- const allowed = allowedFor(descriptor, locale);
28746
- if (fullMatcher(allowed).test(raw)) continue;
28747
- const sample = offendingSample(raw, allowed);
28748
- if (mode === "reject") {
28749
- throw new ScriptViolationError(field, locale, allowed, sample);
28750
- }
28751
- warnings.push({ field, locale, expected: allowed, sample });
28752
- if (mode === "filter") {
28753
- if (out === value) out = { ...value };
28754
- out[locale] = stripDisallowed(raw, allowed);
28755
- }
28756
- }
28757
- return { value: out, warnings };
28758
- }
28759
-
28760
29090
  // src/index.ts
29091
+ init_policy();
29092
+ init_script();
28761
29093
  init_errors();
28762
29094
 
28763
29095
  // src/team/sync-credentials.ts
@@ -29424,6 +29756,7 @@ function shortJSON(value) {
29424
29756
  DICT_COLLECTION_PREFIX,
29425
29757
  DIRECTORY_RECORD_ID,
29426
29758
  DanglingReferenceError,
29759
+ DataResidencyError,
29427
29760
  DecryptionError,
29428
29761
  DelegationTargetMissingError,
29429
29762
  DerivationCapExceededError,
@@ -29746,6 +30079,7 @@ function shortJSON(value) {
29746
30079
  sha256Hex,
29747
30080
  staticDict,
29748
30081
  sum,
30082
+ tokenize,
29749
30083
  transitionGuard,
29750
30084
  unwrapDeksFromBlob,
29751
30085
  unwrapDeksFromPaperEntry,