@noy-db/hub 0.2.0-pre.10 → 0.2.0-pre.12

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 (266) 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 +1468 -19
  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-7CEGU63S.js → chunk-4BHFNKTP.js} +2 -2
  23. package/dist/{chunk-5OEJ6GOT.js → chunk-5ARRXIVR.js} +2 -2
  24. package/dist/{chunk-DRXIZOFV.js → chunk-6AD5TBF2.js} +31 -3
  25. package/dist/chunk-6AD5TBF2.js.map +1 -0
  26. package/dist/{chunk-YM7LFCG7.js → chunk-6BYBVRZU.js} +3 -3
  27. package/dist/{chunk-5IXJGFF2.js → chunk-7JJE3OMJ.js} +5 -5
  28. package/dist/{chunk-HHOO7HGH.js → chunk-7LVRIW4G.js} +4 -4
  29. package/dist/{chunk-O6EJ6WTI.js → chunk-AGRC7NQQ.js} +62 -2
  30. package/dist/chunk-AGRC7NQQ.js.map +1 -0
  31. package/dist/{chunk-IMYKDWB4.js → chunk-B7GGYNKQ.js} +2 -2
  32. package/dist/{chunk-BDV7INMP.js → chunk-BXOUVUES.js} +4 -4
  33. package/dist/{chunk-FO3UEG4S.js → chunk-C2CIIQRG.js} +2 -2
  34. package/dist/{chunk-ZROPXHJY.js → chunk-CHBXWJZQ.js} +2 -2
  35. package/dist/{chunk-RYIL3PI2.js → chunk-CILT6V3V.js} +2 -2
  36. package/dist/{chunk-PXTQPZO4.js → chunk-DLTU4M2I.js} +6 -6
  37. package/dist/{chunk-GAUEWM7D.js → chunk-EKNUBIIQ.js} +4 -4
  38. package/dist/{chunk-HQSQC2XL.js → chunk-GFPR7VJS.js} +17 -4
  39. package/dist/chunk-GFPR7VJS.js.map +1 -0
  40. package/dist/{chunk-6EOXTJS2.js → chunk-HBAJDI2N.js} +5 -5
  41. package/dist/{chunk-PVUUIWHY.js → chunk-HLGDYFWR.js} +10 -3
  42. package/dist/chunk-HLGDYFWR.js.map +1 -0
  43. package/dist/{chunk-RRNA5GKT.js → chunk-IEPT7HVP.js} +2 -2
  44. package/dist/{chunk-R233SLY3.js → chunk-IUBHXEPJ.js} +2 -2
  45. package/dist/{chunk-CH22FZHT.js → chunk-L6BYRCYB.js} +2 -2
  46. package/dist/{chunk-5OX6XVNS.js → chunk-LOA2VCMS.js} +5 -5
  47. package/dist/{chunk-BB27JMWB.js → chunk-LSEW3ZZ2.js} +3 -3
  48. package/dist/{chunk-Y26YV5R3.js → chunk-LWSD4QPT.js} +3 -3
  49. package/dist/{chunk-WIRRPTFH.js → chunk-LYNNZEQD.js} +1 -1
  50. package/dist/chunk-LYNNZEQD.js.map +1 -0
  51. package/dist/{chunk-26NK23DZ.js → chunk-M45IRXDM.js} +3 -3
  52. package/dist/{chunk-CXJG63MA.js → chunk-NP6EZT44.js} +20 -6
  53. package/dist/chunk-NP6EZT44.js.map +1 -0
  54. package/dist/{chunk-GNHAC43Q.js → chunk-O53RIZCC.js} +5 -5
  55. package/dist/chunk-OPDTLHFA.js +783 -0
  56. package/dist/chunk-OPDTLHFA.js.map +1 -0
  57. package/dist/{chunk-LSTBFLL2.js → chunk-P3Z5Y2TS.js} +2 -2
  58. package/dist/{chunk-QSOYKKMD.js → chunk-P4EDT5ZP.js} +2 -2
  59. package/dist/{chunk-PC6ZEDRL.js → chunk-RHQYVHFH.js} +2 -2
  60. package/dist/{chunk-3LPV6BXR.js → chunk-RRDWXNBQ.js} +3 -3
  61. package/dist/{chunk-4CLICFEY.js → chunk-SJJQKNMP.js} +4 -4
  62. package/dist/{chunk-TY32C732.js → chunk-SZ4N3IL5.js} +5 -5
  63. package/dist/{chunk-4USCAEDT.js → chunk-TMHJEYW7.js} +502 -60
  64. package/dist/chunk-TMHJEYW7.js.map +1 -0
  65. package/dist/{chunk-2N62W5YP.js → chunk-UA6G45ME.js} +3 -3
  66. package/dist/{chunk-6YLPHBKR.js → chunk-UOC7JMZO.js} +13 -4
  67. package/dist/chunk-UOC7JMZO.js.map +1 -0
  68. package/dist/{chunk-DAP2XL7Q.js → chunk-VOXMU6LB.js} +2 -2
  69. package/dist/chunk-WNRGOVLG.js +64 -0
  70. package/dist/chunk-WNRGOVLG.js.map +1 -0
  71. package/dist/{chunk-DJRWA3Q5.js → chunk-WUG3E423.js} +4 -4
  72. package/dist/{chunk-PM3QYWUU.js → chunk-XHM2SARW.js} +3 -3
  73. package/dist/{chunk-RC6SU5NO.js → chunk-XSIFXX54.js} +2 -2
  74. package/dist/{chunk-CXFOITNS.js → chunk-ZC7MNVYN.js} +2 -2
  75. package/dist/{chunk-6T2UDBKG.js → chunk-ZCFS7U4J.js} +2 -2
  76. package/dist/consent/index.cjs.map +1 -1
  77. package/dist/consent/index.d.cts +4 -4
  78. package/dist/consent/index.d.ts +4 -4
  79. package/dist/consent/index.js +3 -3
  80. package/dist/{crypto-2CRLG4F4.js → crypto-AJB72OKN.js} +3 -3
  81. package/dist/{delegation-ZTRT2PRV.js → delegation-6FCWDRUS.js} +5 -5
  82. package/dist/derivations/index.cjs.map +1 -1
  83. package/dist/derivations/index.d.cts +5 -5
  84. package/dist/derivations/index.d.ts +5 -5
  85. package/dist/derivations/index.js +4 -4
  86. package/dist/{dev-unlock-BOEYl1xl.d.ts → dev-unlock-D3mpVFRc.d.ts} +1 -1
  87. package/dist/{dev-unlock-AglVnkPY.d.cts → dev-unlock-ckqa_Nso.d.cts} +1 -1
  88. package/dist/executor-7KSCEIFA.js +8 -0
  89. package/dist/executor-D2QMNGRJ.js +8 -0
  90. package/dist/executor-O5AZK7UW.js +11 -0
  91. package/dist/{fanout-sidecar-OKPMMPLG.js → fanout-sidecar-ZSKEQ6NI.js} +2 -2
  92. package/dist/guards/index.cjs +53 -1
  93. package/dist/guards/index.cjs.map +1 -1
  94. package/dist/guards/index.d.cts +12 -6
  95. package/dist/guards/index.d.ts +12 -6
  96. package/dist/guards/index.js +5 -3
  97. package/dist/{hash-B9m3_fhj.d.ts → hash-CTZVkXLx.d.ts} +1 -1
  98. package/dist/{hash-RVqz2zi8.d.cts → hash-rDSSd_oW.d.cts} +1 -1
  99. package/dist/history/index.cjs.map +1 -1
  100. package/dist/history/index.d.cts +5 -5
  101. package/dist/history/index.d.ts +5 -5
  102. package/dist/history/index.js +5 -5
  103. package/dist/i18n/index.cjs.map +1 -1
  104. package/dist/i18n/index.d.cts +4 -4
  105. package/dist/i18n/index.d.ts +4 -4
  106. package/dist/i18n/index.js +6 -6
  107. package/dist/immutable-guard-C51vAHuh.d.cts +67 -0
  108. package/dist/immutable-guard-DyD0qg2k.d.ts +67 -0
  109. package/dist/index-CkFHr4OP.d.ts +1190 -0
  110. package/dist/index-Cmop06zJ.d.cts +1190 -0
  111. package/dist/index.cjs +1636 -61
  112. package/dist/index.cjs.map +1 -1
  113. package/dist/index.d.cts +46 -13
  114. package/dist/index.d.ts +46 -13
  115. package/dist/index.js +76 -44
  116. package/dist/index.js.map +1 -1
  117. package/dist/indexing/index.cjs.map +1 -1
  118. package/dist/indexing/index.js +2 -2
  119. package/dist/issue-YIYG4OW5.js +12 -0
  120. package/dist/{ledger-O7FXOG3D.js → ledger-5JMVF7PY.js} +5 -5
  121. package/dist/materialized-views/index.cjs.map +1 -1
  122. package/dist/materialized-views/index.d.cts +5 -6
  123. package/dist/materialized-views/index.d.ts +5 -6
  124. package/dist/materialized-views/index.js +6 -6
  125. package/dist/noydb-D5SLAJ6V.js +34 -0
  126. package/dist/overlay-views/index.cjs.map +1 -1
  127. package/dist/overlay-views/index.d.cts +5 -5
  128. package/dist/overlay-views/index.d.ts +5 -5
  129. package/dist/overlay-views/index.js +4 -4
  130. package/dist/periods/index.cjs.map +1 -1
  131. package/dist/periods/index.d.cts +4 -4
  132. package/dist/periods/index.d.ts +4 -4
  133. package/dist/periods/index.js +5 -5
  134. package/dist/{public-envelope-HMYHZIRH.js → public-envelope-PFLZI5MO.js} +4 -4
  135. package/dist/query/index.cjs +293 -10
  136. package/dist/query/index.cjs.map +1 -1
  137. package/dist/query/index.d.cts +2 -2
  138. package/dist/query/index.d.ts +2 -2
  139. package/dist/query/index.js +4 -4
  140. package/dist/registry-BVQ5ITMF.js +8 -0
  141. package/dist/registry-JLP3QOLD.js +8 -0
  142. package/dist/{registry-ST2VNFZC.js → registry-NCY445U5.js} +3 -3
  143. package/dist/{revoke-S6JMSLUN.js → revoke-7RLGQWZ7.js} +6 -6
  144. package/dist/session/index.cjs.map +1 -1
  145. package/dist/session/index.d.cts +5 -5
  146. package/dist/session/index.d.ts +5 -5
  147. package/dist/session/index.js +3 -3
  148. package/dist/shadow/index.cjs.map +1 -1
  149. package/dist/shadow/index.d.cts +4 -4
  150. package/dist/shadow/index.d.ts +4 -4
  151. package/dist/shadow/index.js +2 -2
  152. package/dist/{signer-7NPTB3SQ.js → signer-6JF44I4A.js} +5 -5
  153. package/dist/snapshots/index.cjs.map +1 -1
  154. package/dist/snapshots/index.d.cts +4 -4
  155. package/dist/snapshots/index.d.ts +4 -4
  156. package/dist/snapshots/index.js +4 -4
  157. package/dist/{stale-VKXSXJF4.js → stale-UBLP3RJ3.js} +2 -2
  158. package/dist/store/index.cjs.map +1 -1
  159. package/dist/store/index.d.cts +4 -4
  160. package/dist/store/index.d.ts +4 -4
  161. package/dist/store/index.js +2 -2
  162. package/dist/strategy-rtpKDfTC.d.cts +2029 -0
  163. package/dist/strategy-rtpKDfTC.d.ts +2029 -0
  164. package/dist/sync/index.cjs.map +1 -1
  165. package/dist/sync/index.d.cts +3 -3
  166. package/dist/sync/index.d.ts +3 -3
  167. package/dist/sync/index.js +4 -4
  168. package/dist/team/index.cjs.map +1 -1
  169. package/dist/team/index.d.cts +4 -4
  170. package/dist/team/index.d.ts +4 -4
  171. package/dist/team/index.js +8 -8
  172. package/dist/tx/index.cjs +8 -1
  173. package/dist/tx/index.cjs.map +1 -1
  174. package/dist/tx/index.d.cts +4 -4
  175. package/dist/tx/index.d.ts +4 -4
  176. package/dist/tx/index.js +3 -3
  177. package/dist/{types-n2_IfwlQ.d.cts → types-BGwjsDef.d.cts} +520 -6
  178. package/dist/{types-CaNQm4i8.d.ts → types-DRdfwgTG.d.ts} +520 -6
  179. package/dist/{ulid-CLMjmyhG.d.cts → ulid-D4d0Xto3.d.cts} +1 -1
  180. package/dist/{ulid-B9SMWj5i.d.ts → ulid-DOTPZ5_h.d.ts} +1 -1
  181. package/dist/util/index.cjs.map +1 -1
  182. package/dist/util/index.js +1 -1
  183. package/dist/vault-group-Z4KB75ZH.js +450 -0
  184. package/dist/vault-group-Z4KB75ZH.js.map +1 -0
  185. package/dist/{with-derivation-CVIOPTUf.d.ts → with-derivation-B082Y_WQ.d.ts} +1 -1
  186. package/dist/{with-derivation-aKrtS7Jj.d.cts → with-derivation-CB1EdcFF.d.cts} +1 -1
  187. package/dist/{with-materialized-view-C1eA1_T_.d.cts → with-materialized-view-CzRg1Dpr.d.cts} +1 -1
  188. package/dist/{with-materialized-view-DaYaE8-Q.d.ts → with-materialized-view-Dw4SwjKl.d.ts} +1 -1
  189. package/dist/{with-overlayed-view-DleJfKcV.d.cts → with-overlayed-view-C9YFKXzn.d.cts} +1 -1
  190. package/dist/{with-overlayed-view-DQsh2p8H.d.ts → with-overlayed-view-CaCXeW26.d.ts} +1 -1
  191. package/package.json +3 -3
  192. package/dist/chunk-2LPPNWF6.js +0 -340
  193. package/dist/chunk-2LPPNWF6.js.map +0 -1
  194. package/dist/chunk-4USCAEDT.js.map +0 -1
  195. package/dist/chunk-6YLPHBKR.js.map +0 -1
  196. package/dist/chunk-C3WE6UJY.js +0 -19
  197. package/dist/chunk-C3WE6UJY.js.map +0 -1
  198. package/dist/chunk-CXJG63MA.js.map +0 -1
  199. package/dist/chunk-DRXIZOFV.js.map +0 -1
  200. package/dist/chunk-HQSQC2XL.js.map +0 -1
  201. package/dist/chunk-O6EJ6WTI.js.map +0 -1
  202. package/dist/chunk-PVUUIWHY.js.map +0 -1
  203. package/dist/chunk-WIRRPTFH.js.map +0 -1
  204. package/dist/executor-S76VN45G.js +0 -8
  205. package/dist/executor-UCXLIGLW.js +0 -11
  206. package/dist/executor-ZCNZJMGR.js +0 -8
  207. package/dist/index-B8bjExET.d.cts +0 -2434
  208. package/dist/index-DfUbNad8.d.ts +0 -2434
  209. package/dist/issue-3W6IVLKH.js +0 -12
  210. package/dist/noydb-YAZNH5TI.js +0 -34
  211. package/dist/registry-UFIK7CSR.js +0 -8
  212. package/dist/registry-ZGYYSM5I.js +0 -8
  213. package/dist/strategy-CT2LCKAX.d.cts +0 -613
  214. package/dist/strategy-CT2LCKAX.d.ts +0 -613
  215. package/dist/with-guard-DZQbPzoP.d.cts +0 -18
  216. package/dist/with-guard-DseETUrF.d.ts +0 -18
  217. /package/dist/{chunk-7CEGU63S.js.map → chunk-4BHFNKTP.js.map} +0 -0
  218. /package/dist/{chunk-5OEJ6GOT.js.map → chunk-5ARRXIVR.js.map} +0 -0
  219. /package/dist/{chunk-YM7LFCG7.js.map → chunk-6BYBVRZU.js.map} +0 -0
  220. /package/dist/{chunk-5IXJGFF2.js.map → chunk-7JJE3OMJ.js.map} +0 -0
  221. /package/dist/{chunk-HHOO7HGH.js.map → chunk-7LVRIW4G.js.map} +0 -0
  222. /package/dist/{chunk-IMYKDWB4.js.map → chunk-B7GGYNKQ.js.map} +0 -0
  223. /package/dist/{chunk-BDV7INMP.js.map → chunk-BXOUVUES.js.map} +0 -0
  224. /package/dist/{chunk-FO3UEG4S.js.map → chunk-C2CIIQRG.js.map} +0 -0
  225. /package/dist/{chunk-ZROPXHJY.js.map → chunk-CHBXWJZQ.js.map} +0 -0
  226. /package/dist/{chunk-RYIL3PI2.js.map → chunk-CILT6V3V.js.map} +0 -0
  227. /package/dist/{chunk-PXTQPZO4.js.map → chunk-DLTU4M2I.js.map} +0 -0
  228. /package/dist/{chunk-GAUEWM7D.js.map → chunk-EKNUBIIQ.js.map} +0 -0
  229. /package/dist/{chunk-6EOXTJS2.js.map → chunk-HBAJDI2N.js.map} +0 -0
  230. /package/dist/{chunk-RRNA5GKT.js.map → chunk-IEPT7HVP.js.map} +0 -0
  231. /package/dist/{chunk-R233SLY3.js.map → chunk-IUBHXEPJ.js.map} +0 -0
  232. /package/dist/{chunk-CH22FZHT.js.map → chunk-L6BYRCYB.js.map} +0 -0
  233. /package/dist/{chunk-5OX6XVNS.js.map → chunk-LOA2VCMS.js.map} +0 -0
  234. /package/dist/{chunk-BB27JMWB.js.map → chunk-LSEW3ZZ2.js.map} +0 -0
  235. /package/dist/{chunk-Y26YV5R3.js.map → chunk-LWSD4QPT.js.map} +0 -0
  236. /package/dist/{chunk-26NK23DZ.js.map → chunk-M45IRXDM.js.map} +0 -0
  237. /package/dist/{chunk-GNHAC43Q.js.map → chunk-O53RIZCC.js.map} +0 -0
  238. /package/dist/{chunk-LSTBFLL2.js.map → chunk-P3Z5Y2TS.js.map} +0 -0
  239. /package/dist/{chunk-QSOYKKMD.js.map → chunk-P4EDT5ZP.js.map} +0 -0
  240. /package/dist/{chunk-PC6ZEDRL.js.map → chunk-RHQYVHFH.js.map} +0 -0
  241. /package/dist/{chunk-3LPV6BXR.js.map → chunk-RRDWXNBQ.js.map} +0 -0
  242. /package/dist/{chunk-4CLICFEY.js.map → chunk-SJJQKNMP.js.map} +0 -0
  243. /package/dist/{chunk-TY32C732.js.map → chunk-SZ4N3IL5.js.map} +0 -0
  244. /package/dist/{chunk-2N62W5YP.js.map → chunk-UA6G45ME.js.map} +0 -0
  245. /package/dist/{chunk-DAP2XL7Q.js.map → chunk-VOXMU6LB.js.map} +0 -0
  246. /package/dist/{chunk-DJRWA3Q5.js.map → chunk-WUG3E423.js.map} +0 -0
  247. /package/dist/{chunk-PM3QYWUU.js.map → chunk-XHM2SARW.js.map} +0 -0
  248. /package/dist/{chunk-RC6SU5NO.js.map → chunk-XSIFXX54.js.map} +0 -0
  249. /package/dist/{chunk-CXFOITNS.js.map → chunk-ZC7MNVYN.js.map} +0 -0
  250. /package/dist/{chunk-6T2UDBKG.js.map → chunk-ZCFS7U4J.js.map} +0 -0
  251. /package/dist/{crypto-2CRLG4F4.js.map → crypto-AJB72OKN.js.map} +0 -0
  252. /package/dist/{delegation-ZTRT2PRV.js.map → delegation-6FCWDRUS.js.map} +0 -0
  253. /package/dist/{executor-S76VN45G.js.map → executor-7KSCEIFA.js.map} +0 -0
  254. /package/dist/{executor-UCXLIGLW.js.map → executor-D2QMNGRJ.js.map} +0 -0
  255. /package/dist/{executor-ZCNZJMGR.js.map → executor-O5AZK7UW.js.map} +0 -0
  256. /package/dist/{fanout-sidecar-OKPMMPLG.js.map → fanout-sidecar-ZSKEQ6NI.js.map} +0 -0
  257. /package/dist/{issue-3W6IVLKH.js.map → issue-YIYG4OW5.js.map} +0 -0
  258. /package/dist/{ledger-O7FXOG3D.js.map → ledger-5JMVF7PY.js.map} +0 -0
  259. /package/dist/{noydb-YAZNH5TI.js.map → noydb-D5SLAJ6V.js.map} +0 -0
  260. /package/dist/{public-envelope-HMYHZIRH.js.map → public-envelope-PFLZI5MO.js.map} +0 -0
  261. /package/dist/{registry-ST2VNFZC.js.map → registry-BVQ5ITMF.js.map} +0 -0
  262. /package/dist/{registry-UFIK7CSR.js.map → registry-JLP3QOLD.js.map} +0 -0
  263. /package/dist/{registry-ZGYYSM5I.js.map → registry-NCY445U5.js.map} +0 -0
  264. /package/dist/{revoke-S6JMSLUN.js.map → revoke-7RLGQWZ7.js.map} +0 -0
  265. /package/dist/{signer-7NPTB3SQ.js.map → signer-6JF44I4A.js.map} +0 -0
  266. /package/dist/{stale-VKXSXJF4.js.map → stale-UBLP3RJ3.js.map} +0 -0
package/dist/index.js CHANGED
@@ -3,9 +3,10 @@ import {
3
3
  issueDelegation,
4
4
  loadActiveDelegations,
5
5
  revokeDelegation
6
- } from "./chunk-BDV7INMP.js";
6
+ } from "./chunk-BXOUVUES.js";
7
7
  import {
8
8
  Collection,
9
+ ComputedFieldError,
9
10
  DEFAULT_FRESHNESS_MS,
10
11
  ELEVATION_AUDIT_COLLECTION,
11
12
  ElevatedHandle,
@@ -19,6 +20,7 @@ import {
19
20
  RefRegistry,
20
21
  RefScopeError,
21
22
  STRICT_POLICY,
23
+ SequenceStore,
22
24
  UserApi,
23
25
  Vault,
24
26
  checkGate,
@@ -30,6 +32,7 @@ import {
30
32
  describeUserAuth,
31
33
  diagramAuthConfig,
32
34
  estimateRecordBytes,
35
+ evalComputedFields,
33
36
  isZodSchema,
34
37
  loadVaultPolicy,
35
38
  mergePolicy,
@@ -38,8 +41,9 @@ import {
38
41
  ref,
39
42
  saveVaultPolicy,
40
43
  validateSchemaInput,
41
- validateSchemaOutput
42
- } from "./chunk-4USCAEDT.js";
44
+ validateSchemaOutput,
45
+ withArchive
46
+ } from "./chunk-TMHJEYW7.js";
43
47
  import {
44
48
  DEFAULT_PUBLIC_ENVELOPE_SCHEMA,
45
49
  PUBLIC_ENVELOPE_FIELDS,
@@ -50,27 +54,27 @@ import {
50
54
  TxContext,
51
55
  TxVault,
52
56
  runTransaction
53
- } from "./chunk-26NK23DZ.js";
57
+ } from "./chunk-M45IRXDM.js";
54
58
  import {
55
59
  withDerivation
56
- } from "./chunk-DAP2XL7Q.js";
57
- import "./chunk-CH22FZHT.js";
58
- import "./chunk-5OEJ6GOT.js";
60
+ } from "./chunk-VOXMU6LB.js";
61
+ import "./chunk-L6BYRCYB.js";
62
+ import "./chunk-5ARRXIVR.js";
59
63
  import {
60
64
  withMaterializedView
61
- } from "./chunk-ZROPXHJY.js";
62
- import "./chunk-6T2UDBKG.js";
63
- import "./chunk-GAUEWM7D.js";
64
- import "./chunk-FO3UEG4S.js";
65
+ } from "./chunk-CHBXWJZQ.js";
66
+ import "./chunk-ZCFS7U4J.js";
67
+ import "./chunk-EKNUBIIQ.js";
68
+ import "./chunk-C2CIIQRG.js";
65
69
  import {
66
70
  withOverlayedView
67
- } from "./chunk-RC6SU5NO.js";
68
- import "./chunk-PC6ZEDRL.js";
69
- import "./chunk-7CEGU63S.js";
71
+ } from "./chunk-XSIFXX54.js";
72
+ import "./chunk-RHQYVHFH.js";
73
+ import "./chunk-4BHFNKTP.js";
70
74
  import {
71
75
  isDiscriminant
72
76
  } from "./chunk-STNPB3UM.js";
73
- import "./chunk-QSOYKKMD.js";
77
+ import "./chunk-P4EDT5ZP.js";
74
78
  import {
75
79
  mergeCrdtStates,
76
80
  resolveCrdtSnapshot
@@ -85,7 +89,7 @@ import {
85
89
  parseSealedEnvelope,
86
90
  savePersistedSchema,
87
91
  saveSealedPassphrase
88
- } from "./chunk-PM3QYWUU.js";
92
+ } from "./chunk-XHM2SARW.js";
89
93
  import {
90
94
  NOYDB_BUNDLE_FORMAT_VERSION,
91
95
  NOYDB_BUNDLE_MAGIC,
@@ -96,7 +100,7 @@ import {
96
100
  readNoydbBundlePublicEnvelope,
97
101
  resetBrotliSupportCache,
98
102
  writeNoydbBundle
99
- } from "./chunk-BB27JMWB.js";
103
+ } from "./chunk-LSEW3ZZ2.js";
100
104
  import {
101
105
  PUBLIC_ENVELOPE_RECORD_ID,
102
106
  isPublicEnvelope,
@@ -104,28 +108,29 @@ import {
104
108
  readPublicEnvelope,
105
109
  savePublicEnvelope,
106
110
  validatePublicEnvelopeInput
107
- } from "./chunk-2N62W5YP.js";
111
+ } from "./chunk-UA6G45ME.js";
108
112
  import {
109
113
  CONSENT_AUDIT_COLLECTION
110
- } from "./chunk-LSTBFLL2.js";
114
+ } from "./chunk-P3Z5Y2TS.js";
111
115
  import {
112
116
  PERIODS_COLLECTION
113
- } from "./chunk-3LPV6BXR.js";
117
+ } from "./chunk-RRDWXNBQ.js";
114
118
  import "./chunk-UF3BUNQZ.js";
115
119
  import {
120
+ immutableGuard,
116
121
  withGuard
117
- } from "./chunk-C3WE6UJY.js";
122
+ } from "./chunk-WNRGOVLG.js";
118
123
  import "./chunk-A3JMGXPG.js";
119
124
  import "./chunk-UMLVJTYV.js";
120
- import "./chunk-PVUUIWHY.js";
125
+ import "./chunk-HLGDYFWR.js";
121
126
  import {
122
127
  CollectionFrame,
123
128
  VaultFrame
124
- } from "./chunk-RYIL3PI2.js";
129
+ } from "./chunk-CILT6V3V.js";
125
130
  import {
126
131
  enforceScript,
127
132
  inferScripts
128
- } from "./chunk-IMYKDWB4.js";
133
+ } from "./chunk-B7GGYNKQ.js";
129
134
  import {
130
135
  DICT_COLLECTION_PREFIX,
131
136
  DictionaryHandle,
@@ -139,7 +144,7 @@ import {
139
144
  resolveI18nText,
140
145
  resolvePolicy,
141
146
  validateI18nTextValue
142
- } from "./chunk-GNHAC43Q.js";
147
+ } from "./chunk-O53RIZCC.js";
143
148
  import {
144
149
  createBundleStore,
145
150
  routeStore,
@@ -151,7 +156,7 @@ import {
151
156
  withRetry,
152
157
  wrapBundleStore,
153
158
  wrapStore
154
- } from "./chunk-RRNA5GKT.js";
159
+ } from "./chunk-IEPT7HVP.js";
155
160
  import {
156
161
  SYNC_CREDENTIALS_COLLECTION,
157
162
  credentialStatus,
@@ -159,7 +164,7 @@ import {
159
164
  getCredential,
160
165
  listCredentials,
161
166
  putCredential
162
- } from "./chunk-5OX6XVNS.js";
167
+ } from "./chunk-LOA2VCMS.js";
163
168
  import {
164
169
  MAGIC_LINK_CONTENT_INFO_PREFIX,
165
170
  MAGIC_LINK_GRANTS_COLLECTION,
@@ -194,17 +199,17 @@ import {
194
199
  unwrapDeksFromShamirEntry,
195
200
  unwrapMagicLinkGrant,
196
201
  writeMagicLinkGrant
197
- } from "./chunk-PXTQPZO4.js";
202
+ } from "./chunk-DLTU4M2I.js";
198
203
  import {
199
204
  assertTierAccess,
200
205
  dekKey,
201
206
  effectiveClearance
202
- } from "./chunk-CXFOITNS.js";
207
+ } from "./chunk-ZC7MNVYN.js";
203
208
  import {
204
209
  PresenceHandle,
205
210
  SyncEngine,
206
211
  SyncTransaction
207
- } from "./chunk-DJRWA3Q5.js";
212
+ } from "./chunk-WUG3E423.js";
208
213
  import {
209
214
  DIRECTORY_RECORD_ID,
210
215
  USER_ENVELOPE_COLLECTION,
@@ -232,7 +237,7 @@ import {
232
237
  saveUserEnvelope,
233
238
  validatePassphrase,
234
239
  visibilityRecordId
235
- } from "./chunk-HQSQC2XL.js";
240
+ } from "./chunk-GFPR7VJS.js";
236
241
  import {
237
242
  BUNDLE_STORE_POLICY,
238
243
  INDEXED_STORE_POLICY,
@@ -252,7 +257,7 @@ import {
252
257
  revokeAllSessions,
253
258
  revokeSession,
254
259
  validateSessionPolicy
255
- } from "./chunk-Y26YV5R3.js";
260
+ } from "./chunk-LWSD4QPT.js";
256
261
  import {
257
262
  generateULID,
258
263
  isULID
@@ -262,14 +267,14 @@ import {
262
267
  VaultInstant,
263
268
  diff,
264
269
  formatDiff
265
- } from "./chunk-YM7LFCG7.js";
270
+ } from "./chunk-6BYBVRZU.js";
266
271
  import {
267
272
  LEDGER_COLLECTION,
268
273
  LEDGER_DELTAS_COLLECTION,
269
274
  LedgerStore,
270
275
  applyPatch,
271
276
  computePatch
272
- } from "./chunk-4CLICFEY.js";
277
+ } from "./chunk-SJJQKNMP.js";
273
278
  import {
274
279
  canonicalJson,
275
280
  envelopePayloadHash,
@@ -287,7 +292,7 @@ import {
287
292
  buildLiveQuery,
288
293
  executePlan,
289
294
  resetJoinWarnings
290
- } from "./chunk-6YLPHBKR.js";
295
+ } from "./chunk-UOC7JMZO.js";
291
296
  import {
292
297
  CollectionIndexes
293
298
  } from "./chunk-WIBHRONM.js";
@@ -297,7 +302,7 @@ import {
297
302
  max,
298
303
  min,
299
304
  sum
300
- } from "./chunk-CXJG63MA.js";
305
+ } from "./chunk-NP6EZT44.js";
301
306
  import {
302
307
  Aggregation,
303
308
  GROUPBY_MAX_CARDINALITY,
@@ -305,9 +310,15 @@ import {
305
310
  GroupedAggregation,
306
311
  GroupedQuery,
307
312
  GroupedQueryN,
313
+ MoneyCurrencyError,
314
+ MoneyPrecisionError,
315
+ MoneyUnsupportedError,
308
316
  groupAndReduce,
309
- reduceRecords
310
- } from "./chunk-2LPPNWF6.js";
317
+ isMoneyDescriptor,
318
+ money,
319
+ reduceRecords,
320
+ scaleForCurrency
321
+ } from "./chunk-OPDTLHFA.js";
311
322
  import {
312
323
  evaluateClause,
313
324
  evaluateFieldClause,
@@ -324,15 +335,15 @@ import {
324
335
  detectMagic,
325
336
  detectMimeType,
326
337
  isPreCompressed
327
- } from "./chunk-6EOXTJS2.js";
328
- import "./chunk-DRXIZOFV.js";
338
+ } from "./chunk-HBAJDI2N.js";
339
+ import "./chunk-6AD5TBF2.js";
329
340
  import {
330
341
  NOYDB_BACKUP_VERSION,
331
342
  NOYDB_FORMAT_VERSION,
332
343
  NOYDB_KEYRING_VERSION,
333
344
  NOYDB_SYNC_VERSION,
334
345
  createStore
335
- } from "./chunk-WIRRPTFH.js";
346
+ } from "./chunk-LYNNZEQD.js";
336
347
  import {
337
348
  base64ToBuffer,
338
349
  bufferToBase64,
@@ -341,7 +352,7 @@ import {
341
352
  derivePresenceKey,
342
353
  encryptBytes,
343
354
  encryptDeterministic
344
- } from "./chunk-R233SLY3.js";
355
+ } from "./chunk-IUBHXEPJ.js";
345
356
  import {
346
357
  AlreadyElevatedError,
347
358
  AmendmentForbiddenError,
@@ -410,9 +421,12 @@ import {
410
421
  SchemaUpdateError,
411
422
  SchemaValidationError,
412
423
  ScriptViolationError,
424
+ SequenceContentionError,
425
+ SequenceOfflineError,
413
426
  SessionExpiredError,
414
427
  SessionNotFoundError,
415
428
  SessionPolicyError,
429
+ ShardProvisioningError,
416
430
  SnapshotNotFoundError,
417
431
  StoreCapabilityError,
418
432
  TamperedError,
@@ -420,9 +434,11 @@ import {
420
434
  TierNotGrantedError,
421
435
  TranslatorNotConfiguredError,
422
436
  UniqueConstraintError,
437
+ UnknownShardError,
423
438
  UnsupportedIndexOptionError,
424
- ValidationError
425
- } from "./chunk-O6EJ6WTI.js";
439
+ ValidationError,
440
+ VaultTemplateNotFoundError
441
+ } from "./chunk-AGRC7NQQ.js";
426
442
 
427
443
  // src/schema-update/strategies.ts
428
444
  function blindUpdate() {
@@ -648,6 +664,7 @@ export {
648
664
  CollectionFrame,
649
665
  CollectionIndexes,
650
666
  CollectionInstant,
667
+ ComputedFieldError,
651
668
  ConflictError,
652
669
  CrossJoinSourceUnknownError,
653
670
  CrossJoinTooLargeError,
@@ -711,6 +728,9 @@ export {
711
728
  MemorySealingKeyProvider,
712
729
  MigrationRequiredError,
713
730
  MissingTranslationError,
731
+ MoneyCurrencyError,
732
+ MoneyPrecisionError,
733
+ MoneyUnsupportedError,
714
734
  NOYDB_BACKUP_VERSION,
715
735
  NOYDB_BUNDLE_FORMAT_VERSION,
716
736
  NOYDB_BUNDLE_MAGIC,
@@ -763,9 +783,13 @@ export {
763
783
  SchemaUpdateError,
764
784
  SchemaValidationError,
765
785
  ScriptViolationError,
786
+ SequenceContentionError,
787
+ SequenceOfflineError,
788
+ SequenceStore,
766
789
  SessionExpiredError,
767
790
  SessionNotFoundError,
768
791
  SessionPolicyError,
792
+ ShardProvisioningError,
769
793
  SnapshotNotFoundError,
770
794
  StoreCapabilityError,
771
795
  SyncEngine,
@@ -781,6 +805,7 @@ export {
781
805
  USER_ENVELOPE_COLLECTION,
782
806
  USER_ENVELOPE_MAX_BYTES,
783
807
  UniqueConstraintError,
808
+ UnknownShardError,
784
809
  UnsupportedIndexOptionError,
785
810
  UserApi,
786
811
  UserEnvelopeOversizedError,
@@ -789,6 +814,7 @@ export {
789
814
  Vault,
790
815
  VaultFrame,
791
816
  VaultInstant,
817
+ VaultTemplateNotFoundError,
792
818
  WeakPassphraseError,
793
819
  activeSessionCount,
794
820
  additiveOnly,
@@ -845,6 +871,7 @@ export {
845
871
  envelopePayloadHash,
846
872
  estimateEntropy,
847
873
  estimateRecordBytes,
874
+ evalComputedFields,
848
875
  evaluateClause,
849
876
  evaluateExportCapability,
850
877
  evaluateFieldClause,
@@ -861,6 +888,7 @@ export {
861
888
  hasRecoveryEnrolled,
862
889
  hashEntry,
863
890
  i18nText,
891
+ immutableGuard,
864
892
  inferScripts,
865
893
  isDevUnlockActive,
866
894
  isDictCollectionName,
@@ -868,6 +896,7 @@ export {
868
896
  isDiscriminant,
869
897
  isI18nTextDescriptor,
870
898
  isMagicLinkGrantExpired,
899
+ isMoneyDescriptor,
871
900
  isPreCompressed,
872
901
  isPublicEnvelope,
873
902
  isSessionAlive,
@@ -899,6 +928,7 @@ export {
899
928
  mintPaperRecoveryEntry,
900
929
  mintShamirRecoveryEntry,
901
930
  mintWrappedDeksBlob,
931
+ money,
902
932
  paddedIndex,
903
933
  parseBytes,
904
934
  parseIndex,
@@ -939,6 +969,7 @@ export {
939
969
  saveShamirRecoveryEntries,
940
970
  saveUserEnvelope,
941
971
  saveVaultPolicy,
972
+ scaleForCurrency,
942
973
  sha256Hex,
943
974
  sum,
944
975
  unwrapDeksFromBlob,
@@ -952,6 +983,7 @@ export {
952
983
  validateSchemaOutput,
953
984
  validateSessionPolicy,
954
985
  visibilityRecordId,
986
+ withArchive,
955
987
  withCache,
956
988
  withCircuitBreaker,
957
989
  withDerivation,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema-update/strategies.ts","../src/schema-update/cutover.ts","../src/vault-diff.ts"],"sourcesContent":["/** Bundled light update strategies. */\nimport { NonAdditiveSchemaChangeError, SchemaLockedError } from '../errors.js'\nimport type { SchemaUpdateStrategy, SchemaDelta } from './types.js'\n\n/** Allow any schema change. Explicit blind / back-compat. */\nexport function blindUpdate(): SchemaUpdateStrategy {\n return { name: 'blindUpdate', onSchemaDelta: () => ({ action: 'allow' }) }\n}\n\n/** Allow additive changes; reject non-additive ones. The safety backstop. */\nexport function additiveOnly(): SchemaUpdateStrategy {\n return {\n name: 'additiveOnly',\n onSchemaDelta(delta: SchemaDelta) {\n if (delta.kind === 'non-additive') {\n return {\n action: 'reject' as const,\n error: new NonAdditiveSchemaChangeError(\n `Non-additive schema change to \"${delta.collection}\" ` +\n `(added: [${delta.added.join(', ')}], removed: [${delta.removed.join(', ')}], ` +\n `changed: [${delta.changed.map(c => c.field).join(', ')}]). ` +\n `Register a coordinatedCutover() strategy to migrate, or revert the change.`,\n ),\n }\n }\n return { action: 'allow' as const }\n },\n }\n}\n\n/**\n * Reject schema changes. With `fields`, reject only when one of those\n * fields is added/removed/changed; otherwise reject any non-`none` delta.\n */\nexport function lockSchema(opts?: { readonly fields?: readonly string[] }): SchemaUpdateStrategy {\n const fields = opts?.fields\n return {\n name: 'lockSchema',\n onSchemaDelta(delta: SchemaDelta) {\n if (delta.kind === 'none') return { action: 'allow' as const }\n const touched = fields\n ? [...delta.added, ...delta.removed, ...delta.changed.map(c => c.field)].filter(f => fields.includes(f))\n : ['<any>']\n if (touched.length === 0) return { action: 'allow' as const }\n return {\n action: 'reject' as const,\n error: new SchemaLockedError(\n `Schema for \"${delta.collection}\" is locked` +\n (fields ? ` on fields [${fields.join(', ')}] (touched: [${touched.join(', ')}])` : '') +\n `; the change was refused.`,\n ),\n }\n },\n }\n}\n","/** The coordinatedCutover update strategy (single-step — no from/to). */\nimport type { SchemaUpdateStrategy, SchemaDelta, TransformFn } from './types.js'\n\nexport function coordinatedCutover(opts: { readonly transform: TransformFn }): SchemaUpdateStrategy {\n return {\n name: 'coordinatedCutover',\n onSchemaDelta(delta: SchemaDelta) {\n if (delta.kind === 'non-additive') {\n return { action: 'cutover' as const, transform: opts.transform }\n }\n return { action: 'allow' as const }\n },\n }\n}\n","/**\n * Vault-level diff orchestrator.\n *\n * Compares a live `Vault`'s plaintext state against a candidate state\n * (another vault, a plain `{ collection: records[] }` map, or a vault\n * dump JSON) and returns a structured `VaultDiff` plan listing the\n * records that would be added, modified, or deleted to bring the live\n * vault into the candidate's shape.\n *\n * Builds on two existing record-level helpers:\n *\n * 1. `diff(a, b)` from `./history/diff.ts` — emits dot-pathed\n * `DiffEntry[]` with `type: 'added' | 'removed' | 'changed'` for\n * each changed field of two records. Used here for the\n * `fieldDiffs` of every `modified` entry, and (with empty result)\n * as the default deep-equal check.\n *\n * 2. `Vault.exportStream()` from `./vault.ts` — the canonical\n * decrypt-and-stream-records iterator. Used to walk both sides\n * when the candidate is itself a `Vault`. ACL-scoped: collections\n * the caller can't read silently drop out, the same way every\n * other plaintext-emitting export pipeline filters them.\n *\n * The new orchestration is the **vault-level** enumeration: bucket\n * each record id into added (only in candidate), deleted (only in\n * vault), or modified (in both with field changes); leave the\n * field-level granularity to the existing `diff()`.\n *\n * Use cases:\n *\n * - Import preview (`@noy-db/as-*` `fromString` returns a plan\n * whose body is a `VaultDiff`).\n * - Backup verification (\"does this `.noydb` bundle from yesterday\n * match the current vault?\").\n * - Two-vault reconciliation (\"what's different between Office A\n * and Office B before we sync?\").\n * - Test assertions (golden-file testing with one-liner\n * `expect(plan.summary).toEqual(...)`).\n *\n * @module\n */\n\nimport type { Vault } from './vault.js'\nimport { diff as fieldDiff, type DiffEntry as FieldDiffEntry } from './history/diff.js'\n\n// ─── Public types ──────────────────────────────────────────────────────\n\n/** Per-record entry shape — added and deleted records carry only the record value. */\nexport interface VaultDiffEntry<T = unknown> {\n readonly collection: string\n readonly id: string\n readonly record: T\n}\n\n/** Modified records carry both halves of the diff plus the field-level breakdown. */\nexport interface VaultDiffModifiedEntry<T = unknown> extends VaultDiffEntry<T> {\n /** The record as it stands in the live vault. */\n readonly before: T\n /** Top-level keys whose values differ between `before` and `record`. */\n readonly fieldsChanged: readonly string[]\n /**\n * Field-level diff entries from `diff(before, record)`. Reuses the\n * existing per-record diff helper so consumers can render git-style\n * `path: from → to` rows without re-walking the records.\n */\n readonly fieldDiffs: readonly FieldDiffEntry[]\n}\n\nexport interface VaultDiff<T = unknown> {\n readonly added: readonly VaultDiffEntry<T>[]\n readonly modified: readonly VaultDiffModifiedEntry<T>[]\n readonly deleted: readonly VaultDiffEntry<T>[]\n /** Only populated when `options.includeUnchanged: true`. */\n readonly unchanged: readonly VaultDiffEntry<T>[] | undefined\n readonly summary: {\n readonly add: number\n readonly modify: number\n readonly delete: number\n readonly total: number\n }\n /**\n * Format the diff as a human-readable string.\n *\n * - `'count'` — one line, just the numbers (`12 added · 3 modified · 0 deleted`)\n * - `'one-line'` — count plus a single overview line\n * - `'full'` — count + one row per added/modified/deleted record (default)\n */\n format(opts?: { detail?: 'count' | 'one-line' | 'full' }): string\n}\n\nexport interface DiffOptions {\n /** Restrict the diff to a subset of collections. */\n readonly collections?: readonly string[]\n /** Field on each record that carries its id. Defaults to `'id'`. */\n readonly idKey?: string\n /** Override the default deep-equal check for \"modified vs unchanged\". */\n readonly compareFn?: (a: unknown, b: unknown) => boolean\n /** If true, include unchanged records in the diff (off by default to save memory). */\n readonly includeUnchanged?: boolean\n}\n\n/**\n * Candidate state to diff the vault against:\n *\n * - A `Vault` instance — both sides are walked via `exportStream()`.\n * - A `Record<collection, records[]>` map — same shape `as-json.toObject()`\n * produces. Useful for diffing parsed file content against the live vault.\n * - A `VaultDump` (output of `vault.dump()`) — a JSON string carrying the\n * full vault state. Parsed and reduced to the map shape above.\n */\nexport type DiffCandidate<T = unknown> =\n | Vault\n | Record<string, readonly T[]>\n | string\n\n// ─── Implementation ────────────────────────────────────────────────────\n\n/**\n * Compute the diff between a live vault and a candidate state.\n *\n * Returns a fully buffered `VaultDiff` — no streaming. Memory cost is\n * O(n + m) in the row count of vault + candidate. For documented\n * 1K-50K-record vaults this is fine; a streaming variant lands as a\n * follow-up if a > 100K-record consumer arrives.\n */\nexport async function diffVault<T = unknown>(\n vault: Vault,\n candidate: DiffCandidate<T>,\n options: DiffOptions = {},\n): Promise<VaultDiff<T>> {\n const idKey = options.idKey ?? 'id'\n const filter = options.collections ? new Set(options.collections) : null\n const compareFn =\n options.compareFn ?? ((a: unknown, b: unknown) => fieldDiff(a, b).length === 0)\n\n // Side A — walk the live vault via exportStream(). Each chunk arrives\n // already decrypted and ACL-scoped, so collections the caller can't\n // read silently drop out. exportStream's records are typed `unknown[]`\n // — diffVault is the type-erasure boundary; the caller asserts the\n // record shape via the function's `<T>` generic.\n const live = new Map<string, Map<string, T>>()\n for await (const chunk of vault.exportStream({ granularity: 'collection' })) {\n if (filter && !filter.has(chunk.collection)) continue\n const collection = live.get(chunk.collection) ?? new Map<string, T>()\n for (const record of chunk.records) {\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record as T)\n }\n live.set(chunk.collection, collection)\n }\n\n // Side B — normalise the candidate into the same shape.\n const cand = await normaliseCandidate<T>(candidate, idKey, filter)\n\n // Walk every (collection, id) on either side and bucket.\n const added: VaultDiffEntry<T>[] = []\n const modified: VaultDiffModifiedEntry<T>[] = []\n const deleted: VaultDiffEntry<T>[] = []\n const unchanged: VaultDiffEntry<T>[] | undefined = options.includeUnchanged ? [] : undefined\n\n const collectionNames = new Set([...live.keys(), ...cand.keys()])\n for (const collection of [...collectionNames].sort()) {\n const liveColl = live.get(collection) ?? new Map<string, T>()\n const candColl = cand.get(collection) ?? new Map<string, T>()\n const allIds = new Set([...liveColl.keys(), ...candColl.keys()])\n\n for (const id of [...allIds].sort()) {\n const before = liveColl.get(id)\n const after = candColl.get(id)\n\n if (before === undefined && after !== undefined) {\n added.push({ collection, id, record: after })\n } else if (before !== undefined && after === undefined) {\n deleted.push({ collection, id, record: before })\n } else if (before !== undefined && after !== undefined) {\n if (compareFn(before, after)) {\n unchanged?.push({ collection, id, record: after })\n } else {\n const fieldDiffs = fieldDiff(before, after)\n const fieldsChanged = uniqueTopLevelKeys(fieldDiffs)\n modified.push({\n collection,\n id,\n record: after,\n before,\n fieldsChanged,\n fieldDiffs,\n })\n }\n }\n }\n }\n\n const summary = {\n add: added.length,\n modify: modified.length,\n delete: deleted.length,\n total: added.length + modified.length + deleted.length,\n }\n\n return {\n added,\n modified,\n deleted,\n unchanged,\n summary,\n format(opts) {\n return formatDiff(opts?.detail ?? 'full', { added, modified, deleted, summary })\n },\n }\n}\n\n// ─── Internals ─────────────────────────────────────────────────────────\n\nasync function normaliseCandidate<T>(\n candidate: DiffCandidate<T>,\n idKey: string,\n filter: Set<string> | null,\n): Promise<Map<string, Map<string, T>>> {\n const out = new Map<string, Map<string, T>>()\n\n // Vault instance — duck-type via the exportStream method (matches\n // vault.ts's structural shape without forcing a runtime instanceof check\n // that would import the class and risk circular deps).\n if (\n typeof candidate === 'object' &&\n candidate !== null &&\n 'exportStream' in candidate &&\n typeof (candidate as Vault).exportStream === 'function'\n ) {\n for await (const chunk of (candidate as Vault).exportStream({ granularity: 'collection' })) {\n if (filter && !filter.has(chunk.collection)) continue\n const collection = out.get(chunk.collection) ?? new Map<string, T>()\n for (const record of chunk.records) {\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record as T)\n }\n out.set(chunk.collection, collection)\n }\n return out\n }\n\n // String — assume a vault.dump() JSON string. Parse and reduce to the map shape.\n if (typeof candidate === 'string') {\n let parsed: unknown\n try {\n parsed = JSON.parse(candidate)\n } catch (err) {\n throw new Error(\n `diffVault: candidate string is not valid JSON (${(err as Error).message})`,\n )\n }\n return collectionsFromObject<T>(parsed, idKey, filter)\n }\n\n // Plain object — `Record<collection, records[]>` (same shape as-json.toObject() returns).\n return collectionsFromObject<T>(candidate, idKey, filter)\n}\n\nfunction collectionsFromObject<T>(\n raw: unknown,\n idKey: string,\n filter: Set<string> | null,\n): Map<string, Map<string, T>> {\n const out = new Map<string, Map<string, T>>()\n if (raw === null || typeof raw !== 'object') {\n throw new Error('diffVault: candidate must be a Vault, an object, or a JSON string')\n }\n // A vault dump JSON has a top-level shape like { _compartment, _keyring, <coll>: <records[]> }.\n // We accept both: keys starting with `_` are skipped (they're metadata), the rest are collections.\n for (const [key, value] of Object.entries(raw)) {\n if (key.startsWith('_')) continue\n if (filter && !filter.has(key)) continue\n if (!Array.isArray(value)) continue\n const collection = new Map<string, T>()\n for (const record of value as readonly T[]) {\n if (record === null || typeof record !== 'object') continue\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record)\n }\n out.set(key, collection)\n }\n return out\n}\n\nfunction uniqueTopLevelKeys(diffs: readonly FieldDiffEntry[]): readonly string[] {\n const keys = new Set<string>()\n for (const d of diffs) {\n // path is dot-separated; the top-level key is everything before the\n // first `.` or `[`. (`a.b.c` → `a`, `tags[0]` → `tags`, `(root)` → `(root)`).\n const m = /^[^.[]+/.exec(d.path)\n if (m) keys.add(m[0])\n }\n return [...keys]\n}\n\n/**\n * Pull the id field off a record without going through `String(obj)`,\n * which would emit `[object Object]` for nested objects and silently\n * collapse rows that share the same parent. Only string and number ids\n * are accepted; anything else returns the empty string and the record\n * is skipped at the call site.\n */\nfunction readIdField(record: unknown, idKey: string): string {\n if (record === null || typeof record !== 'object') return ''\n const v = (record as Record<string, unknown>)[idKey]\n if (typeof v === 'string') return v\n if (typeof v === 'number' && Number.isFinite(v)) return String(v)\n return ''\n}\n\ninterface FormatBuckets<T> {\n readonly added: readonly VaultDiffEntry<T>[]\n readonly modified: readonly VaultDiffModifiedEntry<T>[]\n readonly deleted: readonly VaultDiffEntry<T>[]\n readonly summary: VaultDiff<T>['summary']\n}\n\nfunction formatDiff<T>(\n detail: 'count' | 'one-line' | 'full',\n b: FormatBuckets<T>,\n): string {\n const head = `${b.summary.add} added · ${b.summary.modify} modified · ${b.summary.delete} deleted`\n if (detail === 'count') return head\n if (b.summary.total === 0) return head + '\\n(no changes)'\n if (detail === 'one-line') return head\n\n const rows: string[] = [head, '']\n for (const e of b.added) rows.push(`${e.collection}/${e.id}\\tadded`)\n for (const e of b.modified) {\n const fields = e.fieldDiffs\n .map((f) => `${f.path}: ${shortJSON(f.from)} → ${shortJSON(f.to)}`)\n .join(', ')\n rows.push(`${e.collection}/${e.id}\\tmodified\\t${fields}`)\n }\n for (const e of b.deleted) rows.push(`${e.collection}/${e.id}\\tdeleted`)\n return rows.join('\\n')\n}\n\nfunction shortJSON(value: unknown): string {\n if (value === undefined) return 'undefined'\n const s = JSON.stringify(value)\n // JSON.stringify returns string for any JSON value except `undefined`\n // (handled above), `function`, and `symbol`. Fall back to a static\n // tag for those — never let an arbitrary object hit the default\n // stringifier (which the lint rule explicitly bans).\n if (typeof s !== 'string') return '<unrepresentable>'\n return s.length > 60 ? s.slice(0, 57) + '...' : s\n}\n"],"mappings":"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","names":["formatDiff"]}
1
+ {"version":3,"sources":["../src/schema-update/strategies.ts","../src/schema-update/cutover.ts","../src/vault-diff.ts"],"sourcesContent":["/** Bundled light update strategies. */\nimport { NonAdditiveSchemaChangeError, SchemaLockedError } from '../errors.js'\nimport type { SchemaUpdateStrategy, SchemaDelta } from './types.js'\n\n/** Allow any schema change. Explicit blind / back-compat. */\nexport function blindUpdate(): SchemaUpdateStrategy {\n return { name: 'blindUpdate', onSchemaDelta: () => ({ action: 'allow' }) }\n}\n\n/** Allow additive changes; reject non-additive ones. The safety backstop. */\nexport function additiveOnly(): SchemaUpdateStrategy {\n return {\n name: 'additiveOnly',\n onSchemaDelta(delta: SchemaDelta) {\n if (delta.kind === 'non-additive') {\n return {\n action: 'reject' as const,\n error: new NonAdditiveSchemaChangeError(\n `Non-additive schema change to \"${delta.collection}\" ` +\n `(added: [${delta.added.join(', ')}], removed: [${delta.removed.join(', ')}], ` +\n `changed: [${delta.changed.map(c => c.field).join(', ')}]). ` +\n `Register a coordinatedCutover() strategy to migrate, or revert the change.`,\n ),\n }\n }\n return { action: 'allow' as const }\n },\n }\n}\n\n/**\n * Reject schema changes. With `fields`, reject only when one of those\n * fields is added/removed/changed; otherwise reject any non-`none` delta.\n */\nexport function lockSchema(opts?: { readonly fields?: readonly string[] }): SchemaUpdateStrategy {\n const fields = opts?.fields\n return {\n name: 'lockSchema',\n onSchemaDelta(delta: SchemaDelta) {\n if (delta.kind === 'none') return { action: 'allow' as const }\n const touched = fields\n ? [...delta.added, ...delta.removed, ...delta.changed.map(c => c.field)].filter(f => fields.includes(f))\n : ['<any>']\n if (touched.length === 0) return { action: 'allow' as const }\n return {\n action: 'reject' as const,\n error: new SchemaLockedError(\n `Schema for \"${delta.collection}\" is locked` +\n (fields ? ` on fields [${fields.join(', ')}] (touched: [${touched.join(', ')}])` : '') +\n `; the change was refused.`,\n ),\n }\n },\n }\n}\n","/** The coordinatedCutover update strategy (single-step — no from/to). */\nimport type { SchemaUpdateStrategy, SchemaDelta, TransformFn } from './types.js'\n\nexport function coordinatedCutover(opts: { readonly transform: TransformFn }): SchemaUpdateStrategy {\n return {\n name: 'coordinatedCutover',\n onSchemaDelta(delta: SchemaDelta) {\n if (delta.kind === 'non-additive') {\n return { action: 'cutover' as const, transform: opts.transform }\n }\n return { action: 'allow' as const }\n },\n }\n}\n","/**\n * Vault-level diff orchestrator.\n *\n * Compares a live `Vault`'s plaintext state against a candidate state\n * (another vault, a plain `{ collection: records[] }` map, or a vault\n * dump JSON) and returns a structured `VaultDiff` plan listing the\n * records that would be added, modified, or deleted to bring the live\n * vault into the candidate's shape.\n *\n * Builds on two existing record-level helpers:\n *\n * 1. `diff(a, b)` from `./history/diff.ts` — emits dot-pathed\n * `DiffEntry[]` with `type: 'added' | 'removed' | 'changed'` for\n * each changed field of two records. Used here for the\n * `fieldDiffs` of every `modified` entry, and (with empty result)\n * as the default deep-equal check.\n *\n * 2. `Vault.exportStream()` from `./vault.ts` — the canonical\n * decrypt-and-stream-records iterator. Used to walk both sides\n * when the candidate is itself a `Vault`. ACL-scoped: collections\n * the caller can't read silently drop out, the same way every\n * other plaintext-emitting export pipeline filters them.\n *\n * The new orchestration is the **vault-level** enumeration: bucket\n * each record id into added (only in candidate), deleted (only in\n * vault), or modified (in both with field changes); leave the\n * field-level granularity to the existing `diff()`.\n *\n * Use cases:\n *\n * - Import preview (`@noy-db/as-*` `fromString` returns a plan\n * whose body is a `VaultDiff`).\n * - Backup verification (\"does this `.noydb` bundle from yesterday\n * match the current vault?\").\n * - Two-vault reconciliation (\"what's different between Office A\n * and Office B before we sync?\").\n * - Test assertions (golden-file testing with one-liner\n * `expect(plan.summary).toEqual(...)`).\n *\n * @module\n */\n\nimport type { Vault } from './vault.js'\nimport { diff as fieldDiff, type DiffEntry as FieldDiffEntry } from './history/diff.js'\n\n// ─── Public types ──────────────────────────────────────────────────────\n\n/** Per-record entry shape — added and deleted records carry only the record value. */\nexport interface VaultDiffEntry<T = unknown> {\n readonly collection: string\n readonly id: string\n readonly record: T\n}\n\n/** Modified records carry both halves of the diff plus the field-level breakdown. */\nexport interface VaultDiffModifiedEntry<T = unknown> extends VaultDiffEntry<T> {\n /** The record as it stands in the live vault. */\n readonly before: T\n /** Top-level keys whose values differ between `before` and `record`. */\n readonly fieldsChanged: readonly string[]\n /**\n * Field-level diff entries from `diff(before, record)`. Reuses the\n * existing per-record diff helper so consumers can render git-style\n * `path: from → to` rows without re-walking the records.\n */\n readonly fieldDiffs: readonly FieldDiffEntry[]\n}\n\nexport interface VaultDiff<T = unknown> {\n readonly added: readonly VaultDiffEntry<T>[]\n readonly modified: readonly VaultDiffModifiedEntry<T>[]\n readonly deleted: readonly VaultDiffEntry<T>[]\n /** Only populated when `options.includeUnchanged: true`. */\n readonly unchanged: readonly VaultDiffEntry<T>[] | undefined\n readonly summary: {\n readonly add: number\n readonly modify: number\n readonly delete: number\n readonly total: number\n }\n /**\n * Format the diff as a human-readable string.\n *\n * - `'count'` — one line, just the numbers (`12 added · 3 modified · 0 deleted`)\n * - `'one-line'` — count plus a single overview line\n * - `'full'` — count + one row per added/modified/deleted record (default)\n */\n format(opts?: { detail?: 'count' | 'one-line' | 'full' }): string\n}\n\nexport interface DiffOptions {\n /** Restrict the diff to a subset of collections. */\n readonly collections?: readonly string[]\n /** Field on each record that carries its id. Defaults to `'id'`. */\n readonly idKey?: string\n /** Override the default deep-equal check for \"modified vs unchanged\". */\n readonly compareFn?: (a: unknown, b: unknown) => boolean\n /** If true, include unchanged records in the diff (off by default to save memory). */\n readonly includeUnchanged?: boolean\n}\n\n/**\n * Candidate state to diff the vault against:\n *\n * - A `Vault` instance — both sides are walked via `exportStream()`.\n * - A `Record<collection, records[]>` map — same shape `as-json.toObject()`\n * produces. Useful for diffing parsed file content against the live vault.\n * - A `VaultDump` (output of `vault.dump()`) — a JSON string carrying the\n * full vault state. Parsed and reduced to the map shape above.\n */\nexport type DiffCandidate<T = unknown> =\n | Vault\n | Record<string, readonly T[]>\n | string\n\n// ─── Implementation ────────────────────────────────────────────────────\n\n/**\n * Compute the diff between a live vault and a candidate state.\n *\n * Returns a fully buffered `VaultDiff` — no streaming. Memory cost is\n * O(n + m) in the row count of vault + candidate. For documented\n * 1K-50K-record vaults this is fine; a streaming variant lands as a\n * follow-up if a > 100K-record consumer arrives.\n */\nexport async function diffVault<T = unknown>(\n vault: Vault,\n candidate: DiffCandidate<T>,\n options: DiffOptions = {},\n): Promise<VaultDiff<T>> {\n const idKey = options.idKey ?? 'id'\n const filter = options.collections ? new Set(options.collections) : null\n const compareFn =\n options.compareFn ?? ((a: unknown, b: unknown) => fieldDiff(a, b).length === 0)\n\n // Side A — walk the live vault via exportStream(). Each chunk arrives\n // already decrypted and ACL-scoped, so collections the caller can't\n // read silently drop out. exportStream's records are typed `unknown[]`\n // — diffVault is the type-erasure boundary; the caller asserts the\n // record shape via the function's `<T>` generic.\n const live = new Map<string, Map<string, T>>()\n for await (const chunk of vault.exportStream({ granularity: 'collection' })) {\n if (filter && !filter.has(chunk.collection)) continue\n const collection = live.get(chunk.collection) ?? new Map<string, T>()\n for (const record of chunk.records) {\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record as T)\n }\n live.set(chunk.collection, collection)\n }\n\n // Side B — normalise the candidate into the same shape.\n const cand = await normaliseCandidate<T>(candidate, idKey, filter)\n\n // Walk every (collection, id) on either side and bucket.\n const added: VaultDiffEntry<T>[] = []\n const modified: VaultDiffModifiedEntry<T>[] = []\n const deleted: VaultDiffEntry<T>[] = []\n const unchanged: VaultDiffEntry<T>[] | undefined = options.includeUnchanged ? [] : undefined\n\n const collectionNames = new Set([...live.keys(), ...cand.keys()])\n for (const collection of [...collectionNames].sort()) {\n const liveColl = live.get(collection) ?? new Map<string, T>()\n const candColl = cand.get(collection) ?? new Map<string, T>()\n const allIds = new Set([...liveColl.keys(), ...candColl.keys()])\n\n for (const id of [...allIds].sort()) {\n const before = liveColl.get(id)\n const after = candColl.get(id)\n\n if (before === undefined && after !== undefined) {\n added.push({ collection, id, record: after })\n } else if (before !== undefined && after === undefined) {\n deleted.push({ collection, id, record: before })\n } else if (before !== undefined && after !== undefined) {\n if (compareFn(before, after)) {\n unchanged?.push({ collection, id, record: after })\n } else {\n const fieldDiffs = fieldDiff(before, after)\n const fieldsChanged = uniqueTopLevelKeys(fieldDiffs)\n modified.push({\n collection,\n id,\n record: after,\n before,\n fieldsChanged,\n fieldDiffs,\n })\n }\n }\n }\n }\n\n const summary = {\n add: added.length,\n modify: modified.length,\n delete: deleted.length,\n total: added.length + modified.length + deleted.length,\n }\n\n return {\n added,\n modified,\n deleted,\n unchanged,\n summary,\n format(opts) {\n return formatDiff(opts?.detail ?? 'full', { added, modified, deleted, summary })\n },\n }\n}\n\n// ─── Internals ─────────────────────────────────────────────────────────\n\nasync function normaliseCandidate<T>(\n candidate: DiffCandidate<T>,\n idKey: string,\n filter: Set<string> | null,\n): Promise<Map<string, Map<string, T>>> {\n const out = new Map<string, Map<string, T>>()\n\n // Vault instance — duck-type via the exportStream method (matches\n // vault.ts's structural shape without forcing a runtime instanceof check\n // that would import the class and risk circular deps).\n if (\n typeof candidate === 'object' &&\n candidate !== null &&\n 'exportStream' in candidate &&\n typeof (candidate as Vault).exportStream === 'function'\n ) {\n for await (const chunk of (candidate as Vault).exportStream({ granularity: 'collection' })) {\n if (filter && !filter.has(chunk.collection)) continue\n const collection = out.get(chunk.collection) ?? new Map<string, T>()\n for (const record of chunk.records) {\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record as T)\n }\n out.set(chunk.collection, collection)\n }\n return out\n }\n\n // String — assume a vault.dump() JSON string. Parse and reduce to the map shape.\n if (typeof candidate === 'string') {\n let parsed: unknown\n try {\n parsed = JSON.parse(candidate)\n } catch (err) {\n throw new Error(\n `diffVault: candidate string is not valid JSON (${(err as Error).message})`,\n )\n }\n return collectionsFromObject<T>(parsed, idKey, filter)\n }\n\n // Plain object — `Record<collection, records[]>` (same shape as-json.toObject() returns).\n return collectionsFromObject<T>(candidate, idKey, filter)\n}\n\nfunction collectionsFromObject<T>(\n raw: unknown,\n idKey: string,\n filter: Set<string> | null,\n): Map<string, Map<string, T>> {\n const out = new Map<string, Map<string, T>>()\n if (raw === null || typeof raw !== 'object') {\n throw new Error('diffVault: candidate must be a Vault, an object, or a JSON string')\n }\n // A vault dump JSON has a top-level shape like { _compartment, _keyring, <coll>: <records[]> }.\n // We accept both: keys starting with `_` are skipped (they're metadata), the rest are collections.\n for (const [key, value] of Object.entries(raw)) {\n if (key.startsWith('_')) continue\n if (filter && !filter.has(key)) continue\n if (!Array.isArray(value)) continue\n const collection = new Map<string, T>()\n for (const record of value as readonly T[]) {\n if (record === null || typeof record !== 'object') continue\n const id = readIdField(record, idKey)\n if (!id) continue\n collection.set(id, record)\n }\n out.set(key, collection)\n }\n return out\n}\n\nfunction uniqueTopLevelKeys(diffs: readonly FieldDiffEntry[]): readonly string[] {\n const keys = new Set<string>()\n for (const d of diffs) {\n // path is dot-separated; the top-level key is everything before the\n // first `.` or `[`. (`a.b.c` → `a`, `tags[0]` → `tags`, `(root)` → `(root)`).\n const m = /^[^.[]+/.exec(d.path)\n if (m) keys.add(m[0])\n }\n return [...keys]\n}\n\n/**\n * Pull the id field off a record without going through `String(obj)`,\n * which would emit `[object Object]` for nested objects and silently\n * collapse rows that share the same parent. Only string and number ids\n * are accepted; anything else returns the empty string and the record\n * is skipped at the call site.\n */\nfunction readIdField(record: unknown, idKey: string): string {\n if (record === null || typeof record !== 'object') return ''\n const v = (record as Record<string, unknown>)[idKey]\n if (typeof v === 'string') return v\n if (typeof v === 'number' && Number.isFinite(v)) return String(v)\n return ''\n}\n\ninterface FormatBuckets<T> {\n readonly added: readonly VaultDiffEntry<T>[]\n readonly modified: readonly VaultDiffModifiedEntry<T>[]\n readonly deleted: readonly VaultDiffEntry<T>[]\n readonly summary: VaultDiff<T>['summary']\n}\n\nfunction formatDiff<T>(\n detail: 'count' | 'one-line' | 'full',\n b: FormatBuckets<T>,\n): string {\n const head = `${b.summary.add} added · ${b.summary.modify} modified · ${b.summary.delete} deleted`\n if (detail === 'count') return head\n if (b.summary.total === 0) return head + '\\n(no changes)'\n if (detail === 'one-line') return head\n\n const rows: string[] = [head, '']\n for (const e of b.added) rows.push(`${e.collection}/${e.id}\\tadded`)\n for (const e of b.modified) {\n const fields = e.fieldDiffs\n .map((f) => `${f.path}: ${shortJSON(f.from)} → ${shortJSON(f.to)}`)\n .join(', ')\n rows.push(`${e.collection}/${e.id}\\tmodified\\t${fields}`)\n }\n for (const e of b.deleted) rows.push(`${e.collection}/${e.id}\\tdeleted`)\n return rows.join('\\n')\n}\n\nfunction shortJSON(value: unknown): string {\n if (value === undefined) return 'undefined'\n const s = JSON.stringify(value)\n // JSON.stringify returns string for any JSON value except `undefined`\n // (handled above), `function`, and `symbol`. Fall back to a static\n // tag for those — never let an arbitrary object hit the default\n // stringifier (which the lint rule explicitly bans).\n if (typeof s !== 'string') return '<unrepresentable>'\n return s.length > 60 ? s.slice(0, 57) + '...' : s\n}\n"],"mappings":"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","names":["formatDiff"]}