@noy-db/hub 0.3.0-pre.2 → 0.3.0-pre.4

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 (383) hide show
  1. package/dist/adapter/index.d.ts +2 -2
  2. package/dist/adapter/index.js +1 -1
  3. package/dist/aggregate/index.d.ts +3 -3
  4. package/dist/aggregate/index.js +4 -4
  5. package/dist/api-JOXUNSKP.js +20 -0
  6. package/dist/as/index.d.ts +4 -4
  7. package/dist/as/index.js +12 -6
  8. package/dist/at/index.d.ts +2 -2
  9. package/dist/attestation/index.d.ts +3 -3
  10. package/dist/attestation/index.js +19 -13
  11. package/dist/attestation/index.js.map +1 -1
  12. package/dist/{backup-KMJQ66MF.js → backup-MOB27UUN.js} +12 -6
  13. package/dist/{backup-KMJQ66MF.js.map → backup-MOB27UUN.js.map} +1 -1
  14. package/dist/blobs/index.d.ts +4 -4
  15. package/dist/blobs/index.js +11 -5
  16. package/dist/blobs/index.js.map +1 -1
  17. package/dist/bundle/index.d.ts +5 -5
  18. package/dist/bundle/index.js +21 -15
  19. package/dist/bundle/index.js.map +1 -1
  20. package/dist/{bundle-PwBGkhpe.d.ts → bundle-Bs13EZtX.d.ts} +1 -1
  21. package/dist/by/index.js +2 -2
  22. package/dist/cargo/index.d.ts +4 -4
  23. package/dist/cargo/index.js +23 -17
  24. package/dist/{chunk-SMXWYP24.js → chunk-3QRQOBS7.js} +3 -3
  25. package/dist/{chunk-QHJW5EXU.js → chunk-3Y4QLJ6K.js} +2 -2
  26. package/dist/{chunk-NF5JWERG.js → chunk-43ISXURO.js} +2 -2
  27. package/dist/{chunk-5LUY7UTV.js → chunk-4K3MQ5S3.js} +2 -2
  28. package/dist/{chunk-QZISFCVG.js → chunk-5CY35H55.js} +11 -9
  29. package/dist/{chunk-QZISFCVG.js.map → chunk-5CY35H55.js.map} +1 -1
  30. package/dist/chunk-5EWYUR5P.js +37 -0
  31. package/dist/chunk-5EWYUR5P.js.map +1 -0
  32. package/dist/{chunk-Y22T3KQE.js → chunk-5MRE3C4Q.js} +5 -5
  33. package/dist/{chunk-M6OST55S.js → chunk-5W7AOFWA.js} +2 -2
  34. package/dist/{chunk-AXRXJTE2.js → chunk-6HNKCKFZ.js} +7 -7
  35. package/dist/{chunk-UAG5KWVA.js → chunk-6RXPSMKR.js} +3 -3
  36. package/dist/{chunk-TJYQIGAP.js → chunk-7J7JRYXW.js} +9 -5
  37. package/dist/chunk-7J7JRYXW.js.map +1 -0
  38. package/dist/{chunk-UDRIWL7A.js → chunk-A5DYVMDR.js} +3 -3
  39. package/dist/chunk-AF5ZRTZ4.js +108 -0
  40. package/dist/chunk-AF5ZRTZ4.js.map +1 -0
  41. package/dist/{chunk-I3TIKTJO.js → chunk-BKGIWGCX.js} +2 -2
  42. package/dist/{chunk-IO6GRPT6.js → chunk-BMQOH7MM.js} +2 -2
  43. package/dist/{chunk-26LGBE4T.js → chunk-CPXPHQGX.js} +6 -4
  44. package/dist/{chunk-26LGBE4T.js.map → chunk-CPXPHQGX.js.map} +1 -1
  45. package/dist/{chunk-FISN7WE4.js → chunk-EWR7HL3K.js} +4 -4
  46. package/dist/{chunk-AQTBSL7R.js → chunk-FH52CDEW.js} +5 -5
  47. package/dist/chunk-G4MGYGSS.js +130 -0
  48. package/dist/chunk-G4MGYGSS.js.map +1 -0
  49. package/dist/{chunk-UV5MFVO3.js → chunk-G7RDYYTE.js} +2 -2
  50. package/dist/{chunk-UIU2THRG.js → chunk-GBTUANXF.js} +16 -297
  51. package/dist/chunk-GBTUANXF.js.map +1 -0
  52. package/dist/{chunk-TEILUWOI.js → chunk-GOUNIHFA.js} +10 -10
  53. package/dist/{chunk-LXQT4WMP.js → chunk-GQOT6QJR.js} +8 -6
  54. package/dist/{chunk-LXQT4WMP.js.map → chunk-GQOT6QJR.js.map} +1 -1
  55. package/dist/{chunk-RUEKROOS.js → chunk-GXGK22QU.js} +2 -2
  56. package/dist/{chunk-IELYAOGG.js → chunk-GZZL5R73.js} +4 -4
  57. package/dist/{chunk-JNUWZ6D3.js → chunk-H5XRIJX3.js} +7 -5
  58. package/dist/{chunk-JNUWZ6D3.js.map → chunk-H5XRIJX3.js.map} +1 -1
  59. package/dist/{chunk-CWPPNPOH.js → chunk-H7RYPVMJ.js} +2 -2
  60. package/dist/{chunk-5N6CZTCY.js → chunk-HBKDR7R3.js} +3 -3
  61. package/dist/{chunk-KXGNJJXB.js → chunk-HLUKZ36Q.js} +9 -9
  62. package/dist/{chunk-LMTH2RM6.js → chunk-HMXLN43G.js} +2 -2
  63. package/dist/{chunk-BG3SPSR4.js → chunk-HY6ZGGEC.js} +2 -2
  64. package/dist/{chunk-UPJNJGGA.js → chunk-K5P46KB3.js} +27 -10
  65. package/dist/chunk-K5P46KB3.js.map +1 -0
  66. package/dist/chunk-KYY7L72M.js +106 -0
  67. package/dist/chunk-KYY7L72M.js.map +1 -0
  68. package/dist/{chunk-62QYRORB.js → chunk-LIP6JWYK.js} +3 -3
  69. package/dist/{chunk-5TDJ56JE.js → chunk-LN22XH4B.js} +1 -1
  70. package/dist/chunk-LN22XH4B.js.map +1 -0
  71. package/dist/chunk-LP7BEXCT.js +32 -0
  72. package/dist/chunk-LP7BEXCT.js.map +1 -0
  73. package/dist/{chunk-IGUYVGGI.js → chunk-LPRPVCNY.js} +5 -5
  74. package/dist/{chunk-AIWULCUO.js → chunk-M66NAZA4.js} +5 -3
  75. package/dist/{chunk-AIWULCUO.js.map → chunk-M66NAZA4.js.map} +1 -1
  76. package/dist/{chunk-KVOXU4T5.js → chunk-N5YVZHCB.js} +2 -2
  77. package/dist/{chunk-76722EBH.js → chunk-NB47TXGP.js} +14 -12
  78. package/dist/{chunk-76722EBH.js.map → chunk-NB47TXGP.js.map} +1 -1
  79. package/dist/chunk-NO272T7Q.js +194 -0
  80. package/dist/chunk-NO272T7Q.js.map +1 -0
  81. package/dist/{chunk-SRB2XEWB.js → chunk-O2DB4C3M.js} +8 -6
  82. package/dist/{chunk-SRB2XEWB.js.map → chunk-O2DB4C3M.js.map} +1 -1
  83. package/dist/{chunk-IUEN57TV.js → chunk-OFBFAVLI.js} +6 -6
  84. package/dist/{chunk-MTMJVJ5W.js → chunk-OPTFANOX.js} +5 -3
  85. package/dist/chunk-OPTFANOX.js.map +1 -0
  86. package/dist/{chunk-5O3AOPDT.js → chunk-OVO2RZAE.js} +212 -439
  87. package/dist/chunk-OVO2RZAE.js.map +1 -0
  88. package/dist/{chunk-GYGWYIOZ.js → chunk-P27Z66EB.js} +7 -5
  89. package/dist/{chunk-GYGWYIOZ.js.map → chunk-P27Z66EB.js.map} +1 -1
  90. package/dist/{chunk-HCIPRAGS.js → chunk-P2LDXRGP.js} +2 -2
  91. package/dist/chunk-P3NGV5RV.js +41 -0
  92. package/dist/chunk-P3NGV5RV.js.map +1 -0
  93. package/dist/{chunk-5R3ERCDH.js → chunk-P3V7JTB6.js} +25 -9
  94. package/dist/{chunk-5R3ERCDH.js.map → chunk-P3V7JTB6.js.map} +1 -1
  95. package/dist/{chunk-LV7M27WM.js → chunk-P5WXDYMD.js} +8 -197
  96. package/dist/chunk-P5WXDYMD.js.map +1 -0
  97. package/dist/chunk-PGFY7IRW.js +95 -0
  98. package/dist/chunk-PGFY7IRW.js.map +1 -0
  99. package/dist/chunk-QKVILR7N.js +25 -0
  100. package/dist/chunk-QKVILR7N.js.map +1 -0
  101. package/dist/{chunk-V7RWQRG7.js → chunk-QNTEDPWP.js} +3 -3
  102. package/dist/{chunk-Q7SS3IME.js → chunk-RDHAGBEB.js} +3 -3
  103. package/dist/{chunk-EIZUR2XW.js → chunk-RTS23VIJ.js} +2 -2
  104. package/dist/{chunk-LFLXAY2W.js → chunk-SEQ2JI3Y.js} +9 -7
  105. package/dist/{chunk-LFLXAY2W.js.map → chunk-SEQ2JI3Y.js.map} +1 -1
  106. package/dist/{chunk-AZAOEIKW.js → chunk-SW56GSYC.js} +2 -2
  107. package/dist/{chunk-TA66UMI4.js → chunk-T2EGAXPM.js} +2 -2
  108. package/dist/{chunk-SM3AVUHC.js → chunk-T45LAT2Y.js} +2 -2
  109. package/dist/{chunk-SKF73JOP.js → chunk-T65UZXR6.js} +3 -3
  110. package/dist/{chunk-ITNUCOXM.js → chunk-TB5RNNJ4.js} +7 -5
  111. package/dist/{chunk-ITNUCOXM.js.map → chunk-TB5RNNJ4.js.map} +1 -1
  112. package/dist/chunk-TCIUO62Z.js +29 -0
  113. package/dist/chunk-TCIUO62Z.js.map +1 -0
  114. package/dist/chunk-THNJ3IKU.js +17 -0
  115. package/dist/chunk-THNJ3IKU.js.map +1 -0
  116. package/dist/chunk-TLJOJBZD.js +404 -0
  117. package/dist/chunk-TLJOJBZD.js.map +1 -0
  118. package/dist/chunk-TQ3REHVF.js +95 -0
  119. package/dist/chunk-TQ3REHVF.js.map +1 -0
  120. package/dist/{chunk-DGDI2D4M.js → chunk-TVRQ3RYH.js} +28 -7
  121. package/dist/chunk-TVRQ3RYH.js.map +1 -0
  122. package/dist/{chunk-PSMV73A5.js → chunk-TYGW5TOR.js} +7 -7
  123. package/dist/{chunk-ZYUC53LT.js → chunk-U23JUUPX.js} +58 -2
  124. package/dist/{chunk-ZYUC53LT.js.map → chunk-U23JUUPX.js.map} +1 -1
  125. package/dist/{chunk-3YFXJ3ZP.js → chunk-U24XHXNK.js} +2 -2
  126. package/dist/chunk-ULIHDPKL.js +94 -0
  127. package/dist/chunk-ULIHDPKL.js.map +1 -0
  128. package/dist/chunk-UOEWDCUX.js +69 -0
  129. package/dist/chunk-UOEWDCUX.js.map +1 -0
  130. package/dist/{chunk-WWGT2MDV.js → chunk-VAWY44JW.js} +8 -8
  131. package/dist/{chunk-WWGT2MDV.js.map → chunk-VAWY44JW.js.map} +1 -1
  132. package/dist/chunk-VFRNWE5P.js +239 -0
  133. package/dist/chunk-VFRNWE5P.js.map +1 -0
  134. package/dist/{chunk-IPB7FTQX.js → chunk-VMJ5URU7.js} +10 -8
  135. package/dist/chunk-VMJ5URU7.js.map +1 -0
  136. package/dist/{chunk-VFQGRQIH.js → chunk-VPCMJ5Z4.js} +7 -5
  137. package/dist/{chunk-VFQGRQIH.js.map → chunk-VPCMJ5Z4.js.map} +1 -1
  138. package/dist/{chunk-VCTFO5CO.js → chunk-VRPBEOWU.js} +2 -2
  139. package/dist/{chunk-ZCGAHGUS.js → chunk-VWGCJUTV.js} +2 -2
  140. package/dist/{chunk-XXYIOFUB.js → chunk-XJR3COJO.js} +5 -5
  141. package/dist/{chunk-PKHL44ER.js → chunk-XYYW64LB.js} +2 -2
  142. package/dist/{chunk-IAGBDSCS.js → chunk-YFF2RP3X.js} +2 -2
  143. package/dist/{chunk-MD3Y6J3L.js → chunk-Z3FZC5GV.js} +7 -5
  144. package/dist/{chunk-MD3Y6J3L.js.map → chunk-Z3FZC5GV.js.map} +1 -1
  145. package/dist/{chunk-DFEMTNPJ.js → chunk-Z5PIUYNB.js} +10 -8
  146. package/dist/{chunk-DFEMTNPJ.js.map → chunk-Z5PIUYNB.js.map} +1 -1
  147. package/dist/{chunk-WYSO2NIH.js → chunk-Z7KI4WHR.js} +2 -2
  148. package/dist/chunk-ZKF6HH7V.js +120 -0
  149. package/dist/chunk-ZKF6HH7V.js.map +1 -0
  150. package/dist/{chunk-I2NOIW44.js → chunk-ZKYMKF2S.js} +8 -6
  151. package/dist/{chunk-I2NOIW44.js.map → chunk-ZKYMKF2S.js.map} +1 -1
  152. package/dist/{chunk-PSHOXR6C.js → chunk-ZPHDGUZZ.js} +737 -1082
  153. package/dist/chunk-ZPHDGUZZ.js.map +1 -0
  154. package/dist/{chunk-CMGR4ZEW.js → chunk-ZROMNP7Q.js} +2 -2
  155. package/dist/classified/index.d.ts +17 -0
  156. package/dist/classified/index.js +38 -0
  157. package/dist/collection-facade-MKEBZDWW.js +39 -0
  158. package/dist/computed-BMMEFRFJ.js +11 -0
  159. package/dist/config-drift-KGM7ZRW4.js +24 -0
  160. package/dist/config-drift-KGM7ZRW4.js.map +1 -0
  161. package/dist/consent/index.d.ts +3 -3
  162. package/dist/consent/index.js +10 -4
  163. package/dist/consent/index.js.map +1 -1
  164. package/dist/crdt/index.d.ts +3 -3
  165. package/dist/delegation-BQNIEHZE.js +25 -0
  166. package/dist/derivations/index.d.ts +4 -4
  167. package/dist/derivations/index.js +12 -6
  168. package/dist/describe/index.d.ts +1 -1
  169. package/dist/{describe-Ccd1hS7a.d.ts → describe-C6iHNlqJ.d.ts} +19 -0
  170. package/dist/{dev-unlock-h0K-UZTk.d.ts → dev-unlock-Cqd5Xv5J.d.ts} +1 -1
  171. package/dist/{enclave-UL5LW66V.js → enclave-YN6223OG.js} +47 -18
  172. package/dist/executor-CBTNU5VZ.js +9 -0
  173. package/dist/executor-DJHNSTIR.js +9 -0
  174. package/dist/executor-FGISLQIN.js +21 -0
  175. package/dist/export-accessible-P7SLRLK3.js +23 -0
  176. package/dist/extract-partition-RNVSFHAB.js +36 -0
  177. package/dist/{fanout-sidecar-GF3DJ6KR.js → fanout-sidecar-WS22Q5WH.js} +17 -14
  178. package/dist/fanout-sidecar-WS22Q5WH.js.map +1 -0
  179. package/dist/fence-watcher-DHQ775JB.js +69 -0
  180. package/dist/fence-watcher-DHQ775JB.js.map +1 -0
  181. package/dist/find-RNBG7LBY.js +11 -0
  182. package/dist/forget/index.js +10 -4
  183. package/dist/forget/index.js.map +1 -1
  184. package/dist/guards/index.d.ts +4 -4
  185. package/dist/guards/index.js +3 -3
  186. package/dist/{hash-CdSr06sm.d.ts → hash-D8Q5MJLA.d.ts} +7 -2
  187. package/dist/history/index.d.ts +4 -4
  188. package/dist/history/index.js +12 -6
  189. package/dist/history/index.js.map +1 -1
  190. package/dist/i18n/index.d.ts +3 -3
  191. package/dist/i18n/index.js +14 -8
  192. package/dist/i18n/index.js.map +1 -1
  193. package/dist/in/index.d.ts +2 -2
  194. package/dist/{index-_6At2_9_.d.ts → index-D4GQe1Rx.d.ts} +1058 -49
  195. package/dist/{index-CGLLRtFc.d.ts → index-DRxk8q_7.d.ts} +3 -3
  196. package/dist/index.d.ts +60 -15
  197. package/dist/index.js +1081 -121
  198. package/dist/index.js.map +1 -1
  199. package/dist/indexing/index.d.ts +3 -3
  200. package/dist/indexing/index.js +4 -4
  201. package/dist/issue-W5QG53B5.js +19 -0
  202. package/dist/json-schema-I22JCYCG.js +44 -0
  203. package/dist/json-schema-I22JCYCG.js.map +1 -0
  204. package/dist/kernel/index.d.ts +3 -3
  205. package/dist/kernel/index.js +13 -7
  206. package/dist/lazy/index.d.ts +21 -0
  207. package/dist/lazy/index.js +12 -0
  208. package/dist/{ledger-RYI35CDS.js → ledger-KZWBKAG5.js} +12 -6
  209. package/dist/liberate-GMGCHIND.js +24 -0
  210. package/dist/link-set-UQEIYQAM.js +31 -0
  211. package/dist/materialized-views/index.d.ts +4 -4
  212. package/dist/materialized-views/index.js +16 -10
  213. package/dist/{mime-magic-B4RoFj3B.d.ts → mime-magic-DmwT7OzZ.d.ts} +1 -1
  214. package/dist/noydb-KS2O2MRI.js +60 -0
  215. package/dist/on/index.d.ts +2 -2
  216. package/dist/on/index.js +10 -4
  217. package/dist/overlay-views/index.d.ts +4 -4
  218. package/dist/overlay-views/index.js +4 -4
  219. package/dist/periods/index.d.ts +3 -3
  220. package/dist/periods/index.js +13 -7
  221. package/dist/pod/index.d.ts +3 -3
  222. package/dist/pod/index.js +12 -6
  223. package/dist/{policy-IXK4FVXP.js → policy-YIKUH4AD.js} +5 -5
  224. package/dist/portability/index.d.ts +3 -3
  225. package/dist/portability/index.js +8 -8
  226. package/dist/{public-envelope-JHDQCPSX.js → public-envelope-MRN5YYZZ.js} +4 -4
  227. package/dist/query/index.d.ts +2 -2
  228. package/dist/query/index.js +6 -6
  229. package/dist/register-K6DDSIXN.js +21 -0
  230. package/dist/registry-IMNMHWTM.js +17 -0
  231. package/dist/registry-K6VUQXKV.js +19 -0
  232. package/dist/registry-ZVO3T4M5.js +9 -0
  233. package/dist/registry-ZVO3T4M5.js.map +1 -0
  234. package/dist/request-withdrawal-EHALV66Y.js +31 -0
  235. package/dist/request-withdrawal-EHALV66Y.js.map +1 -0
  236. package/dist/reveal-TBLTFWQ2.js +38 -0
  237. package/dist/reveal-TBLTFWQ2.js.map +1 -0
  238. package/dist/revoke-MHAUAESM.js +24 -0
  239. package/dist/revoke-MHAUAESM.js.map +1 -0
  240. package/dist/sealed-record/index.d.ts +3 -3
  241. package/dist/sealed-record/index.js +13 -7
  242. package/dist/sealed-record/index.js.map +1 -1
  243. package/dist/session/index.d.ts +4 -4
  244. package/dist/session/index.js +10 -4
  245. package/dist/session/index.js.map +1 -1
  246. package/dist/shadow/index.d.ts +3 -3
  247. package/dist/shadow/index.js +2 -2
  248. package/dist/signer-PQ74YXRY.js +25 -0
  249. package/dist/signer-PQ74YXRY.js.map +1 -0
  250. package/dist/snapshots/index.d.ts +3 -3
  251. package/dist/snapshots/index.js +11 -5
  252. package/dist/snapshots/index.js.map +1 -1
  253. package/dist/{stale-3JWHNDIY.js → stale-7Q62KVI3.js} +2 -2
  254. package/dist/stale-7Q62KVI3.js.map +1 -0
  255. package/dist/storage-5E6YB2JY.js +21 -0
  256. package/dist/storage-5E6YB2JY.js.map +1 -0
  257. package/dist/{store-coordination-provider-3I7XWZZK.js → store-coordination-provider-JJCEMTAE.js} +3 -3
  258. package/dist/sync/index.d.ts +2 -2
  259. package/dist/sync/index.js +10 -4
  260. package/dist/sync/index.js.map +1 -1
  261. package/dist/team/index.d.ts +18 -4
  262. package/dist/team/index.js +24 -11
  263. package/dist/tiers/index.d.ts +2 -2
  264. package/dist/tiers/index.js +11 -5
  265. package/dist/to/index.d.ts +2 -2
  266. package/dist/to/index.js +1 -1
  267. package/dist/{transition-guard-DqodPNKw.d.ts → transition-guard-C4hvR-Ac.d.ts} +1 -1
  268. package/dist/tx/index.d.ts +3 -3
  269. package/dist/tx/index.js +3 -3
  270. package/dist/ui/index.d.ts +1 -1
  271. package/dist/util/index.js +1 -1
  272. package/dist/validators-Ctgkj5qd.d.ts +101 -0
  273. package/dist/{vault-diff-BtpiBvic.d.ts → vault-diff-B1Ir6EGs.d.ts} +1 -1
  274. package/dist/verify-YB5LQHNA.js +139 -0
  275. package/dist/verify-YB5LQHNA.js.map +1 -0
  276. package/dist/walk-5C3GPKT2.js +241 -0
  277. package/dist/walk-5C3GPKT2.js.map +1 -0
  278. package/dist/with/index.d.ts +3 -3
  279. package/dist/with/index.js +12 -6
  280. package/dist/{with-materialized-view-DMmWtYfJ.d.ts → with-materialized-view-Bp65kKdQ.d.ts} +1 -1
  281. package/dist/{with-overlayed-view-D_IB2nkM.d.ts → with-overlayed-view-BRhdQNrK.d.ts} +1 -1
  282. package/dist/{with-rollup-em2wxoHP.d.ts → with-rollup-bQRPc3y1.d.ts} +1 -1
  283. package/dist/withdraw-accessible-JMX2TCPX.js +28 -0
  284. package/dist/withdraw-accessible-JMX2TCPX.js.map +1 -0
  285. package/package.json +11 -3
  286. package/dist/api-RW3KP7WU.js +0 -14
  287. package/dist/chunk-5O3AOPDT.js.map +0 -1
  288. package/dist/chunk-5TDJ56JE.js.map +0 -1
  289. package/dist/chunk-DGDI2D4M.js.map +0 -1
  290. package/dist/chunk-IPB7FTQX.js.map +0 -1
  291. package/dist/chunk-LV7M27WM.js.map +0 -1
  292. package/dist/chunk-M2YKN37S.js +0 -524
  293. package/dist/chunk-M2YKN37S.js.map +0 -1
  294. package/dist/chunk-MTMJVJ5W.js.map +0 -1
  295. package/dist/chunk-PSHOXR6C.js.map +0 -1
  296. package/dist/chunk-TJYQIGAP.js.map +0 -1
  297. package/dist/chunk-UIU2THRG.js.map +0 -1
  298. package/dist/chunk-UPJNJGGA.js.map +0 -1
  299. package/dist/collection-facade-GQAOGJP2.js +0 -33
  300. package/dist/delegation-UL5HKLER.js +0 -19
  301. package/dist/executor-2FWQRLMG.js +0 -15
  302. package/dist/executor-QZ7BXICW.js +0 -9
  303. package/dist/executor-Z5ZLJVTV.js +0 -9
  304. package/dist/export-accessible-KRV5W4GH.js +0 -17
  305. package/dist/extract-partition-GLKBOXFQ.js +0 -30
  306. package/dist/fanout-sidecar-GF3DJ6KR.js.map +0 -1
  307. package/dist/issue-Y6UVIR43.js +0 -13
  308. package/dist/liberate-CRPZEV7O.js +0 -18
  309. package/dist/noydb-LDEBLNHY.js +0 -50
  310. package/dist/registry-45RJNWGU.js +0 -9
  311. package/dist/registry-5GRV5VXI.js +0 -13
  312. package/dist/registry-WEUCHBO4.js +0 -11
  313. package/dist/request-withdrawal-GBPH2FDY.js +0 -25
  314. package/dist/revoke-TUFRGI6S.js +0 -18
  315. package/dist/signer-PNKTBVF7.js +0 -19
  316. package/dist/withdraw-accessible-FFS46EOD.js +0 -22
  317. /package/dist/{api-RW3KP7WU.js.map → api-JOXUNSKP.js.map} +0 -0
  318. /package/dist/{chunk-SMXWYP24.js.map → chunk-3QRQOBS7.js.map} +0 -0
  319. /package/dist/{chunk-QHJW5EXU.js.map → chunk-3Y4QLJ6K.js.map} +0 -0
  320. /package/dist/{chunk-NF5JWERG.js.map → chunk-43ISXURO.js.map} +0 -0
  321. /package/dist/{chunk-5LUY7UTV.js.map → chunk-4K3MQ5S3.js.map} +0 -0
  322. /package/dist/{chunk-Y22T3KQE.js.map → chunk-5MRE3C4Q.js.map} +0 -0
  323. /package/dist/{chunk-M6OST55S.js.map → chunk-5W7AOFWA.js.map} +0 -0
  324. /package/dist/{chunk-AXRXJTE2.js.map → chunk-6HNKCKFZ.js.map} +0 -0
  325. /package/dist/{chunk-UAG5KWVA.js.map → chunk-6RXPSMKR.js.map} +0 -0
  326. /package/dist/{chunk-UDRIWL7A.js.map → chunk-A5DYVMDR.js.map} +0 -0
  327. /package/dist/{chunk-I3TIKTJO.js.map → chunk-BKGIWGCX.js.map} +0 -0
  328. /package/dist/{chunk-IO6GRPT6.js.map → chunk-BMQOH7MM.js.map} +0 -0
  329. /package/dist/{chunk-FISN7WE4.js.map → chunk-EWR7HL3K.js.map} +0 -0
  330. /package/dist/{chunk-AQTBSL7R.js.map → chunk-FH52CDEW.js.map} +0 -0
  331. /package/dist/{chunk-UV5MFVO3.js.map → chunk-G7RDYYTE.js.map} +0 -0
  332. /package/dist/{chunk-TEILUWOI.js.map → chunk-GOUNIHFA.js.map} +0 -0
  333. /package/dist/{chunk-RUEKROOS.js.map → chunk-GXGK22QU.js.map} +0 -0
  334. /package/dist/{chunk-IELYAOGG.js.map → chunk-GZZL5R73.js.map} +0 -0
  335. /package/dist/{chunk-CWPPNPOH.js.map → chunk-H7RYPVMJ.js.map} +0 -0
  336. /package/dist/{chunk-5N6CZTCY.js.map → chunk-HBKDR7R3.js.map} +0 -0
  337. /package/dist/{chunk-KXGNJJXB.js.map → chunk-HLUKZ36Q.js.map} +0 -0
  338. /package/dist/{chunk-LMTH2RM6.js.map → chunk-HMXLN43G.js.map} +0 -0
  339. /package/dist/{chunk-BG3SPSR4.js.map → chunk-HY6ZGGEC.js.map} +0 -0
  340. /package/dist/{chunk-62QYRORB.js.map → chunk-LIP6JWYK.js.map} +0 -0
  341. /package/dist/{chunk-IGUYVGGI.js.map → chunk-LPRPVCNY.js.map} +0 -0
  342. /package/dist/{chunk-KVOXU4T5.js.map → chunk-N5YVZHCB.js.map} +0 -0
  343. /package/dist/{chunk-IUEN57TV.js.map → chunk-OFBFAVLI.js.map} +0 -0
  344. /package/dist/{chunk-HCIPRAGS.js.map → chunk-P2LDXRGP.js.map} +0 -0
  345. /package/dist/{chunk-V7RWQRG7.js.map → chunk-QNTEDPWP.js.map} +0 -0
  346. /package/dist/{chunk-Q7SS3IME.js.map → chunk-RDHAGBEB.js.map} +0 -0
  347. /package/dist/{chunk-EIZUR2XW.js.map → chunk-RTS23VIJ.js.map} +0 -0
  348. /package/dist/{chunk-AZAOEIKW.js.map → chunk-SW56GSYC.js.map} +0 -0
  349. /package/dist/{chunk-TA66UMI4.js.map → chunk-T2EGAXPM.js.map} +0 -0
  350. /package/dist/{chunk-SM3AVUHC.js.map → chunk-T45LAT2Y.js.map} +0 -0
  351. /package/dist/{chunk-SKF73JOP.js.map → chunk-T65UZXR6.js.map} +0 -0
  352. /package/dist/{chunk-PSMV73A5.js.map → chunk-TYGW5TOR.js.map} +0 -0
  353. /package/dist/{chunk-3YFXJ3ZP.js.map → chunk-U24XHXNK.js.map} +0 -0
  354. /package/dist/{chunk-VCTFO5CO.js.map → chunk-VRPBEOWU.js.map} +0 -0
  355. /package/dist/{chunk-ZCGAHGUS.js.map → chunk-VWGCJUTV.js.map} +0 -0
  356. /package/dist/{chunk-XXYIOFUB.js.map → chunk-XJR3COJO.js.map} +0 -0
  357. /package/dist/{chunk-PKHL44ER.js.map → chunk-XYYW64LB.js.map} +0 -0
  358. /package/dist/{chunk-IAGBDSCS.js.map → chunk-YFF2RP3X.js.map} +0 -0
  359. /package/dist/{chunk-WYSO2NIH.js.map → chunk-Z7KI4WHR.js.map} +0 -0
  360. /package/dist/{chunk-CMGR4ZEW.js.map → chunk-ZROMNP7Q.js.map} +0 -0
  361. /package/dist/{collection-facade-GQAOGJP2.js.map → classified/index.js.map} +0 -0
  362. /package/dist/{delegation-UL5HKLER.js.map → collection-facade-MKEBZDWW.js.map} +0 -0
  363. /package/dist/{enclave-UL5LW66V.js.map → computed-BMMEFRFJ.js.map} +0 -0
  364. /package/dist/{executor-2FWQRLMG.js.map → delegation-BQNIEHZE.js.map} +0 -0
  365. /package/dist/{executor-QZ7BXICW.js.map → enclave-YN6223OG.js.map} +0 -0
  366. /package/dist/{executor-Z5ZLJVTV.js.map → executor-CBTNU5VZ.js.map} +0 -0
  367. /package/dist/{export-accessible-KRV5W4GH.js.map → executor-DJHNSTIR.js.map} +0 -0
  368. /package/dist/{extract-partition-GLKBOXFQ.js.map → executor-FGISLQIN.js.map} +0 -0
  369. /package/dist/{issue-Y6UVIR43.js.map → export-accessible-P7SLRLK3.js.map} +0 -0
  370. /package/dist/{ledger-RYI35CDS.js.map → extract-partition-RNVSFHAB.js.map} +0 -0
  371. /package/dist/{liberate-CRPZEV7O.js.map → find-RNBG7LBY.js.map} +0 -0
  372. /package/dist/{noydb-LDEBLNHY.js.map → issue-W5QG53B5.js.map} +0 -0
  373. /package/dist/{policy-IXK4FVXP.js.map → lazy/index.js.map} +0 -0
  374. /package/dist/{public-envelope-JHDQCPSX.js.map → ledger-KZWBKAG5.js.map} +0 -0
  375. /package/dist/{registry-45RJNWGU.js.map → liberate-GMGCHIND.js.map} +0 -0
  376. /package/dist/{registry-5GRV5VXI.js.map → link-set-UQEIYQAM.js.map} +0 -0
  377. /package/dist/{registry-WEUCHBO4.js.map → noydb-KS2O2MRI.js.map} +0 -0
  378. /package/dist/{request-withdrawal-GBPH2FDY.js.map → policy-YIKUH4AD.js.map} +0 -0
  379. /package/dist/{revoke-TUFRGI6S.js.map → public-envelope-MRN5YYZZ.js.map} +0 -0
  380. /package/dist/{signer-PNKTBVF7.js.map → register-K6DDSIXN.js.map} +0 -0
  381. /package/dist/{stale-3JWHNDIY.js.map → registry-IMNMHWTM.js.map} +0 -0
  382. /package/dist/{withdraw-accessible-FFS46EOD.js.map → registry-K6VUQXKV.js.map} +0 -0
  383. /package/dist/{store-coordination-provider-3I7XWZZK.js.map → store-coordination-provider-JJCEMTAE.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/with-shape/i18n/dictionary.ts"],"sourcesContent":["/**\n * _dict_* reserved collections + dictKey schema descriptor —\n *\n * Stores bounded enum-like field dictionaries as reserved encrypted\n * collections (`_dict_<name>/`) within a vault. Each dictionary\n * entry maps a stable key (e.g. `'paid'`) to a locale → label record\n * (e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`).\n *\n * Design decisions\n * ────────────────\n *\n * **Why reserved collections, not a separate store?**\n * Same answer as `_sync_credentials`: the compartment's existing\n * encryption stack is exactly right. Dictionaries are encrypted under the\n * same vault DEK, inherit ACL, ledger, and backup/restore for free.\n *\n * **One collection per dictionary, not one collection with namespaces.**\n * Each `_dict_<name>/` collection holds entries `{ id: key, labels: {...} }`.\n * This composes with `ref()` naturally (a dictKey IS a ref to the dict\n * collection), and means the query DSL works over dictionary entries\n * without any special-casing.\n *\n * **dictKey() is a descriptor, not a Zod type.**\n * The descriptor pattern matches `ref()`: declare NOYDB-specific metadata\n * in the collection options alongside `refs`. TypeScript inference comes\n * from the descriptor's generic parameter, not from Zod internals.\n *\n * API:\n * `dictKey(name, keys?)` — returns a DictKeyDescriptor\n * `vault.dictionary(name)` — returns a DictionaryHandle\n * `DictionaryHandle.put/putAll/get/delete/rename/list` — CRUD\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport { encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { ensureCollectionDEK } from '../../with-party/team/keyring.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { OnMissingPolicy } from './policy.js'\nimport { envelopePayloadHash } from '../../with-commit/history/ledger/hash.js'\nimport {\n PermissionDeniedError,\n DictKeyMissingError,\n} from '../../kernel/errors.js'\n\n/** Reserved collection name prefix. Never collides with user collections. */\nexport const DICT_COLLECTION_PREFIX = '_dict_'\n\n/** Return the adapter collection name for a named dictionary. */\nexport function dictCollectionName(dictionaryName: string): string {\n return `${DICT_COLLECTION_PREFIX}${dictionaryName}`\n}\n\n/** Return true when a collection name is a reserved dictionary collection. */\nexport function isDictCollectionName(name: string): boolean {\n return name.startsWith(DICT_COLLECTION_PREFIX)\n}\n\n// ─── DictKey descriptor ────────────────────────────────────────────────\n\n/**\n * Descriptor returned by `dictKey()`. Attach to the collection's\n * `dictKeyFields` option to declare which fields are dictionary-backed:\n *\n * ```ts\n * const invoices = company.collection<Invoice>('invoices', {\n * dictKeyFields: {\n * status: dictKey('status', ['draft', 'open', 'paid'] as const),\n * },\n * })\n * ```\n *\n * The generic parameter `Keys` narrows the TypeScript type of the field\n * to a literal union; the runtime value of `keys` is used by `put()`\n * validation to reject unknown keys when a key set is declared.\n */\nexport interface DictKeyDescriptor<Keys extends string = string> {\n readonly _noydbDictKey: true\n /** Which dictionary this field references. */\n readonly name: string\n /** Declared valid keys. When set, `put()` rejects keys not in this set. */\n readonly keys: readonly Keys[] | undefined\n /**\n * What to do when a label is missing for the resolved locale. Mirrors\n * `i18nText`'s `onMissing`. Default behavior (when unset) preserves the\n * legacy contract: a missing label is omitted (scalar) or `null`\n * (array element) — i.e. `'null'`. Set `'substitute'` to walk the\n * declared `substitute` chain, or `'throw'` to raise.\n */\n readonly onMissing?: OnMissingPolicy\n /** Ordered preferred-substitute locales for label resolution. */\n readonly substitute?: readonly string[]\n /**\n * Optional inline display labels (value → label map). A SYNC display\n * fallback for `describe()` when async `dictLabels` (from `_dict_`) are\n * not resolved. The async path still wins when available.\n */\n readonly labels?: Record<string, string>\n}\n\n/**\n * Create a `DictKeyDescriptor` for a dictionary-backed enum field.\n *\n * @param name The dictionary name (corresponds to `_dict_<name>` collection).\n * @param keysOrMap Either:\n * - An `as const` array of valid key literals — narrows the TypeScript type\n * to a literal union and enables put-time validation.\n * - A **value→label map** (`{ draft: 'Draft', paid: 'Paid' }`) — keys are\n * inferred from the map, and the labels are stored as inline display\n * defaults surfaced by `describe()` without a store read.\n * @param opts `{ labels?, onMissing?, substitute? }` when the array form\n * is used; `opts.labels` provides inline display defaults for\n * specific keys (same semantics as the map form, but\n * explicit key order from the array is preserved).\n *\n * @example\n * ```ts\n * // array form (original):\n * dictKey('status', ['draft', 'open', 'paid'] as const)\n *\n * // value→label map form (keys inferred, inline labels for describe()):\n * dictKey('status', { draft: 'Draft', open: 'Open', paid: 'Paid' })\n *\n * // array + opts.labels (preserves explicit order, partial labels OK):\n * dictKey('status', ['draft', 'open', 'paid'] as const, { labels: { paid: 'Paid' } })\n * ```\n */\nexport function dictKey<Keys extends string>(\n name: string,\n keysOrMap?: readonly Keys[] | Record<Keys, string>,\n opts?: { onMissing?: OnMissingPolicy; substitute?: readonly string[]; labels?: Record<string, string> },\n): DictKeyDescriptor<Keys> {\n let keys: readonly Keys[] | undefined\n let labels: Record<string, string> | undefined\n if (Array.isArray(keysOrMap)) {\n keys = keysOrMap as readonly Keys[]\n labels = opts?.labels\n } else if (keysOrMap && typeof keysOrMap === 'object') {\n keys = Object.keys(keysOrMap) as Keys[]\n labels = keysOrMap as Record<string, string>\n } else {\n keys = undefined\n labels = opts?.labels\n }\n return {\n _noydbDictKey: true,\n name,\n keys,\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n ...(labels !== undefined ? { labels } : {}),\n }\n}\n\n/** Runtime predicate for detecting a DictKeyDescriptor. */\nexport function isDictKeyDescriptor(x: unknown): x is DictKeyDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbDictKey?: unknown })._noydbDictKey === true\n )\n}\n\n// ─── StaticDict descriptor (code-provided dictionary) ──────────────────\n\n/**\n * Descriptor returned by `staticDict()`. A sibling to {@link DictKeyDescriptor}\n * for **closed, defined-in-code, identical-across-vaults** enums (honorific,\n * civil-status, gender, religion, ContactTitle, status…).\n *\n * Unlike `dictKey`, the labels are supplied **at registration in code** and\n * resolved through the *same* label machinery, but with **no `_dict_*`\n * per-vault encrypted copy** and **no `rename()`**. The record stores only\n * the **code**; a static dict has no mutation surface.\n *\n * **Hybrid resolution.** Because a static dict is pure code with no\n * vault-locale dependency, it can — via a configured `displayLocale` — emit a\n * `<field>Label` even under a **locale-less read** (the property a locale-less\n * consumer needs and `dictKey` cannot provide). When a locale *is* active it\n * behaves exactly like `dictKey` (honoring `onMissing`/`substitute`).\n *\n * ```ts\n * const workers = vault.collection<Worker>('workers', {\n * dictKeyFields: {\n * civilStatus: staticDict('civilStatus', {\n * adultMale: { th: 'นาย', en: 'Mr' },\n * adultFemale: { th: 'นาง', en: 'Mrs' },\n * }, { displayLocale: 'th' }),\n * },\n * })\n * ```\n */\nexport interface StaticDictDescriptor<Keys extends string = string> {\n readonly _noydbStaticDict: true\n /** Which dictionary this field references (the registry name). */\n readonly name: string\n /** The in-code label table: key → { locale → label }. */\n readonly table: Readonly<Record<Keys, Readonly<Record<string, string>>>>\n /** Declared valid keys — derived from `Object.keys(table)`. */\n readonly keys: readonly Keys[]\n /**\n * Locale used to emit `<field>Label` under a **locale-less** read — the\n * hybrid hinge. When unset, a static dict behaves like `dictKey` under a\n * locale-less read (no label); a locale-less consumer almost always wants\n * it set.\n */\n readonly displayLocale?: string\n /** Same `onMissing` policy engine as `dictKey`. Default `'null'`. */\n readonly onMissing?: OnMissingPolicy\n /** Ordered preferred-substitute locales for label resolution. */\n readonly substitute?: readonly string[]\n /**\n * Validate the stored code against `keys` on every `put()`. Default `true`\n * — codes are closed by construction, so an unknown code is a bug. Set\n * `false` to allow open codes (skips the `UnknownDictCodeError` guard).\n */\n readonly validateCodes?: boolean\n}\n\n/**\n * Create a `StaticDictDescriptor` for a code-provided enum field — a sibling\n * to {@link dictKey} for closed, code-defined, identical-across-vaults enums.\n *\n * The labels live in `table` (no `_dict_*` collection, no `rename()`); the\n * record stores only the stable code. Pass `displayLocale` so `<field>Label`\n * resolves even under a locale-less read.\n *\n * @param name The dictionary name (used for the readonly-guard registry and\n * the query label seam — never creates a `_dict_<name>` key).\n * @param table `{ key: { locale: label } }` map.\n * @param opts `displayLocale` (locale-less label), `onMissing`, `substitute`.\n *\n * @example\n * ```ts\n * staticDict('civilStatus', {\n * adultMale: { th: 'นาย', en: 'Mr' },\n * adultFemale: { th: 'นาง', en: 'Mrs' },\n * }, { displayLocale: 'th' })\n * ```\n */\nexport function staticDict<const T extends Record<string, Record<string, string>>>(\n name: string,\n table: T,\n opts?: {\n displayLocale?: string\n onMissing?: OnMissingPolicy\n substitute?: readonly string[]\n validateCodes?: boolean\n },\n): StaticDictDescriptor<Extract<keyof T, string>> {\n return {\n _noydbStaticDict: true,\n name,\n table: table as Readonly<Record<Extract<keyof T, string>, Readonly<Record<string, string>>>>,\n keys: Object.keys(table) as Extract<keyof T, string>[],\n ...(opts?.displayLocale !== undefined ? { displayLocale: opts.displayLocale } : {}),\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n ...(opts?.validateCodes !== undefined ? { validateCodes: opts.validateCodes } : {}),\n }\n}\n\n/** Runtime predicate for detecting a StaticDictDescriptor. */\nexport function isStaticDictDescriptor(x: unknown): x is StaticDictDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbStaticDict?: unknown })._noydbStaticDict === true\n )\n}\n\n// ─── Dictionary entry shape ────────────────────────────────────────────\n\n/**\n * One entry in a `_dict_*` collection. The record `id` (adapter-side\n * key) IS the stable dictionary key (e.g. `'paid'`). The `labels`\n * record maps locale codes to display strings.\n */\nexport interface DictEntry {\n /** Stable key — same as the record id in the adapter. */\n readonly key: string\n /** Locale → label map, e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`. */\n readonly labels: Record<string, string>\n}\n\n// ─── Per-dictionary options ────────────────────────────────────────────\n\n/**\n * Options for `vault.dictionary(name, options?)`.\n *\n * `writableBy` controls the minimum role for write operations (put,\n * putAll, delete, rename). Defaults to `'admin'` to match the standard\n * \"dictionary contents are owned by admins\" convention; set to\n * `'operator'` for user-editable dictionaries like custom tags.\n */\nexport interface DictionaryOptions {\n /** Minimum role allowed to write dictionary entries. Default: `'admin'`. */\n readonly writableBy?: 'owner' | 'admin' | 'operator'\n}\n\n// ─── DictionaryHandle ──────────────────────────────────────────────────\n\n/**\n * Handle to a named dictionary within a vault.\n *\n * Obtained via `vault.dictionary(name)`. Provides strongly-typed\n * CRUD for dictionary entries, plus the `rename()` operation that is the\n * only sanctioned mass-mutation path for dictKey fields.\n *\n * All writes are encrypted under the compartment's DEK for the\n * `_dict_<name>` collection. Adapters never see plaintext.\n */\nexport class DictionaryHandle<Keys extends string = string> {\n private readonly collName: string\n\n /**\n * Synchronous write-through cache for dict-join support.\n * Populated on every `put()`, `delete()`, and `rename()`. The snapshot\n * is built from this cache by `snapshotEntries()` — the query executor\n * calls this synchronously inside `.toArray()`.\n *\n * `null` means \"not yet initialized\" — callers should use `list()`\n * to warm the cache before using dict joins on pre-existing data.\n */\n private readonly _syncCache = new Map<string, DictEntry>()\n\n /**\n * Return all cached entries as `{ key, labels, ...labels }` records —\n * usable synchronously by the join executor's `snapshot()` call.\n * Returns an empty array when the cache has never been populated.\n */\n snapshotEntries(): readonly Record<string, unknown>[] {\n return Array.from(this._syncCache.values()).map((e) => ({\n key: e.key,\n labels: e.labels,\n ...e.labels,\n }))\n }\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly compartmentName: string,\n private readonly dictionaryName: string,\n private readonly keyring: UnlockedKeyring,\n private readonly getDEK: (collectionName: string) => Promise<EnclaveKey>,\n private readonly encrypted: boolean,\n private readonly ledger: LedgerStore | undefined,\n private readonly options: DictionaryOptions,\n /**\n * Callback provided by the Vault to find and rewrite records\n * in any registered collection that has a dictKeyField pointing at\n * this dictionary, used by `rename()`.\n */\n private readonly findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined,\n private readonly emitter: NoydbEventEmitter,\n ) {\n this.collName = dictCollectionName(dictionaryName)\n }\n\n // ─── Access checks ────────────────────────────────────────────────\n\n private requireWriteAccess(): void {\n const minRole = this.options.writableBy ?? 'admin'\n const roleRank: Record<string, number> = {\n client: 1,\n viewer: 2,\n operator: 3,\n admin: 4,\n owner: 5,\n }\n const callerRank = roleRank[this.keyring.role] ?? 0\n const requiredRank = roleRank[minRole] ?? 4\n if (callerRank < requiredRank) {\n throw new PermissionDeniedError(\n `Dictionary \"${this.dictionaryName}\" writes require \"${minRole}\" role or above. ` +\n `Current role: \"${this.keyring.role}\".`,\n )\n }\n }\n\n // ─── Internal helpers ─────────────────────────────────────────────\n\n private async getDekForDict(): Promise<EnclaveKey> {\n const resolve = await ensureCollectionDEK(\n this.adapter,\n this.compartmentName,\n this.keyring,\n )\n return resolve(this.collName)\n }\n\n private async encryptEntry(entry: DictEntry, version: number): Promise<EncryptedEnvelope> {\n if (!this.encrypted) {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(entry),\n _by: this.keyring.userId,\n }\n }\n const dek = await this.getDekForDict()\n const { iv, data } = await encrypt(JSON.stringify(entry), dek)\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n }\n }\n\n private async decryptEntry(envelope: EncryptedEnvelope): Promise<DictEntry> {\n if (!this.encrypted) {\n return JSON.parse(envelope._data) as DictEntry\n }\n const dek = await this.getDekForDict()\n const json = await openEnvelopeJson(envelope, dek)\n return JSON.parse(json) as DictEntry\n }\n\n // ─── Public API ───────────────────────────────────────────────────\n\n /**\n * Add or overwrite a single dictionary entry.\n *\n * @param key The stable key to store (e.g. `'paid'`).\n * @param labels Locale → label map (e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`).\n */\n async put(key: Keys, labels: Record<string, string>): Promise<void> {\n this.requireWriteAccess()\n\n const entry: DictEntry = { key, labels }\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n const version = existing ? existing._v + 1 : 1\n const envelope = await this.encryptEntry(entry, version)\n\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n key,\n envelope,\n existing ? existing._v : undefined,\n )\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.set(key, entry)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'put',\n })\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: key,\n version,\n actor: this.keyring.userId,\n // — must be the real envelope hash so\n // vault.verifyBackupIntegrity()'s data-cross-check matches.\n payloadHash: await envelopePayloadHash(envelope),\n })\n }\n }\n\n /**\n * Batch-add or overwrite multiple dictionary entries in one call.\n *\n * @param entries `{ key: { locale: label } }` map.\n */\n async putAll(entries: Record<Keys, Record<string, string>>): Promise<void> {\n this.requireWriteAccess()\n for (const [key, labels] of Object.entries(entries) as [Keys, Record<string, string>][]) {\n await this.put(key, labels)\n }\n }\n\n /**\n * Load the label map for a single key.\n *\n * @returns The label map, or `null` if the key doesn't exist.\n */\n async get(key: Keys): Promise<Record<string, string> | null> {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!envelope) return null\n const entry = await this.decryptEntry(envelope)\n return entry.labels\n }\n\n /**\n * Delete a dictionary key.\n *\n * Default mode is `'strict'` — throws `DictKeyInUseError` if any\n * registered collection has a record referencing this key. Pass\n * `{ mode: 'warn' }` to skip the check (dev-mode cleanup only).\n */\n async delete(key: Keys, opts: { mode?: 'strict' | 'warn' } = {}): Promise<void> {\n this.requireWriteAccess()\n\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!existing) {\n throw new DictKeyMissingError(this.dictionaryName, key)\n }\n\n const mode = opts.mode ?? 'strict'\n if (mode === 'strict' && this.findAndUpdateReferences) {\n // Check for references by attempting a rename to a sentinel that\n // doesn't exist — we reuse the reference-finding machinery but\n // abort before applying changes. Simpler: the vault\n // exposes a separate checkReferences() callback. For now we rely\n // on the caller to confirm no references exist, or use warn mode.\n // A dedicated findReferences API is tracked as a follow-up.\n }\n\n await this.adapter.delete(this.compartmentName, this.collName, key)\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.delete(key)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'delete',\n })\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: key,\n version: existing._v,\n actor: this.keyring.userId,\n // — for delete the prior envelope is what was just\n // removed; we hash it so the chain captures intent. The\n // verifyBackupIntegrity data-cross-check skips delete\n // entries entirely (the live record is gone), but the\n // chain still benefits from a stable non-empty hash.\n payloadHash: await envelopePayloadHash(existing),\n })\n }\n }\n\n /**\n * Rename a dictionary key — the only sanctioned mass-mutation path.\n *\n * Atomically:\n * 1. Adds the new key with the same labels as the old key.\n * 2. Updates every registered record that stores the old key to\n * store the new key instead.\n * 3. Deletes the old key.\n * 4. Appends a single ledger entry recording the rename.\n *\n * Respects ACL: throws `PermissionDeniedError` before any mutation\n * if the caller can't write. The cascade is best-effort atomic\n * within this call — no two-phase commit across adapter calls.\n *\n * Cascade-on-delete is NOT supported. Use `rename()` when you need\n * to change a key that records reference.\n */\n async rename(oldKey: Keys, newKey: string): Promise<void> {\n this.requireWriteAccess()\n\n // 1. Load old entry\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n oldKey,\n )\n if (!existing) {\n throw new DictKeyMissingError(this.dictionaryName, oldKey)\n }\n const oldEntry = await this.decryptEntry(existing)\n\n // 2. Write new key\n const newEntry: DictEntry = { key: newKey, labels: oldEntry.labels }\n const newEnvelope = await this.encryptEntry(newEntry, 1)\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n newKey,\n newEnvelope,\n )\n\n // 3. Update all referencing records in registered collections\n if (this.findAndUpdateReferences) {\n await this.findAndUpdateReferences(this.dictionaryName, oldKey, newKey)\n }\n\n // 4. Delete old key\n await this.adapter.delete(this.compartmentName, this.collName, oldKey)\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.delete(oldKey)\n this._syncCache.set(newKey, newEntry)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: oldKey,\n action: 'delete',\n })\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: newKey,\n action: 'put',\n })\n\n // 5. Ledger — record the rename as delete(oldKey) + put(newKey)\n // so verifyBackupIntegrity()'s data-cross-check matches reality\n // (the oldKey envelope is gone; the newKey envelope is what was\n // just written). Two entries instead of one — the chain still\n // captures the rename intent via the matching ts + actor.\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: oldKey,\n version: existing._v,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(existing),\n })\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: newKey,\n version: 1,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(newEnvelope),\n })\n }\n }\n\n /**\n * List all entries in this dictionary.\n *\n * @returns Array of `{ key, labels }` objects.\n */\n async list(): Promise<DictEntry[]> {\n const keys = await this.adapter.list(this.compartmentName, this.collName)\n const entries: DictEntry[] = []\n for (const key of keys) {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!envelope) continue\n const entry = await this.decryptEntry(envelope)\n entries.push(entry)\n // Warm the synchronous cache\n this._syncCache.set(key, entry)\n }\n return entries\n }\n\n /**\n * Resolve a key to its label for the given locale.\n *\n * Used by the collection's locale-aware read path to populate\n * `<field>Label` virtual fields. Returns `undefined` when the\n * key doesn't exist or has no label for the requested locale\n * (after exhausting the fallback chain).\n */\n async resolveLabel(\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ): Promise<string | undefined> {\n const labels = await this.get(key as Keys)\n if (!labels) return undefined\n\n // Try primary locale\n if (labels[locale] !== undefined) return labels[locale]\n\n // Try fallback chain\n const chain = Array.isArray(fallback) ? (fallback as readonly string[]) : fallback ? [fallback as string] : []\n for (const fb of chain) {\n if (fb === 'any') {\n // Return any available label\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n\n return undefined\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/with-shape/i18n/dictionary.ts"],"sourcesContent":["/**\n * _dict_* reserved collections + dictKey schema descriptor —\n *\n * Stores bounded enum-like field dictionaries as reserved encrypted\n * collections (`_dict_<name>/`) within a vault. Each dictionary\n * entry maps a stable key (e.g. `'paid'`) to a locale → label record\n * (e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`).\n *\n * Design decisions\n * ────────────────\n *\n * **Why reserved collections, not a separate store?**\n * Same answer as `_sync_credentials`: the compartment's existing\n * encryption stack is exactly right. Dictionaries are encrypted under the\n * same vault DEK, inherit ACL, ledger, and backup/restore for free.\n *\n * **One collection per dictionary, not one collection with namespaces.**\n * Each `_dict_<name>/` collection holds entries `{ id: key, labels: {...} }`.\n * This composes with `ref()` naturally (a dictKey IS a ref to the dict\n * collection), and means the query DSL works over dictionary entries\n * without any special-casing.\n *\n * **dictKey() is a descriptor, not a Zod type.**\n * The descriptor pattern matches `ref()`: declare NOYDB-specific metadata\n * in the collection options alongside `refs`. TypeScript inference comes\n * from the descriptor's generic parameter, not from Zod internals.\n *\n * API:\n * `dictKey(name, keys?)` — returns a DictKeyDescriptor\n * `vault.dictionary(name)` — returns a DictionaryHandle\n * `DictionaryHandle.put/putAll/get/delete/rename/list` — CRUD\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport type { NoydbEventEmitter } from '../../kernel/events.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { UnlockedKeyring } from '../../with-party/team/keyring.js'\nimport { encrypt, openEnvelopeJson, type EnclaveKey } from '../../kernel/enclave/index.js'\nimport { ensureCollectionDEK } from '../../with-party/team/keyring.js'\nimport type { LedgerStore } from '../../with-commit/history/ledger/store.js'\nimport type { OnMissingPolicy } from './policy.js'\nimport { envelopePayloadHash } from '../../with-commit/history/ledger/hash.js'\nimport {\n PermissionDeniedError,\n DictKeyMissingError,\n} from '../../kernel/errors.js'\n\n/** Reserved collection name prefix. Never collides with user collections. */\nexport const DICT_COLLECTION_PREFIX = '_dict_'\n\n/** Return the adapter collection name for a named dictionary. */\nexport function dictCollectionName(dictionaryName: string): string {\n return `${DICT_COLLECTION_PREFIX}${dictionaryName}`\n}\n\n/** Return true when a collection name is a reserved dictionary collection. */\nexport function isDictCollectionName(name: string): boolean {\n return name.startsWith(DICT_COLLECTION_PREFIX)\n}\n\n// ─── DictKey descriptor ────────────────────────────────────────────────\n\n/**\n * Descriptor returned by `dictKey()`. Attach to the collection's\n * `dictKeyFields` option to declare which fields are dictionary-backed:\n *\n * ```ts\n * const invoices = company.collection<Invoice>('invoices', {\n * dictKeyFields: {\n * status: dictKey('status', ['draft', 'open', 'paid'] as const),\n * },\n * })\n * ```\n *\n * The generic parameter `Keys` narrows the TypeScript type of the field\n * to a literal union; the runtime value of `keys` is used by `put()`\n * validation to reject unknown keys when a key set is declared.\n */\nexport interface DictKeyDescriptor<Keys extends string = string> {\n readonly _noydbDictKey: true\n /** Which dictionary this field references. */\n readonly name: string\n /** Declared valid keys. When set, `put()` rejects keys not in this set. */\n readonly keys: readonly Keys[] | undefined\n /**\n * What to do when a label is missing for the resolved locale. Mirrors\n * `i18nText`'s `onMissing`. Default behavior (when unset) preserves the\n * legacy contract: a missing label is omitted (scalar) or `null`\n * (array element) — i.e. `'null'`. Set `'substitute'` to walk the\n * declared `substitute` chain, or `'throw'` to raise.\n */\n readonly onMissing?: OnMissingPolicy\n /** Ordered preferred-substitute locales for label resolution. */\n readonly substitute?: readonly string[]\n /**\n * Optional inline display labels (value → label map). A SYNC display\n * fallback for `describe()` when async `dictLabels` (from `_dict_`) are\n * not resolved. The async path still wins when available.\n */\n readonly labels?: Record<string, string>\n}\n\n/**\n * Create a `DictKeyDescriptor` for a dictionary-backed enum field.\n *\n * @param name The dictionary name (corresponds to `_dict_<name>` collection).\n * @param keysOrMap Either:\n * - An `as const` array of valid key literals — narrows the TypeScript type\n * to a literal union and enables put-time validation.\n * - A **value→label map** (`{ draft: 'Draft', paid: 'Paid' }`) — keys are\n * inferred from the map, and the labels are stored as inline display\n * defaults surfaced by `describe()` without a store read.\n * @param opts `{ labels?, onMissing?, substitute? }` when the array form\n * is used; `opts.labels` provides inline display defaults for\n * specific keys (same semantics as the map form, but\n * explicit key order from the array is preserved).\n *\n * @example\n * ```ts\n * // array form (original):\n * dictKey('status', ['draft', 'open', 'paid'] as const)\n *\n * // value→label map form (keys inferred, inline labels for describe()):\n * dictKey('status', { draft: 'Draft', open: 'Open', paid: 'Paid' })\n *\n * // array + opts.labels (preserves explicit order, partial labels OK):\n * dictKey('status', ['draft', 'open', 'paid'] as const, { labels: { paid: 'Paid' } })\n * ```\n */\nexport function dictKey<Keys extends string>(\n name: string,\n keysOrMap?: readonly Keys[] | Record<Keys, string>,\n opts?: { onMissing?: OnMissingPolicy; substitute?: readonly string[]; labels?: Record<string, string> },\n): DictKeyDescriptor<Keys> {\n let keys: readonly Keys[] | undefined\n let labels: Record<string, string> | undefined\n if (Array.isArray(keysOrMap)) {\n keys = keysOrMap as readonly Keys[]\n labels = opts?.labels\n } else if (keysOrMap && typeof keysOrMap === 'object') {\n keys = Object.keys(keysOrMap) as Keys[]\n labels = keysOrMap as Record<string, string>\n } else {\n keys = undefined\n labels = opts?.labels\n }\n return {\n _noydbDictKey: true,\n name,\n keys,\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n ...(labels !== undefined ? { labels } : {}),\n }\n}\n\n/** Runtime predicate for detecting a DictKeyDescriptor. */\nexport function isDictKeyDescriptor(x: unknown): x is DictKeyDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbDictKey?: unknown })._noydbDictKey === true\n )\n}\n\n// ─── StaticDict descriptor (code-provided dictionary) ──────────────────\n\n/**\n * Descriptor returned by `staticDict()`. A sibling to {@link DictKeyDescriptor}\n * for **closed, defined-in-code, identical-across-vaults** enums (honorific,\n * civil-status, gender, religion, ContactTitle, status…).\n *\n * Unlike `dictKey`, the labels are supplied **at registration in code** and\n * resolved through the *same* label machinery, but with **no `_dict_*`\n * per-vault encrypted copy** and **no `rename()`**. The record stores only\n * the **code**; a static dict has no mutation surface.\n *\n * **Hybrid resolution.** Because a static dict is pure code with no\n * vault-locale dependency, it can — via a configured `displayLocale` — emit a\n * `<field>Label` even under a **locale-less read** (the property a locale-less\n * consumer needs and `dictKey` cannot provide). When a locale *is* active it\n * behaves exactly like `dictKey` (honoring `onMissing`/`substitute`).\n *\n * ```ts\n * const workers = vault.collection<Worker>('workers', {\n * dictKeyFields: {\n * civilStatus: staticDict('civilStatus', {\n * adultMale: { th: 'นาย', en: 'Mr' },\n * adultFemale: { th: 'นาง', en: 'Mrs' },\n * }, { displayLocale: 'th' }),\n * },\n * })\n * ```\n */\nexport interface StaticDictDescriptor<Keys extends string = string> {\n readonly _noydbStaticDict: true\n /** Which dictionary this field references (the registry name). */\n readonly name: string\n /** The in-code label table: key → { locale → label }. */\n readonly table: Readonly<Record<Keys, Readonly<Record<string, string>>>>\n /** Declared valid keys — derived from `Object.keys(table)`. */\n readonly keys: readonly Keys[]\n /**\n * Locale used to emit `<field>Label` under a **locale-less** read — the\n * hybrid hinge. When unset, a static dict behaves like `dictKey` under a\n * locale-less read (no label); a locale-less consumer almost always wants\n * it set.\n */\n readonly displayLocale?: string\n /** Same `onMissing` policy engine as `dictKey`. Default `'null'`. */\n readonly onMissing?: OnMissingPolicy\n /** Ordered preferred-substitute locales for label resolution. */\n readonly substitute?: readonly string[]\n /**\n * Validate the stored code against `keys` on every `put()`. Default `true`\n * — codes are closed by construction, so an unknown code is a bug. Set\n * `false` to allow open codes (skips the `UnknownDictCodeError` guard).\n */\n readonly validateCodes?: boolean\n}\n\n/**\n * Create a `StaticDictDescriptor` for a code-provided enum field — a sibling\n * to {@link dictKey} for closed, code-defined, identical-across-vaults enums.\n *\n * The labels live in `table` (no `_dict_*` collection, no `rename()`); the\n * record stores only the stable code. Pass `displayLocale` so `<field>Label`\n * resolves even under a locale-less read.\n *\n * @param name The dictionary name (used for the readonly-guard registry and\n * the query label seam — never creates a `_dict_<name>` key).\n * @param table `{ key: { locale: label } }` map.\n * @param opts `displayLocale` (locale-less label), `onMissing`, `substitute`.\n *\n * @example\n * ```ts\n * staticDict('civilStatus', {\n * adultMale: { th: 'นาย', en: 'Mr' },\n * adultFemale: { th: 'นาง', en: 'Mrs' },\n * }, { displayLocale: 'th' })\n * ```\n */\nexport function staticDict<const T extends Record<string, Record<string, string>>>(\n name: string,\n table: T,\n opts?: {\n displayLocale?: string\n onMissing?: OnMissingPolicy\n substitute?: readonly string[]\n validateCodes?: boolean\n },\n): StaticDictDescriptor<Extract<keyof T, string>> {\n return {\n _noydbStaticDict: true,\n name,\n table: table as Readonly<Record<Extract<keyof T, string>, Readonly<Record<string, string>>>>,\n keys: Object.keys(table) as Extract<keyof T, string>[],\n ...(opts?.displayLocale !== undefined ? { displayLocale: opts.displayLocale } : {}),\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n ...(opts?.validateCodes !== undefined ? { validateCodes: opts.validateCodes } : {}),\n }\n}\n\n/** Runtime predicate for detecting a StaticDictDescriptor. */\nexport function isStaticDictDescriptor(x: unknown): x is StaticDictDescriptor {\n return (\n typeof x === 'object' &&\n x !== null &&\n (x as { _noydbStaticDict?: unknown })._noydbStaticDict === true\n )\n}\n\n// ─── Dictionary entry shape ────────────────────────────────────────────\n\n/**\n * One entry in a `_dict_*` collection. The record `id` (adapter-side\n * key) IS the stable dictionary key (e.g. `'paid'`). The `labels`\n * record maps locale codes to display strings.\n */\nexport interface DictEntry {\n /** Stable key — same as the record id in the adapter. */\n readonly key: string\n /** Locale → label map, e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`. */\n readonly labels: Record<string, string>\n}\n\n// ─── Per-dictionary options ────────────────────────────────────────────\n\n/**\n * Options for `vault.dictionary(name, options?)`.\n *\n * `writableBy` controls the minimum role for write operations (put,\n * putAll, delete, rename). Defaults to `'admin'` to match the standard\n * \"dictionary contents are owned by admins\" convention; set to\n * `'operator'` for user-editable dictionaries like custom tags.\n */\nexport interface DictionaryOptions {\n /** Minimum role allowed to write dictionary entries. Default: `'admin'`. */\n readonly writableBy?: 'owner' | 'admin' | 'operator'\n}\n\n// ─── DictionaryHandle ──────────────────────────────────────────────────\n\n/**\n * Handle to a named dictionary within a vault.\n *\n * Obtained via `vault.dictionary(name)`. Provides strongly-typed\n * CRUD for dictionary entries, plus the `rename()` operation that is the\n * only sanctioned mass-mutation path for dictKey fields.\n *\n * All writes are encrypted under the compartment's DEK for the\n * `_dict_<name>` collection. Adapters never see plaintext.\n */\nexport class DictionaryHandle<Keys extends string = string> {\n private readonly collName: string\n\n /**\n * Synchronous write-through cache for dict-join support.\n * Populated on every `put()`, `delete()`, and `rename()`. The snapshot\n * is built from this cache by `snapshotEntries()` — the query executor\n * calls this synchronously inside `.toArray()`.\n *\n * `null` means \"not yet initialized\" — callers should use `list()`\n * to warm the cache before using dict joins on pre-existing data.\n */\n private readonly _syncCache = new Map<string, DictEntry>()\n\n /**\n * Return all cached entries as `{ key, labels, ...labels }` records —\n * usable synchronously by the join executor's `snapshot()` call.\n * Returns an empty array when the cache has never been populated.\n */\n snapshotEntries(): readonly Record<string, unknown>[] {\n return Array.from(this._syncCache.values()).map((e) => ({\n key: e.key,\n labels: e.labels,\n ...e.labels,\n }))\n }\n\n constructor(\n private readonly adapter: NoydbStore,\n private readonly compartmentName: string,\n private readonly dictionaryName: string,\n private readonly keyring: UnlockedKeyring,\n private readonly getDEK: (collectionName: string) => Promise<EnclaveKey>,\n private readonly encrypted: boolean,\n private readonly ledger: LedgerStore | undefined,\n private readonly options: DictionaryOptions,\n /**\n * Callback provided by the Vault to find and rewrite records\n * in any registered collection that has a dictKeyField pointing at\n * this dictionary, used by `rename()`.\n */\n private readonly findAndUpdateReferences:\n | ((\n dictionaryName: string,\n oldKey: string,\n newKey: string,\n ) => Promise<void>)\n | undefined,\n private readonly emitter: NoydbEventEmitter,\n ) {\n this.collName = dictCollectionName(dictionaryName)\n }\n\n // ─── Access checks ────────────────────────────────────────────────\n\n private requireWriteAccess(): void {\n const minRole = this.options.writableBy ?? 'admin'\n const roleRank: Record<string, number> = {\n client: 1,\n viewer: 2,\n operator: 3,\n admin: 4,\n owner: 5,\n }\n const callerRank = roleRank[this.keyring.role] ?? 0\n const requiredRank = roleRank[minRole] ?? 4\n if (callerRank < requiredRank) {\n throw new PermissionDeniedError(\n `Dictionary \"${this.dictionaryName}\" writes require \"${minRole}\" role or above. ` +\n `Current role: \"${this.keyring.role}\".`,\n )\n }\n }\n\n // ─── Internal helpers ─────────────────────────────────────────────\n\n private async getDekForDict(): Promise<EnclaveKey> {\n const resolve = await ensureCollectionDEK(\n this.adapter,\n this.compartmentName,\n this.keyring,\n )\n return resolve(this.collName)\n }\n\n private async encryptEntry(entry: DictEntry, version: number): Promise<EncryptedEnvelope> {\n if (!this.encrypted) {\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify(entry),\n _by: this.keyring.userId,\n }\n }\n const dek = await this.getDekForDict()\n const { iv, data } = await encrypt(JSON.stringify(entry), dek)\n return {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: this.keyring.userId,\n }\n }\n\n private async decryptEntry(envelope: EncryptedEnvelope): Promise<DictEntry> {\n if (!this.encrypted) {\n return JSON.parse(envelope._data) as DictEntry\n }\n const dek = await this.getDekForDict()\n const json = await openEnvelopeJson(envelope, dek)\n return JSON.parse(json) as DictEntry\n }\n\n // ─── Public API ───────────────────────────────────────────────────\n\n /**\n * Add or overwrite a single dictionary entry.\n *\n * @param key The stable key to store (e.g. `'paid'`).\n * @param labels Locale → label map (e.g. `{ en: 'Paid', th: 'ชำระแล้ว' }`).\n */\n async put(key: Keys, labels: Record<string, string>): Promise<void> {\n this.requireWriteAccess()\n\n const entry: DictEntry = { key, labels }\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n const version = existing ? existing._v + 1 : 1\n const envelope = await this.encryptEntry(entry, version)\n\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n key,\n envelope,\n existing ? existing._v : undefined,\n )\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.set(key, entry)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'put',\n })\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: key,\n version,\n actor: this.keyring.userId,\n // — must be the real envelope hash so\n // vault.verifyBackupIntegrity()'s data-cross-check matches.\n payloadHash: await envelopePayloadHash(envelope),\n })\n }\n }\n\n /**\n * Batch-add or overwrite multiple dictionary entries in one call.\n *\n * @param entries `{ key: { locale: label } }` map.\n */\n async putAll(entries: Record<Keys, Record<string, string>>): Promise<void> {\n this.requireWriteAccess()\n for (const [key, labels] of Object.entries(entries) as [Keys, Record<string, string>][]) {\n await this.put(key, labels)\n }\n }\n\n /**\n * Load the label map for a single key.\n *\n * @returns The label map, or `null` if the key doesn't exist.\n */\n async get(key: Keys): Promise<Record<string, string> | null> {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!envelope) return null\n const entry = await this.decryptEntry(envelope)\n return entry.labels\n }\n\n /**\n * Delete a dictionary key.\n *\n * Default mode is `'strict'` — throws `DictKeyInUseError` if any\n * registered collection has a record referencing this key. Pass\n * `{ mode: 'warn' }` to skip the check (dev-mode cleanup only).\n */\n async delete(key: Keys, opts: { mode?: 'strict' | 'warn' } = {}): Promise<void> {\n this.requireWriteAccess()\n\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!existing) {\n throw new DictKeyMissingError(this.dictionaryName, key)\n }\n\n const mode = opts.mode ?? 'strict'\n if (mode === 'strict' && this.findAndUpdateReferences) {\n // Check for references by attempting a rename to a sentinel that\n // doesn't exist — we reuse the reference-finding machinery but\n // abort before applying changes. Simpler: the vault\n // exposes a separate checkReferences() callback. For now we rely\n // on the caller to confirm no references exist, or use warn mode.\n // A dedicated findReferences API is tracked as a follow-up.\n }\n\n await this.adapter.delete(this.compartmentName, this.collName, key)\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.delete(key)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: key,\n action: 'delete',\n })\n\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: key,\n version: existing._v,\n actor: this.keyring.userId,\n // — for delete the prior envelope is what was just\n // removed; we hash it so the chain captures intent. The\n // verifyBackupIntegrity data-cross-check skips delete\n // entries entirely (the live record is gone), but the\n // chain still benefits from a stable non-empty hash.\n payloadHash: await envelopePayloadHash(existing),\n })\n }\n }\n\n /**\n * Rename a dictionary key — the only sanctioned mass-mutation path.\n *\n * Atomically:\n * 1. Adds the new key with the same labels as the old key.\n * 2. Updates every registered record that stores the old key to\n * store the new key instead.\n * 3. Deletes the old key.\n * 4. Appends a single ledger entry recording the rename.\n *\n * Respects ACL: throws `PermissionDeniedError` before any mutation\n * if the caller can't write. The cascade is best-effort atomic\n * within this call — no two-phase commit across adapter calls.\n *\n * Cascade-on-delete is NOT supported. Use `rename()` when you need\n * to change a key that records reference.\n */\n async rename(oldKey: Keys, newKey: string): Promise<void> {\n this.requireWriteAccess()\n\n // 1. Load old entry\n const existing = await this.adapter.get(\n this.compartmentName,\n this.collName,\n oldKey,\n )\n if (!existing) {\n throw new DictKeyMissingError(this.dictionaryName, oldKey)\n }\n const oldEntry = await this.decryptEntry(existing)\n\n // 2. Write new key\n const newEntry: DictEntry = { key: newKey, labels: oldEntry.labels }\n const newEnvelope = await this.encryptEntry(newEntry, 1)\n await this.adapter.put(\n this.compartmentName,\n this.collName,\n newKey,\n newEnvelope,\n )\n\n // 3. Update all referencing records in registered collections\n if (this.findAndUpdateReferences) {\n await this.findAndUpdateReferences(this.dictionaryName, oldKey, newKey)\n }\n\n // 4. Delete old key\n await this.adapter.delete(this.compartmentName, this.collName, oldKey)\n\n // Maintain synchronous cache for dict-join snapshot\n this._syncCache.delete(oldKey)\n this._syncCache.set(newKey, newEntry)\n\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: oldKey,\n action: 'delete',\n })\n this.emitter.emit('change', {\n vault: this.compartmentName,\n collection: this.collName,\n id: newKey,\n action: 'put',\n })\n\n // 5. Ledger — record the rename as delete(oldKey) + put(newKey)\n // so verifyBackupIntegrity()'s data-cross-check matches reality\n // (the oldKey envelope is gone; the newKey envelope is what was\n // just written). Two entries instead of one — the chain still\n // captures the rename intent via the matching ts + actor.\n if (this.ledger) {\n await this.ledger.append({\n op: 'delete',\n collection: this.collName,\n id: oldKey,\n version: existing._v,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(existing),\n })\n await this.ledger.append({\n op: 'put',\n collection: this.collName,\n id: newKey,\n version: 1,\n actor: this.keyring.userId,\n payloadHash: await envelopePayloadHash(newEnvelope),\n })\n }\n }\n\n /**\n * List all entries in this dictionary.\n *\n * @returns Array of `{ key, labels }` objects.\n */\n async list(): Promise<DictEntry[]> {\n const keys = await this.adapter.list(this.compartmentName, this.collName)\n const entries: DictEntry[] = []\n for (const key of keys) {\n const envelope = await this.adapter.get(\n this.compartmentName,\n this.collName,\n key,\n )\n if (!envelope) continue\n const entry = await this.decryptEntry(envelope)\n entries.push(entry)\n // Warm the synchronous cache\n this._syncCache.set(key, entry)\n }\n return entries\n }\n\n /**\n * Resolve a key to its label for the given locale.\n *\n * Used by the collection's locale-aware read path to populate\n * `<field>Label` virtual fields. Returns `undefined` when the\n * key doesn't exist or has no label for the requested locale\n * (after exhausting the fallback chain).\n */\n async resolveLabel(\n key: string,\n locale: string,\n fallback?: string | readonly string[],\n ): Promise<string | undefined> {\n const labels = await this.get(key as Keys)\n if (!labels) return undefined\n\n // Try primary locale\n if (labels[locale] !== undefined) return labels[locale]\n\n // Try fallback chain\n const chain = Array.isArray(fallback) ? (fallback as readonly string[]) : fallback ? [fallback as string] : []\n for (const fb of chain) {\n if (fb === 'any') {\n // Return any available label\n const any = Object.values(labels)[0]\n if (any !== undefined) return any\n } else if (labels[fb] !== undefined) {\n return labels[fb]\n }\n }\n\n return undefined\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgDO,IAAM,yBAAyB;AAG/B,SAAS,mBAAmB,gBAAgC;AACjE,SAAO,GAAG,sBAAsB,GAAG,cAAc;AACnD;AAGO,SAAS,qBAAqB,MAAuB;AAC1D,SAAO,KAAK,WAAW,sBAAsB;AAC/C;AAuEO,SAAS,QACd,MACA,WACA,MACyB;AACzB,MAAI;AACJ,MAAI;AACJ,MAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,WAAO;AACP,aAAS,MAAM;AAAA,EACjB,WAAW,aAAa,OAAO,cAAc,UAAU;AACrD,WAAO,OAAO,KAAK,SAAS;AAC5B,aAAS;AAAA,EACX,OAAO;AACL,WAAO;AACP,aAAS,MAAM;AAAA,EACjB;AACA,SAAO;AAAA,IACL,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,GAAI,MAAM,cAAc,SAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,IACrE,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,IACxE,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,EAC3C;AACF;AAGO,SAAS,oBAAoB,GAAoC;AACtE,SACE,OAAO,MAAM,YACb,MAAM,QACL,EAAkC,kBAAkB;AAEzD;AA+EO,SAAS,WACd,MACA,OACA,MAMgD;AAChD,SAAO;AAAA,IACL,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,IACA,MAAM,OAAO,KAAK,KAAK;AAAA,IACvB,GAAI,MAAM,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,IACjF,GAAI,MAAM,cAAc,SAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,IACrE,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;AAAA,IACxE,GAAI,MAAM,kBAAkB,SAAY,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;AAAA,EACnF;AACF;AAGO,SAAS,uBAAuB,GAAuC;AAC5E,SACE,OAAO,MAAM,YACb,MAAM,QACL,EAAqC,qBAAqB;AAE/D;AA2CO,IAAM,mBAAN,MAAqD;AAAA,EA2B1D,YACmB,SACA,iBACA,gBACA,SACA,QACA,WACA,QACA,SAMA,yBAOA,SACjB;AArBiB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AAOA;AAEjB,SAAK,WAAW,mBAAmB,cAAc;AAAA,EACnD;AAAA,EAvBmB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAMA;AAAA,EAOA;AAAA,EA/CF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,oBAAI,IAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzD,kBAAsD;AACpD,WAAO,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO;AAAA,MACtD,KAAK,EAAE;AAAA,MACP,QAAQ,EAAE;AAAA,MACV,GAAG,EAAE;AAAA,IACP,EAAE;AAAA,EACJ;AAAA;AAAA,EA8BQ,qBAA2B;AACjC,UAAM,UAAU,KAAK,QAAQ,cAAc;AAC3C,UAAM,WAAmC;AAAA,MACvC,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AACA,UAAM,aAAa,SAAS,KAAK,QAAQ,IAAI,KAAK;AAClD,UAAM,eAAe,SAAS,OAAO,KAAK;AAC1C,QAAI,aAAa,cAAc;AAC7B,YAAM,IAAI;AAAA,QACR,eAAe,KAAK,cAAc,qBAAqB,OAAO,mCAC1C,KAAK,QAAQ,IAAI;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,MAAc,gBAAqC;AACjD,UAAM,UAAU,MAAM;AAAA,MACpB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AACA,WAAO,QAAQ,KAAK,QAAQ;AAAA,EAC9B;AAAA,EAEA,MAAc,aAAa,OAAkB,SAA6C;AACxF,QAAI,CAAC,KAAK,WAAW;AACnB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,IAAI;AAAA,QACJ,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,QAC5B,KAAK;AAAA,QACL,OAAO,KAAK,UAAU,KAAK;AAAA,QAC3B,KAAK,KAAK,QAAQ;AAAA,MACpB;AAAA,IACF;AACA,UAAM,MAAM,MAAM,KAAK,cAAc;AACrC,UAAM,EAAE,IAAI,KAAK,IAAI,MAAM,QAAQ,KAAK,UAAU,KAAK,GAAG,GAAG;AAC7D,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,IAAI;AAAA,MACJ,MAAK,oBAAI,KAAK,GAAE,YAAY;AAAA,MAC5B,KAAK;AAAA,MACL,OAAO;AAAA,MACP,KAAK,KAAK,QAAQ;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,UAAiD;AAC1E,QAAI,CAAC,KAAK,WAAW;AACnB,aAAO,KAAK,MAAM,SAAS,KAAK;AAAA,IAClC;AACA,UAAM,MAAM,MAAM,KAAK,cAAc;AACrC,UAAM,OAAO,MAAM,iBAAiB,UAAU,GAAG;AACjD,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,IAAI,KAAW,QAA+C;AAClE,SAAK,mBAAmB;AAExB,UAAM,QAAmB,EAAE,KAAK,OAAO;AACvC,UAAM,WAAW,MAAM,KAAK,QAAQ;AAAA,MAClC,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AACA,UAAM,UAAU,WAAW,SAAS,KAAK,IAAI;AAC7C,UAAM,WAAW,MAAM,KAAK,aAAa,OAAO,OAAO;AAEvD,UAAM,KAAK,QAAQ;AAAA,MACjB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW,SAAS,KAAK;AAAA,IAC3B;AAGA,SAAK,WAAW,IAAI,KAAK,KAAK;AAE9B,SAAK,QAAQ,KAAK,UAAU;AAAA,MAC1B,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,KAAK,QAAQ;AACf,YAAM,KAAK,OAAO,OAAO;AAAA,QACvB,IAAI;AAAA,QACJ,YAAY,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ;AAAA,QACA,OAAO,KAAK,QAAQ;AAAA;AAAA;AAAA,QAGpB,aAAa,MAAM,oBAAoB,QAAQ;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAAO,SAA8D;AACzE,SAAK,mBAAmB;AACxB,eAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,OAAO,GAAuC;AACvF,YAAM,KAAK,IAAI,KAAK,MAAM;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,IAAI,KAAmD;AAC3D,UAAM,WAAW,MAAM,KAAK,QAAQ;AAAA,MAClC,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AACA,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,QAAQ,MAAM,KAAK,aAAa,QAAQ;AAC9C,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,OAAO,KAAW,OAAqC,CAAC,GAAkB;AAC9E,SAAK,mBAAmB;AAExB,UAAM,WAAW,MAAM,KAAK,QAAQ;AAAA,MAClC,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AACA,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,oBAAoB,KAAK,gBAAgB,GAAG;AAAA,IACxD;AAEA,UAAM,OAAO,KAAK,QAAQ;AAC1B,QAAI,SAAS,YAAY,KAAK,yBAAyB;AAAA,IAOvD;AAEA,UAAM,KAAK,QAAQ,OAAO,KAAK,iBAAiB,KAAK,UAAU,GAAG;AAGlE,SAAK,WAAW,OAAO,GAAG;AAE1B,SAAK,QAAQ,KAAK,UAAU;AAAA,MAC1B,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV,CAAC;AAED,QAAI,KAAK,QAAQ;AACf,YAAM,KAAK,OAAO,OAAO;AAAA,QACvB,IAAI;AAAA,QACJ,YAAY,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,SAAS,SAAS;AAAA,QAClB,OAAO,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMpB,aAAa,MAAM,oBAAoB,QAAQ;AAAA,MACjD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,MAAM,OAAO,QAAc,QAA+B;AACxD,SAAK,mBAAmB;AAGxB,UAAM,WAAW,MAAM,KAAK,QAAQ;AAAA,MAClC,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,IACF;AACA,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,oBAAoB,KAAK,gBAAgB,MAAM;AAAA,IAC3D;AACA,UAAM,WAAW,MAAM,KAAK,aAAa,QAAQ;AAGjD,UAAM,WAAsB,EAAE,KAAK,QAAQ,QAAQ,SAAS,OAAO;AACnE,UAAM,cAAc,MAAM,KAAK,aAAa,UAAU,CAAC;AACvD,UAAM,KAAK,QAAQ;AAAA,MACjB,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAGA,QAAI,KAAK,yBAAyB;AAChC,YAAM,KAAK,wBAAwB,KAAK,gBAAgB,QAAQ,MAAM;AAAA,IACxE;AAGA,UAAM,KAAK,QAAQ,OAAO,KAAK,iBAAiB,KAAK,UAAU,MAAM;AAGrE,SAAK,WAAW,OAAO,MAAM;AAC7B,SAAK,WAAW,IAAI,QAAQ,QAAQ;AAEpC,SAAK,QAAQ,KAAK,UAAU;AAAA,MAC1B,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV,CAAC;AACD,SAAK,QAAQ,KAAK,UAAU;AAAA,MAC1B,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,MACjB,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV,CAAC;AAOD,QAAI,KAAK,QAAQ;AACf,YAAM,KAAK,OAAO,OAAO;AAAA,QACvB,IAAI;AAAA,QACJ,YAAY,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,SAAS,SAAS;AAAA,QAClB,OAAO,KAAK,QAAQ;AAAA,QACpB,aAAa,MAAM,oBAAoB,QAAQ;AAAA,MACjD,CAAC;AACD,YAAM,KAAK,OAAO,OAAO;AAAA,QACvB,IAAI;AAAA,QACJ,YAAY,KAAK;AAAA,QACjB,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,OAAO,KAAK,QAAQ;AAAA,QACpB,aAAa,MAAM,oBAAoB,WAAW;AAAA,MACpD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,OAA6B;AACjC,UAAM,OAAO,MAAM,KAAK,QAAQ,KAAK,KAAK,iBAAiB,KAAK,QAAQ;AACxE,UAAM,UAAuB,CAAC;AAC9B,eAAW,OAAO,MAAM;AACtB,YAAM,WAAW,MAAM,KAAK,QAAQ;AAAA,QAClC,KAAK;AAAA,QACL,KAAK;AAAA,QACL;AAAA,MACF;AACA,UAAI,CAAC,SAAU;AACf,YAAM,QAAQ,MAAM,KAAK,aAAa,QAAQ;AAC9C,cAAQ,KAAK,KAAK;AAElB,WAAK,WAAW,IAAI,KAAK,KAAK;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,aACJ,KACA,QACA,UAC6B;AAC7B,UAAM,SAAS,MAAM,KAAK,IAAI,GAAW;AACzC,QAAI,CAAC,OAAQ,QAAO;AAGpB,QAAI,OAAO,MAAM,MAAM,OAAW,QAAO,OAAO,MAAM;AAGtD,UAAM,QAAQ,MAAM,QAAQ,QAAQ,IAAK,WAAiC,WAAW,CAAC,QAAkB,IAAI,CAAC;AAC7G,eAAW,MAAM,OAAO;AACtB,UAAI,OAAO,OAAO;AAEhB,cAAM,MAAM,OAAO,OAAO,MAAM,EAAE,CAAC;AACnC,YAAI,QAAQ,OAAW,QAAO;AAAA,MAChC,WAAW,OAAO,EAAE,MAAM,QAAW;AACnC,eAAO,OAAO,EAAE;AAAA,MAClB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ConflictError,
3
3
  PodVersionConflictError
4
- } from "./chunk-ZYUC53LT.js";
4
+ } from "./chunk-U23JUUPX.js";
5
5
 
6
6
  // src/with-pod/pod-store.ts
7
7
  var BUNDLE_STORE_VERSION = 1;
@@ -152,4 +152,4 @@ export {
152
152
  wrapBundleStore,
153
153
  createBundleStore
154
154
  };
155
- //# sourceMappingURL=chunk-AZAOEIKW.js.map
155
+ //# sourceMappingURL=chunk-SW56GSYC.js.map
@@ -2,7 +2,7 @@ import {
2
2
  IllegalTransitionError,
3
3
  RecordLockedError,
4
4
  ValidationError
5
- } from "./chunk-ZYUC53LT.js";
5
+ } from "./chunk-U23JUUPX.js";
6
6
 
7
7
  // src/with-audit/guards/with-guard.ts
8
8
  function withGuard(strategy) {
@@ -120,4 +120,4 @@ export {
120
120
  immutableGuard,
121
121
  transitionGuard
122
122
  };
123
- //# sourceMappingURL=chunk-TA66UMI4.js.map
123
+ //# sourceMappingURL=chunk-T2EGAXPM.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  NOYDB_FORMAT_VERSION
3
- } from "./chunk-5TDJ56JE.js";
3
+ } from "./chunk-LN22XH4B.js";
4
4
 
5
5
  // src/with-party/policy/storage.ts
6
6
  var META_COLLECTION = "_meta";
@@ -39,4 +39,4 @@ export {
39
39
  loadVaultPolicy,
40
40
  saveVaultPolicy
41
41
  };
42
- //# sourceMappingURL=chunk-SM3AVUHC.js.map
42
+ //# sourceMappingURL=chunk-T45LAT2Y.js.map
@@ -6,7 +6,7 @@ import {
6
6
  ConflictError,
7
7
  InvariantError,
8
8
  ValidationError
9
- } from "./chunk-ZYUC53LT.js";
9
+ } from "./chunk-U23JUUPX.js";
10
10
 
11
11
  // src/with-commit/tx/transaction.ts
12
12
  var TxContext = class {
@@ -216,7 +216,7 @@ async function runTransaction(db, fn, options, txInvariants) {
216
216
  db._clearActiveTxContext(ctx);
217
217
  }
218
218
  if (ctx._amendment) {
219
- const { GuardExecutor } = await import("./executor-QZ7BXICW.js");
219
+ const { GuardExecutor } = await import("./executor-DJHNSTIR.js");
220
220
  try {
221
221
  for (const [vaultName, v] of ctx._amendmentVaults) {
222
222
  const registry = v._getGuardRegistry();
@@ -352,4 +352,4 @@ export {
352
352
  runTransaction,
353
353
  revertExecuted
354
354
  };
355
- //# sourceMappingURL=chunk-SKF73JOP.js.map
355
+ //# sourceMappingURL=chunk-T65UZXR6.js.map
@@ -1,16 +1,18 @@
1
1
  import {
2
- encrypt,
3
2
  openEnvelopeJson
4
- } from "./chunk-5O3AOPDT.js";
3
+ } from "./chunk-OVO2RZAE.js";
5
4
  import {
6
5
  NOYDB_FORMAT_VERSION
7
- } from "./chunk-5TDJ56JE.js";
6
+ } from "./chunk-LN22XH4B.js";
7
+ import {
8
+ encrypt
9
+ } from "./chunk-TLJOJBZD.js";
8
10
  import {
9
11
  ConflictError,
10
12
  USER_ENVELOPE_COLLECTION,
11
13
  USER_ENVELOPE_MAX_BYTES,
12
14
  UserEnvelopeOversizedError
13
- } from "./chunk-ZYUC53LT.js";
15
+ } from "./chunk-U23JUUPX.js";
14
16
 
15
17
  // src/with-party/directory/storage.ts
16
18
  var META_COLLECTION = "_meta";
@@ -145,4 +147,4 @@ export {
145
147
  deleteUserEnvelope,
146
148
  listUserEnvelopeIds
147
149
  };
148
- //# sourceMappingURL=chunk-ITNUCOXM.js.map
150
+ //# sourceMappingURL=chunk-TB5RNNJ4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/with-party/directory/storage.ts","../src/with-party/directory/visibility.ts","../src/with-party/directory/user-envelope/storage.ts"],"sourcesContent":["/**\n * Persistence helpers for the vault-level user-directory toggle\n * (`_meta/directory`). Mirrors the bypass-AES pattern used by\n * `_meta/policy` — the directory document is plain JSON, the\n * envelope's `_iv` field is left empty.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { DirectoryConfig } from './types.js'\n\n/** Reserved collection name for vault-level metadata documents. */\nexport const META_COLLECTION = '_meta'\n/** Reserved id for the vault-level directory document. */\nexport const DIRECTORY_RECORD_ID = 'directory'\n\n/**\n * Read the directory toggle from `_meta/directory`. Returns `undefined`\n * when no document has been persisted — callers treat that as the\n * default-on case (`{ enabled: true }`).\n *\n * Tolerates corrupted documents the same way `_meta/policy` does: a\n * JSON parse failure surfaces as `undefined`, not a thrown error, so a\n * bad write never permanently breaks team enumeration.\n */\nexport async function readDirectoryConfig(\n store: NoydbStore,\n vault: string,\n): Promise<DirectoryConfig | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, DIRECTORY_RECORD_ID)\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isDirectoryConfig(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the directory toggle at `_meta/directory`. Idempotent — call\n * on every `db.setDirectoryEnabled()` invocation. Owner-only at the\n * caller site; this primitive does not check roles.\n */\nexport async function persistDirectoryConfig(\n store: NoydbStore,\n vault: string,\n config: DirectoryConfig,\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ enabled: config.enabled }),\n }\n await store.put(vault, META_COLLECTION, DIRECTORY_RECORD_ID, envelope)\n}\n\nfunction isDirectoryConfig(x: unknown): x is DirectoryConfig {\n if (x === null || typeof x !== 'object') return false\n if (!('enabled' in x)) return false\n return typeof (x as { enabled: unknown }).enabled === 'boolean'\n}\n","/**\n * Persistence helpers for the per-user visibility flag\n * (`_meta/visibility/<keyringId>`). Mirrors the bypass-AES pattern used\n * by `_meta/policy` — the visibility document is plain JSON, the\n * envelope's `_iv` field is left empty.\n *\n * Stored alongside the keyring file rather than inside the encrypted\n * user envelope (`_users/<keyringId>`) because:\n *\n * - `UserEnvelope<T>.data` is opaque-to-hub by contract — hub does not\n * introspect or reserve any keys inside it. Adding `hidden` there\n * would violate that contract.\n * - `listUsersWithEnvelopes` filters by the flag, and the filter must\n * work even when decryption fails (legacy keyrings predating the\n * envelope feature, or a corrupted envelope).\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { UserVisibility } from './types.js'\nimport { META_COLLECTION } from './storage.js'\n\n/** Prefix for per-user visibility records inside `_meta`. */\nexport const VISIBILITY_RECORD_PREFIX = 'visibility/'\n\n/** Compose the `_meta` record id for a keyring's visibility doc. */\nexport function visibilityRecordId(keyringId: string): string {\n return VISIBILITY_RECORD_PREFIX + keyringId\n}\n\n/**\n * Read the visibility flag for `keyringId`. Returns `undefined` when no\n * document has been persisted — callers treat that as the default-visible\n * case (`{ hidden: false }`).\n */\nexport async function readUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<UserVisibility | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, visibilityRecordId(keyringId))\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isUserVisibility(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the visibility flag for `keyringId` at\n * `_meta/visibility/<keyringId>`. Idempotent — call on every\n * `vault.user.setMyVisibility()` invocation. Own-only at the caller\n * site; this primitive does not enforce keyring ownership.\n */\nexport async function persistUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n visibility: UserVisibility,\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ hidden: visibility.hidden }),\n }\n await store.put(vault, META_COLLECTION, visibilityRecordId(keyringId), envelope)\n}\n\n/**\n * Delete the visibility flag for `keyringId`. Called from `revoke()`\n * alongside `deleteUserEnvelope` so the sidecar does not leak to a\n * re-granted principal with the same `userId`. Idempotent — the store's\n * `delete()` is already a no-op when the record is absent.\n */\nexport async function deleteUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<void> {\n await store.delete(vault, META_COLLECTION, visibilityRecordId(keyringId))\n}\n\nfunction isUserVisibility(x: unknown): x is UserVisibility {\n if (x === null || typeof x !== 'object') return false\n if (!('hidden' in x)) return false\n return typeof (x as { hidden: unknown }).hidden === 'boolean'\n}\n","/**\n * Persistence helpers for per-principal user envelopes stored at\n * `_users/<keyringId>` (logically: `_meta/user/<keyringId>`).\n *\n * Unlike `_meta/policy` and `_meta/handle` which are plaintext, user\n * envelopes carry user data and are encrypted with a dedicated\n * {@link USER_ENVELOPE_COLLECTION} DEK (provisioned at vault open and\n * propagated to every keyring via the system-collection DEK path in\n * `team/keyring.ts`).\n *\n * This module is the **storage primitive** layer. The public API\n * (`vault.user.*`) sits on top of this; permission gates, own-only\n * write enforcement, and presence-channel propagation live there.\n *\n * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope, UserEnvelope } from '../../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../../kernel/types.js'\nimport { encrypt, openEnvelopeJson, type EnclaveKey } from '../../../kernel/enclave/index.js'\nimport { ConflictError, UserEnvelopeOversizedError } from '../../../kernel/errors.js'\nimport {\n USER_ENVELOPE_COLLECTION,\n USER_ENVELOPE_MAX_BYTES,\n} from '../../../kernel/constants.js'\n\n/**\n * Read and decrypt the user envelope for `keyringId`. Returns `null`\n * when no envelope has been persisted (either the principal has never\n * called `updateMe`, or the keyring predates this feature).\n *\n * Decryption errors propagate — a tampered or wrong-keyed envelope\n * surfaces as the underlying crypto error rather than masquerading as\n * \"not found\".\n */\nexport async function loadUserEnvelope<T = unknown>(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n dek: EnclaveKey,\n): Promise<UserEnvelope<T> | null> {\n const envelope = await store.get(vault, USER_ENVELOPE_COLLECTION, keyringId)\n if (!envelope) return null\n const plaintext = await openEnvelopeJson(envelope, dek)\n const data = JSON.parse(plaintext) as T\n return {\n keyringId,\n data,\n _v: envelope._v,\n _ts: envelope._ts,\n }\n}\n\n/**\n * Encrypt and persist the user envelope for `keyringId`. The new\n * version is `(prior._v ?? 0) + 1`. Pass `expectedVersion` to enable\n * optimistic-concurrency checks: a mismatch with the stored version\n * throws {@link ConflictError} with the actual stored version.\n *\n * `expectedVersion: 0` means \"expect no prior envelope\"; the write\n * succeeds only if no envelope exists yet.\n *\n * Soft-caps the JSON-serialized payload at {@link USER_ENVELOPE_MAX_BYTES};\n * larger payloads throw {@link UserEnvelopeOversizedError}.\n */\nexport async function saveUserEnvelope<T>(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n payload: T,\n dek: EnclaveKey,\n expectedVersion?: number,\n): Promise<UserEnvelope<T>> {\n const json = JSON.stringify(payload)\n // TextEncoder counts bytes correctly for multi-byte UTF-8 (Thai text,\n // emoji, etc.) — JSON.stringify().length would undercount.\n const bytes = new TextEncoder().encode(json).byteLength\n if (bytes > USER_ENVELOPE_MAX_BYTES) {\n throw new UserEnvelopeOversizedError(bytes)\n }\n\n const prior = await store.get(vault, USER_ENVELOPE_COLLECTION, keyringId)\n if (expectedVersion !== undefined) {\n const priorVersion = prior?._v ?? 0\n if (priorVersion !== expectedVersion) {\n throw new ConflictError(\n priorVersion,\n `User envelope for \"${keyringId}\" expected version ${expectedVersion}, ` +\n `actual ${priorVersion}`,\n )\n }\n }\n\n const nextVersion = (prior?._v ?? 0) + 1\n const ts = new Date().toISOString()\n const { iv, data } = await encrypt(json, dek)\n\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: nextVersion,\n _ts: ts,\n _iv: iv,\n _data: data,\n }\n await store.put(vault, USER_ENVELOPE_COLLECTION, keyringId, envelope)\n\n return {\n keyringId,\n data: payload,\n _v: nextVersion,\n _ts: ts,\n }\n}\n\n/**\n * Delete the user envelope for `keyringId`. Idempotent — no error if\n * the envelope is already absent. Called from the keyring revoke path\n * (cascade-delete) and is a no-op for keyrings that never wrote.\n */\nexport async function deleteUserEnvelope(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<void> {\n await store.delete(vault, USER_ENVELOPE_COLLECTION, keyringId)\n}\n\n/**\n * List the keyring ids that have a user envelope persisted in `vault`.\n * Order is store-defined — callers that need a stable order should sort.\n */\nexport async function listUserEnvelopeIds(\n store: NoydbStore,\n vault: string,\n): Promise<string[]> {\n return store.list(vault, USER_ENVELOPE_COLLECTION)\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/with-party/directory/storage.ts","../src/with-party/directory/visibility.ts","../src/with-party/directory/user-envelope/storage.ts"],"sourcesContent":["/**\n * Persistence helpers for the vault-level user-directory toggle\n * (`_meta/directory`). Mirrors the bypass-AES pattern used by\n * `_meta/policy` — the directory document is plain JSON, the\n * envelope's `_iv` field is left empty.\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { DirectoryConfig } from './types.js'\n\n/** Reserved collection name for vault-level metadata documents. */\nexport const META_COLLECTION = '_meta'\n/** Reserved id for the vault-level directory document. */\nexport const DIRECTORY_RECORD_ID = 'directory'\n\n/**\n * Read the directory toggle from `_meta/directory`. Returns `undefined`\n * when no document has been persisted — callers treat that as the\n * default-on case (`{ enabled: true }`).\n *\n * Tolerates corrupted documents the same way `_meta/policy` does: a\n * JSON parse failure surfaces as `undefined`, not a thrown error, so a\n * bad write never permanently breaks team enumeration.\n */\nexport async function readDirectoryConfig(\n store: NoydbStore,\n vault: string,\n): Promise<DirectoryConfig | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, DIRECTORY_RECORD_ID)\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isDirectoryConfig(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the directory toggle at `_meta/directory`. Idempotent — call\n * on every `db.setDirectoryEnabled()` invocation. Owner-only at the\n * caller site; this primitive does not check roles.\n */\nexport async function persistDirectoryConfig(\n store: NoydbStore,\n vault: string,\n config: DirectoryConfig,\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ enabled: config.enabled }),\n }\n await store.put(vault, META_COLLECTION, DIRECTORY_RECORD_ID, envelope)\n}\n\nfunction isDirectoryConfig(x: unknown): x is DirectoryConfig {\n if (x === null || typeof x !== 'object') return false\n if (!('enabled' in x)) return false\n return typeof (x as { enabled: unknown }).enabled === 'boolean'\n}\n","/**\n * Persistence helpers for the per-user visibility flag\n * (`_meta/visibility/<keyringId>`). Mirrors the bypass-AES pattern used\n * by `_meta/policy` — the visibility document is plain JSON, the\n * envelope's `_iv` field is left empty.\n *\n * Stored alongside the keyring file rather than inside the encrypted\n * user envelope (`_users/<keyringId>`) because:\n *\n * - `UserEnvelope<T>.data` is opaque-to-hub by contract — hub does not\n * introspect or reserve any keys inside it. Adding `hidden` there\n * would violate that contract.\n * - `listUsersWithEnvelopes` filters by the flag, and the filter must\n * work even when decryption fails (legacy keyrings predating the\n * envelope feature, or a corrupted envelope).\n *\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/user-envelope.md → Directory visibility\n * @see https://github.com/vLannaAi/noy-db-docs/blob/main/content/docs/services/plaintext-bypass.md — every `_iv: ''` write site\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope } from '../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../kernel/types.js'\nimport type { UserVisibility } from './types.js'\nimport { META_COLLECTION } from './storage.js'\n\n/** Prefix for per-user visibility records inside `_meta`. */\nexport const VISIBILITY_RECORD_PREFIX = 'visibility/'\n\n/** Compose the `_meta` record id for a keyring's visibility doc. */\nexport function visibilityRecordId(keyringId: string): string {\n return VISIBILITY_RECORD_PREFIX + keyringId\n}\n\n/**\n * Read the visibility flag for `keyringId`. Returns `undefined` when no\n * document has been persisted — callers treat that as the default-visible\n * case (`{ hidden: false }`).\n */\nexport async function readUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<UserVisibility | undefined> {\n const envelope = await store.get(vault, META_COLLECTION, visibilityRecordId(keyringId))\n if (!envelope) return undefined\n try {\n const parsed = JSON.parse(envelope._data) as unknown\n if (!isUserVisibility(parsed)) return undefined\n return parsed\n } catch {\n return undefined\n }\n}\n\n/**\n * Persist the visibility flag for `keyringId` at\n * `_meta/visibility/<keyringId>`. Idempotent — call on every\n * `vault.user.setMyVisibility()` invocation. Own-only at the caller\n * site; this primitive does not enforce keyring ownership.\n */\nexport async function persistUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n visibility: UserVisibility,\n): Promise<void> {\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: 1,\n _ts: new Date().toISOString(),\n _iv: '',\n _data: JSON.stringify({ hidden: visibility.hidden }),\n }\n await store.put(vault, META_COLLECTION, visibilityRecordId(keyringId), envelope)\n}\n\n/**\n * Delete the visibility flag for `keyringId`. Called from `revoke()`\n * alongside `deleteUserEnvelope` so the sidecar does not leak to a\n * re-granted principal with the same `userId`. Idempotent — the store's\n * `delete()` is already a no-op when the record is absent.\n */\nexport async function deleteUserVisibility(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<void> {\n await store.delete(vault, META_COLLECTION, visibilityRecordId(keyringId))\n}\n\nfunction isUserVisibility(x: unknown): x is UserVisibility {\n if (x === null || typeof x !== 'object') return false\n if (!('hidden' in x)) return false\n return typeof (x as { hidden: unknown }).hidden === 'boolean'\n}\n","/**\n * Persistence helpers for per-principal user envelopes stored at\n * `_users/<keyringId>` (logically: `_meta/user/<keyringId>`).\n *\n * Unlike `_meta/policy` and `_meta/handle` which are plaintext, user\n * envelopes carry user data and are encrypted with a dedicated\n * {@link USER_ENVELOPE_COLLECTION} DEK (provisioned at vault open and\n * propagated to every keyring via the system-collection DEK path in\n * `team/keyring.ts`).\n *\n * This module is the **storage primitive** layer. The public API\n * (`vault.user.*`) sits on top of this; permission gates, own-only\n * write enforcement, and presence-channel propagation live there.\n *\n * @see docs/superpowers/specs/2026-05-05-user-envelope-design.md\n *\n * @module\n */\nimport type { NoydbStore, EncryptedEnvelope, UserEnvelope } from '../../../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../../../kernel/types.js'\nimport { encrypt, openEnvelopeJson, type EnclaveKey } from '../../../kernel/enclave/index.js'\nimport { ConflictError, UserEnvelopeOversizedError } from '../../../kernel/errors.js'\nimport {\n USER_ENVELOPE_COLLECTION,\n USER_ENVELOPE_MAX_BYTES,\n} from '../../../kernel/constants.js'\n\n/**\n * Read and decrypt the user envelope for `keyringId`. Returns `null`\n * when no envelope has been persisted (either the principal has never\n * called `updateMe`, or the keyring predates this feature).\n *\n * Decryption errors propagate — a tampered or wrong-keyed envelope\n * surfaces as the underlying crypto error rather than masquerading as\n * \"not found\".\n */\nexport async function loadUserEnvelope<T = unknown>(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n dek: EnclaveKey,\n): Promise<UserEnvelope<T> | null> {\n const envelope = await store.get(vault, USER_ENVELOPE_COLLECTION, keyringId)\n if (!envelope) return null\n const plaintext = await openEnvelopeJson(envelope, dek)\n const data = JSON.parse(plaintext) as T\n return {\n keyringId,\n data,\n _v: envelope._v,\n _ts: envelope._ts,\n }\n}\n\n/**\n * Encrypt and persist the user envelope for `keyringId`. The new\n * version is `(prior._v ?? 0) + 1`. Pass `expectedVersion` to enable\n * optimistic-concurrency checks: a mismatch with the stored version\n * throws {@link ConflictError} with the actual stored version.\n *\n * `expectedVersion: 0` means \"expect no prior envelope\"; the write\n * succeeds only if no envelope exists yet.\n *\n * Soft-caps the JSON-serialized payload at {@link USER_ENVELOPE_MAX_BYTES};\n * larger payloads throw {@link UserEnvelopeOversizedError}.\n */\nexport async function saveUserEnvelope<T>(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n payload: T,\n dek: EnclaveKey,\n expectedVersion?: number,\n): Promise<UserEnvelope<T>> {\n const json = JSON.stringify(payload)\n // TextEncoder counts bytes correctly for multi-byte UTF-8 (Thai text,\n // emoji, etc.) — JSON.stringify().length would undercount.\n const bytes = new TextEncoder().encode(json).byteLength\n if (bytes > USER_ENVELOPE_MAX_BYTES) {\n throw new UserEnvelopeOversizedError(bytes)\n }\n\n const prior = await store.get(vault, USER_ENVELOPE_COLLECTION, keyringId)\n if (expectedVersion !== undefined) {\n const priorVersion = prior?._v ?? 0\n if (priorVersion !== expectedVersion) {\n throw new ConflictError(\n priorVersion,\n `User envelope for \"${keyringId}\" expected version ${expectedVersion}, ` +\n `actual ${priorVersion}`,\n )\n }\n }\n\n const nextVersion = (prior?._v ?? 0) + 1\n const ts = new Date().toISOString()\n const { iv, data } = await encrypt(json, dek)\n\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: nextVersion,\n _ts: ts,\n _iv: iv,\n _data: data,\n }\n await store.put(vault, USER_ENVELOPE_COLLECTION, keyringId, envelope)\n\n return {\n keyringId,\n data: payload,\n _v: nextVersion,\n _ts: ts,\n }\n}\n\n/**\n * Delete the user envelope for `keyringId`. Idempotent — no error if\n * the envelope is already absent. Called from the keyring revoke path\n * (cascade-delete) and is a no-op for keyrings that never wrote.\n */\nexport async function deleteUserEnvelope(\n store: NoydbStore,\n vault: string,\n keyringId: string,\n): Promise<void> {\n await store.delete(vault, USER_ENVELOPE_COLLECTION, keyringId)\n}\n\n/**\n * List the keyring ids that have a user envelope persisted in `vault`.\n * Order is store-defined — callers that need a stable order should sort.\n */\nexport async function listUserEnvelopeIds(\n store: NoydbStore,\n vault: string,\n): Promise<string[]> {\n return store.list(vault, USER_ENVELOPE_COLLECTION)\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,29 @@
1
+ import {
2
+ decrypt,
3
+ deriveSealedFieldKey,
4
+ deriveSealedFieldKeyFromCek
5
+ } from "./chunk-TLJOJBZD.js";
6
+
7
+ // src/kernel/enclave/record-keys/sealed-slot.ts
8
+ function parseSealedSlot(blob) {
9
+ const sep = blob.indexOf(":");
10
+ return { iv: blob.slice(0, sep), data: blob.slice(sep + 1) };
11
+ }
12
+ async function dualReadSealedSlot(blob, field, collection, cek, dek) {
13
+ const { iv, data } = parseSealedSlot(blob);
14
+ if (cek !== void 0) {
15
+ try {
16
+ const fieldKey2 = await deriveSealedFieldKeyFromCek(cek, collection, field);
17
+ return await decrypt(iv, data, fieldKey2);
18
+ } catch {
19
+ }
20
+ }
21
+ const fieldKey = await deriveSealedFieldKey(dek, collection, field);
22
+ return decrypt(iv, data, fieldKey);
23
+ }
24
+
25
+ export {
26
+ parseSealedSlot,
27
+ dualReadSealedSlot
28
+ };
29
+ //# sourceMappingURL=chunk-TCIUO62Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kernel/enclave/record-keys/sealed-slot.ts"],"sourcesContent":["/**\n * Sealed-slot (`iv:data`) parsing + the CEK/DEK dual-read, factored out so the\n * three callers that decrypt a `_sealed[field]` slot share ONE implementation\n * with no coupling between them:\n *\n * - {@link RecordCodec.unsealField} / `classifySealedShred` (read + classify),\n * - `record-keys/sealing.ts:rotateRecordCek` (re-seal under a new CEK).\n *\n * These are pure helpers over an explicit `(cek, dek)` pair — NOT a context\n * object — so `sealing.ts` (which holds only the DEK) can import them without\n * pulling in the whole codec, avoiding a codec↔sealing dependency cycle.\n */\nimport { decrypt, deriveSealedFieldKey, deriveSealedFieldKeyFromCek } from '../crypto.js'\n\n/** Parse an `iv:data` sealed slot (split on the FIRST `:`). */\nexport function parseSealedSlot(blob: string): { iv: string; data: string } {\n const sep = blob.indexOf(':')\n return { iv: blob.slice(0, sep), data: blob.slice(sep + 1) }\n}\n\n/**\n * Dual-read: decrypt a sealed slot trying the CEK-derived field key first,\n * falling back to the collection-DEK field key. Legacy records\n * (even ones whose body is CEK-encrypted) are sealed under the collection-DEK\n * key; current writes seal under the per-record CEK. Try the CEK key first; on\n * its AES-GCM auth failure, fall back to the DEK key. Throws only if BOTH fail.\n * Returns the plaintext string (callers `JSON.parse` as needed).\n */\nexport async function dualReadSealedSlot(\n blob: string,\n field: string,\n collection: string,\n cek: CryptoKey | undefined,\n dek: CryptoKey,\n): Promise<string> {\n const { iv, data } = parseSealedSlot(blob)\n if (cek !== undefined) {\n try {\n const fieldKey = await deriveSealedFieldKeyFromCek(cek, collection, field)\n return await decrypt(iv, data, fieldKey)\n } catch {\n // fall through to the legacy collection-DEK derivation\n }\n }\n const fieldKey = await deriveSealedFieldKey(dek, collection, field)\n return decrypt(iv, data, fieldKey)\n}\n"],"mappings":";;;;;;;AAeO,SAAS,gBAAgB,MAA4C;AAC1E,QAAM,MAAM,KAAK,QAAQ,GAAG;AAC5B,SAAO,EAAE,IAAI,KAAK,MAAM,GAAG,GAAG,GAAG,MAAM,KAAK,MAAM,MAAM,CAAC,EAAE;AAC7D;AAUA,eAAsB,mBACpB,MACA,OACA,YACA,KACA,KACiB;AACjB,QAAM,EAAE,IAAI,KAAK,IAAI,gBAAgB,IAAI;AACzC,MAAI,QAAQ,QAAW;AACrB,QAAI;AACF,YAAMA,YAAW,MAAM,4BAA4B,KAAK,YAAY,KAAK;AACzE,aAAO,MAAM,QAAQ,IAAI,MAAMA,SAAQ;AAAA,IACzC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,QAAM,WAAW,MAAM,qBAAqB,KAAK,YAAY,KAAK;AAClE,SAAO,QAAQ,IAAI,MAAM,QAAQ;AACnC;","names":["fieldKey"]}
@@ -0,0 +1,17 @@
1
+ import {
2
+ buildLazyCache
3
+ } from "./chunk-NO272T7Q.js";
4
+
5
+ // src/with-store/lazy/active.ts
6
+ function withLazy() {
7
+ return {
8
+ createCache(collection, cache) {
9
+ return buildLazyCache(collection, cache);
10
+ }
11
+ };
12
+ }
13
+
14
+ export {
15
+ withLazy
16
+ };
17
+ //# sourceMappingURL=chunk-THNJ3IKU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/with-store/lazy/active.ts"],"sourcesContent":["/**\n * Enable the lazy service (#267 Track A tail — lazy-mode promoted out of\n * `routing` into its own opt-in service).\n *\n * Pass to `createNoydb({ lazyStrategy: withLazy() })` to explicitly opt\n * into lazy mode's bounded-LRU working set for collections declared with\n * `prefetch: false` + a `cache` budget. Behavior is identical to the\n * deprecated implicit path (which warns once and will be removed at 1.0) —\n * opting in is the forward-stable spelling and the catalog's contract.\n */\nimport type { LazyStrategy } from './strategy.js'\nimport { buildLazyCache } from './strategy.js'\n\nexport function withLazy(): LazyStrategy {\n return {\n createCache(collection, cache) {\n return buildLazyCache(collection, cache)\n },\n }\n}\n"],"mappings":";;;;;AAaO,SAAS,WAAyB;AACvC,SAAO;AAAA,IACL,YAAY,YAAY,OAAO;AAC7B,aAAO,eAAe,YAAY,KAAK;AAAA,IACzC;AAAA,EACF;AACF;","names":[]}