@noy-db/hub 0.2.0-pre.9 → 0.3.0-pre.1

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 (541) hide show
  1. package/README.md +129 -3
  2. package/dist/adapter/index.d.ts +5 -0
  3. package/dist/adapter/index.js +15 -0
  4. package/dist/aggregate/index.d.ts +6 -2
  5. package/dist/aggregate/index.js +24 -16
  6. package/dist/aggregate/index.js.map +1 -1
  7. package/dist/api-RW3KP7WU.js +14 -0
  8. package/dist/as/index.d.ts +7 -0
  9. package/dist/as/index.js +24 -0
  10. package/dist/at/index.d.ts +5 -0
  11. package/dist/at/index.js +1 -0
  12. package/dist/attestation/index.d.ts +15 -47
  13. package/dist/attestation/index.js +54 -10
  14. package/dist/attestation/index.js.map +1 -1
  15. package/dist/backup-XV3IOEGB.js +217 -0
  16. package/dist/backup-XV3IOEGB.js.map +1 -0
  17. package/dist/blobs/index.d.ts +6 -8
  18. package/dist/blobs/index.js +19 -12
  19. package/dist/blobs/index.js.map +1 -1
  20. package/dist/bundle/index.d.ts +16 -70
  21. package/dist/bundle/index.js +39 -476
  22. package/dist/bundle/index.js.map +1 -1
  23. package/dist/{ulid-CJ8RzRrm.d.ts → bundle-CH-H06dp.d.ts} +31 -86
  24. package/dist/by/index.d.ts +1 -0
  25. package/dist/by/index.js +11 -0
  26. package/dist/cargo/index.d.ts +9 -0
  27. package/dist/cargo/index.js +89 -0
  28. package/dist/chunk-26LGBE4T.js +42 -0
  29. package/dist/chunk-26LGBE4T.js.map +1 -0
  30. package/dist/chunk-2P2HZEXU.js +233 -0
  31. package/dist/chunk-2P2HZEXU.js.map +1 -0
  32. package/dist/{chunk-K3DK3NU5.js → chunk-3YFXJ3ZP.js} +20 -5
  33. package/dist/chunk-3YFXJ3ZP.js.map +1 -0
  34. package/dist/chunk-4Q6HSHHL.js +90 -0
  35. package/dist/chunk-4Q6HSHHL.js.map +1 -0
  36. package/dist/chunk-5LUY7UTV.js +380 -0
  37. package/dist/chunk-5LUY7UTV.js.map +1 -0
  38. package/dist/chunk-5N6CZTCY.js +367 -0
  39. package/dist/chunk-5N6CZTCY.js.map +1 -0
  40. package/dist/chunk-5O3AOPDT.js +992 -0
  41. package/dist/chunk-5O3AOPDT.js.map +1 -0
  42. package/dist/chunk-5R3ERCDH.js +239 -0
  43. package/dist/chunk-5R3ERCDH.js.map +1 -0
  44. package/dist/{chunk-6CME4UEK.js → chunk-5R5JW2JT.js} +7000 -4827
  45. package/dist/chunk-5R5JW2JT.js.map +1 -0
  46. package/dist/chunk-5TDJ56JE.js +32 -0
  47. package/dist/chunk-5TDJ56JE.js.map +1 -0
  48. package/dist/{chunk-T7JEBOGN.js → chunk-62QYRORB.js} +18 -11
  49. package/dist/chunk-62QYRORB.js.map +1 -0
  50. package/dist/{chunk-J66GRPNH.js → chunk-6S7T6WC4.js} +2 -2
  51. package/dist/chunk-6S7T6WC4.js.map +1 -0
  52. package/dist/chunk-76722EBH.js +451 -0
  53. package/dist/chunk-76722EBH.js.map +1 -0
  54. package/dist/{chunk-Z6FNBOTC.js → chunk-AIWULCUO.js} +13 -17
  55. package/dist/chunk-AIWULCUO.js.map +1 -0
  56. package/dist/{chunk-O3VZPBZG.js → chunk-AQTBSL7R.js} +47 -11
  57. package/dist/chunk-AQTBSL7R.js.map +1 -0
  58. package/dist/chunk-AURFOK3D.js +35 -0
  59. package/dist/chunk-AURFOK3D.js.map +1 -0
  60. package/dist/{chunk-53XBRIRT.js → chunk-AXRXJTE2.js} +9 -9
  61. package/dist/chunk-AXRXJTE2.js.map +1 -0
  62. package/dist/chunk-AZAOEIKW.js +155 -0
  63. package/dist/chunk-AZAOEIKW.js.map +1 -0
  64. package/dist/{chunk-HNRHLRDC.js → chunk-BG3SPSR4.js} +3 -3
  65. package/dist/chunk-BG3SPSR4.js.map +1 -0
  66. package/dist/chunk-BGIZAFY7.js +1 -0
  67. package/dist/chunk-CHFZDSE4.js +1 -0
  68. package/dist/{chunk-DJHHA6XH.js → chunk-CMGR4ZEW.js} +50 -20
  69. package/dist/chunk-CMGR4ZEW.js.map +1 -0
  70. package/dist/chunk-CWPPNPOH.js +23 -0
  71. package/dist/chunk-CWPPNPOH.js.map +1 -0
  72. package/dist/{chunk-QODLLGQ7.js → chunk-DFEMTNPJ.js} +371 -38
  73. package/dist/chunk-DFEMTNPJ.js.map +1 -0
  74. package/dist/{chunk-ZYWZWG6G.js → chunk-DGDI2D4M.js} +10 -10
  75. package/dist/chunk-DGDI2D4M.js.map +1 -0
  76. package/dist/{chunk-SYMWGEET.js → chunk-EIZUR2XW.js} +3 -3
  77. package/dist/chunk-EIZUR2XW.js.map +1 -0
  78. package/dist/{chunk-BVRYKATC.js → chunk-FISN7WE4.js} +36 -33
  79. package/dist/chunk-FISN7WE4.js.map +1 -0
  80. package/dist/chunk-GHVIKOHT.js +1 -0
  81. package/dist/chunk-GYGWYIOZ.js +200 -0
  82. package/dist/chunk-GYGWYIOZ.js.map +1 -0
  83. package/dist/chunk-HCIPRAGS.js +45 -0
  84. package/dist/chunk-HCIPRAGS.js.map +1 -0
  85. package/dist/{chunk-PX35GA7L.js → chunk-I2NOIW44.js} +10 -10
  86. package/dist/chunk-I2NOIW44.js.map +1 -0
  87. package/dist/{chunk-OIF6LZUR.js → chunk-I3TIKTJO.js} +3 -3
  88. package/dist/chunk-I3TIKTJO.js.map +1 -0
  89. package/dist/chunk-I7FD46FF.js +9 -0
  90. package/dist/chunk-I7FD46FF.js.map +1 -0
  91. package/dist/chunk-IAGBDSCS.js +40 -0
  92. package/dist/chunk-IAGBDSCS.js.map +1 -0
  93. package/dist/{chunk-JWRVQKRZ.js → chunk-IELYAOGG.js} +6 -18
  94. package/dist/chunk-IELYAOGG.js.map +1 -0
  95. package/dist/chunk-IGUYVGGI.js +205 -0
  96. package/dist/chunk-IGUYVGGI.js.map +1 -0
  97. package/dist/{chunk-U26HQ6KJ.js → chunk-IO6GRPT6.js} +4 -4
  98. package/dist/chunk-IO6GRPT6.js.map +1 -0
  99. package/dist/chunk-IPB7FTQX.js +273 -0
  100. package/dist/chunk-IPB7FTQX.js.map +1 -0
  101. package/dist/chunk-ITNUCOXM.js +148 -0
  102. package/dist/chunk-ITNUCOXM.js.map +1 -0
  103. package/dist/{chunk-WPLVTJ5D.js → chunk-IUEN57TV.js} +10 -10
  104. package/dist/chunk-IUEN57TV.js.map +1 -0
  105. package/dist/{chunk-DL3HWOQ5.js → chunk-JNUWZ6D3.js} +9 -9
  106. package/dist/chunk-JNUWZ6D3.js.map +1 -0
  107. package/dist/chunk-K2WCO3NX.js +1 -0
  108. package/dist/chunk-KVOXU4T5.js +30 -0
  109. package/dist/chunk-KVOXU4T5.js.map +1 -0
  110. package/dist/chunk-KXGNJJXB.js +135 -0
  111. package/dist/chunk-KXGNJJXB.js.map +1 -0
  112. package/dist/chunk-LB7FD65R.js +163 -0
  113. package/dist/chunk-LB7FD65R.js.map +1 -0
  114. package/dist/{chunk-22DWZL57.js → chunk-LFLXAY2W.js} +43 -218
  115. package/dist/chunk-LFLXAY2W.js.map +1 -0
  116. package/dist/chunk-LMTH2RM6.js +129 -0
  117. package/dist/chunk-LMTH2RM6.js.map +1 -0
  118. package/dist/{aggregate/index.cjs → chunk-LV7M27WM.js} +390 -219
  119. package/dist/chunk-LV7M27WM.js.map +1 -0
  120. package/dist/{chunk-PE2FR4J3.js → chunk-LXQT4WMP.js} +16 -18
  121. package/dist/chunk-LXQT4WMP.js.map +1 -0
  122. package/dist/chunk-M2YKN37S.js +524 -0
  123. package/dist/chunk-M2YKN37S.js.map +1 -0
  124. package/dist/chunk-M6OST55S.js +14 -0
  125. package/dist/chunk-M6OST55S.js.map +1 -0
  126. package/dist/{chunk-F3GDRNUT.js → chunk-MD3Y6J3L.js} +35 -69
  127. package/dist/chunk-MD3Y6J3L.js.map +1 -0
  128. package/dist/{chunk-XJFLDA7A.js → chunk-MTMJVJ5W.js} +8 -7
  129. package/dist/chunk-MTMJVJ5W.js.map +1 -0
  130. package/dist/{chunk-DFMLEQZB.js → chunk-NF5JWERG.js} +5 -10
  131. package/dist/chunk-NF5JWERG.js.map +1 -0
  132. package/dist/{chunk-DO7C2TOG.js → chunk-PKHL44ER.js} +3 -3
  133. package/dist/{chunk-DO7C2TOG.js.map → chunk-PKHL44ER.js.map} +1 -1
  134. package/dist/chunk-PSMV73A5.js +117 -0
  135. package/dist/chunk-PSMV73A5.js.map +1 -0
  136. package/dist/chunk-PY4KJPYU.js +9 -0
  137. package/dist/chunk-PY4KJPYU.js.map +1 -0
  138. package/dist/chunk-PZ5AY32C.js +10 -0
  139. package/dist/{chunk-DE6GKS6G.js → chunk-Q7SS3IME.js} +50 -9
  140. package/dist/chunk-Q7SS3IME.js.map +1 -0
  141. package/dist/chunk-QHJW5EXU.js +54 -0
  142. package/dist/chunk-QHJW5EXU.js.map +1 -0
  143. package/dist/{chunk-NONAAENK.js → chunk-RUEKROOS.js} +11 -4
  144. package/dist/chunk-RUEKROOS.js.map +1 -0
  145. package/dist/chunk-RUIMKQTA.js +23 -0
  146. package/dist/chunk-RUIMKQTA.js.map +1 -0
  147. package/dist/{chunk-TFBP23BX.js → chunk-SKF73JOP.js} +66 -7
  148. package/dist/chunk-SKF73JOP.js.map +1 -0
  149. package/dist/chunk-SM3AVUHC.js +42 -0
  150. package/dist/chunk-SM3AVUHC.js.map +1 -0
  151. package/dist/{chunk-ML236QKC.js → chunk-SMXWYP24.js} +5 -5
  152. package/dist/chunk-SMXWYP24.js.map +1 -0
  153. package/dist/chunk-SRB2XEWB.js +148 -0
  154. package/dist/chunk-SRB2XEWB.js.map +1 -0
  155. package/dist/chunk-SVLR4POP.js +64 -0
  156. package/dist/chunk-SVLR4POP.js.map +1 -0
  157. package/dist/chunk-TA66UMI4.js +123 -0
  158. package/dist/chunk-TA66UMI4.js.map +1 -0
  159. package/dist/chunk-TEILUWOI.js +664 -0
  160. package/dist/chunk-TEILUWOI.js.map +1 -0
  161. package/dist/chunk-TJYQIGAP.js +82 -0
  162. package/dist/chunk-TJYQIGAP.js.map +1 -0
  163. package/dist/{chunk-H2X3ISXG.js → chunk-UAG5KWVA.js} +7 -7
  164. package/dist/chunk-UAG5KWVA.js.map +1 -0
  165. package/dist/chunk-UDRIWL7A.js +382 -0
  166. package/dist/chunk-UDRIWL7A.js.map +1 -0
  167. package/dist/{chunk-2GLDA55J.js → chunk-UIU2THRG.js} +498 -133
  168. package/dist/chunk-UIU2THRG.js.map +1 -0
  169. package/dist/{chunk-3YPCK6JX.js → chunk-UPJNJGGA.js} +165 -423
  170. package/dist/chunk-UPJNJGGA.js.map +1 -0
  171. package/dist/chunk-UV5MFVO3.js +21 -0
  172. package/dist/chunk-UV5MFVO3.js.map +1 -0
  173. package/dist/{chunk-2WUSG3IT.js → chunk-V7RWQRG7.js} +5 -5
  174. package/dist/chunk-V7RWQRG7.js.map +1 -0
  175. package/dist/{chunk-VTKGMEPP.js → chunk-VCTFO5CO.js} +13 -3
  176. package/dist/chunk-VCTFO5CO.js.map +1 -0
  177. package/dist/{chunk-5T22KDPN.js → chunk-VFQGRQIH.js} +8 -8
  178. package/dist/chunk-VFQGRQIH.js.map +1 -0
  179. package/dist/{chunk-2QR2PQTT.js → chunk-VQNJ7UZL.js} +5 -3
  180. package/dist/chunk-VQNJ7UZL.js.map +1 -0
  181. package/dist/{chunk-DONMZAD2.js → chunk-WWGT2MDV.js} +43 -165
  182. package/dist/chunk-WWGT2MDV.js.map +1 -0
  183. package/dist/{chunk-EMIGCR7X.js → chunk-WXSYDNBT.js} +2 -2
  184. package/dist/chunk-WXSYDNBT.js.map +1 -0
  185. package/dist/chunk-WYSO2NIH.js +30 -0
  186. package/dist/chunk-WYSO2NIH.js.map +1 -0
  187. package/dist/chunk-XXYIOFUB.js +164 -0
  188. package/dist/chunk-XXYIOFUB.js.map +1 -0
  189. package/dist/{chunk-3BFJOWSU.js → chunk-Y22T3KQE.js} +35 -7
  190. package/dist/chunk-Y22T3KQE.js.map +1 -0
  191. package/dist/{chunk-A3JMGXPG.js → chunk-YMUGBZN2.js} +2 -2
  192. package/dist/chunk-YMUGBZN2.js.map +1 -0
  193. package/dist/{chunk-I5FOWO4J.js → chunk-ZCGAHGUS.js} +52 -73
  194. package/dist/chunk-ZCGAHGUS.js.map +1 -0
  195. package/dist/{chunk-FZU343FL.js → chunk-ZJADGNYF.js} +2 -2
  196. package/dist/chunk-ZJADGNYF.js.map +1 -0
  197. package/dist/{chunk-B6PB7JLN.js → chunk-ZYUC53LT.js} +427 -6
  198. package/dist/chunk-ZYUC53LT.js.map +1 -0
  199. package/dist/collection-facade-GQAOGJP2.js +33 -0
  200. package/dist/consent/index.d.ts +5 -7
  201. package/dist/consent/index.js +7 -5
  202. package/dist/consent/index.js.map +1 -1
  203. package/dist/crdt/index.d.ts +6 -2
  204. package/dist/crdt/index.js +3 -2
  205. package/dist/crdt/index.js.map +1 -1
  206. package/dist/decrypt-partition-IHtxEnTi.d.ts +21 -0
  207. package/dist/delegation-UL5HKLER.js +19 -0
  208. package/dist/derivations/index.d.ts +7 -9
  209. package/dist/derivations/index.js +11 -6
  210. package/dist/describe/index.d.ts +1 -0
  211. package/dist/describe/index.js +1 -0
  212. package/dist/describe-aBkJR2sd.d.ts +131 -0
  213. package/dist/{dev-unlock-B4kDxep_.d.ts → dev-unlock-C9Ro3v_O.d.ts} +1 -1
  214. package/dist/discriminant-BN9REW3o.d.ts +60 -0
  215. package/dist/enclave-UL5LW66V.js +88 -0
  216. package/dist/executor-2FWQRLMG.js +15 -0
  217. package/dist/executor-QZ7BXICW.js +9 -0
  218. package/dist/executor-Z5ZLJVTV.js +9 -0
  219. package/dist/export-accessible-KRV5W4GH.js +17 -0
  220. package/dist/extract-partition-GLKBOXFQ.js +30 -0
  221. package/dist/{fanout-sidecar-OKPMMPLG.js → fanout-sidecar-GF3DJ6KR.js} +34 -14
  222. package/dist/fanout-sidecar-GF3DJ6KR.js.map +1 -0
  223. package/dist/forget/index.d.ts +36 -0
  224. package/dist/forget/index.js +19 -0
  225. package/dist/forget/index.js.map +1 -0
  226. package/dist/guards/index.d.ts +13 -9
  227. package/dist/guards/index.js +12 -5
  228. package/dist/{hash-DdpVypUp.d.cts → hash-Cp5uwiox.d.ts} +5 -1
  229. package/dist/history/index.d.ts +6 -8
  230. package/dist/history/index.js +19 -12
  231. package/dist/history/index.js.map +1 -1
  232. package/dist/i18n/index.d.ts +5 -7
  233. package/dist/i18n/index.js +104 -15
  234. package/dist/i18n/index.js.map +1 -1
  235. package/dist/in/index.d.ts +5 -0
  236. package/dist/in/index.js +1 -0
  237. package/dist/in/index.js.map +1 -0
  238. package/dist/index-B9QdHytu.d.ts +123 -0
  239. package/dist/index-BF9_96A5.d.ts +123 -0
  240. package/dist/{types-Df28QFKb.d.ts → index-BzUo1B6n.d.ts} +16270 -8358
  241. package/dist/index.d.ts +1088 -450
  242. package/dist/index.js +1165 -293
  243. package/dist/index.js.map +1 -1
  244. package/dist/indexing/index.d.ts +6 -3
  245. package/dist/indexing/index.js +6 -5
  246. package/dist/indexing/index.js.map +1 -1
  247. package/dist/issue-Y6UVIR43.js +13 -0
  248. package/dist/issue-Y6UVIR43.js.map +1 -0
  249. package/dist/kernel/index.d.ts +32 -0
  250. package/dist/kernel/index.js +53 -0
  251. package/dist/kernel/index.js.map +1 -0
  252. package/dist/{ledger-TMRZYNVJ.js → ledger-RYI35CDS.js} +12 -9
  253. package/dist/ledger-RYI35CDS.js.map +1 -0
  254. package/dist/liberate-CRPZEV7O.js +18 -0
  255. package/dist/liberate-CRPZEV7O.js.map +1 -0
  256. package/dist/materialized-views/index.d.ts +6 -19
  257. package/dist/materialized-views/index.js +16 -12
  258. package/dist/mime-magic-CGhw37_E.d.ts +103 -0
  259. package/dist/noydb-367AM4HT.js +50 -0
  260. package/dist/noydb-367AM4HT.js.map +1 -0
  261. package/dist/on/index.d.ts +5 -0
  262. package/dist/on/index.js +11 -0
  263. package/dist/on/index.js.map +1 -0
  264. package/dist/overlay-views/index.d.ts +27 -11
  265. package/dist/overlay-views/index.js +7 -6
  266. package/dist/periods/index.d.ts +5 -7
  267. package/dist/periods/index.js +13 -9
  268. package/dist/pod/index.d.ts +63 -0
  269. package/dist/pod/index.js +61 -0
  270. package/dist/pod/index.js.map +1 -0
  271. package/dist/policy-IXK4FVXP.js +41 -0
  272. package/dist/policy-IXK4FVXP.js.map +1 -0
  273. package/dist/portability/index.d.ts +20 -0
  274. package/dist/portability/index.js +43 -0
  275. package/dist/portability/index.js.map +1 -0
  276. package/dist/{public-envelope-BW6OXORV.js → public-envelope-JHDQCPSX.js} +6 -5
  277. package/dist/public-envelope-JHDQCPSX.js.map +1 -0
  278. package/dist/query/index.d.ts +5 -3
  279. package/dist/query/index.js +21 -13
  280. package/dist/read-only-facade-5ADRJVTM.js +8 -0
  281. package/dist/read-only-facade-5ADRJVTM.js.map +1 -0
  282. package/dist/registry-45RJNWGU.js +9 -0
  283. package/dist/registry-45RJNWGU.js.map +1 -0
  284. package/dist/registry-5GRV5VXI.js +13 -0
  285. package/dist/registry-5GRV5VXI.js.map +1 -0
  286. package/dist/registry-VW6P6A3J.js +8 -0
  287. package/dist/registry-VW6P6A3J.js.map +1 -0
  288. package/dist/registry-WEUCHBO4.js +11 -0
  289. package/dist/registry-WEUCHBO4.js.map +1 -0
  290. package/dist/request-withdrawal-GBPH2FDY.js +25 -0
  291. package/dist/request-withdrawal-GBPH2FDY.js.map +1 -0
  292. package/dist/revoke-TUFRGI6S.js +18 -0
  293. package/dist/revoke-TUFRGI6S.js.map +1 -0
  294. package/dist/sealed-record/index.d.ts +69 -0
  295. package/dist/sealed-record/index.js +65 -0
  296. package/dist/sealed-record/index.js.map +1 -0
  297. package/dist/session/index.d.ts +6 -8
  298. package/dist/session/index.js +7 -5
  299. package/dist/session/index.js.map +1 -1
  300. package/dist/shadow/index.d.ts +5 -7
  301. package/dist/shadow/index.js +4 -3
  302. package/dist/shadow/index.js.map +1 -1
  303. package/dist/{signer-72QAUSVW.js → signer-PNKTBVF7.js} +6 -5
  304. package/dist/signer-PNKTBVF7.js.map +1 -0
  305. package/dist/snapshots/index.d.ts +6 -8
  306. package/dist/snapshots/index.js +13 -11
  307. package/dist/snapshots/index.js.map +1 -1
  308. package/dist/{stale-6ZDBTQT7.js → stale-3JWHNDIY.js} +3 -2
  309. package/dist/stale-3JWHNDIY.js.map +1 -0
  310. package/dist/store-coordination-provider-3I7XWZZK.js +142 -0
  311. package/dist/store-coordination-provider-3I7XWZZK.js.map +1 -0
  312. package/dist/subject-index-O75wKshW.d.ts +362 -0
  313. package/dist/sync/index.d.ts +4 -6
  314. package/dist/sync/index.js +7 -6
  315. package/dist/sync/index.js.map +1 -1
  316. package/dist/team/index.d.ts +5 -7
  317. package/dist/team/index.js +20 -16
  318. package/dist/tiers/index.d.ts +5 -0
  319. package/dist/tiers/index.js +33 -0
  320. package/dist/tiers/index.js.map +1 -0
  321. package/dist/to/index.d.ts +5 -0
  322. package/dist/to/index.js +17 -0
  323. package/dist/to/index.js.map +1 -0
  324. package/dist/transition-guard-C7ol6oPw.d.ts +165 -0
  325. package/dist/tx/index.d.ts +23 -9
  326. package/dist/tx/index.js +13 -8
  327. package/dist/tx/index.js.map +1 -1
  328. package/dist/ui/index.d.ts +1 -0
  329. package/dist/ui/index.js +1 -0
  330. package/dist/ui/index.js.map +1 -0
  331. package/dist/ulid-DRH25k3y.d.ts +66 -0
  332. package/dist/ulid-PTAIMDG4.js +10 -0
  333. package/dist/ulid-PTAIMDG4.js.map +1 -0
  334. package/dist/util/index.d.ts +2 -0
  335. package/dist/util/index.js +7 -2
  336. package/dist/util/index.js.map +1 -1
  337. package/dist/vault-diff-B5fYNBL7.d.ts +147 -0
  338. package/dist/with/index.d.ts +38 -0
  339. package/dist/with/index.js +25 -0
  340. package/dist/with/index.js.map +1 -0
  341. package/dist/{with-materialized-view-BLkQxoQN.d.ts → with-materialized-view-6p0Fk8bL.d.ts} +1 -1
  342. package/dist/{with-overlayed-view-CRsSEwHR.d.ts → with-overlayed-view-BJ6mXGMd.d.ts} +2 -3
  343. package/dist/with-rollup-BvQo3ROo.d.ts +47 -0
  344. package/dist/withdraw-accessible-FFS46EOD.js +22 -0
  345. package/dist/withdraw-accessible-FFS46EOD.js.map +1 -0
  346. package/dist/zod-HAJM7LMS.js +14763 -0
  347. package/dist/zod-HAJM7LMS.js.map +1 -0
  348. package/package.json +121 -201
  349. package/dist/aggregate/index.cjs.map +0 -1
  350. package/dist/aggregate/index.d.cts +0 -38
  351. package/dist/attestation/index.cjs +0 -305
  352. package/dist/attestation/index.cjs.map +0 -1
  353. package/dist/attestation/index.d.cts +0 -52
  354. package/dist/blobs/index.cjs +0 -1480
  355. package/dist/blobs/index.cjs.map +0 -1
  356. package/dist/blobs/index.d.cts +0 -46
  357. package/dist/bundle/index.cjs +0 -19264
  358. package/dist/bundle/index.cjs.map +0 -1
  359. package/dist/bundle/index.d.cts +0 -176
  360. package/dist/chunk-22DWZL57.js.map +0 -1
  361. package/dist/chunk-2GLDA55J.js.map +0 -1
  362. package/dist/chunk-2QR2PQTT.js.map +0 -1
  363. package/dist/chunk-2WUSG3IT.js.map +0 -1
  364. package/dist/chunk-3BFJOWSU.js.map +0 -1
  365. package/dist/chunk-3YPCK6JX.js.map +0 -1
  366. package/dist/chunk-53XBRIRT.js.map +0 -1
  367. package/dist/chunk-5T22KDPN.js.map +0 -1
  368. package/dist/chunk-5XHKQ56N.js +0 -340
  369. package/dist/chunk-5XHKQ56N.js.map +0 -1
  370. package/dist/chunk-6CME4UEK.js.map +0 -1
  371. package/dist/chunk-6STK5TQP.js +0 -139
  372. package/dist/chunk-6STK5TQP.js.map +0 -1
  373. package/dist/chunk-A3JMGXPG.js.map +0 -1
  374. package/dist/chunk-B6PB7JLN.js.map +0 -1
  375. package/dist/chunk-BVRYKATC.js.map +0 -1
  376. package/dist/chunk-DE6GKS6G.js.map +0 -1
  377. package/dist/chunk-DFMLEQZB.js.map +0 -1
  378. package/dist/chunk-DJHHA6XH.js.map +0 -1
  379. package/dist/chunk-DL3HWOQ5.js.map +0 -1
  380. package/dist/chunk-DONMZAD2.js.map +0 -1
  381. package/dist/chunk-EMIGCR7X.js.map +0 -1
  382. package/dist/chunk-F3GDRNUT.js.map +0 -1
  383. package/dist/chunk-FZU343FL.js.map +0 -1
  384. package/dist/chunk-H2X3ISXG.js.map +0 -1
  385. package/dist/chunk-HNRHLRDC.js.map +0 -1
  386. package/dist/chunk-I5FOWO4J.js.map +0 -1
  387. package/dist/chunk-J66GRPNH.js.map +0 -1
  388. package/dist/chunk-JWRVQKRZ.js.map +0 -1
  389. package/dist/chunk-K3DK3NU5.js.map +0 -1
  390. package/dist/chunk-ML236QKC.js.map +0 -1
  391. package/dist/chunk-NONAAENK.js.map +0 -1
  392. package/dist/chunk-O3VZPBZG.js.map +0 -1
  393. package/dist/chunk-OIF6LZUR.js.map +0 -1
  394. package/dist/chunk-OQ6PIGHA.js +0 -19
  395. package/dist/chunk-OQ6PIGHA.js.map +0 -1
  396. package/dist/chunk-PE2FR4J3.js.map +0 -1
  397. package/dist/chunk-PP6W64Y3.js +0 -275
  398. package/dist/chunk-PP6W64Y3.js.map +0 -1
  399. package/dist/chunk-PX35GA7L.js.map +0 -1
  400. package/dist/chunk-QEILDE6R.js +0 -793
  401. package/dist/chunk-QEILDE6R.js.map +0 -1
  402. package/dist/chunk-QODLLGQ7.js.map +0 -1
  403. package/dist/chunk-RAZ4OVLL.js +0 -51
  404. package/dist/chunk-RAZ4OVLL.js.map +0 -1
  405. package/dist/chunk-SYMWGEET.js.map +0 -1
  406. package/dist/chunk-T7JEBOGN.js.map +0 -1
  407. package/dist/chunk-TFBP23BX.js.map +0 -1
  408. package/dist/chunk-TV3YZ35S.js +0 -90
  409. package/dist/chunk-TV3YZ35S.js.map +0 -1
  410. package/dist/chunk-U26HQ6KJ.js.map +0 -1
  411. package/dist/chunk-UF3BUNQZ.js +0 -1
  412. package/dist/chunk-UMLVJTYV.js +0 -20
  413. package/dist/chunk-UMLVJTYV.js.map +0 -1
  414. package/dist/chunk-VTKGMEPP.js.map +0 -1
  415. package/dist/chunk-W6EQLGMB.js +0 -100
  416. package/dist/chunk-W6EQLGMB.js.map +0 -1
  417. package/dist/chunk-WIRRPTFH.js +0 -17
  418. package/dist/chunk-WIRRPTFH.js.map +0 -1
  419. package/dist/chunk-WPLVTJ5D.js.map +0 -1
  420. package/dist/chunk-XJFLDA7A.js.map +0 -1
  421. package/dist/chunk-Z6FNBOTC.js.map +0 -1
  422. package/dist/chunk-ZYWZWG6G.js.map +0 -1
  423. package/dist/consent/index.cjs +0 -204
  424. package/dist/consent/index.cjs.map +0 -1
  425. package/dist/consent/index.d.cts +0 -25
  426. package/dist/crdt/index.cjs +0 -152
  427. package/dist/crdt/index.cjs.map +0 -1
  428. package/dist/crdt/index.d.cts +0 -30
  429. package/dist/crypto-HTZ4FJOP.js +0 -44
  430. package/dist/delegation-RI54P6I5.js +0 -17
  431. package/dist/derivations/index.cjs +0 -351
  432. package/dist/derivations/index.cjs.map +0 -1
  433. package/dist/derivations/index.d.cts +0 -72
  434. package/dist/dev-unlock-BIoEFbwm.d.cts +0 -263
  435. package/dist/executor-5PNY7LGW.js +0 -8
  436. package/dist/executor-B4QIYGZX.js +0 -8
  437. package/dist/executor-BWXXDQ7K.js +0 -11
  438. package/dist/fanout-sidecar-OKPMMPLG.js.map +0 -1
  439. package/dist/guards/index.cjs +0 -322
  440. package/dist/guards/index.cjs.map +0 -1
  441. package/dist/guards/index.d.cts +0 -31
  442. package/dist/hash-HJqD14vS.d.ts +0 -63
  443. package/dist/history/index.cjs +0 -1222
  444. package/dist/history/index.cjs.map +0 -1
  445. package/dist/history/index.d.cts +0 -63
  446. package/dist/i18n/index.cjs +0 -1100
  447. package/dist/i18n/index.cjs.map +0 -1
  448. package/dist/i18n/index.d.cts +0 -39
  449. package/dist/index-4fBVt8j9.d.cts +0 -2387
  450. package/dist/index-D8I_pyJD.d.ts +0 -2387
  451. package/dist/index.cjs +0 -24487
  452. package/dist/index.cjs.map +0 -1
  453. package/dist/index.d.cts +0 -776
  454. package/dist/indexing/index.cjs +0 -742
  455. package/dist/indexing/index.cjs.map +0 -1
  456. package/dist/indexing/index.d.cts +0 -36
  457. package/dist/issue-VGDPP4B5.js +0 -12
  458. package/dist/lazy-builder-7tIpFyWN.d.ts +0 -304
  459. package/dist/lazy-builder-wY4pMCEe.d.cts +0 -304
  460. package/dist/materialized-views/index.cjs +0 -854
  461. package/dist/materialized-views/index.cjs.map +0 -1
  462. package/dist/materialized-views/index.d.cts +0 -186
  463. package/dist/mime-magic-CBBSOkjm.d.cts +0 -50
  464. package/dist/mime-magic-CBBSOkjm.d.ts +0 -50
  465. package/dist/noydb-G725ZSZG.js +0 -34
  466. package/dist/overlay-views/index.cjs +0 -359
  467. package/dist/overlay-views/index.cjs.map +0 -1
  468. package/dist/overlay-views/index.d.cts +0 -82
  469. package/dist/periods/index.cjs +0 -1041
  470. package/dist/periods/index.cjs.map +0 -1
  471. package/dist/periods/index.d.cts +0 -22
  472. package/dist/predicate-BSAGEyu5.d.cts +0 -209
  473. package/dist/predicate-BSAGEyu5.d.ts +0 -209
  474. package/dist/query/index.cjs +0 -2375
  475. package/dist/query/index.cjs.map +0 -1
  476. package/dist/query/index.d.cts +0 -3
  477. package/dist/read-only-facade-ITU6L7BL.js +0 -7
  478. package/dist/registry-3QP3YKQS.js +0 -8
  479. package/dist/registry-DKEXOJVO.js +0 -7
  480. package/dist/registry-OJIOSBV6.js +0 -10
  481. package/dist/registry-USRVT6YF.js +0 -8
  482. package/dist/revoke-JCC7N56X.js +0 -17
  483. package/dist/session/index.cjs +0 -495
  484. package/dist/session/index.cjs.map +0 -1
  485. package/dist/session/index.d.cts +0 -46
  486. package/dist/shadow/index.cjs +0 -133
  487. package/dist/shadow/index.cjs.map +0 -1
  488. package/dist/shadow/index.d.cts +0 -17
  489. package/dist/snapshots/index.cjs +0 -937
  490. package/dist/snapshots/index.cjs.map +0 -1
  491. package/dist/snapshots/index.d.cts +0 -28
  492. package/dist/store/index.cjs +0 -1083
  493. package/dist/store/index.cjs.map +0 -1
  494. package/dist/store/index.d.cts +0 -492
  495. package/dist/store/index.d.ts +0 -492
  496. package/dist/store/index.js +0 -37
  497. package/dist/strategy-BSxFXGzb.d.cts +0 -110
  498. package/dist/strategy-BSxFXGzb.d.ts +0 -110
  499. package/dist/strategy-DSTrsZ8t.d.cts +0 -601
  500. package/dist/strategy-DSTrsZ8t.d.ts +0 -601
  501. package/dist/sync/index.cjs +0 -1062
  502. package/dist/sync/index.cjs.map +0 -1
  503. package/dist/sync/index.d.cts +0 -43
  504. package/dist/team/index.cjs +0 -2798
  505. package/dist/team/index.cjs.map +0 -1
  506. package/dist/team/index.d.cts +0 -118
  507. package/dist/tx/index.cjs +0 -544
  508. package/dist/tx/index.cjs.map +0 -1
  509. package/dist/tx/index.d.cts +0 -21
  510. package/dist/types-DyXYr8rE.d.cts +0 -12818
  511. package/dist/ulid-COREQ2RQ.js +0 -9
  512. package/dist/ulid-Drr7ykr6.d.cts +0 -603
  513. package/dist/util/index.cjs +0 -230
  514. package/dist/util/index.cjs.map +0 -1
  515. package/dist/util/index.d.cts +0 -77
  516. package/dist/with-derivation-DFnFByiQ.d.ts +0 -13
  517. package/dist/with-derivation-DU3Sjazm.d.cts +0 -13
  518. package/dist/with-guard-ByyxmEe7.d.cts +0 -18
  519. package/dist/with-guard-qube6BMI.d.ts +0 -18
  520. package/dist/with-materialized-view-BmEToIR1.d.cts +0 -27
  521. package/dist/with-overlayed-view-BMsQQbWm.d.cts +0 -13
  522. /package/dist/{store → adapter}/index.js.map +0 -0
  523. /package/dist/{chunk-UF3BUNQZ.js.map → api-RW3KP7WU.js.map} +0 -0
  524. /package/dist/{crypto-HTZ4FJOP.js.map → as/index.js.map} +0 -0
  525. /package/dist/{delegation-RI54P6I5.js.map → at/index.js.map} +0 -0
  526. /package/dist/{executor-5PNY7LGW.js.map → by/index.js.map} +0 -0
  527. /package/dist/{executor-B4QIYGZX.js.map → cargo/index.js.map} +0 -0
  528. /package/dist/{executor-BWXXDQ7K.js.map → chunk-BGIZAFY7.js.map} +0 -0
  529. /package/dist/{issue-VGDPP4B5.js.map → chunk-CHFZDSE4.js.map} +0 -0
  530. /package/dist/{ledger-TMRZYNVJ.js.map → chunk-GHVIKOHT.js.map} +0 -0
  531. /package/dist/{noydb-G725ZSZG.js.map → chunk-K2WCO3NX.js.map} +0 -0
  532. /package/dist/{public-envelope-BW6OXORV.js.map → chunk-PZ5AY32C.js.map} +0 -0
  533. /package/dist/{read-only-facade-ITU6L7BL.js.map → collection-facade-GQAOGJP2.js.map} +0 -0
  534. /package/dist/{registry-3QP3YKQS.js.map → delegation-UL5HKLER.js.map} +0 -0
  535. /package/dist/{registry-DKEXOJVO.js.map → describe/index.js.map} +0 -0
  536. /package/dist/{registry-OJIOSBV6.js.map → enclave-UL5LW66V.js.map} +0 -0
  537. /package/dist/{registry-USRVT6YF.js.map → executor-2FWQRLMG.js.map} +0 -0
  538. /package/dist/{revoke-JCC7N56X.js.map → executor-QZ7BXICW.js.map} +0 -0
  539. /package/dist/{signer-72QAUSVW.js.map → executor-Z5ZLJVTV.js.map} +0 -0
  540. /package/dist/{stale-6ZDBTQT7.js.map → export-accessible-KRV5W4GH.js.map} +0 -0
  541. /package/dist/{ulid-COREQ2RQ.js.map → extract-partition-GLKBOXFQ.js.map} +0 -0
@@ -5,37 +5,40 @@ import {
5
5
  getCredential,
6
6
  listCredentials,
7
7
  putCredential
8
- } from "../chunk-ZYWZWG6G.js";
8
+ } from "../chunk-DGDI2D4M.js";
9
9
  import {
10
- burnPaperRecoveryEntry,
11
10
  deriveMagicLinkContentKey,
12
11
  enrollAuthenticator,
13
12
  findAuthenticator,
14
13
  isMagicLinkGrantExpired,
15
14
  listMagicLinkGrants,
16
- loadPaperRecoveryEntries,
17
15
  magicLinkGrantRecordId,
18
- mintPaperRecoveryEntry,
19
- mintWrappedDeksBlob,
20
16
  readMagicLinkGrantRecord,
21
17
  recoverPassphrase,
22
18
  recoverUser,
23
19
  removeAuthenticator,
24
20
  revokeMagicLinkGrant,
25
21
  rotatePassphrase,
26
- savePaperRecoveryEntries,
27
- unwrapDeksFromBlob,
28
- unwrapDeksFromPaperEntry,
29
22
  unwrapMagicLinkGrant,
30
23
  updateAuthenticator,
31
24
  writeMagicLinkGrant
32
- } from "../chunk-3YPCK6JX.js";
33
- import "../chunk-U26HQ6KJ.js";
25
+ } from "../chunk-UPJNJGGA.js";
26
+ import {
27
+ burnPaperRecoveryEntry,
28
+ loadPaperRecoveryEntries,
29
+ mintPaperRecoveryEntry,
30
+ mintWrappedDeksBlob,
31
+ savePaperRecoveryEntries,
32
+ unwrapDeksFromBlob,
33
+ unwrapDeksFromPaperEntry
34
+ } from "../chunk-IGUYVGGI.js";
35
+ import "../chunk-IO6GRPT6.js";
34
36
  import {
35
37
  PresenceHandle,
36
38
  SyncEngine,
37
39
  SyncTransaction
38
- } from "../chunk-WPLVTJ5D.js";
40
+ } from "../chunk-IUEN57TV.js";
41
+ import "../chunk-VQNJ7UZL.js";
39
42
  import {
40
43
  buildRecipientKeyringFile,
41
44
  changeSecret,
@@ -52,11 +55,12 @@ import {
52
55
  persistKeyring,
53
56
  revoke,
54
57
  updateKeyringIdentity
55
- } from "../chunk-DONMZAD2.js";
56
- import "../chunk-2QR2PQTT.js";
57
- import "../chunk-WIRRPTFH.js";
58
- import "../chunk-PP6W64Y3.js";
59
- import "../chunk-B6PB7JLN.js";
58
+ } from "../chunk-WWGT2MDV.js";
59
+ import "../chunk-ITNUCOXM.js";
60
+ import "../chunk-5O3AOPDT.js";
61
+ import "../chunk-5TDJ56JE.js";
62
+ import "../chunk-ZYUC53LT.js";
63
+ import "../chunk-PZ5AY32C.js";
60
64
  export {
61
65
  PresenceHandle,
62
66
  SYNC_CREDENTIALS_COLLECTION,
@@ -0,0 +1,5 @@
1
+ export { l0 as NO_TIERS, l1 as TiersContext, iZ as TiersNotEnabledError, l2 as TiersStrategy, l3 as assertDeclaredTier, l4 as assertTiersEnabled, l5 as classifySealedShred, l6 as demote, l7 as elevate, l8 as getAtTier, l9 as listAtTier, la as putAtTier, lb as withTiers } from '../index-BzUo1B6n.js';
2
+ import '../subject-index-O75wKshW.js';
3
+ import '../describe-aBkJR2sd.js';
4
+ import '../index-B9QdHytu.js';
5
+ import '@noy-db/attestation';
@@ -0,0 +1,33 @@
1
+ import {
2
+ NO_TIERS,
3
+ assertDeclaredTier,
4
+ assertTiersEnabled,
5
+ classifySealedShred,
6
+ demote,
7
+ elevate,
8
+ getAtTier,
9
+ listAtTier,
10
+ putAtTier,
11
+ withTiers
12
+ } from "../chunk-IPB7FTQX.js";
13
+ import "../chunk-IO6GRPT6.js";
14
+ import "../chunk-5O3AOPDT.js";
15
+ import "../chunk-5TDJ56JE.js";
16
+ import {
17
+ TiersNotEnabledError
18
+ } from "../chunk-ZYUC53LT.js";
19
+ import "../chunk-PZ5AY32C.js";
20
+ export {
21
+ NO_TIERS,
22
+ TiersNotEnabledError,
23
+ assertDeclaredTier,
24
+ assertTiersEnabled,
25
+ classifySealedShred,
26
+ demote,
27
+ elevate,
28
+ getAtTier,
29
+ listAtTier,
30
+ putAtTier,
31
+ withTiers
32
+ };
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,5 @@
1
+ export { dq as BundleVersionConflictError, eJ as ConflictError, cV as EncryptedEnvelope, ge as ListPageResult, gM as NetworkError, gS as NoydbBundleStore, bX as NoydbPodStore, cT as NoydbStore, du as PodVersionConflictError, iD as StoreCapabilities, iE as StoreCapabilityError, iF as StoreTime, j1 as TxOp, jg as VaultSnapshot } from '../index-BzUo1B6n.js';
2
+ import '../subject-index-O75wKshW.js';
3
+ import '../describe-aBkJR2sd.js';
4
+ import '../index-B9QdHytu.js';
5
+ import '@noy-db/attestation';
@@ -0,0 +1,17 @@
1
+ import "../chunk-K2WCO3NX.js";
2
+ import {
3
+ BundleVersionConflictError,
4
+ ConflictError,
5
+ NetworkError,
6
+ PodVersionConflictError,
7
+ StoreCapabilityError
8
+ } from "../chunk-ZYUC53LT.js";
9
+ import "../chunk-PZ5AY32C.js";
10
+ export {
11
+ BundleVersionConflictError,
12
+ ConflictError,
13
+ NetworkError,
14
+ PodVersionConflictError,
15
+ StoreCapabilityError
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,165 @@
1
+ import { bJ as GuardStrategy, bP as GuardStrategyHandle, bK as GuardChange, bL as GuardContext } from './index-BzUo1B6n.js';
2
+
3
+ /**
4
+ * Register a guard for a collection. Guards run on every `put()` /
5
+ * `delete()` for the named collection (after permissions, before
6
+ * encryption) and may:
7
+ *
8
+ * - `check` — block writes by throwing (typically `RecordLockedError`)
9
+ * - `frozenFields` — freeze specific fields once a condition is true
10
+ * - `amendment` — declare an authorized-override path with invariant
11
+ *
12
+ * Pass the returned handle to `createNoydb({ strategies: [...] })`.
13
+ *
14
+ * @see docs/superpowers/specs/2026-05-18-guards-design.md
15
+ */
16
+ declare function withGuard<T extends Record<string, unknown>>(strategy: GuardStrategy<T>): GuardStrategyHandle<T>;
17
+
18
+ /**
19
+ * `immutableGuard` — declarative WORM / append-only sugar over the guard
20
+ * service.
21
+ *
22
+ * Issued fiscal documents (invoices, DDTs) must be immutable after issue.
23
+ * That is expressible today with a hand-rolled `withGuard` (block on
24
+ * `check`/`onDelete`, allow an admin `amendment`), but the boilerplate is
25
+ * repetitive and easy to get subtly wrong. `immutableGuard` generates
26
+ * exactly that guard from a declarative config, reusing the guard
27
+ * machinery wholesale — `check`/`onDelete` rejection, the ledgered
28
+ * `amendment` override, and composition with `periods`/`history`.
29
+ *
30
+ * ```ts
31
+ * createNoydb({ guardStrategies: [
32
+ * immutableGuard({
33
+ * collection: 'invoices',
34
+ * after: (r) => r.status === 'issued', // immutable once issued
35
+ * }),
36
+ * ] })
37
+ * ```
38
+ *
39
+ * A record is mutable until `after(record)` holds; from then on, updates
40
+ * and deletes throw `RecordLockedError` unless performed inside an
41
+ * `amendment` transaction by an authorized role (the override is
42
+ * ledgered by the guard amendment mechanism). `appendOnly: true` is
43
+ * shorthand for `after: () => true` — immutable from creation.
44
+ */
45
+
46
+ interface ImmutableGuardConfig<T extends Record<string, unknown>> {
47
+ /** The collection to make WORM. */
48
+ collection: string;
49
+ /**
50
+ * A record becomes immutable once this predicate holds. Evaluated on
51
+ * the *existing* (already-persisted) record, so the write that first
52
+ * makes it true is still allowed; subsequent writes are blocked.
53
+ * Mutually exclusive with `appendOnly`.
54
+ */
55
+ after?: (record: T) => boolean;
56
+ /** Shorthand for `after: () => true` — immutable from creation. */
57
+ appendOnly?: boolean;
58
+ /** Roles permitted to override via an amendment transaction. Default `['admin', 'owner']`. */
59
+ amendmentRoles?: ReadonlyArray<'admin' | 'owner'>;
60
+ /**
61
+ * Optional set-level invariant run over the amendment change-set after
62
+ * the writes execute. Signature matches `GuardStrategy.amendment.invariant`
63
+ * exactly: it receives every {before, after} pair touching this
64
+ * collection in the amendment plus the guard context; throwing reverts
65
+ * the whole amendment and surfaces as `InvariantError`.
66
+ *
67
+ * Use this to keep a constraint inviolable EVEN under amendment — e.g.
68
+ * forbid deleting an issued document by re-throwing on any
69
+ * `before !== null && after === null` change, or assert a cross-record
70
+ * sum is preserved. When omitted the amendment is unconditionally
71
+ * allowed (the amendment itself is the sanctioned, ledgered override) —
72
+ * this is the backward-compatible default.
73
+ */
74
+ amendmentInvariant?: (changes: ReadonlyArray<GuardChange<T>>, ctx: GuardContext<T>) => Promise<void> | void;
75
+ }
76
+ /**
77
+ * Build an immutability guard. Pass the returned handle to
78
+ * `createNoydb({ guardStrategies: [...] })`.
79
+ */
80
+ declare function immutableGuard<T extends Record<string, unknown>>(config: ImmutableGuardConfig<T>): GuardStrategyHandle<T>;
81
+
82
+ /**
83
+ * `transitionGuard` — declarative state-machine sugar over the guard
84
+ * service.
85
+ *
86
+ * Any record with a lifecycle field (invoice `status`, order state,
87
+ * ticket workflow, subscription phase) needs transition validation: a
88
+ * write may only move the field along a declared arc. That is expressible
89
+ * with a hand-rolled `withGuard({ check })`, but every consumer
90
+ * re-implements the same graph lookup + error. `transitionGuard`
91
+ * generates exactly that guard from a state graph, reusing the guard
92
+ * machinery wholesale — `check` rejection, the ledgered `amendment`
93
+ * override, and composition with `periods`/`history`.
94
+ *
95
+ * It generalizes {@link immutableGuard}: WORM is the special case "every
96
+ * state has no outgoing arcs", i.e. `transitions` mapping each state to `[]`.
97
+ *
98
+ * ```ts
99
+ * createNoydb({ guardStrategies: [
100
+ * transitionGuard<Sale>({
101
+ * collection: 'sales', field: 'status',
102
+ * transitions: { // absence of an arc = forbidden
103
+ * draft: ['to_verify', 'cancelled'],
104
+ * to_verify: ['proforma', 'draft', 'cancelled'],
105
+ * proforma: ['invoiced', 'cancelled'],
106
+ * invoiced: ['paid'], paid: [], cancelled: [],
107
+ * },
108
+ * initial: ['draft', 'to_verify'], // allowed status on insert
109
+ * }),
110
+ * ] })
111
+ * ```
112
+ *
113
+ * Semantics:
114
+ * - **Insert** (`ctx.existing === null`): `incoming[field]` must be in
115
+ * `initial`. When `initial` is omitted, any value is allowed on insert.
116
+ * - **Update**: the arc `(existing[field] → incoming[field])` must be
117
+ * listed in `transitions[from]`, else `IllegalTransitionError`. A
118
+ * same-value write (`from === to`) is allowed when `allowIdempotent`
119
+ * (default `true`) — so writes that touch other fields without moving
120
+ * state pass.
121
+ * - **Override**: inside an `amendment` transaction by an authorized role
122
+ * the check is skipped and the change is ledgered (mirrors every guard).
123
+ *
124
+ * The status graph is caller-supplied data — no UI, no domain logic.
125
+ */
126
+
127
+ interface TransitionGuardConfig<T extends Record<string, unknown>> {
128
+ /** The collection whose state field is governed. */
129
+ collection: string;
130
+ /** The state field on the record (e.g. `'status'`). */
131
+ field: keyof T & string;
132
+ /**
133
+ * The transition graph: each state maps to the states it may move to.
134
+ * A state absent from the map (or mapped to `[]`) is terminal — no
135
+ * outgoing arc, so any non-idempotent write from it is rejected.
136
+ */
137
+ transitions: Readonly<Record<string, readonly string[]>>;
138
+ /**
139
+ * States allowed as the initial value on insert (`existing === null`).
140
+ * Omit to allow any value on insert.
141
+ */
142
+ initial?: readonly string[];
143
+ /**
144
+ * Allow a same-value write (`from === to`) on update. Default `true` —
145
+ * lets a put that changes other fields, but not the state, through.
146
+ */
147
+ allowIdempotent?: boolean;
148
+ /** Roles permitted to override via an amendment transaction. Default `['admin', 'owner']`. */
149
+ amendmentRoles?: ReadonlyArray<'admin' | 'owner'>;
150
+ /**
151
+ * Optional set-level invariant run over the amendment change-set after
152
+ * the writes execute. Signature matches `GuardStrategy.amendment.invariant`
153
+ * exactly. When omitted the amendment is unconditionally allowed (the
154
+ * amendment itself is the sanctioned, ledgered override) — the
155
+ * backward-compatible default. Mirrors {@link immutableGuard}.
156
+ */
157
+ amendmentInvariant?: (changes: ReadonlyArray<GuardChange<T>>, ctx: GuardContext<T>) => Promise<void> | void;
158
+ }
159
+ /**
160
+ * Build a state-machine transition guard. Pass the returned handle to
161
+ * `createNoydb({ guardStrategies: [...] })`.
162
+ */
163
+ declare function transitionGuard<T extends Record<string, unknown>>(config: TransitionGuardConfig<T>): GuardStrategyHandle<T>;
164
+
165
+ export { type ImmutableGuardConfig as I, type TransitionGuardConfig as T, immutableGuard as i, transitionGuard as t, withGuard as w };
@@ -1,21 +1,35 @@
1
- import { aH as TxStrategy } from '../types-Df28QFKb.js';
2
- export { aI as AmendmentTxOptions, aJ as TxCollection, aK as TxContext, aL as TxVault, aM as runTransaction } from '../types-Df28QFKb.js';
3
- import '../lazy-builder-7tIpFyWN.js';
4
- import '../predicate-BSAGEyu5.js';
5
- import '../strategy-DSTrsZ8t.js';
6
- import '../strategy-BSxFXGzb.js';
7
- import '../index-D8I_pyJD.js';
1
+ import { i_ as TransactionInvariant, kX as TxStrategy } from '../index-BzUo1B6n.js';
2
+ export { kY as AmendmentTxOptions, j0 as TxCollection, dP as TxContext, j2 as TxVault, kx as runTransaction } from '../index-BzUo1B6n.js';
3
+ import '../subject-index-O75wKshW.js';
4
+ import '../describe-aBkJR2sd.js';
5
+ import '../index-B9QdHytu.js';
8
6
  import '@noy-db/attestation';
9
7
 
10
8
  /**
11
9
  * Active transactions strategy. Only reachable via `@noy-db/hub/tx`.
12
10
  */
13
11
 
12
+ /**
13
+ * Options for {@link withTransactions}. Currently only commit-time
14
+ * changeset `invariants` (see {@link TransactionInvariant}).
15
+ */
16
+ interface TransactionStrategyOptions {
17
+ /**
18
+ * Commit-time set-level invariants run over the changeset on every
19
+ * commit (ordinary AND amendment). See {@link TransactionInvariant}.
20
+ */
21
+ invariants?: ReadonlyArray<TransactionInvariant>;
22
+ }
14
23
  /**
15
24
  * Build the default transactions strategy. Pass into
16
25
  * `createNoydb({ txStrategy: withTransactions() })` to enable
17
26
  * `db.transaction(fn)` (and `db.transaction({ dryRun: true }, fn)`).
27
+ *
28
+ * Supply `{ invariants }` to register commit-time changeset invariants —
29
+ * set-level constraints that fire after the writes commit and revert the
30
+ * transaction on a throw. Unlike `amendment.invariant`, these run for
31
+ * ordinary `db.transaction(fn)` calls (and amendments) with no role gate.
18
32
  */
19
- declare function withTransactions(): TxStrategy;
33
+ declare function withTransactions(opts?: TransactionStrategyOptions): TxStrategy;
20
34
 
21
- export { TxStrategy, withTransactions };
35
+ export { TransactionInvariant, type TransactionStrategyOptions, TxStrategy, withTransactions };
package/dist/tx/index.js CHANGED
@@ -3,11 +3,12 @@ import {
3
3
  TxContext,
4
4
  TxVault,
5
5
  runTransaction
6
- } from "../chunk-TFBP23BX.js";
7
- import "../chunk-FZU343FL.js";
8
- import "../chunk-B6PB7JLN.js";
6
+ } from "../chunk-SKF73JOP.js";
7
+ import "../chunk-ZJADGNYF.js";
8
+ import "../chunk-ZYUC53LT.js";
9
+ import "../chunk-PZ5AY32C.js";
9
10
 
10
- // src/tx/dry-run.ts
11
+ // src/with-commit/tx/dry-run.ts
11
12
  var SEP = " ";
12
13
  var keyOf = (op) => `${op.vaultName}${SEP}${op.collectionName}${SEP}${op.id}`;
13
14
  async function runDryRun(db, fn) {
@@ -43,7 +44,7 @@ async function runDryRun(db, fn) {
43
44
  const gctx = { existing: before, vault: facade, userId: v.userId, role: v.role };
44
45
  try {
45
46
  await registry.runChecks(op.collectionName, after, gctx);
46
- const { GuardExecutor } = await import("../executor-5PNY7LGW.js");
47
+ const { GuardExecutor } = await import("../executor-QZ7BXICW.js");
47
48
  for (const g of guards) {
48
49
  await GuardExecutor.checkFrozenFields(g, op.id, before, after);
49
50
  }
@@ -59,9 +60,13 @@ async function runDryRun(db, fn) {
59
60
  return { affected, guardViolations };
60
61
  }
61
62
 
62
- // src/tx/active.ts
63
- function withTransactions() {
64
- return { runTransaction, runDryRun };
63
+ // src/with-commit/tx/active.ts
64
+ function withTransactions(opts) {
65
+ const invariants = opts?.invariants ?? [];
66
+ return {
67
+ runTransaction: (db, fn, options) => runTransaction(db, fn, options, invariants),
68
+ runDryRun
69
+ };
65
70
  }
66
71
  export {
67
72
  TxCollection,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tx/dry-run.ts","../../src/tx/active.ts"],"sourcesContent":["/**\n * Dry-run transactions. Runs the tx body to STAGE ops, then builds\n * the directly-affected diff (before = current committed via collection.get,\n * after = staged record) and collects guard violations — without executing\n * phase 2. No adapter writes, no write-hooks, no commit. MV/derivation\n * cascade is NOT simulated (v2). Mirrors the guard loop in\n * `Collection.putInternal` — keep the two in sync.\n */\nimport type { Noydb } from '../noydb.js'\nimport { TxContext, type StagedOp } from './transaction.js'\nimport type { GuardExecutor as GuardExecutorType } from '../guards/executor.js'\n\nexport interface AffectedDocument {\n readonly vault: string\n readonly op: 'create' | 'update' | 'delete'\n readonly collection: string\n readonly docId: string\n readonly before: unknown // current committed record; null when creating\n readonly after: unknown // staged record; null when deleting\n}\n\nexport interface GuardViolation {\n readonly vault: string\n readonly collection: string\n readonly docId: string\n readonly message: string\n}\n\nexport interface DryRunResult {\n readonly affected: ReadonlyArray<AffectedDocument>\n readonly guardViolations: ReadonlyArray<GuardViolation>\n}\n\nconst SEP = ' '\nconst keyOf = (op: StagedOp) => `${op.vaultName}${SEP}${op.collectionName}${SEP}${op.id}`\n\nexport async function runDryRun(\n db: Noydb,\n fn: (tx: TxContext) => unknown,\n): Promise<DryRunResult> {\n const ctx = new TxContext(db)\n await fn(ctx) // stage ops (reads see staged writes via TxCollection); nothing committed\n\n // Dedup by (vault, collection, id) — last staged op wins.\n const lastOp = new Map<string, StagedOp>()\n for (const op of ctx._ops) lastOp.set(keyOf(op), op)\n\n const affected: AffectedDocument[] = []\n const guardViolations: GuardViolation[] = []\n\n for (const op of lastOp.values()) {\n const v = db.vault(op.vaultName)\n const coll = v.collection(op.collectionName)\n const before = await coll.get(op.id)\n\n if (op.type === 'delete') {\n affected.push({ vault: op.vaultName, op: 'delete', collection: op.collectionName, docId: op.id, before, after: null })\n continue\n }\n\n const after = op.record ?? null\n affected.push({\n vault: op.vaultName,\n op: before === null ? 'create' : 'update',\n collection: op.collectionName,\n docId: op.id,\n before,\n after,\n })\n\n // Guard violations — run the SAME checks Collection.putInternal does,\n // with the SAME ctx (existing + read-only facade + userId + role), but\n // collect the first thrown error instead of aborting.\n const registry = v._getGuardRegistry()\n if (!registry) continue\n const guards = registry.guardsFor(op.collectionName)\n if (guards.length === 0) continue\n const facade = v._getReadOnlyFacade()\n if (!facade) continue\n const gctx = { existing: before as Record<string, unknown> | null, vault: facade, userId: v.userId, role: v.role }\n try {\n await registry.runChecks(op.collectionName, after as Record<string, unknown>, gctx)\n const { GuardExecutor } = (await import('../guards/executor.js')) as { GuardExecutor: typeof GuardExecutorType }\n for (const g of guards) {\n await GuardExecutor.checkFrozenFields(g, op.id, before as Record<string, unknown> | null, after as Record<string, unknown>)\n }\n } catch (err) {\n guardViolations.push({\n vault: op.vaultName,\n collection: op.collectionName,\n docId: op.id,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return { affected, guardViolations }\n}\n","/**\n * Active transactions strategy. Only reachable via `@noy-db/hub/tx`.\n */\n\nimport { runTransaction } from './transaction.js'\nimport { runDryRun } from './dry-run.js'\nimport type { TxStrategy } from './strategy.js'\n\n/**\n * Build the default transactions strategy. Pass into\n * `createNoydb({ txStrategy: withTransactions() })` to enable\n * `db.transaction(fn)` (and `db.transaction({ dryRun: true }, fn)`).\n */\nexport function withTransactions(): TxStrategy {\n return { runTransaction, runDryRun }\n}\n"],"mappings":";;;;;;;;;;AAiCA,IAAM,MAAM;AACZ,IAAM,QAAQ,CAAC,OAAiB,GAAG,GAAG,SAAS,GAAG,GAAG,GAAG,GAAG,cAAc,GAAG,GAAG,GAAG,GAAG,EAAE;AAEvF,eAAsB,UACpB,IACA,IACuB;AACvB,QAAM,MAAM,IAAI,UAAU,EAAE;AAC5B,QAAM,GAAG,GAAG;AAGZ,QAAM,SAAS,oBAAI,IAAsB;AACzC,aAAW,MAAM,IAAI,KAAM,QAAO,IAAI,MAAM,EAAE,GAAG,EAAE;AAEnD,QAAM,WAA+B,CAAC;AACtC,QAAM,kBAAoC,CAAC;AAE3C,aAAW,MAAM,OAAO,OAAO,GAAG;AAChC,UAAM,IAAI,GAAG,MAAM,GAAG,SAAS;AAC/B,UAAM,OAAO,EAAE,WAAW,GAAG,cAAc;AAC3C,UAAM,SAAS,MAAM,KAAK,IAAI,GAAG,EAAE;AAEnC,QAAI,GAAG,SAAS,UAAU;AACxB,eAAS,KAAK,EAAE,OAAO,GAAG,WAAW,IAAI,UAAU,YAAY,GAAG,gBAAgB,OAAO,GAAG,IAAI,QAAQ,OAAO,KAAK,CAAC;AACrH;AAAA,IACF;AAEA,UAAM,QAAQ,GAAG,UAAU;AAC3B,aAAS,KAAK;AAAA,MACZ,OAAO,GAAG;AAAA,MACV,IAAI,WAAW,OAAO,WAAW;AAAA,MACjC,YAAY,GAAG;AAAA,MACf,OAAO,GAAG;AAAA,MACV;AAAA,MACA;AAAA,IACF,CAAC;AAKD,UAAM,WAAW,EAAE,kBAAkB;AACrC,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,SAAS,UAAU,GAAG,cAAc;AACnD,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,SAAS,EAAE,mBAAmB;AACpC,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,EAAE,UAAU,QAA0C,OAAO,QAAQ,QAAQ,EAAE,QAAQ,MAAM,EAAE,KAAK;AACjH,QAAI;AACF,YAAM,SAAS,UAAU,GAAG,gBAAgB,OAAkC,IAAI;AAClF,YAAM,EAAE,cAAc,IAAK,MAAM,OAAO,yBAAuB;AAC/D,iBAAW,KAAK,QAAQ;AACtB,cAAM,cAAc,kBAAkB,GAAG,GAAG,IAAI,QAA0C,KAAgC;AAAA,MAC5H;AAAA,IACF,SAAS,KAAK;AACZ,sBAAgB,KAAK;AAAA,QACnB,OAAO,GAAG;AAAA,QACV,YAAY,GAAG;AAAA,QACf,OAAO,GAAG;AAAA,QACV,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,gBAAgB;AACrC;;;ACpFO,SAAS,mBAA+B;AAC7C,SAAO,EAAE,gBAAgB,UAAU;AACrC;","names":[]}
1
+ {"version":3,"sources":["../../src/with-commit/tx/dry-run.ts","../../src/with-commit/tx/active.ts"],"sourcesContent":["/**\n * Dry-run transactions. Runs the tx body to STAGE ops, then builds\n * the directly-affected diff (before = current committed via collection.get,\n * after = staged record) and collects guard violations — without executing\n * phase 2. No adapter writes, no write-hooks, no commit. MV/derivation\n * cascade is NOT simulated (v2). Mirrors the guard loop in\n * `Collection._putInternal` — keep the two in sync.\n */\nimport type { Noydb } from '../../kernel/noydb.js'\nimport { TxContext, type StagedOp } from './transaction.js'\nimport type { GuardExecutor as GuardExecutorType } from '../../with-audit/guards/executor.js'\n\nexport interface AffectedDocument {\n readonly vault: string\n readonly op: 'create' | 'update' | 'delete'\n readonly collection: string\n readonly docId: string\n readonly before: unknown // current committed record; null when creating\n readonly after: unknown // staged record; null when deleting\n}\n\nexport interface GuardViolation {\n readonly vault: string\n readonly collection: string\n readonly docId: string\n readonly message: string\n}\n\nexport interface DryRunResult {\n readonly affected: ReadonlyArray<AffectedDocument>\n readonly guardViolations: ReadonlyArray<GuardViolation>\n}\n\nconst SEP = ' '\nconst keyOf = (op: StagedOp) => `${op.vaultName}${SEP}${op.collectionName}${SEP}${op.id}`\n\nexport async function runDryRun(\n db: Noydb,\n fn: (tx: TxContext) => unknown,\n): Promise<DryRunResult> {\n const ctx = new TxContext(db)\n await fn(ctx) // stage ops (reads see staged writes via TxCollection); nothing committed\n\n // Dedup by (vault, collection, id) — last staged op wins.\n const lastOp = new Map<string, StagedOp>()\n for (const op of ctx._ops) lastOp.set(keyOf(op), op)\n\n const affected: AffectedDocument[] = []\n const guardViolations: GuardViolation[] = []\n\n for (const op of lastOp.values()) {\n const v = db.vault(op.vaultName)\n const coll = v.collection(op.collectionName)\n const before = await coll.get(op.id)\n\n if (op.type === 'delete') {\n affected.push({ vault: op.vaultName, op: 'delete', collection: op.collectionName, docId: op.id, before, after: null })\n continue\n }\n\n const after = op.record ?? null\n affected.push({\n vault: op.vaultName,\n op: before === null ? 'create' : 'update',\n collection: op.collectionName,\n docId: op.id,\n before,\n after,\n })\n\n // Guard violations — run the SAME checks Collection._putInternal does,\n // with the SAME ctx (existing + read-only facade + userId + role), but\n // collect the first thrown error instead of aborting.\n const registry = v._getGuardRegistry()\n if (!registry) continue\n const guards = registry.guardsFor(op.collectionName)\n if (guards.length === 0) continue\n const facade = v._getReadOnlyFacade()\n if (!facade) continue\n const gctx = { existing: before as Record<string, unknown> | null, vault: facade, userId: v.userId, role: v.role }\n try {\n await registry.runChecks(op.collectionName, after as Record<string, unknown>, gctx)\n const { GuardExecutor } = (await import('../../with-audit/guards/executor.js')) as { GuardExecutor: typeof GuardExecutorType }\n for (const g of guards) {\n await GuardExecutor.checkFrozenFields(g, op.id, before as Record<string, unknown> | null, after as Record<string, unknown>)\n }\n } catch (err) {\n guardViolations.push({\n vault: op.vaultName,\n collection: op.collectionName,\n docId: op.id,\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n return { affected, guardViolations }\n}\n","/**\n * Active transactions strategy. Only reachable via `@noy-db/hub/tx`.\n */\n\nimport { runTransaction } from './transaction.js'\nimport { runDryRun } from './dry-run.js'\nimport type { TxStrategy } from './strategy.js'\nimport type { TransactionInvariant } from './invariants.js'\n\n/**\n * Options for {@link withTransactions}. Currently only commit-time\n * changeset `invariants` (see {@link TransactionInvariant}).\n */\nexport interface TransactionStrategyOptions {\n /**\n * Commit-time set-level invariants run over the changeset on every\n * commit (ordinary AND amendment). See {@link TransactionInvariant}.\n */\n invariants?: ReadonlyArray<TransactionInvariant>\n}\n\n/**\n * Build the default transactions strategy. Pass into\n * `createNoydb({ txStrategy: withTransactions() })` to enable\n * `db.transaction(fn)` (and `db.transaction({ dryRun: true }, fn)`).\n *\n * Supply `{ invariants }` to register commit-time changeset invariants —\n * set-level constraints that fire after the writes commit and revert the\n * transaction on a throw. Unlike `amendment.invariant`, these run for\n * ordinary `db.transaction(fn)` calls (and amendments) with no role gate.\n */\nexport function withTransactions(opts?: TransactionStrategyOptions): TxStrategy {\n const invariants = opts?.invariants ?? []\n return {\n runTransaction: (db, fn, options) => runTransaction(db, fn, options, invariants),\n runDryRun,\n }\n}\n"],"mappings":";;;;;;;;;;;AAiCA,IAAM,MAAM;AACZ,IAAM,QAAQ,CAAC,OAAiB,GAAG,GAAG,SAAS,GAAG,GAAG,GAAG,GAAG,cAAc,GAAG,GAAG,GAAG,GAAG,EAAE;AAEvF,eAAsB,UACpB,IACA,IACuB;AACvB,QAAM,MAAM,IAAI,UAAU,EAAE;AAC5B,QAAM,GAAG,GAAG;AAGZ,QAAM,SAAS,oBAAI,IAAsB;AACzC,aAAW,MAAM,IAAI,KAAM,QAAO,IAAI,MAAM,EAAE,GAAG,EAAE;AAEnD,QAAM,WAA+B,CAAC;AACtC,QAAM,kBAAoC,CAAC;AAE3C,aAAW,MAAM,OAAO,OAAO,GAAG;AAChC,UAAM,IAAI,GAAG,MAAM,GAAG,SAAS;AAC/B,UAAM,OAAO,EAAE,WAAW,GAAG,cAAc;AAC3C,UAAM,SAAS,MAAM,KAAK,IAAI,GAAG,EAAE;AAEnC,QAAI,GAAG,SAAS,UAAU;AACxB,eAAS,KAAK,EAAE,OAAO,GAAG,WAAW,IAAI,UAAU,YAAY,GAAG,gBAAgB,OAAO,GAAG,IAAI,QAAQ,OAAO,KAAK,CAAC;AACrH;AAAA,IACF;AAEA,UAAM,QAAQ,GAAG,UAAU;AAC3B,aAAS,KAAK;AAAA,MACZ,OAAO,GAAG;AAAA,MACV,IAAI,WAAW,OAAO,WAAW;AAAA,MACjC,YAAY,GAAG;AAAA,MACf,OAAO,GAAG;AAAA,MACV;AAAA,MACA;AAAA,IACF,CAAC;AAKD,UAAM,WAAW,EAAE,kBAAkB;AACrC,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,SAAS,UAAU,GAAG,cAAc;AACnD,QAAI,OAAO,WAAW,EAAG;AACzB,UAAM,SAAS,EAAE,mBAAmB;AACpC,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,EAAE,UAAU,QAA0C,OAAO,QAAQ,QAAQ,EAAE,QAAQ,MAAM,EAAE,KAAK;AACjH,QAAI;AACF,YAAM,SAAS,UAAU,GAAG,gBAAgB,OAAkC,IAAI;AAClF,YAAM,EAAE,cAAc,IAAK,MAAM,OAAO,yBAAqC;AAC7E,iBAAW,KAAK,QAAQ;AACtB,cAAM,cAAc,kBAAkB,GAAG,GAAG,IAAI,QAA0C,KAAgC;AAAA,MAC5H;AAAA,IACF,SAAS,KAAK;AACZ,sBAAgB,KAAK;AAAA,QACnB,OAAO,GAAG;AAAA,QACV,YAAY,GAAG;AAAA,QACf,OAAO,GAAG;AAAA,QACV,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,gBAAgB;AACrC;;;AClEO,SAAS,iBAAiB,MAA+C;AAC9E,QAAM,aAAa,MAAM,cAAc,CAAC;AACxC,SAAO;AAAA,IACL,gBAAgB,CAAC,IAAI,IAAI,YAAY,eAAe,IAAI,IAAI,SAAS,UAAU;AAAA,IAC/E;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1 @@
1
+ export { C as CollectionDescription, a as CollectionMeta, D as DescribeOptions, b as DescribedField, F as FieldMeta, S as SemanticType } from '../describe-aBkJR2sd.js';
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Minimal ULID generator — zero dependencies, Web Crypto API only.
3
+ *
4
+ *. Used by the bundle writer to generate stable opaque
5
+ * handles for `.noydb` containers.
6
+ *
7
+ * **What's a ULID?** A 128-bit identifier encoded as 26 Crockford
8
+ * base32 characters. Layout:
9
+ *
10
+ * ```
11
+ * 01HYABCDEFGHJKMNPQRSTVWXYZ
12
+ * |--------||---------------|
13
+ * 48-bit 80-bit
14
+ * timestamp randomness
15
+ * ```
16
+ *
17
+ * The first 10 chars encode a millisecond Unix timestamp (so ULIDs
18
+ * sort lexicographically by creation time), and the remaining 16
19
+ * chars are random. Crockford base32 omits I/L/O/U to avoid
20
+ * ambiguity in handwriting and URLs.
21
+ *
22
+ * **Why hand-roll instead of pulling in `ulid`?** The package adds
23
+ * a dep, the implementation is ~30 lines, and the bundle module
24
+ * is the only consumer. Adding `ulid` would also drag in its own
25
+ * crypto polyfill that we don't need on Node 18+ or modern
26
+ * browsers.
27
+ *
28
+ * **Privacy consideration:** the timestamp prefix is observable in
29
+ * the bundle header. This is a deliberate trade-off:
30
+ * - Pro: lexicographic sortability lets bundle adapters list
31
+ * newest-first without an extra index.
32
+ * - Con: a casual observer can read the bundle's creation time
33
+ * from the handle. They cannot read it from any OTHER field
34
+ * (the header explicitly forbids `_exported_at`), and a
35
+ * creation timestamp is the same kind of metadata that
36
+ * filesystem mtime would already expose for a downloaded
37
+ * bundle. The leak is therefore equivalent to what's already
38
+ * visible from the file's mtime — not a new exposure.
39
+ *
40
+ * If a future use case needs timestamp-free handles, a v2 of the
41
+ * format could specify "use the random portion only" without a
42
+ * format break — `validateBundleHeader` only checks the regex
43
+ * shape, not the encoded timestamp.
44
+ */
45
+ /**
46
+ * Generate a fresh ULID. Uses `crypto.getRandomValues` for the
47
+ * randomness portion — same Web Crypto API the rest of the
48
+ * codebase uses for IVs and salt.
49
+ *
50
+ * Returns a 26-character string. Calling twice in the same
51
+ * millisecond produces two distinct ULIDs (the random portion
52
+ * differs); ULIDs from the same millisecond are NOT guaranteed
53
+ * to be monotonically ordered relative to each other, only
54
+ * relative to ULIDs from a different millisecond. The bundle
55
+ * format never relies on intra-millisecond ordering.
56
+ */
57
+ declare function generateULID(): string;
58
+ /**
59
+ * Validate that a string is a syntactically well-formed ULID. Used
60
+ * by the bundle header validator. Does NOT verify that the
61
+ * timestamp portion decodes to a sensible date — the format only
62
+ * cares about the encoding shape.
63
+ */
64
+ declare function isULID(value: string): boolean;
65
+
66
+ export { generateULID as g, isULID as i };
@@ -0,0 +1,10 @@
1
+ import {
2
+ generateULID,
3
+ isULID
4
+ } from "./chunk-ZJADGNYF.js";
5
+ import "./chunk-PZ5AY32C.js";
6
+ export {
7
+ generateULID,
8
+ isULID
9
+ };
10
+ //# sourceMappingURL=ulid-PTAIMDG4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,3 +1,5 @@
1
+ export { i as isDiscriminant } from '../discriminant-BN9REW3o.js';
2
+
1
3
  /**
2
4
  * Target-profile aware filename sanitizer.
3
5
  *
@@ -1,8 +1,12 @@
1
+ import {
2
+ isDiscriminant
3
+ } from "../chunk-PY4KJPYU.js";
1
4
  import {
2
5
  FilenameSanitizationError
3
- } from "../chunk-B6PB7JLN.js";
6
+ } from "../chunk-ZYUC53LT.js";
7
+ import "../chunk-PZ5AY32C.js";
4
8
 
5
- // src/util/sanitize-filename.ts
9
+ // src/kernel/util/sanitize-filename.ts
6
10
  var REPLACEMENT = "_";
7
11
  var BIDI_OVERRIDES = /[‪-‮⁦-⁩]/g;
8
12
  var WINDOWS_RESERVED_CHARS = /[<>:"/\\|?*]/g;
@@ -185,6 +189,7 @@ function truncateToByteCap(s, max) {
185
189
  return out;
186
190
  }
187
191
  export {
192
+ isDiscriminant,
188
193
  sanitizeFilename
189
194
  };
190
195
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/sanitize-filename.ts"],"sourcesContent":["/**\n * Target-profile aware filename sanitizer.\n *\n * Pure string in / string out. No filesystem access, no I/O. Use this\n * at the boundary where a user-supplied filename meets a storage\n * destination — local FS, ZIP archive, S3 key, URL path, SMB share —\n * to defuse the canonical 14-class footgun before it reaches that\n * destination.\n *\n * ## Threat model\n *\n * 1. Path injection — `..`, NUL bytes, `\\` on POSIX, absolute paths.\n * 2. Windows reserved names — `CON`, `PRN`, `AUX`, `NUL`,\n * `COM1-9`, `LPT1-9`, with or without an extension.\n * 3. Windows reserved chars — `< > : \" / \\ | ? *` plus ASCII 0-31.\n * 4. Trailing `.` and ` ` on Windows / SMB.\n * 5. Unicode normalization drift — same display, different bytes →\n * \"two files with the same name\" sync ghosts.\n * 6. Bidi override spoofing — U+202E reversing `harmless.exe.txt`\n * into `harmless.txt.exe`.\n * 7. URL `+` ambiguity in S3 presigned URLs.\n * 8. ZIP general-purpose-flag bit 11 (UTF-8 filename) optional in\n * pre-2006 readers.\n * 9-14. Length caps, leading/trailing whitespace + controls,\n * `.DS_Store`-style hidden noise, etc.\n *\n * ## Always-on transforms (every profile)\n *\n * - NFC normalize (`String.prototype.normalize('NFC')`).\n * - Reject NUL — hard fail, not strip. Silent strip enables a\n * classic truncation bypass (`safe.txt\\0.exe` → `safe.txt`).\n * - Strip bidi overrides (`U+202A..U+202E`, `U+2066..U+2069`).\n * - Trim leading/trailing whitespace and ASCII control chars.\n *\n * ## Non-goals (i18n boundary policy, )\n *\n * - No transliteration.\n * - No locale-aware slugging.\n * - No script-specific segmentation.\n *\n * @module\n */\n\nimport { FilenameSanitizationError } from '../errors.js'\n\n/**\n * One of seven storage destinations the sanitizer knows how to defang\n * for. Pick the most restrictive that covers your write site:\n * `'macos-smb'` is the safe default for \"I don't know where these\n * files end up but they're going to a real filesystem somewhere.\"\n */\nexport type FilenameProfile =\n | 'posix'\n | 'windows'\n | 'macos-smb'\n | 'zip'\n | 'url-path'\n | 's3-key'\n | 'opaque'\n\nexport interface SanitizeFilenameOptions {\n /** Target-destination profile. */\n readonly profile: FilenameProfile\n /**\n * Override the per-profile length cap. Useful when leaving headroom\n * for a collision suffix — e.g. `maxBytes: 240` on a `posix` write\n * site that wants 15 bytes of slack for `-1`, `-2`, …\n */\n readonly maxBytes?: number\n /**\n * Required when `profile === 'opaque'`. The opaque profile replaces\n * the entire input with `${opaqueId}.${ext}` (extension preserved\n * from the input when present).\n */\n readonly opaqueId?: string\n}\n\nconst REPLACEMENT = '_'\n\n// Bidi overrides: U+202A LRE, U+202B RLE, U+202C PDF, U+202D LRO,\n// U+202E RLO, U+2066 LRI, U+2067 RLI, U+2068 FSI, U+2069 PDI.\nconst BIDI_OVERRIDES = /[‪-‮⁦-⁩]/g\n\n// Reserved by Windows / NTFS / FAT / SMB.\nconst WINDOWS_RESERVED_CHARS = /[<>:\"/\\\\|?*]/g\n\nconst WINDOWS_RESERVED_NAMES = new Set([\n 'CON', 'PRN', 'AUX', 'NUL',\n 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',\n 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9',\n])\n\n// macOS legacy hidden-noise files. Match the full name.\nconst MAC_HIDDEN_NOISE = /^(?:\\.DS_Store|\\.localized|\\.fseventsd|\\._.+)$/i\n\n// RFC 3986 unreserved set.\nconst URL_UNRESERVED = /[A-Za-z0-9\\-._~]/\n\nconst utf8 = new TextEncoder()\n\nfunction isControlCode(cp: number): boolean {\n return (cp >= 0 && cp <= 0x1f) || cp === 0x7f\n}\n\nfunction stripControlChars(s: string): string {\n let out = ''\n for (let i = 0; i < s.length; i++) {\n out += isControlCode(s.charCodeAt(i)) ? REPLACEMENT : s[i]\n }\n return out\n}\n\nfunction trimWhitespaceAndControls(s: string): string {\n let start = 0\n let end = s.length\n while (start < end) {\n const ch = s[start]!\n if (!isControlCode(s.charCodeAt(start)) && ch.trim() !== '') break\n start++\n }\n while (end > start) {\n const ch = s[end - 1]!\n if (!isControlCode(s.charCodeAt(end - 1)) && ch.trim() !== '') break\n end--\n }\n return s.slice(start, end)\n}\n\n/**\n * Sanitize a filename for a target-destination profile. Pure: same\n * input + options always returns the same output, no I/O.\n *\n * Returns the sanitized name. Throws {@link FilenameSanitizationError}\n * when the input cannot be made safe at all (NUL byte, empty after\n * normalization, missing `opaqueId` for the opaque profile,\n * `..` segment that would fall out of any reasonable target).\n */\nexport function sanitizeFilename(name: string, opts: SanitizeFilenameOptions): string {\n if (typeof name !== 'string') {\n throw new FilenameSanitizationError('input must be a string')\n }\n if (name.includes('\\0')) {\n throw new FilenameSanitizationError('NUL byte in filename')\n }\n\n let s = name.normalize('NFC').replace(BIDI_OVERRIDES, '')\n\n if (opts.profile === 'opaque') {\n return applyOpaque(s, opts)\n }\n\n s = trimWhitespaceAndControls(s)\n\n switch (opts.profile) {\n case 'posix': return cap(applyPosix(s), opts.maxBytes ?? 255, 'utf8')\n case 'windows': return cap(applyWindows(s), opts.maxBytes ?? 255, 'utf16')\n case 'macos-smb': return cap(applyMacosSmb(s), opts.maxBytes ?? 240, 'utf8')\n case 'zip': return cap(applyZip(s), opts.maxBytes ?? 255, 'utf8')\n case 'url-path': return cap(applyUrlPath(s), opts.maxBytes ?? 1024, 'bytes-pre-encode')\n case 's3-key': return cap(applyS3Key(s), opts.maxBytes ?? 1024, 'utf8')\n }\n}\n\n// ─── Profile implementations ────────────────────────────────────────────\n\nfunction applyPosix(s: string): string {\n // POSIX is permissive; only `/` and NUL are off-limits.\n const cleaned = s.replace(/\\//g, REPLACEMENT)\n return rejectDotSegments(cleaned)\n}\n\nfunction applyWindows(s: string): string {\n let cleaned = s.replace(WINDOWS_RESERVED_CHARS, REPLACEMENT)\n cleaned = stripControlChars(cleaned)\n // Trailing space/dot are stripped by Win32 path resolution.\n cleaned = cleaned.replace(/[. ]+$/g, '')\n cleaned = rejectDotSegments(cleaned)\n return avoidWindowsReservedName(cleaned)\n}\n\nfunction applyMacosSmb(s: string): string {\n let cleaned = applyWindows(s)\n if (MAC_HIDDEN_NOISE.test(cleaned)) {\n cleaned = REPLACEMENT + cleaned\n }\n return cleaned\n}\n\nfunction applyZip(s: string): string {\n let cleaned = s.replace(/^\\/+/, '')\n cleaned = rejectDotSegments(cleaned)\n return stripControlChars(cleaned)\n}\n\nfunction applyUrlPath(s: string): string {\n // RFC 3986 percent-encoding for path segment. Keep `unreserved`,\n // encode everything else. `+` is encoded as `%2B` because S3 and\n // legacy servers treat raw `+` as space ambiguously.\n let out = ''\n for (const ch of s) {\n if (URL_UNRESERVED.test(ch)) { out += ch; continue }\n const bytes = utf8.encode(ch)\n for (const b of bytes) {\n out += '%' + b.toString(16).toUpperCase().padStart(2, '0')\n }\n }\n return out\n}\n\nfunction applyS3Key(s: string): string {\n // Strip leading slashes BEFORE percent-encoding — once `/` is\n // encoded to `%2F` the leading-slash regex no longer matches.\n return applyUrlPath(s.replace(/^\\/+/, ''))\n}\n\nfunction applyOpaque(s: string, opts: SanitizeFilenameOptions): string {\n if (!opts.opaqueId) {\n throw new FilenameSanitizationError('opaque profile requires opaqueId')\n }\n // Preserve a \"safe-looking\" extension only — alphanumeric, ≤16 bytes.\n const dot = s.lastIndexOf('.')\n if (dot > 0 && dot < s.length - 1) {\n const ext = s.slice(dot + 1)\n if (/^[A-Za-z0-9]{1,16}$/.test(ext)) {\n return `${opts.opaqueId}.${ext.toLowerCase()}`\n }\n }\n return opts.opaqueId\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────\n\nfunction rejectDotSegments(s: string): string {\n if (s === '.' || s === '..' || s.split(/[/\\\\]/).some((seg) => seg === '..')) {\n throw new FilenameSanitizationError('path traversal segment in filename')\n }\n if (s.length === 0) {\n throw new FilenameSanitizationError('empty filename after sanitization')\n }\n return s\n}\n\nfunction avoidWindowsReservedName(s: string): string {\n const dot = s.indexOf('.')\n const base = dot === -1 ? s : s.slice(0, dot)\n if (WINDOWS_RESERVED_NAMES.has(base.toUpperCase())) {\n return REPLACEMENT + s\n }\n return s\n}\n\ntype LengthUnit = 'utf8' | 'utf16' | 'bytes-pre-encode'\n\nfunction cap(s: string, max: number, unit: LengthUnit): string {\n if (max <= 0) {\n throw new FilenameSanitizationError('maxBytes must be positive')\n }\n if (unit === 'utf16') {\n if (s.length <= max) return s\n return s.slice(0, max)\n }\n if (unit === 'bytes-pre-encode') {\n if (utf8.encode(s).byteLength <= max) return s\n return truncateToByteCap(s, max)\n }\n if (utf8.encode(s).byteLength <= max) return s\n return truncateToByteCap(s, max)\n}\n\nfunction truncateToByteCap(s: string, max: number): string {\n // Walk by code points so we never split a multi-byte sequence in\n // the middle. Whole-grapheme handling (ZWJ-joined emoji) is a\n // documented non-goal; we only protect against UTF-8 boundary\n // splits here.\n let out = ''\n let used = 0\n for (const cp of s) {\n const n = utf8.encode(cp).byteLength\n if (used + n > max) break\n out += cp\n used += n\n }\n if (out.length === 0) {\n throw new FilenameSanitizationError('maxBytes too small for a single code point')\n }\n return out\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/kernel/util/sanitize-filename.ts"],"sourcesContent":["/**\n * Target-profile aware filename sanitizer.\n *\n * Pure string in / string out. No filesystem access, no I/O. Use this\n * at the boundary where a user-supplied filename meets a storage\n * destination — local FS, ZIP archive, S3 key, URL path, SMB share —\n * to defuse the canonical 14-class footgun before it reaches that\n * destination.\n *\n * ## Threat model\n *\n * 1. Path injection — `..`, NUL bytes, `\\` on POSIX, absolute paths.\n * 2. Windows reserved names — `CON`, `PRN`, `AUX`, `NUL`,\n * `COM1-9`, `LPT1-9`, with or without an extension.\n * 3. Windows reserved chars — `< > : \" / \\ | ? *` plus ASCII 0-31.\n * 4. Trailing `.` and ` ` on Windows / SMB.\n * 5. Unicode normalization drift — same display, different bytes →\n * \"two files with the same name\" sync ghosts.\n * 6. Bidi override spoofing — U+202E reversing `harmless.exe.txt`\n * into `harmless.txt.exe`.\n * 7. URL `+` ambiguity in S3 presigned URLs.\n * 8. ZIP general-purpose-flag bit 11 (UTF-8 filename) optional in\n * pre-2006 readers.\n * 9-14. Length caps, leading/trailing whitespace + controls,\n * `.DS_Store`-style hidden noise, etc.\n *\n * ## Always-on transforms (every profile)\n *\n * - NFC normalize (`String.prototype.normalize('NFC')`).\n * - Reject NUL — hard fail, not strip. Silent strip enables a\n * classic truncation bypass (`safe.txt\\0.exe` → `safe.txt`).\n * - Strip bidi overrides (`U+202A..U+202E`, `U+2066..U+2069`).\n * - Trim leading/trailing whitespace and ASCII control chars.\n *\n * ## Non-goals (i18n boundary policy, )\n *\n * - No transliteration.\n * - No locale-aware slugging.\n * - No script-specific segmentation.\n *\n * @module\n */\n\nimport { FilenameSanitizationError } from '../errors.js'\n\n/**\n * One of seven storage destinations the sanitizer knows how to defang\n * for. Pick the most restrictive that covers your write site:\n * `'macos-smb'` is the safe default for \"I don't know where these\n * files end up but they're going to a real filesystem somewhere.\"\n */\nexport type FilenameProfile =\n | 'posix'\n | 'windows'\n | 'macos-smb'\n | 'zip'\n | 'url-path'\n | 's3-key'\n | 'opaque'\n\nexport interface SanitizeFilenameOptions {\n /** Target-destination profile. */\n readonly profile: FilenameProfile\n /**\n * Override the per-profile length cap. Useful when leaving headroom\n * for a collision suffix — e.g. `maxBytes: 240` on a `posix` write\n * site that wants 15 bytes of slack for `-1`, `-2`, …\n */\n readonly maxBytes?: number\n /**\n * Required when `profile === 'opaque'`. The opaque profile replaces\n * the entire input with `${opaqueId}.${ext}` (extension preserved\n * from the input when present).\n */\n readonly opaqueId?: string\n}\n\nconst REPLACEMENT = '_'\n\n// Bidi overrides: U+202A LRE, U+202B RLE, U+202C PDF, U+202D LRO,\n// U+202E RLO, U+2066 LRI, U+2067 RLI, U+2068 FSI, U+2069 PDI.\nconst BIDI_OVERRIDES = /[‪-‮⁦-⁩]/g\n\n// Reserved by Windows / NTFS / FAT / SMB.\nconst WINDOWS_RESERVED_CHARS = /[<>:\"/\\\\|?*]/g\n\nconst WINDOWS_RESERVED_NAMES = new Set([\n 'CON', 'PRN', 'AUX', 'NUL',\n 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',\n 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9',\n])\n\n// macOS legacy hidden-noise files. Match the full name.\nconst MAC_HIDDEN_NOISE = /^(?:\\.DS_Store|\\.localized|\\.fseventsd|\\._.+)$/i\n\n// RFC 3986 unreserved set.\nconst URL_UNRESERVED = /[A-Za-z0-9\\-._~]/\n\nconst utf8 = new TextEncoder()\n\nfunction isControlCode(cp: number): boolean {\n return (cp >= 0 && cp <= 0x1f) || cp === 0x7f\n}\n\nfunction stripControlChars(s: string): string {\n let out = ''\n for (let i = 0; i < s.length; i++) {\n out += isControlCode(s.charCodeAt(i)) ? REPLACEMENT : s[i]\n }\n return out\n}\n\nfunction trimWhitespaceAndControls(s: string): string {\n let start = 0\n let end = s.length\n while (start < end) {\n const ch = s[start]!\n if (!isControlCode(s.charCodeAt(start)) && ch.trim() !== '') break\n start++\n }\n while (end > start) {\n const ch = s[end - 1]!\n if (!isControlCode(s.charCodeAt(end - 1)) && ch.trim() !== '') break\n end--\n }\n return s.slice(start, end)\n}\n\n/**\n * Sanitize a filename for a target-destination profile. Pure: same\n * input + options always returns the same output, no I/O.\n *\n * Returns the sanitized name. Throws {@link FilenameSanitizationError}\n * when the input cannot be made safe at all (NUL byte, empty after\n * normalization, missing `opaqueId` for the opaque profile,\n * `..` segment that would fall out of any reasonable target).\n */\nexport function sanitizeFilename(name: string, opts: SanitizeFilenameOptions): string {\n if (typeof name !== 'string') {\n throw new FilenameSanitizationError('input must be a string')\n }\n if (name.includes('\\0')) {\n throw new FilenameSanitizationError('NUL byte in filename')\n }\n\n let s = name.normalize('NFC').replace(BIDI_OVERRIDES, '')\n\n if (opts.profile === 'opaque') {\n return applyOpaque(s, opts)\n }\n\n s = trimWhitespaceAndControls(s)\n\n switch (opts.profile) {\n case 'posix': return cap(applyPosix(s), opts.maxBytes ?? 255, 'utf8')\n case 'windows': return cap(applyWindows(s), opts.maxBytes ?? 255, 'utf16')\n case 'macos-smb': return cap(applyMacosSmb(s), opts.maxBytes ?? 240, 'utf8')\n case 'zip': return cap(applyZip(s), opts.maxBytes ?? 255, 'utf8')\n case 'url-path': return cap(applyUrlPath(s), opts.maxBytes ?? 1024, 'bytes-pre-encode')\n case 's3-key': return cap(applyS3Key(s), opts.maxBytes ?? 1024, 'utf8')\n }\n}\n\n// ─── Profile implementations ────────────────────────────────────────────\n\nfunction applyPosix(s: string): string {\n // POSIX is permissive; only `/` and NUL are off-limits.\n const cleaned = s.replace(/\\//g, REPLACEMENT)\n return rejectDotSegments(cleaned)\n}\n\nfunction applyWindows(s: string): string {\n let cleaned = s.replace(WINDOWS_RESERVED_CHARS, REPLACEMENT)\n cleaned = stripControlChars(cleaned)\n // Trailing space/dot are stripped by Win32 path resolution.\n cleaned = cleaned.replace(/[. ]+$/g, '')\n cleaned = rejectDotSegments(cleaned)\n return avoidWindowsReservedName(cleaned)\n}\n\nfunction applyMacosSmb(s: string): string {\n let cleaned = applyWindows(s)\n if (MAC_HIDDEN_NOISE.test(cleaned)) {\n cleaned = REPLACEMENT + cleaned\n }\n return cleaned\n}\n\nfunction applyZip(s: string): string {\n let cleaned = s.replace(/^\\/+/, '')\n cleaned = rejectDotSegments(cleaned)\n return stripControlChars(cleaned)\n}\n\nfunction applyUrlPath(s: string): string {\n // RFC 3986 percent-encoding for path segment. Keep `unreserved`,\n // encode everything else. `+` is encoded as `%2B` because S3 and\n // legacy servers treat raw `+` as space ambiguously.\n let out = ''\n for (const ch of s) {\n if (URL_UNRESERVED.test(ch)) { out += ch; continue }\n const bytes = utf8.encode(ch)\n for (const b of bytes) {\n out += '%' + b.toString(16).toUpperCase().padStart(2, '0')\n }\n }\n return out\n}\n\nfunction applyS3Key(s: string): string {\n // Strip leading slashes BEFORE percent-encoding — once `/` is\n // encoded to `%2F` the leading-slash regex no longer matches.\n return applyUrlPath(s.replace(/^\\/+/, ''))\n}\n\nfunction applyOpaque(s: string, opts: SanitizeFilenameOptions): string {\n if (!opts.opaqueId) {\n throw new FilenameSanitizationError('opaque profile requires opaqueId')\n }\n // Preserve a \"safe-looking\" extension only — alphanumeric, ≤16 bytes.\n const dot = s.lastIndexOf('.')\n if (dot > 0 && dot < s.length - 1) {\n const ext = s.slice(dot + 1)\n if (/^[A-Za-z0-9]{1,16}$/.test(ext)) {\n return `${opts.opaqueId}.${ext.toLowerCase()}`\n }\n }\n return opts.opaqueId\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────────\n\nfunction rejectDotSegments(s: string): string {\n if (s === '.' || s === '..' || s.split(/[/\\\\]/).some((seg) => seg === '..')) {\n throw new FilenameSanitizationError('path traversal segment in filename')\n }\n if (s.length === 0) {\n throw new FilenameSanitizationError('empty filename after sanitization')\n }\n return s\n}\n\nfunction avoidWindowsReservedName(s: string): string {\n const dot = s.indexOf('.')\n const base = dot === -1 ? s : s.slice(0, dot)\n if (WINDOWS_RESERVED_NAMES.has(base.toUpperCase())) {\n return REPLACEMENT + s\n }\n return s\n}\n\ntype LengthUnit = 'utf8' | 'utf16' | 'bytes-pre-encode'\n\nfunction cap(s: string, max: number, unit: LengthUnit): string {\n if (max <= 0) {\n throw new FilenameSanitizationError('maxBytes must be positive')\n }\n if (unit === 'utf16') {\n if (s.length <= max) return s\n return s.slice(0, max)\n }\n if (unit === 'bytes-pre-encode') {\n if (utf8.encode(s).byteLength <= max) return s\n return truncateToByteCap(s, max)\n }\n if (utf8.encode(s).byteLength <= max) return s\n return truncateToByteCap(s, max)\n}\n\nfunction truncateToByteCap(s: string, max: number): string {\n // Walk by code points so we never split a multi-byte sequence in\n // the middle. Whole-grapheme handling (ZWJ-joined emoji) is a\n // documented non-goal; we only protect against UTF-8 boundary\n // splits here.\n let out = ''\n let used = 0\n for (const cp of s) {\n const n = utf8.encode(cp).byteLength\n if (used + n > max) break\n out += cp\n used += n\n }\n if (out.length === 0) {\n throw new FilenameSanitizationError('maxBytes too small for a single code point')\n }\n return out\n}\n"],"mappings":"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","names":[]}