@nicia-ai/typegraph 0.46.2 → 0.48.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 (310) hide show
  1. package/README.md +20 -1
  2. package/dist/backend/drizzle/indexes.cjs +9 -9
  3. package/dist/backend/drizzle/indexes.d.cts +1 -1
  4. package/dist/backend/drizzle/indexes.d.ts +1 -1
  5. package/dist/backend/drizzle/indexes.js +5 -5
  6. package/dist/backend/index.cjs +58 -49
  7. package/dist/backend/index.d.cts +37 -55
  8. package/dist/backend/index.d.ts +37 -55
  9. package/dist/backend/index.js +11 -10
  10. package/dist/backend/postgres/index.cjs +27 -26
  11. package/dist/backend/postgres/index.d.cts +21 -7
  12. package/dist/backend/postgres/index.d.ts +21 -7
  13. package/dist/backend/postgres/index.js +14 -13
  14. package/dist/backend/postgres/pglite-store.cjs +34 -33
  15. package/dist/backend/postgres/pglite-store.cjs.map +1 -1
  16. package/dist/backend/postgres/pglite-store.d.cts +8 -8
  17. package/dist/backend/postgres/pglite-store.d.ts +8 -8
  18. package/dist/backend/postgres/pglite-store.js +30 -29
  19. package/dist/backend/postgres/pglite-store.js.map +1 -1
  20. package/dist/backend/postgres/pglite.cjs +16 -15
  21. package/dist/backend/postgres/pglite.d.cts +3 -3
  22. package/dist/backend/postgres/pglite.d.ts +3 -3
  23. package/dist/backend/postgres/pglite.js +15 -14
  24. package/dist/backend/sqlite/index.cjs +24 -23
  25. package/dist/backend/sqlite/index.d.cts +20 -7
  26. package/dist/backend/sqlite/index.d.ts +20 -7
  27. package/dist/backend/sqlite/index.js +12 -11
  28. package/dist/backend/sqlite/libsql.cjs +19 -18
  29. package/dist/backend/sqlite/libsql.cjs.map +1 -1
  30. package/dist/backend/sqlite/libsql.d.cts +3 -3
  31. package/dist/backend/sqlite/libsql.d.ts +3 -3
  32. package/dist/backend/sqlite/libsql.js +14 -13
  33. package/dist/backend/sqlite/libsql.js.map +1 -1
  34. package/dist/backend/sqlite/local-store.cjs +35 -34
  35. package/dist/backend/sqlite/local-store.cjs.map +1 -1
  36. package/dist/backend/sqlite/local-store.d.cts +8 -8
  37. package/dist/backend/sqlite/local-store.d.ts +8 -8
  38. package/dist/backend/sqlite/local-store.js +31 -30
  39. package/dist/backend/sqlite/local-store.js.map +1 -1
  40. package/dist/backend/sqlite/local.cjs +17 -16
  41. package/dist/backend/sqlite/local.d.cts +3 -3
  42. package/dist/backend/sqlite/local.d.ts +3 -3
  43. package/dist/backend/sqlite/local.js +15 -14
  44. package/dist/{chunk-TCT66A7N.cjs → chunk-26YKDNUD.cjs} +10 -10
  45. package/dist/{chunk-TCT66A7N.cjs.map → chunk-26YKDNUD.cjs.map} +1 -1
  46. package/dist/{chunk-E4OSGBCM.cjs → chunk-2HIYYMWY.cjs} +139 -136
  47. package/dist/chunk-2HIYYMWY.cjs.map +1 -0
  48. package/dist/chunk-2QGYQBS2.cjs +161 -0
  49. package/dist/chunk-2QGYQBS2.cjs.map +1 -0
  50. package/dist/{chunk-GWXXHOLU.js → chunk-2SYZXD54.js} +21 -18
  51. package/dist/chunk-2SYZXD54.js.map +1 -0
  52. package/dist/{chunk-KA4L2NZ3.js → chunk-2TYSSBU5.js} +14 -14
  53. package/dist/{chunk-KA4L2NZ3.js.map → chunk-2TYSSBU5.js.map} +1 -1
  54. package/dist/{chunk-QOJ2L2AD.js → chunk-3DMMGT6S.js} +3 -3
  55. package/dist/{chunk-QOJ2L2AD.js.map → chunk-3DMMGT6S.js.map} +1 -1
  56. package/dist/{chunk-F36KZDFX.cjs → chunk-3FPR224C.cjs} +91 -91
  57. package/dist/{chunk-F36KZDFX.cjs.map → chunk-3FPR224C.cjs.map} +1 -1
  58. package/dist/{chunk-32UETY6S.cjs → chunk-3KOY4FH3.cjs} +207 -28
  59. package/dist/chunk-3KOY4FH3.cjs.map +1 -0
  60. package/dist/{chunk-QU7QLJA4.cjs → chunk-3U5ABFDW.cjs} +26 -26
  61. package/dist/{chunk-QU7QLJA4.cjs.map → chunk-3U5ABFDW.cjs.map} +1 -1
  62. package/dist/{chunk-RFDEYLIK.js → chunk-4WMMBDS5.js} +7 -7
  63. package/dist/chunk-4WMMBDS5.js.map +1 -0
  64. package/dist/{chunk-R7EWHKID.js → chunk-5K2BKEBD.js} +19 -145
  65. package/dist/chunk-5K2BKEBD.js.map +1 -0
  66. package/dist/chunk-5PRKMB24.cjs +124 -0
  67. package/dist/chunk-5PRKMB24.cjs.map +1 -0
  68. package/dist/chunk-6LN7FIVU.js +107 -0
  69. package/dist/chunk-6LN7FIVU.js.map +1 -0
  70. package/dist/{chunk-D6GCNNMK.cjs → chunk-6NGW27EO.cjs} +10 -10
  71. package/dist/{chunk-D6GCNNMK.cjs.map → chunk-6NGW27EO.cjs.map} +1 -1
  72. package/dist/{chunk-WHS2Y43J.js → chunk-6SWPJEYN.js} +5 -5
  73. package/dist/{chunk-WHS2Y43J.js.map → chunk-6SWPJEYN.js.map} +1 -1
  74. package/dist/{chunk-7TKNK32B.js → chunk-7SQSZN2J.js} +5 -5
  75. package/dist/{chunk-7TKNK32B.js.map → chunk-7SQSZN2J.js.map} +1 -1
  76. package/dist/{chunk-UTVQPZPN.cjs → chunk-7XUYFFR4.cjs} +20 -20
  77. package/dist/chunk-7XUYFFR4.cjs.map +1 -0
  78. package/dist/{chunk-KXSMF6PL.js → chunk-ACGSAMD3.js} +39 -34
  79. package/dist/chunk-ACGSAMD3.js.map +1 -0
  80. package/dist/{chunk-PYKF7UIL.cjs → chunk-AOSSQDVO.cjs} +13 -13
  81. package/dist/{chunk-PYKF7UIL.cjs.map → chunk-AOSSQDVO.cjs.map} +1 -1
  82. package/dist/{chunk-AT3MLMJV.js → chunk-AX6JGVTZ.js} +91 -20
  83. package/dist/chunk-AX6JGVTZ.js.map +1 -0
  84. package/dist/{chunk-WA64ZSCA.cjs → chunk-BFUOME67.cjs} +11 -11
  85. package/dist/{chunk-WA64ZSCA.cjs.map → chunk-BFUOME67.cjs.map} +1 -1
  86. package/dist/{chunk-YQ4JONWE.js → chunk-BRRP76WO.js} +401 -131
  87. package/dist/chunk-BRRP76WO.js.map +1 -0
  88. package/dist/{chunk-FCIZNUW5.js → chunk-CHAOFCHV.js} +3 -3
  89. package/dist/{chunk-FCIZNUW5.js.map → chunk-CHAOFCHV.js.map} +1 -1
  90. package/dist/chunk-CICO5GXD.cjs +12 -0
  91. package/dist/{chunk-73MWKDFK.cjs.map → chunk-CICO5GXD.cjs.map} +1 -1
  92. package/dist/{chunk-S3G5VLSW.js → chunk-CT3ZKTOF.js} +7 -6
  93. package/dist/chunk-CT3ZKTOF.js.map +1 -0
  94. package/dist/{chunk-SXWLLQ3D.js → chunk-D5R42W5D.js} +4 -4
  95. package/dist/{chunk-SXWLLQ3D.js.map → chunk-D5R42W5D.js.map} +1 -1
  96. package/dist/{chunk-BZZI7B43.cjs → chunk-DO7SAMEK.cjs} +47 -47
  97. package/dist/{chunk-BZZI7B43.cjs.map → chunk-DO7SAMEK.cjs.map} +1 -1
  98. package/dist/chunk-DZAICA5J.js +147 -0
  99. package/dist/chunk-DZAICA5J.js.map +1 -0
  100. package/dist/{chunk-2ZWM2RFH.cjs → chunk-EDN4Y4ZG.cjs} +9 -9
  101. package/dist/{chunk-2ZWM2RFH.cjs.map → chunk-EDN4Y4ZG.cjs.map} +1 -1
  102. package/dist/{chunk-A4R3H7RU.cjs → chunk-EZEEWCFJ.cjs} +264 -361
  103. package/dist/chunk-EZEEWCFJ.cjs.map +1 -0
  104. package/dist/{chunk-BEB4OFZF.cjs → chunk-FA2AFWLP.cjs} +51 -59
  105. package/dist/chunk-FA2AFWLP.cjs.map +1 -0
  106. package/dist/{chunk-ZBVZ7HXD.cjs → chunk-FQPEMEWX.cjs} +12 -12
  107. package/dist/{chunk-ZBVZ7HXD.cjs.map → chunk-FQPEMEWX.cjs.map} +1 -1
  108. package/dist/{chunk-LNIWCQR4.js → chunk-GLHXM7C4.js} +3 -3
  109. package/dist/{chunk-LNIWCQR4.js.map → chunk-GLHXM7C4.js.map} +1 -1
  110. package/dist/{chunk-6BD6ZBKT.cjs → chunk-GYEG3ZLZ.cjs} +10 -10
  111. package/dist/{chunk-6BD6ZBKT.cjs.map → chunk-GYEG3ZLZ.cjs.map} +1 -1
  112. package/dist/{chunk-A7NMUYEL.cjs → chunk-HDL2ARHX.cjs} +27 -27
  113. package/dist/{chunk-A7NMUYEL.cjs.map → chunk-HDL2ARHX.cjs.map} +1 -1
  114. package/dist/{chunk-5ZJOB5YS.js → chunk-HEV35TGT.js} +4 -4
  115. package/dist/{chunk-5ZJOB5YS.js.map → chunk-HEV35TGT.js.map} +1 -1
  116. package/dist/{chunk-LHYSY6SE.js → chunk-I4GAZH5Z.js} +186 -9
  117. package/dist/chunk-I4GAZH5Z.js.map +1 -0
  118. package/dist/{chunk-BQM5P2NO.cjs → chunk-JB6T4GLL.cjs} +260 -223
  119. package/dist/chunk-JB6T4GLL.cjs.map +1 -0
  120. package/dist/{chunk-QPOQX2DI.cjs → chunk-JFRT7S3B.cjs} +1026 -369
  121. package/dist/chunk-JFRT7S3B.cjs.map +1 -0
  122. package/dist/{chunk-JCNTKRAK.js → chunk-JONXFAPO.js} +5 -5
  123. package/dist/{chunk-JCNTKRAK.js.map → chunk-JONXFAPO.js.map} +1 -1
  124. package/dist/{chunk-WEJHA7AD.js → chunk-KF6K7TGH.js} +109 -75
  125. package/dist/chunk-KF6K7TGH.js.map +1 -0
  126. package/dist/{chunk-EDJDDY6H.js → chunk-KKBDXCLQ.js} +4 -4
  127. package/dist/{chunk-EDJDDY6H.js.map → chunk-KKBDXCLQ.js.map} +1 -1
  128. package/dist/{chunk-ZHOAZD7Q.cjs → chunk-L3LQNR34.cjs} +161 -161
  129. package/dist/{chunk-ZHOAZD7Q.cjs.map → chunk-L3LQNR34.cjs.map} +1 -1
  130. package/dist/{chunk-AF3TWL5C.cjs → chunk-LRQKXRXO.cjs} +4 -4
  131. package/dist/{chunk-AF3TWL5C.cjs.map → chunk-LRQKXRXO.cjs.map} +1 -1
  132. package/dist/chunk-MKJ4KXL5.cjs +12 -0
  133. package/dist/{chunk-6LAXM4J2.cjs.map → chunk-MKJ4KXL5.cjs.map} +1 -1
  134. package/dist/{chunk-KCH7WQA5.cjs → chunk-MRDBBHIZ.cjs} +48 -2
  135. package/dist/chunk-MRDBBHIZ.cjs.map +1 -0
  136. package/dist/{chunk-FXNHZFZV.js → chunk-MYKHJI2J.js} +3 -3
  137. package/dist/{chunk-FXNHZFZV.js.map → chunk-MYKHJI2J.js.map} +1 -1
  138. package/dist/{chunk-Z43KWLZF.js → chunk-NACVVDWB.js} +213 -12
  139. package/dist/chunk-NACVVDWB.js.map +1 -0
  140. package/dist/{chunk-72WUT4GG.js → chunk-NVY5CJFP.js} +4 -4
  141. package/dist/{chunk-72WUT4GG.js.map → chunk-NVY5CJFP.js.map} +1 -1
  142. package/dist/{chunk-WYFB7BN3.js → chunk-OD4SSY2U.js} +166 -48
  143. package/dist/chunk-OD4SSY2U.js.map +1 -0
  144. package/dist/{chunk-ZIH42CRX.cjs → chunk-OI2GQ25X.cjs} +7 -7
  145. package/dist/{chunk-ZIH42CRX.cjs.map → chunk-OI2GQ25X.cjs.map} +1 -1
  146. package/dist/{chunk-AU3IJNNP.js → chunk-OMZ37BM2.js} +5 -5
  147. package/dist/{chunk-AU3IJNNP.js.map → chunk-OMZ37BM2.js.map} +1 -1
  148. package/dist/{chunk-C4DYN2SD.cjs → chunk-OORXGFL5.cjs} +48 -48
  149. package/dist/{chunk-C4DYN2SD.cjs.map → chunk-OORXGFL5.cjs.map} +1 -1
  150. package/dist/{chunk-HNYLMPQQ.cjs → chunk-OTUPEF2W.cjs} +149 -78
  151. package/dist/chunk-OTUPEF2W.cjs.map +1 -0
  152. package/dist/{chunk-BRN3RGD2.js → chunk-OVI7IXYX.js} +3 -3
  153. package/dist/{chunk-BRN3RGD2.js.map → chunk-OVI7IXYX.js.map} +1 -1
  154. package/dist/{chunk-WMKEGJG4.js → chunk-P6YLZTRE.js} +3 -3
  155. package/dist/{chunk-WMKEGJG4.js.map → chunk-P6YLZTRE.js.map} +1 -1
  156. package/dist/{chunk-C2ZP5YS6.cjs → chunk-PFBRJBUL.cjs} +278 -160
  157. package/dist/chunk-PFBRJBUL.cjs.map +1 -0
  158. package/dist/{chunk-EJSYWAEV.js → chunk-QTD6HX4O.js} +5 -5
  159. package/dist/{chunk-EJSYWAEV.js.map → chunk-QTD6HX4O.js.map} +1 -1
  160. package/dist/{chunk-JL5UEBWT.cjs → chunk-ROR5ZR6A.cjs} +45 -45
  161. package/dist/{chunk-JL5UEBWT.cjs.map → chunk-ROR5ZR6A.cjs.map} +1 -1
  162. package/dist/{chunk-EDHV4CBU.js → chunk-S5TERQVW.js} +37 -134
  163. package/dist/chunk-S5TERQVW.js.map +1 -0
  164. package/dist/{chunk-FSLTU57P.js → chunk-SDBBMD4N.js} +3 -3
  165. package/dist/{chunk-FSLTU57P.js.map → chunk-SDBBMD4N.js.map} +1 -1
  166. package/dist/{chunk-36LIJXWC.js → chunk-SHFBB23Q.js} +4 -4
  167. package/dist/{chunk-36LIJXWC.js.map → chunk-SHFBB23Q.js.map} +1 -1
  168. package/dist/chunk-SIT26LAZ.cjs +614 -0
  169. package/dist/chunk-SIT26LAZ.cjs.map +1 -0
  170. package/dist/{chunk-C6KE2HSQ.cjs → chunk-SR725PWF.cjs} +1662 -1392
  171. package/dist/chunk-SR725PWF.cjs.map +1 -0
  172. package/dist/{chunk-S7WIRFNS.cjs → chunk-TKZXMWQF.cjs} +13 -12
  173. package/dist/chunk-TKZXMWQF.cjs.map +1 -0
  174. package/dist/{chunk-5PDSCELM.cjs → chunk-TQHGE7UC.cjs} +29 -164
  175. package/dist/chunk-TQHGE7UC.cjs.map +1 -0
  176. package/dist/{chunk-XBHRKLZU.cjs → chunk-TUNPBZY3.cjs} +4 -4
  177. package/dist/{chunk-XBHRKLZU.cjs.map → chunk-TUNPBZY3.cjs.map} +1 -1
  178. package/dist/{chunk-KOAI3KIV.cjs → chunk-TZEGUG6D.cjs} +4 -4
  179. package/dist/{chunk-KOAI3KIV.cjs.map → chunk-TZEGUG6D.cjs.map} +1 -1
  180. package/dist/chunk-UGHG7PGX.js +592 -0
  181. package/dist/chunk-UGHG7PGX.js.map +1 -0
  182. package/dist/{chunk-N3QTGPC7.cjs → chunk-UMGZDVOA.cjs} +303 -101
  183. package/dist/chunk-UMGZDVOA.cjs.map +1 -0
  184. package/dist/{chunk-RHDOAQCT.cjs → chunk-WCCATHMB.cjs} +140 -135
  185. package/dist/chunk-WCCATHMB.cjs.map +1 -0
  186. package/dist/{chunk-DYPRZ53S.cjs → chunk-WODMN3Q2.cjs} +27 -27
  187. package/dist/{chunk-DYPRZ53S.cjs.map → chunk-WODMN3Q2.cjs.map} +1 -1
  188. package/dist/{chunk-OZJCH7ZS.js → chunk-XVWOYKIK.js} +3 -3
  189. package/dist/{chunk-OZJCH7ZS.js.map → chunk-XVWOYKIK.js.map} +1 -1
  190. package/dist/{chunk-IHRDX7K6.js → chunk-YIURNGXI.js} +46 -56
  191. package/dist/chunk-YIURNGXI.js.map +1 -0
  192. package/dist/{chunk-GWUWRZXW.js → chunk-YVF2EM7B.js} +3 -3
  193. package/dist/{chunk-GWUWRZXW.js.map → chunk-YVF2EM7B.js.map} +1 -1
  194. package/dist/{chunk-EAMVXR5B.js → chunk-ZDKTPBGV.js} +4 -4
  195. package/dist/{chunk-EAMVXR5B.js.map → chunk-ZDKTPBGV.js.map} +1 -1
  196. package/dist/{chunk-A2LJG5GM.js → chunk-ZFMCDJGB.js} +803 -148
  197. package/dist/chunk-ZFMCDJGB.js.map +1 -0
  198. package/dist/{chunk-62ZXBMSD.js → chunk-ZLONH2UD.js} +46 -3
  199. package/dist/chunk-ZLONH2UD.js.map +1 -0
  200. package/dist/core/index.cjs +28 -27
  201. package/dist/core/index.d.cts +4 -4
  202. package/dist/core/index.d.ts +4 -4
  203. package/dist/core/index.js +8 -7
  204. package/dist/ddl-BL1NZLMY.d.cts +78 -0
  205. package/dist/ddl-D_oW-EVO.d.ts +78 -0
  206. package/dist/graph-extension/index.cjs +20 -20
  207. package/dist/graph-extension/index.d.cts +4 -4
  208. package/dist/graph-extension/index.d.ts +4 -4
  209. package/dist/graph-extension/index.js +4 -4
  210. package/dist/graph-merge/index.cjs +3418 -706
  211. package/dist/graph-merge/index.cjs.map +1 -1
  212. package/dist/graph-merge/index.d.cts +550 -58
  213. package/dist/graph-merge/index.d.ts +550 -58
  214. package/dist/graph-merge/index.js +3191 -497
  215. package/dist/graph-merge/index.js.map +1 -1
  216. package/dist/{index-Deyu8IXL.d.ts → index-COs_z6nV.d.cts} +47 -3
  217. package/dist/{index-DrRS51Ld.d.cts → index-D7d1u2gr.d.ts} +47 -3
  218. package/dist/index.cjs +233 -216
  219. package/dist/index.cjs.map +1 -1
  220. package/dist/index.d.cts +12 -12
  221. package/dist/index.d.ts +12 -12
  222. package/dist/index.js +35 -34
  223. package/dist/index.js.map +1 -1
  224. package/dist/indexes/index.cjs +13 -13
  225. package/dist/indexes/index.d.cts +4 -4
  226. package/dist/indexes/index.d.ts +4 -4
  227. package/dist/indexes/index.js +6 -6
  228. package/dist/interchange/index.cjs +53 -52
  229. package/dist/interchange/index.cjs.map +1 -1
  230. package/dist/interchange/index.d.cts +17 -13
  231. package/dist/interchange/index.d.ts +17 -13
  232. package/dist/interchange/index.js +17 -16
  233. package/dist/interchange/index.js.map +1 -1
  234. package/dist/{manager-ptr3JLRP.d.cts → manager-CYaff3n3.d.cts} +2 -2
  235. package/dist/{manager-DX983gJ0.d.ts → manager-D9eRT_ns.d.ts} +2 -2
  236. package/dist/{materialize-indexes-CpXoggWU.d.ts → materialize-indexes-DJ3ykH59.d.ts} +1 -1
  237. package/dist/{materialize-indexes-BXz77YqO.d.cts → materialize-indexes-DTtAnvfY.d.cts} +1 -1
  238. package/dist/{postgres-DwgEXSPI.d.cts → postgres-CcL4bAHS.d.ts} +1 -1
  239. package/dist/{postgres-QdOMHTBz.d.ts → postgres-DMj39MEu.d.cts} +1 -1
  240. package/dist/profiler/index.d.cts +9 -9
  241. package/dist/profiler/index.d.ts +9 -9
  242. package/dist/provenance/index.cjs +46 -46
  243. package/dist/provenance/index.cjs.map +1 -1
  244. package/dist/provenance/index.d.cts +7 -7
  245. package/dist/provenance/index.d.ts +7 -7
  246. package/dist/provenance/index.js +13 -13
  247. package/dist/provenance/index.js.map +1 -1
  248. package/dist/repair-validity-windows-BFNZvd_H.d.cts +166 -0
  249. package/dist/repair-validity-windows-DlUSqwCg.d.ts +166 -0
  250. package/dist/schema/index.cjs +45 -44
  251. package/dist/schema/index.d.cts +6 -6
  252. package/dist/schema/index.d.ts +6 -6
  253. package/dist/schema/index.js +18 -17
  254. package/dist/{searchable-BOUuA83f.d.ts → searchable-DHJMh_nj.d.cts} +1 -1
  255. package/dist/{searchable-BrUh0pdc.d.cts → searchable-bpE1bBfc.d.ts} +1 -1
  256. package/dist/{sqlite-BfYcV61E.d.cts → sqlite-D7Oz0SQh.d.ts} +1 -1
  257. package/dist/{sqlite-DK40XVR1.d.ts → sqlite-YppHrNFb.d.cts} +1 -1
  258. package/dist/{store-FTqBpuJD.d.cts → store-JUVvtmR4.d.cts} +228 -92
  259. package/dist/{store-Bo1psfVZ.d.ts → store-UzrGvZOo.d.ts} +228 -92
  260. package/dist/{temporal-DPtn0HOu.d.ts → temporal-5GqpYCk2.d.cts} +1 -1
  261. package/dist/{temporal-CXewwLTB.d.cts → temporal-CbnLzTmM.d.ts} +1 -1
  262. package/dist/{types-Du78EvpN.d.ts → types-BqFZTQmV.d.cts} +60 -9
  263. package/dist/{types-Du78EvpN.d.cts → types-BqFZTQmV.d.ts} +60 -9
  264. package/dist/{types-CeT7xM4M.d.ts → types-Bx74kaTt.d.ts} +1 -1
  265. package/dist/{types-XR1nHERK.d.cts → types-CXAhpW-c.d.cts} +1 -1
  266. package/dist/{where-CJsp-YUf.d.cts → where-DI_Fqz-X.d.cts} +1 -1
  267. package/dist/{where-CMbFiWwp.d.ts → where-O-k2wgYm.d.ts} +1 -1
  268. package/package.json +1 -1
  269. package/dist/chunk-32UETY6S.cjs.map +0 -1
  270. package/dist/chunk-5PDSCELM.cjs.map +0 -1
  271. package/dist/chunk-62ZXBMSD.js.map +0 -1
  272. package/dist/chunk-6LAXM4J2.cjs +0 -12
  273. package/dist/chunk-73MWKDFK.cjs +0 -12
  274. package/dist/chunk-A2LJG5GM.js.map +0 -1
  275. package/dist/chunk-A4R3H7RU.cjs.map +0 -1
  276. package/dist/chunk-ANKOXPCC.cjs +0 -267
  277. package/dist/chunk-ANKOXPCC.cjs.map +0 -1
  278. package/dist/chunk-AT3MLMJV.js.map +0 -1
  279. package/dist/chunk-BEB4OFZF.cjs.map +0 -1
  280. package/dist/chunk-BQM5P2NO.cjs.map +0 -1
  281. package/dist/chunk-C2ZP5YS6.cjs.map +0 -1
  282. package/dist/chunk-C6KE2HSQ.cjs.map +0 -1
  283. package/dist/chunk-DSAWGCMP.js +0 -254
  284. package/dist/chunk-DSAWGCMP.js.map +0 -1
  285. package/dist/chunk-E4OSGBCM.cjs.map +0 -1
  286. package/dist/chunk-EDHV4CBU.js.map +0 -1
  287. package/dist/chunk-FA6Z7B5L.js +0 -244
  288. package/dist/chunk-FA6Z7B5L.js.map +0 -1
  289. package/dist/chunk-GVAMRRZR.cjs +0 -268
  290. package/dist/chunk-GVAMRRZR.cjs.map +0 -1
  291. package/dist/chunk-GWXXHOLU.js.map +0 -1
  292. package/dist/chunk-HNYLMPQQ.cjs.map +0 -1
  293. package/dist/chunk-IHRDX7K6.js.map +0 -1
  294. package/dist/chunk-KCH7WQA5.cjs.map +0 -1
  295. package/dist/chunk-KXSMF6PL.js.map +0 -1
  296. package/dist/chunk-LHYSY6SE.js.map +0 -1
  297. package/dist/chunk-N3QTGPC7.cjs.map +0 -1
  298. package/dist/chunk-QPOQX2DI.cjs.map +0 -1
  299. package/dist/chunk-R7EWHKID.js.map +0 -1
  300. package/dist/chunk-RFDEYLIK.js.map +0 -1
  301. package/dist/chunk-RHDOAQCT.cjs.map +0 -1
  302. package/dist/chunk-S3G5VLSW.js.map +0 -1
  303. package/dist/chunk-S7WIRFNS.cjs.map +0 -1
  304. package/dist/chunk-UTVQPZPN.cjs.map +0 -1
  305. package/dist/chunk-WEJHA7AD.js.map +0 -1
  306. package/dist/chunk-WYFB7BN3.js.map +0 -1
  307. package/dist/chunk-YQ4JONWE.js.map +0 -1
  308. package/dist/chunk-Z43KWLZF.js.map +0 -1
  309. package/dist/ddl-mE07h_EM.d.cts +0 -38
  310. package/dist/ddl-opIn8DfX.d.ts +0 -38
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/store/types.ts","../src/store/runtime-port.ts","../src/store/embedding-sync.ts","../src/store/fulltext-sync.ts","../src/store/uniqueness.ts","../src/store/operations/node-write-pipeline.ts"],"names":["typeGraphGlobalSymbol","resolveEmbeddingFields","readOwnProperty","DEFAULT_SEARCHABLE_LANGUAGE","getSearchableFields","getKindsForUniquenessCheck","UniquenessError","checkWherePredicate","computeUniqueKey","RestrictedDeleteError","rowPropsToObject"],"mappings":"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","file":"chunk-32UETY6S.cjs","sourcesContent":["/**\n * Store types for TypeGraph operations.\n */\nimport { type z } from \"zod\";\n\nimport {\n type EdgeRow,\n type NodeRow,\n type TransactionBackend,\n type TransactionReadBackend,\n} from \"../backend/types\";\nimport {\n type EdgeKinds,\n type GraphDef,\n type GraphIdentityConfig,\n type NodeKinds,\n} from \"../core/define-graph\";\nimport { type RecordedInstant } from \"../core/temporal\";\nimport {\n type AnyEdgeType,\n type EdgeId,\n type EdgeRegistration,\n type EdgeType,\n type KindEntity,\n type NodeId,\n type NodeRegistration,\n type NodeType,\n type TemporalMode,\n} from \"../core/types\";\nimport type { IdentityFacade, IdentityWriteSummary } from \"../identity/types\";\nimport type { TraversalExpansion } from \"../query/ast\";\nimport type {\n DynamicEdgeAccessor,\n DynamicNodeAccessor,\n} from \"../query/builder\";\nimport type { BatchableQuery, NodeAccessor } from \"../query/builder/types\";\nimport {\n type ExternalRecordedReadSource,\n type SqlSchema,\n} from \"../query/compiler/schema\";\nimport type { Predicate } from \"../query/predicates\";\nimport { typeGraphGlobalSymbol } from \"../utils/global-symbol\";\nimport type {\n CURRENT_ONLY_READ_NAMES,\n EDGE_BATCH_READ_NAMES,\n EDGE_TEMPORAL_READ_NAMES,\n EDGE_WRITE_NAMES,\n NODE_TEMPORAL_READ_NAMES,\n NODE_WRITE_NAMES,\n RECORDED_POINT_READ_NAMES,\n} from \"./collection-surface\";\n\n// ============================================================\n// Row-to-Meta Field Mapping\n// ============================================================\n\n/**\n * Canonical mapping from snake_case row fields to camelCase meta fields.\n *\n * This is the single source of truth for which row columns become metadata.\n * Both the Meta types and the row-to-meta functions in row-mappers.ts must\n * stay in sync with this mapping. If you add a temporal/audit column to a\n * row type, add the mapping here — the compiler will then force you to\n * update the row mapper functions as well (since their return type is\n * NodeMeta/EdgeMeta, which is derived from this mapping).\n */\ntype TemporalMetaFieldMap = Readonly<{\n valid_from: \"validFrom\";\n valid_to: \"validTo\";\n created_at: \"createdAt\";\n updated_at: \"updatedAt\";\n deleted_at: \"deletedAt\";\n}>;\n\n/**\n * Maps row fields to their camelCase meta counterparts, preserving types.\n */\ntype MapRowToMeta<\n R extends Readonly<Record<string, unknown>>,\n M extends Readonly<Record<string, string>>,\n> = Readonly<{\n [SnakeKey in keyof M as M[SnakeKey] & string]: SnakeKey extends keyof R ?\n R[SnakeKey]\n : never;\n}>;\n\n// ============================================================\n// Node Instance Types\n// ============================================================\n\n/**\n * Metadata for a node instance.\n * Derived from NodeRow via TemporalMetaFieldMap + version.\n *\n * Adding a new metadata column requires:\n * 1. Add the column to NodeRow in backend/types.ts\n * 2. Add the mapping to TemporalMetaFieldMap above\n * 3. The compiler will error in rowToNodeMeta() until you add the field there\n */\nexport type NodeMeta = MapRowToMeta<NodeRow, TemporalMetaFieldMap> &\n Readonly<{ version: NodeRow[\"version\"] }>;\n\n/**\n * A node instance in the graph.\n *\n * Properties from the schema are spread at the top level for ergonomic access:\n * - `node.name` instead of `node.props.name`\n * - System metadata is under `node.meta.*`\n */\nexport type Node<N extends NodeType = NodeType> = Readonly<{\n kind: N[\"kind\"];\n id: NodeId<N>;\n meta: NodeMeta;\n}> &\n Readonly<z.infer<N[\"schema\"]>>;\n\n/**\n * Input for creating a node.\n */\nexport type CreateNodeInput<N extends NodeType = NodeType> = Readonly<{\n kind: N[\"kind\"];\n id?: string; // Optional - will generate ULID if not provided\n props: z.infer<N[\"schema\"]>;\n validFrom?: string;\n validTo?: string;\n}>;\n\n/**\n * Input for updating a node.\n */\nexport type UpdateNodeInput<N extends NodeType = NodeType> = Readonly<{\n kind: N[\"kind\"];\n id: NodeId<N>;\n props: Partial<z.infer<N[\"schema\"]>>;\n validTo?: string;\n}>;\n\n// ============================================================\n// Edge Instance Types\n// ============================================================\n\n/**\n * Metadata for an edge instance.\n * Derived from EdgeRow via TemporalMetaFieldMap (edges have no version).\n */\nexport type EdgeMeta = MapRowToMeta<EdgeRow, TemporalMetaFieldMap>;\n\n/**\n * An edge instance in the graph.\n *\n * Properties from the schema are spread at the top level for ergonomic access:\n * - `edge.role` instead of `edge.props.role`\n * - System metadata is under `edge.meta.*`\n */\nexport type Edge<\n E extends AnyEdgeType = EdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Readonly<{\n id: EdgeId<E>;\n kind: E[\"kind\"];\n fromKind: From[\"kind\"];\n fromId: NodeId<From>;\n toKind: To[\"kind\"];\n toId: NodeId<To>;\n meta: EdgeMeta;\n}> &\n Readonly<z.infer<E[\"schema\"]>>;\n\n/**\n * Input for creating an edge.\n */\nexport type CreateEdgeInput<E extends AnyEdgeType = EdgeType> = Readonly<{\n kind: E[\"kind\"];\n id?: string; // Optional - will generate ULID if not provided\n fromKind: string;\n fromId: string;\n toKind: string;\n toId: string;\n props: z.infer<E[\"schema\"]>;\n validFrom?: string;\n validTo?: string;\n}>;\n\n/**\n * Input for updating an edge.\n */\nexport type UpdateEdgeInput<E extends AnyEdgeType = EdgeType> = Readonly<{\n id: EdgeId<E>;\n props: Partial<z.infer<E[\"schema\"]>>;\n validTo?: string;\n}>;\n\n// ============================================================\n// Query Options\n// ============================================================\n\n/**\n * Options for node and edge queries.\n */\nexport type NoRecordedCoordinate = Readonly<{\n /**\n * Recorded/system-time coordinates are internal-only and supplied by\n * RecordedStoreView. A public options object carrying this key is a type\n * error even when the object is pre-bound before the call site.\n */\n recordedAsOf?: never;\n}>;\n\nexport type QueryOptions = NoRecordedCoordinate &\n Readonly<{\n /** Temporal mode for the query */\n temporalMode?: TemporalMode;\n /** Specific timestamp for asOf queries */\n asOf?: string;\n }>;\n\n// ============================================================\n// Observability Hooks\n// ============================================================\n\n/**\n * Context passed to observability hooks.\n */\nexport type HookContext = Readonly<{\n /** Unique ID for this operation */\n operationId: string;\n /** Graph ID */\n graphId: string;\n /** Timestamp when operation started */\n startedAt: Date;\n}>;\n\n/**\n * Context for one SQL statement a query builder submits to the backend.\n *\n * A single logical query can emit more than one context, for example when a\n * selective projection falls back to a full-row fetch. Backend-internal setup\n * statements are not exposed as separate query-hook events.\n */\nexport type QueryHookContext = HookContext &\n Readonly<{\n /** The SQL statement being executed */\n sql: string;\n /** Query parameters */\n params: readonly unknown[];\n }>;\n\n/**\n * Operation hook context for CRUD operations.\n */\nexport type OperationHookContext = HookContext &\n Readonly<{\n /** Operation type */\n operation: \"create\" | \"update\" | \"delete\";\n /** Entity type */\n entity: KindEntity;\n /** Kind of node or edge */\n kind: string;\n /** Entity ID */\n id: string;\n }>;\n\n/**\n * Context for one set-based collection mutation. Node `updateWhere` is the only\n * mutation that reports one: the `operation` union is the exhaustive list of\n * what `onBulkOperationStart` / `onBulkOperationEnd` observe, so a batch method\n * absent from it (every `bulk*`, including `bulkDelete`) emits no bulk event.\n */\nexport type BulkOperationHookContext = HookContext &\n Readonly<{\n operation: \"updateWhere\";\n entity: \"node\";\n kind: string;\n }>;\n\n/**\n * Observability hooks for monitoring store operations.\n *\n * Note: Batch operations (`bulkCreate`, `bulkInsert`, `bulkUpsertById`,\n * `bulkDelete`) skip per-item operation hooks for throughput, and the bulk\n * hooks below do not stand in for them — those fire only for node\n * `updateWhere`, so a batch method emits no hook events at all, neither\n * per-item nor bulk. Query hooks still fire normally.\n *\n * @example\n * ```typescript\n * const hooks: StoreHooks = {\n * onQueryStart: (ctx) => {\n * console.log(`[${ctx.operationId}] Query: ${ctx.sql}`);\n * },\n * onQueryEnd: (ctx, result) => {\n * const duration = Date.now() - ctx.startedAt.getTime();\n * console.log(`[${ctx.operationId}] Completed in ${duration}ms`);\n * },\n * onError: (ctx, error) => {\n * console.error(`[${ctx.operationId}] Error:`, error);\n * },\n * };\n *\n * const store = createStore(graph, backend, { hooks });\n * ```\n */\nexport type StoreHooks = Readonly<{\n /** Called before each query-builder statement is submitted to the backend. */\n onQueryStart?: (ctx: QueryHookContext) => void;\n /** Called after each submitted query-builder statement succeeds. */\n onQueryEnd?: (\n ctx: QueryHookContext,\n result: Readonly<{ rowCount: number; durationMs: number }>,\n ) => void;\n /** Called before a CRUD operation starts */\n onOperationStart?: (ctx: OperationHookContext) => void;\n /** Called before a set-based collection mutation starts. */\n onBulkOperationStart?: (ctx: BulkOperationHookContext) => void;\n /**\n * Called after a CRUD operation completes AND is durably committed. For a\n * top-level operation that is when its own transaction commits; for an\n * operation inside `store.transaction`, emission is deferred until the\n * enclosing transaction commits — if that commit fails, the operation is\n * reported through `onError` instead. (Inside an adopted transaction —\n * `withTransaction` / `withRecordedTransaction` — the commit belongs to\n * the caller and cannot be observed, so this fires when the operation\n * completes within the still-open transaction.)\n */\n onOperationEnd?: (\n ctx: OperationHookContext,\n result: Readonly<{ durationMs: number }>,\n ) => void;\n /**\n * Called after a set-based mutation durably commits. Inside\n * `store.transaction`, emission is deferred until the enclosing commit.\n */\n onBulkOperationEnd?: (\n ctx: BulkOperationHookContext,\n result: Readonly<{ affectedCount: number; durationMs: number }>,\n ) => void;\n /**\n * Called when an operation fails — including an operation that completed\n * inside a `store.transaction` whose commit then failed and rolled it\n * back.\n */\n onError?: (ctx: HookContext, error: Error) => void;\n}>;\n\n// ============================================================\n// Store Configuration\n// ============================================================\n\n/**\n * Default row count at which an autocommit bulk write triggers an\n * automatic planner-statistics refresh. Below this, the refresh cost is\n * not worth paying per call and autovacuum/PRAGMA optimize cover it.\n */\nexport const AUTO_REFRESH_STATISTICS_ROW_THRESHOLD = 1000;\n\nexport type BaseStoreOptions = Readonly<{\n /** Observability hooks for monitoring */\n hooks?: StoreHooks;\n /**\n * Maintain a durable, graph-wide revision anchor for TypeGraph writes:\n * a random per-graph origin plus a monotonic revision clock. `branch()` uses\n * this anchor to validate that its base has not moved without\n * re-fingerprinting every live row, and cannot confuse a coincident clock in\n * a separately created store for its original base. `history: true` enables\n * the same tracking automatically through its recorded-time commit clock.\n *\n * This is intentionally opt-in for live stores: each successful graph write\n * advances the anchor inside its write transaction. On PostgreSQL, those\n * transactions take a graph-scoped advisory lock until commit; writes to the\n * same graph therefore serialize. Enable it for branchable graphs, but size\n * high-throughput multi-writer workloads for that trade-off.\n *\n * Writes performed directly through a backend — including raw graph-table\n * writes through `tx.sql` — bypass the anchor and are outside the\n * revision-tracking contract.\n */\n revisionTracking?: boolean;\n /**\n * Automatic planner-statistics refresh after large autocommit bulk\n * writes (bulkCreate and bulkInsert on nodes and edges). Stale statistics after a\n * bulk load are a whole class of planner cliffs: the planner keeps\n * pre-load row estimates until ANALYZE runs. When a single\n * autocommit bulk write reaches the threshold\n * ({@link AUTO_REFRESH_STATISTICS_ROW_THRESHOLD} rows by default),\n * the store runs `refreshStatistics()` after the write commits.\n * Pass a number to change the threshold, or `false` to disable.\n * Bulk writes inside a caller-provided transaction never\n * auto-refresh (statistics cannot see uncommitted rows); refresh\n * manually after commit. `importGraph` handles its own refresh.\n */\n autoRefreshStatistics?: false | number;\n /**\n * Skip the write for an `upsertById` (or `bulkUpsertById` item) whose\n * validated props are value-identical to the existing live row. Default\n * off.\n *\n * Enable this for at-least-once / replay materializers. An event log that\n * re-delivers a byte-identical change would otherwise rewrite the row anyway:\n * today an `upsertById` on an existing id calls `updateNode`\n * unconditionally, allocating a fresh recorded instant and a new history row\n * per re-delivery.\n *\n * The win is scoped to re-delivery of the **current** value. A full\n * replay-from-zero over the current state still writes wherever the stream\n * superseded a value in place: re-applying an older value over the live row\n * is a genuine change (and restoring the current value afterwards is\n * another), so only streams whose rows never supersede each other replay\n * without churn. A rebuild that should avoid that re-walk belongs in a fresh\n * store — replay into it and publish it, rather than re-applying the log\n * over current state.\n *\n * When enabled, an upsert that would not change the stored value performs\n * **no write at all**: no `updateNode`, no recorded-time capture, no history\n * row, no revision-anchor advance, and no `update` operation hooks (nothing\n * happened, so nothing is reported). It resolves with the **existing** node,\n * preserving its original `validFrom` / `updatedAt` / `version`.\n *\n * Receipt shape is unchanged and needs no new signal: a coalesced upsert\n * still counts as one write intent (`writes.total` includes it), but\n * captures nothing (`receipt.recorded` stays `undefined` when it is the only\n * write) — the same shape a no-op delete already produces, so a consumer\n * that carries the prior anchor forward on `recorded === undefined` handles\n * it unchanged.\n *\n * A write is coalesced only when **all** of the following hold; otherwise the\n * normal write happens:\n * 1. A value to compare against is known for the id: an existing row, or —\n * for a repeated id in one bulk batch — the value an earlier item in that\n * batch already queued (a create or an update).\n * 2. That row is not soft-deleted (a deleted row resurrects — a real\n * change — and is never coalesced).\n * 3. The caller passed no explicit `validFrom` / `validTo` (an explicit\n * temporal override is a deliberate request and is never coalesced;\n * applied per item in the bulk path).\n * 4. The new props, merged over the stored props and run through the\n * kind's Zod schema (defaults applied, values normalized), are deeply\n * value-identical to the stored props (key order aside).\n *\n * Default-off because some consumers *want* an audit row per re-delivery as\n * proof the event was reprocessed; coalescing removes that signal.\n */\n coalesceUnchangedUpserts?: boolean;\n /** SQL schema configuration from createSqlSchema(...) for custom table names */\n schema?: SqlSchema;\n /** Query default behaviors. */\n queryDefaults?: Readonly<{\n /** Default traversal ontology expansion mode (default: \"inverse\"). */\n traversalExpansion?: TraversalExpansion;\n }>;\n}>;\n\n/**\n * Store options without built-in recorded-time capture. A recorded read relation\n * can still be bound explicitly for hosts that populate history externally.\n */\nexport type LiveStoreOptions = BaseStoreOptions &\n Readonly<{\n history?: false | undefined;\n recordedRead?: ExternalRecordedReadSource | undefined;\n }>;\n\n/** Live-store options that do not bind a recorded-read relation. */\nexport type UnboundLiveStoreOptions = LiveStoreOptions &\n Readonly<{ recordedRead?: undefined }>;\n\n/** Live-store options with an explicitly bound recorded-read relation. */\nexport type RecordedReadStoreOptions = LiveStoreOptions &\n Readonly<{\n recordedRead: NonNullable<LiveStoreOptions[\"recordedRead\"]>;\n }>;\n\n/**\n * Store options with TypeGraph-managed recorded-time capture. `history: true`\n * captures TypeGraph writes and binds TypeGraph's built-in recorded relation\n * internally. Externally populated recorded read sources are read-only bindings\n * and are intentionally accepted only by {@link LiveStoreOptions}.\n */\nexport type HistoryStoreOptions = BaseStoreOptions &\n Readonly<{\n history: true;\n recordedRead?: never;\n }>;\n\n/**\n * Options for creating a store.\n */\nexport type StoreOptions = LiveStoreOptions | HistoryStoreOptions;\n\n/**\n * A mutable handle to the current `Store`, used by `store.evolve(...)`\n * so long-lived consumers can dereference through the ref and pick up\n * the new Store after each evolve call. When the ref is passed via\n * `evolve(extension, { ref })`, `current` is overwritten with the replacement\n * before a successful call resolves.\n *\n * **Request semantics.** Dereference once at request entry only when that\n * request will not change the schema. A schema-changing call such as\n * `evolve()` returns the Store for the resulting schema and updates\n * `ref.current`; a Store captured before that call remains pinned to the old\n * schema. Use the returned Store (or dereference `ref.current` again) for every\n * subsequent operation in the same request:\n *\n * ```ts\n * async function handleRequest(): Promise<void> {\n * const store = ref.current;\n * const evolved = await store.evolve(extension, { ref });\n * await evolved.materializeIndexes();\n * // ref.current === evolved\n * }\n * ```\n *\n * A `StoreRef` tracks only schema changes made by calls that receive that ref.\n * When another process or isolate can commit a schema version, compare\n * `getCommittedSchemaVersion()` with the cached version before reuse and call\n * `createVerifiedStore()` or `createVerifiedAdapterStore()` when it changes.\n *\n * Pure dereferenceable handle — no event/subscription machinery. If\n * consumers need eventing, they wrap the ref themselves.\n *\n * Generic over the held value (typically `Store<G>`) so the store\n * module can refer to it without importing the `Store` class into\n * `types.ts`. The type parameter is deliberately invariant: evolution writes\n * a replacement into `current`, so a ref for an adapter-only or history-only\n * Store must never be accepted by a Store that cannot preserve that surface.\n */\nexport interface StoreRef<in out T> {\n current: T;\n}\n\n// ============================================================\n// Transaction Receipt Types\n// ============================================================\n\n/**\n * Result plus write summary. Returned by `store.transactionWithReceipt(fn)`,\n * `store.withRecordedTransaction(externalTx, fn)` (the adopted-commit path), and\n * `tx.measure(fn)` (a scoped sub-receipt). See {@link TransactionReceipt}.\n */\nexport type TransactionOutcome<T> = Readonly<{\n result: T;\n receipt: TransactionReceipt;\n}>;\n\n/**\n * Transaction write summary.\n *\n * Receipt counts are completed write intents at the collection surface, not\n * rows affected:\n *\n * 1. Every successful completion of a write method on `tx.nodes.*` /\n * `tx.edges.*` counts. The authoritative method list is\n * {@link NodeWrites} / {@link EdgeWrites}.\n * 2. Bulk methods count by input length; an empty bulk call (`bulkCreate([])`)\n * counts 0.\n * 3. Single-row methods count 1 on resolve — including `delete` of an absent\n * id and `getOrCreate*` that found an existing row. Consumers that need\n * \"did anything actually change\" semantics apply their own per-operation\n * policy.\n * 4. A method that rejects counts 0 — even when the backend applied part of a\n * bulk input before failing. On SQLite a failed statement does not abort\n * the surrounding transaction, so a caller that catches the rejection and\n * commits can persist rows the receipt never counted. Do not read the\n * receipt as rows-affected in that scenario.\n * 5. A node `delete` under `cascade` / `disconnect` removes connected edges\n * through the backend, not the edge-collection surface; those removals do\n * not appear in `edges`.\n * 6. Rows-affected fidelity is intentionally out of scope for this first\n * version; a future extension could ask backends to return row counts.\n */\nexport type TransactionReceipt = Readonly<{\n writes: Readonly<{\n /** Completed node write intents by node kind. */\n nodes: Readonly<Record<string, number>>;\n /** Completed edge write intents by edge kind. */\n edges: Readonly<Record<string, number>>;\n /** Completed identity assertion and retraction write intents. */\n identity: IdentityWriteSummary;\n /** Sum of all node, edge, and identity write intents. */\n total: number;\n }>;\n /**\n * The recorded commit instant allocated for this store's graph by this\n * transaction. Undefined when history capture is off, the transaction is\n * read-only, or no captured writes were flushed. **Always undefined on a\n * scoped receipt from {@link ScopedMeasure}** (`tx.measure`) — the recorded\n * instant is a per-transaction flush concern allocated once when the whole\n * transaction's capture flushes, unknowable mid-transaction.\n */\n recorded?: RecordedInstant;\n}>;\n\n// ============================================================\n// Get-Or-Create Types\n// ============================================================\n\n/**\n * Behavior when a get-or-create operation matches an existing record.\n */\nexport type IfExistsMode = \"return\" | \"update\";\n\n/**\n * Action taken by a get-or-create operation.\n */\nexport type GetOrCreateAction = \"created\" | \"found\" | \"updated\" | \"resurrected\";\n\n/**\n * Result of a node getOrCreateByConstraint operation.\n */\nexport type NodeGetOrCreateByConstraintResult<N extends NodeType> = Readonly<{\n node: Node<N>;\n action: GetOrCreateAction;\n}>;\n\n/**\n * Options for node getOrCreateByConstraint operations.\n */\nexport type NodeGetOrCreateByConstraintOptions = Readonly<{\n /** Existing record behavior. Default: \"return\" */\n ifExists?: IfExistsMode;\n}>;\n\n/**\n * Options for node bulkFindByIndex operations.\n */\nexport type NodeBulkFindByIndexOptions = Readonly<{\n /**\n * Maximum number of candidate nodes returned per input item. When omitted,\n * each input's candidate set is unbounded. Must be a positive integer.\n *\n * Candidates are ordered deterministically by node id, so the cap is stable\n * across calls. Use this to bound fan-out on low-selectivity index keys.\n */\n limitPerInput?: number;\n}>;\n\n/**\n * Per-endpoint fan-out cap shared by the live and view forms of the edge\n * bulk endpoint reads.\n */\nexport type EdgeBulkFindOptions = Readonly<{\n /**\n * Maximum number of edges returned for each input endpoint. When omitted,\n * every input's edge set is unbounded. Must be a positive integer.\n *\n * The cap keeps each input's leading edges under the same ordering\n * `findFrom` / `findTo` return, so it bounds fan-out without reordering\n * anything.\n */\n limitPerInput?: number;\n}>;\n\n/**\n * Options for the edge bulk endpoint reads: the temporal coordinate every\n * edge read accepts, plus the per-endpoint fan-out cap.\n */\nexport type EdgeBulkFindEndpointOptions = QueryOptions & EdgeBulkFindOptions;\n\n/** A kind-grouped source list for a heterogeneous bulk edge read. */\nexport type BulkEdgeSourceGroup<G extends GraphDef> = {\n [K in NodeKinds<G>]: Readonly<{\n kind: K;\n ids: readonly NodeId<G[\"nodes\"][K][\"type\"]>[];\n }>;\n}[NodeKinds<G>];\n\n/** A node reference whose kind and branded id remain correlated. */\nexport type GraphNodeReference<G extends GraphDef> = {\n [K in NodeKinds<G>]: Readonly<{\n kind: K;\n id: NodeId<G[\"nodes\"][K][\"type\"]>;\n }>;\n}[NodeKinds<G>];\n\n/** Runtime edge union narrowed to the selected graph edge kinds. */\nexport type GraphEdgeForKinds<G extends GraphDef, K extends EdgeKinds<G>> = {\n [P in K]: Edge<\n G[\"edges\"][P][\"type\"],\n G[\"edges\"][P][\"from\"][number],\n G[\"edges\"][P][\"to\"][number]\n >;\n}[K];\n\n/** Input for {@link Store.bulkFindEdgesFrom}. */\nexport type BulkFindEdgesFromParams<\n G extends GraphDef,\n K extends EdgeKinds<G>,\n> = Readonly<{\n sources: readonly BulkEdgeSourceGroup<G>[];\n edgeKinds: readonly K[];\n}>;\n\n/** One source bucket returned by {@link Store.bulkFindEdgesFrom}. */\nexport type BulkFindEdgesFromResult<\n G extends GraphDef,\n K extends EdgeKinds<G>,\n> = Readonly<{\n source: GraphNodeReference<G>;\n edges: readonly GraphEdgeForKinds<G, K>[];\n}>;\n\n/**\n * Result of an edge getOrCreateByEndpoints operation.\n */\nexport type EdgeGetOrCreateByEndpointsResult<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Readonly<{\n edge: Edge<E, From, To>;\n action: GetOrCreateAction;\n}>;\n\n/**\n * Options for edge findByEndpoints operations.\n */\nexport type EdgeFindByEndpointsOptions<E extends AnyEdgeType> = Readonly<{\n /**\n * Edge property fields to include in the match alongside the (from, to) endpoints.\n * When omitted, matches on endpoints only (returns the first edge at the read coordinate).\n */\n matchOn?: readonly (keyof z.input<E[\"schema\"]>)[];\n /** Property values to match against when matchOn is specified. */\n props?: Partial<z.input<E[\"schema\"]>>;\n}>;\n\n/**\n * Options for edge getOrCreateByEndpoints operations.\n */\nexport type EdgeGetOrCreateByEndpointsOptions<E extends AnyEdgeType> =\n Readonly<{\n /**\n * Edge property fields to include in the match key alongside the (from, to) endpoints.\n * Default: `[]` — match on endpoints only.\n */\n matchOn?: readonly (keyof z.input<E[\"schema\"]>)[];\n /** Existing record behavior. Default: \"return\" */\n ifExists?: IfExistsMode;\n /**\n * Valid-time start for a created or RESURRECTED edge — on a resurrection it\n * asserts the complete window, so an omitted `validTo` reopens the revived\n * row.\n *\n * A live edge's stored lower bound is history, so an in-place update\n * (`ifExists: \"update\"`) cannot store this: one naming a different instant is\n * REFUSED with `IMMUTABLE_VALIDITY_LOWER_BOUND_CODE`, and one restating the\n * bound the edge holds is accepted. Ignored when an existing edge is returned\n * (`ifExists: \"return\"`), which writes nothing at all — there the window\n * describes the edge to create if none is found.\n */\n validFrom?: string;\n /**\n * How an `ifExists: \"update\"` write treats a stated `validFrom` that differs\n * from the live edge's stored lower bound. Default: `\"refuse\"`.\n *\n * `\"preserve\"` makes `validFrom` create/resurrection-only input: it is still\n * validated, but a live update keeps the stored lower bound while applying\n * properties and `validTo`.\n */\n onImmutableLowerBound?: \"preserve\" | \"refuse\";\n /**\n * Valid-time end for a created, updated, or resurrected edge. Ignored when\n * the operation returns an existing edge without writing. May not precede\n * the row's effective start; see `INVERTED_VALIDITY_WINDOW_CODE`.\n */\n validTo?: string;\n }>;\n\n// ============================================================\n// Collection Interfaces\n// ============================================================\n\n/**\n * A collection of nodes of a specific type.\n *\n * Provides ergonomic CRUD operations for a single node type.\n */\nexport type NodeCollection<\n N extends NodeType,\n CN extends string = string,\n> = Readonly<{\n /**\n * Create a new node.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n */\n create: (\n props: z.input<N[\"schema\"]>,\n options?: Readonly<{ id?: string; validFrom?: string; validTo?: string }>,\n ) => Promise<Node<N>>;\n\n /** Get a node by ID */\n getById: (\n id: NodeId<N>,\n options?: QueryOptions,\n ) => Promise<Node<N> | undefined>;\n\n /** Get multiple nodes by ID, preserving input order (undefined for missing) */\n getByIds: (\n ids: readonly NodeId<N>[],\n options?: QueryOptions,\n ) => Promise<readonly (Node<N> | undefined)[]>;\n\n /** Update a node */\n update: (\n id: NodeId<N>,\n props: Partial<z.input<N[\"schema\"]>>,\n options?: Readonly<{ validTo?: string }>,\n ) => Promise<Node<N>>;\n\n /**\n * Updates every current node selected by the supplied predicates in one\n * set-based write. Relationship clauses are independent EXISTS predicates\n * and are ANDed with each other and with `where`.\n */\n updateWhere: (\n params: Readonly<{\n patch: Partial<z.input<N[\"schema\"]>>;\n where?: (\n accessor: string extends N[\"kind\"] ? DynamicNodeAccessor\n : NodeAccessor<N>,\n ) => Predicate;\n exists?: readonly Readonly<{\n edgeKind: string;\n direction: \"out\" | \"in\";\n relatedKind: string;\n whereEdge?: (accessor: DynamicEdgeAccessor) => Predicate;\n whereRelated?: (accessor: DynamicNodeAccessor) => Predicate;\n }>[];\n all?: true;\n }>,\n ) => Promise<Readonly<{ affectedCount: number }>>;\n\n /** Delete a node (soft delete - sets deletedAt timestamp) */\n delete: (id: NodeId<N>) => Promise<void>;\n\n /**\n * Permanently delete a node from the database.\n *\n * Unlike `delete()` which performs a soft delete, this permanently\n * removes the node and its associated data (uniqueness entries, embeddings).\n *\n * **Warning:** This operation is irreversible and should be used carefully.\n * Consider using soft delete (`delete()`) for most use cases.\n *\n * @throws Error if edges are still connected to this node (delete edges first)\n */\n hardDelete: (id: NodeId<N>) => Promise<void>;\n\n /**\n * Find nodes matching criteria.\n *\n * Supports predicate filtering via the `where` option for SQL-level filtering.\n * For simple queries. Use store.query() for complex traversals.\n */\n find: (\n filter?: Readonly<{\n where?: (accessor: NodeAccessor<N>) => Predicate;\n limit?: number;\n offset?: number;\n }>,\n temporal?: QueryOptions,\n ) => Promise<Node<N>[]>;\n\n /** Count nodes matching criteria */\n count: (temporal?: QueryOptions) => Promise<number>;\n\n /**\n * Create a node from untyped data, relying on runtime Zod validation.\n *\n * Use this for dynamic dispatch (changesets, migrations, imports) where\n * the data shape is determined at runtime, not compile time.\n * The return type is fully typed — only the input gate is relaxed.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n */\n createFromRecord: (\n data: Record<string, unknown>,\n options?: Readonly<{ id?: string; validFrom?: string; validTo?: string }>,\n ) => Promise<Node<N>>;\n\n /**\n * Create or update a node.\n *\n * If a node with the given ID exists, updates it with the provided props.\n * Otherwise, creates a new node with that ID.\n *\n * `validFrom` applies when the upsert CREATES the row and when it RESURRECTS\n * a tombstoned one — both write a fresh validity window — defaulting to the\n * operation's timestamp when omitted. An update to a LIVE row stores no lower\n * bound, because that row's is already history, so one naming a different\n * instant is REFUSED (`ValidationError` carrying\n * `IMMUTABLE_VALIDITY_LOWER_BOUND_CODE`) rather than ignored. Restating the\n * bound the row already holds is accepted and changes nothing. Set\n * `onImmutableLowerBound: \"preserve\"` for event materializers whose\n * `validFrom` is create/resurrection input: a live update then preserves the\n * stored lower bound while still applying props and `validTo`.\n */\n upsertById: (\n id: string,\n props: z.input<N[\"schema\"]>,\n options?: Readonly<{\n validFrom?: string;\n validTo?: string;\n onImmutableLowerBound?: \"preserve\" | \"refuse\";\n }>,\n ) => Promise<Node<N>>;\n\n /**\n * Upsert a node from untyped data, relying on runtime Zod validation.\n *\n * Use this for dynamic dispatch (changesets, migrations, imports) where\n * the data shape is determined at runtime, not compile time.\n * The return type is fully typed — only the input gate is relaxed.\n *\n * `validFrom` applies when the upsert CREATES the row and when it RESURRECTS\n * a tombstoned one — both write a fresh validity window — defaulting to the\n * operation's timestamp when omitted. An update to a LIVE row stores no lower\n * bound, because that row's is already history, so one naming a different\n * instant is REFUSED (`ValidationError` carrying\n * `IMMUTABLE_VALIDITY_LOWER_BOUND_CODE`) rather than ignored. Restating the\n * bound the row already holds is accepted and changes nothing. Set\n * `onImmutableLowerBound: \"preserve\"` for create/resurrection-only input.\n */\n upsertByIdFromRecord: (\n id: string,\n data: Record<string, unknown>,\n options?: Readonly<{\n validFrom?: string;\n validTo?: string;\n onImmutableLowerBound?: \"preserve\" | \"refuse\";\n }>,\n ) => Promise<Node<N>>;\n\n /**\n * Create multiple nodes in a batch.\n *\n * More efficient than calling create() multiple times.\n * Use `bulkInsert` for the dedicated fast path that skips returning results.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n */\n bulkCreate: (\n items: readonly Readonly<{\n props: z.input<N[\"schema\"]>;\n id?: string;\n validFrom?: string;\n validTo?: string;\n }>[],\n ) => Promise<Node<N>[]>;\n\n /**\n * Create or update multiple nodes in a batch.\n *\n * For each item, if a node with the given ID exists, updates it.\n * Otherwise, creates a new node with that ID.\n *\n * Items are applied in order, so a **repeated id** within one batch is\n * last-write-wins: the first item creates or updates the row, and every later\n * copy is an update over the value the earlier item wrote — the same final row\n * the equivalent sequence of `upsertById` calls produces. This holds whether\n * or not the row existed before the batch.\n *\n * `validFrom` applies when the upsert CREATES the row and when it RESURRECTS\n * a tombstoned one — both write a fresh validity window — defaulting to the\n * operation's timestamp when omitted. An update to a LIVE row stores no lower\n * bound, because that row's is already history, so one naming a different\n * instant is REFUSED (`ValidationError` carrying\n * `IMMUTABLE_VALIDITY_LOWER_BOUND_CODE`) rather than ignored. Restating the\n * bound the row already holds is accepted and changes nothing. Per-item\n * `onImmutableLowerBound: \"preserve\"` makes the bound create/resurrection\n * input while a live update preserves the stored lower bound.\n *\n * **Limitation — a batch cannot hand a unique value from one row to\n * another.** Item order settles which value each id ends up with, but the\n * writes themselves are grouped: every create runs before every update. So a\n * batch where one item RELEASES a `unique` constraint value and a later item\n * CLAIMS it — `[{ id: \"a\", props: { email: \"moved@x\" } }, { id: \"b\", props:\n * { email: \"shared@x\" } }]` where `a` currently holds `\"shared@x\"` and `b` is\n * new — checks `b`'s create while `a` still reserves the value, and the whole\n * batch fails with a `UniquenessError`. The equivalent sequence of\n * single `upsertById` calls succeeds. A batch states the set of rows it wants,\n * not a script to reach them by; the failure is loud rather than silent, and\n * the workaround is to split the handoff across two batches (release, then\n * claim) or to apply those items as sequential `upsertById` calls.\n */\n bulkUpsertById: (\n items: readonly Readonly<{\n id: string;\n props: z.input<N[\"schema\"]>;\n validFrom?: string;\n validTo?: string;\n onImmutableLowerBound?: \"preserve\" | \"refuse\";\n }>[],\n ) => Promise<Node<N>[]>;\n\n /**\n * Insert multiple nodes without returning results.\n *\n * This is the dedicated fast path for bulk inserts. Unlike `bulkCreate`\n * with `returnResults: false`, the intent is unambiguous: no results\n * are returned and the operation is wrapped in a transaction.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n */\n bulkInsert: (\n items: readonly Readonly<{\n props: z.input<N[\"schema\"]>;\n id?: string;\n validFrom?: string;\n validTo?: string;\n }>[],\n ) => Promise<void>;\n\n /**\n * Delete multiple nodes by ID.\n *\n * Atomic when the backend supports transactions. Silently ignores IDs\n * that don't exist.\n */\n bulkDelete: (ids: readonly NodeId<N>[]) => Promise<void>;\n\n /**\n * Find a node by uniqueness constraint.\n *\n * Looks up a live node by the named constraint key computed from `props`.\n * Returns the node if found, or undefined. Soft-deleted nodes are excluded.\n *\n * @param constraintName - Name of the uniqueness constraint to match on\n * @param props - Properties to compute the constraint key from\n */\n findByConstraint: (\n constraintName: CN,\n props: z.input<N[\"schema\"]>,\n ) => Promise<Node<N> | undefined>;\n\n /**\n * Batch version of findByConstraint.\n *\n * Results are returned in the same order as the input items.\n * Returns undefined for entries that don't match.\n */\n bulkFindByConstraint: (\n constraintName: CN,\n items: readonly Readonly<{\n props: z.input<N[\"schema\"]>;\n }>[],\n ) => Promise<(Node<N> | undefined)[]>;\n\n /**\n * Batched candidate retrieval against a declared node index.\n *\n * For each input item, TypeGraph computes the index lookup key from\n * `index.fields` (JSON-pointer extraction, partial-`where` applied to\n * stored rows, null-safe matching) and returns the live, non-soft-deleted\n * nodes that share that key. Unlike {@link bulkFindByConstraint}, the index\n * may be non-unique, so each input yields a (possibly empty) array.\n *\n * Results preserve input order; each inner array is ordered by node id.\n * Empty input returns `[]`. An unknown index name throws\n * `NodeIndexNotFoundError`; a type-incompatible indexed field throws\n * `ValidationError`. This is candidate retrieval, not a uniqueness or\n * identity guarantee.\n *\n * @param indexName - Name of the declared node index to match on\n * @param items - Records whose `props` supply the indexed-field values\n * @param options - Optional `limitPerInput` to bound per-input fan-out\n */\n bulkFindByIndex: (\n indexName: string,\n items: readonly Readonly<{\n props: Partial<z.input<N[\"schema\"]>>;\n }>[],\n options?: NodeBulkFindByIndexOptions,\n ) => Promise<readonly Node<N>[][]>;\n\n /**\n * Get an existing node by uniqueness constraint, or create a new one.\n *\n * Looks up a node by the named constraint key computed from `props`.\n * If found, returns it (optionally updating with `ifExists: \"update\"`).\n * If not found, creates a new node. Soft-deleted matches are always resurrected.\n *\n * @param constraintName - Name of the uniqueness constraint to match on\n * @param props - Full properties for create, or merge source for update\n * @param options - Existing record behavior (default: \"return\")\n */\n getOrCreateByConstraint: (\n constraintName: CN,\n props: z.input<N[\"schema\"]>,\n options?: NodeGetOrCreateByConstraintOptions,\n ) => Promise<NodeGetOrCreateByConstraintResult<N>>;\n\n /**\n * Batch version of getOrCreateByConstraint.\n *\n * Results are returned in the same order as the input items.\n * Atomic when the backend supports transactions.\n */\n bulkGetOrCreateByConstraint: (\n constraintName: CN,\n items: readonly Readonly<{\n props: z.input<N[\"schema\"]>;\n }>[],\n options?: NodeGetOrCreateByConstraintOptions,\n ) => Promise<NodeGetOrCreateByConstraintResult<N>[]>;\n}>;\n\n/**\n * Reference to a node of a specific kind.\n *\n * Accepts either:\n * - A Node instance of the correct kind\n * - An explicit { kind, id } object with the correct kind name\n *\n * This provides compile-time checking that edge endpoints match the\n * allowed node kinds defined in the edge registration.\n */\nexport type NodeRef<N extends NodeType = NodeType> =\n Node<N> | Readonly<{ kind: N[\"kind\"]; id: string }>;\n\n/**\n * Options for creating an edge.\n */\ntype EdgeCreateOptions = Readonly<{\n id?: string;\n validFrom?: string;\n validTo?: string;\n}>;\n\n/**\n * Arguments for edge creation, with props optional when schema allows empty object.\n *\n * Uses `{}` to check if an empty object literal satisfies the schema input type.\n */\n/* eslint-disable @typescript-eslint/no-empty-object-type -- {} is intentional: checking if empty object satisfies schema */\ntype EdgeCreateArguments<E extends AnyEdgeType> =\n {} extends z.input<E[\"schema\"]> ?\n [props?: z.input<E[\"schema\"]>, options?: EdgeCreateOptions]\n : [props: z.input<E[\"schema\"]>, options?: EdgeCreateOptions];\n/* eslint-enable @typescript-eslint/no-empty-object-type */\n\n/**\n * A collection of edges of a specific type.\n *\n * Provides ergonomic CRUD operations for a single edge type.\n * The From and To type parameters enforce that edge endpoints\n * match the allowed node types at compile time.\n *\n * @example\n * ```typescript\n * // Create an edge - pass Node objects directly\n * const edge = await store.edges.worksAt.create(alice, acme, { role: \"Engineer\" });\n *\n * // TypeScript error: Company is not a valid 'from' type for worksAt\n * // store.edges.worksAt.create(acme, alice, { role: \"Engineer\" });\n *\n * // For edges with empty schemas, props is optional\n * await store.edges.wrote.create(author, book);\n *\n * // Find edges from a node\n * const edges = await store.edges.worksAt.findFrom(alice);\n * ```\n */\nexport type EdgeCollection<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Readonly<{\n /**\n * Create a new edge.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n *\n * @param from - Source node (must be one of the allowed 'from' types)\n * @param to - Target node (must be one of the allowed 'to' types)\n * @param args - Edge properties (optional if schema is empty) and creation options\n */\n create: (\n from: NodeRef<From>,\n to: NodeRef<To>,\n ...args: EdgeCreateArguments<E>\n ) => Promise<Edge<E, From, To>>;\n\n /** Get an edge by ID */\n getById: (\n id: EdgeId<E>,\n options?: QueryOptions,\n ) => Promise<Edge<E, From, To> | undefined>;\n\n /** Get multiple edges by ID, preserving input order (undefined for missing) */\n getByIds: (\n ids: readonly EdgeId<E>[],\n options?: QueryOptions,\n ) => Promise<readonly (Edge<E, From, To> | undefined)[]>;\n\n /** Update an edge's properties */\n update: (\n id: EdgeId<E>,\n props: Partial<z.input<E[\"schema\"]>>,\n options?: Readonly<{ validTo?: string }>,\n ) => Promise<Edge<E, From, To>>;\n\n /**\n * Find edges from a specific node.\n *\n * Honors the same temporal model as `getById` / `find`: with no\n * `options`, the graph's default `temporalMode` applies (excluding\n * soft-deleted edges and, in `current` / `asOf` modes, edges outside\n * their validity window). Pass `temporalMode` / `asOf` to read the\n * endpoint's edges at another temporal coordinate.\n */\n findFrom: (\n from: NodeRef<From>,\n options?: QueryOptions,\n ) => Promise<Edge<E, From, To>[]>;\n\n /**\n * Find edges to a specific node.\n *\n * Temporal semantics mirror {@link EdgeCollection.findFrom}.\n */\n findTo: (\n to: NodeRef<To>,\n options?: QueryOptions,\n ) => Promise<Edge<E, From, To>[]>;\n\n /**\n * Find the edges from a SET of source nodes in one read.\n *\n * `findFrom` with a widened endpoint predicate and nothing else: the same\n * temporal model, the same soft-delete filtering, and the same per-source\n * ordering — but `from_id IN (...)` instead of `from_id = ?`, so a page of\n * N sources costs one statement per distinct source kind and bind-budget\n * chunk rather than N singleton statements.\n *\n * Results are grouped per input: the outer array is parallel to `froms`\n * (index `i` holds the edges of `froms[i]`), and repeated inputs each get\n * their own copy of the same edge set. Empty input returns `[]`; a source\n * with no edges gets an empty array. Large inputs are split across\n * statements to respect the backend's bound-parameter budget, which is\n * invisible in the result.\n *\n * Requires a backend implementing `findEdgesByEndpointSet` — both bundled\n * Drizzle backends do. On one that does not, this **refuses** with a\n * `ConfigurationError` rather than looping `findFrom` per input: asking for\n * a bulk read is asking for set-oriented statements, and silently issuing N\n * singleton statements is the cost surprise the method exists to remove.\n *\n * @param froms - Source nodes to read the edges of\n * @param options - Temporal coordinate plus optional `limitPerInput`\n * @throws {ConfigurationError} when the backend cannot read an endpoint set\n */\n bulkFindFrom: (\n froms: readonly NodeRef<From>[],\n options?: EdgeBulkFindEndpointOptions,\n ) => Promise<readonly Edge<E, From, To>[][]>;\n\n /**\n * Find the edges into a SET of target nodes in one read.\n *\n * Mirrors {@link EdgeCollection.bulkFindFrom} on the `to` endpoint.\n */\n bulkFindTo: (\n tos: readonly NodeRef<To>[],\n options?: EdgeBulkFindEndpointOptions,\n ) => Promise<readonly Edge<E, From, To>[][]>;\n\n /**\n * Deferred variant of `findFrom` for use with `store.batch()`.\n *\n * Returns a `BatchableQuery` instead of executing immediately. Accepts\n * the same temporal `options` as {@link EdgeCollection.findFrom}.\n *\n * Batching these still issues one statement per call — it does not merge\n * the reads, and whether they share a connection is up to the adapter. It\n * is not a snapshot: PostgreSQL's default read-committed isolation lets a\n * later read observe a commit the earlier ones did not. To read edges for\n * many sources in one statement, traverse from them in a single query.\n */\n batchFindFrom: (\n from: NodeRef<From>,\n options?: QueryOptions,\n ) => BatchableQuery<Edge<E, From, To>>;\n\n /**\n * Deferred variant of `findTo` for use with `store.batch()`.\n *\n * Returns a `BatchableQuery` instead of executing immediately. Accepts\n * the same temporal `options` as {@link EdgeCollection.findTo}. Costs one\n * statement per call, like {@link EdgeCollection.batchFindFrom}.\n */\n batchFindTo: (\n to: NodeRef<To>,\n options?: QueryOptions,\n ) => BatchableQuery<Edge<E, From, To>>;\n\n /**\n * Deferred variant of `findByEndpoints` for use with `store.batch()`.\n *\n * Returns a `BatchableQuery` that yields a 0-or-1 element array\n * (matching `findByEndpoints`' at-most-one semantics). Costs one statement\n * per call, like {@link EdgeCollection.batchFindFrom}.\n */\n batchFindByEndpoints: (\n from: NodeRef<From>,\n to: NodeRef<To>,\n options?: EdgeFindByEndpointsOptions<E>,\n temporal?: QueryOptions,\n ) => BatchableQuery<Edge<E, From, To>>;\n\n /** Delete an edge (soft delete - sets deletedAt timestamp) */\n delete: (id: EdgeId<E>) => Promise<void>;\n\n /**\n * Permanently delete an edge from the database.\n *\n * Unlike `delete()` which performs a soft delete, this permanently\n * removes the edge record.\n *\n * **Warning:** This operation is irreversible and should be used carefully.\n * Consider using soft delete (`delete()`) for most use cases.\n */\n hardDelete: (id: EdgeId<E>) => Promise<void>;\n\n /** Find edges matching endpoint and pagination criteria */\n find: (\n filter?: Readonly<{\n from?: NodeRef<From>;\n to?: NodeRef<To>;\n limit?: number;\n offset?: number;\n }>,\n temporal?: QueryOptions,\n ) => Promise<Edge<E, From, To>[]>;\n\n /** Count edges matching criteria */\n count: (\n filter?: Readonly<{\n from?: NodeRef<From>;\n to?: NodeRef<To>;\n }>,\n temporal?: QueryOptions,\n ) => Promise<number>;\n\n /**\n * Create multiple edges in a batch.\n *\n * More efficient than calling create() multiple times.\n * Use `bulkInsert` for the dedicated fast path that skips returning results.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n */\n bulkCreate: (\n items: readonly Readonly<{\n from: NodeRef<From>;\n to: NodeRef<To>;\n props?: z.input<E[\"schema\"]>;\n id?: string;\n validFrom?: string;\n validTo?: string;\n }>[],\n ) => Promise<Edge<E, From, To>[]>;\n\n /**\n * Create or update multiple edges in a batch.\n *\n * For each item, if an edge with the given ID exists, updates it.\n * Otherwise, creates a new edge with that ID.\n *\n * Items are applied in order, so a **repeated id** within one batch is\n * last-write-wins: the first item creates or updates the edge, and every later\n * copy is an update over the value the earlier item wrote. This holds whether\n * or not the edge existed before the batch. An update never repoints an edge,\n * so every item's `from` / `to` must exactly restate the endpoints already\n * owned by that id (including an earlier item in the same batch). A mismatch\n * is refused with `ValidationError` carrying\n * `EDGE_IDENTITY_MISMATCH_CODE`; it is never silently ignored.\n *\n * `validFrom` applies when the upsert CREATES the row and when it RESURRECTS\n * a tombstoned one — both write a fresh validity window — defaulting to the\n * operation's timestamp when omitted. An update to a LIVE row stores no lower\n * bound, because that row's is already history, so one naming a different\n * instant is REFUSED (`ValidationError` carrying\n * `IMMUTABLE_VALIDITY_LOWER_BOUND_CODE`) rather than ignored. Restating the\n * bound the row already holds is accepted and changes nothing.\n *\n * **Limitation — a batch cannot hand a constrained slot from one edge to\n * another.** Item order settles the final props, but the writes are grouped:\n * every create runs before every update. So a batch where one item frees the\n * slot a `cardinality` constraint allows and a later item claims it — ending\n * the lone `oneActive` edge from a source while creating its replacement —\n * checks the create while the old edge is still active, and the whole batch\n * fails with a `CardinalityError`. Applying the update first, as\n * separate `update` / `create` calls, succeeds. A batch states the set of\n * edges it wants, not a script to reach them by; the failure is loud rather\n * than silent, and the workaround is to split the handoff across two batches\n * (free the slot, then claim it) or to apply those items individually.\n */\n bulkUpsertById: (\n items: readonly Readonly<{\n id: EdgeId<E>;\n from: NodeRef<From>;\n to: NodeRef<To>;\n props?: z.input<E[\"schema\"]>;\n validFrom?: string;\n validTo?: string;\n }>[],\n ) => Promise<Edge<E, From, To>[]>;\n\n /**\n * Insert multiple edges without returning results.\n *\n * This is the dedicated fast path for bulk inserts. Unlike `bulkCreate`\n * with `returnResults: false`, the intent is unambiguous: no results\n * are returned and the operation is wrapped in a transaction.\n *\n * `validFrom` defaults to the operation's creation timestamp when omitted.\n */\n bulkInsert: (\n items: readonly Readonly<{\n from: NodeRef<From>;\n to: NodeRef<To>;\n props?: z.input<E[\"schema\"]>;\n id?: string;\n validFrom?: string;\n validTo?: string;\n }>[],\n ) => Promise<void>;\n\n /**\n * Delete multiple edges by ID.\n *\n * Atomic when the backend supports transactions. Silently ignores IDs\n * that don't exist.\n *\n * The batch runs as one transaction, checking each id's kind against the\n * authoritative row as it goes. An id owned by another edge kind is\n * refused with `ValidationError` carrying `EDGE_IDENTITY_MISMATCH_CODE`;\n * because the whole batch is one transaction, that refusal rolls back\n * every delete already applied for an earlier id in the same batch.\n */\n bulkDelete: (ids: readonly EdgeId<E>[]) => Promise<void>;\n\n /**\n * Find an edge by endpoints and optional property fields.\n *\n * Returns the first matching edge at the read coordinate, or undefined.\n * Honors the temporal model like `findFrom` / `findTo`: by default\n * (`current` mode) soft-deleted and out-of-window edges are excluded; under\n * `includeTombstones` a soft-deleted edge can be returned.\n *\n * @param from - Source node\n * @param to - Target node\n * @param options - Match criteria (matchOn fields and property values)\n * @param temporal - Temporal coordinate. With no `temporal`, the graph's\n * default `temporalMode` applies (so under the default `\"current\"` mode,\n * edges outside their validity window are excluded). Pass\n * `temporalMode` / `asOf` to read the edge as of another coordinate.\n */\n findByEndpoints: (\n from: NodeRef<From>,\n to: NodeRef<To>,\n options?: EdgeFindByEndpointsOptions<E>,\n temporal?: QueryOptions,\n ) => Promise<Edge<E, From, To> | undefined>;\n\n /**\n * Get an existing edge by endpoints and optional property fields, or create a new one.\n *\n * Matches edges of this kind between `(from, to)`. When `matchOn` specifies\n * property fields, only edges whose properties match on those fields are considered.\n * Soft-deleted matches are resurrected when cardinality allows.\n *\n * `validFrom` applies on the create and RESURRECT branches, defaulting to the\n * operation's creation timestamp when omitted. On the `ifExists: \"update\"`\n * branch a live edge's lower bound is history and cannot be stored, so a\n * `validFrom` naming a different instant is REFUSED (`ValidationError`\n * carrying `IMMUTABLE_VALIDITY_LOWER_BOUND_CODE`); restating the bound the\n * edge holds is accepted. A returned existing edge (`ifExists: \"return\"`)\n * writes nothing and judges nothing — the window options describe the row to\n * create if none is found. `validTo` applies on create, update, and\n * resurrection, but not when an existing edge is returned without a write.\n *\n * @param from - Source node\n * @param to - Target node\n * @param props - Full properties for create, or merge source for update\n * @param options - Match criteria and conflict resolution\n */\n getOrCreateByEndpoints: (\n from: NodeRef<From>,\n to: NodeRef<To>,\n props: z.input<E[\"schema\"]>,\n options?: EdgeGetOrCreateByEndpointsOptions<E>,\n ) => Promise<EdgeGetOrCreateByEndpointsResult<E, From, To>>;\n\n /**\n * Batch version of getOrCreateByEndpoints.\n *\n * Results are returned in the same order as the input items.\n * Atomic when the backend supports transactions.\n */\n bulkGetOrCreateByEndpoints: (\n items: readonly Readonly<{\n from: NodeRef<From>;\n to: NodeRef<To>;\n props: z.input<E[\"schema\"]>;\n validFrom?: string;\n validTo?: string;\n onImmutableLowerBound?: \"preserve\" | \"refuse\";\n }>[],\n options?: Pick<\n EdgeGetOrCreateByEndpointsOptions<E>,\n \"matchOn\" | \"ifExists\"\n >,\n ) => Promise<EdgeGetOrCreateByEndpointsResult<E, From, To>[]>;\n}>;\n\n// ============================================================\n// Type Helpers\n// ============================================================\n\n/**\n * Extract uniqueness constraint names from a NodeRegistration.\n *\n * - Returns `never` when no uniqueness constraints are configured.\n * - Returns a literal union when names are inferred via `defineGraph` const params.\n * - Falls back to `string` when names are widened/dynamic.\n */\nexport type ConstraintNames<R extends NodeRegistration> =\n \"unique\" extends keyof R ?\n R[\"unique\"] extends readonly { readonly name: infer N }[] ?\n N & string\n : string\n : never;\n\n/**\n * Extract the union of 'from' node types from an EdgeRegistration.\n */\ntype EdgeFromTypes<R extends EdgeRegistration> =\n R[\"from\"] extends readonly (infer N)[] ? N : never;\n\n/**\n * Extract the union of 'to' node types from an EdgeRegistration.\n */\ntype EdgeToTypes<R extends EdgeRegistration> =\n R[\"to\"] extends readonly (infer N)[] ? N : never;\n\n/**\n * Create a type-safe EdgeCollection from an EdgeRegistration.\n * Extracts the edge type and from/to node types automatically.\n */\nexport type TypedEdgeCollection<R extends EdgeRegistration> = EdgeCollection<\n R[\"type\"],\n EdgeFromTypes<R> extends NodeType ? EdgeFromTypes<R> : NodeType,\n EdgeToTypes<R> extends NodeType ? EdgeToTypes<R> : NodeType\n>;\n\n// ============================================================\n// Transaction Types\n// ============================================================\n\n// ============================================================\n// Graph Collection Maps\n// ============================================================\n\n/** Mapped type of all node collections for a graph. */\nexport type GraphNodeCollections<G extends GraphDef> = {\n [K in keyof G[\"nodes\"] & string]-?: NodeCollection<\n G[\"nodes\"][K][\"type\"],\n ConstraintNames<G[\"nodes\"][K]>\n >;\n};\n\n/** Mapped type of all edge collections for a graph. */\nexport type GraphEdgeCollections<G extends GraphDef> = {\n [K in keyof G[\"edges\"] & string]-?: TypedEdgeCollection<G[\"edges\"][K]>;\n};\n\n// ============================================================\n// StoreView read-only collection surfaces\n// ============================================================\n\n/** Temporal-aware node reads — a {@link StoreView} pins these. */\nexport type NodeTemporalReads<\n N extends NodeType,\n CN extends string = string,\n> = Pick<NodeCollection<N, CN>, (typeof NODE_TEMPORAL_READ_NAMES)[number]>;\n\n/**\n * Current-state-only node reads (constraint / index lookups). No temporal\n * axis, so a {@link StoreView} delegates them on a `current` pin and refuses\n * them on a temporal pin.\n */\nexport type NodeCurrentReads<\n N extends NodeType,\n CN extends string = string,\n> = Pick<NodeCollection<N, CN>, (typeof CURRENT_ONLY_READ_NAMES)[number]>;\n\n/** Node writes — never available on a read-only {@link StoreView}. */\nexport type NodeWrites<N extends NodeType, CN extends string = string> = Pick<\n NodeCollection<N, CN>,\n (typeof NODE_WRITE_NAMES)[number]\n>;\n\n/** Temporal-aware edge reads — a {@link StoreView} pins these. */\nexport type EdgeTemporalReads<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Pick<\n EdgeCollection<E, From, To>,\n (typeof EDGE_TEMPORAL_READ_NAMES)[number]\n>;\n\n/**\n * Deferred edge reads for `store.batch()` — absent from a {@link StoreView},\n * which has no batch context.\n */\nexport type EdgeBatchReads<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Pick<EdgeCollection<E, From, To>, (typeof EDGE_BATCH_READ_NAMES)[number]>;\n\n/** Edge writes — never available on a read-only {@link StoreView}. */\nexport type EdgeWrites<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Pick<EdgeCollection<E, From, To>, (typeof EDGE_WRITE_NAMES)[number]>;\n\n/**\n * The read-only node surface a {@link StoreView} exposes for one node kind.\n * The temporal reads drop the per-call temporal argument — the pin owns the\n * axis; the current reads ({@link NodeCurrentReads}) are exposed as-is\n * (delegated on a `current` view, refused on a temporal pin). Writes live on\n * the live `Store`. The conformance test asserts the temporal part equals the\n * pinned form of {@link NodeTemporalReads}.\n */\nexport type StoreViewNodeCollection<\n N extends NodeType,\n CN extends string = string,\n> = Readonly<{\n /** Get a node by ID at the view's pinned coordinate. */\n getById: (id: NodeId<N>) => Promise<Node<N> | undefined>;\n\n /** Get multiple nodes by ID, preserving input order (undefined for missing). */\n getByIds: (\n ids: readonly NodeId<N>[],\n ) => Promise<readonly (Node<N> | undefined)[]>;\n\n /** Find nodes matching criteria at the view's pinned coordinate. */\n find: (\n filter?: Readonly<{\n where?: (accessor: NodeAccessor<N>) => Predicate;\n limit?: number;\n offset?: number;\n }>,\n ) => Promise<Node<N>[]>;\n\n /** Count nodes at the view's pinned coordinate. */\n count: () => Promise<number>;\n}> &\n NodeCurrentReads<N, CN>;\n\n/**\n * The read-only edge surface a {@link StoreView} exposes for one edge\n * kind, mirroring {@link StoreViewNodeCollection}. Every edge read —\n * including `findByEndpoints` — honors the pin via the same temporal model,\n * so (unlike nodes) there are no current-state-only edge reads.\n */\nexport type StoreViewEdgeCollection<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Readonly<{\n /** Get an edge by ID at the view's pinned coordinate. */\n getById: (id: EdgeId<E>) => Promise<Edge<E, From, To> | undefined>;\n\n /** Get multiple edges by ID, preserving input order (undefined for missing). */\n getByIds: (\n ids: readonly EdgeId<E>[],\n ) => Promise<readonly (Edge<E, From, To> | undefined)[]>;\n\n /** Find edges matching endpoint and pagination criteria. */\n find: (\n filter?: Readonly<{\n from?: NodeRef<From>;\n to?: NodeRef<To>;\n limit?: number;\n offset?: number;\n }>,\n ) => Promise<Edge<E, From, To>[]>;\n\n /** Count edges matching criteria at the view's pinned coordinate. */\n count: (\n filter?: Readonly<{ from?: NodeRef<From>; to?: NodeRef<To> }>,\n ) => Promise<number>;\n\n /** Find edges from a specific node at the view's pinned coordinate. */\n findFrom: (from: NodeRef<From>) => Promise<Edge<E, From, To>[]>;\n\n /** Find edges to a specific node at the view's pinned coordinate. */\n findTo: (to: NodeRef<To>) => Promise<Edge<E, From, To>[]>;\n\n /** Find the edges from a set of source nodes at the view's pinned coordinate. */\n bulkFindFrom: (\n froms: readonly NodeRef<From>[],\n options?: EdgeBulkFindOptions,\n ) => Promise<readonly Edge<E, From, To>[][]>;\n\n /** Find the edges into a set of target nodes at the view's pinned coordinate. */\n bulkFindTo: (\n tos: readonly NodeRef<To>[],\n options?: EdgeBulkFindOptions,\n ) => Promise<readonly Edge<E, From, To>[][]>;\n\n /** Find the edge between two endpoints at the view's pinned coordinate. */\n findByEndpoints: (\n from: NodeRef<From>,\n to: NodeRef<To>,\n options?: EdgeFindByEndpointsOptions<E>,\n ) => Promise<Edge<E, From, To> | undefined>;\n}>;\n\n/**\n * Read-only view edge collection derived from an `EdgeRegistration`,\n * extracting the edge type and from/to node types — the read-only\n * counterpart of {@link TypedEdgeCollection}.\n */\nexport type TypedStoreViewEdgeCollection<R extends EdgeRegistration> =\n StoreViewEdgeCollection<\n R[\"type\"],\n EdgeFromTypes<R> extends NodeType ? EdgeFromTypes<R> : NodeType,\n EdgeToTypes<R> extends NodeType ? EdgeToTypes<R> : NodeType\n >;\n\n/** Mapped type of all read-only view node collections for a graph. */\nexport type StoreViewNodeCollections<G extends GraphDef> = {\n [K in keyof G[\"nodes\"] & string]-?: StoreViewNodeCollection<\n G[\"nodes\"][K][\"type\"]\n >;\n};\n\n/** Mapped type of all read-only view edge collections for a graph. */\nexport type StoreViewEdgeCollections<G extends GraphDef> = {\n [K in keyof G[\"edges\"] & string]-?: TypedStoreViewEdgeCollection<\n G[\"edges\"][K]\n >;\n};\n\n/** Options for one bounded, forward-only recorded-time collection scan. */\nexport type RecordedScanOptions = Readonly<{\n /** Maximum entities to return. Defaults to 1,000 and cannot exceed 1,000. */\n limit?: number;\n /** Opaque cursor returned by the preceding page. */\n after?: string;\n}>;\n\n/** One page from a deterministic recorded-time collection scan. */\nexport type RecordedScanPage<T> = Readonly<{\n /** Entities ordered by canonical id ascending. */\n data: readonly T[];\n /** Cursor for the next page, or `undefined` when the scan is complete. */\n nextCursor: string | undefined;\n /** Whether another page exists after this one. */\n hasNextPage: boolean;\n}>;\n\n/** Recorded-time reconstructing reads for one node kind. */\nexport type RecordedStoreViewNodeCollection<N extends NodeType> = Pick<\n StoreViewNodeCollection<N>,\n (typeof RECORDED_POINT_READ_NAMES)[number]\n> &\n Readonly<{\n /** Scan one bounded page at the view's pinned coordinate. */\n scan: (options?: RecordedScanOptions) => Promise<RecordedScanPage<Node<N>>>;\n }>;\n\n/** Recorded-time reconstructing reads for one edge kind. */\nexport type RecordedStoreViewEdgeCollection<\n E extends AnyEdgeType,\n From extends NodeType = NodeType,\n To extends NodeType = NodeType,\n> = Pick<\n StoreViewEdgeCollection<E, From, To>,\n (typeof RECORDED_POINT_READ_NAMES)[number]\n> &\n Readonly<{\n /** Scan one bounded page at the view's pinned coordinate. */\n scan: (\n options?: RecordedScanOptions,\n ) => Promise<RecordedScanPage<Edge<E, From, To>>>;\n }>;\n\n/** Recorded-time edge collection derived from an `EdgeRegistration`. */\nexport type TypedRecordedStoreViewEdgeCollection<R extends EdgeRegistration> =\n RecordedStoreViewEdgeCollection<\n R[\"type\"],\n EdgeFromTypes<R> extends NodeType ? EdgeFromTypes<R> : NodeType,\n EdgeToTypes<R> extends NodeType ? EdgeToTypes<R> : NodeType\n >;\n\n/** Mapped type of all recorded-time node reconstructing-read collections. */\nexport type RecordedStoreViewNodeCollections<G extends GraphDef> = {\n [K in keyof G[\"nodes\"] & string]-?: RecordedStoreViewNodeCollection<\n G[\"nodes\"][K][\"type\"]\n >;\n};\n\n/** Mapped type of all recorded-time edge reconstructing-read collections. */\nexport type RecordedStoreViewEdgeCollections<G extends GraphDef> = {\n [K in keyof G[\"edges\"] & string]-?: TypedRecordedStoreViewEdgeCollection<\n G[\"edges\"][K]\n >;\n};\n\n// ============================================================\n// Transaction Context\n// ============================================================\n\n/**\n * Whether — and why — `tx.sql` can be used on a transaction context. A single\n * required discriminant covering exactly the four states raw-SQL access can be\n * in, so an adapter caller branches on capability instead of truthiness-testing\n * `tx.sql`. The non-available variants omit `sql` entirely, so even reading the\n * handle requires first narrowing `sqlAvailability` to `\"available\"`. The\n * runtime object keeps a fail-loud getter under history / revision tracking for\n * JavaScript and type-suppressed callers. See\n * {@link AdapterTransactionContext} for the per-value semantics.\n */\nexport type SqlAvailability =\n \"available\" | \"history\" | \"revisionTracking\" | \"unavailable\";\n\ntype AdapterTransactionSqlAccess<TNativeTransaction> =\n | Readonly<{\n sql: TNativeTransaction;\n sqlAvailability: \"available\";\n }>\n | Readonly<{\n sqlAvailability: \"history\" | \"revisionTracking\";\n }>\n | Readonly<{\n sqlAvailability: \"unavailable\";\n }>;\n\nexport const TRANSACTION_RUNTIME: unique symbol = typeGraphGlobalSymbol(\n \"transaction-runtime-v1\",\n);\n\ntype TransactionRuntime = Readonly<{\n backend: TransactionBackend;\n runNodeOperationHooks: <T>(\n operation: \"create\" | \"update\" | \"delete\",\n kind: string,\n id: string,\n fn: () => Promise<T>,\n ) => Promise<T>;\n}>;\n\n/**\n * The portable transaction context mirrors the Store's typed graph operations\n * while exposing only a read-only backend projection bound to the transaction.\n * Adapter-native handles are available only through\n * {@link AdapterTransactionContext}; arbitrary backend writes are absent from\n * every public transaction context. TypeGraph's non-enumerable symbol port is\n * an unsupported implementation detail, not a JavaScript security boundary:\n * reflective code can still discover symbol properties.\n *\n * @example\n * ```typescript\n * await store.transaction(async (tx) => {\n * const person = await tx.nodes.Person.create({ name: \"Alice\" });\n * const company = await tx.nodes.Company.create({ name: \"Acme\" });\n * await tx.edges.worksAt.create(person, company, { role: \"Engineer\" });\n * });\n * ```\n */\ntype TransactionCollections<G extends GraphDef> = Readonly<{\n [TRANSACTION_RUNTIME]: TransactionRuntime;\n nodes: GraphNodeCollections<G>;\n edges: GraphEdgeCollections<G>;\n /** Read-only backend projection bound to the same graph transaction. */\n backend: TransactionReadBackend;\n /**\n * Runtime string-keyed node collection access, mirroring\n * `Store.getNodeCollection`. Returns `undefined` when `kind` is not\n * registered in this graph.\n */\n getNodeCollection: (kind: string) => DynamicNodeCollection | undefined;\n}> &\n (G[\"identity\"] extends GraphIdentityConfig ?\n Readonly<{ identity: IdentityFacade<G> }>\n : Readonly<Record<never, never>>);\n\n/**\n * A portable transaction context containing only TypeGraph-owned graph\n * operations. Managed Stores use this surface so adapter-native handles never\n * enter their public contract.\n */\nexport type TransactionContext<G extends GraphDef> = TransactionCollections<G>;\n\n/**\n * A transaction context exposed by an {@link AdapterStore}. In addition to the\n * portable graph collections, it carries the adapter-native handle when that\n * capability is available. The TypeGraph backend remains the same runtime\n * read projection as the portable context; adapter-native writes intentionally\n * go through `sql`, making that escape hatch explicit.\n */\nexport type AdapterTransactionContext<\n G extends GraphDef,\n TNativeTransaction,\n> = TransactionCollections<G> & AdapterTransactionSqlAccess<TNativeTransaction>;\n\n/**\n * Scoped write measurement, available only on the receipt-enabled transaction\n * contexts (`transactionWithReceipt`, `withRecordedTransaction`). Runs `fn`,\n * passing it a **scoped context** — a second view over the same transaction — and\n * returns a {@link TransactionOutcome} whose receipt counts exactly the writes\n * made *through that scoped context* (`scoped.nodes` / `scoped.edges`).\n *\n * Attribution is by **which context you write through**, not by timing. A write\n * through the scoped context counts in both the scope and the outer receipt (it\n * happened in the transaction); a write through the outer `tx` during the scope\n * counts only in the outer receipt. This makes overlapping and concurrent\n * measures safe by construction — two scopes running under `Promise.all`, each\n * writing through its own scoped context, never cross-count. Nesting composes:\n * `scoped.measure(...)` opens a child scope that counts in itself, every\n * ancestor scope, and the outer receipt.\n *\n * Counts otherwise inherit {@link TransactionReceipt} (bulk by input length, a\n * rejected write counts 0). The returned receipt's `recorded` is **always\n * `undefined`**: the recorded commit instant is a per-transaction flush concern,\n * unknowable mid-transaction.\n */\nexport type ScopedMeasure<Context> = <T>(\n fn: (scoped: Context) => Promise<T>,\n) => Promise<TransactionOutcome<T>>;\n\n/**\n * A {@link TransactionContext} that also exposes {@link ScopedMeasure}. Only the\n * receipt-enabled entry points (`transactionWithReceipt`,\n * `withRecordedTransaction`) hand a callback this type; plain `transaction()`\n * contexts have no recorder and therefore no `measure`, keeping that path\n * zero-overhead. Assignable to {@link TransactionContext}, so a projector helper\n * typed `(tx: TransactionContext<G>) => ...` accepts a measurable context. The\n * scoped context handed to `measure` is itself measurable, so scopes nest.\n */\nexport type MeasurableTransactionContext<G extends GraphDef> =\n TransactionContext<G> &\n Readonly<{\n measure: ScopedMeasure<MeasurableTransactionContext<G>>;\n }>;\n\n/** Receipt-enabled transaction context for an {@link AdapterStore}. */\nexport type MeasurableAdapterTransactionContext<\n G extends GraphDef,\n TNativeTransaction,\n> = AdapterTransactionContext<G, TNativeTransaction> &\n Readonly<{\n measure: ScopedMeasure<\n MeasurableAdapterTransactionContext<G, TNativeTransaction>\n >;\n }>;\n\n// ============================================================\n// Dynamic Collection Types (widened for runtime dispatch)\n// ============================================================\n\n/**\n * Replace branded `NodeId` / `EdgeId` with plain `string` in each\n * method's parameter list. Return types are preserved unchanged.\n *\n * Handles three shapes:\n * 1. Direct branded ID parameter → `string`\n * 2. `readonly NodeId[]` / `readonly EdgeId[]` → `readonly string[]`\n * 3. Branded IDs nested one level inside bulk-item object arrays\n */\ntype WidenBrandedIds<T> = {\n readonly [K in keyof T]: T[K] extends (...args: infer A) => infer R ?\n (...args: { [P in keyof A]: UnbrandParam<A[P]> }) => R\n : T[K];\n};\n\n/** Replace a branded ID with `string`, recursing one level into arrays. */\ntype UnbrandParam<T> =\n T extends NodeId<NodeType> ? string\n : T extends EdgeId<AnyEdgeType> ? string\n : T extends readonly NodeId<NodeType>[] ? readonly string[]\n : T extends readonly EdgeId<AnyEdgeType>[] ? readonly string[]\n : T extends readonly (infer Item extends Record<string, unknown>)[] ?\n readonly UnbrandRecord<Item>[]\n : T;\n\n/** Replace branded ID values in object properties (does not recurse into nested structures). */\ntype UnbrandRecord<T extends Record<string, unknown>> = {\n readonly [K in keyof T]: T[K] extends NodeId<NodeType> ? string\n : T[K] extends EdgeId<AnyEdgeType> ? string\n : T[K];\n};\n\n/**\n * A node collection with widened generics for runtime string-keyed access.\n *\n * This is the return type of `store.getNodeCollection(kind)`. It exposes\n * the full `NodeCollection` API but with `NodeType` and `string` constraint\n * names instead of the specific generic parameters, since the concrete type\n * is not known at compile time.\n *\n * ID parameters accept plain `string` instead of branded `NodeId<N>`, since\n * the dynamic path typically receives IDs from edge metadata, snapshots,\n * or external input where the brand is not available.\n */\nexport type DynamicNodeCollection = WidenBrandedIds<\n NodeCollection<NodeType, string>\n>;\n\n/**\n * An edge collection with widened generics for runtime string-keyed access.\n *\n * This is the return type of `store.getEdgeCollection(kind)`. It exposes\n * the full `EdgeCollection` API but with `NodeType` endpoint types, since\n * the concrete from/to types are not known at compile time.\n *\n * ID parameters accept plain `string` instead of branded `EdgeId<E>`, since\n * the dynamic path typically receives IDs from edge metadata, snapshots,\n * or external input where the brand is not available.\n */\nexport type DynamicEdgeCollection = WidenBrandedIds<\n EdgeCollection<AnyEdgeType, NodeType, NodeType>\n>;\n\n// ============================================================\n// Store Projection\n// ============================================================\n\n/**\n * A type-level projection of a store's surface onto a subset of its\n * node and edge collections.\n *\n * Node collections are projected with constraint names erased (`never`),\n * so constraint-based methods like `findByConstraint` become uncallable.\n * This is intentional: unique constraints are graph-registration-level\n * details that differ between graphs sharing the same node types.\n *\n * @example\n * ```typescript\n * type CoreStore = StoreProjection<\n * typeof myGraph,\n * \"Document\" | \"Chunk\",\n * \"hasChunk\"\n * >;\n *\n * async function ingestChunk(\n * store: CoreStore,\n * document: Node<typeof Document>,\n * text: string,\n * ) {\n * const chunk = await store.nodes.Chunk.create({ text });\n * await store.edges.hasChunk.create(document, chunk);\n * return chunk;\n * }\n * ```\n *\n * Both `Store<G>` and `TransactionContext<G>` are structurally assignable\n * to a `StoreProjection` whose keys are a subset of `G`.\n */\nexport type StoreProjection<\n G extends GraphDef,\n N extends keyof G[\"nodes\"] & string = never,\n E extends keyof G[\"edges\"] & string = never,\n> = Readonly<{\n nodes: { [K in N]-?: NodeCollection<G[\"nodes\"][K][\"type\"], never> };\n edges: Pick<GraphEdgeCollections<G>, E>;\n}>;\n","import { type GraphBackend, type TransactionBackend } from \"../backend/types\";\nimport {\n type AllNodeTypes,\n type EdgeKinds,\n type GraphDef,\n type NodeKinds,\n} from \"../core/define-graph\";\nimport { type ReadCoordinate } from \"../core/temporal\";\nimport {\n type AnyEdgeType,\n type EdgeId,\n type NodeId,\n type NodeType,\n} from \"../core/types\";\nimport { type IdentityReadFacade } from \"../identity/types\";\nimport { type InitialQueryBuilder } from \"../query/builder\";\nimport { typeGraphGlobalSymbol } from \"../utils/global-symbol\";\nimport { type InternalGraphAlgorithms } from \"./algorithms\";\nimport {\n type InternalSubgraphOptions,\n type SubgraphProject,\n type SubgraphResult,\n} from \"./subgraph\";\nimport {\n type Edge,\n type Node,\n type RecordedScanOptions,\n type RecordedScanPage,\n TRANSACTION_RUNTIME,\n} from \"./types\";\n\nexport const STORE_RUNTIME: unique symbol =\n typeGraphGlobalSymbol(\"store-runtime-v1\");\n\n/**\n * @internal Operations used by Store-owned views. The port is absent from the\n * public Store contract and non-enumerable at runtime. JavaScript reflection\n * can still discover symbol properties, so this is an unsupported internal\n * surface rather than a security boundary.\n */\nexport type StoreRuntime<G extends GraphDef> = Readonly<{\n backend: GraphBackend;\n sealedQuery: (coordinate: ReadCoordinate) => InitialQueryBuilder<G, \"sealed\">;\n recordedNodeGetById: <N extends NodeType>(\n kind: string,\n id: NodeId<N>,\n coordinate: ReadCoordinate,\n ) => Promise<Node<N> | undefined>;\n recordedNodeGetByIds: <N extends NodeType>(\n kind: string,\n ids: readonly NodeId<N>[],\n coordinate: ReadCoordinate,\n ) => Promise<readonly (Node<N> | undefined)[]>;\n recordedNodeScan: <N extends NodeType>(\n kind: string,\n coordinate: ReadCoordinate,\n options?: RecordedScanOptions,\n ) => Promise<RecordedScanPage<Node<N>>>;\n recordedEdgeGetById: <E extends AnyEdgeType>(\n kind: string,\n id: EdgeId<E>,\n coordinate: ReadCoordinate,\n ) => Promise<Edge<E> | undefined>;\n recordedEdgeGetByIds: <E extends AnyEdgeType>(\n kind: string,\n ids: readonly EdgeId<E>[],\n coordinate: ReadCoordinate,\n ) => Promise<readonly (Edge<E> | undefined)[]>;\n recordedEdgeScan: <E extends AnyEdgeType>(\n kind: string,\n coordinate: ReadCoordinate,\n options?: RecordedScanOptions,\n ) => Promise<RecordedScanPage<Edge<E>>>;\n subgraphAtCoordinate: <\n const EK extends EdgeKinds<G>,\n const NK extends NodeKinds<G> = NodeKinds<G>,\n const P extends SubgraphProject<G, NK, EK> | undefined = undefined,\n >(\n rootId: NodeId<AllNodeTypes<G>>,\n options: InternalSubgraphOptions<G, EK, NK, P>,\n ) => Promise<SubgraphResult<G, NK, EK, P>>;\n algorithmsAtCoordinate: (\n coordinate: ReadCoordinate,\n ) => InternalGraphAlgorithms<G>;\n identityAtCoordinate: (coordinate: ReadCoordinate) => IdentityReadFacade<G>;\n rebuildIdentityClosure: () => Promise<void>;\n validateIdentity: () => Promise<void>;\n /**\n * @internal Reads the graph's identity assertions in transfer shape, honoring\n * this store's SQL binding. Used by interchange export, base-version\n * fingerprinting, and merge staging/diff.\n */\n readCurrentIdentityAssertions: (\n mode: \"state\" | \"archival\",\n options?: Readonly<{\n nodeKinds?: readonly string[];\n includeDeleted?: boolean;\n }>,\n ) => Promise<\n readonly Readonly<{\n id: string;\n relation: \"same\" | \"different\";\n a: Readonly<{ kind: string; id: string }>;\n b: Readonly<{ kind: string; id: string }>;\n validFrom: string;\n validTo?: string | undefined;\n endedBy?: Readonly<{ kind: string; id: string }> | undefined;\n }>[]\n >;\n /**\n * Live nodes (registry kinds only) sharing any of the given bare ids —\n * the cross-kind peer set same-id folding would join. Used by graph-merge's\n * plan-time contradiction simulation to seed its node universe.\n */\n liveNodesSharingIds: (\n ids: readonly string[],\n target?: GraphBackend | TransactionBackend,\n ) => Promise<readonly Readonly<{ kind: string; id: string }>[]>;\n /**\n * Every stored assertion row (ended rows included) for the given assertion\n * ids — the rows the import coordinator's id-conflict check compares\n * against. Used by graph-merge to validate the one-id-one-truth invariant\n * at plan time and inside the commit transaction.\n */\n identityAssertionRowsByIds: (\n ids: readonly string[],\n target?: GraphBackend | TransactionBackend,\n ) => Promise<\n ReadonlyMap<\n string,\n Readonly<{\n id: string;\n relation: \"same\" | \"different\";\n a: Readonly<{ kind: string; id: string }>;\n b: Readonly<{ kind: string; id: string }>;\n validFrom: string;\n validTo?: string | undefined;\n endedBy?: Readonly<{ kind: string; id: string }> | undefined;\n }>\n >\n >;\n /**\n * The CURRENT structural identity class (materialized closure: folds plus\n * asserted links) of each reference, keyed by `refKey` — the\n * `JSON.stringify([kind, id])` serialization exported from\n * `identity/service`, which callers must use to probe the returned map. A\n * missing node coalesces to its singleton. Used by graph-merge's fold-peer\n * window guard to detect class-transitive drift in the plan→commit window.\n */\n structuralIdentityClasses: (\n references: readonly Readonly<{ kind: string; id: string }>[],\n target?: GraphBackend | TransactionBackend,\n ) => Promise<\n ReadonlyMap<string, readonly Readonly<{ kind: string; id: string }>[]>\n >;\n identityAssertionsAtTarget: (\n target: GraphBackend | TransactionBackend,\n mode?: \"state\" | \"archival\",\n ) => Promise<\n readonly Readonly<{\n id: string;\n relation: \"same\" | \"different\";\n a: Readonly<{ kind: string; id: string }>;\n b: Readonly<{ kind: string; id: string }>;\n validFrom: string;\n validTo?: string | undefined;\n endedBy?: Readonly<{ kind: string; id: string }> | undefined;\n }>[]\n >;\n readIdentityAssertionPageAtTarget: (\n target: GraphBackend | TransactionBackend,\n mode: \"state\" | \"archival\",\n options: Readonly<{\n nodeKinds?: readonly string[];\n includeDeleted?: boolean;\n after?: string;\n limit: number;\n }>,\n ) => Promise<\n Readonly<{\n assertions: readonly Readonly<{\n id: string;\n relation: \"same\" | \"different\";\n a: Readonly<{ kind: string; id: string }>;\n b: Readonly<{ kind: string; id: string }>;\n validFrom: string;\n validTo?: string | undefined;\n endedBy?: Readonly<{ kind: string; id: string }> | undefined;\n }>[];\n nextAfter?: string;\n done: boolean;\n }>\n >;\n lockIdentityImportTarget: (\n target: GraphBackend | TransactionBackend,\n ) => Promise<void>;\n foldImportedIdentityNodes: (\n target: GraphBackend | TransactionBackend,\n references: readonly Readonly<{ kind: string; id: string }>[],\n ) => Promise<void>;\n importIdentityAssertionsAtTarget: (\n target: GraphBackend | TransactionBackend,\n assertions: readonly Readonly<{\n id: string;\n relation: \"same\" | \"different\";\n a: Readonly<{ kind: string; id: string }>;\n b: Readonly<{ kind: string; id: string }>;\n validFrom: string;\n validTo?: string | undefined;\n endedBy?: Readonly<{ kind: string; id: string }> | undefined;\n }>[],\n mode: \"state\" | \"archival\",\n ) => Promise<Readonly<{ created: number; skipped: number }>>;\n applyIdentityMergeAtTarget: (\n target: GraphBackend | TransactionBackend,\n retractionIds: readonly string[],\n assertions: readonly Readonly<{\n id: string;\n relation: \"same\" | \"different\";\n a: Readonly<{ kind: string; id: string }>;\n b: Readonly<{ kind: string; id: string }>;\n validFrom: string;\n validTo?: string | undefined;\n endedBy?: Readonly<{ kind: string; id: string }> | undefined;\n }>[],\n ) => Promise<Readonly<{ created: number; retracted: number }>>;\n /**\n * Proves the identity classes of `seeds` carry no contradiction in the state\n * the caller's transaction has just written — the post-write half of\n * graph-merge's identity correctness, scoped to the classes the merge\n * touched. A refusal aborts the caller's transaction; identity-disabled\n * graphs resolve immediately.\n */\n assertIdentityClassesConsistentAtTarget: (\n target: GraphBackend | TransactionBackend,\n seeds: readonly Readonly<{ kind: string; id: string }>[],\n ) => Promise<void>;\n}>;\n\nexport function storeRuntime<G extends GraphDef>(\n store: Readonly<{ [STORE_RUNTIME]?: StoreRuntime<G> }>,\n): StoreRuntime<G> {\n const runtime = store[STORE_RUNTIME];\n if (runtime === undefined) {\n throw new TypeError(\n \"Cannot access this Store's runtime port. The Store may come from an incompatible TypeGraph version.\",\n );\n }\n return runtime;\n}\n\nexport function storeBackend<G extends GraphDef>(\n store: Readonly<{ [STORE_RUNTIME]?: StoreRuntime<G> }>,\n): GraphBackend {\n return storeRuntime(store).backend;\n}\n\ntype TransactionRuntimePort = Readonly<{\n [TRANSACTION_RUNTIME]?: Readonly<{\n backend: TransactionBackend;\n runNodeOperationHooks: TransactionNodeOperationHookRunner;\n }>;\n}>;\n\ntype TransactionNodeOperationHookRunner = <T>(\n operation: \"create\" | \"update\" | \"delete\",\n kind: string,\n id: string,\n fn: () => Promise<T>,\n) => Promise<T>;\n\n/** Returns the full backend for privileged transaction-bound internals. */\nexport function transactionBackend(\n transaction: TransactionRuntimePort,\n): TransactionBackend {\n const runtime = transaction[TRANSACTION_RUNTIME];\n if (runtime === undefined) {\n throw new TypeError(\n \"Cannot access this transaction's runtime port. The transaction may come from an incompatible TypeGraph version.\",\n );\n }\n return runtime.backend;\n}\n\n/** Returns the hook runner paired with a transaction's internal backend. */\nexport function transactionNodeOperationHookRunner(\n transaction: TransactionRuntimePort,\n): TransactionNodeOperationHookRunner {\n const runtime = transaction[TRANSACTION_RUNTIME];\n if (runtime === undefined) {\n throw new TypeError(\n \"Cannot access this transaction's runtime port. The transaction may come from an incompatible TypeGraph version.\",\n );\n }\n return runtime.runNodeOperationHooks;\n}\n","/**\n * Embedding Sync Utilities\n *\n * Handles automatic synchronization of embedding fields with the embeddings table.\n * When nodes with embedding properties are created, updated, or deleted,\n * these utilities ensure the embeddings table stays in sync.\n */\nimport { type z } from \"zod\";\n\nimport { type GraphBackend, type TransactionBackend } from \"../backend/types\";\nimport {\n type ResolvedEmbeddingField,\n resolveEmbeddingFields,\n} from \"../core/embedding\";\nimport { readOwnProperty } from \"../utils/object\";\n\n// ============================================================\n// Types\n// ============================================================\n\n/**\n * Information about an embedding field in a node schema.\n *\n * Re-exports the canonical {@link ResolvedEmbeddingField} so the backend\n * gets `dimensions` plus the resolved index `(metric, indexType)` — all\n * three needed to address the field's typed per-`(kind, field)` storage\n * slot when upserting.\n */\ntype EmbeddingFieldInfo = ResolvedEmbeddingField;\n\n/**\n * Context for embedding sync operations.\n */\nexport type EmbeddingSyncContext = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n backend: GraphBackend | TransactionBackend;\n}>;\n\n// ============================================================\n// Schema Introspection\n// ============================================================\n\n/**\n * Cache keyed by the Zod schema instance. Schemas are immutable at\n * runtime; the same reference recurs across every CRUD call.\n */\nconst embeddingFieldsCache = new WeakMap<\n z.ZodType,\n readonly EmbeddingFieldInfo[]\n>();\n\n/**\n * Extracts embedding field information from a Zod schema.\n * Returns all embedding fields found at the top level of an object schema.\n *\n * Thin per-schema-instance memoization over the canonical\n * {@link resolveEmbeddingFields}; the same schema reference recurs across\n * every CRUD call, so caching avoids re-walking the shape each time.\n */\nexport function getEmbeddingFields(\n schema: z.ZodType,\n): readonly EmbeddingFieldInfo[] {\n const cached = embeddingFieldsCache.get(schema);\n if (cached) return cached;\n const fields = resolveEmbeddingFields(schema);\n embeddingFieldsCache.set(schema, fields);\n return fields;\n}\n\n// ============================================================\n// Embedding Sync Operations\n// ============================================================\n\n/**\n * Syncs embeddings after a node create or update operation.\n *\n * For each embedding field in the schema:\n * - If the props contain an embedding value, upsert it to the embeddings table\n * - If the props don't contain an embedding value (undefined), delete any existing embedding\n */\nexport async function syncEmbeddings(\n ctx: EmbeddingSyncContext,\n schema: z.ZodType,\n props: Record<string, unknown>,\n): Promise<void> {\n const { backend } = ctx;\n\n // Check if backend supports embedding operations\n if (!backend.upsertEmbedding || !backend.deleteEmbedding) {\n return;\n }\n\n const embeddingFields = getEmbeddingFields(schema);\n if (embeddingFields.length === 0) {\n return;\n }\n\n for (const field of embeddingFields) {\n const value = readOwnProperty(props, field.fieldPath);\n\n if (isValidEmbeddingValue(value)) {\n // Upsert the embedding\n await backend.upsertEmbedding({\n graphId: ctx.graphId,\n nodeKind: ctx.nodeKind,\n nodeId: ctx.nodeId,\n fieldPath: field.fieldPath,\n embedding: value,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n });\n } else if (value === undefined) {\n // Delete any existing embedding for this field\n await backend.deleteEmbedding({\n graphId: ctx.graphId,\n nodeKind: ctx.nodeKind,\n nodeId: ctx.nodeId,\n fieldPath: field.fieldPath,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n });\n }\n // If value is null or invalid, skip (validation should have caught this)\n }\n}\n\n/**\n * Syncs embeddings for a batch of same-kind node creates through one\n * `upsertEmbeddingBatch` per field (falling back to per-row\n * `upsertEmbedding` when the backend lacks the batch primitive). Mirrors\n * `syncEmbeddings` per row: present values upsert, `undefined` values\n * delete any existing embedding for the field.\n */\nexport async function syncEmbeddingsBatchForKind(\n args: Readonly<{\n graphId: string;\n nodeKind: string;\n backend: GraphBackend | TransactionBackend;\n }>,\n schema: z.ZodType,\n items: readonly Readonly<{\n nodeId: string;\n props: Record<string, unknown>;\n }>[],\n): Promise<void> {\n const { graphId, nodeKind, backend } = args;\n if (!backend.upsertEmbedding || !backend.deleteEmbedding) {\n return;\n }\n\n const embeddingFields = getEmbeddingFields(schema);\n if (embeddingFields.length === 0) {\n return;\n }\n\n for (const field of embeddingFields) {\n const rows: { nodeId: string; embedding: readonly number[] }[] = [];\n const deletionIds: string[] = [];\n for (const item of items) {\n const value = readOwnProperty(item.props, field.fieldPath);\n if (isValidEmbeddingValue(value)) {\n rows.push({ nodeId: item.nodeId, embedding: value });\n } else if (value === undefined) {\n deletionIds.push(item.nodeId);\n }\n }\n\n if (rows.length > 0) {\n if (backend.upsertEmbeddingBatch === undefined) {\n for (const row of rows) {\n await backend.upsertEmbedding({\n graphId,\n nodeKind,\n nodeId: row.nodeId,\n fieldPath: field.fieldPath,\n embedding: row.embedding,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n });\n }\n } else {\n await backend.upsertEmbeddingBatch({\n graphId,\n nodeKind,\n fieldPath: field.fieldPath,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n rows,\n });\n }\n }\n\n if (deletionIds.length > 0 && backend.deleteEmbeddingBatch !== undefined) {\n await backend.deleteEmbeddingBatch({\n graphId,\n nodeKind,\n nodeIds: deletionIds,\n fieldPath: field.fieldPath,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n });\n } else {\n for (const nodeId of deletionIds) {\n await backend.deleteEmbedding({\n graphId,\n nodeKind,\n nodeId,\n fieldPath: field.fieldPath,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n });\n }\n }\n }\n}\n\n/**\n * Deletes a node's embeddings for the embedding fields its kind CURRENTLY\n * declares. A field dropped from the schema after the node was written is\n * intentionally NOT swept here — its entire per-field table is reclaimed\n * wholesale by `store.materializeRemovals()` (the deferred-cleanup verb), which\n * also covers live (never-deleted) nodes' rows. So a hard/soft delete can leave\n * a transient orphan row in a removed field's table until the next reclaim pass;\n * that is the deferred-cleanup design, not a leak.\n */\nexport async function deleteNodeEmbeddings(\n ctx: EmbeddingSyncContext,\n schema: z.ZodType,\n): Promise<void> {\n const { backend } = ctx;\n\n // Check if backend supports embedding operations\n if (!backend.deleteEmbedding) {\n return;\n }\n\n const embeddingFields = getEmbeddingFields(schema);\n if (embeddingFields.length === 0) {\n return;\n }\n\n for (const field of embeddingFields) {\n await backend.deleteEmbedding({\n graphId: ctx.graphId,\n nodeKind: ctx.nodeKind,\n nodeId: ctx.nodeId,\n fieldPath: field.fieldPath,\n dimensions: field.dimensions,\n metric: field.metric,\n indexType: field.indexType,\n });\n }\n}\n\n// ============================================================\n// Validation Helpers\n// ============================================================\n\n/**\n * Checks if a value is a valid embedding (array of numbers).\n */\nfunction isValidEmbeddingValue(value: unknown): value is readonly number[] {\n if (!Array.isArray(value)) {\n return false;\n }\n return value.every((n) => typeof n === \"number\" && Number.isFinite(n));\n}\n","/**\n * Keeps the fulltext index in sync with node data. One row per node:\n * the values of every `searchable()` field are concatenated (joined by\n * `\\n`) and stored as the indexed `content`, so a single FTS query can\n * match terms spanning multiple source fields — which a per-field\n * layout cannot, since FTS5 / Postgres MATCH require all terms in one\n * indexed document.\n *\n * Sync runs inline in the node-operation call path, so it inherits the\n * caller's transaction context.\n */\nimport { type z } from \"zod\";\n\nimport { type GraphBackend, type TransactionBackend } from \"../backend/types\";\nimport {\n DEFAULT_SEARCHABLE_LANGUAGE,\n getSearchableFields,\n type SearchableFieldInfo,\n} from \"../core/searchable\";\nimport { readOwnProperty } from \"../utils/object\";\n\nexport { getSearchableFields } from \"../core/searchable\";\n\nexport type FulltextSyncContext = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n backend: GraphBackend | TransactionBackend;\n}>;\n\nconst FIELD_SEPARATOR = \"\\n\";\n\n/**\n * Picks a representative language when a node has searchable fields with\n * different language settings. Users who need true per-field\n * multilingual indexing should split the data across node kinds.\n */\nfunction resolveCombinedLanguage(\n fields: readonly SearchableFieldInfo[],\n): string {\n return fields[0]?.metadata.language ?? DEFAULT_SEARCHABLE_LANGUAGE;\n}\n\n/**\n * Computes the combined fulltext content for a node, or `undefined`\n * if the node has no non-empty searchable fields.\n *\n * Shared between `syncFulltext` (per-write) and `rebuildFulltextIndex`\n * (bulk) so the two never drift.\n */\nexport function computeFulltextContent(\n schema: z.ZodType,\n props: Record<string, unknown>,\n): { content: string; language: string } | undefined {\n const searchableFields = getSearchableFields(schema);\n if (searchableFields.length === 0) return undefined;\n\n const parts: string[] = [];\n for (const field of searchableFields) {\n const value = readOwnProperty(props, field.fieldPath);\n if (typeof value === \"string\" && value.length > 0) {\n parts.push(value);\n }\n }\n if (parts.length === 0) return undefined;\n\n return {\n content: parts.join(FIELD_SEPARATOR),\n language: resolveCombinedLanguage(searchableFields),\n };\n}\n\n/**\n * Syncs the fulltext index row after a node create or update.\n *\n * Concatenates the values of all searchable fields into a single content\n * string and upserts it. If every field is empty / undefined, deletes\n * any existing row for the node.\n */\nexport async function syncFulltext(\n ctx: FulltextSyncContext,\n schema: z.ZodType,\n props: Record<string, unknown>,\n): Promise<void> {\n const { backend } = ctx;\n\n if (!backend.upsertFulltext || !backend.deleteFulltext) {\n return;\n }\n\n // `computeFulltextContent` returns `undefined` both when the schema has\n // no `searchable()` fields and when every value is empty — either case\n // means the row should not exist. Delete any stale row only when the\n // schema declares searchable fields (nothing to clean up otherwise).\n const computed = computeFulltextContent(schema, props);\n if (computed !== undefined) {\n await backend.upsertFulltext({\n graphId: ctx.graphId,\n nodeKind: ctx.nodeKind,\n nodeId: ctx.nodeId,\n content: computed.content,\n language: computed.language,\n });\n return;\n }\n if (getSearchableFields(schema).length === 0) return;\n await backend.deleteFulltext({\n graphId: ctx.graphId,\n nodeKind: ctx.nodeKind,\n nodeId: ctx.nodeId,\n });\n}\n\n/**\n * Syncs the fulltext rows for a batch of same-kind node creates through\n * one `upsertFulltextBatch` call (falling back to per-row `upsertFulltext`\n * when the backend lacks the batch primitive). Mirrors `syncFulltext`\n * per row: computed content upserts, empty content deletes any stale row\n * when the schema declares searchable fields.\n */\nexport async function syncFulltextBatchForKind(\n args: Readonly<{\n graphId: string;\n nodeKind: string;\n backend: GraphBackend | TransactionBackend;\n }>,\n schema: z.ZodType,\n items: readonly Readonly<{\n nodeId: string;\n props: Record<string, unknown>;\n }>[],\n): Promise<void> {\n const { graphId, nodeKind, backend } = args;\n if (!backend.upsertFulltext || !backend.deleteFulltext) {\n return;\n }\n\n const rows: { nodeId: string; content: string; language: string }[] = [];\n const emptyContentIds: string[] = [];\n const hasSearchableFields = getSearchableFields(schema).length > 0;\n for (const item of items) {\n const computed = computeFulltextContent(schema, item.props);\n if (computed !== undefined) {\n rows.push({\n nodeId: item.nodeId,\n content: computed.content,\n language: computed.language,\n });\n } else if (hasSearchableFields) {\n emptyContentIds.push(item.nodeId);\n }\n }\n\n if (rows.length > 0) {\n if (backend.upsertFulltextBatch === undefined) {\n for (const row of rows) {\n await backend.upsertFulltext({\n graphId,\n nodeKind,\n nodeId: row.nodeId,\n content: row.content,\n language: row.language,\n });\n }\n } else {\n await backend.upsertFulltextBatch({ graphId, nodeKind, rows });\n }\n }\n\n if (emptyContentIds.length > 0) {\n if (backend.deleteFulltextBatch === undefined) {\n for (const nodeId of emptyContentIds) {\n await backend.deleteFulltext({ graphId, nodeKind, nodeId });\n }\n } else {\n await backend.deleteFulltextBatch({\n graphId,\n nodeKind,\n nodeIds: emptyContentIds,\n });\n }\n }\n}\n\n/**\n * Deletes the fulltext row for a node.\n * Called on soft-delete; hard-delete is handled by the backend cascade.\n */\nexport async function deleteNodeFulltext(\n ctx: FulltextSyncContext,\n schema: z.ZodType,\n): Promise<void> {\n const { backend } = ctx;\n\n if (!backend.deleteFulltext) {\n return;\n }\n\n if (getSearchableFields(schema).length === 0) {\n return;\n }\n\n await backend.deleteFulltext({\n graphId: ctx.graphId,\n nodeKind: ctx.nodeKind,\n nodeId: ctx.nodeId,\n });\n}\n","/**\n * Uniqueness Constraint Management\n *\n * Handles checking, inserting, updating, and deleting uniqueness constraint entries.\n */\nimport {\n type GraphBackend,\n type InsertUniqueParams,\n type TransactionBackend,\n} from \"../backend/types\";\nimport {\n checkWherePredicate,\n computeUniqueKey,\n getKindsForUniquenessCheck,\n} from \"../constraints\";\nimport { type UniqueConstraint } from \"../core/types\";\nimport { UniquenessError } from \"../errors\";\nimport { type KindRegistry } from \"../registry/kind-registry\";\n\n/**\n * Context for uniqueness operations.\n */\nexport type UniquenessContext = Readonly<{\n graphId: string;\n registry: KindRegistry;\n backend: GraphBackend | TransactionBackend;\n}>;\n\n/** Builds a {@link UniquenessContext} — the one constructor every call site shares. */\nexport function createUniquenessContext(\n graphId: string,\n registry: KindRegistry,\n backend: GraphBackend | TransactionBackend,\n): UniquenessContext {\n return { graphId, registry, backend };\n}\n\n/**\n * Probes ONE constraint's key across every kind its scope covers.\n *\n * THE SINGLE OWNER of \"is this key available to this node?\" — the conflict\n * verdict and the ownership reading are one read, so no caller can consult one\n * without the other. {@link checkUniquenessConstraints} is this probe run for\n * its refusal alone; the plan builders below additionally keep what it read.\n *\n * @returns whether THIS node already holds the key live under its OWN kind, in\n * which case a claim would be a no-op and a compensating release would strip\n * a reservation the node is entitled to.\n * @throws UniquenessError when a DIFFERENT node holds the key under any kind in\n * scope.\n */\nasync function probeUniqueKey(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n constraint: UniqueConstraint,\n key: string,\n): Promise<boolean> {\n const kindsToCheck = getKindsForUniquenessCheck(\n kind,\n constraint.scope,\n ctx.registry,\n );\n\n // `let` earns its place: the loop must visit EVERY kind in scope to reach its\n // refusal, so the ownership reading cannot be an early return.\n let heldByThisNode = false;\n for (const kindToCheck of kindsToCheck) {\n const existing = await ctx.backend.checkUnique({\n graphId: ctx.graphId,\n nodeKind: kindToCheck,\n constraintName: constraint.name,\n key,\n });\n\n if (existing === undefined) continue;\n if (existing.node_id !== id) {\n throw new UniquenessError({\n constraintName: constraint.name,\n kind: kindToCheck,\n existingId: existing.node_id,\n newId: id,\n fields: constraint.fields,\n });\n }\n if (kindToCheck === kind) heldByThisNode = true;\n }\n return heldByThisNode;\n}\n\n/**\n * Checks uniqueness constraints for a new or existing node.\n *\n * @throws ValidationError if any constraint is violated\n */\nexport async function checkUniquenessConstraints(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n props: Record<string, unknown>,\n constraints: readonly UniqueConstraint[],\n): Promise<void> {\n for (const constraint of constraints) {\n if (!checkWherePredicate(constraint, props)) {\n continue;\n }\n\n await probeUniqueKey(\n ctx,\n kind,\n id,\n constraint,\n computeUniqueKey(props, constraint.fields, constraint.collation),\n );\n }\n}\n\n/**\n * Inserts uniqueness entries for a newly created node.\n */\nexport async function insertUniquenessEntries(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n props: Record<string, unknown>,\n constraints: readonly UniqueConstraint[],\n): Promise<void> {\n for (const constraint of constraints) {\n if (!checkWherePredicate(constraint, props)) {\n continue;\n }\n\n const key = computeUniqueKey(\n props,\n constraint.fields,\n constraint.collation,\n );\n\n await ctx.backend.insertUnique({\n graphId: ctx.graphId,\n nodeKind: kind,\n constraintName: constraint.name,\n key,\n nodeId: id,\n concreteKind: kind,\n });\n }\n}\n\n/**\n * Inserts uniqueness entries for a batch of newly created nodes through one\n * `insertUniqueBatch` call (falling back to per-entry `insertUnique` when\n * the backend lacks the batch primitive). Same conflict semantics as the\n * per-node path: the first entry whose key a different live node holds\n * throws `UniquenessError`.\n */\nexport async function insertUniquenessEntriesBatch(\n ctx: UniquenessContext,\n items: readonly Readonly<{\n kind: string;\n id: string;\n props: Record<string, unknown>;\n constraints: readonly UniqueConstraint[];\n }>[],\n): Promise<void> {\n const entries: InsertUniqueParams[] = [];\n for (const item of items) {\n for (const constraint of item.constraints) {\n if (!checkWherePredicate(constraint, item.props)) {\n continue;\n }\n entries.push({\n graphId: ctx.graphId,\n nodeKind: item.kind,\n constraintName: constraint.name,\n key: computeUniqueKey(\n item.props,\n constraint.fields,\n constraint.collation,\n ),\n nodeId: item.id,\n concreteKind: item.kind,\n });\n }\n }\n if (entries.length === 0) return;\n\n if (ctx.backend.insertUniqueBatch !== undefined) {\n await ctx.backend.insertUniqueBatch(entries);\n return;\n }\n for (const entry of entries) {\n await ctx.backend.insertUnique(entry);\n }\n}\n\n/**\n * Deletes uniqueness entries for a node being deleted.\n */\nexport async function deleteUniquenessEntries(\n ctx: UniquenessContext,\n kind: string,\n props: Record<string, unknown>,\n constraints: readonly UniqueConstraint[],\n): Promise<void> {\n for (const constraint of constraints) {\n if (!checkWherePredicate(constraint, props)) {\n continue;\n }\n\n const key = computeUniqueKey(\n props,\n constraint.fields,\n constraint.collation,\n );\n\n await ctx.backend.deleteUnique({\n graphId: ctx.graphId,\n nodeKind: kind,\n constraintName: constraint.name,\n key,\n });\n }\n}\n\n/**\n * A single constraint's sidecar transition, decided by a plan builder and\n * carried out by {@link withUniquenessTransition}.\n *\n * The two keys move at DIFFERENT times relative to the primary row write, so\n * they are named for when they move rather than for old/new:\n * `claim` is reserved BEFORE the write (it is the write's conflict gate),\n * `release` is given up AFTER it (it is history the write supersedes).\n */\ntype PendingUniqueMutation = Readonly<{\n constraintName: string;\n /** The key to give up once the primary write lands; undefined = none. */\n release: string | undefined;\n /**\n * The key to reserve before the primary write; undefined = none, either\n * because the constraint stopped applying or because {@link probeUniqueKey}\n * found this node already holding it live.\n */\n claim: string | undefined;\n}>;\n\n/**\n * The sidecar transition a node write owes, decided but not yet performed.\n *\n * Opaque to its holder on purpose: the only thing a caller does with a plan is\n * hand it to {@link withUniquenessTransition} together with the primary row\n * write it belongs to.\n */\nexport type UniquenessUpdatePlan = readonly PendingUniqueMutation[];\n\n/**\n * Decides the uniqueness-entry changes a node's new props require, WITHOUT\n * writing any of them.\n *\n * Preflights EVERY changed constraint before anything is written. A node can\n * carry several unique constraints; probing them one at a time as they are\n * applied would let a later constraint's conflict throw after earlier sidecars\n * already moved. Probing all of them first means a refusal here happens with\n * zero writes, and the probes are independent per `constraintName`, so one\n * constraint's verdict is unaffected by the others' still-unapplied changes.\n *\n * Handles the cases where a constraint starts applying, stops applying, or\n * keeps applying under a different key.\n *\n * @throws UniquenessError if an updated value is already held by another node\n */\nexport async function planUniquenessUpdate(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n oldProps: Record<string, unknown>,\n newProps: Record<string, unknown>,\n constraints: readonly UniqueConstraint[],\n): Promise<UniquenessUpdatePlan> {\n const pending: PendingUniqueMutation[] = [];\n for (const constraint of constraints) {\n const oldApplies = checkWherePredicate(constraint, oldProps);\n const newApplies = checkWherePredicate(constraint, newProps);\n\n const oldKey =\n oldApplies ?\n computeUniqueKey(oldProps, constraint.fields, constraint.collation)\n : undefined;\n const newKey =\n newApplies ?\n computeUniqueKey(newProps, constraint.fields, constraint.collation)\n : undefined;\n\n // No change - constraint didn't apply and still doesn't\n if (!oldApplies && !newApplies) {\n continue;\n }\n\n // Keys are the same and constraint still applies - nothing to do\n if (oldApplies && newApplies && oldKey === newKey) {\n continue;\n }\n\n // Probe the new key: refuse a value another node holds, and note a value\n // this node somehow holds already so the transition neither re-claims nor\n // releases it.\n const alreadyHeld =\n newKey === undefined ? false : (\n await probeUniqueKey(ctx, kind, id, constraint, newKey)\n );\n\n pending.push({\n constraintName: constraint.name,\n release: oldKey,\n claim: alreadyHeld ? undefined : newKey,\n });\n }\n\n return pending;\n}\n\n/**\n * The plan a RESURRECTING write needs: every applying constraint re-reserved\n * from scratch.\n *\n * A tombstoned node holds no live reservations — {@link deleteUniquenessEntries}\n * released them at soft-delete time — so the diff-based\n * {@link planUniquenessUpdate} cannot be used here: it would skip an unchanged\n * key and leave the revived node holding NO reservation, letting a later create\n * silently duplicate the value.\n *\n * @throws UniquenessError if a key this node held was taken while it was\n * tombstoned\n */\nexport async function planUniquenessReinsert(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n props: Record<string, unknown>,\n constraints: readonly UniqueConstraint[],\n): Promise<UniquenessUpdatePlan> {\n const pending: PendingUniqueMutation[] = [];\n for (const constraint of constraints) {\n if (!checkWherePredicate(constraint, props)) continue;\n\n const key = computeUniqueKey(\n props,\n constraint.fields,\n constraint.collation,\n );\n const alreadyHeld = await probeUniqueKey(ctx, kind, id, constraint, key);\n\n pending.push({\n constraintName: constraint.name,\n release: undefined,\n claim: alreadyHeld ? undefined : key,\n });\n }\n return pending;\n}\n\n/** Gives up the reservations named by `keys`, in plan order. */\nasync function releaseUniqueKeys(\n ctx: UniquenessContext,\n kind: string,\n keys: readonly Readonly<{ constraintName: string; key: string }>[],\n): Promise<void> {\n for (const entry of keys) {\n await ctx.backend.deleteUnique({\n graphId: ctx.graphId,\n nodeKind: kind,\n constraintName: entry.constraintName,\n key: entry.key,\n });\n }\n}\n\n/**\n * Reserves the plan's new keys, runs the primary row write they gate, and undoes\n * the reservations if that write does not land.\n */\nasync function claimUniqueKeysThen<T>(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n plan: UniquenessUpdatePlan,\n gatedWrite: () => Promise<T>,\n): Promise<T> {\n const claimed: Readonly<{ constraintName: string; key: string }>[] = [];\n try {\n for (const mutation of plan) {\n if (mutation.claim === undefined) continue;\n await ctx.backend.insertUnique({\n graphId: ctx.graphId,\n nodeKind: kind,\n constraintName: mutation.constraintName,\n key: mutation.claim,\n nodeId: id,\n concreteKind: kind,\n });\n claimed.push({\n constraintName: mutation.constraintName,\n key: mutation.claim,\n });\n }\n return await gatedWrite();\n } catch (error) {\n // Compensate, not swallow: the reservations this transition took are given\n // back and the original failure is rethrown, so the caller sees the SAME\n // error it would have seen with no reservation attempted at all.\n //\n // The give-back is exact because of what a claim can be. `probeUniqueKey`\n // refuses a key another node holds and reports one THIS node already holds\n // (which the plan then does not claim), so every claimed key was free or\n // tombstoned beforehand and releasing it restores precisely that. And no\n // peer can have taken it in between: this transaction holds the row.\n //\n // One detail is restored in kind rather than exactly: a claim that took over\n // a TOMBSTONED reservation rewrites its recorded owner, and the give-back\n // re-tombstones it under THIS node's id instead of the previous holder's.\n // The key reads as free either way — `checkUnique` skips tombstoned rows —\n // and the one reader that looks at them, `getOrCreateByConstraint`'s\n // resurrect-by-key lookup, writes the props it was called with onto whatever\n // row it revives, so the reservation and the row holding the value stay\n // consistent. Which tombstone that lookup revives can differ. If the\n // compensation itself fails the row is genuinely half-written, and the\n // error that then surfaces is a raw backend failure no per-row consumer\n // catches — the enclosing transaction aborts, which is the only honest\n // outcome left.\n await releaseUniqueKeys(ctx, kind, claimed);\n throw error;\n }\n}\n\n/**\n * Runs one node's primary row write with its uniqueness transition wrapped\n * around it, so the pair commits or fails AS ONE UNIT.\n *\n * ## Why the sequence is claim, gate, release\n *\n * A node update is two independently fallible writes — the row itself and its\n * uniqueness entries — with no rollback between them: nothing here is\n * savepoint-protected (see `operations/write-transaction.ts`), and the backends\n * this supports do not all have savepoints to reach for. Sequencing is the only\n * atomicity available, and only ONE sequence makes both failures leave zero net\n * effect:\n *\n * - **Claim first.** `insertUnique` is an upsert that reports the key's final\n * owner, so claiming IS the conflict gate — and once this transaction holds\n * the row, no concurrent writer can take the key from under it. Probing and\n * then claiming later leaves a window (wide open under PostgreSQL READ\n * COMMITTED, where a peer commits between the two) in which the claim fails\n * AFTER the row was already updated.\n * - **Then the row write.** It can legitimately match nothing —\n * `expectedValidFrom`, `deleted_at` — and callers that catch that per row and\n * commit the rest (interchange import) must not be left with reservations for\n * a row that never changed. A refusal here compensates the claims away.\n * - **Release last.** Giving up the old key before the row write would free a\n * value for a write that may never land; giving it up after is safe because\n * nothing can fail on it.\n *\n * The predecessor of this helper ordered the whole sidecar transition after the\n * row write, which closed the second failure and left the first: a caught\n * `UniquenessError` then reported `updated: 0` for a row whose props HAD\n * changed, whose old reservation was gone, and whose new one belonged to someone\n * else.\n */\nexport async function withUniquenessTransition<T>(\n ctx: UniquenessContext,\n kind: string,\n id: string,\n plan: UniquenessUpdatePlan,\n gatedWrite: () => Promise<T>,\n): Promise<T> {\n const result = await claimUniqueKeysThen(ctx, kind, id, plan, gatedWrite);\n await releaseUniqueKeys(\n ctx,\n kind,\n plan.flatMap((mutation) =>\n mutation.release === undefined ?\n []\n : [{ constraintName: mutation.constraintName, key: mutation.release }],\n ),\n );\n return result;\n}\n","/**\n * Composable node write steps — the integrity side effects that every node\n * mutation must apply, extracted so there is a single implementation instead of\n * one hand-stitched copy per write path.\n *\n * A node mutation is the core row write plus a fixed set of side effects:\n * uniqueness entries, embedding sync, fulltext sync, and — for deletes —\n * delete-behavior enforcement over connected edges. These steps are shared by\n * the canonical collection operations (create / update / delete) and by\n * provenance retraction, which drives the same close/reopen of a fact node's\n * currency but skips delete-behavior enforcement so every connected edge\n * survives for a later reopen.\n *\n * The steps assume they run inside a write transaction (see\n * {@link runInWriteTransaction}); they perform no transaction management of\n * their own.\n */\nimport { type z } from \"zod\";\n\nimport {\n type GraphBackend,\n type LiveNodeRow,\n type NodeRow,\n rowPropsToObject,\n type TombstonedNodeRow,\n type TransactionBackend,\n} from \"../../backend/types\";\nimport { type DeleteBehavior, type UniqueConstraint } from \"../../core/types\";\nimport { RestrictedDeleteError } from \"../../errors\";\nimport { type KindRegistry } from \"../../registry/kind-registry\";\nimport {\n deleteNodeEmbeddings,\n syncEmbeddings,\n syncEmbeddingsBatchForKind,\n} from \"../embedding-sync\";\nimport {\n deleteNodeFulltext,\n syncFulltext,\n syncFulltextBatchForKind,\n} from \"../fulltext-sync\";\nimport { type GraphWriteLock } from \"../recorded-capture/clock\";\nimport {\n createUniquenessContext,\n deleteUniquenessEntries,\n insertUniquenessEntries,\n insertUniquenessEntriesBatch,\n planUniquenessReinsert,\n planUniquenessUpdate,\n type UniquenessUpdatePlan,\n withUniquenessTransition,\n} from \"../uniqueness\";\n\ntype Backend = GraphBackend | TransactionBackend;\n\n/**\n * The graph-scoped state the node write steps need. `lock` is compile-time\n * evidence that the per-graph write-lock discipline was satisfied BEFORE any\n * row work (see {@link GraphWriteLock}): the pipeline performs no locking of\n * its own, so requiring the token here makes \"sidecar write before lock\" a\n * type error at the call site instead of a lock-order inversion in review.\n */\nexport type NodeWriteContext = Readonly<{\n graphId: string;\n registry: KindRegistry;\n lock: GraphWriteLock;\n}>;\n\n/** Builds a {@link NodeWriteContext} — the one constructor every call site shares. */\nexport function createNodeWriteContext(\n graphId: string,\n registry: KindRegistry,\n lock: GraphWriteLock,\n): NodeWriteContext {\n return { graphId, registry, lock };\n}\n\n/** Whether a delete removes the node (`hard`) or tombstones it (`soft`). */\ntype NodeDeleteMode = \"soft\" | \"hard\";\n\n/**\n * Tunes how a delete treats the node's connected edges.\n *\n * By default delete behavior is enforced: connected edges block a `restrict`\n * node and are removed under `cascade` / `disconnect`. Provenance retraction\n * passes `enforceDeleteBehavior: false` — closing a fact's currency is a\n * belief-status change, not a domain delete, so its edges neither block the\n * close nor get removed; they survive untouched so a later reopen is an exact\n * inverse.\n */\nexport type NodeDeletePolicy = Readonly<{\n enforceDeleteBehavior: boolean;\n}>;\n\nfunction uniquenessContext(ctx: NodeWriteContext, backend: Backend) {\n return createUniquenessContext(ctx.graphId, ctx.registry, backend);\n}\n\n/**\n * The `(graphId, nodeKind, nodeId, backend)` context shared by the embedding and\n * fulltext sync helpers — `EmbeddingSyncContext` and `FulltextSyncContext` are\n * structurally identical, so one builder serves both.\n */\nfunction nodeSyncContext(\n ctx: NodeWriteContext,\n kind: string,\n id: string,\n backend: Backend,\n) {\n return { graphId: ctx.graphId, nodeKind: kind, nodeId: id, backend };\n}\n\n/**\n * Enforces a node's delete behavior against its connected edges: they block\n * the delete (`restrict`) or are removed alongside the node (`cascade` /\n * `disconnect`). Skipped entirely when the caller's {@link NodeDeletePolicy}\n * disables enforcement.\n */\nasync function enforceNodeDeleteBehavior(\n ctx: NodeWriteContext,\n args: Readonly<{\n kind: string;\n id: string;\n mode: NodeDeleteMode;\n onDelete: DeleteBehavior | undefined;\n }>,\n backend: Backend,\n policy?: NodeDeletePolicy,\n): Promise<void> {\n if (policy?.enforceDeleteBehavior === false) return;\n const behavior = args.onDelete ?? \"restrict\";\n const connectedEdges = await backend.findEdgesConnectedTo({\n graphId: ctx.graphId,\n nodeKind: args.kind,\n nodeId: args.id,\n });\n\n if (connectedEdges.length === 0) return;\n\n switch (behavior) {\n case \"restrict\": {\n throw new RestrictedDeleteError({\n nodeKind: args.kind,\n nodeId: args.id,\n edgeCount: connectedEdges.length,\n edgeKinds: [...new Set(connectedEdges.map((edge) => edge.kind))],\n });\n }\n\n case \"cascade\":\n case \"disconnect\": {\n // Both behaviors remove connected edges. \"cascade\" signals intent to\n // remove dependent data; \"disconnect\" signals intent to sever the\n // relationship. The effect is identical because edges cannot exist\n // without both endpoints. One batched statement per bind-budget\n // chunk instead of one statement per edge; the per-edge loop remains\n // for backends without the batch members.\n const batchDelete =\n args.mode === \"hard\" ?\n backend.hardDeleteEdgesBatch\n : backend.deleteEdgesBatch;\n if (batchDelete !== undefined) {\n await batchDelete({\n graphId: ctx.graphId,\n ids: connectedEdges.map((edge) => edge.id),\n });\n break;\n }\n for (const edge of connectedEdges) {\n await (args.mode === \"hard\" ?\n backend.hardDeleteEdge({ graphId: ctx.graphId, id: edge.id })\n : backend.deleteEdge({ graphId: ctx.graphId, id: edge.id }));\n }\n break;\n }\n }\n}\n\n/**\n * Applies the side effects that follow a node insert: uniqueness entries, then\n * embedding and fulltext sync. Uniqueness has already been *checked* during\n * create preparation; this writes the entries.\n */\nexport async function applyNodeInsertSideEffects(\n ctx: NodeWriteContext,\n args: Readonly<{\n kind: string;\n id: string;\n schema: z.ZodType;\n props: Record<string, unknown>;\n uniqueConstraints: readonly UniqueConstraint[];\n }>,\n backend: Backend,\n): Promise<void> {\n await insertUniquenessEntries(\n uniquenessContext(ctx, backend),\n args.kind,\n args.id,\n args.props,\n args.uniqueConstraints,\n );\n await Promise.all([\n syncEmbeddings(\n nodeSyncContext(ctx, args.kind, args.id, backend),\n args.schema,\n args.props,\n ),\n syncFulltext(\n nodeSyncContext(ctx, args.kind, args.id, backend),\n args.schema,\n args.props,\n ),\n ]);\n}\n\n/**\n * Batched {@link applyNodeInsertSideEffects}: one uniqueness batch across\n * every item, then one embedding batch per (kind, field) and one fulltext\n * batch per kind — instead of the per-row statement fan the single-op path\n * issues. Ordering matches the single-op path (uniqueness first, then the\n * sync fans).\n */\nexport async function applyNodeInsertSideEffectsBatch(\n ctx: NodeWriteContext,\n items: readonly Readonly<{\n kind: string;\n id: string;\n schema: z.ZodType;\n props: Record<string, unknown>;\n uniqueConstraints: readonly UniqueConstraint[];\n }>[],\n backend: Backend,\n): Promise<void> {\n if (items.length === 0) return;\n\n await insertUniquenessEntriesBatch(\n uniquenessContext(ctx, backend),\n items.map((item) => ({\n kind: item.kind,\n id: item.id,\n props: item.props,\n constraints: item.uniqueConstraints,\n })),\n );\n\n interface KindGroup {\n schema: z.ZodType;\n rows: { nodeId: string; props: Record<string, unknown> }[];\n }\n const byKind = new Map<string, KindGroup>();\n for (const item of items) {\n const group = byKind.get(item.kind) ?? { schema: item.schema, rows: [] };\n group.rows.push({ nodeId: item.id, props: item.props });\n byKind.set(item.kind, group);\n }\n\n await Promise.all(\n [...byKind.entries()].flatMap(([kind, group]) => {\n const syncArguments = { graphId: ctx.graphId, nodeKind: kind, backend };\n return [\n syncEmbeddingsBatchForKind(syncArguments, group.schema, group.rows),\n syncFulltextBatchForKind(syncArguments, group.schema, group.rows),\n ];\n }),\n );\n}\n\nfunction parseRowProps(row: NodeRow): Record<string, unknown> {\n return rowPropsToObject(row.props);\n}\n\n/**\n * The row a node update targets. A plain update runs live-row side effects\n * (uniqueness diff, embedding/fulltext sync), so it must be handed a\n * {@link LiveNodeRow}; only an explicit `clearDeleted: true` resurrecting\n * upsert may target a possibly-tombstoned row. Encoding the pairing as a\n * union makes \"live-row update pipeline on a tombstoned row\" a type error.\n */\nexport type NodeUpdateTarget =\n | Readonly<{ existing: LiveNodeRow; clearDeleted?: false }>\n | Readonly<{ existing: NodeRow; clearDeleted: true }>;\n\n/**\n * Decides a node update's uniqueness transition, writing nothing.\n *\n * Two shapes behind one seam. A live row diffs its old and new keys; a\n * resurrecting update (`clearDeleted` on a tombstoned row) cannot, because the\n * soft delete already removed its entries — the diff would skip an unchanged\n * key and leave the resurrected node holding NO reservation, so a later create\n * could silently duplicate the value. It re-reserves every applying key\n * instead. Both refuse a conflict before returning, and both hand the caller a\n * plan that only {@link withUniquenessTransition} may carry out.\n */\nasync function planNodeUpdateUniqueness(\n ctx: NodeWriteContext,\n args: Readonly<{\n existing: NodeRow;\n validatedProps: Record<string, unknown>;\n uniqueConstraints: readonly UniqueConstraint[];\n }>,\n backend: Backend,\n): Promise<UniquenessUpdatePlan> {\n const { kind, id } = args.existing;\n\n if (args.existing.deleted_at !== undefined) {\n return planUniquenessReinsert(\n uniquenessContext(ctx, backend),\n kind,\n id,\n args.validatedProps,\n args.uniqueConstraints,\n );\n }\n\n return planUniquenessUpdate(\n uniquenessContext(ctx, backend),\n kind,\n id,\n parseRowProps(args.existing),\n args.validatedProps,\n args.uniqueConstraints,\n );\n}\n\n/**\n * Applies a node update: uniqueness maintenance (diff-based for a live row;\n * check-and-reinsert for a resurrecting update, whose entries the soft delete\n * removed), the core row update, then embedding and fulltext sync. Returns\n * the updated row.\n *\n * ## The row write and its uniqueness transition are ONE unit\n *\n * Both can fail — the row write matches nothing when `expectedValidFrom` or the\n * `deleted_at` fence stopped holding, the uniqueness claim loses a race for a\n * key — and a caller that catches either PER ROW and commits the rest of the\n * transaction (interchange import) must never be left with half of the pair\n * applied. {@link withUniquenessTransition} owns that sequencing and documents\n * why claim/gate/release is the only order that works; this function just hands\n * it the plan and the write.\n *\n * The embedding and fulltext syncs stay AFTER the gate: they are derived data\n * with no claim to make, so a row write that lands on nothing must not rewrite\n * a fulltext row or re-embed props no row ever received.\n */\nexport async function applyNodeUpdate(\n ctx: NodeWriteContext,\n args: Readonly<{\n schema: z.ZodType;\n validatedProps: Record<string, unknown>;\n uniqueConstraints: readonly UniqueConstraint[];\n validFrom?: string | null;\n validTo?: string;\n /** See {@link UpdateNodeParams.expectedValidFrom}. */\n expectedValidFrom?: string | null;\n }> &\n NodeUpdateTarget,\n backend: Backend,\n): Promise<NodeRow> {\n const { kind, id } = args.existing;\n\n // Read-only phase: decide the sidecar changes, refuse a conflict, write\n // nothing.\n const plan = await planNodeUpdateUniqueness(\n ctx,\n {\n existing: args.existing,\n validatedProps: args.validatedProps,\n uniqueConstraints: args.uniqueConstraints,\n },\n backend,\n );\n\n const updateParams: {\n graphId: string;\n kind: string;\n id: string;\n props: Record<string, unknown>;\n validFrom?: string | null;\n validTo?: string;\n expectedValidFrom?: string | null;\n incrementVersion?: boolean;\n clearDeleted?: boolean;\n } = {\n graphId: ctx.graphId,\n kind,\n id,\n props: args.validatedProps,\n incrementVersion: true,\n };\n if (args.validFrom !== undefined) updateParams.validFrom = args.validFrom;\n if (args.validTo !== undefined) updateParams.validTo = args.validTo;\n if (args.expectedValidFrom !== undefined) {\n updateParams.expectedValidFrom = args.expectedValidFrom;\n }\n if (args.clearDeleted) updateParams.clearDeleted = true;\n\n const row = await withUniquenessTransition(\n uniquenessContext(ctx, backend),\n kind,\n id,\n plan,\n () => backend.updateNode(updateParams),\n );\n\n await Promise.all([\n syncEmbeddings(\n nodeSyncContext(ctx, kind, id, backend),\n args.schema,\n args.validatedProps,\n ),\n syncFulltext(\n nodeSyncContext(ctx, kind, id, backend),\n args.schema,\n args.validatedProps,\n ),\n ]);\n\n return row;\n}\n\n/**\n * Applies a node soft delete: delete-behavior enforcement, the tombstone\n * write, then removal of uniqueness entries, embeddings, and fulltext.\n * Requires a {@link LiveNodeRow}: deleting an already-tombstoned row would\n * re-run sidecar cleanup against entries the first delete already removed.\n */\nexport async function applyNodeSoftDelete(\n ctx: NodeWriteContext,\n args: Readonly<{\n existing: LiveNodeRow;\n schema: z.ZodType;\n uniqueConstraints: readonly UniqueConstraint[];\n onDelete: DeleteBehavior | undefined;\n }>,\n backend: Backend,\n policy?: NodeDeletePolicy,\n): Promise<void> {\n const { kind, id } = args.existing;\n await enforceNodeDeleteBehavior(\n ctx,\n { kind, id, mode: \"soft\", onDelete: args.onDelete },\n backend,\n policy,\n );\n await backend.deleteNode({\n graphId: ctx.graphId,\n kind,\n id,\n });\n await deleteUniquenessEntries(\n uniquenessContext(ctx, backend),\n kind,\n parseRowProps(args.existing),\n args.uniqueConstraints,\n );\n await deleteNodeEmbeddings(\n nodeSyncContext(ctx, kind, id, backend),\n args.schema,\n );\n await deleteNodeFulltext(\n nodeSyncContext(ctx, kind, id, backend),\n args.schema,\n );\n}\n\n/**\n * Applies a node hard delete: delete-behavior enforcement, permanent removal,\n * then embedding cleanup. Uniqueness and fulltext rows are removed by the\n * backend's `hardDeleteNode` cascade; embeddings live in strategy-owned\n * per-`(kind, field)` tables the graph-agnostic cascade cannot reach, so they\n * are cleaned here.\n */\nexport async function applyNodeHardDelete(\n ctx: NodeWriteContext,\n args: Readonly<{\n kind: string;\n id: string;\n schema: z.ZodType;\n onDelete: DeleteBehavior | undefined;\n }>,\n backend: Backend,\n): Promise<void> {\n await enforceNodeDeleteBehavior(\n ctx,\n { kind: args.kind, id: args.id, mode: \"hard\", onDelete: args.onDelete },\n backend,\n );\n await backend.hardDeleteNode({\n graphId: ctx.graphId,\n kind: args.kind,\n id: args.id,\n });\n await deleteNodeEmbeddings(\n nodeSyncContext(ctx, args.kind, args.id, backend),\n args.schema,\n );\n}\n\n/**\n * Reopens a soft-deleted node with its stored props (no merge, no\n * re-validation): re-checks and re-inserts uniqueness entries (the delete\n * removed them), clears the tombstone, then re-syncs embeddings and fulltext.\n * Used by provenance to reinstate a fact whose currency is restored. Returns\n * the reopened row.\n *\n * @throws {UniquenessError} when a unique key the node held was taken by\n * another node while it was tombstoned.\n */\nexport async function applyNodeResurrect(\n ctx: NodeWriteContext,\n args: Readonly<{\n existing: TombstonedNodeRow;\n schema: z.ZodType;\n uniqueConstraints: readonly UniqueConstraint[];\n }>,\n backend: Backend,\n): Promise<NodeRow> {\n const { kind, id } = args.existing;\n const props = parseRowProps(args.existing);\n // One unit, exactly as `applyNodeUpdate`, and for the same reason: the\n // resurrecting UPDATE carries `deleted_at IS NOT NULL`, so a peer that revived\n // this tombstone first makes it match zero rows — and the reservations that\n // revival is entitled to are the peer's, not this caller's.\n // `withUniquenessTransition` gives them back when the gate refuses.\n const plan = await planUniquenessReinsert(\n uniquenessContext(ctx, backend),\n kind,\n id,\n props,\n args.uniqueConstraints,\n );\n const row = await withUniquenessTransition(\n uniquenessContext(ctx, backend),\n kind,\n id,\n plan,\n () =>\n backend.updateNode({\n graphId: ctx.graphId,\n kind,\n id,\n props,\n incrementVersion: true,\n clearDeleted: true,\n }),\n );\n await Promise.all([\n syncEmbeddings(nodeSyncContext(ctx, kind, id, backend), args.schema, props),\n syncFulltext(nodeSyncContext(ctx, kind, id, backend), args.schema, props),\n ]);\n return row;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/date.ts","../src/core/temporal.ts"],"names":["ValidationError","INVERTED_VALIDITY_WINDOW_CODE","IMMUTABLE_VALIDITY_LOWER_BOUND_CODE"],"mappings":"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","file":"chunk-5PDSCELM.cjs","sourcesContent":["/**\n * Date encoding utilities for consistent storage.\n *\n * Contract: All dates are stored as ISO 8601 strings in UTC.\n * - Always includes milliseconds\n * - Always UTC (Z suffix)\n * - Sorts correctly as strings\n */\n\nimport {\n IMMUTABLE_VALIDITY_LOWER_BOUND_CODE,\n INVERTED_VALIDITY_WINDOW_CODE,\n ValidationError,\n} from \"../errors\";\n\n/**\n * ISO 8601 datetime pattern.\n * Matches formats like:\n * - 2024-01-15T10:30:00.000Z\n * - 2024-01-15T10:30:00Z\n * - 2024-01-15T10:30:00.123Z\n */\nconst ISO_DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$/;\n\n/**\n * Checks if a string is a valid ISO 8601 datetime.\n *\n * @param value - String to validate\n * @returns True if valid ISO 8601 datetime\n */\nexport function isValidIsoDate(value: string): boolean {\n if (!ISO_DATE_PATTERN.test(value)) {\n return false;\n }\n // Also check that Date parsing produces a valid date\n const date = new Date(value);\n return !Number.isNaN(date.getTime());\n}\n\n/**\n * Validates that a string is a valid ISO 8601 datetime.\n * Throws ValidationError if invalid.\n *\n * @param value - String to validate\n * @param fieldName - Name of field for error message\n * @returns The validated string\n * @throws ValidationError if not a valid ISO datetime\n */\nexport function validateIsoDate(value: string, fieldName: string): string {\n if (!isValidIsoDate(value)) {\n throw new ValidationError(\n `Invalid ISO 8601 datetime for \"${fieldName}\": \"${value}\". ` +\n `Expected format: YYYY-MM-DDTHH:mm:ss.sssZ`,\n {\n issues: [\n {\n path: fieldName,\n message: `Invalid ISO 8601 datetime format. Expected: YYYY-MM-DDTHH:mm:ss.sssZ, got: \"${value}\"`,\n },\n ],\n },\n {\n suggestion: `Use a valid ISO 8601 UTC datetime like \"2024-01-15T10:30:00.000Z\"`,\n },\n );\n }\n return value;\n}\n\n/**\n * Strict canonical ISO 8601 pattern: fixed-width UTC with exactly\n * millisecond precision (`YYYY-MM-DDTHH:mm:ss.sssZ`). Unlike\n * {@link ISO_DATE_PATTERN}, which tolerates a missing or variable-width\n * fractional part, this is the only shape whose lexicographic text order\n * matches chronological order — avoiding cases like `\"...:00.1Z\"` (= `.100`)\n * sorting *after* `\"...:00.101Z\"`.\n */\nconst CANONICAL_ISO_DATE_PATTERN =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\n\nconst ZONELESS_DATETIME_PATTERN =\n /^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?$/;\nconst OFFSET_DATETIME_PATTERN =\n /^(\\d{4}-\\d{2}-\\d{2})[ T](\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?)(Z|[+-]\\d{2}(?::?\\d{2})?)$/i;\nconst DATE_ONLY_PATTERN = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction normalizedOffset(offset: string): string {\n if (offset.toUpperCase() === \"Z\") return \"Z\";\n if (/^[+-]\\d{2}$/.test(offset)) return `${offset}:00`;\n if (/^[+-]\\d{4}$/.test(offset)) {\n return `${offset.slice(0, 3)}:${offset.slice(3)}`;\n }\n return offset;\n}\n\nfunction databaseTimestampMilliseconds(value: string): number {\n if (ZONELESS_DATETIME_PATTERN.test(value)) {\n return Date.parse(`${value.replace(\" \", \"T\")}Z`);\n }\n const offsetMatch = OFFSET_DATETIME_PATTERN.exec(value);\n if (offsetMatch !== null) {\n const date = offsetMatch[1];\n const time = offsetMatch[2];\n const offset = offsetMatch[3];\n if (date === undefined || time === undefined || offset === undefined) {\n return Number.NaN;\n }\n return Date.parse(`${date}T${time}${normalizedOffset(offset)}`);\n }\n if (DATE_ONLY_PATTERN.test(value)) {\n return Date.parse(`${value}T00:00:00.000Z`);\n }\n return Number.NaN;\n}\n\n/**\n * Canonicalizes a database-driver timestamp without interpreting a zoneless\n * string in the host timezone. PostgreSQL drivers can return values such as\n * `2026-06-25 12:00:00`; TypeGraph treats that shape as UTC so the same stored\n * clock value cannot move across hosts or daylight-saving boundaries.\n *\n * Returns `undefined` for an unsupported or unrepresentable value so callers\n * can raise an error specific to their storage boundary.\n */\nexport function canonicalizeDatabaseTimestamp(\n value: unknown,\n): string | undefined {\n if (value instanceof Date) {\n if (Number.isNaN(value.getTime())) return undefined;\n return value.toISOString();\n }\n if (typeof value !== \"string\") return undefined;\n const milliseconds = databaseTimestampMilliseconds(value);\n if (Number.isNaN(milliseconds)) return undefined;\n return new Date(milliseconds).toISOString();\n}\n\n/**\n * Checks if a string is a canonical UTC ISO 8601 datetime with fixed\n * millisecond width (`YYYY-MM-DDTHH:mm:ss.sssZ`).\n */\nexport function isCanonicalIsoDate(value: string): boolean {\n if (!CANONICAL_ISO_DATE_PATTERN.test(value)) return false;\n const date = new Date(value);\n return !Number.isNaN(date.getTime()) && date.toISOString() === value;\n}\n\n/**\n * Validates that a string is a canonical UTC ISO 8601 datetime with fixed\n * millisecond width. Stricter than {@link validateIsoDate} (which also\n * accepts missing or 1–2 digit milliseconds): required wherever the value\n * is compared **as text** against stored timestamps and must sort\n * chronologically — e.g. a temporal `asOf` coordinate, where a\n * variable-width value would mis-order and silently include or exclude the\n * wrong rows. Produce one with `new Date(value).toISOString()`.\n *\n * @param value - String to validate\n * @param fieldName - Name of field for error message\n * @returns The validated string\n * @throws ValidationError if not a canonical UTC ISO datetime\n */\nexport function validateCanonicalIsoDate(\n value: string,\n fieldName: string,\n): string {\n if (!isCanonicalIsoDate(value)) {\n throw new ValidationError(\n `Invalid canonical ISO 8601 datetime for \"${fieldName}\": \"${value}\". ` +\n `Expected fixed-width UTC: YYYY-MM-DDTHH:mm:ss.sssZ`,\n {\n issues: [\n {\n path: fieldName,\n message: `Expected canonical UTC ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ), got: \"${value}\"`,\n },\n ],\n },\n {\n suggestion: `Use a fixed-width UTC datetime like \"2024-01-15T10:30:00.000Z\" (e.g. new Date(value).toISOString()).`,\n },\n );\n }\n return value;\n}\n\n/**\n * Validates an optional canonical ISO date string. Returns `undefined` for an\n * absent value; otherwise enforces canonical fixed-width UTC ISO 8601 via\n * {@link validateCanonicalIsoDate}. Used for stored validity-window inputs\n * (`validFrom` / `validTo`) so every timestamp the temporal filters compare as\n * text is canonical and sorts chronologically — the same contract the `asOf`\n * read coordinate already enforces.\n */\nexport function validateOptionalCanonicalIsoDate(\n value: string | undefined,\n fieldName: string,\n): string | undefined {\n if (value === undefined) return undefined;\n return validateCanonicalIsoDate(value, fieldName);\n}\n\n/**\n * Whether a CANONICAL stated bound names the same instant a row already stores.\n *\n * The one comparison of a caller's bound against a stored one, so the coalesce\n * dirty check (\"would this write move the window?\") and the write guard (\"can\n * this stated bound be applied?\") can never disagree about what \"the same bound\"\n * means. Two copies of it did disagree — one comparing driver text, one\n * comparing instants — which is how a re-stated window wrote on one backend and\n * coalesced on the other.\n *\n * Only the STORED side is canonicalized. It arrives as the driver rendered it,\n * and the dialects do not render a timestamp the same way (SQLite returns the\n * written text; a Postgres driver may hand back a zoned string equivalent to the\n * canonical form without being identical to it). The stated side needs no\n * canonicalization because every write path validates it as canonical first —\n * which is a PRECONDITION here, not an assumption: a non-canonical stated bound\n * would compare unequal to an equivalent stored instant and must be rejected by\n * {@link validateCanonicalIsoDate} rather than silently treated as a mismatch.\n */\nexport function statedBoundMatchesStored(\n stated: string,\n stored: string | undefined,\n): boolean {\n return stated === canonicalizeDatabaseTimestamp(stored);\n}\n\n/**\n * Whether a stated validity window has NEGATIVE width — a row that stopped\n * being true before it started. The one comparison every window refusal is\n * built on, so paths that must report the fault through their own error type\n * (trusted import) decide it identically to the ones that throw a\n * `ValidationError`.\n *\n * PRECONDITION: both endpoints are canonical fixed-width UTC ISO 8601, which is\n * what makes a lexicographic compare a chronological one. Every caller\n * establishes that before comparing, with no exception: the paths that throw a\n * `ValidationError` reach this through {@link validateOptionalCanonicalIsoDate},\n * and trusted import — which skips schema validation for throughput —\n * format-checks the stated window fields of every streamed row against\n * {@link isCanonicalIsoDate} before reaching here. A bound read back from a row\n * needs no check of its own: it is canonical because the write that stored it\n * was held to this same contract — SQLite hands that text back verbatim, and the\n * PostgreSQL row mapper normalizes the driver's shape back to it. So no caller\n * can compare a value that would mis-sort, here or later against an `asOf`\n * coordinate.\n *\n * ZERO width (`validFrom === validTo`) is not inverted: it is what a\n * same-instant retraction produces at millisecond precision, and the store's own\n * output must round-trip.\n */\nexport function isInvertedValidityWindow(\n validFrom: string | undefined,\n validTo: string | undefined,\n): boolean {\n if (validFrom === undefined || validTo === undefined) return false;\n return validFrom > validTo;\n}\n\n/**\n * Refuses a `validTo` whose EFFECTIVE lower bound would invert the window. On an\n * in-place update the row's stored lower bound is the effective one and must stay\n * <= the new `validTo`; on a resurrection that RESETS `valid_from` it is the\n * write instant, so a lone past `validTo` would be born inverted.\n *\n * A ZERO-width window (`validTo === effectiveValidFrom`) is legal and stays\n * legal: it is what a same-instant retraction produces at millisecond\n * precision, and the identity-import window check sanctions it for the same\n * reason. Only NEGATIVE width refuses.\n *\n * Reached through {@link assertWritableValidityWindow} rather than called\n * directly, so no writer can check the effective bound without also checking a\n * stated pair.\n */\nfunction assertEffectiveValidityLowerBound(\n subject: string,\n effectiveValidFrom: string | undefined,\n validTo: string | undefined,\n): void {\n if (!isInvertedValidityWindow(effectiveValidFrom, validTo)) return;\n throw new ValidationError(\n `Inverted validity window for ${subject}: the effective validFrom \"${effectiveValidFrom}\" is after validTo \"${validTo}\".`,\n {\n issues: [\n {\n path: \"validTo\",\n code: INVERTED_VALIDITY_WINDOW_CODE,\n message: `Expected the effective validFrom <= validTo, got \"${effectiveValidFrom}\" > \"${validTo}\". The effective validFrom is the row's stored lower bound, or the write instant where the write stamps one.`,\n },\n ],\n },\n {\n suggestion:\n \"Provide both validFrom and validTo for a historical window, or drop validTo to keep the row current.\",\n },\n );\n}\n\n/**\n * Rejects an inverted validity window. `validFrom > validTo` describes a row\n * that stopped being true before it started, so no current-mode or `asOf` read\n * can ever observe it — the write succeeds and the row is then reachable only\n * through `includeEnded`, which reads as data loss rather than as the error it\n * is. Call this wherever both endpoints are supplied together; both are\n * canonical ISO 8601 by then, so a lexicographic compare is a chronological\n * compare.\n *\n * @param subject - Human-readable identification of the row, for the message\n * (e.g. `Person \"01H...\"`).\n * @throws ValidationError if both endpoints are present and out of order\n */\nexport function assertOrderedValidityWindow(\n subject: string,\n validFrom: string | undefined,\n validTo: string | undefined,\n): void {\n if (!isInvertedValidityWindow(validFrom, validTo)) return;\n throw new ValidationError(\n `Inverted validity window for ${subject}: validFrom \"${validFrom}\" is after validTo \"${validTo}\".`,\n {\n issues: [\n {\n path: \"validFrom\",\n code: INVERTED_VALIDITY_WINDOW_CODE,\n message: `Expected validFrom <= validTo, got \"${validFrom}\" > \"${validTo}\"`,\n },\n ],\n },\n {\n suggestion:\n \"Pass a validFrom at or before validTo, or omit validTo to leave the window open.\",\n },\n );\n}\n\n/**\n * What an UPDATE will do with the row's validity lower bound — the two facts the\n * write guard needs, stated by the writer that knows them.\n *\n * Every update path must decide `appliesStatedValidFrom` explicitly, because the\n * answer is not a property of the guard's other arguments: the same\n * `(validFrom, storedBound, validTo)` triple is a legal window restatement on a\n * resurrection and an unappliable bound on an in-place update.\n */\nexport type UpdateValidityLowerBound = Readonly<{\n /**\n * The bound the row will hold when the caller states no `validFrom`: the\n * stored `valid_from` for an in-place update, the write instant for a\n * resurrection that stamps a new one, `undefined` where there is no bound to\n * invert against.\n */\n effectiveValidFrom: string | undefined;\n /**\n * Whether the write STORES a stated `validFrom`. False for an in-place update\n * of a live row — `buildUpdateNode` / `buildUpdateEdge` rewrite `valid_from`\n * only on a resurrection — which is what makes a differing stated bound a\n * refusal rather than a silent drop.\n */\n appliesStatedValidFrom: boolean;\n /**\n * Whether `effectiveValidFrom` IS the row's stored `valid_from` — the value an\n * `expectedValidFrom` predicate would name — rather than a bound this write is\n * about to stamp itself.\n *\n * A node resurrection resets `valid_from` to the write instant and passes THAT\n * as the effective bound, so its verdict never looked at what the row holds and\n * a fence on the stored value would predicate the write on something nothing\n * read. An edge retains its bound through a resurrection, so its effective\n * bound is the stored one on both legs.\n */\n effectiveBoundIsStored: boolean;\n}>;\n\n/**\n * The `expectedValidFrom` predicate a write owes its verdict, shaped for\n * spreading straight into the backend's update params.\n *\n * `{}` means \"assert nothing\"; `{ expectedValidFrom: null }` means \"assert the\n * row still has NO lower bound\". The two are different claims and the object\n * form keeps them distinguishable at every call site — see\n * `UpdateNodeParams.expectedValidFrom`.\n */\nexport type ValidityLowerBoundFence = Readonly<{\n expectedValidFrom?: string | null;\n}>;\n\n/**\n * What {@link assertWritableValidityWindow} reports back about the verdict it\n * just reached — not about the window, but about what the verdict DEPENDED ON.\n *\n * THE SINGLE OWNER of the question \"must this write assert the row's stored\n * lower bound?\", and it answers by handing over the predicate ITSELF rather than\n * a flag a caller then turns into one. A write asserts every component its\n * verdict read (see `UpdateNodeParams.expectedValidFrom`), and which components\n * those are is decided by which branches the guard actually took — so a caller\n * that could still spell the fence on its own would eventually spell a different\n * one. Interchange import did exactly that: it asserted the probed\n * `valid_from` unconditionally, over-fencing props-only updates the store paths\n * (correctly) left unfenced. There is now nothing to re-derive.\n *\n * Too FEW assertions is a silent race; too many is a refusal of writes that are\n * legitimate. Both failures come from a second spelling.\n */\nexport type ValidityWindowVerdict = Readonly<{\n /**\n * The fence this verdict obliges the write to carry. Non-empty when the\n * verdict consulted the row's STORED `valid_from` — either by comparing a\n * stated bound against it, or by inverting a lone `validTo` against it — and\n * empty when the caller named no window at all, when the write applies the\n * bound it stated, or when the effective bound was one this write will stamp\n * rather than one the row holds. In those cases the verdict is independent of\n * what the row carries, and predicating the write on it would refuse a\n * concurrent recreate that changed nothing this decision looked at.\n */\n storedLowerBoundFence: ValidityLowerBoundFence;\n}>;\n\n/**\n * Whether an upsert explicitly treats its stated lower bound as\n * create/resurrection-only input.\n *\n * This predicate owns the policy decision for both write execution and\n * unchanged-upsert coalescing, so those paths cannot drift on whether a live\n * row's stored lower bound is preserved.\n */\nexport function preservesImmutableLowerBound(\n policy: \"preserve\" | \"refuse\" | undefined,\n): policy is \"preserve\" {\n return policy === \"preserve\";\n}\n\n/**\n * Refuses a stated `validFrom` the write would not apply.\n *\n * A live row's lower bound is HISTORY: it records when the row started being\n * true, and an in-place update never moves it. Accepting a bound that names a\n * different instant and then dropping it is the API lying — the caller's stated\n * window silently is not the stored one, while the write still spends a version\n * bump and a history row moving nothing. Restating the bound the row already\n * holds stays legal, so a caller that echoes a row's own window back (a merge\n * commit, a re-delivered upsert) is unaffected.\n *\n * Reached through {@link assertWritableValidityWindow} rather than called\n * directly, so no writer can accept a lower bound without declaring whether it\n * applies one.\n */\nfunction assertStatedLowerBoundIsApplicable(\n subject: string,\n statedValidFrom: string,\n storedValidFrom: string | undefined,\n): void {\n if (statedBoundMatchesStored(statedValidFrom, storedValidFrom)) return;\n const storedDescription =\n storedValidFrom === undefined ?\n \"the row has no lower bound\"\n : `the row's stored lower bound is \"${storedValidFrom}\"`;\n throw new ValidationError(\n `Unappliable validFrom for ${subject}: stated \"${statedValidFrom}\", but ${storedDescription} and the row is live.`,\n {\n issues: [\n {\n path: \"validFrom\",\n code: IMMUTABLE_VALIDITY_LOWER_BOUND_CODE,\n message: `A live row's lower bound is history and an in-place update never rewrites it, so \"${statedValidFrom}\" could not be applied.`,\n },\n ],\n },\n {\n suggestion:\n storedValidFrom === undefined ?\n \"Omit validFrom: this row has no lower bound to restate, and only a resurrection can give it one.\"\n : `Restate the stored bound (\"${storedValidFrom}\") or omit validFrom.`,\n },\n );\n}\n\n/**\n * THE window-ordering guard a valid-time UPDATE goes through, identically for\n * nodes and edges. Refuses a window of negative width — a row that stopped\n * being true before it started — whether the caller states both endpoints or\n * only the new end. Also refuses a stated lower bound the write cannot apply,\n * so no update accepts a `validFrom` it will ignore.\n *\n * Three checks, because the failures deserve different messages: the caller who\n * supplied both endpoints out of order gets told about the pair, the caller who\n * stated a lower bound this write cannot store gets told which bound the row\n * holds, and the caller whose lone `validTo` inverts against the bound the row\n * will actually carry gets told which bound that is.\n *\n * The stated pair is judged FIRST — an inverted pair is wrong whatever the row\n * holds — and the applicability of the lower bound before the effective-bound\n * check, so a caller is told their bound will not be stored rather than being\n * told about a bound they did not name.\n *\n * INSERTS use {@link assertOrderedValidityWindow} alone. An insert carrying a\n * lone historical `validTo` means \"born already ended\", and the write instant\n * the backend stamps as `valid_from` is a storage convention rather than a\n * caller assertion — the row is deliberately not current and is read back\n * through `includeEnded`. Only an UPDATE has a lower bound the caller can be\n * held to.\n *\n * @param subject - Human-readable identification of the row, for the message\n * (e.g. `Person \"01H...\"`).\n * @param validFrom - The caller's explicit lower bound, if any.\n * @param lowerBound - What the write will do with the row's lower bound; see\n * {@link UpdateValidityLowerBound}.\n * @returns {@link ValidityWindowVerdict} — the `expectedValidFrom` fence this\n * verdict obliges the write to carry, empty when it read no stored bound.\n * @throws ValidationError with issue code {@link INVERTED_VALIDITY_WINDOW_CODE}\n * or {@link IMMUTABLE_VALIDITY_LOWER_BOUND_CODE}\n */\nexport function assertWritableValidityWindow(\n subject: string,\n validFrom: string | undefined,\n lowerBound: UpdateValidityLowerBound,\n validTo: string | undefined,\n): ValidityWindowVerdict {\n assertOrderedValidityWindow(subject, validFrom, validTo);\n\n // The stated bound is COMPARED against the stored one only here — a write\n // that applies what the caller stated has nothing to compare it to.\n const comparedStatedBound =\n validFrom !== undefined && !lowerBound.appliesStatedValidFrom;\n if (comparedStatedBound) {\n assertStatedLowerBoundIsApplicable(\n subject,\n validFrom,\n lowerBound.effectiveValidFrom,\n );\n }\n\n assertEffectiveValidityLowerBound(\n subject,\n validFrom ?? lowerBound.effectiveValidFrom,\n validTo,\n );\n // ...and the inversion check falls back to the row's bound only when the\n // caller named an end without a start. Note this is true whether or not the\n // row HAS a bound: \"no lower bound to invert against\" is itself a reading of\n // the row, and a recreate that gives the row one changes the answer.\n const comparedStoredBoundAgainstEnd =\n validFrom === undefined && validTo !== undefined;\n\n const readEffectiveLowerBound =\n comparedStatedBound || comparedStoredBoundAgainstEnd;\n return {\n storedLowerBoundFence:\n readEffectiveLowerBound && lowerBound.effectiveBoundIsStored ?\n // eslint-disable-next-line unicorn/no-null -- `expectedValidFrom` distinguishes \"assert IS NULL\" (null) from \"assert nothing\" (an absent key); see UpdateNodeParams.\n { expectedValidFrom: lowerBound.effectiveValidFrom ?? null }\n : {},\n };\n}\n\n/**\n * Encodes a Date to an ISO 8601 string for storage.\n */\nexport function encodeDate(date: Date): string {\n return date.toISOString();\n}\n\n/**\n * Decodes an ISO 8601 string to a Date.\n * Validates the string format first.\n *\n * @throws ValidationError if not a valid ISO datetime\n */\nexport function decodeDate(isoString: string): Date {\n validateIsoDate(isoString, \"date\");\n return new Date(isoString);\n}\n\n/**\n * Returns the current timestamp as an ISO string.\n */\nexport function nowIso(): string {\n return new Date().toISOString();\n}\n","/**\n * Shared temporal coordinate + validation.\n */\nimport { ValidationError } from \"../errors\";\nimport { validateCanonicalIsoDate } from \"../utils/date\";\nimport { type TemporalMode } from \"./types\";\n\nconst RECORDED_INSTANT_VERSION = \"r1\";\nconst RECORDED_REVISION_WIDTH = 16;\n/** Open interval ceiling for numeric recorded-revision columns. */\nexport const RECORDED_MAX_REVISION = Number.MAX_SAFE_INTEGER;\nconst RECORDED_INSTANT_PATTERN =\n /^r1:(\\d{16}):(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z)$/;\n\ndeclare const RECORDED_INSTANT_BRAND: unique symbol;\n\n/**\n * A versioned recorded-time anchor containing a fixed-width logical revision\n * and a canonical UTC physical timestamp:\n * `r1:0000000000000001:YYYY-MM-DDTHH:mm:ss.sssZ`.\n *\n * Logical revisions are strictly monotonic per graph and make every commit\n * addressable even when many commits share one wall-clock millisecond. The\n * timestamp is a non-decreasing physical wall-time high-water mark used by\n * diagonal valid-time reads. Same-millisecond commits repeat it; backward clock\n * corrections hold it at the previous value until wall time catches up. The\n * string is canonical and lexicographically ordered by revision, so it can\n * round-trip through plain string checkpoint columns without a custom\n * serializer.\n */\nexport type RecordedInstant = string & {\n readonly [RECORDED_INSTANT_BRAND]: \"RecordedInstant\";\n};\n\nexport type RecordedInstantParts = Readonly<{\n revision: number;\n recordedAt: string;\n}>;\n\nfunction invalidRecordedInstant(value: string, path: string): ValidationError {\n return new ValidationError(\n `${path} must be a canonical versioned recorded instant.`,\n {\n issues: [\n {\n path,\n message: `Expected ${RECORDED_INSTANT_VERSION}:<${RECORDED_REVISION_WIDTH}-digit revision>:YYYY-MM-DDTHH:mm:ss.sssZ, got \"${value}\"`,\n },\n ],\n },\n {\n suggestion:\n \"Persist the exact string returned by store.recordedNow(); migrate preview-schema checkpoints with migrateLegacyRecordedTime() and migrateRecordedAnchor().\",\n },\n );\n}\n\nexport function parseRecordedInstant(\n value: string,\n path = \"RecordedInstant\",\n): RecordedInstantParts {\n const match = RECORDED_INSTANT_PATTERN.exec(value);\n if (match === null) throw invalidRecordedInstant(value, path);\n const revisionText = match[1];\n const recordedAt = match[2];\n if (revisionText === undefined || recordedAt === undefined) {\n throw invalidRecordedInstant(value, path);\n }\n const revision = Number(revisionText);\n if (\n !Number.isSafeInteger(revision) ||\n revision < 1 ||\n revision >= RECORDED_MAX_REVISION\n ) {\n throw invalidRecordedInstant(value, path);\n }\n validateCanonicalIsoDate(recordedAt, path);\n return { revision, recordedAt };\n}\n\nexport function assertValidRecordedInstant(value: string, path: string): void {\n parseRecordedInstant(value, path);\n}\n\n/**\n * Splits an optional recorded anchor into the numeric revision that recorded\n * relations store their `recorded_from`/`recorded_to` boundaries as, and the\n * wall time that valid-time windows are measured against. Compilers that\n * consult both halves parse once through this instead of per predicate.\n */\nexport function optionalRecordedInstantParts(\n value: string | undefined,\n path = \"RecordedInstant\",\n): RecordedInstantParts | undefined {\n return value === undefined ? undefined : parseRecordedInstant(value, path);\n}\n\nexport function createRecordedInstant(\n revision: number,\n recordedAt: string,\n): RecordedInstant {\n if (\n !Number.isSafeInteger(revision) ||\n revision < 1 ||\n revision >= RECORDED_MAX_REVISION\n ) {\n throw new ValidationError(\n \"createRecordedInstant revision must be a valid recorded revision.\",\n {\n issues: [\n {\n path: \"createRecordedInstant.revision\",\n message: `Expected a safe integer from 1 through ${String(RECORDED_MAX_REVISION - 1)}, got ${String(revision)}`,\n },\n ],\n },\n );\n }\n const revisionText = revision\n .toString()\n .padStart(RECORDED_REVISION_WIDTH, \"0\");\n return asRecordedInstant(\n `${RECORDED_INSTANT_VERSION}:${revisionText}:${recordedAt}`,\n );\n}\n\n/**\n * Returns the canonical UTC wall-time component of a recorded anchor.\n *\n * The value is non-decreasing per graph, but it is not the commit-order key;\n * use the complete {@link RecordedInstant} when ordering or replaying commits.\n */\nexport function recordedInstantWallTime(instant: RecordedInstant): string {\n return parseRecordedInstant(instant).recordedAt;\n}\n\n/** Returns the strict per-graph logical revision carried by an anchor. */\nexport function recordedInstantRevision(instant: RecordedInstant): number {\n return parseRecordedInstant(instant).revision;\n}\n\n/**\n * Compares two recorded anchors by logical revision.\n *\n * Revisions are local to a graph, so only compare anchors produced by the same\n * graph. The physical wall-time component deliberately does not participate.\n */\nexport function compareRecordedInstants(\n left: RecordedInstant,\n right: RecordedInstant,\n): -1 | 0 | 1 {\n const leftRevision = recordedInstantRevision(left);\n const rightRevision = recordedInstantRevision(right);\n if (leftRevision < rightRevision) return -1;\n if (leftRevision > rightRevision) return 1;\n return 0;\n}\n\n/**\n * Brands a canonical versioned anchor string as a {@link RecordedInstant}.\n *\n * The escape hatch for an instant that round-trips through untyped storage:\n * captured from {@link Store.recordedNow}, persisted as a plain string, read\n * back, and replayed into `asOfRecorded`. Validates the canonical form eagerly —\n * the same check `asOfRecorded` applies — so a malformed value fails here, at the\n * brand site, rather than deeper in a read. Does *not* assert the instant is a\n * real captured commit; it only guarantees the value is well-formed enough to\n * compare correctly against the recorded relations.\n *\n * @throws {ValidationError} when `value` is not a canonical versioned anchor.\n */\nexport function asRecordedInstant(value: string): RecordedInstant {\n assertValidRecordedInstant(value, \"asRecordedInstant\");\n return value as RecordedInstant;\n}\n\n/**\n * The single opaque temporal coordinate every pinned read is resolved\n * against. It carries the valid-time axis plus an optional recorded/system-time\n * axis, so every surface can inject one coordinate object instead of threading\n * each temporal dimension separately.\n */\nexport type ReadCoordinate = Readonly<{\n /**\n * The valid-time axis: a resolved temporal mode and (only for `\"asOf\"`) the\n * instant it is pinned to.\n */\n valid: Readonly<{\n mode: TemporalMode;\n /** Defined only when `mode` is `\"asOf\"`. */\n asOf?: string;\n }>;\n /** The recorded/system-time axis. Defined only for recorded-pinned views. */\n recorded?: Readonly<{ asOf: RecordedInstant }>;\n}>;\n\n/**\n * Resolves and validates a `(mode, asOf)` pair into a {@link ReadCoordinate}.\n * Rejects an `asOf` paired with any non-`\"asOf\"` mode rather than silently\n * dropping it — pinning an instant is only meaningful in `\"asOf\"` mode, so a\n * `view({ mode: \"current\", asOf })` is a caller mistake, not a coordinate to\n * quietly discard. Then validates via {@link assertValidAsOf}.\n *\n * @param mode - The temporal mode to pin.\n * @param asOf - The supplied timestamp. Required for `\"asOf\"`; rejected for\n * every other mode.\n * @param suggestion - Caller-specific remediation hint for the\n * missing/invalid-timestamp case.\n */\nexport function resolveReadCoordinate(\n mode: TemporalMode,\n asOf: string | undefined,\n suggestion?: string,\n): ReadCoordinate {\n if (mode !== \"asOf\" && asOf !== undefined) {\n throw new ValidationError(\n `Temporal mode \"${mode}\" does not take an asOf timestamp.`,\n {\n issues: [\n {\n path: \"asOf\",\n message: `asOf is only valid with mode \"asOf\", not \"${mode}\"`,\n },\n ],\n },\n {\n suggestion:\n 'Pin an instant with store.asOf(timestamp) or store.view({ mode: \"asOf\", asOf }); drop asOf for other modes.',\n },\n );\n }\n assertValidAsOf(\n mode,\n asOf,\n suggestion === undefined ? undefined : { suggestion },\n );\n return { valid: asOf === undefined ? { mode } : { mode, asOf } };\n}\n\n/**\n * Adds a recorded/system-time pin to an existing valid-time coordinate.\n * Direct `store.asOfRecorded(T)` passes the diagonal valid-time coordinate\n * (`mode: \"asOf\", asOf: T`); `store.asOf(vt).asOfRecorded(rt)` passes the\n * already-resolved valid coordinate and adds the recorded sibling.\n */\nexport function withRecordedCoordinate(\n coordinate: ReadCoordinate,\n recordedAsOf: RecordedInstant,\n): ReadCoordinate {\n assertValidRecordedInstant(recordedAsOf, \"asOfRecorded\");\n return {\n ...coordinate,\n recorded: { asOf: recordedAsOf },\n };\n}\n\n/**\n * Validates the `asOf` coordinate of a temporal read: `\"asOf\"` mode\n * requires a timestamp, and any supplied timestamp must be a canonical\n * fixed-width UTC ISO-8601 string (`YYYY-MM-DDTHH:mm:ss.sssZ`). The latter\n * is load-bearing — temporal filters compare `asOf` against `valid_from` /\n * `valid_to` as text on SQLite, so a non-canonical value (date-only, an\n * offset, natural language, or variable-width / missing milliseconds like\n * `.1Z`) would sort and compare wrong rather than error. Reached only through\n * {@link resolveReadCoordinate}, which every temporal read entry point routes\n * through (direct reads, queries, subgraphs, algorithms, and StoreView), so\n * they all fail identically.\n *\n * @param mode - The resolved temporal mode.\n * @param asOf - The supplied timestamp (may be `undefined`).\n * @param options.suggestion - A caller-specific remediation hint for the\n * missing-timestamp case.\n *\n * @throws {ValidationError} when `mode` is `\"asOf\"` and `asOf` is missing, or\n * when any supplied `asOf` is not a canonical UTC ISO-8601 timestamp. The\n * canonical check runs for *every* mode that consumes `asOf`, so a\n * non-canonical value can never reach a text comparison.\n */\nfunction assertValidAsOf(\n mode: TemporalMode,\n asOf: string | undefined,\n options?: Readonly<{ suggestion?: string }>,\n): void {\n if (mode === \"asOf\" && asOf === undefined) {\n throw new ValidationError(\n 'Temporal mode \"asOf\" requires a timestamp',\n {\n issues: [\n { path: \"asOf\", message: \"Timestamp is required for asOf mode\" },\n ],\n },\n {\n suggestion:\n options?.suggestion ??\n 'Provide an ISO-8601 timestamp for asOf mode, e.g. \"2026-01-01T00:00:00.000Z\".',\n },\n );\n }\n if (asOf !== undefined) {\n validateCanonicalIsoDate(asOf, \"asOf\");\n }\n}\n\n/**\n * A human-readable description of a coordinate for error messages, e.g.\n * `mode \"current\"` or `mode \"asOf\" asOf 2026-01-01T00:00:00.000Z`. Shared by\n * every refusal path (the `StoreView` read-only / current-only / search facades\n * and the sealed-query builder) so they describe a coordinate identically — and\n * a future axis (recorded time) is reflected everywhere from one place.\n */\nexport function describeCoordinate(coordinate: ReadCoordinate): string {\n const { mode, asOf } = coordinate.valid;\n const valid =\n asOf === undefined ? `mode \"${mode}\"` : `mode \"${mode}\" asOf ${asOf}`;\n return coordinate.recorded === undefined ?\n valid\n : `${valid}, recorded asOf ${coordinate.recorded.asOf}`;\n}\n\n/**\n * The structured error-context fields describing a coordinate, shared by the\n * same refusal paths as {@link describeCoordinate}.\n */\nexport function coordinateContext(\n coordinate: ReadCoordinate,\n): Record<string, unknown> {\n const { mode, asOf } = coordinate.valid;\n return {\n temporalMode: mode,\n ...(asOf !== undefined && { asOf }),\n ...(coordinate.recorded === undefined ?\n {}\n : { recordedAsOf: coordinate.recorded.asOf }),\n };\n}\n"]}