@noy-db/hub 0.4.0-pre.9 → 0.4.0

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 (243) hide show
  1. package/dist/{api-3NKVNZPM.js → api-SI2IVBQO.js} +6 -6
  2. package/dist/attestation/index.js +12 -12
  3. package/dist/{backup-PTSVXDDW.js → backup-X7F3TCFV.js} +6 -6
  4. package/dist/blobs/index.js +5 -5
  5. package/dist/broker/index.js +6 -6
  6. package/dist/cargo/index.js +20 -20
  7. package/dist/{chunk-WZ3NCMK6.js → chunk-2BET5QTS.js} +3 -3
  8. package/dist/{chunk-Y6B6HVKC.js → chunk-2J6UEN2V.js} +41 -17
  9. package/dist/chunk-2J6UEN2V.js.map +1 -0
  10. package/dist/{chunk-BYFXLDVV.js → chunk-3ECU57YH.js} +7 -7
  11. package/dist/{chunk-ZWBKDKXC.js → chunk-467SWYT5.js} +2 -2
  12. package/dist/{chunk-MTJLOC3Y.js → chunk-55LKVALY.js} +106 -10
  13. package/dist/chunk-55LKVALY.js.map +1 -0
  14. package/dist/{chunk-XIDQKFZF.js → chunk-5UQ7Y6SQ.js} +2 -2
  15. package/dist/{chunk-GZACYEOB.js → chunk-77AEMXFA.js} +1 -1
  16. package/dist/chunk-77AEMXFA.js.map +1 -0
  17. package/dist/{chunk-IMRB2C4O.js → chunk-7H3WWH6J.js} +3 -3
  18. package/dist/{chunk-OLIWCCFM.js → chunk-CLE3TMIS.js} +2 -2
  19. package/dist/{chunk-ZFUFAHZ3.js → chunk-DAFBJS4Y.js} +2 -2
  20. package/dist/{chunk-ISRKW4YN.js → chunk-DQZXPGGZ.js} +2 -2
  21. package/dist/{chunk-FMNU7IUG.js → chunk-DTFA5DO4.js} +2 -2
  22. package/dist/{chunk-VH6SOCXH.js → chunk-EFJAAFBW.js} +2 -2
  23. package/dist/{chunk-TIVK6PRK.js → chunk-ERGECZEI.js} +5 -5
  24. package/dist/{chunk-NGSJZFGL.js → chunk-GTYFIVIZ.js} +83 -21
  25. package/dist/chunk-GTYFIVIZ.js.map +1 -0
  26. package/dist/{chunk-KW42W6SV.js → chunk-HLKXPJ4V.js} +4 -4
  27. package/dist/{chunk-MANUDU7I.js → chunk-HZZP2ZIG.js} +4 -4
  28. package/dist/{chunk-DZAF24PG.js → chunk-IFOH7RBI.js} +3 -3
  29. package/dist/{chunk-FRMW23UK.js → chunk-IVYQAVWO.js} +2 -2
  30. package/dist/{chunk-SGQ4N5FS.js → chunk-JEI6JJNI.js} +3 -3
  31. package/dist/{chunk-BN4HRYAZ.js → chunk-JQ2AX4T5.js} +2 -2
  32. package/dist/{chunk-OBPVWOSQ.js → chunk-KD4HGBJV.js} +3 -3
  33. package/dist/{chunk-QADFHRQM.js → chunk-KYRDJI5O.js} +8 -8
  34. package/dist/{chunk-2NMEGSFV.js → chunk-LLYIMSQQ.js} +9 -9
  35. package/dist/{chunk-GP3UWP22.js → chunk-LRRX57UA.js} +2 -2
  36. package/dist/{chunk-OLSARBZU.js → chunk-LXRTP3AQ.js} +2 -2
  37. package/dist/{chunk-EBKCYQ2D.js → chunk-NBXFCQX4.js} +3 -3
  38. package/dist/{chunk-BXHMZ2XW.js → chunk-NLYALJMY.js} +24 -14
  39. package/dist/chunk-NLYALJMY.js.map +1 -0
  40. package/dist/{chunk-EZNTORXE.js → chunk-NM5UYF6Q.js} +1 -1
  41. package/dist/chunk-NM5UYF6Q.js.map +1 -0
  42. package/dist/{chunk-NEX7JCMO.js → chunk-OWHP3H5C.js} +3 -3
  43. package/dist/{chunk-WO4T4OD5.js → chunk-P4JO3H6R.js} +2 -2
  44. package/dist/{chunk-CCDP6EPB.js → chunk-PWPYO73B.js} +2 -2
  45. package/dist/{chunk-56IIVAEO.js → chunk-Q2SEJMP2.js} +2 -2
  46. package/dist/{chunk-JIDLU57U.js → chunk-Q36YXK77.js} +2 -2
  47. package/dist/{chunk-KPXM4WO6.js → chunk-Q5YJCVJY.js} +3 -3
  48. package/dist/{chunk-JYV4JJV2.js → chunk-QGIBI6GL.js} +4 -4
  49. package/dist/{chunk-DGBIHDVK.js → chunk-RBTVFPHF.js} +3 -3
  50. package/dist/{chunk-6R6Q3MRN.js → chunk-RQ4ZI4ZI.js} +4 -4
  51. package/dist/{chunk-FO6RNKKW.js → chunk-S7GIXBXV.js} +2 -2
  52. package/dist/chunk-SBHN6QUT.js +25 -0
  53. package/dist/chunk-SBHN6QUT.js.map +1 -0
  54. package/dist/{chunk-3XKESW5E.js → chunk-SF2ZIRD6.js} +2 -2
  55. package/dist/{chunk-TE6LH6J2.js → chunk-SFBYQMZM.js} +3 -3
  56. package/dist/{chunk-RZPOZPZU.js → chunk-SU6SGWXM.js} +3 -3
  57. package/dist/{chunk-6L3DKWRY.js → chunk-T2MOJF76.js} +2 -2
  58. package/dist/{chunk-SKM35Y4Q.js → chunk-TS5XLBZR.js} +3 -3
  59. package/dist/{chunk-HFUAFR6B.js → chunk-TWPK7KUJ.js} +3 -3
  60. package/dist/{chunk-6M2I3DKF.js → chunk-WK7ULBTP.js} +2 -2
  61. package/dist/{chunk-IF6WNGAK.js → chunk-WUHEP3HH.js} +2 -2
  62. package/dist/{chunk-NQSO4UAH.js → chunk-WYUAEZSC.js} +3 -3
  63. package/dist/{chunk-Y6VZQGGH.js → chunk-YGK2HMLR.js} +4 -4
  64. package/dist/{chunk-OW5Y6HA6.js → chunk-ZBYFMI6D.js} +223 -119
  65. package/dist/chunk-ZBYFMI6D.js.map +1 -0
  66. package/dist/{chunk-N5PLUFH2.js → chunk-ZFG5EBI3.js} +4 -4
  67. package/dist/{chunk-KFRPNHWR.js → chunk-ZHDSUZQU.js} +3 -3
  68. package/dist/{chunk-C25JXSOR.js → chunk-ZNWSG7XC.js} +5 -5
  69. package/dist/classified/index.js +3 -3
  70. package/dist/{classified-marker-EOOSMWFC.js → classified-marker-LE54HWSX.js} +3 -3
  71. package/dist/{collection-facade-TTRF5NFJ.js → collection-facade-DO2AABZT.js} +8 -8
  72. package/dist/consent/index.js +4 -4
  73. package/dist/cover/index.js +2 -2
  74. package/dist/custody/index.js +6 -6
  75. package/dist/{dead-filter-6DYY7S64.js → dead-filter-V3LVWYEJ.js} +2 -2
  76. package/dist/debug/index.js +29 -0
  77. package/dist/debug/index.js.map +1 -0
  78. package/dist/{delegation-ONOZVPIP.js → delegation-JDUMAF6L.js} +4 -4
  79. package/dist/derivations/index.js +3 -3
  80. package/dist/{derive-IGGVSUPH.js → derive-ZPGVLE2Q.js} +4 -4
  81. package/dist/directory/index.js +5 -5
  82. package/dist/{dispatch-RPTLK7LJ.js → dispatch-6TV3DGO6.js} +5 -5
  83. package/dist/{dispatch-7T45NN7C.js → dispatch-W7NWQ637.js} +9 -9
  84. package/dist/{enclave-CLJVSDFG.js → enclave-YFCLPIDR.js} +4 -4
  85. package/dist/{executor-XZYM4KHT.js → executor-FPHKWDWT.js} +8 -8
  86. package/dist/{export-accessible-24XCCD3A.js → export-accessible-EKM3HGB2.js} +7 -7
  87. package/dist/{extract-partition-H2TPEEOF.js → extract-partition-LS4ET5A6.js} +10 -10
  88. package/dist/{fanout-sidecar-TV7CXAJ6.js → fanout-sidecar-273RDMYS.js} +4 -4
  89. package/dist/forget/index.js +4 -4
  90. package/dist/history/index.js +6 -6
  91. package/dist/i18n/index.js +6 -6
  92. package/dist/index.d.ts +7 -7
  93. package/dist/index.js +148 -96
  94. package/dist/index.js.map +1 -1
  95. package/dist/introspection/index.js +5 -5
  96. package/dist/{issue-55HJE7JF.js → issue-LIA7FXBJ.js} +6 -6
  97. package/dist/kernel/collection.d.ts +89 -2
  98. package/dist/kernel/debug.d.ts +11 -0
  99. package/dist/kernel/noydb.d.ts +3 -3
  100. package/dist/kernel/prepared-write.d.ts +70 -0
  101. package/dist/kernel/sync-policy.d.ts +75 -3
  102. package/dist/kernel/types.d.ts +27 -8
  103. package/dist/{ledger-XY6NP3J2.js → ledger-XE7JF2I2.js} +6 -6
  104. package/dist/liberate-WZ3RHVKW.js +24 -0
  105. package/dist/{link-set-POQB7BU5.js → link-set-CGYC3OH5.js} +5 -5
  106. package/dist/materialized-views/index.js +13 -13
  107. package/dist/{noydb-MGPOYDOD.js → noydb-ZLPVCDES.js} +30 -31
  108. package/dist/periods/index.js +8 -8
  109. package/dist/pod/index.js +6 -6
  110. package/dist/policy/index.js +3 -3
  111. package/dist/port/with/strategies.d.ts +1 -1
  112. package/dist/portability/index.js +6 -6
  113. package/dist/{post-register-URQANI3B.js → post-register-LY35EDTJ.js} +4 -4
  114. package/dist/{register-5W6CG4RM.js → register-6RIBIT3I.js} +6 -6
  115. package/dist/{registry-UJFP3NWF.js → registry-MUSL4AW6.js} +4 -4
  116. package/dist/{registry-MCSGBZXI.js → registry-RON4WHAP.js} +4 -4
  117. package/dist/{request-withdrawal-IWYDM4SO.js → request-withdrawal-FT3ORAWN.js} +9 -9
  118. package/dist/{reveal-BXZGWIOP.js → reveal-T34ADTPY.js} +3 -3
  119. package/dist/{revoke-TINYPHYY.js → revoke-HC7WG3HE.js} +6 -6
  120. package/dist/sealed-record/index.js +6 -6
  121. package/dist/search/index.js +1 -1
  122. package/dist/{seed-F7YYQTRC.js → seed-JOV54PB3.js} +6 -6
  123. package/dist/seed-JOV54PB3.js.map +1 -0
  124. package/dist/sequence/index.js +4 -4
  125. package/dist/session/index.js +3 -3
  126. package/dist/{signer-WMZKCNKC.js → signer-CTWOH6KT.js} +5 -5
  127. package/dist/snapshots/index.js +5 -5
  128. package/dist/{stale-JOE7GBAE.js → stale-T3V7XEOB.js} +5 -5
  129. package/dist/{storage-B3WBKXKT.js → storage-LLNLPWWB.js} +5 -5
  130. package/dist/{store-coordination-provider-5LX2UFU2.js → store-coordination-provider-AHGFEMFA.js} +3 -3
  131. package/dist/sync/index.js +9 -10
  132. package/dist/sync/index.js.map +1 -1
  133. package/dist/team/index.js +8 -30
  134. package/dist/tiers/index.js +4 -4
  135. package/dist/transactions/index.js +1 -1
  136. package/dist/{walk-6OHAWGBS.js → walk-G3NFEP5L.js} +6 -6
  137. package/dist/with-commit/tx/atomic-eligibility.d.ts +47 -0
  138. package/dist/with-commit/tx/transaction.d.ts +22 -9
  139. package/dist/with-party/broker/seed.d.ts +1 -1
  140. package/dist/with-party/team/index.d.ts +0 -5
  141. package/dist/{with-party/team/sync-active.d.ts → with-sync/active.d.ts} +1 -1
  142. package/dist/{with-party/team/sync-credentials.d.ts → with-sync/credentials.d.ts} +3 -3
  143. package/dist/{with-party/team/sync.d.ts → with-sync/engine.d.ts} +5 -5
  144. package/dist/{with-party/sync → with-sync}/index.d.ts +3 -3
  145. package/dist/{with-party/team/sync-period-scope.d.ts → with-sync/period-scope.d.ts} +2 -2
  146. package/dist/{with-party/team → with-sync}/presence.d.ts +2 -2
  147. package/dist/{with-party/team/sync-strategy.d.ts → with-sync/strategy.d.ts} +6 -6
  148. package/dist/{with-party/team/sync-transaction.d.ts → with-sync/transaction.d.ts} +3 -3
  149. package/dist/{withdraw-accessible-DEUCOO4F.js → withdraw-accessible-ANSVG6XG.js} +8 -8
  150. package/package.json +8 -4
  151. package/dist/chunk-BXHMZ2XW.js.map +0 -1
  152. package/dist/chunk-EP5L47XV.js +0 -22
  153. package/dist/chunk-EP5L47XV.js.map +0 -1
  154. package/dist/chunk-EZNTORXE.js.map +0 -1
  155. package/dist/chunk-GZACYEOB.js.map +0 -1
  156. package/dist/chunk-MTJLOC3Y.js.map +0 -1
  157. package/dist/chunk-NGSJZFGL.js.map +0 -1
  158. package/dist/chunk-OW5Y6HA6.js.map +0 -1
  159. package/dist/chunk-SHYIA73K.js +0 -99
  160. package/dist/chunk-SHYIA73K.js.map +0 -1
  161. package/dist/chunk-Y6B6HVKC.js.map +0 -1
  162. package/dist/liberate-LXOJ2EMB.js +0 -24
  163. package/dist/seed-F7YYQTRC.js.map +0 -1
  164. /package/dist/{api-3NKVNZPM.js.map → api-SI2IVBQO.js.map} +0 -0
  165. /package/dist/{backup-PTSVXDDW.js.map → backup-X7F3TCFV.js.map} +0 -0
  166. /package/dist/{chunk-WZ3NCMK6.js.map → chunk-2BET5QTS.js.map} +0 -0
  167. /package/dist/{chunk-BYFXLDVV.js.map → chunk-3ECU57YH.js.map} +0 -0
  168. /package/dist/{chunk-ZWBKDKXC.js.map → chunk-467SWYT5.js.map} +0 -0
  169. /package/dist/{chunk-XIDQKFZF.js.map → chunk-5UQ7Y6SQ.js.map} +0 -0
  170. /package/dist/{chunk-IMRB2C4O.js.map → chunk-7H3WWH6J.js.map} +0 -0
  171. /package/dist/{chunk-OLIWCCFM.js.map → chunk-CLE3TMIS.js.map} +0 -0
  172. /package/dist/{chunk-ZFUFAHZ3.js.map → chunk-DAFBJS4Y.js.map} +0 -0
  173. /package/dist/{chunk-ISRKW4YN.js.map → chunk-DQZXPGGZ.js.map} +0 -0
  174. /package/dist/{chunk-FMNU7IUG.js.map → chunk-DTFA5DO4.js.map} +0 -0
  175. /package/dist/{chunk-VH6SOCXH.js.map → chunk-EFJAAFBW.js.map} +0 -0
  176. /package/dist/{chunk-TIVK6PRK.js.map → chunk-ERGECZEI.js.map} +0 -0
  177. /package/dist/{chunk-KW42W6SV.js.map → chunk-HLKXPJ4V.js.map} +0 -0
  178. /package/dist/{chunk-MANUDU7I.js.map → chunk-HZZP2ZIG.js.map} +0 -0
  179. /package/dist/{chunk-DZAF24PG.js.map → chunk-IFOH7RBI.js.map} +0 -0
  180. /package/dist/{chunk-FRMW23UK.js.map → chunk-IVYQAVWO.js.map} +0 -0
  181. /package/dist/{chunk-SGQ4N5FS.js.map → chunk-JEI6JJNI.js.map} +0 -0
  182. /package/dist/{chunk-BN4HRYAZ.js.map → chunk-JQ2AX4T5.js.map} +0 -0
  183. /package/dist/{chunk-OBPVWOSQ.js.map → chunk-KD4HGBJV.js.map} +0 -0
  184. /package/dist/{chunk-QADFHRQM.js.map → chunk-KYRDJI5O.js.map} +0 -0
  185. /package/dist/{chunk-2NMEGSFV.js.map → chunk-LLYIMSQQ.js.map} +0 -0
  186. /package/dist/{chunk-GP3UWP22.js.map → chunk-LRRX57UA.js.map} +0 -0
  187. /package/dist/{chunk-OLSARBZU.js.map → chunk-LXRTP3AQ.js.map} +0 -0
  188. /package/dist/{chunk-EBKCYQ2D.js.map → chunk-NBXFCQX4.js.map} +0 -0
  189. /package/dist/{chunk-NEX7JCMO.js.map → chunk-OWHP3H5C.js.map} +0 -0
  190. /package/dist/{chunk-WO4T4OD5.js.map → chunk-P4JO3H6R.js.map} +0 -0
  191. /package/dist/{chunk-CCDP6EPB.js.map → chunk-PWPYO73B.js.map} +0 -0
  192. /package/dist/{chunk-56IIVAEO.js.map → chunk-Q2SEJMP2.js.map} +0 -0
  193. /package/dist/{chunk-JIDLU57U.js.map → chunk-Q36YXK77.js.map} +0 -0
  194. /package/dist/{chunk-KPXM4WO6.js.map → chunk-Q5YJCVJY.js.map} +0 -0
  195. /package/dist/{chunk-JYV4JJV2.js.map → chunk-QGIBI6GL.js.map} +0 -0
  196. /package/dist/{chunk-DGBIHDVK.js.map → chunk-RBTVFPHF.js.map} +0 -0
  197. /package/dist/{chunk-6R6Q3MRN.js.map → chunk-RQ4ZI4ZI.js.map} +0 -0
  198. /package/dist/{chunk-FO6RNKKW.js.map → chunk-S7GIXBXV.js.map} +0 -0
  199. /package/dist/{chunk-3XKESW5E.js.map → chunk-SF2ZIRD6.js.map} +0 -0
  200. /package/dist/{chunk-TE6LH6J2.js.map → chunk-SFBYQMZM.js.map} +0 -0
  201. /package/dist/{chunk-RZPOZPZU.js.map → chunk-SU6SGWXM.js.map} +0 -0
  202. /package/dist/{chunk-6L3DKWRY.js.map → chunk-T2MOJF76.js.map} +0 -0
  203. /package/dist/{chunk-SKM35Y4Q.js.map → chunk-TS5XLBZR.js.map} +0 -0
  204. /package/dist/{chunk-HFUAFR6B.js.map → chunk-TWPK7KUJ.js.map} +0 -0
  205. /package/dist/{chunk-6M2I3DKF.js.map → chunk-WK7ULBTP.js.map} +0 -0
  206. /package/dist/{chunk-IF6WNGAK.js.map → chunk-WUHEP3HH.js.map} +0 -0
  207. /package/dist/{chunk-NQSO4UAH.js.map → chunk-WYUAEZSC.js.map} +0 -0
  208. /package/dist/{chunk-Y6VZQGGH.js.map → chunk-YGK2HMLR.js.map} +0 -0
  209. /package/dist/{chunk-N5PLUFH2.js.map → chunk-ZFG5EBI3.js.map} +0 -0
  210. /package/dist/{chunk-KFRPNHWR.js.map → chunk-ZHDSUZQU.js.map} +0 -0
  211. /package/dist/{chunk-C25JXSOR.js.map → chunk-ZNWSG7XC.js.map} +0 -0
  212. /package/dist/{classified-marker-EOOSMWFC.js.map → classified-marker-LE54HWSX.js.map} +0 -0
  213. /package/dist/{collection-facade-TTRF5NFJ.js.map → collection-facade-DO2AABZT.js.map} +0 -0
  214. /package/dist/{dead-filter-6DYY7S64.js.map → dead-filter-V3LVWYEJ.js.map} +0 -0
  215. /package/dist/{delegation-ONOZVPIP.js.map → delegation-JDUMAF6L.js.map} +0 -0
  216. /package/dist/{derive-IGGVSUPH.js.map → derive-ZPGVLE2Q.js.map} +0 -0
  217. /package/dist/{dispatch-RPTLK7LJ.js.map → dispatch-6TV3DGO6.js.map} +0 -0
  218. /package/dist/{dispatch-7T45NN7C.js.map → dispatch-W7NWQ637.js.map} +0 -0
  219. /package/dist/{enclave-CLJVSDFG.js.map → enclave-YFCLPIDR.js.map} +0 -0
  220. /package/dist/{executor-XZYM4KHT.js.map → executor-FPHKWDWT.js.map} +0 -0
  221. /package/dist/{export-accessible-24XCCD3A.js.map → export-accessible-EKM3HGB2.js.map} +0 -0
  222. /package/dist/{extract-partition-H2TPEEOF.js.map → extract-partition-LS4ET5A6.js.map} +0 -0
  223. /package/dist/{fanout-sidecar-TV7CXAJ6.js.map → fanout-sidecar-273RDMYS.js.map} +0 -0
  224. /package/dist/{issue-55HJE7JF.js.map → issue-LIA7FXBJ.js.map} +0 -0
  225. /package/dist/{ledger-XY6NP3J2.js.map → ledger-XE7JF2I2.js.map} +0 -0
  226. /package/dist/{liberate-LXOJ2EMB.js.map → liberate-WZ3RHVKW.js.map} +0 -0
  227. /package/dist/{link-set-POQB7BU5.js.map → link-set-CGYC3OH5.js.map} +0 -0
  228. /package/dist/{noydb-MGPOYDOD.js.map → noydb-ZLPVCDES.js.map} +0 -0
  229. /package/dist/{post-register-URQANI3B.js.map → post-register-LY35EDTJ.js.map} +0 -0
  230. /package/dist/{register-5W6CG4RM.js.map → register-6RIBIT3I.js.map} +0 -0
  231. /package/dist/{registry-MCSGBZXI.js.map → registry-MUSL4AW6.js.map} +0 -0
  232. /package/dist/{registry-UJFP3NWF.js.map → registry-RON4WHAP.js.map} +0 -0
  233. /package/dist/{request-withdrawal-IWYDM4SO.js.map → request-withdrawal-FT3ORAWN.js.map} +0 -0
  234. /package/dist/{reveal-BXZGWIOP.js.map → reveal-T34ADTPY.js.map} +0 -0
  235. /package/dist/{revoke-TINYPHYY.js.map → revoke-HC7WG3HE.js.map} +0 -0
  236. /package/dist/{signer-WMZKCNKC.js.map → signer-CTWOH6KT.js.map} +0 -0
  237. /package/dist/{stale-JOE7GBAE.js.map → stale-T3V7XEOB.js.map} +0 -0
  238. /package/dist/{storage-B3WBKXKT.js.map → storage-LLNLPWWB.js.map} +0 -0
  239. /package/dist/{store-coordination-provider-5LX2UFU2.js.map → store-coordination-provider-AHGFEMFA.js.map} +0 -0
  240. /package/dist/{walk-6OHAWGBS.js.map → walk-G3NFEP5L.js.map} +0 -0
  241. /package/dist/{with-party → with-sync}/tab-coordination.d.ts +0 -0
  242. /package/dist/{with-party → with-sync}/tab-write-relay.d.ts +0 -0
  243. /package/dist/{withdraw-accessible-DEUCOO4F.js.map → withdraw-accessible-ANSVG6XG.js.map} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/with-commit/numbering/descriptor.ts","../src/via/computed/binding.ts","../src/via/computed/descriptor.ts","../src/via/lookup/binding.ts","../src/via/lookup/descriptor.ts"],"sourcesContent":["/**\n * @category capability\n * Deferred-numbering config descriptor. See\n * docs/superpowers/specs/2026-06-08-sealed-numbering-and-store-clock-design.md.\n */\n\n/** A registered deferred-numbering series. */\nexport interface DeferredNumberingConfig {\n /** Series name — the key passed to `vault.sequence(series)`. */\n readonly series: string\n /** Collection holding the records to number. */\n readonly collection: string\n /** Field on each record where the assigned serial is written. */\n readonly field: string\n /**\n * Minimum wall-clock age (ms) before an entry is eligible at a pass, in\n * addition to the interval commit-wait. Default 0 — the store-clock\n * interval (`storeLatest ≤ now.earliest`) is the correctness mechanism.\n */\n readonly settleWindowMs: number\n}\n\n/**\n * Options for {@link withDeferredNumbering} (#844b — was an inline literal, so\n * unnameable). Same shape as {@link DeferredNumberingConfig} except\n * `settleWindowMs` is optional; the factory defaults it to 0.\n */\nexport interface WithDeferredNumberingOptions {\n /** Series name — the key passed to `vault.sequence(series)`. */\n readonly series: string\n /** Collection holding the records to number. */\n readonly collection: string\n /** Field on each record where the assigned serial is written. */\n readonly field: string\n /** See {@link DeferredNumberingConfig.settleWindowMs}. Default 0. */\n readonly settleWindowMs?: number\n}\n\n/** Declare a deferred-numbering series. Pass the result in `createNoydb({ numbering: [...] })`. */\nexport function withDeferredNumbering(opts: WithDeferredNumberingOptions): DeferredNumberingConfig {\n return {\n series: opts.series,\n collection: opts.collection,\n field: opts.field,\n settleWindowMs: opts.settleWindowMs ?? 0,\n }\n}\n","/**\n * The `computed` via-binding (#638 Task 7) — covers ONLY `mode: 'virtual'`\n * fields. Materialized entries never reach here: they compile into\n * `mergedComputed` (`kernel/collection-config.ts`) and run through the\n * EXISTING stage-5 `evalComputedFields` write path, byte-for-byte unchanged\n * (the behavior lock).\n *\n * A virtual field is computed on READ, inside `present()` — the money-\n * `Formatted`/i18n-`Label` precedent (seam map Part 4) generalized to a\n * user-declared function. It is NEVER stored (no `encodeAtRest`/\n * `decodeAtRest` — the field never appears in `_data` or any `_sealed`\n * slot), and its posture is fixed `queryable: 'none'` — there is no stored/\n * indexed form to query against, regardless of what its sources would\n * otherwise permit (`ViaGraph`'s grain-'virtual' clamp, `kernel/via/graph.ts`,\n * is the belt; this binding's own static posture is the suspenders for a\n * depsless virtual field, which registers no graph edge at all).\n *\n * Export/read redaction for a TAINTED virtual field (sourced from a\n * classified/sealed field) is NOT this binding's job — it stays ignorant of\n * taint, exactly like `evalComputedFields` stays ignorant of it for\n * materialized fields. `kernel/via/taint-binding.ts#taintBinding` (appended\n * to the pipeline by `via/graph-wiring.ts#applyTaintOverlay`, AFTER this\n * binding) overwrites a tainted virtual field's value with the same\n * `EXPORT_REDACTION_MARKER` on every present() — the one enforcement seam\n * every via feature's taint already routes through.\n */\nimport type { ViaBinding, ViaPosture } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport type { ComputedDescriptor } from './descriptor.js'\n\nexport interface ComputedViaConfig {\n /** field name -> its virtual-mode descriptor. Materialized entries are never present here. */\n readonly virtualFields: ReadonlyMap<string, ComputedDescriptor>\n}\n\nconst VIRTUAL_POSTURE: ViaPosture = { encryptedAtRest: 'envelope', queryable: 'none', exportable: true, forgettable: false }\n\nexport function computedBinding(cfg: ComputedViaConfig): ViaBinding {\n const fields = cfg.virtualFields\n return {\n brand: 'computed',\n posture: VIRTUAL_POSTURE,\n covers: (field) => fields.has(field),\n present: (record) => {\n let r = record\n for (const [field, desc] of fields) {\n if (r === record) r = { ...record }\n r[field] = desc.fn(r)\n }\n return r\n },\n }\n}\n\nexport function linkComputedVia(): void {\n installViaBinder('computed', (cfg) => computedBinding(cfg as ComputedViaConfig))\n}\n","/**\n * computed() — the declaration factory for a field whose value is DERIVED\n * from other fields on the same record (#638 Task 7, spec §6). Composes\n * with `via()` (the locked grammar since phase A: `via(computed(fn, { deps,\n * mode }), money('EUR'))`), grouped by `_viaBrand` like every other via\n * feature (`kernel/via/compose.ts#mergeViaFields`).\n *\n * `mode` picks where the function runs:\n * - `'materialized'` (default) — TODAY's stage-5 write-time eager compute\n * (`with-formula/computed/index.ts#evalComputedFields`), stored like any\n * other field. Byte-for-byte the existing `computed: { field: fn }` sugar.\n * - `'virtual'` — rides the `present` read phase (the money-`Formatted`/\n * i18n-`Label` precedent, seam map Part 4): computed fresh on every\n * read, NEVER stored, `queryable: 'none'`, excluded from export unless\n * its declared `deps` permit (identical taint rule to materialized —\n * see `via/computed/binding.ts`).\n *\n * `deps` names the OTHER fields `fn` reads — feeds `ViaGraph` (Task 1/2) so\n * a source's taint (e.g. a classified field) propagates to this derived\n * field. A depsless entry is fine UNLESS the collection also declares\n * classified fields (`kernel/collection-config.ts#resolveComputedEdges`\n * refuses it — closes the #636 opaque-function leak).\n */\nimport type { ViaDescriptor } from '../../kernel/via/index.js'\nimport { linkComputedVia } from './binding.js'\n\nexport interface ComputedDescriptor extends ViaDescriptor {\n readonly _viaBrand: 'computed'\n readonly fn: (record: Record<string, unknown>) => unknown\n readonly deps?: readonly string[]\n readonly mode: 'materialized' | 'virtual'\n}\n\nexport function computed(\n fn: (record: Record<string, unknown>) => unknown,\n opts?: { readonly deps?: readonly string[]; readonly mode?: 'materialized' | 'virtual' },\n): ComputedDescriptor {\n // Self-link, exactly as `money()` and `lookup()` do (#813). Until this call\n // existed, `computed` was the only via feature whose binder was installed by a\n // DIFFERENT module — `port/with/computed-strategy.ts` — rather than by its own\n // declaration factory. That works whenever the kernel spine and the consumer's\n // `computed` import resolve to one module instance, and fails when they do not:\n // under vitest's `server.deps.inline`, a consumer got the descriptor from one\n // transformed instance while the binder registry consulted at bind time lived in\n // another, producing `VIA_NOT_LINKED` for a descriptor `isComputedDescriptor()`\n // accepted. money/i18n/lookup were immune precisely because they self-link.\n //\n // Constructing a descriptor is the binding's opt-in unit, so linking here makes\n // the guarantee local: whatever instance produced the descriptor also has the\n // binder. `installViaBinder` is idempotent + first-wins, so the eager call in\n // `port/with/computed-strategy.ts` stays harmless.\n linkComputedVia()\n return {\n _viaBrand: 'computed',\n fn,\n ...(opts?.deps !== undefined ? { deps: opts.deps } : {}),\n mode: opts?.mode ?? 'materialized',\n }\n}\n\nexport function isComputedDescriptor(x: unknown): x is ComputedDescriptor {\n return typeof x === 'object' && x !== null && (x as { _viaBrand?: unknown })._viaBrand === 'computed'\n}\n","/**\n * The `'lookup'` `ViaBinding` — wires the lookup engine (present-time label\n * dressing across all three backing tiers) into the kernel's generic Via\n * port. Mirrors `via/i18n/binding.ts`'s #553 static-link pattern; the\n * present-time label-dressing algorithm below is adapted from\n * `via-i18n/binding.ts:253-337` (the same wildcard/array/scalar handling,\n * the same `onMissing`/`substitute` policy engine), generalized to branch on\n * `backing` instead of a static-vs-dynamic descriptor-shape check. For the\n * `'static'` and `'reserved'` tiers this delegates to `cfg.lookupLabelResolver`\n * — the SAME vault-built closure the i18n binding's `dictLabelResolver` uses\n * (static table first, else the `vault.dictionary()` handle) — so a native\n * `dict()`/`lookup(static)` field resolves through the identical label data\n * as its `dictKey()`/`staticDict()` alias (the byte-equivalence lock).\n *\n * `lookup()`/`enumOf()`/`dict()` each call {@link linkLookupVia} first — the\n * same #553 pattern `money()`/`dictKey()` use.\n *\n * `buildClause` (label-predicate queries) is still undeclared — out of scope\n * for #650. `compareForOrder` (#650 Task 6, spec §5; matrix tier added Task\n * 7) resolves a `sortBy`-declared field's ordering via `cfg.snapshotFor`'s\n * sync snapshot; the hook signature is UNCHANGED (`via/index.ts:128-129` — no\n * locale param), so it closes over each descriptor's own `displayLocale`\n * (the same locale-less-hinge default `runLookupPresent`'s\n * `hasStaticDisplay` branch already uses). `resolveOrderLabel` (#650 Task\n * 7) is the PER-CALL-locale sibling `orderBy(..., {by:'label'})` needs —\n * see its own doc comment below. `describeFragment` (#650 Task 7) is the\n * first-ever consumed `ViaBinding.describeFragment` implementation — see\n * `with-shape/introspection/describe.ts`'s `buildDescription`.\n */\nimport type { ViaBinding, ViaReadCtx } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport type { LookupDescriptor, LookupBacking, Vocabulary, OnDelete } from './descriptor.js'\nimport { resolvePolicy, type Layer } from '../i18n/policy.js'\nimport { LocaleNotSpecifiedError, UnknownLookupKeyError, ValidationError } from '../../kernel/errors.js'\nimport { getAtPath, setAtPathInPlace } from '../../kernel/paths.js'\nimport type { MaterializedBacking } from './registry.js'\nimport { buildLookupSnapshot } from './snapshot.js'\n\n/**\n * Config a collection's lookup declarations resolve to — the binding's\n * construction input. `lookupLabelResolver`/`getLookupBacking`/`membership`/\n * `snapshotFor` are vault-built closures (never a `Collection` handle,\n * keyring, or DEK/CEK — the zero-knowledge boundary).\n */\nexport interface LookupViaConfig {\n readonly lookupFields: Record<string, LookupDescriptor>\n readonly lookupLabelResolver?: (dimension: string, key: string, locale: string, fallback?: unknown) => Promise<string | undefined>\n /**\n * The matrix (collection) tier's present-time backing-row source, keyed by the full\n * descriptor (not a bare dimension name) so the closure can resolve by `descriptor.key`,\n * not the backing row's PUT-id (#651 Task 3 — the same descriptor-gaining dispatch Task 7\n * already applied to `snapshotFor`).\n */\n readonly getLookupBacking?: (descriptor: LookupDescriptor) => (key: string) => Promise<Record<string, unknown> | undefined>\n /** Closed-vocabulary write-time membership test (#650 Task 3) — `(field, key) => known?`. */\n readonly membership?: (field: string, key: string) => boolean | Promise<boolean>\n /** Sync per-descriptor altKey index — `ingest`'s normalization source (#650 Task 3). */\n readonly getAltIndex?: (desc: LookupDescriptor) => MaterializedBacking | undefined\n /**\n * Sync materialized `key -> row` rows for a lookup descriptor (#650 Task\n * 6, spec §5; matrix-tier routing added #650 Task 7) — `compareForOrder`\n * and `resolveOrderLabel` below, and `snapshot.ts`'s `presentForJoin`\n * builder, all read this same vault-built closure. Reserved AND\n * collection (matrix) tier route here (the vault wires\n * `dimension -> LookupHandle.snapshotEntries()` / `dimension ->\n * collection.querySourceForJoin().snapshot()` respectively, keyed by\n * `descriptor.key` for the matrix case — see `registry.ts`'s\n * `buildLookupSnapshotRows`); static tier is resolved locally from\n * `descriptor.table` without calling this.\n */\n readonly snapshotFor?: (descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined\n readonly collectionName: string\n}\n\n/** Enum tier (`backing:'static'`, no `table`) has no label source at all — never dressed. */\nfunction hasLabelSource(desc: LookupDescriptor): boolean {\n return !(desc.backing === 'static' && desc.table === undefined)\n}\n\n/**\n * Resolve one key's label. `'static'`/`'reserved'` both go through\n * `cfg.lookupLabelResolver` (mirrors `dictLabelResolver`'s own static-table-\n * first-else-reserved-handle branching — the SAME closure is reused, see\n * `kernel/vault.ts`). `'collection'` (matrix tier) reads the declared\n * `present.label` off the backing row via `cfg.getLookupBacking`; when\n * `present.by` is set, that field's value is a `{ locale -> label }` map\n * indexed by the effective locale.\n */\nasync function fetchLookupLabel(\n desc: LookupDescriptor,\n key: string,\n effLocale: string,\n fieldFallback: string | readonly string[] | undefined,\n cfg: LookupViaConfig,\n): Promise<string | undefined> {\n if (desc.backing === 'collection') {\n const getRow = cfg.getLookupBacking?.(desc)\n const row = getRow ? await getRow(key) : undefined\n const labelField = desc.present?.label\n if (!row || labelField === undefined) return undefined\n const raw = row[labelField]\n if (desc.present?.by !== undefined) {\n return raw && typeof raw === 'object' ? (raw as Record<string, unknown>)[effLocale] as string | undefined : undefined\n }\n return typeof raw === 'string' ? raw : undefined\n }\n return cfg.lookupLabelResolver?.(desc.dimension, key, effLocale, fieldFallback)\n}\n\n/** `present` — resolve `<field>Label` for every declared lookup field. Adapted from `via-i18n/binding.ts:253-337`. */\nasync function runLookupPresent(\n record: Record<string, unknown>,\n ctx: ViaReadCtx,\n cfg: LookupViaConfig,\n): Promise<Record<string, unknown>> {\n const fields = Object.entries(cfg.lookupFields).filter(([, d]) => hasLabelSource(d))\n if (fields.length === 0) return record\n\n const locale = typeof ctx.locale === 'string' ? ctx.locale : undefined\n const fallback = ctx.fallback as string | readonly string[] | undefined\n const layer = ctx.layer as Layer\n\n // `{ locale: 'raw' }` wants the untouched record — mirrors\n // `via-i18n/binding.ts`'s `locale !== 'raw'` dict-label gate exactly (no\n // synthetic `<field>Label` derivative on a raw read).\n if (locale === 'raw') return record\n\n // Static-display hybrid hinge: a `backing:'static'` field with a declared\n // `displayLocale` resolves its `<field>Label` even under a locale-less\n // read (mirrors staticDict's `hasStaticDisplay` gate).\n const hasStaticDisplay = fields.some(([, d]) => d.backing === 'static' && d.displayLocale !== undefined)\n if (!locale && !hasStaticDisplay) return record\n\n let result = record\n const withLabels = { ...result }\n\n for (const [field, desc] of fields) {\n const policy = desc.onMissing ? resolvePolicy(desc.onMissing, layer) : 'null'\n const fieldFallback = policy === 'substitute' ? (fallback ?? desc.substitute) : fallback\n const effLocale = locale ?? (desc.backing === 'static' ? desc.displayLocale : undefined)\n\n const resolveKey = async (key: string): Promise<string | null> => {\n if (!effLocale) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(field, `lookup \"${field}\": no locale active to resolve key \"${key}\".`)\n }\n return null\n }\n const label = await fetchLookupLabel(desc, key, effLocale, fieldFallback, cfg)\n if (label === undefined) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(field, `lookup \"${field}\": no label for key \"${key}\" in locale \"${effLocale}\".`)\n }\n return null\n }\n return label\n }\n\n if (field.includes('[].')) {\n const parts = field.split('[].')\n const arrayKey = parts[0]!\n const leaf = parts[1]\n if (!leaf || leaf.includes('.')) continue\n const arr = (withLabels as Record<string, unknown>)[arrayKey]\n if (!Array.isArray(arr)) continue\n const labelKey = `${leaf}Label`\n ;(withLabels as Record<string, unknown>)[arrayKey] = await Promise.all(\n arr.map(async (el) => {\n if (!el || typeof el !== 'object' || Array.isArray(el)) return el\n const k = (el as Record<string, unknown>)[leaf]\n if (typeof k !== 'string') return el\n return { ...(el as Record<string, unknown>), [labelKey]: await resolveKey(k) }\n }),\n )\n continue\n }\n\n const val = result[field]\n if (Array.isArray(val)) {\n withLabels[`${field}Label`] = await Promise.all(\n val.map(async (k) => ({ key: k, label: typeof k === 'string' ? await resolveKey(k) : null })),\n )\n } else if (typeof val === 'string') {\n const label = await resolveKey(val)\n if (label !== null) withLabels[`${field}Label`] = label\n }\n }\n\n result = withLabels\n return result\n}\n\n/**\n * One field's `lookup` descriptor as it appears on a `ViaBinding.\n * describeFragment()` payload (#650 Task 7 — the first real consumer,\n * `with-shape/introspection/describe.ts`'s `buildDescription`, imports this\n * type directly; `describe.ts` is NOT under `kernel/**`, so it's free to\n * import concrete via/ types the way it already does for\n * `LookupDescriptor`/`MoneyDescriptor`/etc.). `dimension` is OMITTED (not\n * emitted as `''`) for a bare `enumOf()` descriptor — the #650 Task 2\n * `dimension:''` sentinel resolved: no dimension name means no `dimension`\n * key, not a meaningless empty string (T2 carry, #650 Task 7).\n */\nexport interface LookupDescribeFragmentEntry {\n readonly dimension?: string\n readonly backing: LookupBacking\n readonly vocabulary: Vocabulary\n readonly key: string\n readonly altKeys?: readonly string[]\n readonly present?: { readonly label: string; readonly by?: string }\n readonly sortBy?: string\n readonly onDelete: OnDelete\n /** Statically-known closed-vocabulary key set (declared `keys`, or a static table's own keys). Omitted when membership lives only in the backing collection/dictionary (open vocabulary, or closed with no declared `keys`). */\n readonly keys?: readonly string[]\n}\n\n/** The `'lookup'` binding's `describeFragment()` payload shape. */\nexport interface LookupDescribeFragment {\n readonly lookupFields: Record<string, LookupDescribeFragmentEntry>\n}\n\nfunction buildLookupDescribeFragment(cfg: LookupViaConfig): Record<string, unknown> {\n const lookupFields: Record<string, LookupDescribeFragmentEntry> = {}\n for (const [field, desc] of Object.entries(cfg.lookupFields)) {\n lookupFields[field] = {\n ...(desc.dimension !== '' ? { dimension: desc.dimension } : {}),\n backing: desc.backing,\n vocabulary: desc.vocabulary,\n key: desc.key,\n onDelete: desc.onDelete,\n ...(desc.altKeys !== undefined ? { altKeys: desc.altKeys } : {}),\n ...(desc.present !== undefined ? { present: desc.present } : {}),\n ...(desc.sortBy !== undefined ? { sortBy: desc.sortBy } : {}),\n // #657 — static tier: when no `keys` was explicitly declared but a\n // `table` was (the staticDict()-equivalent `lookup(dim, {backing:\n // 'static', table})` shape), the table's own key set IS the\n // statically-known closed-vocabulary set the DescribedField.lookup\n // docblock promises (\"declared `keys`, OR a static table's own\n // keys\"). Reserved/matrix tiers never carry `table`, so this branch\n // never fires for them — their `keys` emission is unchanged.\n ...(desc.keys !== undefined\n ? { keys: desc.keys }\n : desc.backing === 'static' && desc.table !== undefined ? { keys: Object.keys(desc.table) } : {}),\n }\n }\n return { lookupFields }\n}\n\n/**\n * `cfg.getAltIndex(desc)` (matrix tier) reads the backing collection's cache\n * via `querySourceForJoin()` (`buildLookupAltIndex`, registry.ts) — which\n * throws a `.join()`-branded message when that collection was opened\n * `{prefetch:false}` (lazy mode is unsupported for altKey normalization).\n * Normalization must never silently not happen (the banned silent-no-op\n * class, #650 Task 3 review, Important 2) — detect that specific failure\n * and surface a CLEAR, lookup-branded `ValidationError` at the point of\n * failure instead of letting the confusing join-branded one leak onto an\n * unrelated `put()`. Any OTHER error (e.g. `materializeBackingTable`'s own\n * altKey-collision `ValidationError`) propagates unchanged.\n */\nfunction getAltIndexOrThrow(field: string, desc: LookupDescriptor, cfg: LookupViaConfig): MaterializedBacking | undefined {\n try {\n return cfg.getAltIndex?.(desc)\n } catch (err) {\n if (err instanceof Error && err.message.includes('lazy-mode')) {\n throw new ValidationError(\n `lookup: altKeys on \"${field}\" require the backing collection \"${desc.dimension}\" to be ` +\n `prefetch-enabled (lazy mode unsupported); open it without {prefetch:false} or drop altKeys.`,\n )\n }\n throw err\n }\n}\n\n/**\n * `ingest` — altKey candidate values normalize to the canonical key (#650\n * Task 3, spec §3). Pure, sync, idempotent (a canonical key maps to\n * itself); no store read — consults the pre-materialized\n * `cfg.getAltIndex(desc)`. The money `canonicalizeIncomingMoney` precedent\n * (`via/index.ts:108`).\n *\n * A `[].`-wildcard multi-value path (`getAtPath` resolves >1 entries — an\n * array of nested objects, e.g. `'lines[].country'`, the same wildcard\n * convention `runLookupPresent` above already handles) normalizes EVERY\n * element's leaf value, not just a lone scalar (#652 fix — this used to bail\n * out entirely here while `runLookupEnforceWrite` below validated every\n * value unnormalized, so a legitimate altKey in an array position was\n * wrongly refused by closed-vocabulary enforcement). `setAtPathInPlace`\n * can't write into a `[].`-wildcard path, so the array is reconstructed\n * immutably instead, mirroring `runLookupPresent`'s own `field.includes\n * ('[].')` branch. A plain field whose OWN value is a bare top-level array\n * (not a `[].`-wildcard path) gets the SAME element-wise normalization\n * against `backing.altIndex` (#661 fix — `getAtPath` resolves it to one\n * opaque value, so the array itself is `values[0]`; a non-string element is\n * left untouched, mirroring the scalar branch's own `typeof !== 'string'`\n * skip — no parallel coercion invented for this shape).\n */\nfunction runLookupIngest(record: Record<string, unknown>, cfg: LookupViaConfig): Record<string, unknown> {\n const withAltKeys = Object.entries(cfg.lookupFields).filter(([, d]) => (d.altKeys?.length ?? 0) > 0)\n if (withAltKeys.length === 0) return record\n\n let result = record\n for (const [field, desc] of withAltKeys) {\n const backing = getAltIndexOrThrow(field, desc, cfg)\n if (!backing || backing.altIndex.size === 0) continue\n\n if (field.includes('[].')) {\n const [arrayKey, leaf] = field.split('[].')\n if (!leaf || leaf.includes('.')) continue\n const arr = record[arrayKey!]\n if (!Array.isArray(arr)) continue\n let changed = false\n const normalized = arr.map((item) => {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return item\n const value = (item as Record<string, unknown>)[leaf]\n if (typeof value !== 'string') return item\n const canonical = backing.altIndex.get(value)\n if (canonical === undefined || canonical === value) return item\n changed = true\n return { ...(item as Record<string, unknown>), [leaf]: canonical }\n })\n if (!changed) continue\n if (result === record) result = { ...record }\n result[arrayKey!] = normalized\n continue\n }\n\n const values = getAtPath(record, field)\n if (values.length !== 1) continue\n const value = values[0]\n\n // `getAtPath`/`setAtPathInPlace` resolve `field` generically, dotted\n // paths included (e.g. 'meta.tags') — do not rewrite this branch to a\n // direct `record[field]` bracket access, which would silently stop\n // normalizing/enforcing a dotted-non-wildcard bare-array field (#661).\n if (Array.isArray(value)) {\n if (value.length === 0) continue\n let changed = false\n const normalized = value.map((el) => {\n if (typeof el !== 'string') return el\n const canonical = backing.altIndex.get(el)\n if (canonical === undefined || canonical === el) return el\n changed = true\n return canonical\n })\n if (!changed) continue\n if (result === record) result = { ...record }\n setAtPathInPlace(result, field, normalized)\n continue\n }\n\n if (typeof value !== 'string') continue\n const canonical = backing.altIndex.get(value)\n if (canonical === undefined || canonical === value) continue\n if (result === record) result = { ...record }\n setAtPathInPlace(result, field, canonical)\n }\n return result\n}\n\n/**\n * `enforceWrite` — closed-vocabulary write refusal (#650 Task 3, spec §3).\n * Runs only for `vocabulary:'closed'` fields; `'open'` (the dictKey/dict\n * default) skips the check entirely, so #649's fix is additive — existing\n * dictKey/staticDict collections are unaffected. `ctx` carries no\n * cross-collection door (`id`/`vault`/`prior`/`emit` only, unchanged) —\n * membership is a vault-built closure on `cfg`, per spec.\n */\nasync function runLookupEnforceWrite(record: Record<string, unknown>, cfg: LookupViaConfig): Promise<void> {\n for (const [field, desc] of Object.entries(cfg.lookupFields)) {\n if (desc.vocabulary !== 'closed') continue\n // Checks every value `getAtPath` returns — for a `[].`-wildcard\n // multi-value path, that's every element's leaf value.\n // `runLookupIngest` above now normalizes each of those elements first\n // (#652), so what lands here for a `[].`-wildcard field is already\n // canonical; this loop's job stays membership, not normalization.\n for (const value of getAtPath(record, field)) {\n // A plain field whose OWN value is a bare top-level array (#661) —\n // `runLookupIngest` above has already normalized its elements'\n // altKeys, so membership-check each element through the SAME\n // `cfg.membership` closure the scalar branch below uses, refusing on\n // the first unknown one. A non-string element is skipped, mirroring\n // the scalar branch's own skip.\n if (Array.isArray(value)) {\n for (const el of value) {\n if (typeof el !== 'string') continue\n const known = cfg.membership ? await cfg.membership(field, el) : true\n if (!known) throw new UnknownLookupKeyError(desc.dimension, field, el)\n }\n continue\n }\n if (typeof value !== 'string') continue\n const known = cfg.membership ? await cfg.membership(field, value) : true\n if (!known) throw new UnknownLookupKeyError(desc.dimension, field, value)\n }\n }\n}\n\n/**\n * `compareForOrder` — exact ordering for a `sortBy`-declared lookup field\n * against the sync snapshot (#650 Task 6, spec §5, conflict resolution 4;\n * matrix-tier coverage added #650 Task 7). Opt-in: undeclared `sortBy`\n * (every dictKey/staticDict alias and every lookup field declared before\n * Task 6) returns `undefined` — falls through to the generic stored-value\n * comparator, byte-identical to today. Static tier reads `descriptor.table`\n * directly; reserved AND matrix (collection) tier both read `cfg.snapshotFor`\n * (the SAME live cache `presentForJoin`'s lookup half reads — see\n * `snapshot.ts`'s file header). The hook has no locale parameter\n * (`via/index.ts:128-129`, unchanged) — closes over the descriptor's own\n * `displayLocale` (the same locale-less-hinge default `runLookupPresent`\n * already uses); a `sortBy` field whose value isn't locale-keyed\n * (`present.by` undefined) never needs one. A `by`-keyed `sortBy` field\n * with NO declared `displayLocale` degrades to comparing the raw canonical\n * keys (silent — `LookupSnapshot.compareKeys` never throws; declare-time\n * warning at `descriptor.ts`'s `lookup()` factory; use\n * `orderBy(field, dir, {by:'label'})` — `resolveOrderLabel` below — for a\n * PER-CALL locale instead).\n */\nfunction compareLookupOrder(field: string, a: unknown, b: unknown, cfg: LookupViaConfig): number | undefined {\n if (typeof a !== 'string' || typeof b !== 'string') return undefined\n const desc = cfg.lookupFields[field]\n if (!desc || desc.sortBy === undefined) return undefined\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : cfg.snapshotFor?.(desc)\n if (!rows) return undefined\n return buildLookupSnapshot(desc.dimension, rows, desc).compareKeys(a, b, desc.displayLocale ?? '')\n}\n\n/**\n * `resolveOrderLabel` — per-key, PER-CALL-locale label resolution for\n * `orderBy(field, dir, { by: 'label' })` (#650 Task 7, spec §6 / seam map\n * Part 10 surprise 6's option (b)) — the channel `compareForOrder` above\n * structurally cannot serve, since `ViaBinding.compareForOrder` carries no\n * locale parameter. Consumed by `kernel/query/builder.ts`'s\n * `buildOrderLabelMaps` as the fallback for lookup fields the legacy dict\n * registries don't bridge (matrix tier; reserved/static tier already\n * resolves via that bridge — `JoinContext.resolveDictSource` — tried\n * FIRST by the caller, see `registry.ts`'s `collectLookupDictCompat` doc\n * comment). Reuses the exact same `cfg.snapshotFor`/`buildLookupSnapshot`\n * machinery as `compareLookupOrder` above, just with the per-call `locale`\n * in place of the descriptor's own `displayLocale` — falling back to\n * `displayLocale` only when the call itself is locale-less, the same\n * hinge order `runLookupPresent` already uses.\n */\nfunction resolveLookupOrderLabel(field: string, key: string, locale: string | undefined, cfg: LookupViaConfig): string | undefined {\n const desc = cfg.lookupFields[field]\n if (!desc) return undefined\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : cfg.snapshotFor?.(desc)\n if (!rows) return undefined\n return buildLookupSnapshot(desc.dimension, rows, desc).label(key, locale ?? desc.displayLocale ?? '')\n}\n\nexport function lookupBinding(cfg: LookupViaConfig): ViaBinding {\n return {\n brand: 'lookup',\n posture: { encryptedAtRest: 'envelope', queryable: 'full', exportable: true, forgettable: false },\n reservedPrefixes: ['_dict_', '_lookup_'],\n covers: (field) => field in cfg.lookupFields,\n ingest: (record) => runLookupIngest(record, cfg),\n enforceWrite: (record) => runLookupEnforceWrite(record, cfg),\n present: async (record, ctx) => runLookupPresent(record, ctx, cfg),\n compareForOrder: (field, a, b) => compareLookupOrder(field, a, b, cfg),\n resolveOrderLabel: (field, key, locale) => resolveLookupOrderLabel(field, key, locale, cfg),\n describeFragment: () => buildLookupDescribeFragment(cfg),\n }\n}\n\nexport function linkLookupVia(): void {\n installViaBinder('lookup', (c) => lookupBinding(c as LookupViaConfig))\n}\n","/**\n * `lookup()` / `enumOf()` / `dict()` descriptors — the three declaration\n * surfaces for the `'lookup'` via binding (#650 Task 2, phase D of the Via\n * port). One `LookupDescriptor` shape; the tiers are `backing` details:\n *\n * - `lookup(dimension, opts?)` — matrix tier: first-class collection backing\n * (default `backing:'collection'`) — a reference-collection dimension\n * (e.g. `countries`), open vocabulary by default.\n * - `enumOf(keys)` — enum tier: static in-config table, CLOSED\n * vocabulary, no backing store at all (no dimension name — pure inline\n * keys). Exported as `enumOf`; the barrel (`index.ts`) re-exports it as\n * `enum` (`enum` is a reserved word, so it can't be the function's own\n * name).\n * - `dict(dimension, opts?)` — dict tier: reserved `_dict_<dimension>`\n * micro-collection backing (the `vault.dictionary(name)` engine), open\n * vocabulary by default.\n *\n * Each factory calls {@link linkLookupVia} first — the declaration IS the\n * via binding's opt-in unit (#553), same pattern as `money()`/`i18nText()`/\n * `dictKey()`.\n */\n\nimport type { OnMissingPolicy } from '../i18n/policy.js'\nimport { linkLookupVia } from './binding.js'\n\n/** `'closed'` = enum semantics (membership enforced, Task 3); `'open'` permits unknown keys. */\nexport type Vocabulary = 'open' | 'closed'\n\n/** Where a dimension's rows live: static in-config table / reserved micro-collection / first-class collection. */\nexport type LookupBacking = 'static' | 'reserved' | 'collection'\n\n/** Delete-time referential policy for the backing dimension (default `'restrict'`, enforced in Task 5). */\nexport type OnDelete = 'restrict' | 'cascade' | 'nullify'\n\n/** The one descriptor shape every tier compiles to — tiers differ only by `backing`. */\nexport interface LookupDescriptor<Keys extends string = string> {\n readonly _viaBrand: 'lookup'\n /** Dimension/dictionary/target name. Empty for a bare `enumOf()` (no backing store, no name). */\n readonly dimension: string\n /** Canonical key field on the row (default `'id'`). */\n readonly key: string\n /** Candidate keys normalized to `key` on ingest (Task 3). */\n readonly altKeys?: readonly string[]\n readonly vocabulary: Vocabulary\n /** Dressing dimension: which backing-row field supplies `<field>Label`, optionally keyed `by` a sub-field (e.g. locale). */\n readonly present?: { readonly label: string; readonly by?: string }\n /** Field to sort by against the snapshot (Task 6). */\n readonly sortBy?: string\n readonly backing: LookupBacking\n readonly onDelete: OnDelete\n /** Static/enum inline key set. */\n readonly keys?: readonly Keys[]\n /** Static tier only: in-code `key -> { locale -> label }` table. */\n readonly table?: Readonly<Record<string, Readonly<Record<string, string>>>>\n /** Static hybrid hinge (the `staticDict` alias) — locale-less `<field>Label`. */\n readonly displayLocale?: string\n readonly onMissing?: OnMissingPolicy\n readonly substitute?: readonly string[]\n /** Inline display labels (value -> label), the dict-tier sync fallback (mirrors `dictKey`'s `labels`). */\n readonly labels?: Record<string, string>\n}\n\n/**\n * `sortBy`/`present.by` coupling warning (#650 Task 7, T6 minor — task-6-\n * report.md Concern #4). A `by`-keyed `present` (locale-map) field used as\n * `sortBy` needs a declared `displayLocale` for the locale-less\n * `compareForOrder` sort hook (a plain `orderBy(field)`, no `{by:'label'}`)\n * to resolve anything — without one it silently degrades to comparing the\n * raw canonical keys (never throws — `LookupSnapshot.compareKeys`'s\n * contract). `orderBy(field, dir, {by:'label'})` doesn't need this (it\n * carries its own per-call locale via `ViaBinding.resolveOrderLabel`,\n * #650 Task 7) — only a sortBy-driven PLAIN orderBy does. Warn once at\n * declare time rather than degrade silently at query time.\n */\nfunction warnIfSortByNeedsDisplayLocale(\n dimension: string,\n opts?: { sortBy?: string; present?: { by?: string }; displayLocale?: string },\n): void {\n if (opts?.sortBy !== undefined && opts.present?.by !== undefined && opts.displayLocale === undefined) {\n console.warn(\n `[noy-db] lookup(\"${dimension}\"): sortBy \"${opts.sortBy}\" is locale-keyed (present.by is set) but no ` +\n `displayLocale is declared — a locale-less orderBy() will silently sort by the raw stored key instead ` +\n `of the resolved label. Declare displayLocale, or sort via orderBy(field, dir, { by: 'label' }), which ` +\n `resolves at the query's own per-call locale.`,\n )\n }\n}\n\n/**\n * Matrix tier — first-class collection backing (default `backing:'collection'`).\n * `dimension` names the backing collection (e.g. `'countries'`).\n *\n * `backing` may be overridden to construct any tier through this one\n * factory — e.g. `lookup(name, { backing:'static', table, displayLocale })`\n * is the table-bearing static tier `staticDict()` compiles onto. The\n * `table`/`displayLocale`/`keys`/`onMissing`/`substitute`/`labels` options\n * are a superset of the brief's literal opts list: `LookupDescriptor`\n * already carries these fields for exactly this purpose, and without them\n * `backing:'static'` would be unreachable stand-alone through `lookup()`\n * (see task-2-report.md's \"Design decisions\").\n *\n * **`altKeys` caveat (matrix tier only)**: normalizing an altKey candidate\n * to its canonical `key` requires the backing `dimension` collection to be\n * open in EAGER mode (the default; `{ prefetch: false }` — lazy mode — is\n * unsupported). A `put()` on a field with `altKeys` whose backing collection\n * is lazy throws a `ValidationError` naming the field and dimension; open\n * the backing collection without `{ prefetch: false }`, or drop `altKeys`.\n */\nexport function lookup<Keys extends string>(\n dimension: string,\n opts?: {\n key?: string\n altKeys?: readonly string[]\n vocabulary?: Vocabulary\n present?: { label: string; by?: string }\n sortBy?: string\n backing?: LookupBacking\n onDelete?: OnDelete\n keys?: readonly Keys[]\n table?: Readonly<Record<string, Readonly<Record<string, string>>>>\n displayLocale?: string\n onMissing?: OnMissingPolicy\n substitute?: readonly string[]\n labels?: Record<string, string>\n },\n): LookupDescriptor<Keys> {\n linkLookupVia()\n warnIfSortByNeedsDisplayLocale(dimension, opts)\n return {\n _viaBrand: 'lookup',\n dimension,\n key: opts?.key ?? 'id',\n vocabulary: opts?.vocabulary ?? 'open',\n backing: opts?.backing ?? 'collection',\n onDelete: opts?.onDelete ?? 'restrict',\n ...(opts?.altKeys !== undefined ? { altKeys: opts.altKeys } : {}),\n ...(opts?.present !== undefined ? { present: opts.present } : {}),\n ...(opts?.sortBy !== undefined ? { sortBy: opts.sortBy } : {}),\n ...(opts?.keys !== undefined ? { keys: opts.keys } : {}),\n ...(opts?.table !== undefined ? { table: opts.table } : {}),\n ...(opts?.displayLocale !== undefined ? { displayLocale: opts.displayLocale } : {}),\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n ...(opts?.labels !== undefined ? { labels: opts.labels } : {}),\n }\n}\n\n/**\n * Enum tier — static in-config table, CLOSED vocabulary, no backing store.\n * No dimension name (pure inline keys) — `dimension` is `''`.\n */\nexport function enumOf<const Keys extends readonly string[]>(keys: Keys): LookupDescriptor<Keys[number]> {\n linkLookupVia()\n return {\n _viaBrand: 'lookup',\n dimension: '',\n key: 'id',\n vocabulary: 'closed',\n backing: 'static',\n onDelete: 'restrict',\n keys,\n }\n}\n\n/**\n * Dict tier — reserved `_dict_<dimension>` micro-collection backing (the\n * `vault.dictionary(dimension)` engine), open vocabulary by default. The\n * native equivalent of `dictKey()`.\n *\n * Unlike `lookup()`'s matrix tier, `dict()` has no `altKeys` option — its\n * `_dict_<dimension>` backing is the always-synchronous `LookupHandle`\n * write-through cache, never a `vault.collection()` that can be opened\n * `{ prefetch: false }`, so the matrix tier's lazy-mode altKeys restriction\n * does not apply here.\n */\nexport function dict<Keys extends string>(\n dimension: string,\n opts?: {\n keys?: readonly Keys[]\n vocabulary?: Vocabulary\n present?: { label: string; by?: string }\n onDelete?: OnDelete\n onMissing?: OnMissingPolicy\n substitute?: readonly string[]\n },\n): LookupDescriptor<Keys> {\n linkLookupVia()\n return {\n _viaBrand: 'lookup',\n dimension,\n key: 'id',\n vocabulary: opts?.vocabulary ?? 'open',\n backing: 'reserved',\n onDelete: opts?.onDelete ?? 'restrict',\n ...(opts?.keys !== undefined ? { keys: opts.keys } : {}),\n ...(opts?.present !== undefined ? { present: opts.present } : {}),\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n }\n}\n"],"mappings":"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","names":["value","canonical","known"]}
1
+ {"version":3,"sources":["../src/with-commit/numbering/descriptor.ts","../src/via/computed/binding.ts","../src/via/computed/descriptor.ts","../src/via/lookup/binding.ts","../src/via/lookup/descriptor.ts","../src/with-sync/credentials.ts"],"sourcesContent":["/**\n * @category capability\n * Deferred-numbering config descriptor. See\n * docs/superpowers/specs/2026-06-08-sealed-numbering-and-store-clock-design.md.\n */\n\n/** A registered deferred-numbering series. */\nexport interface DeferredNumberingConfig {\n /** Series name — the key passed to `vault.sequence(series)`. */\n readonly series: string\n /** Collection holding the records to number. */\n readonly collection: string\n /** Field on each record where the assigned serial is written. */\n readonly field: string\n /**\n * Minimum wall-clock age (ms) before an entry is eligible at a pass, in\n * addition to the interval commit-wait. Default 0 — the store-clock\n * interval (`storeLatest ≤ now.earliest`) is the correctness mechanism.\n */\n readonly settleWindowMs: number\n}\n\n/**\n * Options for {@link withDeferredNumbering} (#844b — was an inline literal, so\n * unnameable). Same shape as {@link DeferredNumberingConfig} except\n * `settleWindowMs` is optional; the factory defaults it to 0.\n */\nexport interface WithDeferredNumberingOptions {\n /** Series name — the key passed to `vault.sequence(series)`. */\n readonly series: string\n /** Collection holding the records to number. */\n readonly collection: string\n /** Field on each record where the assigned serial is written. */\n readonly field: string\n /** See {@link DeferredNumberingConfig.settleWindowMs}. Default 0. */\n readonly settleWindowMs?: number\n}\n\n/** Declare a deferred-numbering series. Pass the result in `createNoydb({ numbering: [...] })`. */\nexport function withDeferredNumbering(opts: WithDeferredNumberingOptions): DeferredNumberingConfig {\n return {\n series: opts.series,\n collection: opts.collection,\n field: opts.field,\n settleWindowMs: opts.settleWindowMs ?? 0,\n }\n}\n","/**\n * The `computed` via-binding (#638 Task 7) — covers ONLY `mode: 'virtual'`\n * fields. Materialized entries never reach here: they compile into\n * `mergedComputed` (`kernel/collection-config.ts`) and run through the\n * EXISTING stage-5 `evalComputedFields` write path, byte-for-byte unchanged\n * (the behavior lock).\n *\n * A virtual field is computed on READ, inside `present()` — the money-\n * `Formatted`/i18n-`Label` precedent (seam map Part 4) generalized to a\n * user-declared function. It is NEVER stored (no `encodeAtRest`/\n * `decodeAtRest` — the field never appears in `_data` or any `_sealed`\n * slot), and its posture is fixed `queryable: 'none'` — there is no stored/\n * indexed form to query against, regardless of what its sources would\n * otherwise permit (`ViaGraph`'s grain-'virtual' clamp, `kernel/via/graph.ts`,\n * is the belt; this binding's own static posture is the suspenders for a\n * depsless virtual field, which registers no graph edge at all).\n *\n * Export/read redaction for a TAINTED virtual field (sourced from a\n * classified/sealed field) is NOT this binding's job — it stays ignorant of\n * taint, exactly like `evalComputedFields` stays ignorant of it for\n * materialized fields. `kernel/via/taint-binding.ts#taintBinding` (appended\n * to the pipeline by `via/graph-wiring.ts#applyTaintOverlay`, AFTER this\n * binding) overwrites a tainted virtual field's value with the same\n * `EXPORT_REDACTION_MARKER` on every present() — the one enforcement seam\n * every via feature's taint already routes through.\n */\nimport type { ViaBinding, ViaPosture } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport type { ComputedDescriptor } from './descriptor.js'\n\nexport interface ComputedViaConfig {\n /** field name -> its virtual-mode descriptor. Materialized entries are never present here. */\n readonly virtualFields: ReadonlyMap<string, ComputedDescriptor>\n}\n\nconst VIRTUAL_POSTURE: ViaPosture = { encryptedAtRest: 'envelope', queryable: 'none', exportable: true, forgettable: false }\n\nexport function computedBinding(cfg: ComputedViaConfig): ViaBinding {\n const fields = cfg.virtualFields\n return {\n brand: 'computed',\n posture: VIRTUAL_POSTURE,\n covers: (field) => fields.has(field),\n present: (record) => {\n let r = record\n for (const [field, desc] of fields) {\n if (r === record) r = { ...record }\n r[field] = desc.fn(r)\n }\n return r\n },\n }\n}\n\nexport function linkComputedVia(): void {\n installViaBinder('computed', (cfg) => computedBinding(cfg as ComputedViaConfig))\n}\n","/**\n * computed() — the declaration factory for a field whose value is DERIVED\n * from other fields on the same record (#638 Task 7, spec §6). Composes\n * with `via()` (the locked grammar since phase A: `via(computed(fn, { deps,\n * mode }), money('EUR'))`), grouped by `_viaBrand` like every other via\n * feature (`kernel/via/compose.ts#mergeViaFields`).\n *\n * `mode` picks where the function runs:\n * - `'materialized'` (default) — TODAY's stage-5 write-time eager compute\n * (`with-formula/computed/index.ts#evalComputedFields`), stored like any\n * other field. Byte-for-byte the existing `computed: { field: fn }` sugar.\n * - `'virtual'` — rides the `present` read phase (the money-`Formatted`/\n * i18n-`Label` precedent, seam map Part 4): computed fresh on every\n * read, NEVER stored, `queryable: 'none'`, excluded from export unless\n * its declared `deps` permit (identical taint rule to materialized —\n * see `via/computed/binding.ts`).\n *\n * `deps` names the OTHER fields `fn` reads — feeds `ViaGraph` (Task 1/2) so\n * a source's taint (e.g. a classified field) propagates to this derived\n * field. A depsless entry is fine UNLESS the collection also declares\n * classified fields (`kernel/collection-config.ts#resolveComputedEdges`\n * refuses it — closes the #636 opaque-function leak).\n */\nimport type { ViaDescriptor } from '../../kernel/via/index.js'\nimport { linkComputedVia } from './binding.js'\n\nexport interface ComputedDescriptor extends ViaDescriptor {\n readonly _viaBrand: 'computed'\n readonly fn: (record: Record<string, unknown>) => unknown\n readonly deps?: readonly string[]\n readonly mode: 'materialized' | 'virtual'\n}\n\nexport function computed(\n fn: (record: Record<string, unknown>) => unknown,\n opts?: { readonly deps?: readonly string[]; readonly mode?: 'materialized' | 'virtual' },\n): ComputedDescriptor {\n // Self-link, exactly as `money()` and `lookup()` do (#813). Until this call\n // existed, `computed` was the only via feature whose binder was installed by a\n // DIFFERENT module — `port/with/computed-strategy.ts` — rather than by its own\n // declaration factory. That works whenever the kernel spine and the consumer's\n // `computed` import resolve to one module instance, and fails when they do not:\n // under vitest's `server.deps.inline`, a consumer got the descriptor from one\n // transformed instance while the binder registry consulted at bind time lived in\n // another, producing `VIA_NOT_LINKED` for a descriptor `isComputedDescriptor()`\n // accepted. money/i18n/lookup were immune precisely because they self-link.\n //\n // Constructing a descriptor is the binding's opt-in unit, so linking here makes\n // the guarantee local: whatever instance produced the descriptor also has the\n // binder. `installViaBinder` is idempotent + first-wins, so the eager call in\n // `port/with/computed-strategy.ts` stays harmless.\n linkComputedVia()\n return {\n _viaBrand: 'computed',\n fn,\n ...(opts?.deps !== undefined ? { deps: opts.deps } : {}),\n mode: opts?.mode ?? 'materialized',\n }\n}\n\nexport function isComputedDescriptor(x: unknown): x is ComputedDescriptor {\n return typeof x === 'object' && x !== null && (x as { _viaBrand?: unknown })._viaBrand === 'computed'\n}\n","/**\n * The `'lookup'` `ViaBinding` — wires the lookup engine (present-time label\n * dressing across all three backing tiers) into the kernel's generic Via\n * port. Mirrors `via/i18n/binding.ts`'s #553 static-link pattern; the\n * present-time label-dressing algorithm below is adapted from\n * `via-i18n/binding.ts:253-337` (the same wildcard/array/scalar handling,\n * the same `onMissing`/`substitute` policy engine), generalized to branch on\n * `backing` instead of a static-vs-dynamic descriptor-shape check. For the\n * `'static'` and `'reserved'` tiers this delegates to `cfg.lookupLabelResolver`\n * — the SAME vault-built closure the i18n binding's `dictLabelResolver` uses\n * (static table first, else the `vault.dictionary()` handle) — so a native\n * `dict()`/`lookup(static)` field resolves through the identical label data\n * as its `dictKey()`/`staticDict()` alias (the byte-equivalence lock).\n *\n * `lookup()`/`enumOf()`/`dict()` each call {@link linkLookupVia} first — the\n * same #553 pattern `money()`/`dictKey()` use.\n *\n * `buildClause` (label-predicate queries) is still undeclared — out of scope\n * for #650. `compareForOrder` (#650 Task 6, spec §5; matrix tier added Task\n * 7) resolves a `sortBy`-declared field's ordering via `cfg.snapshotFor`'s\n * sync snapshot; the hook signature is UNCHANGED (`via/index.ts:128-129` — no\n * locale param), so it closes over each descriptor's own `displayLocale`\n * (the same locale-less-hinge default `runLookupPresent`'s\n * `hasStaticDisplay` branch already uses). `resolveOrderLabel` (#650 Task\n * 7) is the PER-CALL-locale sibling `orderBy(..., {by:'label'})` needs —\n * see its own doc comment below. `describeFragment` (#650 Task 7) is the\n * first-ever consumed `ViaBinding.describeFragment` implementation — see\n * `with-shape/introspection/describe.ts`'s `buildDescription`.\n */\nimport type { ViaBinding, ViaReadCtx } from '../../kernel/via/index.js'\nimport { installViaBinder } from '../../kernel/via/index.js'\nimport type { LookupDescriptor, LookupBacking, Vocabulary, OnDelete } from './descriptor.js'\nimport { resolvePolicy, type Layer } from '../i18n/policy.js'\nimport { LocaleNotSpecifiedError, UnknownLookupKeyError, ValidationError } from '../../kernel/errors.js'\nimport { getAtPath, setAtPathInPlace } from '../../kernel/paths.js'\nimport type { MaterializedBacking } from './registry.js'\nimport { buildLookupSnapshot } from './snapshot.js'\n\n/**\n * Config a collection's lookup declarations resolve to — the binding's\n * construction input. `lookupLabelResolver`/`getLookupBacking`/`membership`/\n * `snapshotFor` are vault-built closures (never a `Collection` handle,\n * keyring, or DEK/CEK — the zero-knowledge boundary).\n */\nexport interface LookupViaConfig {\n readonly lookupFields: Record<string, LookupDescriptor>\n readonly lookupLabelResolver?: (dimension: string, key: string, locale: string, fallback?: unknown) => Promise<string | undefined>\n /**\n * The matrix (collection) tier's present-time backing-row source, keyed by the full\n * descriptor (not a bare dimension name) so the closure can resolve by `descriptor.key`,\n * not the backing row's PUT-id (#651 Task 3 — the same descriptor-gaining dispatch Task 7\n * already applied to `snapshotFor`).\n */\n readonly getLookupBacking?: (descriptor: LookupDescriptor) => (key: string) => Promise<Record<string, unknown> | undefined>\n /** Closed-vocabulary write-time membership test (#650 Task 3) — `(field, key) => known?`. */\n readonly membership?: (field: string, key: string) => boolean | Promise<boolean>\n /** Sync per-descriptor altKey index — `ingest`'s normalization source (#650 Task 3). */\n readonly getAltIndex?: (desc: LookupDescriptor) => MaterializedBacking | undefined\n /**\n * Sync materialized `key -> row` rows for a lookup descriptor (#650 Task\n * 6, spec §5; matrix-tier routing added #650 Task 7) — `compareForOrder`\n * and `resolveOrderLabel` below, and `snapshot.ts`'s `presentForJoin`\n * builder, all read this same vault-built closure. Reserved AND\n * collection (matrix) tier route here (the vault wires\n * `dimension -> LookupHandle.snapshotEntries()` / `dimension ->\n * collection.querySourceForJoin().snapshot()` respectively, keyed by\n * `descriptor.key` for the matrix case — see `registry.ts`'s\n * `buildLookupSnapshotRows`); static tier is resolved locally from\n * `descriptor.table` without calling this.\n */\n readonly snapshotFor?: (descriptor: LookupDescriptor) => ReadonlyMap<string, Record<string, unknown>> | undefined\n readonly collectionName: string\n}\n\n/** Enum tier (`backing:'static'`, no `table`) has no label source at all — never dressed. */\nfunction hasLabelSource(desc: LookupDescriptor): boolean {\n return !(desc.backing === 'static' && desc.table === undefined)\n}\n\n/**\n * Resolve one key's label. `'static'`/`'reserved'` both go through\n * `cfg.lookupLabelResolver` (mirrors `dictLabelResolver`'s own static-table-\n * first-else-reserved-handle branching — the SAME closure is reused, see\n * `kernel/vault.ts`). `'collection'` (matrix tier) reads the declared\n * `present.label` off the backing row via `cfg.getLookupBacking`; when\n * `present.by` is set, that field's value is a `{ locale -> label }` map\n * indexed by the effective locale.\n */\nasync function fetchLookupLabel(\n desc: LookupDescriptor,\n key: string,\n effLocale: string,\n fieldFallback: string | readonly string[] | undefined,\n cfg: LookupViaConfig,\n): Promise<string | undefined> {\n if (desc.backing === 'collection') {\n const getRow = cfg.getLookupBacking?.(desc)\n const row = getRow ? await getRow(key) : undefined\n const labelField = desc.present?.label\n if (!row || labelField === undefined) return undefined\n const raw = row[labelField]\n if (desc.present?.by !== undefined) {\n return raw && typeof raw === 'object' ? (raw as Record<string, unknown>)[effLocale] as string | undefined : undefined\n }\n return typeof raw === 'string' ? raw : undefined\n }\n return cfg.lookupLabelResolver?.(desc.dimension, key, effLocale, fieldFallback)\n}\n\n/** `present` — resolve `<field>Label` for every declared lookup field. Adapted from `via-i18n/binding.ts:253-337`. */\nasync function runLookupPresent(\n record: Record<string, unknown>,\n ctx: ViaReadCtx,\n cfg: LookupViaConfig,\n): Promise<Record<string, unknown>> {\n const fields = Object.entries(cfg.lookupFields).filter(([, d]) => hasLabelSource(d))\n if (fields.length === 0) return record\n\n const locale = typeof ctx.locale === 'string' ? ctx.locale : undefined\n const fallback = ctx.fallback as string | readonly string[] | undefined\n const layer = ctx.layer as Layer\n\n // `{ locale: 'raw' }` wants the untouched record — mirrors\n // `via-i18n/binding.ts`'s `locale !== 'raw'` dict-label gate exactly (no\n // synthetic `<field>Label` derivative on a raw read).\n if (locale === 'raw') return record\n\n // Static-display hybrid hinge: a `backing:'static'` field with a declared\n // `displayLocale` resolves its `<field>Label` even under a locale-less\n // read (mirrors staticDict's `hasStaticDisplay` gate).\n const hasStaticDisplay = fields.some(([, d]) => d.backing === 'static' && d.displayLocale !== undefined)\n if (!locale && !hasStaticDisplay) return record\n\n let result = record\n const withLabels = { ...result }\n\n for (const [field, desc] of fields) {\n const policy = desc.onMissing ? resolvePolicy(desc.onMissing, layer) : 'null'\n const fieldFallback = policy === 'substitute' ? (fallback ?? desc.substitute) : fallback\n const effLocale = locale ?? (desc.backing === 'static' ? desc.displayLocale : undefined)\n\n const resolveKey = async (key: string): Promise<string | null> => {\n if (!effLocale) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(field, `lookup \"${field}\": no locale active to resolve key \"${key}\".`)\n }\n return null\n }\n const label = await fetchLookupLabel(desc, key, effLocale, fieldFallback, cfg)\n if (label === undefined) {\n if (policy === 'throw') {\n throw new LocaleNotSpecifiedError(field, `lookup \"${field}\": no label for key \"${key}\" in locale \"${effLocale}\".`)\n }\n return null\n }\n return label\n }\n\n if (field.includes('[].')) {\n const parts = field.split('[].')\n const arrayKey = parts[0]!\n const leaf = parts[1]\n if (!leaf || leaf.includes('.')) continue\n const arr = (withLabels as Record<string, unknown>)[arrayKey]\n if (!Array.isArray(arr)) continue\n const labelKey = `${leaf}Label`\n ;(withLabels as Record<string, unknown>)[arrayKey] = await Promise.all(\n arr.map(async (el) => {\n if (!el || typeof el !== 'object' || Array.isArray(el)) return el\n const k = (el as Record<string, unknown>)[leaf]\n if (typeof k !== 'string') return el\n return { ...(el as Record<string, unknown>), [labelKey]: await resolveKey(k) }\n }),\n )\n continue\n }\n\n const val = result[field]\n if (Array.isArray(val)) {\n withLabels[`${field}Label`] = await Promise.all(\n val.map(async (k) => ({ key: k, label: typeof k === 'string' ? await resolveKey(k) : null })),\n )\n } else if (typeof val === 'string') {\n const label = await resolveKey(val)\n if (label !== null) withLabels[`${field}Label`] = label\n }\n }\n\n result = withLabels\n return result\n}\n\n/**\n * One field's `lookup` descriptor as it appears on a `ViaBinding.\n * describeFragment()` payload (#650 Task 7 — the first real consumer,\n * `with-shape/introspection/describe.ts`'s `buildDescription`, imports this\n * type directly; `describe.ts` is NOT under `kernel/**`, so it's free to\n * import concrete via/ types the way it already does for\n * `LookupDescriptor`/`MoneyDescriptor`/etc.). `dimension` is OMITTED (not\n * emitted as `''`) for a bare `enumOf()` descriptor — the #650 Task 2\n * `dimension:''` sentinel resolved: no dimension name means no `dimension`\n * key, not a meaningless empty string (T2 carry, #650 Task 7).\n */\nexport interface LookupDescribeFragmentEntry {\n readonly dimension?: string\n readonly backing: LookupBacking\n readonly vocabulary: Vocabulary\n readonly key: string\n readonly altKeys?: readonly string[]\n readonly present?: { readonly label: string; readonly by?: string }\n readonly sortBy?: string\n readonly onDelete: OnDelete\n /** Statically-known closed-vocabulary key set (declared `keys`, or a static table's own keys). Omitted when membership lives only in the backing collection/dictionary (open vocabulary, or closed with no declared `keys`). */\n readonly keys?: readonly string[]\n}\n\n/** The `'lookup'` binding's `describeFragment()` payload shape. */\nexport interface LookupDescribeFragment {\n readonly lookupFields: Record<string, LookupDescribeFragmentEntry>\n}\n\nfunction buildLookupDescribeFragment(cfg: LookupViaConfig): Record<string, unknown> {\n const lookupFields: Record<string, LookupDescribeFragmentEntry> = {}\n for (const [field, desc] of Object.entries(cfg.lookupFields)) {\n lookupFields[field] = {\n ...(desc.dimension !== '' ? { dimension: desc.dimension } : {}),\n backing: desc.backing,\n vocabulary: desc.vocabulary,\n key: desc.key,\n onDelete: desc.onDelete,\n ...(desc.altKeys !== undefined ? { altKeys: desc.altKeys } : {}),\n ...(desc.present !== undefined ? { present: desc.present } : {}),\n ...(desc.sortBy !== undefined ? { sortBy: desc.sortBy } : {}),\n // #657 — static tier: when no `keys` was explicitly declared but a\n // `table` was (the staticDict()-equivalent `lookup(dim, {backing:\n // 'static', table})` shape), the table's own key set IS the\n // statically-known closed-vocabulary set the DescribedField.lookup\n // docblock promises (\"declared `keys`, OR a static table's own\n // keys\"). Reserved/matrix tiers never carry `table`, so this branch\n // never fires for them — their `keys` emission is unchanged.\n ...(desc.keys !== undefined\n ? { keys: desc.keys }\n : desc.backing === 'static' && desc.table !== undefined ? { keys: Object.keys(desc.table) } : {}),\n }\n }\n return { lookupFields }\n}\n\n/**\n * `cfg.getAltIndex(desc)` (matrix tier) reads the backing collection's cache\n * via `querySourceForJoin()` (`buildLookupAltIndex`, registry.ts) — which\n * throws a `.join()`-branded message when that collection was opened\n * `{prefetch:false}` (lazy mode is unsupported for altKey normalization).\n * Normalization must never silently not happen (the banned silent-no-op\n * class, #650 Task 3 review, Important 2) — detect that specific failure\n * and surface a CLEAR, lookup-branded `ValidationError` at the point of\n * failure instead of letting the confusing join-branded one leak onto an\n * unrelated `put()`. Any OTHER error (e.g. `materializeBackingTable`'s own\n * altKey-collision `ValidationError`) propagates unchanged.\n */\nfunction getAltIndexOrThrow(field: string, desc: LookupDescriptor, cfg: LookupViaConfig): MaterializedBacking | undefined {\n try {\n return cfg.getAltIndex?.(desc)\n } catch (err) {\n if (err instanceof Error && err.message.includes('lazy-mode')) {\n throw new ValidationError(\n `lookup: altKeys on \"${field}\" require the backing collection \"${desc.dimension}\" to be ` +\n `prefetch-enabled (lazy mode unsupported); open it without {prefetch:false} or drop altKeys.`,\n )\n }\n throw err\n }\n}\n\n/**\n * `ingest` — altKey candidate values normalize to the canonical key (#650\n * Task 3, spec §3). Pure, sync, idempotent (a canonical key maps to\n * itself); no store read — consults the pre-materialized\n * `cfg.getAltIndex(desc)`. The money `canonicalizeIncomingMoney` precedent\n * (`via/index.ts:108`).\n *\n * A `[].`-wildcard multi-value path (`getAtPath` resolves >1 entries — an\n * array of nested objects, e.g. `'lines[].country'`, the same wildcard\n * convention `runLookupPresent` above already handles) normalizes EVERY\n * element's leaf value, not just a lone scalar (#652 fix — this used to bail\n * out entirely here while `runLookupEnforceWrite` below validated every\n * value unnormalized, so a legitimate altKey in an array position was\n * wrongly refused by closed-vocabulary enforcement). `setAtPathInPlace`\n * can't write into a `[].`-wildcard path, so the array is reconstructed\n * immutably instead, mirroring `runLookupPresent`'s own `field.includes\n * ('[].')` branch. A plain field whose OWN value is a bare top-level array\n * (not a `[].`-wildcard path) gets the SAME element-wise normalization\n * against `backing.altIndex` (#661 fix — `getAtPath` resolves it to one\n * opaque value, so the array itself is `values[0]`; a non-string element is\n * left untouched, mirroring the scalar branch's own `typeof !== 'string'`\n * skip — no parallel coercion invented for this shape).\n */\nfunction runLookupIngest(record: Record<string, unknown>, cfg: LookupViaConfig): Record<string, unknown> {\n const withAltKeys = Object.entries(cfg.lookupFields).filter(([, d]) => (d.altKeys?.length ?? 0) > 0)\n if (withAltKeys.length === 0) return record\n\n let result = record\n for (const [field, desc] of withAltKeys) {\n const backing = getAltIndexOrThrow(field, desc, cfg)\n if (!backing || backing.altIndex.size === 0) continue\n\n if (field.includes('[].')) {\n const [arrayKey, leaf] = field.split('[].')\n if (!leaf || leaf.includes('.')) continue\n const arr = record[arrayKey!]\n if (!Array.isArray(arr)) continue\n let changed = false\n const normalized = arr.map((item) => {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return item\n const value = (item as Record<string, unknown>)[leaf]\n if (typeof value !== 'string') return item\n const canonical = backing.altIndex.get(value)\n if (canonical === undefined || canonical === value) return item\n changed = true\n return { ...(item as Record<string, unknown>), [leaf]: canonical }\n })\n if (!changed) continue\n if (result === record) result = { ...record }\n result[arrayKey!] = normalized\n continue\n }\n\n const values = getAtPath(record, field)\n if (values.length !== 1) continue\n const value = values[0]\n\n // `getAtPath`/`setAtPathInPlace` resolve `field` generically, dotted\n // paths included (e.g. 'meta.tags') — do not rewrite this branch to a\n // direct `record[field]` bracket access, which would silently stop\n // normalizing/enforcing a dotted-non-wildcard bare-array field (#661).\n if (Array.isArray(value)) {\n if (value.length === 0) continue\n let changed = false\n const normalized = value.map((el) => {\n if (typeof el !== 'string') return el\n const canonical = backing.altIndex.get(el)\n if (canonical === undefined || canonical === el) return el\n changed = true\n return canonical\n })\n if (!changed) continue\n if (result === record) result = { ...record }\n setAtPathInPlace(result, field, normalized)\n continue\n }\n\n if (typeof value !== 'string') continue\n const canonical = backing.altIndex.get(value)\n if (canonical === undefined || canonical === value) continue\n if (result === record) result = { ...record }\n setAtPathInPlace(result, field, canonical)\n }\n return result\n}\n\n/**\n * `enforceWrite` — closed-vocabulary write refusal (#650 Task 3, spec §3).\n * Runs only for `vocabulary:'closed'` fields; `'open'` (the dictKey/dict\n * default) skips the check entirely, so #649's fix is additive — existing\n * dictKey/staticDict collections are unaffected. `ctx` carries no\n * cross-collection door (`id`/`vault`/`prior`/`emit` only, unchanged) —\n * membership is a vault-built closure on `cfg`, per spec.\n */\nasync function runLookupEnforceWrite(record: Record<string, unknown>, cfg: LookupViaConfig): Promise<void> {\n for (const [field, desc] of Object.entries(cfg.lookupFields)) {\n if (desc.vocabulary !== 'closed') continue\n // Checks every value `getAtPath` returns — for a `[].`-wildcard\n // multi-value path, that's every element's leaf value.\n // `runLookupIngest` above now normalizes each of those elements first\n // (#652), so what lands here for a `[].`-wildcard field is already\n // canonical; this loop's job stays membership, not normalization.\n for (const value of getAtPath(record, field)) {\n // A plain field whose OWN value is a bare top-level array (#661) —\n // `runLookupIngest` above has already normalized its elements'\n // altKeys, so membership-check each element through the SAME\n // `cfg.membership` closure the scalar branch below uses, refusing on\n // the first unknown one. A non-string element is skipped, mirroring\n // the scalar branch's own skip.\n if (Array.isArray(value)) {\n for (const el of value) {\n if (typeof el !== 'string') continue\n const known = cfg.membership ? await cfg.membership(field, el) : true\n if (!known) throw new UnknownLookupKeyError(desc.dimension, field, el)\n }\n continue\n }\n if (typeof value !== 'string') continue\n const known = cfg.membership ? await cfg.membership(field, value) : true\n if (!known) throw new UnknownLookupKeyError(desc.dimension, field, value)\n }\n }\n}\n\n/**\n * `compareForOrder` — exact ordering for a `sortBy`-declared lookup field\n * against the sync snapshot (#650 Task 6, spec §5, conflict resolution 4;\n * matrix-tier coverage added #650 Task 7). Opt-in: undeclared `sortBy`\n * (every dictKey/staticDict alias and every lookup field declared before\n * Task 6) returns `undefined` — falls through to the generic stored-value\n * comparator, byte-identical to today. Static tier reads `descriptor.table`\n * directly; reserved AND matrix (collection) tier both read `cfg.snapshotFor`\n * (the SAME live cache `presentForJoin`'s lookup half reads — see\n * `snapshot.ts`'s file header). The hook has no locale parameter\n * (`via/index.ts:128-129`, unchanged) — closes over the descriptor's own\n * `displayLocale` (the same locale-less-hinge default `runLookupPresent`\n * already uses); a `sortBy` field whose value isn't locale-keyed\n * (`present.by` undefined) never needs one. A `by`-keyed `sortBy` field\n * with NO declared `displayLocale` degrades to comparing the raw canonical\n * keys (silent — `LookupSnapshot.compareKeys` never throws; declare-time\n * warning at `descriptor.ts`'s `lookup()` factory; use\n * `orderBy(field, dir, {by:'label'})` — `resolveOrderLabel` below — for a\n * PER-CALL locale instead).\n */\nfunction compareLookupOrder(field: string, a: unknown, b: unknown, cfg: LookupViaConfig): number | undefined {\n if (typeof a !== 'string' || typeof b !== 'string') return undefined\n const desc = cfg.lookupFields[field]\n if (!desc || desc.sortBy === undefined) return undefined\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : cfg.snapshotFor?.(desc)\n if (!rows) return undefined\n return buildLookupSnapshot(desc.dimension, rows, desc).compareKeys(a, b, desc.displayLocale ?? '')\n}\n\n/**\n * `resolveOrderLabel` — per-key, PER-CALL-locale label resolution for\n * `orderBy(field, dir, { by: 'label' })` (#650 Task 7, spec §6 / seam map\n * Part 10 surprise 6's option (b)) — the channel `compareForOrder` above\n * structurally cannot serve, since `ViaBinding.compareForOrder` carries no\n * locale parameter. Consumed by `kernel/query/builder.ts`'s\n * `buildOrderLabelMaps` as the fallback for lookup fields the legacy dict\n * registries don't bridge (matrix tier; reserved/static tier already\n * resolves via that bridge — `JoinContext.resolveDictSource` — tried\n * FIRST by the caller, see `registry.ts`'s `collectLookupDictCompat` doc\n * comment). Reuses the exact same `cfg.snapshotFor`/`buildLookupSnapshot`\n * machinery as `compareLookupOrder` above, just with the per-call `locale`\n * in place of the descriptor's own `displayLocale` — falling back to\n * `displayLocale` only when the call itself is locale-less, the same\n * hinge order `runLookupPresent` already uses.\n */\nfunction resolveLookupOrderLabel(field: string, key: string, locale: string | undefined, cfg: LookupViaConfig): string | undefined {\n const desc = cfg.lookupFields[field]\n if (!desc) return undefined\n const rows = desc.backing === 'static'\n ? (desc.table ? new Map(Object.entries(desc.table)) : undefined)\n : cfg.snapshotFor?.(desc)\n if (!rows) return undefined\n return buildLookupSnapshot(desc.dimension, rows, desc).label(key, locale ?? desc.displayLocale ?? '')\n}\n\nexport function lookupBinding(cfg: LookupViaConfig): ViaBinding {\n return {\n brand: 'lookup',\n posture: { encryptedAtRest: 'envelope', queryable: 'full', exportable: true, forgettable: false },\n reservedPrefixes: ['_dict_', '_lookup_'],\n covers: (field) => field in cfg.lookupFields,\n ingest: (record) => runLookupIngest(record, cfg),\n enforceWrite: (record) => runLookupEnforceWrite(record, cfg),\n present: async (record, ctx) => runLookupPresent(record, ctx, cfg),\n compareForOrder: (field, a, b) => compareLookupOrder(field, a, b, cfg),\n resolveOrderLabel: (field, key, locale) => resolveLookupOrderLabel(field, key, locale, cfg),\n describeFragment: () => buildLookupDescribeFragment(cfg),\n }\n}\n\nexport function linkLookupVia(): void {\n installViaBinder('lookup', (c) => lookupBinding(c as LookupViaConfig))\n}\n","/**\n * `lookup()` / `enumOf()` / `dict()` descriptors — the three declaration\n * surfaces for the `'lookup'` via binding (#650 Task 2, phase D of the Via\n * port). One `LookupDescriptor` shape; the tiers are `backing` details:\n *\n * - `lookup(dimension, opts?)` — matrix tier: first-class collection backing\n * (default `backing:'collection'`) — a reference-collection dimension\n * (e.g. `countries`), open vocabulary by default.\n * - `enumOf(keys)` — enum tier: static in-config table, CLOSED\n * vocabulary, no backing store at all (no dimension name — pure inline\n * keys). Exported as `enumOf`; the barrel (`index.ts`) re-exports it as\n * `enum` (`enum` is a reserved word, so it can't be the function's own\n * name).\n * - `dict(dimension, opts?)` — dict tier: reserved `_dict_<dimension>`\n * micro-collection backing (the `vault.dictionary(name)` engine), open\n * vocabulary by default.\n *\n * Each factory calls {@link linkLookupVia} first — the declaration IS the\n * via binding's opt-in unit (#553), same pattern as `money()`/`i18nText()`/\n * `dictKey()`.\n */\n\nimport type { OnMissingPolicy } from '../i18n/policy.js'\nimport { linkLookupVia } from './binding.js'\n\n/** `'closed'` = enum semantics (membership enforced, Task 3); `'open'` permits unknown keys. */\nexport type Vocabulary = 'open' | 'closed'\n\n/** Where a dimension's rows live: static in-config table / reserved micro-collection / first-class collection. */\nexport type LookupBacking = 'static' | 'reserved' | 'collection'\n\n/** Delete-time referential policy for the backing dimension (default `'restrict'`, enforced in Task 5). */\nexport type OnDelete = 'restrict' | 'cascade' | 'nullify'\n\n/** The one descriptor shape every tier compiles to — tiers differ only by `backing`. */\nexport interface LookupDescriptor<Keys extends string = string> {\n readonly _viaBrand: 'lookup'\n /** Dimension/dictionary/target name. Empty for a bare `enumOf()` (no backing store, no name). */\n readonly dimension: string\n /** Canonical key field on the row (default `'id'`). */\n readonly key: string\n /** Candidate keys normalized to `key` on ingest (Task 3). */\n readonly altKeys?: readonly string[]\n readonly vocabulary: Vocabulary\n /** Dressing dimension: which backing-row field supplies `<field>Label`, optionally keyed `by` a sub-field (e.g. locale). */\n readonly present?: { readonly label: string; readonly by?: string }\n /** Field to sort by against the snapshot (Task 6). */\n readonly sortBy?: string\n readonly backing: LookupBacking\n readonly onDelete: OnDelete\n /** Static/enum inline key set. */\n readonly keys?: readonly Keys[]\n /** Static tier only: in-code `key -> { locale -> label }` table. */\n readonly table?: Readonly<Record<string, Readonly<Record<string, string>>>>\n /** Static hybrid hinge (the `staticDict` alias) — locale-less `<field>Label`. */\n readonly displayLocale?: string\n readonly onMissing?: OnMissingPolicy\n readonly substitute?: readonly string[]\n /** Inline display labels (value -> label), the dict-tier sync fallback (mirrors `dictKey`'s `labels`). */\n readonly labels?: Record<string, string>\n}\n\n/**\n * `sortBy`/`present.by` coupling warning (#650 Task 7, T6 minor — task-6-\n * report.md Concern #4). A `by`-keyed `present` (locale-map) field used as\n * `sortBy` needs a declared `displayLocale` for the locale-less\n * `compareForOrder` sort hook (a plain `orderBy(field)`, no `{by:'label'}`)\n * to resolve anything — without one it silently degrades to comparing the\n * raw canonical keys (never throws — `LookupSnapshot.compareKeys`'s\n * contract). `orderBy(field, dir, {by:'label'})` doesn't need this (it\n * carries its own per-call locale via `ViaBinding.resolveOrderLabel`,\n * #650 Task 7) — only a sortBy-driven PLAIN orderBy does. Warn once at\n * declare time rather than degrade silently at query time.\n */\nfunction warnIfSortByNeedsDisplayLocale(\n dimension: string,\n opts?: { sortBy?: string; present?: { by?: string }; displayLocale?: string },\n): void {\n if (opts?.sortBy !== undefined && opts.present?.by !== undefined && opts.displayLocale === undefined) {\n console.warn(\n `[noy-db] lookup(\"${dimension}\"): sortBy \"${opts.sortBy}\" is locale-keyed (present.by is set) but no ` +\n `displayLocale is declared — a locale-less orderBy() will silently sort by the raw stored key instead ` +\n `of the resolved label. Declare displayLocale, or sort via orderBy(field, dir, { by: 'label' }), which ` +\n `resolves at the query's own per-call locale.`,\n )\n }\n}\n\n/**\n * Matrix tier — first-class collection backing (default `backing:'collection'`).\n * `dimension` names the backing collection (e.g. `'countries'`).\n *\n * `backing` may be overridden to construct any tier through this one\n * factory — e.g. `lookup(name, { backing:'static', table, displayLocale })`\n * is the table-bearing static tier `staticDict()` compiles onto. The\n * `table`/`displayLocale`/`keys`/`onMissing`/`substitute`/`labels` options\n * are a superset of the brief's literal opts list: `LookupDescriptor`\n * already carries these fields for exactly this purpose, and without them\n * `backing:'static'` would be unreachable stand-alone through `lookup()`\n * (see task-2-report.md's \"Design decisions\").\n *\n * **`altKeys` caveat (matrix tier only)**: normalizing an altKey candidate\n * to its canonical `key` requires the backing `dimension` collection to be\n * open in EAGER mode (the default; `{ prefetch: false }` — lazy mode — is\n * unsupported). A `put()` on a field with `altKeys` whose backing collection\n * is lazy throws a `ValidationError` naming the field and dimension; open\n * the backing collection without `{ prefetch: false }`, or drop `altKeys`.\n */\nexport function lookup<Keys extends string>(\n dimension: string,\n opts?: {\n key?: string\n altKeys?: readonly string[]\n vocabulary?: Vocabulary\n present?: { label: string; by?: string }\n sortBy?: string\n backing?: LookupBacking\n onDelete?: OnDelete\n keys?: readonly Keys[]\n table?: Readonly<Record<string, Readonly<Record<string, string>>>>\n displayLocale?: string\n onMissing?: OnMissingPolicy\n substitute?: readonly string[]\n labels?: Record<string, string>\n },\n): LookupDescriptor<Keys> {\n linkLookupVia()\n warnIfSortByNeedsDisplayLocale(dimension, opts)\n return {\n _viaBrand: 'lookup',\n dimension,\n key: opts?.key ?? 'id',\n vocabulary: opts?.vocabulary ?? 'open',\n backing: opts?.backing ?? 'collection',\n onDelete: opts?.onDelete ?? 'restrict',\n ...(opts?.altKeys !== undefined ? { altKeys: opts.altKeys } : {}),\n ...(opts?.present !== undefined ? { present: opts.present } : {}),\n ...(opts?.sortBy !== undefined ? { sortBy: opts.sortBy } : {}),\n ...(opts?.keys !== undefined ? { keys: opts.keys } : {}),\n ...(opts?.table !== undefined ? { table: opts.table } : {}),\n ...(opts?.displayLocale !== undefined ? { displayLocale: opts.displayLocale } : {}),\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n ...(opts?.labels !== undefined ? { labels: opts.labels } : {}),\n }\n}\n\n/**\n * Enum tier — static in-config table, CLOSED vocabulary, no backing store.\n * No dimension name (pure inline keys) — `dimension` is `''`.\n */\nexport function enumOf<const Keys extends readonly string[]>(keys: Keys): LookupDescriptor<Keys[number]> {\n linkLookupVia()\n return {\n _viaBrand: 'lookup',\n dimension: '',\n key: 'id',\n vocabulary: 'closed',\n backing: 'static',\n onDelete: 'restrict',\n keys,\n }\n}\n\n/**\n * Dict tier — reserved `_dict_<dimension>` micro-collection backing (the\n * `vault.dictionary(dimension)` engine), open vocabulary by default. The\n * native equivalent of `dictKey()`.\n *\n * Unlike `lookup()`'s matrix tier, `dict()` has no `altKeys` option — its\n * `_dict_<dimension>` backing is the always-synchronous `LookupHandle`\n * write-through cache, never a `vault.collection()` that can be opened\n * `{ prefetch: false }`, so the matrix tier's lazy-mode altKeys restriction\n * does not apply here.\n */\nexport function dict<Keys extends string>(\n dimension: string,\n opts?: {\n keys?: readonly Keys[]\n vocabulary?: Vocabulary\n present?: { label: string; by?: string }\n onDelete?: OnDelete\n onMissing?: OnMissingPolicy\n substitute?: readonly string[]\n },\n): LookupDescriptor<Keys> {\n linkLookupVia()\n return {\n _viaBrand: 'lookup',\n dimension,\n key: 'id',\n vocabulary: opts?.vocabulary ?? 'open',\n backing: 'reserved',\n onDelete: opts?.onDelete ?? 'restrict',\n ...(opts?.keys !== undefined ? { keys: opts.keys } : {}),\n ...(opts?.present !== undefined ? { present: opts.present } : {}),\n ...(opts?.onMissing !== undefined ? { onMissing: opts.onMissing } : {}),\n ...(opts?.substitute !== undefined ? { substitute: opts.substitute } : {}),\n }\n}\n","/**\n * _sync_credentials reserved collection —\n *\n * Stores per-adapter OAuth tokens (and any other long-lived sync secrets) as\n * encrypted records inside the vault itself. Tokens are wrapped with the\n * compartment's own DEK, live on disk as ciphertext like any other record, and\n * are accessed only through the dedicated API in this module — never via\n * `vault.collection('_sync_credentials')`.\n *\n * Design decisions\n * ────────────────\n *\n * **Why a reserved collection, not a separate store?**\n * The compartment's existing encryption stack (AES-256-GCM + collection DEK)\n * is exactly the right primitive for protecting OAuth tokens at rest. Using a\n * separate store would require a new encryption surface, new adapter calls,\n * and a new backup/restore path — all of which already exist for collections.\n *\n * **Why not exposed as a regular collection?**\n * The same reason `_keyring` and `_ledger` aren't: they have invariants that\n * must be enforced (naming scheme, no cross-user leakage, no schema\n * validation, no history/ledger writes for privacy). Routing through a\n * dedicated API enforces those invariants.\n *\n * **Token lifecycle:**\n * - `putCredential(vault, adapterId, token)` — store or overwrite\n * - `getCredential(vault, adapterId)` — load and decrypt\n * - `deleteCredential(vault, adapterId)` — remove\n * - `listCredentials(vault)` — enumerate adapter IDs (not tokens)\n *\n * The `adapterId` is the record ID within the `_sync_credentials` collection.\n * It should be a stable, human-readable identifier for the adapter instance\n * (e.g. `'google-drive'`, `'dropbox'`, `'s3-prod'`).\n *\n * **ACL:** only `owner` and `admin` roles can read/write sync credentials.\n * Operators, viewers, and clients cannot call this API. The check is made\n * against the caller's keyring role at call time.\n */\n\nimport type { NoydbStore, EncryptedEnvelope } from '../kernel/types.js'\nimport { NOYDB_FORMAT_VERSION } from '../kernel/types.js'\nimport type { UnlockedKeyring } from '../with-party/team/keyring.js'\nimport { encrypt, openEnvelopeJson } from '../kernel/enclave/index.js'\nimport { ensureCollectionDEK } from '../with-party/team/keyring.js'\nimport { PermissionDeniedError } from '../kernel/errors.js'\n\n/**\n * The reserved collection name. Never collides with user collections.\n * Canonical definition lives in `reserved-secret-collections.ts` (shared with\n * the `vault.collection()` guard and grant DEK-propagation); re-exported here\n * for existing consumers.\n */\nexport { SYNC_CREDENTIALS_COLLECTION } from '../with-party/team/reserved-secret-collections.js'\nimport { SYNC_CREDENTIALS_COLLECTION } from '../with-party/team/reserved-secret-collections.js'\n\n// ─── Token types ──────────────────────────────────────────────────────\n\n/**\n * An OAuth/auth token stored in `_sync_credentials`.\n *\n * Fields mirror the OAuth2 token response shape. `customData` is an escape\n * hatch for adapter-specific secrets (API keys, connection strings, etc.)\n * that don't fit the OAuth2 shape.\n */\nexport interface SyncCredential {\n /** Stable identifier for the adapter instance (e.g. 'google-drive'). */\n readonly adapterId: string\n /** OAuth token type, usually 'Bearer'. */\n readonly tokenType: string\n /** The access token. Expires at `expiresAt` if set. */\n readonly accessToken: string\n /** Long-lived refresh token for renewing the access token. */\n readonly refreshToken?: string\n /** ISO timestamp when `accessToken` expires. Absent means \"no expiry\". */\n readonly expiresAt?: string\n /** Space-separated OAuth scopes. */\n readonly scopes?: string\n /** Adapter-specific opaque data (API keys, endpoints, etc.). */\n readonly customData?: Record<string, string>\n}\n\n// ─── Access check ─────────────────────────────────────────────────────\n\nfunction requireAdminAccess(keyring: UnlockedKeyring): void {\n // FR-6: custodian is INTENTIONALLY excluded. Sync credentials are the\n // firm's hosting/infrastructure secrets (OAuth tokens, connection strings) —\n // not the custodian's operational scope. A custodian operates the DATA but\n // must never mint or read transport credentials that could be used to\n // re-home or impersonate the firm's vault. Do NOT add 'custodian' here.\n if (keyring.role !== 'owner' && keyring.role !== 'admin') {\n throw new PermissionDeniedError(\n `Sync credentials require owner or admin role. Current role: \"${keyring.role}\"`,\n )\n }\n}\n\n// ─── Public API ────────────────────────────────────────────────────────\n\n/**\n * Store or overwrite a sync credential for the given adapter.\n *\n * The credential is encrypted with the `_sync_credentials` collection DEK\n * (auto-generated on first use). The record ID is the `adapterId`.\n *\n * Requires owner or admin role.\n */\nexport async function putCredential(\n adapter: NoydbStore,\n vault: string,\n keyring: UnlockedKeyring,\n credential: SyncCredential,\n): Promise<void> {\n requireAdminAccess(keyring)\n\n const getDek = await ensureCollectionDEK(adapter, vault, keyring)\n const dek = await getDek(SYNC_CREDENTIALS_COLLECTION)\n\n const { iv, data } = await encrypt(JSON.stringify(credential), dek)\n\n const existing = await adapter.get(vault, SYNC_CREDENTIALS_COLLECTION, credential.adapterId)\n const version = existing ? existing._v + 1 : 1\n\n const envelope: EncryptedEnvelope = {\n _noydb: NOYDB_FORMAT_VERSION,\n _v: version,\n _ts: new Date().toISOString(),\n _iv: iv,\n _data: data,\n _by: keyring.userId,\n }\n\n await adapter.put(\n vault,\n SYNC_CREDENTIALS_COLLECTION,\n credential.adapterId,\n envelope,\n existing ? existing._v : undefined,\n )\n}\n\n/**\n * Load and decrypt a sync credential for the given adapter ID.\n *\n * Returns `null` if no credential exists for this adapter.\n * Requires owner or admin role.\n */\nexport async function getCredential(\n adapter: NoydbStore,\n vault: string,\n keyring: UnlockedKeyring,\n adapterId: string,\n): Promise<SyncCredential | null> {\n requireAdminAccess(keyring)\n\n const getDek = await ensureCollectionDEK(adapter, vault, keyring)\n const dek = await getDek(SYNC_CREDENTIALS_COLLECTION)\n\n const envelope = await adapter.get(vault, SYNC_CREDENTIALS_COLLECTION, adapterId)\n if (!envelope) return null\n\n const plaintext = await openEnvelopeJson(envelope, dek)\n return JSON.parse(plaintext) as SyncCredential\n}\n\n/**\n * Delete a sync credential by adapter ID.\n *\n * No-op if the credential doesn't exist. Requires owner or admin role.\n */\nexport async function deleteCredential(\n adapter: NoydbStore,\n vault: string,\n keyring: UnlockedKeyring,\n adapterId: string,\n): Promise<void> {\n requireAdminAccess(keyring)\n await adapter.delete(vault, SYNC_CREDENTIALS_COLLECTION, adapterId)\n}\n\n/**\n * List all adapter IDs that have stored credentials.\n *\n * Returns only the IDs, never the credential payloads. Useful for\n * displaying \"connected adapters\" in UI without decrypting tokens.\n * Requires owner or admin role.\n */\nexport async function listCredentials(\n adapter: NoydbStore,\n vault: string,\n keyring: UnlockedKeyring,\n): Promise<string[]> {\n requireAdminAccess(keyring)\n return adapter.list(vault, SYNC_CREDENTIALS_COLLECTION)\n}\n\n/**\n * Check whether a credential exists and whether its access token has expired.\n *\n * Returns `{ exists: false }` if no credential is stored, or\n * `{ exists: true, expired: boolean }` based on the `expiresAt` field.\n * Requires owner or admin role.\n */\nexport async function credentialStatus(\n adapter: NoydbStore,\n vault: string,\n keyring: UnlockedKeyring,\n adapterId: string,\n): Promise<{ exists: false } | { exists: true; expired: boolean }> {\n const credential = await getCredential(adapter, vault, keyring, adapterId)\n if (!credential) return { exists: false }\n\n const expired = credential.expiresAt\n ? Date.now() > new Date(credential.expiresAt).getTime()\n : false\n\n return { exists: true, expired }\n}\n"],"mappings":"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","names":["value","canonical","known"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  dumpVaultSchema
3
- } from "../chunk-ZWBKDKXC.js";
3
+ } from "../chunk-467SWYT5.js";
4
4
  import {
5
5
  applyListProjection
6
6
  } from "../chunk-VG2ZSFYD.js";
@@ -9,15 +9,15 @@ import {
9
9
  } from "../chunk-VYYM3MEN.js";
10
10
  import "../chunk-6ZNSB3H6.js";
11
11
  import "../chunk-Y2NBBT6K.js";
12
- import "../chunk-OBPVWOSQ.js";
13
- import "../chunk-RZPOZPZU.js";
14
- import "../chunk-VH6SOCXH.js";
12
+ import "../chunk-KD4HGBJV.js";
13
+ import "../chunk-SU6SGWXM.js";
14
+ import "../chunk-EFJAAFBW.js";
15
15
  import "../chunk-35NMVJ7I.js";
16
16
  import "../chunk-NFZGZ4AK.js";
17
17
  import "../chunk-QJNCB5SK.js";
18
18
  import "../chunk-LP7BEXCT.js";
19
19
  import "../chunk-AKKRXT23.js";
20
- import "../chunk-GZACYEOB.js";
20
+ import "../chunk-77AEMXFA.js";
21
21
  import "../chunk-QZWTRENR.js";
22
22
  import "../chunk-PZ5AY32C.js";
23
23
  export {
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  issueAttestationCore
3
- } from "./chunk-DGBIHDVK.js";
4
- import "./chunk-DZAF24PG.js";
3
+ } from "./chunk-RBTVFPHF.js";
4
+ import "./chunk-IFOH7RBI.js";
5
5
  import "./chunk-ZJADGNYF.js";
6
- import "./chunk-RZPOZPZU.js";
7
- import "./chunk-VH6SOCXH.js";
6
+ import "./chunk-SU6SGWXM.js";
7
+ import "./chunk-EFJAAFBW.js";
8
8
  import "./chunk-35NMVJ7I.js";
9
9
  import "./chunk-NFZGZ4AK.js";
10
10
  import "./chunk-QJNCB5SK.js";
11
11
  import "./chunk-LP7BEXCT.js";
12
12
  import "./chunk-AKKRXT23.js";
13
- import "./chunk-GZACYEOB.js";
13
+ import "./chunk-77AEMXFA.js";
14
14
  import "./chunk-QZWTRENR.js";
15
15
  import "./chunk-PZ5AY32C.js";
16
16
  export {
17
17
  issueAttestationCore
18
18
  };
19
- //# sourceMappingURL=issue-55HJE7JF.js.map
19
+ //# sourceMappingURL=issue-LIA7FXBJ.js.map
@@ -1,4 +1,5 @@
1
1
  import type { EncryptedEnvelope, HistoryOptions, HistoryEntry, PruneOptions, LocaleReadOptions, PutManyItemOptions, PutManyOptions, PutManyResult, DeleteManyResult, SealedView, ClassifiedVerdict } from './types.js';
2
+ import type { PreparedPut, PreparedDelete } from './prepared-write.js';
2
3
  import type { FieldMeta } from '../with-shape/introspection/field-meta.js';
3
4
  import type { CollectionMeta } from '../with-shape/introspection/meta.js';
4
5
  import { type ClassifiedEntry } from '../port/with/classified-strategy.js';
@@ -24,7 +25,7 @@ import type { RetrieveOptions, RetrieveHit } from '../with-lookup/search/retriev
24
25
  import { type CollectionDescription, type DescribeOptions } from '../with-shape/introspection/describe.js';
25
26
  import type { CollectionConfig } from '../with-shape/introspection/types.js';
26
27
  import { type LruStats } from './cache/index.js';
27
- import type { PresenceHandle } from '../with-party/team/presence.js';
28
+ import type { PresenceHandle } from '../with-sync/presence.js';
28
29
  import type { BlobSet } from '../with-shape/blobs/blob-set.js';
29
30
  import type { TxContext } from '../with-commit/tx/transaction.js';
30
31
  import { type CollectionOpts } from './collection-config.js';
@@ -116,7 +117,7 @@ export declare class Collection<T, S extends keyof T = never, Q extends keyof T
116
117
  * re-create version-continuity gate in `_putInternal` read the store ONLY
117
118
  * for a known marker prior, instead of unconditionally on every insert.
118
119
  * Populated on hydration (`ensureHydrated`/`hydrateFromSnapshot`), local
119
- * delete (`_doDelete`), and the sync/tab/cutover choke point
120
+ * delete (`_commitDelete`), and the sync/tab/cutover choke point
120
121
  * (`_invalidateCacheEntry`). Accepted drift: `vault._purgeDeleteMarkers`/
121
122
  * `_purgeMarkersOn` remove markers directly on the raw store, bypassing
122
123
  * Collection, so this set can hold stale ids after a purge on an
@@ -666,6 +667,44 @@ export declare class Collection<T, S extends keyof T = never, Q extends keyof T
666
667
  */
667
668
  private _toCacheableRecord;
668
669
  private _putInternal;
670
+ /**
671
+ * Prepare half of the ordinary (non-CRDT) write (#893/#904): run every
672
+ * pre-envelope stage, resolve the prior version, and produce the encrypted
673
+ * envelope — with ZERO observable side effects. No store write, no cache or
674
+ * index mutation, no history entry, no ledger append, no event. It may READ
675
+ * the store (gate prior, lazy prior, vdig prior) and it may THROW; refusing
676
+ * a write before anything commits is precisely its job.
677
+ *
678
+ * Pairs with {@link _commitPut}. Split out so a batch can prepare every op,
679
+ * submit ONE `store.tx()`, then finalize each op.
680
+ *
681
+ * @internal
682
+ */
683
+ _preparePut(id: string, record: T, options?: {
684
+ readonly reason?: string;
685
+ readonly source?: string;
686
+ readonly sourceTs?: string;
687
+ }): Promise<PreparedPut<T>>;
688
+ /**
689
+ * Commit half (#893/#904): the only place an ordinary put becomes
690
+ * observable — history snapshot of the prior version, store write, marker
691
+ * clear, then the shared write tail.
692
+ *
693
+ * History still runs BEFORE the store write, so a history failure leaves no
694
+ * write behind. It now runs AFTER `encryptRecord` rather than before it —
695
+ * the split's one sanctioned reorder, which also stops an encrypt failure
696
+ * from leaving an orphan snapshot behind.
697
+ *
698
+ * @internal `persist: false` skips the `adapter.put` — see {@link _finalizePut}.
699
+ */
700
+ _commitPut(prepared: PreparedPut<T>, persist?: boolean): Promise<void>;
701
+ /**
702
+ * {@link _commitPut} minus the `adapter.put`: the store already holds this
703
+ * envelope because it was written as one leg of a `store.tx()` batch.
704
+ *
705
+ * @internal
706
+ */
707
+ _finalizePut(prepared: PreparedPut<T>): Promise<void>;
669
708
  /**
670
709
  * Fire registered MV strategies whose dependency set includes this
671
710
  * collection. Eager-mode MVs re-materialize inline via
@@ -781,6 +820,52 @@ export declare class Collection<T, S extends keyof T = never, Q extends keyof T
781
820
  */
782
821
  _internalDelete(id: string, txCtx?: TxContext | null): Promise<boolean>;
783
822
  private _doDelete;
823
+ /**
824
+ * Prepare half of the delete (#893/#905): every refusal (write permission,
825
+ * tier, the beforeDelete gate bus, foreign-key refs), the prior-version
826
+ * resolution, the pre-delete payload hash, and the #589 marker DECISION —
827
+ * the marker is minted here but NOT written.
828
+ *
829
+ * Commits nothing of its own: no store write, no history entry, no ledger
830
+ * append, no cache/index mutation, no event, no `markerIds` entry. It READS
831
+ * the store and it may THROW — refusing a delete before anything commits is
832
+ * precisely its job. `null` is the "nothing to delete" answer that the early
833
+ * `return false` paths gave: no live record, an already-shredded tombstone,
834
+ * an existing marker, or the #718 elevated-internal skip.
835
+ *
836
+ * ONE exception to that guarantee: on a collection with `cascade` inbound
837
+ * refs, prepare itself deletes the referencing children (via
838
+ * `enforceRefsOnDelete`, as it always has) — prepare is NOT abortable there.
839
+ * The transaction atomic path must never call this on such a collection; its
840
+ * eligibility gate excludes refs-bearing collections.
841
+ *
842
+ * Pairs with {@link _commitDelete}. A deliberately separate split from the
843
+ * put pair (#842c) — delete differs in hydration, in the history-read gate
844
+ * and in the marker rules.
845
+ *
846
+ * @internal
847
+ */
848
+ _prepareDelete(id: string, internal: boolean): Promise<PreparedDelete<T> | null>;
849
+ /**
850
+ * Commit half (#893/#905): the only place a delete becomes observable —
851
+ * history snapshot of the deleted version, the store write (the #589 marker
852
+ * put, or the physical removal when sync is off), then the ledger entry,
853
+ * cache/index teardown, the mutation event, and the user-initiated
854
+ * derivation dispatch.
855
+ *
856
+ * History still runs BEFORE the store write, exactly as today, so a history
857
+ * failure leaves no delete behind.
858
+ *
859
+ * @internal `persist: false` skips the store write — see {@link _finalizeDelete}.
860
+ */
861
+ _commitDelete(prepared: PreparedDelete<T>, persist?: boolean): Promise<boolean>;
862
+ /**
863
+ * {@link _commitDelete} minus the store write: the marker (or the removal)
864
+ * already landed as one leg of a `store.tx()` batch.
865
+ *
866
+ * @internal
867
+ */
868
+ _finalizeDelete(prepared: PreparedDelete<T>): Promise<boolean>;
784
869
  /**
785
870
  * @internal — GDPR crypto-shred a LIVE record to a tombstone.
786
871
  *
@@ -1489,6 +1574,8 @@ export declare class Collection<T, S extends keyof T = never, Q extends keyof T
1489
1574
  i18nFields: Record<string, I18nTextDescriptor> | undefined;
1490
1575
  lookupFields: Record<string, LookupDescriptor> | undefined;
1491
1576
  };
1577
+ _assertWriteGates(): Promise<void>;
1578
+ _txAtomicSafe(opType: 'put' | 'delete'): boolean;
1492
1579
  _reconcileReadState(patch: {
1493
1580
  dictKeyFields?: Record<string, DictKeyDescriptor | StaticDictDescriptor>;
1494
1581
  i18nFields?: Record<string, I18nTextDescriptor>;
@@ -4,6 +4,17 @@
4
4
  * See the plaintext/debug-store-mode design.
5
5
  */
6
6
  import type { EncryptedEnvelope } from './types.js';
7
+ /**
8
+ * The option's two failure modes, re-exported here so a consumer can `catch`
9
+ * them by identity (#914). Both are thrown from the kernel — `createNoydb`
10
+ * raises `DebugPlaintextError` when `debugPlaintext` is combined with
11
+ * encryption, and the record codec raises `DebugReservedFieldError` for a
12
+ * field colliding with the `_`-prefixed metadata. This entry is the only one
13
+ * that publishes them.
14
+ */
15
+ export { DebugPlaintextError, DebugReservedFieldError } from './errors.js';
16
+ /** Re-exported so `readPlaintextRecord`'s parameter is nameable from this entry. */
17
+ export type { EncryptedEnvelope } from './types.js';
7
18
  /**
8
19
  * Extract the record from a plaintext stored envelope, handling both layouts:
9
20
  *
@@ -9,10 +9,10 @@ import type { VaultMeta } from '../with-shape/introspection/meta.js';
9
9
  import { WriteQueueTracker, type WriteQueue } from './write-queue.js';
10
10
  import { WriteHookRegistry, type WriteHook, type Unsubscribe } from '../port/with/write-hooks.js';
11
11
  import { ServiceBus } from '../port/with/service-bus.js';
12
- import { type TabCoordinationOptions, type TabRole, type TabPresence } from '../with-party/tab-coordination.js';
12
+ import { type TabCoordinationOptions, type TabRole, type TabPresence } from '../with-sync/tab-coordination.js';
13
13
  import type { UnlockedKeyring } from '../with-party/team/keyring.js';
14
- import type { SyncEngine } from '../with-party/team/sync.js';
15
- import type { SyncTransaction } from '../with-party/team/sync-transaction.js';
14
+ import type { SyncEngine } from '../with-sync/engine.js';
15
+ import type { SyncTransaction } from '../with-sync/transaction.js';
16
16
  import { type SnapshotMeta } from '../with-fork/snapshots/strategy.js';
17
17
  import type { AmendmentTxOptions } from '../with-commit/tx/transaction.js';
18
18
  import { TxContext } from '../with-commit/tx/transaction.js';
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Carrier types for the prepare/commit write split (#893, #904, #905).
3
+ *
4
+ * `Collection._preparePut` runs every pre-envelope stage and stops holding an
5
+ * encrypted envelope with ZERO observable side effects; `_commitPut` (or
6
+ * `_finalizePut`, when the store already persisted the bytes inside a
7
+ * `store.tx()`) turns that into a committed write. Everything the commit half
8
+ * still needs from the prepare half travels in the structures below.
9
+ *
10
+ * Type-only by design — this module erases at runtime and stays out of the
11
+ * kernel-surface line budget.
12
+ */
13
+ import type { EncryptedEnvelope } from './types.js';
14
+ import type { EnclaveKey } from './enclave/index.js';
15
+ /** @internal Everything `_commitPut` needs after `_preparePut` produced the envelope. */
16
+ export interface PreparedPut<T> {
17
+ readonly id: string;
18
+ readonly envelope: EncryptedEnvelope;
19
+ readonly version: number;
20
+ /** Record as caches/indexes/ledger-delta see it. */
21
+ readonly indexed: T;
22
+ /** Record as `_onRecordMutated` reports it (drives events). */
23
+ readonly event: T;
24
+ readonly prior: {
25
+ record: T;
26
+ version: number;
27
+ } | undefined;
28
+ readonly cek: EnclaveKey | undefined;
29
+ readonly vdigCtx: {
30
+ id: string;
31
+ prev: EncryptedEnvelope | null;
32
+ } | undefined;
33
+ readonly reason: string | undefined;
34
+ }
35
+ /**
36
+ * @internal Everything `_commitDelete` needs after `_prepareDelete` decided the
37
+ * delete goes ahead (#905). A deliberately separate carrier from
38
+ * {@link PreparedPut}: the delete path differs in hydration, in the
39
+ * history-read gate, and in the #589 marker rules.
40
+ */
41
+ export interface PreparedDelete<T> {
42
+ readonly id: string;
43
+ /** System-internal delete — skips the user-facing MV/derivation/rollup dispatch. */
44
+ readonly internal: boolean;
45
+ /** Prior live version, for the history snapshot / ledger version / index teardown. */
46
+ readonly existing: {
47
+ record: T;
48
+ version: number;
49
+ } | undefined;
50
+ /** Payload hash of the pre-delete envelope, captured for the ledger entry. */
51
+ readonly previousPayloadHash: string;
52
+ /**
53
+ * History-snapshot key material, resolved from the LIVE envelope before any
54
+ * write — `_finalizeDelete` runs once the marker/removal already landed, and
55
+ * a marker carries no `_cek` (re-resolving would mint a fresh key) and no
56
+ * `_vdig` (re-reading would chain the digest off the marker). Both are
57
+ * `undefined` when no snapshot will be written.
58
+ */
59
+ readonly cek: EnclaveKey | undefined;
60
+ readonly vdigCtx: {
61
+ id: string;
62
+ prev: EncryptedEnvelope | null;
63
+ } | undefined;
64
+ /**
65
+ * #589 delete marker, minted at `live._v + 1` but NOT yet written. Present
66
+ * only under sync (`onDirty`); `undefined` means the delete is a physical
67
+ * `adapter.delete`.
68
+ */
69
+ readonly marker: EncryptedEnvelope | undefined;
70
+ }