@noy-db/hub 0.2.0-pre.2 → 0.2.0-pre.3

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 (246) hide show
  1. package/dist/aggregate/index.cjs.map +1 -1
  2. package/dist/aggregate/index.js +2 -2
  3. package/dist/attestation/index.cjs.map +1 -1
  4. package/dist/attestation/index.d.cts +2 -2
  5. package/dist/attestation/index.d.ts +2 -2
  6. package/dist/attestation/index.js +6 -6
  7. package/dist/blobs/index.cjs.map +1 -1
  8. package/dist/blobs/index.d.cts +3 -3
  9. package/dist/blobs/index.d.ts +3 -3
  10. package/dist/blobs/index.js +5 -5
  11. package/dist/bundle/index.cjs +1245 -6
  12. package/dist/bundle/index.cjs.map +1 -1
  13. package/dist/bundle/index.d.cts +4 -4
  14. package/dist/bundle/index.d.ts +4 -4
  15. package/dist/bundle/index.js +10 -10
  16. package/dist/{chunk-EUYOGYGV.js → chunk-2EYC3WDT.js} +6 -6
  17. package/dist/{chunk-MUWOSVEP.js → chunk-2XLVPKXG.js} +2 -2
  18. package/dist/{chunk-NWZ3I6R6.js → chunk-4OQWR46B.js} +5 -5
  19. package/dist/{chunk-J4KLMEUL.js → chunk-4UBOTYP5.js} +2 -2
  20. package/dist/{chunk-UND4XIB6.js → chunk-4X2S7PBF.js} +3 -3
  21. package/dist/{chunk-VE6YVP32.js → chunk-5YHWBPOT.js} +2 -2
  22. package/dist/{chunk-7BUTTVMR.js → chunk-6S3LLAQ5.js} +2 -2
  23. package/dist/{chunk-7Z23ZFLV.js → chunk-74JEQFMT.js} +5 -5
  24. package/dist/{chunk-AHPFONIL.js → chunk-75QDHSE4.js} +5 -5
  25. package/dist/{chunk-3XHOCQK4.js → chunk-A6SWRXUQ.js} +2 -2
  26. package/dist/{chunk-PLI5TV7N.js → chunk-BFI3RS42.js} +2 -2
  27. package/dist/{chunk-CXSCDO5T.js → chunk-EMEX37ZN.js} +2 -2
  28. package/dist/{chunk-PEULZC6M.js → chunk-EPK6A3WJ.js} +8 -1
  29. package/dist/chunk-EPK6A3WJ.js.map +1 -0
  30. package/dist/{chunk-JYQTXEIO.js → chunk-FBMXWVGP.js} +5 -5
  31. package/dist/{chunk-QXQRKXCU.js → chunk-FCDO7UAO.js} +2 -2
  32. package/dist/{chunk-243PNUA6.js → chunk-FS7A4XNF.js} +3 -3
  33. package/dist/{chunk-YS3POABP.js → chunk-FXQYZNOW.js} +1 -1
  34. package/dist/chunk-FXQYZNOW.js.map +1 -0
  35. package/dist/{chunk-Y2RKOPNC.js → chunk-G7PAZ3TD.js} +4 -4
  36. package/dist/{chunk-QPEXPHJR.js → chunk-GAUBWHAF.js} +4 -4
  37. package/dist/{chunk-GIV6DWBG.js → chunk-GD3BGKAR.js} +2 -2
  38. package/dist/{chunk-TBKOGSYR.js → chunk-GDTCGIPX.js} +2 -2
  39. package/dist/{chunk-3Z2TPHC4.js → chunk-GVXBHCZ2.js} +8 -3
  40. package/dist/chunk-GVXBHCZ2.js.map +1 -0
  41. package/dist/{chunk-OVZDFEOR.js → chunk-HGZ7DC5H.js} +2 -2
  42. package/dist/{chunk-VPSUZLOJ.js → chunk-IS5HWQO7.js} +4 -4
  43. package/dist/{chunk-VPSUZLOJ.js.map → chunk-IS5HWQO7.js.map} +1 -1
  44. package/dist/{chunk-VK5EER6C.js → chunk-K5PVGKE4.js} +2 -2
  45. package/dist/{chunk-LRAZDV5X.js → chunk-KMI2NBBF.js} +6 -6
  46. package/dist/{chunk-VRBCTEKQ.js → chunk-KYKMKLJ6.js} +2 -2
  47. package/dist/{chunk-PFSNOPBQ.js → chunk-LOL725S4.js} +3 -3
  48. package/dist/{chunk-3Y53S2SA.js → chunk-LS3JLEIB.js} +4 -4
  49. package/dist/{chunk-XG3PTSCD.js → chunk-NCO2JGKK.js} +1 -1
  50. package/dist/chunk-NCO2JGKK.js.map +1 -0
  51. package/dist/{chunk-YTXSFG3C.js → chunk-NGSPBLLE.js} +2 -2
  52. package/dist/{chunk-FAQVNJD4.js → chunk-NSLTPGEN.js} +2 -2
  53. package/dist/{chunk-VCGTOS2A.js → chunk-P6256WTJ.js} +3 -3
  54. package/dist/{chunk-7Q5PLD5C.js → chunk-QAU5HM6Q.js} +3 -3
  55. package/dist/{chunk-HXJXPZRE.js → chunk-SAVQ6E2O.js} +2 -2
  56. package/dist/{chunk-E535SAN4.js → chunk-T6HQMVML.js} +1177 -51
  57. package/dist/chunk-T6HQMVML.js.map +1 -0
  58. package/dist/{chunk-Q6W2CMEJ.js → chunk-TLFUDXVV.js} +4 -4
  59. package/dist/{chunk-2PAQNPE3.js → chunk-UOF74WQY.js} +2 -2
  60. package/dist/{chunk-3QAKZ37R.js → chunk-UVPGJXVO.js} +5 -5
  61. package/dist/{chunk-7BRE6EUA.js → chunk-WRLHNG6H.js} +2 -2
  62. package/dist/{chunk-W3XXT26A.js → chunk-YDLAFP36.js} +43 -1
  63. package/dist/chunk-YDLAFP36.js.map +1 -0
  64. package/dist/{chunk-G6FRSBKK.js → chunk-YK72A4IT.js} +4 -4
  65. package/dist/{chunk-3S4BJX25.js → chunk-YL2DR3HY.js} +2 -2
  66. package/dist/{chunk-RTZVQAJ7.js → chunk-ZC2AAE6J.js} +2 -2
  67. package/dist/{chunk-4HIL6AHQ.js → chunk-ZUMGGHRB.js} +4 -4
  68. package/dist/consent/index.cjs.map +1 -1
  69. package/dist/consent/index.d.cts +3 -3
  70. package/dist/consent/index.d.ts +3 -3
  71. package/dist/consent/index.js +3 -3
  72. package/dist/{crypto-5ZDIY3NG.js → crypto-H2Y3DDFW.js} +3 -3
  73. package/dist/{delegation-QYXZW25W.js → delegation-QSC7G5QC.js} +5 -5
  74. package/dist/derivations/index.cjs.map +1 -1
  75. package/dist/derivations/index.d.cts +4 -4
  76. package/dist/derivations/index.d.ts +4 -4
  77. package/dist/derivations/index.js +4 -4
  78. package/dist/{dev-unlock-utkybTKb.d.ts → dev-unlock-Cf2B7Kih.d.ts} +1 -1
  79. package/dist/{dev-unlock-DQCNDfFp.d.cts → dev-unlock-De3mjQWv.d.cts} +1 -1
  80. package/dist/executor-BZKFZVRC.js +8 -0
  81. package/dist/executor-GFZFDQXV.js +8 -0
  82. package/dist/executor-KT2IOZVP.js +11 -0
  83. package/dist/{fanout-sidecar-VJ52RIEY.js → fanout-sidecar-NRBWSLRK.js} +2 -2
  84. package/dist/guards/index.cjs +7 -0
  85. package/dist/guards/index.cjs.map +1 -1
  86. package/dist/guards/index.d.cts +4 -4
  87. package/dist/guards/index.d.ts +4 -4
  88. package/dist/guards/index.js +4 -4
  89. package/dist/{hash-DcoYWfJ_.d.ts → hash-gVn_uKhp.d.ts} +1 -1
  90. package/dist/{hash-jDowCrK2.d.cts → hash-vBCB0-Ps.d.cts} +1 -1
  91. package/dist/history/index.cjs +1 -1
  92. package/dist/history/index.cjs.map +1 -1
  93. package/dist/history/index.d.cts +4 -4
  94. package/dist/history/index.d.ts +4 -4
  95. package/dist/history/index.js +6 -6
  96. package/dist/i18n/index.cjs.map +1 -1
  97. package/dist/i18n/index.d.cts +3 -3
  98. package/dist/i18n/index.d.ts +3 -3
  99. package/dist/i18n/index.js +7 -7
  100. package/dist/{index-BCKdioeh.d.ts → index-BF1B2HB9.d.ts} +25 -1
  101. package/dist/{index-BMjrzNZr.d.cts → index-DVkvrgpm.d.cts} +25 -1
  102. package/dist/index.cjs +1273 -27
  103. package/dist/index.cjs.map +1 -1
  104. package/dist/index.d.cts +33 -12
  105. package/dist/index.d.ts +33 -12
  106. package/dist/index.js +109 -42
  107. package/dist/index.js.map +1 -1
  108. package/dist/indexing/index.cjs.map +1 -1
  109. package/dist/indexing/index.js +2 -2
  110. package/dist/issue-BAJ7ZB4S.js +12 -0
  111. package/dist/{ledger-3IU5GMXA.js → ledger-WOEJUYTP.js} +6 -6
  112. package/dist/materialized-views/index.cjs.map +1 -1
  113. package/dist/materialized-views/index.d.cts +5 -5
  114. package/dist/materialized-views/index.d.ts +5 -5
  115. package/dist/materialized-views/index.js +6 -6
  116. package/dist/noydb-XNQSKXGO.js +34 -0
  117. package/dist/overlay-views/index.cjs.map +1 -1
  118. package/dist/overlay-views/index.d.cts +4 -4
  119. package/dist/overlay-views/index.d.ts +4 -4
  120. package/dist/overlay-views/index.js +4 -4
  121. package/dist/periods/index.cjs.map +1 -1
  122. package/dist/periods/index.d.cts +3 -3
  123. package/dist/periods/index.d.ts +3 -3
  124. package/dist/periods/index.js +6 -6
  125. package/dist/{public-envelope-U3CMEOMV.js → public-envelope-OHQ5UZFM.js} +4 -4
  126. package/dist/query/index.cjs.map +1 -1
  127. package/dist/query/index.d.cts +1 -1
  128. package/dist/query/index.d.ts +1 -1
  129. package/dist/query/index.js +3 -3
  130. package/dist/registry-2IEARCGT.js +7 -0
  131. package/dist/{registry-3ALP62P6.js → registry-CDHASH73.js} +3 -3
  132. package/dist/registry-EMGLZGR6.js +8 -0
  133. package/dist/registry-NQALYR77.js +8 -0
  134. package/dist/{revoke-KY2GB4KP.js → revoke-7JOVLZFD.js} +6 -6
  135. package/dist/session/index.cjs.map +1 -1
  136. package/dist/session/index.d.cts +4 -4
  137. package/dist/session/index.d.ts +4 -4
  138. package/dist/session/index.js +3 -3
  139. package/dist/shadow/index.cjs.map +1 -1
  140. package/dist/shadow/index.d.cts +3 -3
  141. package/dist/shadow/index.d.ts +3 -3
  142. package/dist/shadow/index.js +2 -2
  143. package/dist/{signer-GRI5TZKH.js → signer-M4K5HBLD.js} +5 -5
  144. package/dist/{stale-OTOF3FH7.js → stale-PAGCS4K5.js} +2 -2
  145. package/dist/store/index.cjs.map +1 -1
  146. package/dist/store/index.d.cts +3 -3
  147. package/dist/store/index.d.ts +3 -3
  148. package/dist/store/index.js +2 -2
  149. package/dist/sync/index.cjs.map +1 -1
  150. package/dist/sync/index.d.cts +2 -2
  151. package/dist/sync/index.d.ts +2 -2
  152. package/dist/sync/index.js +4 -4
  153. package/dist/team/index.cjs.map +1 -1
  154. package/dist/team/index.d.cts +3 -3
  155. package/dist/team/index.d.ts +3 -3
  156. package/dist/team/index.js +8 -8
  157. package/dist/tx/index.cjs +81 -1
  158. package/dist/tx/index.cjs.map +1 -1
  159. package/dist/tx/index.d.cts +4 -4
  160. package/dist/tx/index.d.ts +4 -4
  161. package/dist/tx/index.js +56 -3
  162. package/dist/tx/index.js.map +1 -1
  163. package/dist/{types-DJG8HG6F.d.cts → types-CSLcfytP.d.cts} +528 -5
  164. package/dist/{types-BoFFiskX.d.ts → types-D9eB0Rvh.d.ts} +528 -5
  165. package/dist/{ulid-C7ms9oli.d.cts → ulid-CG2YvAbg.d.cts} +1 -1
  166. package/dist/{ulid-BmBgooGm.d.ts → ulid-CiM2OAeM.d.ts} +1 -1
  167. package/dist/util/index.cjs.map +1 -1
  168. package/dist/util/index.js +1 -1
  169. package/dist/{with-derivation-BKXXa8Vt.d.ts → with-derivation-Bzpj6UTv.d.ts} +1 -1
  170. package/dist/{with-derivation-BjQ7q4NE.d.cts → with-derivation-DWajFh4K.d.cts} +1 -1
  171. package/dist/{with-guard-DQme5DKE.d.cts → with-guard-DF_Ul3DT.d.cts} +1 -1
  172. package/dist/{with-guard-C25yNjzd.d.ts → with-guard-DR7U-l4v.d.ts} +1 -1
  173. package/dist/{with-materialized-view-BbEPFIIJ.d.cts → with-materialized-view-_piodoIz.d.cts} +1 -1
  174. package/dist/{with-materialized-view-CqnRwI2S.d.ts → with-materialized-view-qtoJ3xKJ.d.ts} +1 -1
  175. package/dist/{with-overlayed-view-Ct1fSJt-.d.ts → with-overlayed-view-DFaRfgMr.d.ts} +1 -1
  176. package/dist/{with-overlayed-view-bwlmmFjx.d.cts → with-overlayed-view-DwzCKxn2.d.cts} +1 -1
  177. package/package.json +3 -3
  178. package/dist/chunk-3Z2TPHC4.js.map +0 -1
  179. package/dist/chunk-E535SAN4.js.map +0 -1
  180. package/dist/chunk-PEULZC6M.js.map +0 -1
  181. package/dist/chunk-W3XXT26A.js.map +0 -1
  182. package/dist/chunk-XG3PTSCD.js.map +0 -1
  183. package/dist/chunk-YS3POABP.js.map +0 -1
  184. package/dist/executor-AS2IDHKZ.js +0 -11
  185. package/dist/executor-HLXFXNFM.js +0 -8
  186. package/dist/executor-HN6YBHZ5.js +0 -8
  187. package/dist/issue-ORP37MVW.js +0 -12
  188. package/dist/noydb-5H3C24GG.js +0 -34
  189. package/dist/registry-7HE6VJGC.js +0 -8
  190. package/dist/registry-PSIPG2QR.js +0 -8
  191. package/dist/registry-RFGGMVNJ.js +0 -7
  192. /package/dist/{chunk-EUYOGYGV.js.map → chunk-2EYC3WDT.js.map} +0 -0
  193. /package/dist/{chunk-MUWOSVEP.js.map → chunk-2XLVPKXG.js.map} +0 -0
  194. /package/dist/{chunk-NWZ3I6R6.js.map → chunk-4OQWR46B.js.map} +0 -0
  195. /package/dist/{chunk-J4KLMEUL.js.map → chunk-4UBOTYP5.js.map} +0 -0
  196. /package/dist/{chunk-UND4XIB6.js.map → chunk-4X2S7PBF.js.map} +0 -0
  197. /package/dist/{chunk-VE6YVP32.js.map → chunk-5YHWBPOT.js.map} +0 -0
  198. /package/dist/{chunk-7BUTTVMR.js.map → chunk-6S3LLAQ5.js.map} +0 -0
  199. /package/dist/{chunk-7Z23ZFLV.js.map → chunk-74JEQFMT.js.map} +0 -0
  200. /package/dist/{chunk-AHPFONIL.js.map → chunk-75QDHSE4.js.map} +0 -0
  201. /package/dist/{chunk-3XHOCQK4.js.map → chunk-A6SWRXUQ.js.map} +0 -0
  202. /package/dist/{chunk-PLI5TV7N.js.map → chunk-BFI3RS42.js.map} +0 -0
  203. /package/dist/{chunk-CXSCDO5T.js.map → chunk-EMEX37ZN.js.map} +0 -0
  204. /package/dist/{chunk-JYQTXEIO.js.map → chunk-FBMXWVGP.js.map} +0 -0
  205. /package/dist/{chunk-QXQRKXCU.js.map → chunk-FCDO7UAO.js.map} +0 -0
  206. /package/dist/{chunk-243PNUA6.js.map → chunk-FS7A4XNF.js.map} +0 -0
  207. /package/dist/{chunk-Y2RKOPNC.js.map → chunk-G7PAZ3TD.js.map} +0 -0
  208. /package/dist/{chunk-QPEXPHJR.js.map → chunk-GAUBWHAF.js.map} +0 -0
  209. /package/dist/{chunk-GIV6DWBG.js.map → chunk-GD3BGKAR.js.map} +0 -0
  210. /package/dist/{chunk-TBKOGSYR.js.map → chunk-GDTCGIPX.js.map} +0 -0
  211. /package/dist/{chunk-OVZDFEOR.js.map → chunk-HGZ7DC5H.js.map} +0 -0
  212. /package/dist/{chunk-VK5EER6C.js.map → chunk-K5PVGKE4.js.map} +0 -0
  213. /package/dist/{chunk-LRAZDV5X.js.map → chunk-KMI2NBBF.js.map} +0 -0
  214. /package/dist/{chunk-VRBCTEKQ.js.map → chunk-KYKMKLJ6.js.map} +0 -0
  215. /package/dist/{chunk-PFSNOPBQ.js.map → chunk-LOL725S4.js.map} +0 -0
  216. /package/dist/{chunk-3Y53S2SA.js.map → chunk-LS3JLEIB.js.map} +0 -0
  217. /package/dist/{chunk-YTXSFG3C.js.map → chunk-NGSPBLLE.js.map} +0 -0
  218. /package/dist/{chunk-FAQVNJD4.js.map → chunk-NSLTPGEN.js.map} +0 -0
  219. /package/dist/{chunk-VCGTOS2A.js.map → chunk-P6256WTJ.js.map} +0 -0
  220. /package/dist/{chunk-7Q5PLD5C.js.map → chunk-QAU5HM6Q.js.map} +0 -0
  221. /package/dist/{chunk-HXJXPZRE.js.map → chunk-SAVQ6E2O.js.map} +0 -0
  222. /package/dist/{chunk-Q6W2CMEJ.js.map → chunk-TLFUDXVV.js.map} +0 -0
  223. /package/dist/{chunk-2PAQNPE3.js.map → chunk-UOF74WQY.js.map} +0 -0
  224. /package/dist/{chunk-3QAKZ37R.js.map → chunk-UVPGJXVO.js.map} +0 -0
  225. /package/dist/{chunk-7BRE6EUA.js.map → chunk-WRLHNG6H.js.map} +0 -0
  226. /package/dist/{chunk-G6FRSBKK.js.map → chunk-YK72A4IT.js.map} +0 -0
  227. /package/dist/{chunk-3S4BJX25.js.map → chunk-YL2DR3HY.js.map} +0 -0
  228. /package/dist/{chunk-RTZVQAJ7.js.map → chunk-ZC2AAE6J.js.map} +0 -0
  229. /package/dist/{chunk-4HIL6AHQ.js.map → chunk-ZUMGGHRB.js.map} +0 -0
  230. /package/dist/{crypto-5ZDIY3NG.js.map → crypto-H2Y3DDFW.js.map} +0 -0
  231. /package/dist/{delegation-QYXZW25W.js.map → delegation-QSC7G5QC.js.map} +0 -0
  232. /package/dist/{executor-AS2IDHKZ.js.map → executor-BZKFZVRC.js.map} +0 -0
  233. /package/dist/{executor-HLXFXNFM.js.map → executor-GFZFDQXV.js.map} +0 -0
  234. /package/dist/{executor-HN6YBHZ5.js.map → executor-KT2IOZVP.js.map} +0 -0
  235. /package/dist/{fanout-sidecar-VJ52RIEY.js.map → fanout-sidecar-NRBWSLRK.js.map} +0 -0
  236. /package/dist/{issue-ORP37MVW.js.map → issue-BAJ7ZB4S.js.map} +0 -0
  237. /package/dist/{ledger-3IU5GMXA.js.map → ledger-WOEJUYTP.js.map} +0 -0
  238. /package/dist/{noydb-5H3C24GG.js.map → noydb-XNQSKXGO.js.map} +0 -0
  239. /package/dist/{public-envelope-U3CMEOMV.js.map → public-envelope-OHQ5UZFM.js.map} +0 -0
  240. /package/dist/{registry-3ALP62P6.js.map → registry-2IEARCGT.js.map} +0 -0
  241. /package/dist/{registry-7HE6VJGC.js.map → registry-CDHASH73.js.map} +0 -0
  242. /package/dist/{registry-PSIPG2QR.js.map → registry-EMGLZGR6.js.map} +0 -0
  243. /package/dist/{registry-RFGGMVNJ.js.map → registry-NQALYR77.js.map} +0 -0
  244. /package/dist/{revoke-KY2GB4KP.js.map → revoke-7JOVLZFD.js.map} +0 -0
  245. /package/dist/{signer-GRI5TZKH.js.map → signer-M4K5HBLD.js.map} +0 -0
  246. /package/dist/{stale-OTOF3FH7.js.map → stale-PAGCS4K5.js.map} +0 -0
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  issueDelegation,
4
4
  loadActiveDelegations,
5
5
  revokeDelegation
6
- } from "./chunk-G6FRSBKK.js";
6
+ } from "./chunk-YK72A4IT.js";
7
7
  import {
8
8
  Collection,
9
9
  DEFAULT_FRESHNESS_MS,
@@ -39,7 +39,7 @@ import {
39
39
  saveVaultPolicy,
40
40
  validateSchemaInput,
41
41
  validateSchemaOutput
42
- } from "./chunk-E535SAN4.js";
42
+ } from "./chunk-T6HQMVML.js";
43
43
  import {
44
44
  DEFAULT_PUBLIC_ENVELOPE_SCHEMA,
45
45
  PUBLIC_ENVELOPE_FIELDS,
@@ -50,24 +50,24 @@ import {
50
50
  TxContext,
51
51
  TxVault,
52
52
  runTransaction
53
- } from "./chunk-3Z2TPHC4.js";
53
+ } from "./chunk-GVXBHCZ2.js";
54
54
  import {
55
55
  withDerivation
56
- } from "./chunk-CXSCDO5T.js";
57
- import "./chunk-GIV6DWBG.js";
58
- import "./chunk-OVZDFEOR.js";
56
+ } from "./chunk-EMEX37ZN.js";
57
+ import "./chunk-GD3BGKAR.js";
58
+ import "./chunk-HGZ7DC5H.js";
59
59
  import {
60
60
  withMaterializedView
61
- } from "./chunk-RTZVQAJ7.js";
62
- import "./chunk-Y2RKOPNC.js";
63
- import "./chunk-TBKOGSYR.js";
64
- import "./chunk-PLI5TV7N.js";
61
+ } from "./chunk-ZC2AAE6J.js";
62
+ import "./chunk-G7PAZ3TD.js";
63
+ import "./chunk-GDTCGIPX.js";
64
+ import "./chunk-BFI3RS42.js";
65
65
  import {
66
66
  withOverlayedView
67
- } from "./chunk-3S4BJX25.js";
68
- import "./chunk-YTXSFG3C.js";
69
- import "./chunk-FAQVNJD4.js";
70
- import "./chunk-7BRE6EUA.js";
67
+ } from "./chunk-YL2DR3HY.js";
68
+ import "./chunk-NGSPBLLE.js";
69
+ import "./chunk-NSLTPGEN.js";
70
+ import "./chunk-WRLHNG6H.js";
71
71
  import {
72
72
  mergeCrdtStates,
73
73
  resolveCrdtSnapshot
@@ -82,7 +82,7 @@ import {
82
82
  readNoydbBundlePublicEnvelope,
83
83
  resetBrotliSupportCache,
84
84
  writeNoydbBundle
85
- } from "./chunk-VCGTOS2A.js";
85
+ } from "./chunk-P6256WTJ.js";
86
86
  import {
87
87
  MemoryRecipientSealer,
88
88
  MemorySealingKeyProvider,
@@ -93,7 +93,7 @@ import {
93
93
  parseSealedEnvelope,
94
94
  savePersistedSchema,
95
95
  saveSealedPassphrase
96
- } from "./chunk-UND4XIB6.js";
96
+ } from "./chunk-4X2S7PBF.js";
97
97
  import {
98
98
  PUBLIC_ENVELOPE_RECORD_ID,
99
99
  isPublicEnvelope,
@@ -101,31 +101,31 @@ import {
101
101
  readPublicEnvelope,
102
102
  savePublicEnvelope,
103
103
  validatePublicEnvelopeInput
104
- } from "./chunk-243PNUA6.js";
104
+ } from "./chunk-FS7A4XNF.js";
105
105
  import {
106
106
  CONSENT_AUDIT_COLLECTION
107
- } from "./chunk-VK5EER6C.js";
107
+ } from "./chunk-K5PVGKE4.js";
108
108
  import {
109
109
  PERIODS_COLLECTION
110
- } from "./chunk-QPEXPHJR.js";
110
+ } from "./chunk-GAUBWHAF.js";
111
111
  import "./chunk-UF3BUNQZ.js";
112
112
  import {
113
113
  withGuard
114
- } from "./chunk-VE6YVP32.js";
115
- import "./chunk-PEULZC6M.js";
114
+ } from "./chunk-5YHWBPOT.js";
115
+ import "./chunk-EPK6A3WJ.js";
116
116
  import "./chunk-UMLVJTYV.js";
117
- import "./chunk-HXJXPZRE.js";
117
+ import "./chunk-SAVQ6E2O.js";
118
118
  import {
119
119
  CollectionFrame,
120
120
  VaultFrame
121
- } from "./chunk-QXQRKXCU.js";
121
+ } from "./chunk-FCDO7UAO.js";
122
122
  import {
123
123
  applyI18nLocale,
124
124
  i18nText,
125
125
  isI18nTextDescriptor,
126
126
  resolveI18nText,
127
127
  validateI18nTextValue
128
- } from "./chunk-3XHOCQK4.js";
128
+ } from "./chunk-A6SWRXUQ.js";
129
129
  import {
130
130
  DICT_COLLECTION_PREFIX,
131
131
  DictionaryHandle,
@@ -133,7 +133,7 @@ import {
133
133
  dictKey,
134
134
  isDictCollectionName,
135
135
  isDictKeyDescriptor
136
- } from "./chunk-LRAZDV5X.js";
136
+ } from "./chunk-KMI2NBBF.js";
137
137
  import {
138
138
  createBundleStore,
139
139
  routeStore,
@@ -145,7 +145,7 @@ import {
145
145
  withRetry,
146
146
  wrapBundleStore,
147
147
  wrapStore
148
- } from "./chunk-MUWOSVEP.js";
148
+ } from "./chunk-2XLVPKXG.js";
149
149
  import {
150
150
  SYNC_CREDENTIALS_COLLECTION,
151
151
  credentialStatus,
@@ -153,7 +153,7 @@ import {
153
153
  getCredential,
154
154
  listCredentials,
155
155
  putCredential
156
- } from "./chunk-NWZ3I6R6.js";
156
+ } from "./chunk-4OQWR46B.js";
157
157
  import {
158
158
  MAGIC_LINK_CONTENT_INFO_PREFIX,
159
159
  MAGIC_LINK_GRANTS_COLLECTION,
@@ -188,17 +188,17 @@ import {
188
188
  unwrapDeksFromShamirEntry,
189
189
  unwrapMagicLinkGrant,
190
190
  writeMagicLinkGrant
191
- } from "./chunk-EUYOGYGV.js";
191
+ } from "./chunk-2EYC3WDT.js";
192
192
  import {
193
193
  assertTierAccess,
194
194
  dekKey,
195
195
  effectiveClearance
196
- } from "./chunk-7BUTTVMR.js";
196
+ } from "./chunk-6S3LLAQ5.js";
197
197
  import {
198
198
  PresenceHandle,
199
199
  SyncEngine,
200
200
  SyncTransaction
201
- } from "./chunk-3Y53S2SA.js";
201
+ } from "./chunk-LS3JLEIB.js";
202
202
  import {
203
203
  DIRECTORY_RECORD_ID,
204
204
  USER_ENVELOPE_COLLECTION,
@@ -226,7 +226,7 @@ import {
226
226
  saveUserEnvelope,
227
227
  validatePassphrase,
228
228
  visibilityRecordId
229
- } from "./chunk-Q6W2CMEJ.js";
229
+ } from "./chunk-TLFUDXVV.js";
230
230
  import {
231
231
  BUNDLE_STORE_POLICY,
232
232
  INDEXED_STORE_POLICY,
@@ -246,7 +246,7 @@ import {
246
246
  revokeAllSessions,
247
247
  revokeSession,
248
248
  validateSessionPolicy
249
- } from "./chunk-7Q5PLD5C.js";
249
+ } from "./chunk-QAU5HM6Q.js";
250
250
  import {
251
251
  generateULID,
252
252
  isULID
@@ -256,14 +256,14 @@ import {
256
256
  VaultInstant,
257
257
  diff,
258
258
  formatDiff
259
- } from "./chunk-VPSUZLOJ.js";
259
+ } from "./chunk-IS5HWQO7.js";
260
260
  import {
261
261
  LEDGER_COLLECTION,
262
262
  LEDGER_DELTAS_COLLECTION,
263
263
  LedgerStore,
264
264
  applyPatch,
265
265
  computePatch
266
- } from "./chunk-7Z23ZFLV.js";
266
+ } from "./chunk-74JEQFMT.js";
267
267
  import {
268
268
  canonicalJson,
269
269
  envelopePayloadHash,
@@ -271,7 +271,7 @@ import {
271
271
  paddedIndex,
272
272
  parseIndex,
273
273
  sha256Hex
274
- } from "./chunk-XG3PTSCD.js";
274
+ } from "./chunk-NCO2JGKK.js";
275
275
  import {
276
276
  DEFAULT_JOIN_MAX_ROWS,
277
277
  Query,
@@ -280,7 +280,7 @@ import {
280
280
  buildLiveQuery,
281
281
  executePlan,
282
282
  resetJoinWarnings
283
- } from "./chunk-J4KLMEUL.js";
283
+ } from "./chunk-4UBOTYP5.js";
284
284
  import {
285
285
  CollectionIndexes
286
286
  } from "./chunk-YMYK7US4.js";
@@ -300,7 +300,7 @@ import {
300
300
  GroupedQueryN,
301
301
  groupAndReduce,
302
302
  reduceRecords
303
- } from "./chunk-VRBCTEKQ.js";
303
+ } from "./chunk-KYKMKLJ6.js";
304
304
  import {
305
305
  evaluateClause,
306
306
  evaluateFieldClause,
@@ -317,15 +317,15 @@ import {
317
317
  detectMagic,
318
318
  detectMimeType,
319
319
  isPreCompressed
320
- } from "./chunk-JYQTXEIO.js";
321
- import "./chunk-PFSNOPBQ.js";
320
+ } from "./chunk-FBMXWVGP.js";
321
+ import "./chunk-LOL725S4.js";
322
322
  import {
323
323
  NOYDB_BACKUP_VERSION,
324
324
  NOYDB_FORMAT_VERSION,
325
325
  NOYDB_KEYRING_VERSION,
326
326
  NOYDB_SYNC_VERSION,
327
327
  createStore
328
- } from "./chunk-YS3POABP.js";
328
+ } from "./chunk-FXQYZNOW.js";
329
329
  import {
330
330
  base64ToBuffer,
331
331
  bufferToBase64,
@@ -334,7 +334,7 @@ import {
334
334
  derivePresenceKey,
335
335
  encryptBytes,
336
336
  encryptDeterministic
337
- } from "./chunk-2PAQNPE3.js";
337
+ } from "./chunk-UOF74WQY.js";
338
338
  import {
339
339
  AlreadyElevatedError,
340
340
  AmendmentForbiddenError,
@@ -375,9 +375,11 @@ import {
375
375
  MaterializedViewCycleError,
376
376
  MaterializedViewSourceUnknownError,
377
377
  MaterializedViewTooLargeError,
378
+ MigrationRequiredError,
378
379
  MissingTranslationError,
379
380
  NetworkError,
380
381
  NoAccessError,
382
+ NonAdditiveSchemaChangeError,
381
383
  NotFoundError,
382
384
  NoydbError,
383
385
  OverlayBaseIsVirtualError,
@@ -388,11 +390,15 @@ import {
388
390
  PeriodClosedError,
389
391
  PermissionDeniedError,
390
392
  PrivilegeEscalationError,
393
+ QuiesceTimeoutError,
391
394
  ReadOnlyAtInstantError,
392
395
  ReadOnlyError,
393
396
  ReadOnlyFrameError,
394
397
  RecordLockedError,
395
398
  ReservedCollectionNameError,
399
+ SchemaFenceError,
400
+ SchemaLockedError,
401
+ SchemaUpdateError,
396
402
  SchemaValidationError,
397
403
  SessionExpiredError,
398
404
  SessionNotFoundError,
@@ -403,7 +409,58 @@ import {
403
409
  TierNotGrantedError,
404
410
  TranslatorNotConfiguredError,
405
411
  ValidationError
406
- } from "./chunk-W3XXT26A.js";
412
+ } from "./chunk-YDLAFP36.js";
413
+
414
+ // src/schema-update/strategies.ts
415
+ function blindUpdate() {
416
+ return { name: "blindUpdate", onSchemaDelta: () => ({ action: "allow" }) };
417
+ }
418
+ function additiveOnly() {
419
+ return {
420
+ name: "additiveOnly",
421
+ onSchemaDelta(delta) {
422
+ if (delta.kind === "non-additive") {
423
+ return {
424
+ action: "reject",
425
+ error: new NonAdditiveSchemaChangeError(
426
+ `Non-additive schema change to "${delta.collection}" (added: [${delta.added.join(", ")}], removed: [${delta.removed.join(", ")}], changed: [${delta.changed.map((c) => c.field).join(", ")}]). Register a coordinatedCutover() strategy to migrate, or revert the change.`
427
+ )
428
+ };
429
+ }
430
+ return { action: "allow" };
431
+ }
432
+ };
433
+ }
434
+ function lockSchema(opts) {
435
+ const fields = opts?.fields;
436
+ return {
437
+ name: "lockSchema",
438
+ onSchemaDelta(delta) {
439
+ if (delta.kind === "none") return { action: "allow" };
440
+ const touched = fields ? [...delta.added, ...delta.removed, ...delta.changed.map((c) => c.field)].filter((f) => fields.includes(f)) : ["<any>"];
441
+ if (touched.length === 0) return { action: "allow" };
442
+ return {
443
+ action: "reject",
444
+ error: new SchemaLockedError(
445
+ `Schema for "${delta.collection}" is locked` + (fields ? ` on fields [${fields.join(", ")}] (touched: [${touched.join(", ")}])` : "") + `; the change was refused.`
446
+ )
447
+ };
448
+ }
449
+ };
450
+ }
451
+
452
+ // src/schema-update/cutover.ts
453
+ function coordinatedCutover(opts) {
454
+ return {
455
+ name: "coordinatedCutover",
456
+ onSchemaDelta(delta) {
457
+ if (delta.kind === "non-additive") {
458
+ return { action: "cutover", transform: opts.transform };
459
+ }
460
+ return { action: "allow" };
461
+ }
462
+ };
463
+ }
407
464
 
408
465
  // src/vault-diff.ts
409
466
  async function diffVault(vault, candidate, options = {}) {
@@ -636,6 +693,7 @@ export {
636
693
  MaterializedViewTooLargeError,
637
694
  MemoryRecipientSealer,
638
695
  MemorySealingKeyProvider,
696
+ MigrationRequiredError,
639
697
  MissingTranslationError,
640
698
  NOYDB_BACKUP_VERSION,
641
699
  NOYDB_BUNDLE_FORMAT_VERSION,
@@ -646,6 +704,7 @@ export {
646
704
  NOYDB_SYNC_VERSION,
647
705
  NetworkError,
648
706
  NoAccessError,
707
+ NonAdditiveSchemaChangeError,
649
708
  NotFoundError,
650
709
  Noydb,
651
710
  NoydbError,
@@ -667,6 +726,7 @@ export {
667
726
  PrivilegeEscalationError,
668
727
  Query,
669
728
  QuickUnlockStore,
729
+ QuiesceTimeoutError,
670
730
  ReadOnlyAtInstantError,
671
731
  ReadOnlyError,
672
732
  ReadOnlyFrameError,
@@ -682,6 +742,9 @@ export {
682
742
  STRICT_POLICY,
683
743
  SYNC_CREDENTIALS_COLLECTION,
684
744
  ScanBuilder,
745
+ SchemaFenceError,
746
+ SchemaLockedError,
747
+ SchemaUpdateError,
685
748
  SchemaValidationError,
686
749
  SessionExpiredError,
687
750
  SessionNotFoundError,
@@ -708,6 +771,7 @@ export {
708
771
  VaultInstant,
709
772
  WeakPassphraseError,
710
773
  activeSessionCount,
774
+ additiveOnly,
711
775
  applyI18nLocale,
712
776
  applyJoins,
713
777
  applyPatch,
@@ -715,6 +779,7 @@ export {
715
779
  assertTierAccess,
716
780
  avg,
717
781
  base64ToBuffer,
782
+ blindUpdate,
718
783
  bufferToBase64,
719
784
  buildLiveQuery,
720
785
  buildRecipientKeyringFile,
@@ -723,6 +788,7 @@ export {
723
788
  checkGate,
724
789
  clearDevUnlock,
725
790
  computePatch,
791
+ coordinatedCutover,
726
792
  count,
727
793
  createBundleStore,
728
794
  createEnforcer,
@@ -801,6 +867,7 @@ export {
801
867
  loadShamirRecoveryEntries,
802
868
  loadUserEnvelope,
803
869
  loadVaultPolicy,
870
+ lockSchema,
804
871
  magicLinkGrantRecordId,
805
872
  max,
806
873
  mergeCrdtStates,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/vault-diff.ts"],"sourcesContent":["/**\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 (#245). */\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 (#232, 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"]}