@noy-db/hub 0.2.0-pre.11 → 0.2.0-pre.13

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 (269) hide show
  1. package/README.md +126 -0
  2. package/dist/aggregate/index.cjs +289 -12
  3. package/dist/aggregate/index.cjs.map +1 -1
  4. package/dist/aggregate/index.d.cts +2 -2
  5. package/dist/aggregate/index.d.ts +2 -2
  6. package/dist/aggregate/index.js +7 -7
  7. package/dist/aggregate/index.js.map +1 -1
  8. package/dist/attestation/index.cjs.map +1 -1
  9. package/dist/attestation/index.d.cts +3 -3
  10. package/dist/attestation/index.d.ts +3 -3
  11. package/dist/attestation/index.js +6 -6
  12. package/dist/blobs/index.cjs +28 -0
  13. package/dist/blobs/index.cjs.map +1 -1
  14. package/dist/blobs/index.d.cts +4 -4
  15. package/dist/blobs/index.d.ts +4 -4
  16. package/dist/blobs/index.js +5 -5
  17. package/dist/bundle/index.cjs +2024 -69
  18. package/dist/bundle/index.cjs.map +1 -1
  19. package/dist/bundle/index.d.cts +5 -5
  20. package/dist/bundle/index.d.ts +5 -5
  21. package/dist/bundle/index.js +9 -9
  22. package/dist/{chunk-LSTBFLL2.js → chunk-3OUCWHV6.js} +2 -2
  23. package/dist/{chunk-7CEGU63S.js → chunk-3XZRRBFW.js} +2 -2
  24. package/dist/{chunk-RC6SU5NO.js → chunk-4VCQH32J.js} +2 -2
  25. package/dist/{chunk-ZROPXHJY.js → chunk-4YDZ7JPZ.js} +2 -2
  26. package/dist/{chunk-IMYKDWB4.js → chunk-5NISHSBO.js} +2 -2
  27. package/dist/{chunk-ZBBW7YQN.js → chunk-7TEI2K2A.js} +5 -5
  28. package/dist/{chunk-6T2UDBKG.js → chunk-AYNF7PVX.js} +2 -2
  29. package/dist/{chunk-QCXNMCHN.js → chunk-C3WRKABE.js} +4 -4
  30. package/dist/{chunk-GAUEWM7D.js → chunk-CWFQTAD4.js} +4 -4
  31. package/dist/{chunk-QSOYKKMD.js → chunk-D5Y3HIC6.js} +2 -2
  32. package/dist/{chunk-R233SLY3.js → chunk-E3DIBDKA.js} +2 -2
  33. package/dist/chunk-FNVFT4HZ.js +64 -0
  34. package/dist/chunk-FNVFT4HZ.js.map +1 -0
  35. package/dist/{chunk-SLV4LAKX.js → chunk-GC4V7RU7.js} +1 -1
  36. package/dist/chunk-GC4V7RU7.js.map +1 -0
  37. package/dist/{chunk-5OEJ6GOT.js → chunk-GL3Z7LH7.js} +2 -2
  38. package/dist/{chunk-YW5DBAPG.js → chunk-GZJ5JBED.js} +4 -4
  39. package/dist/{chunk-LJXYPGRH.js → chunk-HHZ77DHM.js} +3 -3
  40. package/dist/{chunk-6MFH4BMK.js → chunk-HQXOEWLZ.js} +4 -4
  41. package/dist/{chunk-RYIL3PI2.js → chunk-ILWQGTNH.js} +2 -2
  42. package/dist/{chunk-3DGHRDCX.js → chunk-J67BP5EP.js} +3 -3
  43. package/dist/{chunk-PVUUIWHY.js → chunk-JPOQMXGT.js} +10 -3
  44. package/dist/chunk-JPOQMXGT.js.map +1 -0
  45. package/dist/{chunk-RRNA5GKT.js → chunk-JWFNOD2T.js} +2 -2
  46. package/dist/{chunk-BDV7INMP.js → chunk-KHQ3N5AB.js} +4 -4
  47. package/dist/{chunk-JQ4NEJJ6.js → chunk-KJF7EPUE.js} +3 -3
  48. package/dist/{chunk-FO3UEG4S.js → chunk-KKB42D3Q.js} +2 -2
  49. package/dist/{chunk-26NK23DZ.js → chunk-M6KXHRIA.js} +3 -3
  50. package/dist/{chunk-DAP2XL7Q.js → chunk-NIUXQDWD.js} +2 -2
  51. package/dist/{chunk-6YLPHBKR.js → chunk-NJMKHRQI.js} +145 -11
  52. package/dist/chunk-NJMKHRQI.js.map +1 -0
  53. package/dist/{chunk-O6EJ6WTI.js → chunk-NKGY3C53.js} +87 -2
  54. package/dist/chunk-NKGY3C53.js.map +1 -0
  55. package/dist/{chunk-CXJG63MA.js → chunk-NP6EZT44.js} +20 -6
  56. package/dist/chunk-NP6EZT44.js.map +1 -0
  57. package/dist/{chunk-Y26YV5R3.js → chunk-O2JW656W.js} +3 -3
  58. package/dist/{chunk-MPOLUAMI.js → chunk-P5MW7BG2.js} +665 -60
  59. package/dist/chunk-P5MW7BG2.js.map +1 -0
  60. package/dist/{chunk-TGALXXLV.js → chunk-PW26DAXS.js} +3 -3
  61. package/dist/{chunk-V2PZC6AW.js → chunk-QAWCVWCX.js} +5 -5
  62. package/dist/{chunk-CH22FZHT.js → chunk-QFYVGJLI.js} +2 -2
  63. package/dist/{chunk-YM7LFCG7.js → chunk-QIVFGU2M.js} +3 -3
  64. package/dist/{chunk-CXFOITNS.js → chunk-SJ24GHID.js} +2 -2
  65. package/dist/{chunk-EBVBE7UK.js → chunk-SOU42FGB.js} +5 -5
  66. package/dist/{chunk-YVZRTCGG.js → chunk-SYSKC237.js} +6 -6
  67. package/dist/{chunk-77DWLQRY.js → chunk-TDECYU4Y.js} +31 -3
  68. package/dist/chunk-TDECYU4Y.js.map +1 -0
  69. package/dist/{chunk-73YLDCNF.js → chunk-TEQGXA7L.js} +5 -5
  70. package/dist/{chunk-PC6ZEDRL.js → chunk-UNQEWORI.js} +2 -2
  71. package/dist/{chunk-PC3ZZBTO.js → chunk-VAK6NQAK.js} +5 -5
  72. package/dist/{chunk-GKI4SDP7.js → chunk-WQKZIQIL.js} +4 -4
  73. package/dist/chunk-YWBHS25M.js +783 -0
  74. package/dist/chunk-YWBHS25M.js.map +1 -0
  75. package/dist/chunk-ZC7J6ZYV.js +7 -0
  76. package/dist/chunk-ZC7J6ZYV.js.map +1 -0
  77. package/dist/consent/index.cjs.map +1 -1
  78. package/dist/consent/index.d.cts +4 -4
  79. package/dist/consent/index.d.ts +4 -4
  80. package/dist/consent/index.js +3 -3
  81. package/dist/{crypto-2CRLG4F4.js → crypto-YXH6SAOW.js} +3 -3
  82. package/dist/{delegation-ZTRT2PRV.js → delegation-K5ERUH6A.js} +5 -5
  83. package/dist/derivations/index.cjs.map +1 -1
  84. package/dist/derivations/index.d.cts +5 -5
  85. package/dist/derivations/index.d.ts +5 -5
  86. package/dist/derivations/index.js +4 -4
  87. package/dist/{dev-unlock-BH6y3Hx0.d.ts → dev-unlock-BW0GNBEV.d.ts} +1 -1
  88. package/dist/{dev-unlock-H1Xwxc3U.d.cts → dev-unlock-a7SOtaV0.d.cts} +1 -1
  89. package/dist/executor-AVJ7UEWA.js +8 -0
  90. package/dist/executor-IQO3KGXQ.js +11 -0
  91. package/dist/executor-VT7TKGE4.js +8 -0
  92. package/dist/{fanout-sidecar-F3ZRFU4H.js → fanout-sidecar-N6OJX6QR.js} +2 -2
  93. package/dist/guards/index.cjs +53 -1
  94. package/dist/guards/index.cjs.map +1 -1
  95. package/dist/guards/index.d.cts +12 -6
  96. package/dist/guards/index.d.ts +12 -6
  97. package/dist/guards/index.js +5 -3
  98. package/dist/{hash-_sDFvtmX.d.cts → hash-B0cLQcq_.d.cts} +1 -1
  99. package/dist/{hash-D89JdDbj.d.ts → hash-uMNIAAW8.d.ts} +1 -1
  100. package/dist/history/index.cjs.map +1 -1
  101. package/dist/history/index.d.cts +5 -5
  102. package/dist/history/index.d.ts +5 -5
  103. package/dist/history/index.js +5 -5
  104. package/dist/i18n/index.cjs.map +1 -1
  105. package/dist/i18n/index.d.cts +4 -4
  106. package/dist/i18n/index.d.ts +4 -4
  107. package/dist/i18n/index.js +6 -6
  108. package/dist/immutable-guard-B0h-ipLz.d.ts +67 -0
  109. package/dist/immutable-guard-BZIcYhYX.d.cts +67 -0
  110. package/dist/index-CUVOMtgg.d.cts +1216 -0
  111. package/dist/index-Cqzp4tt9.d.ts +1216 -0
  112. package/dist/index.cjs +2200 -106
  113. package/dist/index.cjs.map +1 -1
  114. package/dist/index.d.cts +55 -13
  115. package/dist/index.d.ts +55 -13
  116. package/dist/index.js +95 -44
  117. package/dist/index.js.map +1 -1
  118. package/dist/indexing/index.cjs.map +1 -1
  119. package/dist/indexing/index.js +2 -2
  120. package/dist/issue-ZH27C23Y.js +12 -0
  121. package/dist/{ledger-NYCGJX2D.js → ledger-64TTQMRS.js} +5 -5
  122. package/dist/materialized-views/index.cjs.map +1 -1
  123. package/dist/materialized-views/index.d.cts +5 -6
  124. package/dist/materialized-views/index.d.ts +5 -6
  125. package/dist/materialized-views/index.js +6 -6
  126. package/dist/noydb-O76SKBST.js +35 -0
  127. package/dist/overlay-views/index.cjs.map +1 -1
  128. package/dist/overlay-views/index.d.cts +5 -5
  129. package/dist/overlay-views/index.d.ts +5 -5
  130. package/dist/overlay-views/index.js +4 -4
  131. package/dist/periods/index.cjs.map +1 -1
  132. package/dist/periods/index.d.cts +4 -4
  133. package/dist/periods/index.d.ts +4 -4
  134. package/dist/periods/index.js +5 -5
  135. package/dist/{public-envelope-QOXZEHKH.js → public-envelope-MHG6YVXW.js} +4 -4
  136. package/dist/query/index.cjs +382 -17
  137. package/dist/query/index.cjs.map +1 -1
  138. package/dist/query/index.d.cts +2 -2
  139. package/dist/query/index.d.ts +2 -2
  140. package/dist/query/index.js +4 -4
  141. package/dist/registry-2PKBQDCH.js +8 -0
  142. package/dist/registry-4VXFKCBJ.js +8 -0
  143. package/dist/{registry-ST2VNFZC.js → registry-PV4G3OPA.js} +3 -3
  144. package/dist/{revoke-RT7QYB4G.js → revoke-5BOLVJ3N.js} +6 -6
  145. package/dist/session/index.cjs.map +1 -1
  146. package/dist/session/index.d.cts +5 -5
  147. package/dist/session/index.d.ts +5 -5
  148. package/dist/session/index.js +3 -3
  149. package/dist/shadow/index.cjs.map +1 -1
  150. package/dist/shadow/index.d.cts +4 -4
  151. package/dist/shadow/index.d.ts +4 -4
  152. package/dist/shadow/index.js +2 -2
  153. package/dist/{signer-QNU66JF5.js → signer-GRIYBA22.js} +5 -5
  154. package/dist/snapshots/index.cjs.map +1 -1
  155. package/dist/snapshots/index.d.cts +4 -4
  156. package/dist/snapshots/index.d.ts +4 -4
  157. package/dist/snapshots/index.js +4 -4
  158. package/dist/{stale-VKXSXJF4.js → stale-LZYMMDDS.js} +2 -2
  159. package/dist/state-vault-QFJWU23A.js +147 -0
  160. package/dist/state-vault-QFJWU23A.js.map +1 -0
  161. package/dist/store/index.cjs.map +1 -1
  162. package/dist/store/index.d.cts +4 -4
  163. package/dist/store/index.d.ts +4 -4
  164. package/dist/store/index.js +2 -2
  165. package/dist/strategy-CrS7PnbE.d.cts +2048 -0
  166. package/dist/strategy-CrS7PnbE.d.ts +2048 -0
  167. package/dist/sync/index.cjs.map +1 -1
  168. package/dist/sync/index.d.cts +3 -3
  169. package/dist/sync/index.d.ts +3 -3
  170. package/dist/sync/index.js +4 -4
  171. package/dist/team/index.cjs.map +1 -1
  172. package/dist/team/index.d.cts +4 -4
  173. package/dist/team/index.d.ts +4 -4
  174. package/dist/team/index.js +8 -8
  175. package/dist/tx/index.cjs +8 -1
  176. package/dist/tx/index.cjs.map +1 -1
  177. package/dist/tx/index.d.cts +4 -4
  178. package/dist/tx/index.d.ts +4 -4
  179. package/dist/tx/index.js +3 -3
  180. package/dist/{types-DiSXn3a4.d.cts → types-CDwSSXiI.d.cts} +709 -6
  181. package/dist/{types-CD8mc8zR.d.ts → types-pax34sec.d.ts} +709 -6
  182. package/dist/{ulid-DQ1hcJvZ.d.cts → ulid-7bCSgIgb.d.cts} +1 -1
  183. package/dist/{ulid-8p83wbR4.d.ts → ulid-C_t4hL3d.d.ts} +1 -1
  184. package/dist/util/index.cjs.map +1 -1
  185. package/dist/util/index.js +1 -1
  186. package/dist/vault-group-UO4YUZOG.js +493 -0
  187. package/dist/vault-group-UO4YUZOG.js.map +1 -0
  188. package/dist/{with-derivation-DWMTpgEH.d.ts → with-derivation-BjdOxUBn.d.ts} +1 -1
  189. package/dist/{with-derivation-CVT7-dUt.d.cts → with-derivation-D8wFlb6V.d.cts} +1 -1
  190. package/dist/{with-materialized-view-BTTU3BNK.d.cts → with-materialized-view-5QMF1rS_.d.cts} +1 -1
  191. package/dist/{with-materialized-view-X0CoL8-L.d.ts → with-materialized-view-DJb-HO65.d.ts} +1 -1
  192. package/dist/{with-overlayed-view-DQjO_DSG.d.ts → with-overlayed-view-CkqTefbz.d.ts} +1 -1
  193. package/dist/{with-overlayed-view-DcacRRsS.d.cts → with-overlayed-view-DDNflPvC.d.cts} +1 -1
  194. package/package.json +3 -3
  195. package/dist/chunk-2LPPNWF6.js +0 -340
  196. package/dist/chunk-2LPPNWF6.js.map +0 -1
  197. package/dist/chunk-6YLPHBKR.js.map +0 -1
  198. package/dist/chunk-77DWLQRY.js.map +0 -1
  199. package/dist/chunk-C3WE6UJY.js +0 -19
  200. package/dist/chunk-C3WE6UJY.js.map +0 -1
  201. package/dist/chunk-CXJG63MA.js.map +0 -1
  202. package/dist/chunk-MPOLUAMI.js.map +0 -1
  203. package/dist/chunk-O6EJ6WTI.js.map +0 -1
  204. package/dist/chunk-PVUUIWHY.js.map +0 -1
  205. package/dist/chunk-SLV4LAKX.js.map +0 -1
  206. package/dist/executor-S76VN45G.js +0 -8
  207. package/dist/executor-UCXLIGLW.js +0 -11
  208. package/dist/executor-ZCNZJMGR.js +0 -8
  209. package/dist/index-B8bjExET.d.cts +0 -2434
  210. package/dist/index-DfUbNad8.d.ts +0 -2434
  211. package/dist/issue-IVTVSKWW.js +0 -12
  212. package/dist/noydb-SH4RLE47.js +0 -34
  213. package/dist/registry-UFIK7CSR.js +0 -8
  214. package/dist/registry-ZGYYSM5I.js +0 -8
  215. package/dist/strategy-CT2LCKAX.d.cts +0 -613
  216. package/dist/strategy-CT2LCKAX.d.ts +0 -613
  217. package/dist/with-guard-BRvt53da.d.ts +0 -18
  218. package/dist/with-guard-Dx2zZnTA.d.cts +0 -18
  219. /package/dist/{chunk-LSTBFLL2.js.map → chunk-3OUCWHV6.js.map} +0 -0
  220. /package/dist/{chunk-7CEGU63S.js.map → chunk-3XZRRBFW.js.map} +0 -0
  221. /package/dist/{chunk-RC6SU5NO.js.map → chunk-4VCQH32J.js.map} +0 -0
  222. /package/dist/{chunk-ZROPXHJY.js.map → chunk-4YDZ7JPZ.js.map} +0 -0
  223. /package/dist/{chunk-IMYKDWB4.js.map → chunk-5NISHSBO.js.map} +0 -0
  224. /package/dist/{chunk-ZBBW7YQN.js.map → chunk-7TEI2K2A.js.map} +0 -0
  225. /package/dist/{chunk-6T2UDBKG.js.map → chunk-AYNF7PVX.js.map} +0 -0
  226. /package/dist/{chunk-QCXNMCHN.js.map → chunk-C3WRKABE.js.map} +0 -0
  227. /package/dist/{chunk-GAUEWM7D.js.map → chunk-CWFQTAD4.js.map} +0 -0
  228. /package/dist/{chunk-QSOYKKMD.js.map → chunk-D5Y3HIC6.js.map} +0 -0
  229. /package/dist/{chunk-R233SLY3.js.map → chunk-E3DIBDKA.js.map} +0 -0
  230. /package/dist/{chunk-5OEJ6GOT.js.map → chunk-GL3Z7LH7.js.map} +0 -0
  231. /package/dist/{chunk-YW5DBAPG.js.map → chunk-GZJ5JBED.js.map} +0 -0
  232. /package/dist/{chunk-LJXYPGRH.js.map → chunk-HHZ77DHM.js.map} +0 -0
  233. /package/dist/{chunk-6MFH4BMK.js.map → chunk-HQXOEWLZ.js.map} +0 -0
  234. /package/dist/{chunk-RYIL3PI2.js.map → chunk-ILWQGTNH.js.map} +0 -0
  235. /package/dist/{chunk-3DGHRDCX.js.map → chunk-J67BP5EP.js.map} +0 -0
  236. /package/dist/{chunk-RRNA5GKT.js.map → chunk-JWFNOD2T.js.map} +0 -0
  237. /package/dist/{chunk-BDV7INMP.js.map → chunk-KHQ3N5AB.js.map} +0 -0
  238. /package/dist/{chunk-JQ4NEJJ6.js.map → chunk-KJF7EPUE.js.map} +0 -0
  239. /package/dist/{chunk-FO3UEG4S.js.map → chunk-KKB42D3Q.js.map} +0 -0
  240. /package/dist/{chunk-26NK23DZ.js.map → chunk-M6KXHRIA.js.map} +0 -0
  241. /package/dist/{chunk-DAP2XL7Q.js.map → chunk-NIUXQDWD.js.map} +0 -0
  242. /package/dist/{chunk-Y26YV5R3.js.map → chunk-O2JW656W.js.map} +0 -0
  243. /package/dist/{chunk-TGALXXLV.js.map → chunk-PW26DAXS.js.map} +0 -0
  244. /package/dist/{chunk-V2PZC6AW.js.map → chunk-QAWCVWCX.js.map} +0 -0
  245. /package/dist/{chunk-CH22FZHT.js.map → chunk-QFYVGJLI.js.map} +0 -0
  246. /package/dist/{chunk-YM7LFCG7.js.map → chunk-QIVFGU2M.js.map} +0 -0
  247. /package/dist/{chunk-CXFOITNS.js.map → chunk-SJ24GHID.js.map} +0 -0
  248. /package/dist/{chunk-EBVBE7UK.js.map → chunk-SOU42FGB.js.map} +0 -0
  249. /package/dist/{chunk-YVZRTCGG.js.map → chunk-SYSKC237.js.map} +0 -0
  250. /package/dist/{chunk-73YLDCNF.js.map → chunk-TEQGXA7L.js.map} +0 -0
  251. /package/dist/{chunk-PC6ZEDRL.js.map → chunk-UNQEWORI.js.map} +0 -0
  252. /package/dist/{chunk-PC3ZZBTO.js.map → chunk-VAK6NQAK.js.map} +0 -0
  253. /package/dist/{chunk-GKI4SDP7.js.map → chunk-WQKZIQIL.js.map} +0 -0
  254. /package/dist/{crypto-2CRLG4F4.js.map → crypto-YXH6SAOW.js.map} +0 -0
  255. /package/dist/{delegation-ZTRT2PRV.js.map → delegation-K5ERUH6A.js.map} +0 -0
  256. /package/dist/{executor-S76VN45G.js.map → executor-AVJ7UEWA.js.map} +0 -0
  257. /package/dist/{executor-UCXLIGLW.js.map → executor-IQO3KGXQ.js.map} +0 -0
  258. /package/dist/{executor-ZCNZJMGR.js.map → executor-VT7TKGE4.js.map} +0 -0
  259. /package/dist/{fanout-sidecar-F3ZRFU4H.js.map → fanout-sidecar-N6OJX6QR.js.map} +0 -0
  260. /package/dist/{issue-IVTVSKWW.js.map → issue-ZH27C23Y.js.map} +0 -0
  261. /package/dist/{ledger-NYCGJX2D.js.map → ledger-64TTQMRS.js.map} +0 -0
  262. /package/dist/{noydb-SH4RLE47.js.map → noydb-O76SKBST.js.map} +0 -0
  263. /package/dist/{public-envelope-QOXZEHKH.js.map → public-envelope-MHG6YVXW.js.map} +0 -0
  264. /package/dist/{registry-ST2VNFZC.js.map → registry-2PKBQDCH.js.map} +0 -0
  265. /package/dist/{registry-UFIK7CSR.js.map → registry-4VXFKCBJ.js.map} +0 -0
  266. /package/dist/{registry-ZGYYSM5I.js.map → registry-PV4G3OPA.js.map} +0 -0
  267. /package/dist/{revoke-RT7QYB4G.js.map → revoke-5BOLVJ3N.js.map} +0 -0
  268. /package/dist/{signer-QNU66JF5.js.map → signer-GRIYBA22.js.map} +0 -0
  269. /package/dist/{stale-VKXSXJF4.js.map → stale-LZYMMDDS.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, PeriodClosedError, RecordLockedError, FieldFrozenError, InvariantError, AmendmentForbiddenError, DirectoryDisabledError, TierNotGrantedError, ElevationExpiredError, AlreadyElevatedError, TierDemoteDeniedError, DelegationTargetMissingError, ConflictError, LedgerContentionError, BundleVersionConflictError, NetworkError, NotFoundError, ValidationError, SchemaValidationError, SchemaUpdateError, NonAdditiveSchemaChangeError, SchemaLockedError, SchemaFenceError, MigrationRequiredError, QuiesceTimeoutError, GroupCardinalityError, IndexRequiredError, UniqueConstraintError, UnsupportedIndexOptionError, IndexWriteFailureError, BundleIntegrityError, BundleSealMismatchError, ReservedCollectionNameError, DictKeyMissingError, DictKeyInUseError, MissingTranslationError, LocaleNotSpecifiedError, ScriptViolationError, 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;
49
+ var NoydbError, DecryptionError, TamperedError, InvalidKeyError, KeyringCorruptError, NoAccessError, ReadOnlyError, ReadOnlyAtInstantError, ReadOnlyFrameError, PermissionDeniedError, ExportCapabilityError, KeyringExpiredError, ImportCapabilityError, StoreCapabilityError, PrivilegeEscalationError, ReservedVaultNameError, PeriodClosedError, RecordLockedError, FieldFrozenError, 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, 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, VaultTemplateNotFoundError;
50
50
  var init_errors = __esm({
51
51
  "src/errors.ts"() {
52
52
  "use strict";
@@ -188,6 +188,18 @@ var init_errors = __esm({
188
188
  this.offendingCollection = offendingCollection;
189
189
  }
190
190
  };
191
+ ReservedVaultNameError = class extends NoydbError {
192
+ /** The rejected vault name. */
193
+ vaultName;
194
+ constructor(vaultName) {
195
+ super(
196
+ "RESERVED_VAULT_NAME",
197
+ `"${vaultName}" is a reserved internal vault name and cannot be used as a group name or partition key`
198
+ );
199
+ this.name = "ReservedVaultNameError";
200
+ this.vaultName = vaultName;
201
+ }
202
+ };
191
203
  PeriodClosedError = class extends NoydbError {
192
204
  periodName;
193
205
  endDate;
@@ -340,6 +352,39 @@ var init_errors = __esm({
340
352
  this.attempts = attempts;
341
353
  }
342
354
  };
355
+ SequenceContentionError = class extends NoydbError {
356
+ sequence;
357
+ attempts;
358
+ constructor(sequence, attempts) {
359
+ super(
360
+ "SEQUENCE_CONTENTION",
361
+ `vault.sequence("${sequence}").next(): failed to allocate after ${attempts} optimistic-CAS retries`
362
+ );
363
+ this.name = "SequenceContentionError";
364
+ this.sequence = sequence;
365
+ this.attempts = attempts;
366
+ }
367
+ };
368
+ SequenceOfflineError = class extends NoydbError {
369
+ constructor() {
370
+ super(
371
+ "SEQUENCE_OFFLINE",
372
+ "vault.sequence().next() requires an online CAS-capable store (capabilities.casAtomic). Gap-free numbering cannot be serialized offline."
373
+ );
374
+ this.name = "SequenceOfflineError";
375
+ }
376
+ };
377
+ NumberingUncertaintyError = class extends NoydbError {
378
+ series;
379
+ constructor(series) {
380
+ super(
381
+ "NUMBERING_UNCERTAINTY",
382
+ `Deferred numbering for series "${series}" cannot run: the store does not expose getStoreTime() (capabilities.serverWriteTime). Use a CAS sequence or a store with serverWriteTime.`
383
+ );
384
+ this.name = "NumberingUncertaintyError";
385
+ this.series = series;
386
+ }
387
+ };
343
388
  BundleVersionConflictError = class extends NoydbError {
344
389
  /** The bundle handle of the newer remote version that rejected the push. */
345
390
  remoteVersion;
@@ -451,14 +496,14 @@ var init_errors = __esm({
451
496
  recordId;
452
497
  fields;
453
498
  conflictingId;
454
- constructor(collection, recordId2, fields, conflictingId) {
499
+ constructor(collection, recordId3, fields, conflictingId) {
455
500
  super(
456
501
  "UNIQUE_CONSTRAINT",
457
- `Unique constraint on ${collection}.[${fields.join(", ")}] violated: record "${recordId2}" duplicates a value already held by "${conflictingId}".`
502
+ `Unique constraint on ${collection}.[${fields.join(", ")}] violated: record "${recordId3}" duplicates a value already held by "${conflictingId}".`
458
503
  );
459
504
  this.name = "UniqueConstraintError";
460
505
  this.collection = collection;
461
- this.recordId = recordId2;
506
+ this.recordId = recordId3;
462
507
  this.fields = fields;
463
508
  this.conflictingId = conflictingId;
464
509
  }
@@ -921,6 +966,39 @@ Resolutions:
921
966
  this.version = version;
922
967
  }
923
968
  };
969
+ UnknownShardError = class extends NoydbError {
970
+ partitionKey;
971
+ constructor(partitionKey, groupName) {
972
+ super(
973
+ "SHARD_UNKNOWN",
974
+ `No shard for partition key "${partitionKey}" in vault group "${groupName}" and autoCreate is disabled. Call group.createShard(${JSON.stringify(partitionKey)}) first, or enable sharding.autoCreate.`
975
+ );
976
+ this.name = "UnknownShardError";
977
+ this.partitionKey = partitionKey;
978
+ }
979
+ };
980
+ ShardProvisioningError = class extends NoydbError {
981
+ vaultId;
982
+ constructor(vaultId, partitionKey) {
983
+ super(
984
+ "SHARD_PROVISIONING",
985
+ `Registry has a row for partition "${partitionKey}" (vault "${vaultId}") but that vault is not provisioned in the store. Refusing to recreate it \u2014 the registry and store have diverged. Investigate before retrying.`
986
+ );
987
+ this.name = "ShardProvisioningError";
988
+ this.vaultId = vaultId;
989
+ }
990
+ };
991
+ VaultTemplateNotFoundError = class extends NoydbError {
992
+ templateName;
993
+ constructor(templateName) {
994
+ super(
995
+ "VAULT_TEMPLATE_NOT_FOUND",
996
+ `No vault template registered under "${templateName}". Register it with db.withVaultTemplate(${JSON.stringify(templateName)}, { version, configure }) before opening the vault group.`
997
+ );
998
+ this.name = "VaultTemplateNotFoundError";
999
+ this.templateName = templateName;
1000
+ }
1001
+ };
924
1002
  }
925
1003
  });
926
1004
 
@@ -1200,6 +1278,15 @@ var init_crypto = __esm({
1200
1278
  }
1201
1279
  });
1202
1280
 
1281
+ // src/federation/constants.ts
1282
+ var STATE_VAULT_NAME;
1283
+ var init_constants = __esm({
1284
+ "src/federation/constants.ts"() {
1285
+ "use strict";
1286
+ STATE_VAULT_NAME = "__noydb_state__";
1287
+ }
1288
+ });
1289
+
1203
1290
  // src/meta/public-envelope/schema.ts
1204
1291
  function validatePublicEnvelopeInput(input, schema) {
1205
1292
  const allowed = new Set(schema.fields);
@@ -1664,7 +1751,7 @@ var init_patch = __esm({
1664
1751
 
1665
1752
  // src/history/ledger/constants.ts
1666
1753
  var LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION;
1667
- var init_constants = __esm({
1754
+ var init_constants2 = __esm({
1668
1755
  "src/history/ledger/constants.ts"() {
1669
1756
  "use strict";
1670
1757
  LEDGER_COLLECTION = "_ledger";
@@ -1685,7 +1772,7 @@ var init_hash = __esm({
1685
1772
  });
1686
1773
 
1687
1774
  // src/history/ledger/store.ts
1688
- function sleepBackoff(attempt) {
1775
+ function sleepBackoff2(attempt) {
1689
1776
  const base = 5 * Math.pow(2, attempt);
1690
1777
  const jitter = Math.random() * base;
1691
1778
  return new Promise((resolve) => setTimeout(resolve, base + jitter));
@@ -1699,7 +1786,7 @@ var init_store = __esm({
1699
1786
  init_errors();
1700
1787
  init_entry();
1701
1788
  init_patch();
1702
- init_constants();
1789
+ init_constants2();
1703
1790
  init_hash();
1704
1791
  MAX_APPEND_ATTEMPTS = 8;
1705
1792
  LedgerStore = class {
@@ -1807,7 +1894,7 @@ var init_store = __esm({
1807
1894
  if (err instanceof ConflictError) {
1808
1895
  lastConflict = err;
1809
1896
  if (attempt < MAX_APPEND_ATTEMPTS - 1) {
1810
- await sleepBackoff(attempt);
1897
+ await sleepBackoff2(attempt);
1811
1898
  }
1812
1899
  continue;
1813
1900
  }
@@ -2221,6 +2308,278 @@ var init_public_envelope = __esm({
2221
2308
  }
2222
2309
  });
2223
2310
 
2311
+ // src/money/fixed-point.ts
2312
+ function expandExponent(s) {
2313
+ const m = /^([+-]?)(\d+)(?:\.(\d+))?[eE]([+-]?\d+)$/.exec(s);
2314
+ if (!m) return s;
2315
+ const sign = m[1] === "-" ? "-" : "";
2316
+ const intp = m[2];
2317
+ const frac = m[3] ?? "";
2318
+ const exp = Number(m[4]);
2319
+ const digits = intp + frac;
2320
+ const pointPos = intp.length + exp;
2321
+ let body;
2322
+ if (pointPos <= 0) {
2323
+ body = "0." + "0".repeat(-pointPos) + digits;
2324
+ } else if (pointPos >= digits.length) {
2325
+ body = digits + "0".repeat(pointPos - digits.length);
2326
+ } else {
2327
+ body = digits.slice(0, pointPos) + "." + digits.slice(pointPos);
2328
+ }
2329
+ return sign + body;
2330
+ }
2331
+ function toCanonicalDecimalString(input) {
2332
+ let s;
2333
+ if (typeof input === "number") {
2334
+ if (!Number.isFinite(input)) return null;
2335
+ s = String(input);
2336
+ } else {
2337
+ s = input.trim();
2338
+ }
2339
+ s = expandExponent(s);
2340
+ if (s.startsWith("+")) s = s.slice(1);
2341
+ if (!/^-?(\d+(\.\d*)?|\.\d+)$/.test(s)) return null;
2342
+ return s;
2343
+ }
2344
+ function shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, mode) {
2345
+ switch (mode) {
2346
+ case "up":
2347
+ return true;
2348
+ case "down":
2349
+ return false;
2350
+ case "ceil":
2351
+ return !negative;
2352
+ case "floor":
2353
+ return negative;
2354
+ case "half-up":
2355
+ return firstDiscarded >= 5;
2356
+ case "half-down":
2357
+ return firstDiscarded > 5 || firstDiscarded === 5 && hasMoreNonZeroAfterFirst;
2358
+ case "half-even":
2359
+ if (firstDiscarded > 5) return true;
2360
+ if (firstDiscarded < 5) return false;
2361
+ return hasMoreNonZeroAfterFirst || lastKeptDigit % 2 === 1;
2362
+ }
2363
+ }
2364
+ function parseToScaledInt(input, scale, rounding) {
2365
+ const canonical2 = toCanonicalDecimalString(input);
2366
+ if (canonical2 === null) return { ok: false, reason: "nonfinite" };
2367
+ const negative = canonical2.startsWith("-");
2368
+ const unsigned = negative ? canonical2.slice(1) : canonical2;
2369
+ const dot = unsigned.indexOf(".");
2370
+ const intPart = dot === -1 ? unsigned : unsigned.slice(0, dot);
2371
+ const fracPart = dot === -1 ? "" : unsigned.slice(dot + 1);
2372
+ const intDigits = intPart === "" ? "0" : intPart;
2373
+ if (fracPart.length <= scale) {
2374
+ const keep2 = fracPart.padEnd(scale, "0");
2375
+ const magnitude2 = BigInt(intDigits + keep2);
2376
+ return { ok: true, value: negative && magnitude2 !== 0n ? -magnitude2 : magnitude2 };
2377
+ }
2378
+ const keep = fracPart.slice(0, scale);
2379
+ const tail = fracPart.slice(scale);
2380
+ const magnitudeDigits = intDigits + keep;
2381
+ let magnitude = BigInt(magnitudeDigits);
2382
+ if (/^0+$/.test(tail)) {
2383
+ return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
2384
+ }
2385
+ if (rounding === void 0) return { ok: false, reason: "precision" };
2386
+ const lastKeptDigit = Number(magnitudeDigits[magnitudeDigits.length - 1]);
2387
+ const firstDiscarded = Number(tail[0]);
2388
+ const hasMoreNonZeroAfterFirst = /[1-9]/.test(tail.slice(1));
2389
+ if (shouldRoundUp(negative, lastKeptDigit, firstDiscarded, hasMoreNonZeroAfterFirst, rounding)) {
2390
+ magnitude += 1n;
2391
+ }
2392
+ return { ok: true, value: negative && magnitude !== 0n ? -magnitude : magnitude };
2393
+ }
2394
+ function formatScaledInt(value, scale) {
2395
+ const negative = value < 0n;
2396
+ const abs = (negative ? -value : value).toString();
2397
+ if (scale === 0) return (negative ? "-" : "") + abs;
2398
+ const padded = abs.padStart(scale + 1, "0");
2399
+ const cut = padded.length - scale;
2400
+ const intPart = padded.slice(0, cut);
2401
+ const fracPart = padded.slice(cut);
2402
+ return (negative ? "-" : "") + intPart + "." + fracPart;
2403
+ }
2404
+ var init_fixed_point = __esm({
2405
+ "src/money/fixed-point.ts"() {
2406
+ "use strict";
2407
+ }
2408
+ });
2409
+
2410
+ // src/money/iso4217.ts
2411
+ function scaleForCurrency(code) {
2412
+ const v = MINOR_UNITS[code];
2413
+ return v === void 0 ? null : v;
2414
+ }
2415
+ var MINOR_UNITS;
2416
+ var init_iso4217 = __esm({
2417
+ "src/money/iso4217.ts"() {
2418
+ "use strict";
2419
+ MINOR_UNITS = {
2420
+ // 2-decimal majors
2421
+ EUR: 2,
2422
+ USD: 2,
2423
+ GBP: 2,
2424
+ CHF: 2,
2425
+ CAD: 2,
2426
+ AUD: 2,
2427
+ NZD: 2,
2428
+ SGD: 2,
2429
+ HKD: 2,
2430
+ CNY: 2,
2431
+ INR: 2,
2432
+ BRL: 2,
2433
+ MXN: 2,
2434
+ ZAR: 2,
2435
+ RUB: 2,
2436
+ TRY: 2,
2437
+ PLN: 2,
2438
+ SEK: 2,
2439
+ NOK: 2,
2440
+ DKK: 2,
2441
+ CZK: 2,
2442
+ HUF: 2,
2443
+ RON: 2,
2444
+ ILS: 2,
2445
+ THB: 2,
2446
+ PHP: 2,
2447
+ MYR: 2,
2448
+ IDR: 2,
2449
+ AED: 2,
2450
+ SAR: 2,
2451
+ QAR: 2,
2452
+ EGP: 2,
2453
+ // 0-decimal
2454
+ JPY: 0,
2455
+ KRW: 0,
2456
+ ISK: 0,
2457
+ CLP: 0,
2458
+ VND: 0,
2459
+ XOF: 0,
2460
+ XAF: 0,
2461
+ PYG: 0,
2462
+ // 3-decimal
2463
+ BHD: 3,
2464
+ KWD: 3,
2465
+ OMR: 3,
2466
+ TND: 3,
2467
+ JOD: 3,
2468
+ IQD: 3,
2469
+ LYD: 3
2470
+ };
2471
+ }
2472
+ });
2473
+
2474
+ // src/money/descriptor.ts
2475
+ function isMultiOptions(o) {
2476
+ return "currencies" in o;
2477
+ }
2478
+ function money(options) {
2479
+ const hasFixed = "currency" in options;
2480
+ const hasMulti = "currencies" in options;
2481
+ if (hasFixed && hasMulti) {
2482
+ throw new TypeError("money: `currency` and `currencies` are mutually exclusive");
2483
+ }
2484
+ if (!hasFixed && !hasMulti) {
2485
+ throw new TypeError("money: one of `currency` or `currencies` is required");
2486
+ }
2487
+ const rounding = options.rounding;
2488
+ if (isMultiOptions(options)) {
2489
+ const overrides = options.scaleOverrides ?? {};
2490
+ const allowList = options.currencies;
2491
+ const allows = (c) => allowList === "any" ? true : allowList.includes(c);
2492
+ const scaleFor = (c) => {
2493
+ if (!allows(c)) throw new MoneyCurrencyError(c, "not-allowed");
2494
+ const s = overrides[c] ?? scaleForCurrency(c);
2495
+ if (s === null || s === void 0) throw new MoneyCurrencyError(c, "unknown-scale");
2496
+ return s;
2497
+ };
2498
+ if (allowList !== "any") for (const c of allowList) scaleFor(c);
2499
+ const soleCurrency = () => allowList !== "any" && allowList.length === 1 ? allowList[0] : void 0;
2500
+ return {
2501
+ _noydbMoney: true,
2502
+ mode: "multi",
2503
+ options,
2504
+ rounding,
2505
+ fixedCurrency: void 0,
2506
+ scaleFor,
2507
+ allows,
2508
+ soleCurrency
2509
+ };
2510
+ }
2511
+ const currency = options.currency;
2512
+ const resolvedScale = options.scale ?? scaleForCurrency(currency);
2513
+ if (resolvedScale === null || resolvedScale === void 0) {
2514
+ throw new MoneyCurrencyError(currency, "unknown-scale");
2515
+ }
2516
+ return {
2517
+ _noydbMoney: true,
2518
+ mode: "fixed",
2519
+ options,
2520
+ rounding,
2521
+ fixedCurrency: currency,
2522
+ scaleFor(c) {
2523
+ if (c !== currency) throw new MoneyCurrencyError(c, "not-allowed");
2524
+ return resolvedScale;
2525
+ },
2526
+ allows: (c) => c === currency,
2527
+ soleCurrency: () => currency
2528
+ };
2529
+ }
2530
+ function isMoneyDescriptor(x) {
2531
+ return typeof x === "object" && x !== null && x._noydbMoney === true;
2532
+ }
2533
+ var MoneyPrecisionError, MoneyCurrencyError, MoneyUnsupportedError;
2534
+ var init_descriptor = __esm({
2535
+ "src/money/descriptor.ts"() {
2536
+ "use strict";
2537
+ init_iso4217();
2538
+ init_errors();
2539
+ MoneyPrecisionError = class extends NoydbError {
2540
+ constructor(field, value, scale) {
2541
+ super(
2542
+ "MONEY_PRECISION",
2543
+ `money: value ${JSON.stringify(value)} for field "${field}" exceeds scale ${scale} and no rounding mode is configured`
2544
+ );
2545
+ this.field = field;
2546
+ this.value = value;
2547
+ this.scale = scale;
2548
+ this.name = "MoneyPrecisionError";
2549
+ }
2550
+ field;
2551
+ value;
2552
+ scale;
2553
+ };
2554
+ MoneyCurrencyError = class extends NoydbError {
2555
+ constructor(currency, reason, field) {
2556
+ super(
2557
+ "MONEY_CURRENCY",
2558
+ reason === "not-allowed" ? `money: currency "${currency}" is not allowed${field ? ` for field "${field}"` : ""}` : `money: no scale known for currency "${currency}"${field ? ` (field "${field}")` : ""} \u2014 pass an explicit scale / scaleOverrides`
2559
+ );
2560
+ this.currency = currency;
2561
+ this.reason = reason;
2562
+ this.field = field;
2563
+ this.name = "MoneyCurrencyError";
2564
+ }
2565
+ currency;
2566
+ reason;
2567
+ field;
2568
+ };
2569
+ MoneyUnsupportedError = class extends NoydbError {
2570
+ constructor(field, message) {
2571
+ super(
2572
+ "MONEY_UNSUPPORTED",
2573
+ message ?? `money: operation is not supported on field "${field}" \u2014 use sum() and count() and divide at the boundary`
2574
+ );
2575
+ this.field = field;
2576
+ this.name = "MoneyUnsupportedError";
2577
+ }
2578
+ field;
2579
+ };
2580
+ }
2581
+ });
2582
+
2224
2583
  // src/team/tiers.ts
2225
2584
  function dekKey(collection, tier) {
2226
2585
  if (tier <= 0) return collection;
@@ -2340,6 +2699,189 @@ var init_predicate = __esm({
2340
2699
  }
2341
2700
  });
2342
2701
 
2702
+ // src/money/money-reducer.ts
2703
+ function toScaledInt(v) {
2704
+ if (typeof v === "string" || typeof v === "number" || typeof v === "bigint") {
2705
+ try {
2706
+ return BigInt(v);
2707
+ } catch {
2708
+ return null;
2709
+ }
2710
+ }
2711
+ return null;
2712
+ }
2713
+ function readMoney(record, field, desc) {
2714
+ const raw = readPath(record, field);
2715
+ if (raw === null || raw === void 0) return null;
2716
+ if (desc.mode === "fixed") {
2717
+ const value2 = toScaledInt(raw);
2718
+ return value2 === null ? null : { currency: desc.fixedCurrency, value: value2 };
2719
+ }
2720
+ if (typeof raw !== "object") return null;
2721
+ const o = raw;
2722
+ if (typeof o.currency !== "string") return null;
2723
+ const value = toScaledInt(o.amount);
2724
+ return value === null ? null : { currency: o.currency, value };
2725
+ }
2726
+ function targetScaleFor(desc, currency) {
2727
+ if (desc.allows(currency)) return desc.scaleFor(currency);
2728
+ const s = scaleForCurrency(currency);
2729
+ if (s === null) {
2730
+ throw new Error(`money: cannot determine scale for conversion target "${currency}"`);
2731
+ }
2732
+ return s;
2733
+ }
2734
+ function parseRate(rate) {
2735
+ const s = String(rate).trim();
2736
+ const neg = s.startsWith("-");
2737
+ const body = neg ? s.slice(1) : s;
2738
+ const dot = body.indexOf(".");
2739
+ const intPart = dot === -1 ? body : body.slice(0, dot);
2740
+ const fracPart = dot === -1 ? "" : body.slice(dot + 1);
2741
+ const int = BigInt((intPart === "" ? "0" : intPart) + fracPart);
2742
+ return { int: neg ? -int : int, scale: fracPart.length };
2743
+ }
2744
+ function divRoundHalfEven(n, d) {
2745
+ const q = n / d;
2746
+ const r = n % d;
2747
+ const twiceR = (r < 0n ? -r : r) * 2n;
2748
+ if (twiceR < d) return q;
2749
+ if (twiceR > d) return q + (n < 0n ? -1n : 1n);
2750
+ return q % 2n === 0n ? q : q + (n < 0n ? -1n : 1n);
2751
+ }
2752
+ function convertScaled(value, srcScale, rate, targetScale) {
2753
+ const { int: rateInt, scale: rateScale } = parseRate(rate);
2754
+ const product = value * rateInt;
2755
+ const curScale = srcScale + rateScale;
2756
+ if (curScale === targetScale) return product;
2757
+ if (curScale < targetScale) return product * 10n ** BigInt(targetScale - curScale);
2758
+ return divRoundHalfEven(product, 10n ** BigInt(curScale - targetScale));
2759
+ }
2760
+ function finalizeSum(state, desc, convertTo, fx) {
2761
+ if (convertTo !== void 0) {
2762
+ if (fx === void 0) {
2763
+ throw new Error(`money: sum convertTo "${convertTo}" requires an fx rate map`);
2764
+ }
2765
+ const targetScale = targetScaleFor(desc, convertTo);
2766
+ let total = 0n;
2767
+ for (const [cur, v] of state) {
2768
+ if (cur === convertTo) {
2769
+ total += convertScaled(v, desc.scaleFor(cur), 1, targetScale);
2770
+ continue;
2771
+ }
2772
+ const rate = fx[`${cur}->${convertTo}`];
2773
+ if (rate === void 0) {
2774
+ throw new Error(`money: no fx rate for "${cur}->${convertTo}"`);
2775
+ }
2776
+ total += convertScaled(v, desc.scaleFor(cur), rate, targetScale);
2777
+ }
2778
+ return formatScaledInt(total, targetScale);
2779
+ }
2780
+ if (desc.mode === "fixed") {
2781
+ const cur = desc.fixedCurrency;
2782
+ return formatScaledInt(state.get(cur) ?? 0n, desc.scaleFor(cur));
2783
+ }
2784
+ const out = {};
2785
+ for (const [cur, v] of state) out[cur] = formatScaledInt(v, desc.scaleFor(cur));
2786
+ return out;
2787
+ }
2788
+ function moneySumReducer(field, desc, convertTo, fx) {
2789
+ return {
2790
+ op: "sum",
2791
+ field,
2792
+ init: () => /* @__PURE__ */ new Map(),
2793
+ step: (state, record) => {
2794
+ const m = readMoney(record, field, desc);
2795
+ if (m) state.set(m.currency, (state.get(m.currency) ?? 0n) + m.value);
2796
+ return state;
2797
+ },
2798
+ remove: (state, record) => {
2799
+ const m = readMoney(record, field, desc);
2800
+ if (m) state.set(m.currency, (state.get(m.currency) ?? 0n) - m.value);
2801
+ return state;
2802
+ },
2803
+ finalize: (state) => finalizeSum(state, desc, convertTo, fx)
2804
+ };
2805
+ }
2806
+ function extremum(values, op) {
2807
+ let out = values[0];
2808
+ for (let i = 1; i < values.length; i++) {
2809
+ const v = values[i];
2810
+ if (op === "min" ? v < out : v > out) out = v;
2811
+ }
2812
+ return out;
2813
+ }
2814
+ function moneyMinMaxReducer(op, field, desc) {
2815
+ return {
2816
+ op,
2817
+ field,
2818
+ init: () => /* @__PURE__ */ new Map(),
2819
+ step: (state, record) => {
2820
+ const m = readMoney(record, field, desc);
2821
+ if (m) {
2822
+ const arr = state.get(m.currency);
2823
+ if (arr) arr.push(m.value);
2824
+ else state.set(m.currency, [m.value]);
2825
+ }
2826
+ return state;
2827
+ },
2828
+ remove: (state, record) => {
2829
+ const m = readMoney(record, field, desc);
2830
+ if (m) {
2831
+ const arr = state.get(m.currency);
2832
+ if (arr) {
2833
+ const idx = arr.indexOf(m.value);
2834
+ if (idx >= 0) arr.splice(idx, 1);
2835
+ }
2836
+ }
2837
+ return state;
2838
+ },
2839
+ finalize: (state) => {
2840
+ if (desc.mode === "fixed") {
2841
+ const cur = desc.fixedCurrency;
2842
+ const arr = state.get(cur);
2843
+ if (!arr || arr.length === 0) return null;
2844
+ return formatScaledInt(extremum(arr, op), desc.scaleFor(cur));
2845
+ }
2846
+ const out = {};
2847
+ for (const [cur, arr] of state) {
2848
+ if (arr.length > 0) out[cur] = formatScaledInt(extremum(arr, op), desc.scaleFor(cur));
2849
+ }
2850
+ return out;
2851
+ }
2852
+ };
2853
+ }
2854
+ function wrapMoneyReducers(spec, moneyFields) {
2855
+ let changed = false;
2856
+ const out = {};
2857
+ for (const [key, reducer] of Object.entries(spec)) {
2858
+ const field = reducer.field;
2859
+ const desc = field ? moneyFields[field] : void 0;
2860
+ if (desc && reducer.op === "avg") {
2861
+ throw new MoneyUnsupportedError(
2862
+ field,
2863
+ `avg() is not supported on money field "${field}" in v1 \u2014 use sum() and count() and divide at the boundary.`
2864
+ );
2865
+ }
2866
+ if (desc && (reducer.op === "sum" || reducer.op === "min" || reducer.op === "max")) {
2867
+ changed = true;
2868
+ out[key] = reducer.op === "sum" ? moneySumReducer(field, desc, reducer.convertTo, reducer.fx) : moneyMinMaxReducer(reducer.op, field, desc);
2869
+ } else {
2870
+ out[key] = reducer;
2871
+ }
2872
+ }
2873
+ return changed ? out : spec;
2874
+ }
2875
+ var init_money_reducer = __esm({
2876
+ "src/money/money-reducer.ts"() {
2877
+ "use strict";
2878
+ init_predicate();
2879
+ init_fixed_point();
2880
+ init_iso4217();
2881
+ init_descriptor();
2882
+ }
2883
+ });
2884
+
2343
2885
  // src/aggregate/aggregation.ts
2344
2886
  function reduceRecords(records, spec) {
2345
2887
  const state = {};
@@ -2557,19 +3099,22 @@ var init_groupby = __esm({
2557
3099
  init_aggregation();
2558
3100
  init_canonical_key();
2559
3101
  init_errors();
3102
+ init_money_reducer();
2560
3103
  GROUPBY_WARN_CARDINALITY = 1e4;
2561
3104
  GROUPBY_MAX_CARDINALITY = 1e5;
2562
3105
  warnedCardinalityFields = /* @__PURE__ */ new Set();
2563
3106
  GroupedQueryBase = class {
2564
- constructor(executeRecords, fieldOrFields, upstreams, dictLabelResolver) {
3107
+ constructor(executeRecords, fieldOrFields, upstreams, dictLabelResolver, moneyFields) {
2565
3108
  this.executeRecords = executeRecords;
2566
3109
  this.upstreams = upstreams;
2567
3110
  this.dictLabelResolver = dictLabelResolver;
3111
+ this.moneyFields = moneyFields;
2568
3112
  this.fields = typeof fieldOrFields === "string" ? [fieldOrFields] : [...fieldOrFields];
2569
3113
  }
2570
3114
  executeRecords;
2571
3115
  upstreams;
2572
3116
  dictLabelResolver;
3117
+ moneyFields;
2573
3118
  /**
2574
3119
  * Field set this grouped query buckets on. Stored in declaration
2575
3120
  * order — the same order is preserved on every result row by
@@ -2577,6 +3122,10 @@ var init_groupby = __esm({
2577
3122
  * `[field]`.
2578
3123
  */
2579
3124
  fields;
3125
+ /** Apply money-aware reducer rewriting when money fields are declared. */
3126
+ wrapSpec(spec) {
3127
+ return this.moneyFields ? wrapMoneyReducers(spec, this.moneyFields) : spec;
3128
+ }
2580
3129
  };
2581
3130
  GroupedQuery = class extends GroupedQueryBase {
2582
3131
  /**
@@ -2589,7 +3138,7 @@ var init_groupby = __esm({
2589
3138
  return new GroupedAggregation(
2590
3139
  this.executeRecords,
2591
3140
  this.fields,
2592
- spec,
3141
+ this.wrapSpec(spec),
2593
3142
  this.upstreams,
2594
3143
  this.dictLabelResolver
2595
3144
  );
@@ -2600,7 +3149,7 @@ var init_groupby = __esm({
2600
3149
  return new GroupedAggregation(
2601
3150
  this.executeRecords,
2602
3151
  this.fields,
2603
- spec,
3152
+ this.wrapSpec(spec),
2604
3153
  this.upstreams,
2605
3154
  this.dictLabelResolver
2606
3155
  );
@@ -2716,14 +3265,21 @@ var init_executor = __esm({
2716
3265
  * Compare existing vs incoming for each `frozenFields.fields` entry
2717
3266
  * when `frozenFields.when(existing)` is true. Throws
2718
3267
  * `FieldFrozenError` listing every changed frozen field.
3268
+ *
3269
+ * @param skipFields — field names that are schema-owned computed fields.
3270
+ * These are excluded from the comparison because `incoming` carries the
3271
+ * raw user input (computed fields not yet evaluated), so comparing
3272
+ * `existing[field]` vs `incoming[field]` would always look like a
3273
+ * change even when the computed result is unchanged.
2719
3274
  */
2720
- async checkFrozenFields(guard, id, existing, incoming) {
3275
+ async checkFrozenFields(guard, id, existing, incoming, skipFields) {
2721
3276
  const ff = guard.frozenFields;
2722
3277
  if (!ff) return;
2723
3278
  if (existing === null) return;
2724
3279
  if (!ff.when(existing)) return;
2725
3280
  const changed = [];
2726
3281
  for (const f of ff.fields) {
3282
+ if (skipFields?.has(String(f))) continue;
2727
3283
  if (existing[f] !== incoming[f]) {
2728
3284
  if (!deepEqual2(existing[f], incoming[f])) changed.push(String(f));
2729
3285
  }
@@ -2942,12 +3498,12 @@ var init_dependency_analyzer = __esm({
2942
3498
 
2943
3499
  // src/materialized-views/query-hash.ts
2944
3500
  async function computeQueryHash(mvName, dependencies, queryPlanSummary) {
2945
- const canonical = JSON.stringify({
3501
+ const canonical2 = JSON.stringify({
2946
3502
  mvName,
2947
3503
  dependencies: [...dependencies].sort(),
2948
3504
  queryPlanSummary
2949
3505
  });
2950
- const bytes = new TextEncoder().encode(canonical);
3506
+ const bytes = new TextEncoder().encode(canonical2);
2951
3507
  const digest = await crypto.subtle.digest("SHA-256", bytes);
2952
3508
  return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
2953
3509
  }
@@ -3786,12 +4342,12 @@ var init_read_only_facade = __esm({
3786
4342
 
3787
4343
  // src/derivations/strategy-hash.ts
3788
4344
  async function computeStrategyHash(source, outputKeys, derive) {
3789
- const canonical = JSON.stringify({
4345
+ const canonical2 = JSON.stringify({
3790
4346
  source,
3791
4347
  outputs: [...outputKeys].sort(),
3792
4348
  derive: derive.toString()
3793
4349
  });
3794
- const bytes = new TextEncoder().encode(canonical);
4350
+ const bytes = new TextEncoder().encode(canonical2);
3795
4351
  const digest = await crypto.subtle.digest("SHA-256", bytes);
3796
4352
  return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
3797
4353
  }
@@ -4052,6 +4608,669 @@ var init_delegation = __esm({
4052
4608
  }
4053
4609
  });
4054
4610
 
4611
+ // src/federation/classify-skip.ts
4612
+ function classifyShardSkip(err) {
4613
+ return err instanceof NoAccessError ? "no-grant" : "error";
4614
+ }
4615
+ var init_classify_skip = __esm({
4616
+ "src/federation/classify-skip.ts"() {
4617
+ "use strict";
4618
+ init_errors();
4619
+ }
4620
+ });
4621
+
4622
+ // src/federation/cross-vault-live.ts
4623
+ var CrossVaultLive;
4624
+ var init_cross_vault_live = __esm({
4625
+ "src/federation/cross-vault-live.ts"() {
4626
+ "use strict";
4627
+ CrossVaultLive = class {
4628
+ snapshot;
4629
+ error = null;
4630
+ ready;
4631
+ subs = /* @__PURE__ */ new Set();
4632
+ unsubChange;
4633
+ opts;
4634
+ stopped = false;
4635
+ computing = false;
4636
+ dirty = false;
4637
+ scheduled = false;
4638
+ timer = null;
4639
+ resolveReady;
4640
+ settledOnce = false;
4641
+ constructor(opts) {
4642
+ this.opts = opts;
4643
+ this.snapshot = opts.initialSnapshot;
4644
+ this.ready = new Promise((res) => {
4645
+ this.resolveReady = res;
4646
+ });
4647
+ this.unsubChange = opts.subscribeToChanges((e) => {
4648
+ if (this.stopped || !opts.isRelevant(e)) return;
4649
+ this.schedule();
4650
+ });
4651
+ this.schedule();
4652
+ }
4653
+ subscribe(cb) {
4654
+ if (this.stopped) return () => {
4655
+ };
4656
+ this.subs.add(cb);
4657
+ return () => this.subs.delete(cb);
4658
+ }
4659
+ stop() {
4660
+ if (this.stopped) return;
4661
+ this.stopped = true;
4662
+ this.unsubChange();
4663
+ if (this.timer !== null) clearTimeout(this.timer);
4664
+ this.subs.clear();
4665
+ if (!this.settledOnce) this.resolveReady();
4666
+ }
4667
+ schedule() {
4668
+ if (this.stopped) return;
4669
+ if (this.computing) {
4670
+ this.dirty = true;
4671
+ return;
4672
+ }
4673
+ if (this.scheduled) return;
4674
+ this.scheduled = true;
4675
+ const run = () => {
4676
+ this.scheduled = false;
4677
+ void this.runCompute();
4678
+ };
4679
+ const ms = this.opts.debounceMs ?? 0;
4680
+ if (ms > 0) this.timer = setTimeout(run, ms);
4681
+ else queueMicrotask(run);
4682
+ }
4683
+ async runCompute() {
4684
+ if (this.stopped) return;
4685
+ this.computing = true;
4686
+ this.dirty = false;
4687
+ try {
4688
+ const next = await this.opts.compute();
4689
+ if (this.stopped) return;
4690
+ this.snapshot = next;
4691
+ this.error = null;
4692
+ } catch (err) {
4693
+ if (this.stopped) return;
4694
+ this.error = err instanceof Error ? err : new Error(String(err));
4695
+ } finally {
4696
+ this.computing = false;
4697
+ if (!this.stopped) {
4698
+ if (!this.settledOnce) {
4699
+ this.settledOnce = true;
4700
+ this.resolveReady();
4701
+ }
4702
+ for (const cb of this.subs) cb();
4703
+ if (this.dirty) this.schedule();
4704
+ }
4705
+ }
4706
+ }
4707
+ };
4708
+ }
4709
+ });
4710
+
4711
+ // src/federation/aggregate-across.ts
4712
+ var CrossVaultAggregation, CrossVaultGroupedAggregation;
4713
+ var init_aggregate_across = __esm({
4714
+ "src/federation/aggregate-across.ts"() {
4715
+ "use strict";
4716
+ init_aggregation();
4717
+ init_groupby();
4718
+ init_cross_vault_live();
4719
+ CrossVaultAggregation = class {
4720
+ constructor(src, spec, bind) {
4721
+ this.src = src;
4722
+ this.spec = spec;
4723
+ this.bind = bind;
4724
+ }
4725
+ src;
4726
+ spec;
4727
+ bind;
4728
+ async run(options = {}) {
4729
+ const { records, skippedVaults } = await this.src.fanoutRecords(options);
4730
+ return { result: reduceRecords(records, this.spec), skippedVaults };
4731
+ }
4732
+ live(options = {}) {
4733
+ if (!this.bind) throw new Error("CrossVaultAggregation: live() requires a LiveBinding \u2014 use ShardedQuery.aggregate()");
4734
+ const spec = this.spec;
4735
+ const src = this.src;
4736
+ const core = new CrossVaultLive({
4737
+ subscribeToChanges: this.bind.subscribeToChanges,
4738
+ isRelevant: this.bind.isRelevant,
4739
+ compute: async () => {
4740
+ const { records, skippedVaults } = await src.fanoutRecords(options);
4741
+ return { value: reduceRecords(records, spec), skipped: skippedVaults };
4742
+ },
4743
+ initialSnapshot: { value: void 0, skipped: [] },
4744
+ ...options.debounceMs !== void 0 ? { debounceMs: options.debounceMs } : {}
4745
+ });
4746
+ return {
4747
+ get value() {
4748
+ return core.snapshot.value;
4749
+ },
4750
+ get skippedVaults() {
4751
+ return core.snapshot.skipped;
4752
+ },
4753
+ get error() {
4754
+ return core.error;
4755
+ },
4756
+ ready: core.ready,
4757
+ subscribe: (cb) => core.subscribe(cb),
4758
+ stop: () => core.stop()
4759
+ };
4760
+ }
4761
+ };
4762
+ CrossVaultGroupedAggregation = class {
4763
+ constructor(src, field, spec, bind) {
4764
+ this.src = src;
4765
+ this.field = field;
4766
+ this.spec = spec;
4767
+ this.bind = bind;
4768
+ }
4769
+ src;
4770
+ field;
4771
+ spec;
4772
+ bind;
4773
+ async run(options = {}) {
4774
+ const { records, skippedVaults } = await this.src.fanoutRecords(options);
4775
+ return {
4776
+ results: groupAndReduce(records, this.field, this.spec),
4777
+ skippedVaults
4778
+ };
4779
+ }
4780
+ live(options = {}) {
4781
+ if (!this.bind) throw new Error("CrossVaultGroupedAggregation: live() requires a LiveBinding \u2014 use ShardedQuery.groupBy().aggregate()");
4782
+ const field = this.field;
4783
+ const spec = this.spec;
4784
+ const src = this.src;
4785
+ const core = new CrossVaultLive({
4786
+ subscribeToChanges: this.bind.subscribeToChanges,
4787
+ isRelevant: this.bind.isRelevant,
4788
+ compute: async () => {
4789
+ const { records, skippedVaults } = await src.fanoutRecords(options);
4790
+ return {
4791
+ records: groupAndReduce(records, field, spec),
4792
+ skipped: skippedVaults
4793
+ };
4794
+ },
4795
+ initialSnapshot: { records: [], skipped: [] },
4796
+ ...options.debounceMs !== void 0 ? { debounceMs: options.debounceMs } : {}
4797
+ });
4798
+ return {
4799
+ get value() {
4800
+ return core.snapshot.records;
4801
+ },
4802
+ get skippedVaults() {
4803
+ return core.snapshot.skipped;
4804
+ },
4805
+ get error() {
4806
+ return core.error;
4807
+ },
4808
+ ready: core.ready,
4809
+ subscribe: (cb) => core.subscribe(cb),
4810
+ stop: () => core.stop()
4811
+ };
4812
+ }
4813
+ };
4814
+ }
4815
+ });
4816
+
4817
+ // src/federation/vault-group.ts
4818
+ var vault_group_exports = {};
4819
+ __export(vault_group_exports, {
4820
+ ShardedCollection: () => ShardedCollection,
4821
+ ShardedGroupedQuery: () => ShardedGroupedQuery,
4822
+ ShardedQuery: () => ShardedQuery,
4823
+ VaultGroup: () => VaultGroup
4824
+ });
4825
+ function assertSafePartitionKey(partitionKey) {
4826
+ if (partitionKey.length === 0) {
4827
+ throw new ValidationError("partitionKey must be a non-empty string");
4828
+ }
4829
+ if (partitionKey === STATE_VAULT_NAME) {
4830
+ throw new ReservedVaultNameError(partitionKey);
4831
+ }
4832
+ if (!SAFE_PARTITION_KEY.test(partitionKey)) {
4833
+ throw new ValidationError(
4834
+ `partitionKey "${partitionKey}" contains characters outside [A-Za-z0-9._-]. Map your records to a store-safe key in sharding.keyOf.`
4835
+ );
4836
+ }
4837
+ if (partitionKey.includes(SHARD_SEPARATOR)) {
4838
+ throw new ValidationError(
4839
+ `partitionKey "${partitionKey}" must not contain "--" \u2014 it is reserved as the shard vault-id separator and would risk shard-id collisions.`
4840
+ );
4841
+ }
4842
+ }
4843
+ var SHARD_SEPARATOR, SAFE_PARTITION_KEY, VaultGroup, ShardedCollection, ShardedQuery, ShardedGroupedQuery;
4844
+ var init_vault_group = __esm({
4845
+ "src/federation/vault-group.ts"() {
4846
+ "use strict";
4847
+ init_errors();
4848
+ init_constants();
4849
+ init_classify_skip();
4850
+ init_cross_vault_live();
4851
+ init_aggregate_across();
4852
+ SHARD_SEPARATOR = "--";
4853
+ SAFE_PARTITION_KEY = /^[A-Za-z0-9._-]+$/;
4854
+ VaultGroup = class {
4855
+ constructor(db, name, registry, sharding, template) {
4856
+ this.db = db;
4857
+ this.name = name;
4858
+ this.registry = registry;
4859
+ this.sharding = sharding;
4860
+ this.template = template;
4861
+ if (name.includes(SHARD_SEPARATOR)) {
4862
+ throw new ValidationError(
4863
+ `VaultGroup name "${name}" must not contain "--" (reserved shard vault-id separator).`
4864
+ );
4865
+ }
4866
+ }
4867
+ db;
4868
+ name;
4869
+ registry;
4870
+ sharding;
4871
+ template;
4872
+ /** @internal — set when the group is managed (no explicit registry). */
4873
+ stateVault;
4874
+ /** @internal */
4875
+ _attachStateVault(sv) {
4876
+ this.stateVault = sv;
4877
+ }
4878
+ /** Deterministic vault name for a partition key, namespaced by the group. */
4879
+ shardVaultId(partitionKey) {
4880
+ assertSafePartitionKey(partitionKey);
4881
+ return `${this.name}${SHARD_SEPARATOR}${partitionKey}`;
4882
+ }
4883
+ /**
4884
+ * @internal — group-qualified registry record key (avoids cross-group key
4885
+ * collisions). Identical to the shard vault id by design — the registry row
4886
+ * for a shard is keyed by that shard's vault id — so it delegates to
4887
+ * `shardVaultId`, reusing its partition-key validation.
4888
+ */
4889
+ registryId(partitionKey) {
4890
+ return this.shardVaultId(partitionKey);
4891
+ }
4892
+ /**
4893
+ * Registry rows for THIS group (hydrates the registry collection first).
4894
+ * The registry may be shared across groups (the auto-wired StateManagement
4895
+ * vault holds one `vaultRegistry` for the whole instance), so rows are
4896
+ * filtered by `group` — without this, a group's fan-out reads would leak
4897
+ * across into other groups' shards. Mirrors the `${group}--` scoping that
4898
+ * `liveBinding().isRelevant` already applies to the reactive path.
4899
+ */
4900
+ async allRows() {
4901
+ await this.registry.list();
4902
+ const rows = this.registry.query().toArray();
4903
+ return rows.filter((r) => r.group === this.name);
4904
+ }
4905
+ /** Open an existing shard and apply the template. */
4906
+ async openShard(partitionKey) {
4907
+ const vault = await this.db.openVault(this.shardVaultId(partitionKey), { create: false });
4908
+ this.template.configure(vault);
4909
+ return vault;
4910
+ }
4911
+ /**
4912
+ * Idempotently provision a shard for `partitionKey`. Returns the
4913
+ * configured vault handle.
4914
+ *
4915
+ * - row + vault present → no-op, return handle
4916
+ * - row present, vault gone → ShardProvisioningError
4917
+ * - row absent (vault present or not) → open-or-create, configure, write row
4918
+ */
4919
+ async createShard(partitionKey) {
4920
+ const vaultId = this.shardVaultId(partitionKey);
4921
+ const row = await this.registry.get(this.registryId(partitionKey));
4922
+ const provisioned = await this.db._shardVaultProvisioned(vaultId);
4923
+ if (row && !provisioned) throw new ShardProvisioningError(vaultId, partitionKey);
4924
+ if (row && provisioned) return this.openShard(partitionKey);
4925
+ const vault = await this.db.openVault(vaultId);
4926
+ this.template.configure(vault);
4927
+ await this.registry.put(this.registryId(partitionKey), {
4928
+ vaultId,
4929
+ partitionKey,
4930
+ templateName: this.sharding.vaultTemplate,
4931
+ schemaVersion: this.template.version,
4932
+ createdAt: Date.now(),
4933
+ group: this.name
4934
+ });
4935
+ if (this.stateVault) {
4936
+ try {
4937
+ await this.stateVault.appendEvent({
4938
+ type: "shard-created",
4939
+ group: this.name,
4940
+ vaultId,
4941
+ templateName: this.sharding.vaultTemplate,
4942
+ version: this.template.version
4943
+ });
4944
+ } catch {
4945
+ }
4946
+ }
4947
+ return vault;
4948
+ }
4949
+ /**
4950
+ * Drill down to a single shard's full Collection API. Throws if the shard is unknown.
4951
+ * Also throws ShardProvisioningError if the registry row exists but the vault has been deleted
4952
+ * (registry/store divergence).
4953
+ */
4954
+ async shard(partitionKey) {
4955
+ const vaultId = this.shardVaultId(partitionKey);
4956
+ const row = await this.registry.get(this.registryId(partitionKey));
4957
+ if (!row) throw new UnknownShardError(partitionKey, this.name);
4958
+ const provisioned = await this.db._shardVaultProvisioned(vaultId);
4959
+ if (!provisioned) throw new ShardProvisioningError(vaultId, partitionKey);
4960
+ return this.openShard(partitionKey);
4961
+ }
4962
+ /** A sharded view over one logical collection across all shards. */
4963
+ collection(collectionName) {
4964
+ return new ShardedCollection(this, collectionName);
4965
+ }
4966
+ /** @internal — eligible (openable-candidate) rows + drift/divergence skips. */
4967
+ async resolveEligible(options = {}) {
4968
+ const rows = await this.allRows();
4969
+ const skipped = [];
4970
+ const versionOk = [];
4971
+ for (const row of rows) {
4972
+ if (options.minVersion !== void 0 && row.schemaVersion < options.minVersion) {
4973
+ skipped.push({ vaultId: row.vaultId, reason: "schema-drift" });
4974
+ } else versionOk.push(row);
4975
+ }
4976
+ const provisioned = await Promise.all(versionOk.map((r) => this.db._shardVaultProvisioned(r.vaultId)));
4977
+ const eligible = [];
4978
+ versionOk.forEach((row, i) => {
4979
+ if (provisioned[i]) eligible.push(row);
4980
+ else skipped.push({ vaultId: row.vaultId, reason: "error", error: new ShardProvisioningError(row.vaultId, row.partitionKey) });
4981
+ });
4982
+ return { eligible, skipped };
4983
+ }
4984
+ };
4985
+ ShardedCollection = class {
4986
+ constructor(group, collectionName) {
4987
+ this.group = group;
4988
+ this.collectionName = collectionName;
4989
+ }
4990
+ group;
4991
+ collectionName;
4992
+ /** Route a write to the shard owning `keyOf(record)`. */
4993
+ async put(id, record) {
4994
+ const key = this.group.sharding.keyOf(record);
4995
+ const row = await this.group.registry.get(this.group.registryId(key));
4996
+ let vault;
4997
+ if (!row) {
4998
+ if (this.group.sharding.autoCreate === false) {
4999
+ throw new UnknownShardError(key, this.group.name);
5000
+ }
5001
+ vault = await this.group.createShard(key);
5002
+ } else {
5003
+ vault = await this.group.openShard(key);
5004
+ }
5005
+ await vault.collection(this.collectionName).put(id, record);
5006
+ }
5007
+ /** Begin a cross-shard fan-out query. */
5008
+ query() {
5009
+ return new ShardedQuery(this.group, this.collectionName, []);
5010
+ }
5011
+ };
5012
+ ShardedQuery = class _ShardedQuery {
5013
+ constructor(group, collectionName, clauses) {
5014
+ this.group = group;
5015
+ this.collectionName = collectionName;
5016
+ this.clauses = clauses;
5017
+ }
5018
+ group;
5019
+ collectionName;
5020
+ clauses;
5021
+ where(field, op, value) {
5022
+ return new _ShardedQuery(this.group, this.collectionName, [
5023
+ ...this.clauses,
5024
+ { field, op, value }
5025
+ ]);
5026
+ }
5027
+ /** @internal — fan out the where-filtered records across eligible shards. */
5028
+ async fanoutRecords(options = {}) {
5029
+ const { eligible, skipped } = await this.group.resolveEligible(options);
5030
+ const across = await this.group.db.queryAcross(
5031
+ eligible.map((r) => r.vaultId),
5032
+ async (vault) => {
5033
+ this.group.template.configure(vault);
5034
+ const coll = vault.collection(this.collectionName);
5035
+ await coll.list();
5036
+ let q = coll.query();
5037
+ for (const c of this.clauses) q = q.where(c.field, c.op, c.value);
5038
+ return q.toArray();
5039
+ },
5040
+ { concurrency: options.concurrency ?? 1, create: false }
5041
+ );
5042
+ const results = [];
5043
+ for (const r of across) {
5044
+ if (r.error) skipped.push({ vaultId: r.vault, reason: classifyShardSkip(r.error), error: r.error });
5045
+ else for (const item of r.result) results.push(item);
5046
+ }
5047
+ return { records: results, skippedVaults: skipped };
5048
+ }
5049
+ /** Fan out across eligible shards and merge results. */
5050
+ async toArray(options = {}) {
5051
+ const { records, skippedVaults } = await this.fanoutRecords(options);
5052
+ return { results: records, skippedVaults };
5053
+ }
5054
+ /** @internal — build the change-subscription + relevance binding for this query's group+collection. */
5055
+ liveBinding() {
5056
+ const group = this.group;
5057
+ const collectionName = this.collectionName;
5058
+ return {
5059
+ subscribeToChanges: (h) => {
5060
+ group.db.on("change", h);
5061
+ return () => group.db.off("change", h);
5062
+ },
5063
+ isRelevant: (e) => e.collection === collectionName && e.vault.startsWith(`${group.name}--`)
5064
+ };
5065
+ }
5066
+ /** Returns a reactive cross-shard live query — a facade over CrossVaultLive. */
5067
+ live(options = {}) {
5068
+ const bind = this.liveBinding();
5069
+ const core = new CrossVaultLive({
5070
+ ...bind,
5071
+ compute: async () => {
5072
+ const { records, skippedVaults } = await this.fanoutRecords(options);
5073
+ return { records, skipped: skippedVaults };
5074
+ },
5075
+ initialSnapshot: { records: [], skipped: [] },
5076
+ ...options.debounceMs !== void 0 ? { debounceMs: options.debounceMs } : {}
5077
+ });
5078
+ return {
5079
+ get value() {
5080
+ return core.snapshot.records;
5081
+ },
5082
+ get skippedVaults() {
5083
+ return core.snapshot.skipped;
5084
+ },
5085
+ get error() {
5086
+ return core.error;
5087
+ },
5088
+ ready: core.ready,
5089
+ subscribe: (cb) => core.subscribe(cb),
5090
+ stop: () => core.stop()
5091
+ };
5092
+ }
5093
+ /** One-shot distributed aggregate — central reduce over all shard records. */
5094
+ aggregate(spec) {
5095
+ return new CrossVaultAggregation(this, spec, this.liveBinding());
5096
+ }
5097
+ /** Begin a grouped cross-shard aggregate. */
5098
+ groupBy(field) {
5099
+ return new ShardedGroupedQuery(this, field);
5100
+ }
5101
+ };
5102
+ ShardedGroupedQuery = class {
5103
+ constructor(query, field) {
5104
+ this.query = query;
5105
+ this.field = field;
5106
+ }
5107
+ query;
5108
+ field;
5109
+ aggregate(spec) {
5110
+ return new CrossVaultGroupedAggregation(
5111
+ { fanoutRecords: (o) => this.query.fanoutRecords(o) },
5112
+ this.field,
5113
+ spec,
5114
+ this.query.liveBinding()
5115
+ );
5116
+ }
5117
+ };
5118
+ }
5119
+ });
5120
+
5121
+ // src/federation/schema-manifest.ts
5122
+ function captureBlueprint(configure) {
5123
+ const recorded = [];
5124
+ const collectionStub = new Proxy(
5125
+ {},
5126
+ {
5127
+ get: () => () => collectionStub
5128
+ }
5129
+ );
5130
+ const proxy = new Proxy(
5131
+ {},
5132
+ {
5133
+ get: (_t, prop) => {
5134
+ if (prop === "collection") {
5135
+ return (name, opts) => {
5136
+ recorded.push({
5137
+ name,
5138
+ indexes: opts?.indexes ?? [],
5139
+ persistJsonSchema: !!opts?.persistJsonSchema
5140
+ });
5141
+ return collectionStub;
5142
+ };
5143
+ }
5144
+ return () => proxy;
5145
+ }
5146
+ }
5147
+ );
5148
+ configure(proxy);
5149
+ const sorted = [...recorded].sort((a, b) => a.name.localeCompare(b.name));
5150
+ const indexes = {};
5151
+ const persistJsonSchema = [];
5152
+ for (const c of sorted) {
5153
+ indexes[c.name] = c.indexes;
5154
+ if (c.persistJsonSchema) persistJsonSchema.push(c.name);
5155
+ }
5156
+ return {
5157
+ // `persistJsonSchema` is already name-sorted: it is populated while
5158
+ // iterating `sorted` (collections in name order).
5159
+ collections: sorted.map((c) => c.name),
5160
+ indexes,
5161
+ persistJsonSchema
5162
+ };
5163
+ }
5164
+ function canonical(value) {
5165
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
5166
+ if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
5167
+ const obj = value;
5168
+ const keys = Object.keys(obj).sort();
5169
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canonical(obj[k])}`).join(",")}}`;
5170
+ }
5171
+ async function fingerprintBlueprint(bp) {
5172
+ return sha256Hex(new TextEncoder().encode(canonical(bp)));
5173
+ }
5174
+ var init_schema_manifest = __esm({
5175
+ "src/federation/schema-manifest.ts"() {
5176
+ "use strict";
5177
+ init_crypto();
5178
+ }
5179
+ });
5180
+
5181
+ // src/federation/state-vault.ts
5182
+ var state_vault_exports = {};
5183
+ __export(state_vault_exports, {
5184
+ STATE_VAULT_NAME: () => STATE_VAULT_NAME,
5185
+ StateManagementVault: () => StateManagementVault
5186
+ });
5187
+ var REGISTRY, MANIFEST, EVENTS, StateManagementVault;
5188
+ var init_state_vault = __esm({
5189
+ "src/federation/state-vault.ts"() {
5190
+ "use strict";
5191
+ init_schema_manifest();
5192
+ init_constants();
5193
+ init_ulid();
5194
+ init_constants();
5195
+ REGISTRY = "vaultRegistry";
5196
+ MANIFEST = "schemaManifest";
5197
+ EVENTS = "deploymentEvents";
5198
+ StateManagementVault = class _StateManagementVault {
5199
+ constructor(registry, schemaManifest, events) {
5200
+ this.registry = registry;
5201
+ this.schemaManifest = schemaManifest;
5202
+ this.#events = events;
5203
+ }
5204
+ registry;
5205
+ schemaManifest;
5206
+ /**
5207
+ * The append-only deployment-events log is kept truly private so the raw
5208
+ * mutable Collection is never surfaced — events may only be written via
5209
+ * `appendEvent` and read via `queryEvents`. (`registry` and
5210
+ * `schemaManifest` are deliberately public: consumers read and write them.)
5211
+ */
5212
+ #events;
5213
+ /** Idempotently open the reserved state vault and bind the three control-plane collections. */
5214
+ static async open(db) {
5215
+ const vault = await db.openVault(STATE_VAULT_NAME);
5216
+ return new _StateManagementVault(
5217
+ vault.collection(REGISTRY),
5218
+ vault.collection(MANIFEST),
5219
+ vault.collection(EVENTS)
5220
+ );
5221
+ }
5222
+ /** Read-only query over the append-only deployment-events log. */
5223
+ queryEvents() {
5224
+ return this.#events.query();
5225
+ }
5226
+ /**
5227
+ * Append a deployment event with a fresh unique (ULID) id. This is the
5228
+ * only write path to the events log; no update/delete is exposed.
5229
+ * Callers should treat failures as non-fatal — this method does not
5230
+ * swallow errors, so wrap the call site in try/catch where appropriate.
5231
+ */
5232
+ async appendEvent(event) {
5233
+ const ts = event.ts ?? Date.now();
5234
+ const id = generateULID();
5235
+ await this.#events.put(id, { ...event, id, ts });
5236
+ }
5237
+ /**
5238
+ * Ensure a manifest row exists for `(templateName, template.version)`.
5239
+ * Safe to call repeatedly: the `fingerprint` is a deterministic hash of
5240
+ * the template's declared shape (stable across calls), though each call
5241
+ * refreshes `recordedAt`.
5242
+ */
5243
+ async recordManifest(templateName, template) {
5244
+ const bp = captureBlueprint(template.configure);
5245
+ const fingerprint = await fingerprintBlueprint(bp);
5246
+ await this.schemaManifest.put(`${templateName}:${template.version}`, {
5247
+ templateName,
5248
+ version: template.version,
5249
+ collections: bp.collections,
5250
+ indexes: bp.indexes,
5251
+ persistJsonSchema: bp.persistJsonSchema,
5252
+ fingerprint,
5253
+ recordedAt: Date.now()
5254
+ });
5255
+ return fingerprint;
5256
+ }
5257
+ /**
5258
+ * True when `template`'s current declared shape does not match the recorded
5259
+ * manifest for `(templateName, template.version)`. Because shards carry no
5260
+ * schema state independent of their template, this catches "a template's
5261
+ * shape changed without bumping `version`" — not independent per-shard drift.
5262
+ * A missing manifest is treated as drift (nothing to verify against).
5263
+ */
5264
+ async detectDrift(templateName, template) {
5265
+ const row = await this.schemaManifest.get(`${templateName}:${template.version}`);
5266
+ if (!row) return true;
5267
+ const current = await fingerprintBlueprint(captureBlueprint(template.configure));
5268
+ return current !== row.fingerprint;
5269
+ }
5270
+ };
5271
+ }
5272
+ });
5273
+
4055
5274
  // src/index.ts
4056
5275
  var src_exports = {};
4057
5276
  __export(src_exports, {
@@ -4076,6 +5295,7 @@ __export(src_exports, {
4076
5295
  CollectionFrame: () => CollectionFrame,
4077
5296
  CollectionIndexes: () => CollectionIndexes,
4078
5297
  CollectionInstant: () => CollectionInstant,
5298
+ ComputedFieldError: () => ComputedFieldError,
4079
5299
  ConflictError: () => ConflictError,
4080
5300
  CrossJoinSourceUnknownError: () => CrossJoinSourceUnknownError,
4081
5301
  CrossJoinTooLargeError: () => CrossJoinTooLargeError,
@@ -4139,6 +5359,9 @@ __export(src_exports, {
4139
5359
  MemorySealingKeyProvider: () => MemorySealingKeyProvider,
4140
5360
  MigrationRequiredError: () => MigrationRequiredError,
4141
5361
  MissingTranslationError: () => MissingTranslationError,
5362
+ MoneyCurrencyError: () => MoneyCurrencyError,
5363
+ MoneyPrecisionError: () => MoneyPrecisionError,
5364
+ MoneyUnsupportedError: () => MoneyUnsupportedError,
4142
5365
  NOYDB_BACKUP_VERSION: () => NOYDB_BACKUP_VERSION,
4143
5366
  NOYDB_BUNDLE_FORMAT_VERSION: () => NOYDB_BUNDLE_FORMAT_VERSION,
4144
5367
  NOYDB_BUNDLE_MAGIC: () => NOYDB_BUNDLE_MAGIC,
@@ -4152,6 +5375,7 @@ __export(src_exports, {
4152
5375
  NotFoundError: () => NotFoundError,
4153
5376
  Noydb: () => Noydb,
4154
5377
  NoydbError: () => NoydbError,
5378
+ NumberingUncertaintyError: () => NumberingUncertaintyError,
4155
5379
  OverlayBaseIsVirtualError: () => OverlayBaseIsVirtualError,
4156
5380
  OverlayCollectionUnavailableError: () => OverlayCollectionUnavailableError,
4157
5381
  OverlayIdMismatchError: () => OverlayIdMismatchError,
@@ -4181,8 +5405,10 @@ __export(src_exports, {
4181
5405
  RefRegistry: () => RefRegistry,
4182
5406
  RefScopeError: () => RefScopeError,
4183
5407
  ReservedCollectionNameError: () => ReservedCollectionNameError,
5408
+ ReservedVaultNameError: () => ReservedVaultNameError,
4184
5409
  SCHEMAS_COLLECTION: () => SCHEMAS_COLLECTION,
4185
5410
  SEALED_PASSPHRASE_RECORD_ID: () => SEALED_PASSPHRASE_RECORD_ID,
5411
+ STATE_VAULT_NAME: () => STATE_VAULT_NAME,
4186
5412
  STRICT_POLICY: () => STRICT_POLICY,
4187
5413
  SYNC_CREDENTIALS_COLLECTION: () => SYNC_CREDENTIALS_COLLECTION,
4188
5414
  ScanBuilder: () => ScanBuilder,
@@ -4191,9 +5417,13 @@ __export(src_exports, {
4191
5417
  SchemaUpdateError: () => SchemaUpdateError,
4192
5418
  SchemaValidationError: () => SchemaValidationError,
4193
5419
  ScriptViolationError: () => ScriptViolationError,
5420
+ SequenceContentionError: () => SequenceContentionError,
5421
+ SequenceOfflineError: () => SequenceOfflineError,
5422
+ SequenceStore: () => SequenceStore,
4194
5423
  SessionExpiredError: () => SessionExpiredError,
4195
5424
  SessionNotFoundError: () => SessionNotFoundError,
4196
5425
  SessionPolicyError: () => SessionPolicyError,
5426
+ ShardProvisioningError: () => ShardProvisioningError,
4197
5427
  SnapshotNotFoundError: () => SnapshotNotFoundError,
4198
5428
  StoreCapabilityError: () => StoreCapabilityError,
4199
5429
  SyncEngine: () => SyncEngine,
@@ -4209,6 +5439,7 @@ __export(src_exports, {
4209
5439
  USER_ENVELOPE_COLLECTION: () => USER_ENVELOPE_COLLECTION,
4210
5440
  USER_ENVELOPE_MAX_BYTES: () => USER_ENVELOPE_MAX_BYTES,
4211
5441
  UniqueConstraintError: () => UniqueConstraintError,
5442
+ UnknownShardError: () => UnknownShardError,
4212
5443
  UnsupportedIndexOptionError: () => UnsupportedIndexOptionError,
4213
5444
  UserApi: () => UserApi,
4214
5445
  UserEnvelopeOversizedError: () => UserEnvelopeOversizedError,
@@ -4217,6 +5448,7 @@ __export(src_exports, {
4217
5448
  Vault: () => Vault,
4218
5449
  VaultFrame: () => VaultFrame,
4219
5450
  VaultInstant: () => VaultInstant,
5451
+ VaultTemplateNotFoundError: () => VaultTemplateNotFoundError,
4220
5452
  WeakPassphraseError: () => WeakPassphraseError,
4221
5453
  activeSessionCount: () => activeSessionCount,
4222
5454
  additiveOnly: () => additiveOnly,
@@ -4273,6 +5505,7 @@ __export(src_exports, {
4273
5505
  envelopePayloadHash: () => envelopePayloadHash,
4274
5506
  estimateEntropy: () => estimateEntropy,
4275
5507
  estimateRecordBytes: () => estimateRecordBytes,
5508
+ evalComputedFields: () => evalComputedFields,
4276
5509
  evaluateClause: () => evaluateClause,
4277
5510
  evaluateExportCapability: () => evaluateExportCapability,
4278
5511
  evaluateFieldClause: () => evaluateFieldClause,
@@ -4289,6 +5522,7 @@ __export(src_exports, {
4289
5522
  hasRecoveryEnrolled: () => hasRecoveryEnrolled,
4290
5523
  hashEntry: () => hashEntry,
4291
5524
  i18nText: () => i18nText,
5525
+ immutableGuard: () => immutableGuard,
4292
5526
  inferScripts: () => inferScripts,
4293
5527
  isDevUnlockActive: () => isDevUnlockActive,
4294
5528
  isDictCollectionName: () => isDictCollectionName,
@@ -4296,6 +5530,7 @@ __export(src_exports, {
4296
5530
  isDiscriminant: () => isDiscriminant,
4297
5531
  isI18nTextDescriptor: () => isI18nTextDescriptor,
4298
5532
  isMagicLinkGrantExpired: () => isMagicLinkGrantExpired,
5533
+ isMoneyDescriptor: () => isMoneyDescriptor,
4299
5534
  isPreCompressed: () => isPreCompressed,
4300
5535
  isPublicEnvelope: () => isPublicEnvelope,
4301
5536
  isSessionAlive: () => isSessionAlive,
@@ -4327,6 +5562,7 @@ __export(src_exports, {
4327
5562
  mintPaperRecoveryEntry: () => mintPaperRecoveryEntry,
4328
5563
  mintShamirRecoveryEntry: () => mintShamirRecoveryEntry,
4329
5564
  mintWrappedDeksBlob: () => mintWrappedDeksBlob,
5565
+ money: () => money,
4330
5566
  paddedIndex: () => paddedIndex,
4331
5567
  parseBytes: () => parseBytes,
4332
5568
  parseIndex: () => parseIndex,
@@ -4367,6 +5603,7 @@ __export(src_exports, {
4367
5603
  saveShamirRecoveryEntries: () => saveShamirRecoveryEntries,
4368
5604
  saveUserEnvelope: () => saveUserEnvelope,
4369
5605
  saveVaultPolicy: () => saveVaultPolicy,
5606
+ scaleForCurrency: () => scaleForCurrency,
4370
5607
  sha256Hex: () => sha256Hex3,
4371
5608
  sum: () => sum,
4372
5609
  unwrapDeksFromBlob: () => unwrapDeksFromBlob,
@@ -4380,8 +5617,10 @@ __export(src_exports, {
4380
5617
  validateSchemaOutput: () => validateSchemaOutput,
4381
5618
  validateSessionPolicy: () => validateSessionPolicy,
4382
5619
  visibilityRecordId: () => visibilityRecordId,
5620
+ withArchive: () => withArchive,
4383
5621
  withCache: () => withCache,
4384
5622
  withCircuitBreaker: () => withCircuitBreaker,
5623
+ withDeferredNumbering: () => withDeferredNumbering,
4385
5624
  withDerivation: () => withDerivation,
4386
5625
  withGuard: () => withGuard,
4387
5626
  withHealthCheck: () => withHealthCheck,
@@ -6338,37 +7577,214 @@ function withHealthCheck(opts = {}) {
6338
7577
  }
6339
7578
  }
6340
7579
  }
6341
- setInterval(() => {
6342
- void doCheck();
6343
- }, intervalMs);
6344
- const wrapped = {
6345
- ...next,
6346
- name: next.name ? `health(${next.name})` : "health",
6347
- async get(v, c, id) {
6348
- return isSuspended ? null : next.get(v, c, id);
6349
- },
6350
- async put(v, c, id, env, ev) {
6351
- if (!isSuspended) await next.put(v, c, id, env, ev);
6352
- },
6353
- async delete(v, c, id) {
6354
- if (!isSuspended) await next.delete(v, c, id);
6355
- },
6356
- async list(v, c) {
6357
- return isSuspended ? [] : next.list(v, c);
6358
- },
6359
- async loadAll(v) {
6360
- return isSuspended ? {} : next.loadAll(v);
6361
- },
6362
- async saveAll(v, d) {
6363
- if (!isSuspended) await next.saveAll(v, d);
6364
- }
6365
- };
6366
- return wrapped;
7580
+ setInterval(() => {
7581
+ void doCheck();
7582
+ }, intervalMs);
7583
+ const wrapped = {
7584
+ ...next,
7585
+ name: next.name ? `health(${next.name})` : "health",
7586
+ async get(v, c, id) {
7587
+ return isSuspended ? null : next.get(v, c, id);
7588
+ },
7589
+ async put(v, c, id, env, ev) {
7590
+ if (!isSuspended) await next.put(v, c, id, env, ev);
7591
+ },
7592
+ async delete(v, c, id) {
7593
+ if (!isSuspended) await next.delete(v, c, id);
7594
+ },
7595
+ async list(v, c) {
7596
+ return isSuspended ? [] : next.list(v, c);
7597
+ },
7598
+ async loadAll(v) {
7599
+ return isSuspended ? {} : next.loadAll(v);
7600
+ },
7601
+ async saveAll(v, d) {
7602
+ if (!isSuspended) await next.saveAll(v, d);
7603
+ }
7604
+ };
7605
+ return wrapped;
7606
+ };
7607
+ }
7608
+
7609
+ // src/index.ts
7610
+ init_errors();
7611
+ init_errors();
7612
+
7613
+ // src/archive/engine.ts
7614
+ function isHeld(policy, record) {
7615
+ if (!policy.legalHold) return false;
7616
+ try {
7617
+ return policy.legalHold(record);
7618
+ } catch {
7619
+ return true;
7620
+ }
7621
+ }
7622
+ async function runArchive(ctx, options = {}) {
7623
+ const maxArchives = options.maxArchives ?? Infinity;
7624
+ const dryRun = options.dryRun === true;
7625
+ let archived = 0;
7626
+ let held = 0;
7627
+ let scanned = 0;
7628
+ const byCollection = {};
7629
+ outer: for (const collection of ctx.collectionsWithPolicy()) {
7630
+ const policy = ctx.getPolicy(collection);
7631
+ if (!policy) continue;
7632
+ byCollection[collection] = { archived: 0, held: 0 };
7633
+ for (const id of await ctx.listRecordIds(collection)) {
7634
+ if (archived >= maxArchives) break outer;
7635
+ const record = await ctx.getRecord(collection, id).catch(() => null);
7636
+ if (record === null) continue;
7637
+ scanned += 1;
7638
+ let eligible = false;
7639
+ try {
7640
+ eligible = policy.archiveWhen(record);
7641
+ } catch {
7642
+ eligible = false;
7643
+ }
7644
+ if (!eligible) continue;
7645
+ if (isHeld(policy, record)) {
7646
+ held += 1;
7647
+ byCollection[collection].held += 1;
7648
+ continue;
7649
+ }
7650
+ if (!dryRun) {
7651
+ const env = await ctx.getEnvelope(collection, id);
7652
+ if (!env) continue;
7653
+ await ctx.archiveStore.put(ctx.vaultId, collection, id, env);
7654
+ await ctx.removeFromPrimary(collection, id);
7655
+ }
7656
+ archived += 1;
7657
+ byCollection[collection].archived += 1;
7658
+ }
7659
+ }
7660
+ return { archived, held, scanned, byCollection };
7661
+ }
7662
+ async function runRestore(ctx, collection, id) {
7663
+ const env = await ctx.archiveStore.get(ctx.vaultId, collection, id);
7664
+ if (!env) return false;
7665
+ await ctx.restoreToPrimary(collection, id, env);
7666
+ await ctx.archiveStore.delete(ctx.vaultId, collection, id);
7667
+ return true;
7668
+ }
7669
+ async function runListArchived(ctx, collection) {
7670
+ const collections = collection ? [collection] : ctx.collectionsWithPolicy();
7671
+ const out = [];
7672
+ for (const c of collections) {
7673
+ const ids = await ctx.archiveStore.list(ctx.vaultId, c);
7674
+ for (const id of ids) out.push({ collection: c, id });
7675
+ }
7676
+ return out;
7677
+ }
7678
+
7679
+ // src/archive/index.ts
7680
+ function withArchive(opts) {
7681
+ return { store: opts.store };
7682
+ }
7683
+
7684
+ // src/sequence/index.ts
7685
+ init_types();
7686
+ init_crypto();
7687
+ init_errors();
7688
+ var SEQUENCE_COLLECTION = "_sequences";
7689
+ var MAX_NEXT_ATTEMPTS = 16;
7690
+ async function sleepBackoff(attempt) {
7691
+ const ceil = Math.min(2 ** attempt, 32);
7692
+ const ms = Math.floor(Math.random() * ceil);
7693
+ await new Promise((r) => setTimeout(r, ms));
7694
+ }
7695
+ var SequenceStore = class {
7696
+ adapter;
7697
+ vault;
7698
+ encrypted;
7699
+ getDEK;
7700
+ actor;
7701
+ /**
7702
+ * Memoized DEK promise. The `_sequences` collection DEK is created on
7703
+ * first access; without sharing one promise, a burst of concurrent
7704
+ * `next()` calls would each trigger DEK creation and diverge (one
7705
+ * writer's ciphertext unreadable by another). One shared promise → one
7706
+ * DEK.
7707
+ */
7708
+ dekPromise = null;
7709
+ constructor(opts) {
7710
+ this.adapter = opts.adapter;
7711
+ this.vault = opts.vault;
7712
+ this.encrypted = opts.encrypted;
7713
+ this.getDEK = opts.getDEK;
7714
+ this.actor = opts.actor;
7715
+ }
7716
+ /** A handle bound to one sequence name. */
7717
+ handle(name) {
7718
+ return {
7719
+ next: () => this.next(name),
7720
+ peek: () => this.peek(name)
7721
+ };
7722
+ }
7723
+ assertOnline() {
7724
+ if (this.adapter.capabilities?.casAtomic !== true) {
7725
+ throw new SequenceOfflineError();
7726
+ }
7727
+ }
7728
+ dek() {
7729
+ if (!this.dekPromise) this.dekPromise = this.getDEK(SEQUENCE_COLLECTION);
7730
+ return this.dekPromise;
7731
+ }
7732
+ async read(name) {
7733
+ const env = await this.adapter.get(this.vault, SEQUENCE_COLLECTION, name);
7734
+ if (!env) return { env: null, value: 0 };
7735
+ const json = this.encrypted ? await decrypt(env._iv, env._data, await this.dek()) : env._data;
7736
+ const state = JSON.parse(json);
7737
+ return { env, value: state.value };
7738
+ }
7739
+ async encryptState(state, version) {
7740
+ const json = JSON.stringify(state);
7741
+ if (!this.encrypted) {
7742
+ return { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: (/* @__PURE__ */ new Date()).toISOString(), _iv: "", _data: json, _by: this.actor };
7743
+ }
7744
+ const { iv, data } = await encrypt(json, await this.dek());
7745
+ return { _noydb: NOYDB_FORMAT_VERSION, _v: version, _ts: (/* @__PURE__ */ new Date()).toISOString(), _iv: iv, _data: data, _by: this.actor };
7746
+ }
7747
+ async peek(name) {
7748
+ return (await this.read(name)).value;
7749
+ }
7750
+ async next(name) {
7751
+ this.assertOnline();
7752
+ let lastConflict;
7753
+ for (let attempt = 0; attempt < MAX_NEXT_ATTEMPTS; attempt++) {
7754
+ const { env, value } = await this.read(name);
7755
+ const nextValue = value + 1;
7756
+ const expectedVersion = env?._v ?? 0;
7757
+ const envelope = await this.encryptState({ value: nextValue }, expectedVersion + 1);
7758
+ try {
7759
+ await this.adapter.put(this.vault, SEQUENCE_COLLECTION, name, envelope, expectedVersion);
7760
+ return nextValue;
7761
+ } catch (err) {
7762
+ if (err instanceof ConflictError) {
7763
+ lastConflict = err;
7764
+ if (attempt < MAX_NEXT_ATTEMPTS - 1) await sleepBackoff(attempt);
7765
+ continue;
7766
+ }
7767
+ throw err;
7768
+ }
7769
+ }
7770
+ void lastConflict;
7771
+ throw new SequenceContentionError(name, MAX_NEXT_ATTEMPTS);
7772
+ }
7773
+ };
7774
+
7775
+ // src/numbering/descriptor.ts
7776
+ function withDeferredNumbering(config) {
7777
+ return {
7778
+ series: config.series,
7779
+ collection: config.collection,
7780
+ field: config.field,
7781
+ settleWindowMs: config.settleWindowMs ?? 0
6367
7782
  };
6368
7783
  }
6369
7784
 
6370
7785
  // src/index.ts
6371
7786
  init_errors();
7787
+ init_constants();
6372
7788
  init_errors();
6373
7789
 
6374
7790
  // src/bundle/format.ts
@@ -7176,8 +8592,8 @@ async function derivePersistedSchema(validator) {
7176
8592
  if (kind === "Zod") {
7177
8593
  const convert = await loadZodConverter();
7178
8594
  const jsonSchema = convert(validator);
7179
- const canonical = canonicalize(jsonSchema);
7180
- const hash = await sha256Hex(new TextEncoder().encode(canonical));
8595
+ const canonical2 = canonicalize(jsonSchema);
8596
+ const hash = await sha256Hex(new TextEncoder().encode(canonical2));
7181
8597
  return { _noydb_schema: 1, kind, jsonSchema, hash, derivedAt };
7182
8598
  }
7183
8599
  return {
@@ -7251,15 +8667,15 @@ function isEquivalent(a, b) {
7251
8667
 
7252
8668
  // src/history/history.ts
7253
8669
  var HISTORY_COLLECTION = "_history";
7254
- function matchesPrefix(id, collection, recordId2) {
7255
- if (recordId2) {
7256
- return id.startsWith(`${collection}:${recordId2}:`);
8670
+ function matchesPrefix(id, collection, recordId3) {
8671
+ if (recordId3) {
8672
+ return id.startsWith(`${collection}:${recordId3}:`);
7257
8673
  }
7258
8674
  return id.startsWith(`${collection}:`);
7259
8675
  }
7260
- async function getHistory(adapter, vault, collection, recordId2, options) {
8676
+ async function getHistory(adapter, vault, collection, recordId3, options) {
7261
8677
  const allIds = await adapter.list(vault, HISTORY_COLLECTION);
7262
- const matchingIds = allIds.filter((id) => matchesPrefix(id, collection, recordId2)).sort().reverse();
8678
+ const matchingIds = allIds.filter((id) => matchesPrefix(id, collection, recordId3)).sort().reverse();
7263
8679
  const entries = [];
7264
8680
  for (const id of matchingIds) {
7265
8681
  const envelope = await adapter.get(vault, HISTORY_COLLECTION, id);
@@ -9808,6 +11224,7 @@ init_errors();
9808
11224
 
9809
11225
  // src/noydb.ts
9810
11226
  init_errors();
11227
+ init_constants();
9811
11228
  init_ulid();
9812
11229
  init_public_envelope();
9813
11230
 
@@ -10034,6 +11451,119 @@ function applyI18nLocale(record, i18nFields, locale, fallback, layer = "read") {
10034
11451
  return result;
10035
11452
  }
10036
11453
 
11454
+ // src/money/normalize.ts
11455
+ init_fixed_point();
11456
+ init_descriptor();
11457
+ function isMoneyValueObject(v) {
11458
+ return typeof v === "object" && v !== null && "currency" in v;
11459
+ }
11460
+ function quantizeAmount(field, input, scale, rounding) {
11461
+ const r = parseToScaledInt(input, scale, rounding);
11462
+ if (!r.ok) {
11463
+ if (r.reason === "precision") throw new MoneyPrecisionError(field, input, scale);
11464
+ throw new TypeError(`money: field "${field}" value ${JSON.stringify(input)} is not a finite decimal`);
11465
+ }
11466
+ return r.value.toString();
11467
+ }
11468
+ function quantizeMoneyFields(record, moneyFields) {
11469
+ const out = { ...record };
11470
+ for (const [field, desc] of Object.entries(moneyFields)) {
11471
+ const raw = out[field];
11472
+ if (raw === null || raw === void 0) continue;
11473
+ if (desc.mode === "fixed") {
11474
+ const currency2 = desc.fixedCurrency;
11475
+ out[field] = quantizeAmount(field, raw, desc.scaleFor(currency2), desc.rounding);
11476
+ continue;
11477
+ }
11478
+ let amount;
11479
+ let currency;
11480
+ if (isMoneyValueObject(raw)) {
11481
+ currency = String(raw.currency);
11482
+ amount = raw.amount;
11483
+ } else {
11484
+ const sole = desc.soleCurrency();
11485
+ if (sole === void 0) {
11486
+ throw new TypeError(
11487
+ `money: field "${field}" is multi-currency \u2014 write { amount, currency }, not a bare amount`
11488
+ );
11489
+ }
11490
+ currency = sole;
11491
+ amount = raw;
11492
+ }
11493
+ const scale = desc.scaleFor(currency);
11494
+ out[field] = { amount: quantizeAmount(field, amount, scale, desc.rounding), currency };
11495
+ }
11496
+ return out;
11497
+ }
11498
+ function formatCurrency(decimal, currency, scale, locale) {
11499
+ const fmt = new Intl.NumberFormat(locale, {
11500
+ style: "currency",
11501
+ currency,
11502
+ minimumFractionDigits: scale,
11503
+ maximumFractionDigits: scale
11504
+ });
11505
+ return fmt.format(decimal);
11506
+ }
11507
+ function decodeMoneyFields(record, moneyFields, locale) {
11508
+ const out = { ...record };
11509
+ const format = locale !== "raw";
11510
+ const fmtLocale = typeof locale === "string" && locale !== "raw" ? locale : "en-US";
11511
+ for (const [field, desc] of Object.entries(moneyFields)) {
11512
+ const stored = out[field];
11513
+ if (stored === null || stored === void 0) continue;
11514
+ let currency;
11515
+ let scaledIntString;
11516
+ if (desc.mode === "fixed") {
11517
+ if (typeof stored !== "string" && typeof stored !== "number") continue;
11518
+ currency = desc.fixedCurrency;
11519
+ scaledIntString = String(stored);
11520
+ } else {
11521
+ if (!isMoneyValueObject(stored)) continue;
11522
+ const amount = stored.amount;
11523
+ if (typeof stored.currency !== "string" || typeof amount !== "string" && typeof amount !== "number") continue;
11524
+ currency = stored.currency;
11525
+ scaledIntString = String(amount);
11526
+ }
11527
+ const scale = desc.scaleFor(currency);
11528
+ const decimal = formatScaledInt(BigInt(scaledIntString), scale);
11529
+ out[field] = desc.mode === "fixed" ? decimal : { amount: decimal, currency };
11530
+ if (format) {
11531
+ out[`${field}Formatted`] = formatCurrency(decimal, currency, scale, fmtLocale);
11532
+ out[`${field}Number`] = Number(decimal);
11533
+ }
11534
+ }
11535
+ return out;
11536
+ }
11537
+
11538
+ // src/computed/index.ts
11539
+ init_errors();
11540
+ var ComputedFieldError = class extends NoydbError {
11541
+ constructor(field, id, cause) {
11542
+ super(
11543
+ "COMPUTED_FIELD",
11544
+ `computed field "${field}" threw for record "${id}": ` + (cause instanceof Error ? cause.message : String(cause))
11545
+ );
11546
+ this.field = field;
11547
+ this.id = id;
11548
+ this.cause = cause;
11549
+ this.name = "ComputedFieldError";
11550
+ }
11551
+ field;
11552
+ id;
11553
+ cause;
11554
+ };
11555
+ function evalComputedFields(record, computed, id) {
11556
+ const out = { ...record };
11557
+ for (const [field, fn] of Object.entries(computed)) {
11558
+ try {
11559
+ out[field] = fn(out);
11560
+ } catch (cause) {
11561
+ throw new ComputedFieldError(field, id, cause);
11562
+ }
11563
+ }
11564
+ return out;
11565
+ }
11566
+
10037
11567
  // src/i18n/strategy.ts
10038
11568
  function notEnabled(op) {
10039
11569
  return new Error(
@@ -10352,6 +11882,7 @@ var NO_AGGREGATE = {
10352
11882
  };
10353
11883
 
10354
11884
  // src/query/builder.ts
11885
+ init_money_reducer();
10355
11886
  var EMPTY_PLAN = {
10356
11887
  clauses: [],
10357
11888
  orderBy: [],
@@ -10720,7 +12251,7 @@ var Query = class _Query {
10720
12251
  * for the ordering rationale.
10721
12252
  */
10722
12253
  toArray() {
10723
- const base = executePlanWithSource(this.source, this.plan, this.joinContext);
12254
+ const base = this.decodeMoney(executePlanWithSource(this.source, this.plan, this.joinContext));
10724
12255
  if (this.plan.joins.length === 0) return base;
10725
12256
  if (!this.joinContext) {
10726
12257
  throw new Error(
@@ -10729,6 +12260,23 @@ var Query = class _Query {
10729
12260
  }
10730
12261
  return applyJoins(base, this.plan.joins, this.joinContext);
10731
12262
  }
12263
+ /**
12264
+ * Decode this source's money fields on read (stored scaled-int → canonical
12265
+ * decimal), so `query().toArray()` agrees with `get()`/`sum()` on the value.
12266
+ * No-op when the source declares no money fields.
12267
+ *
12268
+ * The query layer carries no locale context, so we decode with `'raw'` —
12269
+ * canonical decimal, WITHOUT fabricating locale-formatted `<field>Formatted`
12270
+ * / `<field>Number` virtuals. Producing a guessed-locale string here would
12271
+ * just reintroduce #322's "two read paths disagree" failure on the virtual
12272
+ * field (e.g. it-IT via `get()` vs en-US here). Consumers who need formatted
12273
+ * money read through `get()`/`list()` with a locale.
12274
+ */
12275
+ decodeMoney(records) {
12276
+ const moneyFields = this.source.moneyFields;
12277
+ if (!moneyFields || Object.keys(moneyFields).length === 0) return records;
12278
+ return records.map((r) => decodeMoneyFields(r, moneyFields, "raw"));
12279
+ }
10732
12280
  /** Return the first matching record, or null. Joins are applied. */
10733
12281
  first() {
10734
12282
  const arr = this.limit(1).toArray();
@@ -10797,6 +12345,10 @@ var Query = class _Query {
10797
12345
  * partition boundaries without an API break.
10798
12346
  */
10799
12347
  aggregate(spec) {
12348
+ const moneyFields = this.source.moneyFields;
12349
+ if (moneyFields) {
12350
+ spec = wrapMoneyReducers(spec, moneyFields);
12351
+ }
10800
12352
  const source = this.source;
10801
12353
  const clauses = this.plan.clauses;
10802
12354
  const joinCtx = this.joinContext;
@@ -10844,13 +12396,15 @@ var Query = class _Query {
10844
12396
  executeRecords,
10845
12397
  field,
10846
12398
  upstreams,
10847
- dictLabelResolver
12399
+ dictLabelResolver,
12400
+ this.source.moneyFields
10848
12401
  );
10849
12402
  }
10850
12403
  return this.aggregateStrategy.groupByN(
10851
12404
  executeRecords,
10852
12405
  fields,
10853
- upstreams
12406
+ upstreams,
12407
+ this.source.moneyFields
10854
12408
  );
10855
12409
  }
10856
12410
  /**
@@ -11207,7 +12761,7 @@ function serializeClause(clause) {
11207
12761
  }
11208
12762
  function canonicalCtxHash(ctx) {
11209
12763
  if (ctx === void 0) return "";
11210
- const canonical = JSON.stringify(ctx, (_key, value) => {
12764
+ const canonical2 = JSON.stringify(ctx, (_key, value) => {
11211
12765
  if (value && typeof value === "object" && !Array.isArray(value)) {
11212
12766
  const sorted = {};
11213
12767
  for (const k of Object.keys(value).sort()) {
@@ -11218,8 +12772,8 @@ function canonicalCtxHash(ctx) {
11218
12772
  return value;
11219
12773
  });
11220
12774
  let h = 5381;
11221
- for (let i = 0; i < canonical.length; i++) {
11222
- h = (h << 5) + h ^ canonical.charCodeAt(i);
12775
+ for (let i = 0; i < canonical2.length; i++) {
12776
+ h = (h << 5) + h ^ canonical2.charCodeAt(i);
11223
12777
  }
11224
12778
  return (h >>> 0).toString(16).padStart(8, "0");
11225
12779
  }
@@ -11391,7 +12945,8 @@ function count(opts) {
11391
12945
  init: () => 0,
11392
12946
  step: (state) => state + 1,
11393
12947
  remove: (state) => state - 1,
11394
- finalize: (state) => state
12948
+ finalize: (state) => state,
12949
+ merge: (a, b) => a + b
11395
12950
  };
11396
12951
  }
11397
12952
  function sum(field, opts) {
@@ -11400,10 +12955,15 @@ function sum(field, opts) {
11400
12955
  return {
11401
12956
  op: "sum",
11402
12957
  field,
12958
+ // Money-only metadata, read by `wrapMoneyReducers`. No effect on a
12959
+ // generic numeric sum.
12960
+ ...opts?.convertTo !== void 0 ? { convertTo: opts.convertTo } : {},
12961
+ ...opts?.fx !== void 0 ? { fx: opts.fx } : {},
11403
12962
  init: () => 0,
11404
12963
  step: (state, record) => state + readNumber(record, field),
11405
12964
  remove: (state, record) => state - readNumber(record, field),
11406
- finalize: (state) => state
12965
+ finalize: (state) => state,
12966
+ merge: (a, b) => a + b
11407
12967
  };
11408
12968
  }
11409
12969
  function avg(field, opts) {
@@ -11421,7 +12981,8 @@ function avg(field, opts) {
11421
12981
  sum: state.sum - readNumber(record, field),
11422
12982
  count: state.count - 1
11423
12983
  }),
11424
- finalize: (state) => state.count === 0 ? null : state.sum / state.count
12984
+ finalize: (state) => state.count === 0 ? null : state.sum / state.count,
12985
+ merge: (a, b) => ({ sum: a.sum + b.sum, count: a.count + b.count })
11425
12986
  };
11426
12987
  }
11427
12988
  function pushValue(state, value) {
@@ -11451,7 +13012,8 @@ function min(field, opts) {
11451
13012
  if (v < out) out = v;
11452
13013
  }
11453
13014
  return out;
11454
- }
13015
+ },
13016
+ merge: (a, b) => ({ values: [...a.values, ...b.values] })
11455
13017
  };
11456
13018
  }
11457
13019
  function max(field, opts) {
@@ -11471,11 +13033,17 @@ function max(field, opts) {
11471
13033
  if (v > out) out = v;
11472
13034
  }
11473
13035
  return out;
11474
- }
13036
+ },
13037
+ merge: (a, b) => ({ values: [...a.values, ...b.values] })
11475
13038
  };
11476
13039
  }
11477
13040
  function readNumber(record, field) {
11478
13041
  const value = readPath(record, field);
13042
+ if (typeof value === "object" && value !== null && "amount" in value && "currency" in value) {
13043
+ throw new Error(
13044
+ `aggregate: field "${field}" holds a money value but was not money-aware \u2014 declare it in the collection's moneyFields so sum/min/max stay exact`
13045
+ );
13046
+ }
11479
13047
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
11480
13048
  }
11481
13049
 
@@ -11511,12 +13079,29 @@ var ScanBuilder = class _ScanBuilder {
11511
13079
  * context throws with an actionable error.
11512
13080
  */
11513
13081
  joinContext;
11514
- constructor(pageProvider, pageSize = DEFAULT_SCAN_PAGE_SIZE, clauses = [], joins = [], joinContext) {
13082
+ /**
13083
+ * Money field descriptors for the backing collection. When present, yielded
13084
+ * records are decoded (stored scaled-int → canonical decimal) so `scan()`
13085
+ * agrees with `get()`/`list()`/`query().toArray()` — #322. Decoded with
13086
+ * `'raw'` (canonical decimal, no locale-formatted virtuals) since the scan
13087
+ * stream carries no locale context, mirroring `Query.toArray()`.
13088
+ */
13089
+ moneyFields;
13090
+ constructor(pageProvider, pageSize = DEFAULT_SCAN_PAGE_SIZE, clauses = [], joins = [], joinContext, moneyFields) {
11515
13091
  this.pageProvider = pageProvider;
11516
13092
  this.pageSize = pageSize;
11517
13093
  this.clauses = clauses;
11518
13094
  this.joins = joins;
11519
13095
  this.joinContext = joinContext;
13096
+ this.moneyFields = moneyFields;
13097
+ }
13098
+ /**
13099
+ * Decode this scan's money fields on a record (stored scaled-int → canonical
13100
+ * decimal). No-op when no money fields are declared. See {@link moneyFields}.
13101
+ */
13102
+ decodeMoney(record) {
13103
+ if (!this.moneyFields || Object.keys(this.moneyFields).length === 0) return record;
13104
+ return decodeMoneyFields(record, this.moneyFields, "raw");
11520
13105
  }
11521
13106
  /**
11522
13107
  * Add a field comparison. Runs per record as the scan stream
@@ -11538,7 +13123,8 @@ var ScanBuilder = class _ScanBuilder {
11538
13123
  this.pageSize,
11539
13124
  [...this.clauses, clause],
11540
13125
  this.joins,
11541
- this.joinContext
13126
+ this.joinContext,
13127
+ this.moneyFields
11542
13128
  );
11543
13129
  }
11544
13130
  /**
@@ -11557,7 +13143,8 @@ var ScanBuilder = class _ScanBuilder {
11557
13143
  this.pageSize,
11558
13144
  [...this.clauses, clause],
11559
13145
  this.joins,
11560
- this.joinContext
13146
+ this.joinContext,
13147
+ this.moneyFields
11561
13148
  );
11562
13149
  }
11563
13150
  /**
@@ -11668,7 +13255,8 @@ var ScanBuilder = class _ScanBuilder {
11668
13255
  this.pageSize,
11669
13256
  this.clauses,
11670
13257
  [...this.joins, leg],
11671
- this.joinContext
13258
+ this.joinContext,
13259
+ this.moneyFields
11672
13260
  );
11673
13261
  }
11674
13262
  /**
@@ -11685,10 +13273,11 @@ var ScanBuilder = class _ScanBuilder {
11685
13273
  while (true) {
11686
13274
  for (const record of page.items) {
11687
13275
  if (!this.recordMatches(record)) continue;
13276
+ const decoded = this.decodeMoney(record);
11688
13277
  if (joinResolvers === null) {
11689
- yield record;
13278
+ yield decoded;
11690
13279
  } else {
11691
- let attached = record;
13280
+ let attached = decoded;
11692
13281
  for (const resolver of joinResolvers) {
11693
13282
  attached = this.applyOneJoinStreaming(attached, resolver);
11694
13283
  }
@@ -11889,8 +13478,8 @@ function coerceRefKey2(value) {
11889
13478
 
11890
13479
  // src/indexing/persisted-indexes.ts
11891
13480
  var IDX_PREFIX = "_idx/";
11892
- function encodeIdxId(field, recordId2) {
11893
- return `${IDX_PREFIX}${field}/${recordId2}`;
13481
+ function encodeIdxId(field, recordId3) {
13482
+ return `${IDX_PREFIX}${field}/${recordId3}`;
11894
13483
  }
11895
13484
  function decodeIdxId(id) {
11896
13485
  if (!id.startsWith(IDX_PREFIX)) return null;
@@ -11898,9 +13487,9 @@ function decodeIdxId(id) {
11898
13487
  const firstSlash = rest.indexOf("/");
11899
13488
  if (firstSlash <= 0) return null;
11900
13489
  const field = rest.slice(0, firstSlash);
11901
- const recordId2 = rest.slice(firstSlash + 1);
11902
- if (recordId2.length === 0) return null;
11903
- return { field, recordId: recordId2 };
13490
+ const recordId3 = rest.slice(firstSlash + 1);
13491
+ if (recordId3.length === 0) return null;
13492
+ return { field, recordId: recordId3 };
11904
13493
  }
11905
13494
 
11906
13495
  // src/indexing/lazy-builder.ts
@@ -12886,6 +14475,18 @@ var Collection = class {
12886
14475
  * fields when a locale is requested.
12887
14476
  */
12888
14477
  dictKeyFields;
14478
+ /**
14479
+ * Money field descriptors keyed by field path. Declared via the
14480
+ * `moneyFields` collection option: `put()` quantizes to a scaled-int
14481
+ * string, `get()`/`list()` decode back. Mutable so {@link _applyMoneyFields}
14482
+ * can attach descriptors to a collection MV-analysis pre-created.
14483
+ */
14484
+ moneyFields;
14485
+ /**
14486
+ * Computed scalar fields, evaluated first on every `put()`. Mutable for
14487
+ * the same MV-pre-creation reconcile as {@link moneyFields}.
14488
+ */
14489
+ computed;
12889
14490
  /**
12890
14491
  * Async callback provided by the Vault that resolves a dict key
12891
14492
  * to its label for a given locale. Used by the locale-read path for
@@ -13027,6 +14628,8 @@ var Collection = class {
13027
14628
  this.joinResolver = opts.joinResolver;
13028
14629
  this.i18nFields = opts.i18nFields;
13029
14630
  this.dictKeyFields = opts.dictKeyFields;
14631
+ this.moneyFields = opts.moneyFields;
14632
+ this.computed = opts.computed;
13030
14633
  this.dictLabelResolver = opts.dictLabelResolver;
13031
14634
  this.i18nPutValidator = opts.i18nPutValidator;
13032
14635
  this.autoTranslateHook = opts.autoTranslateHook;
@@ -13151,6 +14754,19 @@ var Collection = class {
13151
14754
  getSchema() {
13152
14755
  return this.schema;
13153
14756
  }
14757
+ /**
14758
+ * @internal — attach money descriptors post-construction. MV dependency
14759
+ * analysis auto-creates a source collection (without options) during
14760
+ * `openVault`, before the user's `collection(name, { moneyFields })`
14761
+ * declaration; this reconciles that ordering. First-wins. Not public.
14762
+ */
14763
+ _applyMoneyFields(moneyFields) {
14764
+ if (this.moneyFields === void 0) this.moneyFields = moneyFields;
14765
+ }
14766
+ /** @internal — attach computed fields post-construction. See {@link _applyMoneyFields}. */
14767
+ _applyComputed(computed) {
14768
+ if (this.computed === void 0) this.computed = computed;
14769
+ }
13154
14770
  /**
13155
14771
  * Get a single record by ID.
13156
14772
  *
@@ -13322,7 +14938,7 @@ var Collection = class {
13322
14938
  existingRecord = null;
13323
14939
  }
13324
14940
  }
13325
- await this.subsystemBus.dispatchGate("beforePut", {
14941
+ const gateEvent = {
13326
14942
  op: existingEnv ? "update" : "create",
13327
14943
  vault: this.vault,
13328
14944
  collection: this.name,
@@ -13332,12 +14948,20 @@ var Collection = class {
13332
14948
  existingVersion: existingEnv?._v ?? 0,
13333
14949
  existingTs: existingEnv?._ts,
13334
14950
  userId: this.keyring.userId,
13335
- role: this.keyring.role
13336
- });
14951
+ role: this.keyring.role,
14952
+ ...this.computed !== void 0 ? { computedFieldNames: new Set(Object.keys(this.computed)) } : {}
14953
+ };
14954
+ await this.subsystemBus.dispatchGate("beforePut", gateEvent);
14955
+ }
14956
+ if (this.computed !== void 0) {
14957
+ record = evalComputedFields(record, this.computed, id);
13337
14958
  }
13338
14959
  if (this.schema !== void 0) {
13339
14960
  record = await validateSchemaInput(this.schema, record, `put(${id})`);
13340
14961
  }
14962
+ if (this.moneyFields) {
14963
+ record = quantizeMoneyFields(record, this.moneyFields);
14964
+ }
13341
14965
  if (this.i18nFields) {
13342
14966
  const obj = record;
13343
14967
  for (const [field, descriptor] of Object.entries(this.i18nFields)) {
@@ -13988,9 +15612,17 @@ var Collection = class {
13988
15612
  }
13989
15613
  await this.ensureHydrated();
13990
15614
  const records = [...this.cache.values()].map((e) => e.record);
13991
- if (!locale) return records;
15615
+ if (!this.hasReadTransforms()) return records;
13992
15616
  return Promise.all(records.map((r) => this.applyLocaleToRecord(r, locale)));
13993
15617
  }
15618
+ /**
15619
+ * @internal — whether any read-side record transform is registered
15620
+ * (money decode, i18nText resolution, dictKey labels). Gates the
15621
+ * no-transform fast path in {@link list}.
15622
+ */
15623
+ hasReadTransforms() {
15624
+ 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;
15625
+ }
13994
15626
  // ─── Bulk operations ─────────────────────────────────────
13995
15627
  /**
13996
15628
  * Put many records in one call. Each item is processed sequentially
@@ -14159,7 +15791,8 @@ var Collection = class {
14159
15791
  // fields. The Query builder consults these when present and falls
14160
15792
  // back to a linear scan otherwise.
14161
15793
  getIndexes: () => this.getIndexes(),
14162
- lookupById: (id) => this.cache.get(id)?.record
15794
+ lookupById: (id) => this.cache.get(id)?.record,
15795
+ ...this.moneyFields ? { moneyFields: this.moneyFields } : {}
14163
15796
  };
14164
15797
  const resolver = this.joinResolver;
14165
15798
  const leftCollection = this.name;
@@ -14495,7 +16128,8 @@ var Collection = class {
14495
16128
  pageSize,
14496
16129
  [],
14497
16130
  [],
14498
- joinContext
16131
+ joinContext,
16132
+ this.moneyFields
14499
16133
  );
14500
16134
  }
14501
16135
  /** Decrypt a page of envelopes returned by `adapter.listPage`. */
@@ -14661,11 +16295,11 @@ var Collection = class {
14661
16295
  }
14662
16296
  }
14663
16297
  persisted.clear();
14664
- for (const recordId2 of canonicalIds) {
14665
- const envelope = await this.adapter.get(this.vault, this.name, recordId2);
16298
+ for (const recordId3 of canonicalIds) {
16299
+ const envelope = await this.adapter.get(this.vault, this.name, recordId3);
14666
16300
  if (!envelope) continue;
14667
16301
  const record = await this.decryptRecord(envelope, { skipValidation: true });
14668
- await this.maintainPersistedIndexesOnPut(recordId2, record, null, envelope._v);
16302
+ await this.maintainPersistedIndexesOnPut(recordId3, record, null, envelope._v);
14669
16303
  }
14670
16304
  this.persistedIndexesLoaded = true;
14671
16305
  }
@@ -14841,10 +16475,14 @@ var Collection = class {
14841
16475
  async applyLocaleToRecord(record, localeOpts) {
14842
16476
  const hasI18n = this.i18nFields && Object.keys(this.i18nFields).length > 0;
14843
16477
  const hasDict = this.dictKeyFields && Object.keys(this.dictKeyFields).length > 0;
14844
- if (!hasI18n && !hasDict) return record;
16478
+ const hasMoney = this.moneyFields && Object.keys(this.moneyFields).length > 0;
16479
+ if (!hasI18n && !hasDict && !hasMoney) return record;
14845
16480
  const locale = localeOpts?.locale ?? this.defaultLocale;
14846
- if (!locale) return record;
14847
16481
  let result = record;
16482
+ if (hasMoney && this.moneyFields) {
16483
+ result = decodeMoneyFields(result, this.moneyFields, typeof locale === "string" ? locale : void 0);
16484
+ }
16485
+ if (!locale) return result;
14848
16486
  if (hasI18n && this.i18nFields) {
14849
16487
  result = this.i18nStrategy.applyI18nLocale(result, this.i18nFields, locale, localeOpts?.fallback);
14850
16488
  }
@@ -15715,7 +17353,165 @@ var OverlayedCollection = class {
15715
17353
  // src/vault.ts
15716
17354
  init_errors();
15717
17355
  init_errors();
15718
- init_constants();
17356
+
17357
+ // src/numbering/index.ts
17358
+ init_types();
17359
+ init_crypto();
17360
+ init_errors();
17361
+ var NUMBERING_HEAD_COLLECTION = "_numbering_head";
17362
+ var NUMBERING_PENDING_COLLECTION = "_numbering_pending";
17363
+ var DeferredNumberingStore = class {
17364
+ adapter;
17365
+ vault;
17366
+ encrypted;
17367
+ getDEK;
17368
+ actor;
17369
+ configs;
17370
+ /**
17371
+ * Stamp a serial onto a USER record THROUGH the Collection layer (so the
17372
+ * cache, indexes, and MVs stay coherent — the engine must NOT write user
17373
+ * collections at the raw adapter level). Returns false if the record is
17374
+ * gone (the engine then skips it without burning a serial). Provided by the
17375
+ * vault; unit tests pass a Map-backed double.
17376
+ */
17377
+ stamp;
17378
+ /** In-process registry: `${series}::${recordId}` → resolver for the live next() Promise. */
17379
+ waiters = /* @__PURE__ */ new Map();
17380
+ dekCache = /* @__PURE__ */ new Map();
17381
+ constructor(opts) {
17382
+ this.adapter = opts.adapter;
17383
+ this.vault = opts.vault;
17384
+ this.encrypted = opts.encrypted;
17385
+ this.getDEK = opts.getDEK;
17386
+ this.actor = opts.actor;
17387
+ this.configs = opts.configs;
17388
+ this.stamp = opts.stamp;
17389
+ }
17390
+ has(series) {
17391
+ return this.configs.has(series);
17392
+ }
17393
+ dek(collection) {
17394
+ let p = this.dekCache.get(collection);
17395
+ if (!p) {
17396
+ p = this.getDEK(collection);
17397
+ this.dekCache.set(collection, p);
17398
+ }
17399
+ return p;
17400
+ }
17401
+ async readJson(collection, id) {
17402
+ const env = await this.adapter.get(this.vault, collection, id);
17403
+ if (!env) return { env: null, value: null };
17404
+ const json = this.encrypted ? await decrypt(env._iv, env._data, await this.dek(collection)) : env._data;
17405
+ return { env, value: JSON.parse(json) };
17406
+ }
17407
+ async writeJson(collection, id, value, expectedVersion) {
17408
+ const json = JSON.stringify(value);
17409
+ let env;
17410
+ if (!this.encrypted) {
17411
+ env = { _noydb: NOYDB_FORMAT_VERSION, _v: expectedVersion + 1, _ts: (/* @__PURE__ */ new Date()).toISOString(), _iv: "", _data: json, _by: this.actor };
17412
+ } else {
17413
+ const { iv, data } = await encrypt(json, await this.dek(collection));
17414
+ env = { _noydb: NOYDB_FORMAT_VERSION, _v: expectedVersion + 1, _ts: (/* @__PURE__ */ new Date()).toISOString(), _iv: iv, _data: data, _by: this.actor };
17415
+ }
17416
+ await this.adapter.put(this.vault, collection, id, env, expectedVersion);
17417
+ }
17418
+ pendingId(series, recordId3) {
17419
+ return `${series}::${recordId3}`;
17420
+ }
17421
+ /** Current last-assigned serial for a series (0 if none). */
17422
+ async peek(series) {
17423
+ const { value } = await this.readJson(NUMBERING_HEAD_COLLECTION, series);
17424
+ return value?.lastSerial ?? 0;
17425
+ }
17426
+ /**
17427
+ * Enqueue a record for numbering: stamp it with the current store clock and
17428
+ * durably write a pending entry. The returned Promise resolves once the
17429
+ * record is durably enqueued; its `assigned` field resolves with the serial
17430
+ * at the next pass (the record's `field` is the durable source of truth —
17431
+ * `assigned` is an in-process convenience that a crash may drop).
17432
+ */
17433
+ async enqueue(series, recordId3) {
17434
+ const cfg = this.configs.get(series);
17435
+ if (!cfg) throw new NumberingUncertaintyError(series);
17436
+ if (typeof this.adapter.getStoreTime !== "function") throw new NumberingUncertaintyError(series);
17437
+ const st = await this.adapter.getStoreTime();
17438
+ const id = this.pendingId(series, recordId3);
17439
+ const { env } = await this.readJson(NUMBERING_PENDING_COLLECTION, id);
17440
+ const entry = {
17441
+ series,
17442
+ recordId: recordId3,
17443
+ collection: cfg.collection,
17444
+ field: cfg.field,
17445
+ storeEarliest: st.earliest,
17446
+ storeLatest: st.latest,
17447
+ enqueuedAt: Date.now()
17448
+ };
17449
+ await this.writeJson(NUMBERING_PENDING_COLLECTION, id, entry, env?._v ?? 0);
17450
+ const assigned = new Promise((resolve, reject) => {
17451
+ this.waiters.set(id, { resolve, reject });
17452
+ });
17453
+ return { assigned };
17454
+ }
17455
+ async listPending(series) {
17456
+ const ids = await this.adapter.list(this.vault, NUMBERING_PENDING_COLLECTION);
17457
+ const prefix = `${series}::`;
17458
+ const out = [];
17459
+ for (const id of ids) {
17460
+ if (!id.startsWith(prefix)) continue;
17461
+ const { value } = await this.readJson(NUMBERING_PENDING_COLLECTION, id);
17462
+ if (value) out.push({ id, entry: value });
17463
+ }
17464
+ return out;
17465
+ }
17466
+ /**
17467
+ * Run a numbering pass for `series`: select entries provably settled
17468
+ * (`storeLatest ≤ now.earliest` — commit-wait), order by
17469
+ * `(storeEarliest, recordId)`, assign serials after the head, stamp each
17470
+ * record's field, advance the head with one CAS, and consume the entries.
17471
+ * Idempotent/convergent: a losing concurrent pass returns `[]` and the next
17472
+ * pass reconciles. Resolves any in-process enqueue() `assigned` Promises.
17473
+ */
17474
+ async runPass(series) {
17475
+ const cfg = this.configs.get(series);
17476
+ if (!cfg) throw new NumberingUncertaintyError(series);
17477
+ if (typeof this.adapter.getStoreTime !== "function") throw new NumberingUncertaintyError(series);
17478
+ const now = await this.adapter.getStoreTime();
17479
+ const settled = (await this.listPending(series)).filter((p) => p.entry.storeLatest <= now.earliest).sort(
17480
+ (a, b) => a.entry.storeEarliest - b.entry.storeEarliest || (a.entry.recordId < b.entry.recordId ? -1 : a.entry.recordId > b.entry.recordId ? 1 : 0)
17481
+ );
17482
+ if (settled.length === 0) return [];
17483
+ const { env: headEnv, value: head } = await this.readJson(NUMBERING_HEAD_COLLECTION, series);
17484
+ let serial = head?.lastSerial ?? 0;
17485
+ const assignments = [];
17486
+ for (const { entry } of settled) {
17487
+ serial += 1;
17488
+ const ok = await this.stamp(entry.collection, entry.recordId, entry.field, serial);
17489
+ if (!ok) {
17490
+ serial -= 1;
17491
+ continue;
17492
+ }
17493
+ assignments.push({ recordId: entry.recordId, serial });
17494
+ }
17495
+ try {
17496
+ await this.writeJson(NUMBERING_HEAD_COLLECTION, series, { series, lastSerial: serial, watermark: now.earliest }, headEnv?._v ?? 0);
17497
+ } catch (err) {
17498
+ if (err instanceof ConflictError) return [];
17499
+ throw err;
17500
+ }
17501
+ for (const { id, entry } of settled) {
17502
+ await this.adapter.delete(this.vault, NUMBERING_PENDING_COLLECTION, id);
17503
+ const a = assignments.find((x) => x.recordId === entry.recordId);
17504
+ if (a) {
17505
+ this.waiters.get(id)?.resolve(a.serial);
17506
+ this.waiters.delete(id);
17507
+ }
17508
+ }
17509
+ return assignments;
17510
+ }
17511
+ };
17512
+
17513
+ // src/vault.ts
17514
+ init_constants2();
15719
17515
  init_entry();
15720
17516
 
15721
17517
  // src/shadow/strategy.ts
@@ -16243,6 +18039,7 @@ async function runCompaction(ctx, options = {}) {
16243
18039
  let evicted = 0;
16244
18040
  let records = 0;
16245
18041
  let auditEntries = 0;
18042
+ let held = 0;
16246
18043
  let collectionsWithPolicy = 0;
16247
18044
  outer: for (const collectionName of allCollections) {
16248
18045
  if (collectionName.startsWith("_")) continue;
@@ -16253,25 +18050,29 @@ async function runCompaction(ctx, options = {}) {
16253
18050
  collectionsWithPolicy += 1;
16254
18051
  byCollection[collectionName] = { records: 0, evicted: 0 };
16255
18052
  const ids = await ctx.listRecords(collectionName);
16256
- for (const recordId2 of ids) {
18053
+ for (const recordId3 of ids) {
16257
18054
  if (evicted >= maxEvictions) break outer;
16258
- const record = await ctx.getRecord(collectionName, recordId2).catch(() => null);
18055
+ const record = await ctx.getRecord(collectionName, recordId3).catch(() => null);
16259
18056
  if (record === null) continue;
16260
18057
  records += 1;
16261
18058
  byCollection[collectionName].records += 1;
16262
- const slots = await ctx.listSlots(collectionName, recordId2).catch(() => []);
18059
+ const slots = await ctx.listSlots(collectionName, recordId3).catch(() => []);
16263
18060
  for (const slot of slots) {
16264
18061
  if (evicted >= maxEvictions) break outer;
16265
18062
  const policy = config[slot.name];
16266
18063
  if (!policy) continue;
16267
18064
  const reason = evaluatePolicy(policy, record, slot, now);
16268
18065
  if (!reason) continue;
18066
+ if (isHeld2(policy, record, now)) {
18067
+ held += 1;
18068
+ continue;
18069
+ }
16269
18070
  if (!dryRun) {
16270
- await ctx.deleteSlot(collectionName, recordId2, slot.name);
18071
+ await ctx.deleteSlot(collectionName, recordId3, slot.name);
16271
18072
  await writeAuditEntry(ctx, {
16272
- id: generateEvictionId(collectionName, recordId2, slot.name),
18073
+ id: generateEvictionId(collectionName, recordId3, slot.name),
16273
18074
  collection: collectionName,
16274
- recordId: recordId2,
18075
+ recordId: recordId3,
16275
18076
  slotName: slot.name,
16276
18077
  blobHash: slot.eTag,
16277
18078
  reason,
@@ -16290,9 +18091,32 @@ async function runCompaction(ctx, options = {}) {
16290
18091
  records,
16291
18092
  collections: collectionsWithPolicy,
16292
18093
  auditEntries,
18094
+ held,
16293
18095
  byCollection
16294
18096
  };
16295
18097
  }
18098
+ function isHeld2(policy, record, now) {
18099
+ if (policy.legalHold) {
18100
+ try {
18101
+ if (policy.legalHold(record)) return true;
18102
+ } catch {
18103
+ return true;
18104
+ }
18105
+ }
18106
+ if (policy.retainUntil) {
18107
+ try {
18108
+ const until = policy.retainUntil(record);
18109
+ if (until !== null && until !== void 0) {
18110
+ const t = until instanceof Date ? until.getTime() : typeof until === "number" ? until : Date.parse(String(until));
18111
+ if (!Number.isFinite(t)) return true;
18112
+ if (t > now.getTime()) return true;
18113
+ }
18114
+ } catch {
18115
+ return true;
18116
+ }
18117
+ }
18118
+ return false;
18119
+ }
16296
18120
  function evaluatePolicy(policy, record, slot, now) {
16297
18121
  let ttlTriggered = false;
16298
18122
  let predicateTriggered = false;
@@ -16315,11 +18139,11 @@ function evaluatePolicy(policy, record, slot, now) {
16315
18139
  if (predicateTriggered) return "predicate";
16316
18140
  return null;
16317
18141
  }
16318
- function generateEvictionId(collection, recordId2, slotName) {
18142
+ function generateEvictionId(collection, recordId3, slotName) {
16319
18143
  const rand = globalThis.crypto.getRandomValues(new Uint8Array(8));
16320
18144
  let suffix = "";
16321
18145
  for (const b of rand) suffix += b.toString(16).padStart(2, "0");
16322
- return `${collection}__${recordId2}__${slotName}__${suffix}`;
18146
+ return `${collection}__${recordId3}__${slotName}__${suffix}`;
16323
18147
  }
16324
18148
  async function writeAuditEntry(ctx, entry) {
16325
18149
  const json = JSON.stringify(entry);
@@ -16370,7 +18194,7 @@ async function deriveMagicLinkContentKey(serverSecret, token, vault) {
16370
18194
  ["encrypt", "decrypt"]
16371
18195
  );
16372
18196
  }
16373
- async function writeMagicLinkGrant(store, vault, grantor, contentKey, grantKek, recordId2, opts) {
18197
+ async function writeMagicLinkGrant(store, vault, grantor, contentKey, grantKek, recordId3, opts) {
16374
18198
  const collectionName = opts.collection ?? null;
16375
18199
  const sourceKey = collectionName ? dekKey(collectionName, opts.tier) : `__any#${opts.tier}`;
16376
18200
  const sourceDek = grantor.deks.get(sourceKey);
@@ -16383,7 +18207,7 @@ async function writeMagicLinkGrant(store, vault, grantor, contentKey, grantKek,
16383
18207
  const until = typeof opts.until === "string" ? opts.until : opts.until.toISOString();
16384
18208
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
16385
18209
  const payload = {
16386
- id: recordId2,
18210
+ id: recordId3,
16387
18211
  toUser: opts.toUser,
16388
18212
  fromUser: grantor.userId,
16389
18213
  tier: opts.tier,
@@ -16403,11 +18227,11 @@ async function writeMagicLinkGrant(store, vault, grantor, contentKey, grantKek,
16403
18227
  _data: data,
16404
18228
  _by: grantor.userId
16405
18229
  };
16406
- await store.put(vault, MAGIC_LINK_GRANTS_COLLECTION, recordId2, envelope);
16407
- return { recordId: recordId2, payload };
18230
+ await store.put(vault, MAGIC_LINK_GRANTS_COLLECTION, recordId3, envelope);
18231
+ return { recordId: recordId3, payload };
16408
18232
  }
16409
- async function readMagicLinkGrantRecord(store, vault, contentKey, recordId2) {
16410
- const env = await store.get(vault, MAGIC_LINK_GRANTS_COLLECTION, recordId2);
18233
+ async function readMagicLinkGrantRecord(store, vault, contentKey, recordId3) {
18234
+ const env = await store.get(vault, MAGIC_LINK_GRANTS_COLLECTION, recordId3);
16411
18235
  if (!env) return null;
16412
18236
  try {
16413
18237
  const json = await decrypt(env._iv, env._data, contentKey);
@@ -17009,6 +18833,10 @@ var Vault = class {
17009
18833
  * call throws with a pointer at `@noy-db/hub/blobs`.
17010
18834
  */
17011
18835
  blobStrategy;
18836
+ /** Cold-storage archival strategy (the archive target store). */
18837
+ archiveStrategy;
18838
+ /** Per-collection record archival policies. Indexed by collection name. */
18839
+ archiveRegistry = /* @__PURE__ */ new Map();
17012
18840
  indexStrategy;
17013
18841
  aggregateStrategy;
17014
18842
  crdtStrategy;
@@ -17112,6 +18940,12 @@ var Vault = class {
17112
18940
  * docstring.
17113
18941
  */
17114
18942
  ledgerStore = null;
18943
+ /** Lazily-built atomic-sequence store. See {@link sequence}. */
18944
+ sequenceStore = null;
18945
+ /** Lazily-built deferred-numbering engine. See {@link runNumberingPass}. */
18946
+ deferredNumbering = null;
18947
+ /** Registered deferred-numbering series, keyed by series name. */
18948
+ numberingConfigs;
17115
18949
  /**
17116
18950
  * Background writes for persisted-schema envelopes (#schema-dump v0
17117
18951
  * slice 1). One promise per `collection({ persistJsonSchema: true })`
@@ -17198,6 +19032,7 @@ var Vault = class {
17198
19032
  constructor(opts) {
17199
19033
  this.adapter = opts.adapter;
17200
19034
  this.name = opts.name;
19035
+ this.numberingConfigs = new Map((opts.numberingConfigs ?? []).map((c) => [c.series, c]));
17201
19036
  this.noydb = opts.noydb;
17202
19037
  this.keyring = opts.keyring;
17203
19038
  this.encrypted = opts.encrypted;
@@ -17213,6 +19048,7 @@ var Vault = class {
17213
19048
  this.onRegisterConflictResolver = opts.onRegisterConflictResolver;
17214
19049
  this.syncAdapter = opts.syncAdapter;
17215
19050
  this.blobStrategy = opts.blobStrategy;
19051
+ this.archiveStrategy = opts.archiveStrategy;
17216
19052
  this.indexStrategy = opts.indexStrategy;
17217
19053
  this.aggregateStrategy = opts.aggregateStrategy;
17218
19054
  this.crdtStrategy = opts.crdtStrategy;
@@ -17275,8 +19111,9 @@ var Vault = class {
17275
19111
  *. `put()` validates keys against the declared set; reads
17276
19112
  * with `{ locale }` add `<field>Label` virtual fields.
17277
19113
  *
17278
- * Throws `ReservedCollectionNameError` for names starting with `_dict_`.
17279
- * Use `vault.dictionary(name)` to access dictionary collections.
19114
+ * Throws `ReservedCollectionNameError` for names starting with `_dict_` or
19115
+ * equal to `_sequences`. Use `vault.dictionary(name)` for dict collections
19116
+ * and `vault.sequence(name)` for sequence counters.
17280
19117
  *
17281
19118
  * Lazy mode + indexes is rejected at construction time — see the
17282
19119
  * Collection constructor for the rationale.
@@ -17295,7 +19132,16 @@ var Vault = class {
17295
19132
  if (isDictCollectionName(collectionName)) {
17296
19133
  throw new ReservedCollectionNameError(collectionName);
17297
19134
  }
19135
+ if (collectionName === SEQUENCE_COLLECTION) {
19136
+ throw new ReservedCollectionNameError(collectionName);
19137
+ }
17298
19138
  let coll = this.collectionCache.get(collectionName);
19139
+ if (coll && options?.moneyFields) {
19140
+ coll._applyMoneyFields(options.moneyFields);
19141
+ }
19142
+ if (coll && options?.computed) {
19143
+ coll._applyComputed(options.computed);
19144
+ }
17299
19145
  if (!coll) {
17300
19146
  if (options?.refs) {
17301
19147
  this.refRegistry.register(collectionName, options.refs);
@@ -17306,6 +19152,9 @@ var Vault = class {
17306
19152
  if (options?.blobFields) {
17307
19153
  this.blobFieldsRegistry.set(collectionName, options.blobFields);
17308
19154
  }
19155
+ if (options?.archive) {
19156
+ this.archiveRegistry.set(collectionName, options.archive);
19157
+ }
17309
19158
  if (options?.attestation !== void 0) {
17310
19159
  this.attestationRegistry.set(collectionName, options.attestation);
17311
19160
  }
@@ -17421,6 +19270,8 @@ var Vault = class {
17421
19270
  collOpts.onCrossTierAccess = (event) => this.emitCrossTier(event);
17422
19271
  if (this.syncAdapter !== void 0) collOpts.syncAdapter = this.syncAdapter;
17423
19272
  if (options?.i18nFields !== void 0) collOpts.i18nFields = options.i18nFields;
19273
+ if (options?.moneyFields !== void 0) collOpts.moneyFields = options.moneyFields;
19274
+ if (options?.computed !== void 0) collOpts.computed = options.computed;
17424
19275
  if (options?.dictKeyFields !== void 0) {
17425
19276
  collOpts.dictLabelResolver = async (dictName, key, locale, fallback) => {
17426
19277
  const handle = this.dictionary(dictName);
@@ -17840,6 +19691,77 @@ var Vault = class {
17840
19691
  * await vault.compact({ maxEvictions: 1000 }) // cap batch
17841
19692
  * ```
17842
19693
  */
19694
+ /**
19695
+ * Atomic, gap-free numbering. `vault.sequence('invoice-2026').next()`
19696
+ * returns 1, 2, 3, … with no gaps or duplicates under concurrency, via
19697
+ * an optimistic-CAS counter at `_sequences/<name>`. Each name is an
19698
+ * independent sequence.
19699
+ *
19700
+ * **Online-only:** `next()` throws `SequenceOfflineError` unless the
19701
+ * store advertises `capabilities.casAtomic` — gap-free numbering cannot
19702
+ * be serialized by an offline / non-CAS writer.
19703
+ *
19704
+ * ```ts
19705
+ * const n = await vault.sequence('invoice-2026').next() // 1, then 2, …
19706
+ * const cur = await vault.sequence('invoice-2026').peek() // current value, no allocation
19707
+ * ```
19708
+ */
19709
+ sequence(name) {
19710
+ if (this.numberingConfigs.has(name)) {
19711
+ const eng = this.deferred();
19712
+ return {
19713
+ next: async (opts) => {
19714
+ if (!opts?.for) {
19715
+ throw new ValidationError(`sequence("${name}") is a deferred-numbering series; call next({ for: recordId }).`);
19716
+ }
19717
+ return (await eng.enqueue(name, opts.for)).assigned;
19718
+ },
19719
+ peek: () => eng.peek(name)
19720
+ };
19721
+ }
19722
+ if (!this.sequenceStore) {
19723
+ this.sequenceStore = new SequenceStore({
19724
+ adapter: this.adapter,
19725
+ vault: this.name,
19726
+ encrypted: this.encrypted,
19727
+ getDEK: this.getDEK,
19728
+ actor: this.keyring.userId
19729
+ });
19730
+ }
19731
+ return this.sequenceStore.handle(name);
19732
+ }
19733
+ /** @internal — lazily build the deferred-numbering engine with a cache-coherent stamp. */
19734
+ deferred() {
19735
+ if (!this.deferredNumbering) {
19736
+ this.deferredNumbering = new DeferredNumberingStore({
19737
+ adapter: this.adapter,
19738
+ vault: this.name,
19739
+ encrypted: this.encrypted,
19740
+ getDEK: this.getDEK,
19741
+ actor: this.keyring.userId,
19742
+ configs: this.numberingConfigs,
19743
+ // Stamp THROUGH the Collection layer so cache/indexes/MVs stay coherent —
19744
+ // `this.collection(name)` returns the shared cached instance, so a
19745
+ // subsequent user `collection.get(id)` sees the assigned serial.
19746
+ stamp: async (collection, recordId3, field, serial) => {
19747
+ const coll = this.collection(collection);
19748
+ const rec = await coll.get(recordId3);
19749
+ if (!rec) return false;
19750
+ await coll.put(recordId3, { ...rec, [field]: serial });
19751
+ return true;
19752
+ }
19753
+ });
19754
+ }
19755
+ return this.deferredNumbering;
19756
+ }
19757
+ /**
19758
+ * Run a deferred-numbering pass for `series`: assign gap-free serials to all
19759
+ * records whose store-commit-time interval has settled, in store-time order.
19760
+ * Returns the assignments made. See {@link sequence} / `withDeferredNumbering`.
19761
+ */
19762
+ async runNumberingPass(series) {
19763
+ return this.deferred().runPass(series);
19764
+ }
17843
19765
  async compact(options = {}) {
17844
19766
  return runCompaction({
17845
19767
  adapter: this.adapter,
@@ -17864,6 +19786,48 @@ var Vault = class {
17864
19786
  }
17865
19787
  }, options);
17866
19788
  }
19789
+ /**
19790
+ * Sweep records eligible by their collection's `archive` policy into the
19791
+ * cold archive store. Relocation is envelope-level (no re-encryption) and
19792
+ * bypasses guards + materialized-view dispatch, so issued/immutable
19793
+ * records over a sealed period can be archived without recomputing
19794
+ * finalized aggregates. A `legalHold` predicate blocks archival.
19795
+ * Requires `archiveStrategy: withArchive({ store })` in `createNoydb`.
19796
+ */
19797
+ async archive(options = {}) {
19798
+ return runArchive(this._archiveContext(), options);
19799
+ }
19800
+ /** Relocate one archived record back to the primary store. Returns false if it was not archived. */
19801
+ async restore(collection, id) {
19802
+ return runRestore(this._archiveContext(), collection, id);
19803
+ }
19804
+ /** List archived record ids for a collection (or all collections with an archive policy). */
19805
+ async listArchived(collection) {
19806
+ return runListArchived(this._archiveContext(), collection);
19807
+ }
19808
+ _archiveContext() {
19809
+ const strategy = this.archiveStrategy;
19810
+ if (!strategy) {
19811
+ throw new Error(
19812
+ "vault.archive/restore/listArchived require `archiveStrategy: withArchive({ store })` in createNoydb"
19813
+ );
19814
+ }
19815
+ const archiveStore = strategy.store;
19816
+ return {
19817
+ vaultId: this.name,
19818
+ archiveStore,
19819
+ collectionsWithPolicy: () => [...this.archiveRegistry.keys()],
19820
+ getPolicy: (c) => this.archiveRegistry.get(c) ?? null,
19821
+ listRecordIds: (c) => this.adapter.list(this.name, c),
19822
+ getRecord: async (c, id) => await this.collection(c).get(id, { locale: "raw" }),
19823
+ getEnvelope: (c, id) => this.adapter.get(this.name, c, id),
19824
+ removeFromPrimary: (c, id) => this.collection(c)._internalDelete(id),
19825
+ restoreToPrimary: async (c, id, env) => {
19826
+ await this.adapter.put(this.name, c, id, env);
19827
+ await this.collection(c)._invalidateCacheEntry(id);
19828
+ }
19829
+ };
19830
+ }
17867
19831
  exportBlobs(options = {}) {
17868
19832
  this.assertCanExport("plaintext", "blob");
17869
19833
  return createExportBlobsHandle(
@@ -18562,7 +20526,7 @@ var Vault = class {
18562
20526
  *
18563
20527
  * @internal
18564
20528
  */
18565
- async _logConsent(op, collection, recordId2) {
20529
+ async _logConsent(op, collection, recordId3) {
18566
20530
  const ctx = this.consentContext;
18567
20531
  if (!ctx) return;
18568
20532
  await this.consentStrategy.write(
@@ -18575,7 +20539,7 @@ var Vault = class {
18575
20539
  consentHash: ctx.consentHash,
18576
20540
  op,
18577
20541
  collection,
18578
- recordId: recordId2
20542
+ recordId: recordId3
18579
20543
  },
18580
20544
  this.getDEK
18581
20545
  );
@@ -18758,14 +20722,14 @@ var Vault = class {
18758
20722
  * the HKDF derivation, record-id composition, and batch logic so the
18759
20723
  * grantor doesn't touch this method directly.
18760
20724
  */
18761
- async writeMagicLinkGrant(contentKey, grantKek, recordId2, opts) {
20725
+ async writeMagicLinkGrant(contentKey, grantKek, recordId3, opts) {
18762
20726
  return writeMagicLinkGrant(
18763
20727
  this.adapter,
18764
20728
  this.name,
18765
20729
  this.keyring,
18766
20730
  contentKey,
18767
20731
  grantKek,
18768
- recordId2,
20732
+ recordId3,
18769
20733
  opts
18770
20734
  );
18771
20735
  }
@@ -19125,7 +21089,7 @@ var Vault = class {
19125
21089
  }
19126
21090
  }
19127
21091
  const internalSnapshot = {};
19128
- for (const internalName of [LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, SCHEMAS_COLLECTION]) {
21092
+ for (const internalName of [LEDGER_COLLECTION, LEDGER_DELTAS_COLLECTION, SCHEMAS_COLLECTION, SEQUENCE_COLLECTION]) {
19129
21093
  const ids = await this.adapter.list(this.name, internalName);
19130
21094
  if (ids.length === 0) continue;
19131
21095
  const records = {};
@@ -20601,6 +22565,7 @@ var Noydb = class {
20601
22565
  writeRelay;
20602
22566
  /** Per-vault policy enforcers. */
20603
22567
  policyEnforcers = /* @__PURE__ */ new Map();
22568
+ vaultTemplates = /* @__PURE__ */ new Map();
20604
22569
  txStrategy;
20605
22570
  sessionStrategy;
20606
22571
  syncStrategy;
@@ -20670,7 +22635,7 @@ var Noydb = class {
20670
22635
  await registry.runChecks(e.collection, incoming, ctx);
20671
22636
  const { GuardExecutor: GuardExecutor2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
20672
22637
  for (const g of guards) {
20673
- await GuardExecutor2.checkFrozenFields(g, e.docId, existing, incoming);
22638
+ await GuardExecutor2.checkFrozenFields(g, e.docId, existing, incoming, e.computedFieldNames);
20674
22639
  }
20675
22640
  });
20676
22641
  this.subsystemBus.registerGate("beforeDelete", async (e) => {
@@ -20849,6 +22814,7 @@ var Noydb = class {
20849
22814
  syncAdapter: targets.length > 0 ? targets[0].store : void 0,
20850
22815
  historyConfig: this.options.history,
20851
22816
  ...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
22817
+ ...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
20852
22818
  ...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
20853
22819
  ...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
20854
22820
  ...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
@@ -20859,6 +22825,7 @@ var Noydb = class {
20859
22825
  ...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
20860
22826
  ...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
20861
22827
  ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
22828
+ ...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
20862
22829
  locale: opts?.locale,
20863
22830
  // Thread the translator hook so Collection.put() can invoke it
20864
22831
  plaintextTranslator: this.options.plaintextTranslator ? (text, from, to, field, collection) => this.invokeTranslator(text, from, to, field, collection) : void 0,
@@ -20902,6 +22869,7 @@ var Noydb = class {
20902
22869
  emitter: this.emitter,
20903
22870
  historyConfig: this.options.history,
20904
22871
  ...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
22872
+ ...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
20905
22873
  ...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
20906
22874
  ...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
20907
22875
  ...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
@@ -20911,7 +22879,8 @@ var Noydb = class {
20911
22879
  ...this.options.historyStrategy !== void 0 ? { historyStrategy: this.options.historyStrategy } : {},
20912
22880
  ...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
20913
22881
  ...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
20914
- ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {}
22882
+ ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
22883
+ ...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {}
20915
22884
  });
20916
22885
  this.vaultCache.set(name, comp2);
20917
22886
  return comp2;
@@ -20930,6 +22899,7 @@ var Noydb = class {
20930
22899
  encrypted: true,
20931
22900
  historyConfig: this.options.history,
20932
22901
  ...this.options.blobStrategy !== void 0 ? { blobStrategy: this.options.blobStrategy } : {},
22902
+ ...this.options.archiveStrategy !== void 0 ? { archiveStrategy: this.options.archiveStrategy } : {},
20933
22903
  ...this.options.indexStrategy !== void 0 ? { indexStrategy: this.options.indexStrategy } : {},
20934
22904
  ...this.options.aggregateStrategy !== void 0 ? { aggregateStrategy: this.options.aggregateStrategy } : {},
20935
22905
  ...this.options.crdtStrategy !== void 0 ? { crdtStrategy: this.options.crdtStrategy } : {},
@@ -20940,6 +22910,7 @@ var Noydb = class {
20940
22910
  ...this.options.i18nStrategy !== void 0 ? { i18nStrategy: this.options.i18nStrategy } : {},
20941
22911
  ...this.options.syncStrategy !== void 0 ? { syncStrategy: this.options.syncStrategy } : {},
20942
22912
  ...this.options.guardStrategies !== void 0 ? { guardStrategies: this.options.guardStrategies } : {},
22913
+ ...this.options.numbering !== void 0 ? { numberingConfigs: this.options.numbering } : {},
20943
22914
  emitter: this.emitter
20944
22915
  });
20945
22916
  this.vaultCache.set(name, comp);
@@ -21244,6 +23215,61 @@ var Noydb = class {
21244
23215
  }
21245
23216
  return results;
21246
23217
  }
23218
+ /**
23219
+ * Register a shard schema blueprint. `createShard` / `openVaultGroup`
23220
+ * stamp shards from the named template. See the MVF design spec.
23221
+ */
23222
+ withVaultTemplate(name, template) {
23223
+ this.vaultTemplates.set(name, template);
23224
+ }
23225
+ /**
23226
+ * Open a VaultGroup — transparent routing over per-partition shard
23227
+ * vaults, with shard discovery backed by the supplied `vault-registry`
23228
+ * collection.
23229
+ */
23230
+ async openVaultGroup(name, opts) {
23231
+ if (this.closed) throw new ValidationError("Instance is closed");
23232
+ if (name === STATE_VAULT_NAME) throw new ReservedVaultNameError(name);
23233
+ const template = this.vaultTemplates.get(opts.sharding.vaultTemplate);
23234
+ if (!template) throw new VaultTemplateNotFoundError(opts.sharding.vaultTemplate);
23235
+ const { VaultGroup: VaultGroup2 } = await Promise.resolve().then(() => (init_vault_group(), vault_group_exports));
23236
+ const { StateManagementVault: StateManagementVault2 } = await Promise.resolve().then(() => (init_state_vault(), state_vault_exports));
23237
+ const stateVault = opts.registry ? void 0 : await StateManagementVault2.open(this);
23238
+ const registry = opts.registry ?? stateVault.registry;
23239
+ const group = new VaultGroup2(this, name, registry, opts.sharding, template);
23240
+ if (stateVault) {
23241
+ group._attachStateVault(stateVault);
23242
+ await stateVault.recordManifest(opts.sharding.vaultTemplate, template);
23243
+ try {
23244
+ await stateVault.appendEvent({
23245
+ type: "manifest-recorded",
23246
+ group: name,
23247
+ templateName: opts.sharding.vaultTemplate,
23248
+ version: template.version
23249
+ });
23250
+ await stateVault.appendEvent({ type: "group-opened", group: name });
23251
+ } catch {
23252
+ }
23253
+ }
23254
+ return group;
23255
+ }
23256
+ /**
23257
+ * Open the reserved StateManagement control-plane vault (registry +
23258
+ * schema-manifest + deployment-events). Lazy-loaded so the federation
23259
+ * chunk stays out of the core graph until used.
23260
+ */
23261
+ async openStateManagementVault() {
23262
+ if (this.closed) throw new ValidationError("Instance is closed");
23263
+ const { StateManagementVault: StateManagementVault2 } = await Promise.resolve().then(() => (init_state_vault(), state_vault_exports));
23264
+ return StateManagementVault2.open(this);
23265
+ }
23266
+ /**
23267
+ * @internal — true when an encrypted shard vault is provisioned
23268
+ * (its keyring exists in the store).
23269
+ */
23270
+ async _shardVaultProvisioned(vaultId) {
23271
+ return (await this.options.store.list(vaultId, "_keyring")).length > 0;
23272
+ }
21247
23273
  /**
21248
23274
  * Change the current user's passphrase for a vault.
21249
23275
  *
@@ -23506,6 +25532,50 @@ function withGuard(strategy) {
23506
25532
  };
23507
25533
  }
23508
25534
 
25535
+ // src/guards/immutable-guard.ts
25536
+ init_errors();
25537
+ function recordId2(record) {
25538
+ const id = record?.id;
25539
+ return typeof id === "string" ? id : "";
25540
+ }
25541
+ function immutableGuard(config) {
25542
+ const { collection, after, appendOnly, amendmentRoles } = config;
25543
+ if (appendOnly && after !== void 0) {
25544
+ throw new ValidationError("immutableGuard: `after` and `appendOnly` are mutually exclusive");
25545
+ }
25546
+ if (!appendOnly && after === void 0) {
25547
+ throw new ValidationError("immutableGuard: provide `after` or `appendOnly: true`");
25548
+ }
25549
+ const isImmutable = appendOnly ? () => true : after;
25550
+ const reason = appendOnly ? "append-only collection" : "record is immutable after issue";
25551
+ const spec = {
25552
+ collection,
25553
+ // Block updates to an already-immutable record. Inserts (existing
25554
+ // null) and the transition write that first makes the record
25555
+ // immutable are allowed — `after` reads the prior state.
25556
+ check: (incoming, ctx) => {
25557
+ if (ctx.existing !== null && isImmutable(ctx.existing)) {
25558
+ throw new RecordLockedError(collection, recordId2(incoming), reason);
25559
+ }
25560
+ },
25561
+ // Block deletes of an immutable record.
25562
+ onDelete: (existing) => {
25563
+ if (isImmutable(existing)) {
25564
+ throw new RecordLockedError(collection, recordId2(existing), reason);
25565
+ }
25566
+ },
25567
+ // The authorized override: inside an amendment transaction the
25568
+ // check/onDelete are skipped and the change is ledgered. No extra
25569
+ // invariant — the amendment itself is the sanctioned exception.
25570
+ amendment: {
25571
+ roles: amendmentRoles ?? ["admin", "owner"],
25572
+ invariant: () => {
25573
+ }
25574
+ }
25575
+ };
25576
+ return withGuard(spec);
25577
+ }
25578
+
23509
25579
  // src/derivations/with-derivation.ts
23510
25580
  init_errors();
23511
25581
  function withDerivation(spec) {
@@ -23663,6 +25733,10 @@ function withOverlayedView(spec) {
23663
25733
  init_errors();
23664
25734
  init_errors();
23665
25735
 
25736
+ // src/money/index.ts
25737
+ init_descriptor();
25738
+ init_iso4217();
25739
+
23666
25740
  // src/i18n/script.ts
23667
25741
  init_errors();
23668
25742
  var LATIN_BASE = /* @__PURE__ */ new Set([
@@ -24448,6 +26522,7 @@ function shortJSON(value) {
24448
26522
  CollectionFrame,
24449
26523
  CollectionIndexes,
24450
26524
  CollectionInstant,
26525
+ ComputedFieldError,
24451
26526
  ConflictError,
24452
26527
  CrossJoinSourceUnknownError,
24453
26528
  CrossJoinTooLargeError,
@@ -24511,6 +26586,9 @@ function shortJSON(value) {
24511
26586
  MemorySealingKeyProvider,
24512
26587
  MigrationRequiredError,
24513
26588
  MissingTranslationError,
26589
+ MoneyCurrencyError,
26590
+ MoneyPrecisionError,
26591
+ MoneyUnsupportedError,
24514
26592
  NOYDB_BACKUP_VERSION,
24515
26593
  NOYDB_BUNDLE_FORMAT_VERSION,
24516
26594
  NOYDB_BUNDLE_MAGIC,
@@ -24524,6 +26602,7 @@ function shortJSON(value) {
24524
26602
  NotFoundError,
24525
26603
  Noydb,
24526
26604
  NoydbError,
26605
+ NumberingUncertaintyError,
24527
26606
  OverlayBaseIsVirtualError,
24528
26607
  OverlayCollectionUnavailableError,
24529
26608
  OverlayIdMismatchError,
@@ -24553,8 +26632,10 @@ function shortJSON(value) {
24553
26632
  RefRegistry,
24554
26633
  RefScopeError,
24555
26634
  ReservedCollectionNameError,
26635
+ ReservedVaultNameError,
24556
26636
  SCHEMAS_COLLECTION,
24557
26637
  SEALED_PASSPHRASE_RECORD_ID,
26638
+ STATE_VAULT_NAME,
24558
26639
  STRICT_POLICY,
24559
26640
  SYNC_CREDENTIALS_COLLECTION,
24560
26641
  ScanBuilder,
@@ -24563,9 +26644,13 @@ function shortJSON(value) {
24563
26644
  SchemaUpdateError,
24564
26645
  SchemaValidationError,
24565
26646
  ScriptViolationError,
26647
+ SequenceContentionError,
26648
+ SequenceOfflineError,
26649
+ SequenceStore,
24566
26650
  SessionExpiredError,
24567
26651
  SessionNotFoundError,
24568
26652
  SessionPolicyError,
26653
+ ShardProvisioningError,
24569
26654
  SnapshotNotFoundError,
24570
26655
  StoreCapabilityError,
24571
26656
  SyncEngine,
@@ -24581,6 +26666,7 @@ function shortJSON(value) {
24581
26666
  USER_ENVELOPE_COLLECTION,
24582
26667
  USER_ENVELOPE_MAX_BYTES,
24583
26668
  UniqueConstraintError,
26669
+ UnknownShardError,
24584
26670
  UnsupportedIndexOptionError,
24585
26671
  UserApi,
24586
26672
  UserEnvelopeOversizedError,
@@ -24589,6 +26675,7 @@ function shortJSON(value) {
24589
26675
  Vault,
24590
26676
  VaultFrame,
24591
26677
  VaultInstant,
26678
+ VaultTemplateNotFoundError,
24592
26679
  WeakPassphraseError,
24593
26680
  activeSessionCount,
24594
26681
  additiveOnly,
@@ -24645,6 +26732,7 @@ function shortJSON(value) {
24645
26732
  envelopePayloadHash,
24646
26733
  estimateEntropy,
24647
26734
  estimateRecordBytes,
26735
+ evalComputedFields,
24648
26736
  evaluateClause,
24649
26737
  evaluateExportCapability,
24650
26738
  evaluateFieldClause,
@@ -24661,6 +26749,7 @@ function shortJSON(value) {
24661
26749
  hasRecoveryEnrolled,
24662
26750
  hashEntry,
24663
26751
  i18nText,
26752
+ immutableGuard,
24664
26753
  inferScripts,
24665
26754
  isDevUnlockActive,
24666
26755
  isDictCollectionName,
@@ -24668,6 +26757,7 @@ function shortJSON(value) {
24668
26757
  isDiscriminant,
24669
26758
  isI18nTextDescriptor,
24670
26759
  isMagicLinkGrantExpired,
26760
+ isMoneyDescriptor,
24671
26761
  isPreCompressed,
24672
26762
  isPublicEnvelope,
24673
26763
  isSessionAlive,
@@ -24699,6 +26789,7 @@ function shortJSON(value) {
24699
26789
  mintPaperRecoveryEntry,
24700
26790
  mintShamirRecoveryEntry,
24701
26791
  mintWrappedDeksBlob,
26792
+ money,
24702
26793
  paddedIndex,
24703
26794
  parseBytes,
24704
26795
  parseIndex,
@@ -24739,6 +26830,7 @@ function shortJSON(value) {
24739
26830
  saveShamirRecoveryEntries,
24740
26831
  saveUserEnvelope,
24741
26832
  saveVaultPolicy,
26833
+ scaleForCurrency,
24742
26834
  sha256Hex,
24743
26835
  sum,
24744
26836
  unwrapDeksFromBlob,
@@ -24752,8 +26844,10 @@ function shortJSON(value) {
24752
26844
  validateSchemaOutput,
24753
26845
  validateSessionPolicy,
24754
26846
  visibilityRecordId,
26847
+ withArchive,
24755
26848
  withCache,
24756
26849
  withCircuitBreaker,
26850
+ withDeferredNumbering,
24757
26851
  withDerivation,
24758
26852
  withGuard,
24759
26853
  withHealthCheck,