@nicia-ai/typegraph 0.43.0 → 0.45.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 (307) hide show
  1. package/dist/backend/drizzle/indexes.cjs +9 -9
  2. package/dist/backend/drizzle/indexes.d.cts +1 -1
  3. package/dist/backend/drizzle/indexes.d.ts +1 -1
  4. package/dist/backend/drizzle/indexes.js +5 -5
  5. package/dist/backend/index.cjs +50 -50
  6. package/dist/backend/index.d.cts +3 -3
  7. package/dist/backend/index.d.ts +3 -3
  8. package/dist/backend/index.js +11 -11
  9. package/dist/backend/postgres/index.cjs +26 -26
  10. package/dist/backend/postgres/index.d.cts +6 -5
  11. package/dist/backend/postgres/index.d.ts +6 -5
  12. package/dist/backend/postgres/index.js +13 -13
  13. package/dist/backend/postgres/pglite-store.cjs +32 -33
  14. package/dist/backend/postgres/pglite-store.cjs.map +1 -1
  15. package/dist/backend/postgres/pglite-store.d.cts +7 -7
  16. package/dist/backend/postgres/pglite-store.d.ts +7 -7
  17. package/dist/backend/postgres/pglite-store.js +28 -29
  18. package/dist/backend/postgres/pglite-store.js.map +1 -1
  19. package/dist/backend/postgres/pglite.cjs +15 -15
  20. package/dist/backend/postgres/pglite.d.cts +3 -2
  21. package/dist/backend/postgres/pglite.d.ts +3 -2
  22. package/dist/backend/postgres/pglite.js +14 -14
  23. package/dist/backend/sqlite/index.cjs +23 -23
  24. package/dist/backend/sqlite/index.d.cts +7 -6
  25. package/dist/backend/sqlite/index.d.ts +7 -6
  26. package/dist/backend/sqlite/index.js +11 -11
  27. package/dist/backend/sqlite/libsql.cjs +17 -17
  28. package/dist/backend/sqlite/libsql.cjs.map +1 -1
  29. package/dist/backend/sqlite/libsql.d.cts +3 -2
  30. package/dist/backend/sqlite/libsql.d.ts +3 -2
  31. package/dist/backend/sqlite/libsql.js +13 -13
  32. package/dist/backend/sqlite/libsql.js.map +1 -1
  33. package/dist/backend/sqlite/local-store.cjs +33 -34
  34. package/dist/backend/sqlite/local-store.cjs.map +1 -1
  35. package/dist/backend/sqlite/local-store.d.cts +8 -7
  36. package/dist/backend/sqlite/local-store.d.ts +8 -7
  37. package/dist/backend/sqlite/local-store.js +29 -30
  38. package/dist/backend/sqlite/local-store.js.map +1 -1
  39. package/dist/backend/sqlite/local.cjs +16 -16
  40. package/dist/backend/sqlite/local.d.cts +3 -2
  41. package/dist/backend/sqlite/local.d.ts +3 -2
  42. package/dist/backend/sqlite/local.js +14 -14
  43. package/dist/{chunk-2OOY4OYT.js → chunk-2L54C2C2.js} +4 -4
  44. package/dist/{chunk-2OOY4OYT.js.map → chunk-2L54C2C2.js.map} +1 -1
  45. package/dist/{chunk-4WYFRACU.js → chunk-42PYUGLS.js} +58 -4
  46. package/dist/chunk-42PYUGLS.js.map +1 -0
  47. package/dist/{chunk-EQOQOT55.js → chunk-4GUBTVPV.js} +4 -5
  48. package/dist/chunk-4GUBTVPV.js.map +1 -0
  49. package/dist/{chunk-ZIRC2U6G.js → chunk-4GUTQPVO.js} +102 -16
  50. package/dist/chunk-4GUTQPVO.js.map +1 -0
  51. package/dist/{chunk-OYJSYDIH.js → chunk-4MB3AQAQ.js} +13 -3
  52. package/dist/chunk-4MB3AQAQ.js.map +1 -0
  53. package/dist/{chunk-5Q3P6OIC.cjs → chunk-4MEWSUVM.cjs} +12 -12
  54. package/dist/chunk-4MEWSUVM.cjs.map +1 -0
  55. package/dist/{chunk-VC26BUNP.js → chunk-4QIKLIGG.js} +17 -5
  56. package/dist/chunk-4QIKLIGG.js.map +1 -0
  57. package/dist/chunk-4SZ6XPTG.cjs +12 -0
  58. package/dist/{chunk-VGMNGWBR.cjs.map → chunk-4SZ6XPTG.cjs.map} +1 -1
  59. package/dist/{chunk-UZLEQFTV.js → chunk-55ITBQJI.js} +4 -4
  60. package/dist/chunk-55ITBQJI.js.map +1 -0
  61. package/dist/{chunk-JOYPNY33.js → chunk-5EKPX6QU.js} +9 -9
  62. package/dist/{chunk-JOYPNY33.js.map → chunk-5EKPX6QU.js.map} +1 -1
  63. package/dist/{chunk-TRC646QQ.cjs → chunk-5GAONX5G.cjs} +7 -7
  64. package/dist/{chunk-TRC646QQ.cjs.map → chunk-5GAONX5G.cjs.map} +1 -1
  65. package/dist/{chunk-M4GYQF2H.js → chunk-6DCB664D.js} +7 -4
  66. package/dist/chunk-6DCB664D.js.map +1 -0
  67. package/dist/{chunk-64LERBFM.cjs → chunk-6RYPD3NJ.cjs} +75 -65
  68. package/dist/chunk-6RYPD3NJ.cjs.map +1 -0
  69. package/dist/{chunk-5AERZSHC.cjs → chunk-7PF2L3H6.cjs} +4 -4
  70. package/dist/{chunk-5AERZSHC.cjs.map → chunk-7PF2L3H6.cjs.map} +1 -1
  71. package/dist/chunk-B3F2D3SP.cjs +12 -0
  72. package/dist/{chunk-U3YRCZ5L.cjs.map → chunk-B3F2D3SP.cjs.map} +1 -1
  73. package/dist/{chunk-Z3WIL6S3.js → chunk-BGYJW37L.js} +5 -5
  74. package/dist/{chunk-Z3WIL6S3.js.map → chunk-BGYJW37L.js.map} +1 -1
  75. package/dist/{chunk-DMZEVJGL.cjs → chunk-BNS75YNF.cjs} +12 -13
  76. package/dist/chunk-BNS75YNF.cjs.map +1 -0
  77. package/dist/{chunk-KTBTSHU6.cjs → chunk-C4F7VJ5D.cjs} +13 -3
  78. package/dist/chunk-C4F7VJ5D.cjs.map +1 -0
  79. package/dist/{chunk-L2BYRYHC.js → chunk-CBKG6HEP.js} +43 -33
  80. package/dist/chunk-CBKG6HEP.js.map +1 -0
  81. package/dist/{chunk-CVK4T34X.cjs → chunk-CPEL3YIR.cjs} +22 -22
  82. package/dist/{chunk-CVK4T34X.cjs.map → chunk-CPEL3YIR.cjs.map} +1 -1
  83. package/dist/{chunk-O2GZM7UK.cjs → chunk-D54WH24V.cjs} +62 -7
  84. package/dist/chunk-D54WH24V.cjs.map +1 -0
  85. package/dist/{chunk-33PAKPED.cjs → chunk-D56XG4EI.cjs} +53 -41
  86. package/dist/chunk-D56XG4EI.cjs.map +1 -0
  87. package/dist/{chunk-O3USVVWS.js → chunk-DK2S42XB.js} +3 -3
  88. package/dist/{chunk-O3USVVWS.js.map → chunk-DK2S42XB.js.map} +1 -1
  89. package/dist/{chunk-HHBKGPEI.js → chunk-DXEEHSGN.js} +517 -26
  90. package/dist/chunk-DXEEHSGN.js.map +1 -0
  91. package/dist/{chunk-UJRWOV5B.js → chunk-EFEOOCJ3.js} +5 -5
  92. package/dist/{chunk-UJRWOV5B.js.map → chunk-EFEOOCJ3.js.map} +1 -1
  93. package/dist/{chunk-ECU53PMN.cjs → chunk-EKFUG4G7.cjs} +5 -5
  94. package/dist/chunk-EKFUG4G7.cjs.map +1 -0
  95. package/dist/{chunk-FSCJOTHF.cjs → chunk-EQ7JKLZO.cjs} +10 -10
  96. package/dist/{chunk-FSCJOTHF.cjs.map → chunk-EQ7JKLZO.cjs.map} +1 -1
  97. package/dist/{chunk-AQR6BHB3.cjs → chunk-F4NHQHEZ.cjs} +10 -10
  98. package/dist/{chunk-AQR6BHB3.cjs.map → chunk-F4NHQHEZ.cjs.map} +1 -1
  99. package/dist/{chunk-2G6ZEGYO.js → chunk-FL5UQRES.js} +4 -4
  100. package/dist/{chunk-2G6ZEGYO.js.map → chunk-FL5UQRES.js.map} +1 -1
  101. package/dist/{chunk-ZP2KPDNN.js → chunk-FLEQ2HBK.js} +3 -3
  102. package/dist/{chunk-ZP2KPDNN.js.map → chunk-FLEQ2HBK.js.map} +1 -1
  103. package/dist/{chunk-RAWG2FEU.js → chunk-FQ7ZPOTZ.js} +264 -18
  104. package/dist/chunk-FQ7ZPOTZ.js.map +1 -0
  105. package/dist/{chunk-O7XVCLXW.cjs → chunk-H7VE3FL4.cjs} +577 -82
  106. package/dist/chunk-H7VE3FL4.cjs.map +1 -0
  107. package/dist/{chunk-JNXZQBN3.js → chunk-ID4WXTKL.js} +1039 -482
  108. package/dist/chunk-ID4WXTKL.js.map +1 -0
  109. package/dist/{chunk-ZGOUVMVS.js → chunk-ISLPNELU.js} +17 -5
  110. package/dist/chunk-ISLPNELU.js.map +1 -0
  111. package/dist/{chunk-I73ATSAH.cjs → chunk-IX64T5OL.cjs} +4 -4
  112. package/dist/{chunk-I73ATSAH.cjs.map → chunk-IX64T5OL.cjs.map} +1 -1
  113. package/dist/{chunk-XDMPDUKL.cjs → chunk-J2ICGNHO.cjs} +8 -9
  114. package/dist/chunk-J2ICGNHO.cjs.map +1 -0
  115. package/dist/{chunk-KDRF3NR2.cjs → chunk-J7LXTUTP.cjs} +295 -201
  116. package/dist/chunk-J7LXTUTP.cjs.map +1 -0
  117. package/dist/{chunk-AO2WPYFZ.cjs → chunk-JQXSZHF2.cjs} +14 -4
  118. package/dist/chunk-JQXSZHF2.cjs.map +1 -0
  119. package/dist/{chunk-UTTW2Q3M.cjs → chunk-JXUTCSXX.cjs} +197 -133
  120. package/dist/chunk-JXUTCSXX.cjs.map +1 -0
  121. package/dist/{chunk-GT7NEXSU.js → chunk-KCO5EFJU.js} +3 -3
  122. package/dist/{chunk-GT7NEXSU.js.map → chunk-KCO5EFJU.js.map} +1 -1
  123. package/dist/{chunk-ARN3ZODS.cjs → chunk-KKYELPZ2.cjs} +6 -6
  124. package/dist/{chunk-ARN3ZODS.cjs.map → chunk-KKYELPZ2.cjs.map} +1 -1
  125. package/dist/{chunk-7Y6BV3TK.cjs → chunk-KMXWZLQX.cjs} +100 -100
  126. package/dist/{chunk-7Y6BV3TK.cjs.map → chunk-KMXWZLQX.cjs.map} +1 -1
  127. package/dist/{chunk-CDYRPI5U.js → chunk-MIJKEVV7.js} +4 -4
  128. package/dist/{chunk-CDYRPI5U.js.map → chunk-MIJKEVV7.js.map} +1 -1
  129. package/dist/{chunk-FFQGI67R.cjs → chunk-NAAMUYMS.cjs} +56 -44
  130. package/dist/chunk-NAAMUYMS.cjs.map +1 -0
  131. package/dist/{chunk-6TJ6PKPS.cjs → chunk-OOA273IJ.cjs} +27 -27
  132. package/dist/{chunk-6TJ6PKPS.cjs.map → chunk-OOA273IJ.cjs.map} +1 -1
  133. package/dist/{chunk-F2KVJ6FF.cjs → chunk-P7GTYOLB.cjs} +203 -117
  134. package/dist/chunk-P7GTYOLB.cjs.map +1 -0
  135. package/dist/{chunk-42XYPKZU.js → chunk-PVUI6KGR.js} +67 -3
  136. package/dist/chunk-PVUI6KGR.js.map +1 -0
  137. package/dist/{chunk-L5AUCL5P.js → chunk-Q6EDCUXV.js} +274 -14
  138. package/dist/chunk-Q6EDCUXV.js.map +1 -0
  139. package/dist/{chunk-ZPCKPLMX.cjs → chunk-QB6VMOJ2.cjs} +8 -8
  140. package/dist/{chunk-ZPCKPLMX.cjs.map → chunk-QB6VMOJ2.cjs.map} +1 -1
  141. package/dist/{chunk-3RPQDGUE.cjs → chunk-QC4MCOFV.cjs} +5 -5
  142. package/dist/{chunk-3RPQDGUE.cjs.map → chunk-QC4MCOFV.cjs.map} +1 -1
  143. package/dist/{chunk-4XRP2N6B.js → chunk-QLUXRWKL.js} +3 -3
  144. package/dist/{chunk-4XRP2N6B.js.map → chunk-QLUXRWKL.js.map} +1 -1
  145. package/dist/{chunk-OM6RIOA5.cjs → chunk-QR24DJDF.cjs} +13 -13
  146. package/dist/{chunk-OM6RIOA5.cjs.map → chunk-QR24DJDF.cjs.map} +1 -1
  147. package/dist/{chunk-YPVQYM3L.js → chunk-QRNYDV5Z.js} +138 -31
  148. package/dist/chunk-QRNYDV5Z.js.map +1 -0
  149. package/dist/{chunk-ZOHCFYXE.js → chunk-QT6V3YRH.js} +3 -3
  150. package/dist/{chunk-ZOHCFYXE.js.map → chunk-QT6V3YRH.js.map} +1 -1
  151. package/dist/{chunk-5C75HQYQ.js → chunk-RFRM3Q5K.js} +17 -5
  152. package/dist/chunk-RFRM3Q5K.js.map +1 -0
  153. package/dist/{chunk-NXIZL7ZZ.js → chunk-RUQS6M7G.js} +6 -6
  154. package/dist/chunk-RUQS6M7G.js.map +1 -0
  155. package/dist/{chunk-CI5NPLXX.js → chunk-S3ZRKJHY.js} +3 -3
  156. package/dist/{chunk-CI5NPLXX.js.map → chunk-S3ZRKJHY.js.map} +1 -1
  157. package/dist/{chunk-3V6D5DEC.js → chunk-S4KQ5LV4.js} +3 -3
  158. package/dist/{chunk-3V6D5DEC.js.map → chunk-S4KQ5LV4.js.map} +1 -1
  159. package/dist/{chunk-CTWZPYJW.js → chunk-TKORQCG4.js} +108 -15
  160. package/dist/chunk-TKORQCG4.js.map +1 -0
  161. package/dist/{chunk-2HKIID5K.js → chunk-TKP5T34P.js} +4 -5
  162. package/dist/chunk-TKP5T34P.js.map +1 -0
  163. package/dist/{chunk-X2XOQZT3.cjs → chunk-U5W4LKZV.cjs} +13 -9
  164. package/dist/chunk-U5W4LKZV.cjs.map +1 -0
  165. package/dist/{chunk-BLBG2VZ5.cjs → chunk-UCQ3BFSY.cjs} +372 -110
  166. package/dist/chunk-UCQ3BFSY.cjs.map +1 -0
  167. package/dist/{chunk-CUPJL6TS.js → chunk-V34A6R5V.js} +13 -4
  168. package/dist/chunk-V34A6R5V.js.map +1 -0
  169. package/dist/{chunk-LQLVJWUH.js → chunk-VTN3C3CH.js} +7 -7
  170. package/dist/chunk-VTN3C3CH.js.map +1 -0
  171. package/dist/{chunk-FY4VY5EV.cjs → chunk-VVQM4CZD.cjs} +20 -20
  172. package/dist/chunk-VVQM4CZD.cjs.map +1 -0
  173. package/dist/{chunk-LDCWO5B6.js → chunk-WDAVPX46.js} +3 -3
  174. package/dist/{chunk-LDCWO5B6.js.map → chunk-WDAVPX46.js.map} +1 -1
  175. package/dist/{chunk-5GV4JQNA.cjs → chunk-WDBXJOU5.cjs} +55 -43
  176. package/dist/chunk-WDBXJOU5.cjs.map +1 -0
  177. package/dist/{chunk-FMPZPOUD.js → chunk-WUFASQUO.js} +3 -3
  178. package/dist/{chunk-FMPZPOUD.js.map → chunk-WUFASQUO.js.map} +1 -1
  179. package/dist/{chunk-5ZPRE4CV.cjs → chunk-YDWLUT5V.cjs} +237 -130
  180. package/dist/chunk-YDWLUT5V.cjs.map +1 -0
  181. package/dist/{chunk-CVNGKTHO.js → chunk-YMTXMPV6.js} +4 -4
  182. package/dist/{chunk-CVNGKTHO.js.map → chunk-YMTXMPV6.js.map} +1 -1
  183. package/dist/{chunk-NDQLPKBX.cjs → chunk-YOALGKRE.cjs} +2092 -1535
  184. package/dist/chunk-YOALGKRE.cjs.map +1 -0
  185. package/dist/{chunk-OMQ2NBOR.cjs → chunk-Z3WO6MND.cjs} +27 -27
  186. package/dist/{chunk-OMQ2NBOR.cjs.map → chunk-Z3WO6MND.cjs.map} +1 -1
  187. package/dist/{chunk-V2GZBPY2.cjs → chunk-ZI6VQSZA.cjs} +310 -61
  188. package/dist/chunk-ZI6VQSZA.cjs.map +1 -0
  189. package/dist/{chunk-ZBV4LQD2.cjs → chunk-ZTAJL4DT.cjs} +4 -4
  190. package/dist/{chunk-ZBV4LQD2.cjs.map → chunk-ZTAJL4DT.cjs.map} +1 -1
  191. package/dist/core/index.cjs +27 -28
  192. package/dist/core/index.d.cts +5 -5
  193. package/dist/core/index.d.ts +5 -5
  194. package/dist/core/index.js +7 -8
  195. package/dist/{ddl-3unqC-kg.d.cts → ddl-BG4J805L.d.cts} +3 -3
  196. package/dist/{ddl-Bc4Dl8fu.d.ts → ddl-CgiS9QLj.d.ts} +3 -3
  197. package/dist/{define-graph-DBFnc7u_.d.ts → define-graph-BGrJahvp.d.ts} +1 -1
  198. package/dist/{define-graph-Byslw2OO.d.cts → define-graph-alREY2wj.d.cts} +1 -1
  199. package/dist/graph-extension/index.cjs +19 -20
  200. package/dist/graph-extension/index.d.cts +4 -4
  201. package/dist/graph-extension/index.d.ts +4 -4
  202. package/dist/graph-extension/index.js +4 -5
  203. package/dist/graph-merge/index.cjs +103 -104
  204. package/dist/graph-merge/index.cjs.map +1 -1
  205. package/dist/graph-merge/index.d.cts +9 -8
  206. package/dist/graph-merge/index.d.ts +9 -8
  207. package/dist/graph-merge/index.js +23 -24
  208. package/dist/graph-merge/index.js.map +1 -1
  209. package/dist/{index-DHXw7QAl.d.cts → index-BBxZCUdu.d.ts} +37 -7
  210. package/dist/{index-DQzVJBHa.d.ts → index-C3y_98iN.d.cts} +37 -7
  211. package/dist/index.cjs +209 -202
  212. package/dist/index.cjs.map +1 -1
  213. package/dist/index.d.cts +13 -13
  214. package/dist/index.d.ts +13 -13
  215. package/dist/index.js +33 -34
  216. package/dist/index.js.map +1 -1
  217. package/dist/indexes/index.cjs +13 -13
  218. package/dist/indexes/index.d.cts +4 -4
  219. package/dist/indexes/index.d.ts +4 -4
  220. package/dist/indexes/index.js +6 -6
  221. package/dist/interchange/index.cjs +50 -41
  222. package/dist/interchange/index.cjs.map +1 -1
  223. package/dist/interchange/index.d.cts +11 -11
  224. package/dist/interchange/index.d.ts +11 -11
  225. package/dist/interchange/index.js +24 -15
  226. package/dist/interchange/index.js.map +1 -1
  227. package/dist/{manager-U9_zopqr.d.cts → manager-KS7CGQQT.d.cts} +44 -6
  228. package/dist/{manager-Dl0-er1G.d.ts → manager-YoLEfcc1.d.ts} +44 -6
  229. package/dist/{materialize-indexes-BM3u0aXE.d.ts → materialize-indexes-Bhhyb1B3.d.ts} +1 -1
  230. package/dist/{materialize-indexes-DzMCetZe.d.cts → materialize-indexes-OHRWypW6.d.cts} +1 -1
  231. package/dist/{postgres-DpJqtbSX.d.cts → postgres-DpkW3R5Y.d.cts} +1 -1
  232. package/dist/{postgres-C5-WMKFA.d.ts → postgres-DwqyIniy.d.ts} +1 -1
  233. package/dist/profiler/index.d.cts +10 -9
  234. package/dist/profiler/index.d.ts +10 -9
  235. package/dist/provenance/index.cjs +38 -38
  236. package/dist/provenance/index.cjs.map +1 -1
  237. package/dist/provenance/index.d.cts +7 -7
  238. package/dist/provenance/index.d.ts +7 -7
  239. package/dist/provenance/index.js +8 -8
  240. package/dist/provenance/index.js.map +1 -1
  241. package/dist/schema/index.cjs +40 -41
  242. package/dist/schema/index.d.cts +7 -7
  243. package/dist/schema/index.d.ts +7 -7
  244. package/dist/schema/index.js +13 -14
  245. package/dist/{searchable-B4mUXZT6.d.cts → searchable-CIZL8Hyw.d.cts} +2 -2
  246. package/dist/{searchable-C7jmPNLT.d.ts → searchable-DLWEfC4a.d.ts} +2 -2
  247. package/dist/{sqlite-Ch5tSYQY.d.ts → sqlite-DY0WODUK.d.cts} +1 -1
  248. package/dist/{sqlite-Da7jiYu9.d.cts → sqlite-L-VIRzqA.d.ts} +1 -1
  249. package/dist/{store-view-DdwBNjZQ.d.ts → store-view-66p92IPi.d.ts} +1974 -1751
  250. package/dist/{store-view-D1F6KqsE.d.cts → store-view-A85FFRnk.d.cts} +1974 -1751
  251. package/dist/{temporal-CMpigMCW.d.cts → temporal-BNbjXqer.d.cts} +1 -1
  252. package/dist/{temporal-BtrTYTiB.d.ts → temporal-Bob6Nfbp.d.ts} +1 -1
  253. package/dist/{types-Dh-EgT-w.d.cts → types-Ch9a0Dx6.d.cts} +483 -20
  254. package/dist/{types-Dh-EgT-w.d.ts → types-Ch9a0Dx6.d.ts} +483 -20
  255. package/dist/{types-D2rU5Taq.d.ts → types-ClCzT-dT.d.ts} +1 -1
  256. package/dist/{types-G4sVM-76.d.cts → types-DeORZhxn.d.cts} +1 -1
  257. package/dist/{where-DbZ9XDOI.d.cts → where-DPw52ksb.d.cts} +1 -1
  258. package/dist/{where-B8Y21kig.d.ts → where-kWUZPvEA.d.ts} +1 -1
  259. package/package.json +1 -1
  260. package/dist/chunk-2HKIID5K.js.map +0 -1
  261. package/dist/chunk-33PAKPED.cjs.map +0 -1
  262. package/dist/chunk-42XYPKZU.js.map +0 -1
  263. package/dist/chunk-4WYFRACU.js.map +0 -1
  264. package/dist/chunk-5C75HQYQ.js.map +0 -1
  265. package/dist/chunk-5GV4JQNA.cjs.map +0 -1
  266. package/dist/chunk-5Q3P6OIC.cjs.map +0 -1
  267. package/dist/chunk-5ZPRE4CV.cjs.map +0 -1
  268. package/dist/chunk-64LERBFM.cjs.map +0 -1
  269. package/dist/chunk-AO2WPYFZ.cjs.map +0 -1
  270. package/dist/chunk-BLBG2VZ5.cjs.map +0 -1
  271. package/dist/chunk-CTWZPYJW.js.map +0 -1
  272. package/dist/chunk-CUPJL6TS.js.map +0 -1
  273. package/dist/chunk-DMZEVJGL.cjs.map +0 -1
  274. package/dist/chunk-ECU53PMN.cjs.map +0 -1
  275. package/dist/chunk-EQOQOT55.js.map +0 -1
  276. package/dist/chunk-F2KVJ6FF.cjs.map +0 -1
  277. package/dist/chunk-F7TDKSVB.cjs +0 -61
  278. package/dist/chunk-F7TDKSVB.cjs.map +0 -1
  279. package/dist/chunk-FFQGI67R.cjs.map +0 -1
  280. package/dist/chunk-FY4VY5EV.cjs.map +0 -1
  281. package/dist/chunk-HHBKGPEI.js.map +0 -1
  282. package/dist/chunk-JNXZQBN3.js.map +0 -1
  283. package/dist/chunk-KDRF3NR2.cjs.map +0 -1
  284. package/dist/chunk-KTBTSHU6.cjs.map +0 -1
  285. package/dist/chunk-L2BYRYHC.js.map +0 -1
  286. package/dist/chunk-L5AUCL5P.js.map +0 -1
  287. package/dist/chunk-LQLVJWUH.js.map +0 -1
  288. package/dist/chunk-M4GYQF2H.js.map +0 -1
  289. package/dist/chunk-NDQLPKBX.cjs.map +0 -1
  290. package/dist/chunk-NXIZL7ZZ.js.map +0 -1
  291. package/dist/chunk-O2GZM7UK.cjs.map +0 -1
  292. package/dist/chunk-O7XVCLXW.cjs.map +0 -1
  293. package/dist/chunk-OYJSYDIH.js.map +0 -1
  294. package/dist/chunk-RAWG2FEU.js.map +0 -1
  295. package/dist/chunk-RXOAXO3R.js +0 -59
  296. package/dist/chunk-RXOAXO3R.js.map +0 -1
  297. package/dist/chunk-U3YRCZ5L.cjs +0 -12
  298. package/dist/chunk-UTTW2Q3M.cjs.map +0 -1
  299. package/dist/chunk-UZLEQFTV.js.map +0 -1
  300. package/dist/chunk-V2GZBPY2.cjs.map +0 -1
  301. package/dist/chunk-VC26BUNP.js.map +0 -1
  302. package/dist/chunk-VGMNGWBR.cjs +0 -12
  303. package/dist/chunk-X2XOQZT3.cjs.map +0 -1
  304. package/dist/chunk-XDMPDUKL.cjs.map +0 -1
  305. package/dist/chunk-YPVQYM3L.js.map +0 -1
  306. package/dist/chunk-ZGOUVMVS.js.map +0 -1
  307. package/dist/chunk-ZIRC2U6G.js.map +0 -1
@@ -1,31 +1,31 @@
1
- import { createEdgeRowMapper, createNodeRowMapper, SQLITE_ROW_MAPPER_CONFIG, POSTGRES_ROW_MAPPER_CONFIG } from './chunk-CVNGKTHO.js';
2
- import { rowToNode, executeNodeBulkFindByIndex, executeNodeBulkFindByConstraint, executeNodeFindByConstraint, executeNodeBulkGetOrCreateByConstraint, executeNodeGetOrCreateByConstraint, executeNodeHardDelete, executeNodeDelete, nodeUpsertDirtyCheck, executeNodeUpsertUpdate, executeNodeUpdate, executeNodeCreateNoReturnBatch, executeNodeCreateBatch, executeNodeCreate, rowToEdge, runInWriteTransaction, checkCardinalityConstraint, runHookedWriteOperation, rowToNodeMeta, rowToEdgeMeta } from './chunk-L5AUCL5P.js';
3
- import { isParameterRef, fieldRef, buildFieldBuilderForTypeInfo, stringField, createFulltextAccessor, storeRuntime, CURRENT_READ_INSTANT_PLACEHOLDER, withPinnedReadInstant, STORE_RUNTIME, assertRevisionTrackableBackend, createRecordedBackend, readRecordedClock, ensureRevisionOrigin, TRANSACTION_RUNTIME, withRecordedFlushObserver, recordedCaptureRequiresCallbackTransactionError, assertRecordedCaptureTransactionIsolation, createRecordedTransactionScope, lockRecordedGraphWrite, generateId, createGraphBackendProjection, assertCurrentRecordedSchema, baseField, objectField, arrayField, dateField, numberField, computeFulltextContent, AUTO_REFRESH_STATISTICS_ROW_THRESHOLD, advanceRevisionClock, runInsertBatch, edgeInsertDispatch, runInsertBatchReturning, projectBackendMembers, sqlValueList, getEmbeddingFields, getNodeRowsByIds, getEdgeRowsByIds, compileKindFilter, currentReadInstant, compileTemporalFilter, validateEdgeEndpoints, buildPredicateIndex, compileFieldValue, recordedBindParamBudget, extractVectorSimilarityPredicates, extractFulltextMatchPredicates, currentReadInstantFor, extractTemporalOptions, compilePredicateExpression, getPredicatesForAlias, getFieldPointer, getNodeKindsForAlias, getHybridTargetAlias, closeRecordedHardDeletedKind, throwHistoryUnsafeSqlAccess, throwRevisionTrackingUnsafeSqlAccess, compilePredicateClauses } from './chunk-CTWZPYJW.js';
4
- import { chunk } from './chunk-35S6P5ZU.js';
5
- import { DEFAULT_SQL_SCHEMA, requireSqlSchema, recordedReadSchemaFor, createSqlSchema, requireExternalRecordedReadSource, createRecordedReadBinding, vectorSlotKey, recordedReadSqlSchema, requireRecordedReadBinding, ALIAS_CTE_PREFIX, EMBEDDINGS_CTE_ALIAS, FULLTEXT_CTE_ALIAS, HYBRID_CANDIDATES_CTE_ALIAS } from './chunk-CDYRPI5U.js';
6
- import { runOptionallyInTransaction, createTransactionReadBackend, rowPropsToObject, createBackendOverlay, INTERNAL_TEMPORARY_WRITES } from './chunk-UZLEQFTV.js';
7
- import { resolveReadCoordinate, withRecordedCoordinate, describeCoordinate, coordinateContext, recordedInstantWallTime, asRecordedInstant, assertValidRecordedInstant } from './chunk-2OOY4OYT.js';
8
- import { loadAndMergeGraphExtensionDocument, ensureSchema, loadAndVerifyGraph, buildKindRegistry, getSchemaChanges, requiresMigration, mergeGraphExtension, commitNewSchemaVersion, applyDeprecatedKinds, loadActiveSchemaWithBootstrap, parseSerializedSchema, extensionKindNames, serializeSchemaProperties, buildGraphExtensionOntologyKeySet, compileTimeOntologyKey, serializeIndexDeclaration } from './chunk-RAWG2FEU.js';
1
+ import { createEdgeRowMapper, createNodeRowMapper, SQLITE_ROW_MAPPER_CONFIG, POSTGRES_ROW_MAPPER_CONFIG } from './chunk-YMTXMPV6.js';
2
+ import { rowToNode, executeNodeBulkFindByIndex, executeNodeBulkFindByConstraint, executeNodeFindByConstraint, executeNodeBulkGetOrCreateByConstraint, executeNodeGetOrCreateByConstraint, executeNodeHardDelete, executeNodeDelete, nodeUpsertDirtyCheck, executeNodeUpsertUpdate, executeNodeUpdateWhere, executeNodeUpdate, executeNodeCreateNoReturnBatch, executeNodeCreateBatch, executeNodeCreate, rowToEdge, lockSchemaVersionForStoreWrite, runInWriteTransaction, checkCardinalityConstraint, runHookedWriteOperation, rowToNodeMeta, rowToEdgeMeta } from './chunk-Q6EDCUXV.js';
3
+ import { isParameterRef, resolveParameterValueType, fieldRef, buildFieldBuilderForTypeInfo, stringField, createFulltextAccessor, storeRuntime, CURRENT_READ_INSTANT_PLACEHOLDER, withPinnedReadInstant, STORE_RUNTIME, assertRevisionTrackableBackend, createRecordedBackend, readRecordedClock, ensureRevisionOrigin, TRANSACTION_RUNTIME, withRecordedFlushObserver, recordedCaptureRequiresCallbackTransactionError, assertRecordedCaptureTransactionIsolation, createRecordedTransactionScope, lockRecordedGraphWrite, createGraphBackendProjection, generateId, assertCurrentRecordedSchema, baseField, objectField, arrayField, dateField, numberField, computeFulltextContent, AUTO_REFRESH_STATISTICS_ROW_THRESHOLD, advanceRevisionClock, runInsertBatch, edgeInsertDispatch, runInsertBatchReturning, projectBackendMembers, sqlValueList, getEmbeddingFields, getNodeRowsByIds, getEdgeRowsByIds, compileKindFilter, currentReadInstant, compileTemporalFilter, validateEdgeEndpoints, closeRecordedHardDeletedKind, buildPredicateIndex, compileFieldValue, recordedBindParamBudget, extractVectorSimilarityPredicates, extractFulltextMatchPredicates, currentReadInstantFor, extractTemporalOptions, compilePredicateExpression, getPredicatesForAlias, getFieldPointer, getNodeKindsForAlias, getHybridTargetAlias, throwHistoryUnsafeSqlAccess, throwRevisionTrackingUnsafeSqlAccess, compilePredicateClauses } from './chunk-TKORQCG4.js';
4
+ import { chunk, groupBy } from './chunk-35S6P5ZU.js';
5
+ import { DEFAULT_SQL_SCHEMA, requireSqlSchema, recordedReadSchemaFor, createSqlSchema, requireExternalRecordedReadSource, createRecordedReadBinding, vectorSlotKey, recordedReadSqlSchema, requireRecordedReadBinding, ALIAS_CTE_PREFIX, EMBEDDINGS_CTE_ALIAS, FULLTEXT_CTE_ALIAS, HYBRID_CANDIDATES_CTE_ALIAS } from './chunk-MIJKEVV7.js';
6
+ import { runOptionallyInTransaction, createTransactionReadBackend, rowPropsToObject, createBackendOverlay, INTERNAL_TEMPORARY_WRITES } from './chunk-55ITBQJI.js';
7
+ import { resolveReadCoordinate, withRecordedCoordinate, describeCoordinate, coordinateContext, recordedInstantWallTime, asRecordedInstant, assertValidRecordedInstant } from './chunk-2L54C2C2.js';
8
+ import { loadAndMergeGraphExtensionDocument, ensureSchema, loadAndVerifyGraph, buildKindRegistry, getSchemaChanges, requiresMigration, mergeGraphExtension, commitNewSchemaVersion, planRemovals, stripGraphExtension, applyDeprecatedKinds, loadActiveSchemaWithBootstrap, parseSerializedSchema, extensionKindNames, serializeSchemaProperties, buildGraphExtensionOntologyKeySet, compileTimeOntologyKey, commitNewSchemaVersionIfKindsEmpty, serializeIndexDeclaration } from './chunk-FQ7ZPOTZ.js';
9
9
  import { compareStrings, compareCodePoints } from './chunk-DRACN6XG.js';
10
- import { getTypeName } from './chunk-2HKIID5K.js';
11
- import { validateEdgeProps } from './chunk-O3USVVWS.js';
10
+ import { getTypeName } from './chunk-TKP5T34P.js';
11
+ import { validateEdgeProps } from './chunk-DK2S42XB.js';
12
12
  import { canonicalEqual, sortedReplacer } from './chunk-UR7W5YQK.js';
13
- import { withRecordedRelationsPrecondition, isMissingTableError } from './chunk-CUPJL6TS.js';
14
- import { isKnownKind } from './chunk-3V6D5DEC.js';
15
- import { nowIso, validateOptionalCanonicalIsoDate } from './chunk-GT7NEXSU.js';
16
- import { generateIndexDDL } from './chunk-2G6ZEGYO.js';
17
- import { SYSTEM_INDEX_DECLARATIONS, resolveSystemIndexTableName, systemIndexName, resolveSystemIndexNames, generateSystemIndexDDL } from './chunk-4XRP2N6B.js';
18
- import { NODE_META_KEYS, EDGE_META_KEYS } from './chunk-ZP2KPDNN.js';
13
+ import { withRecordedRelationsPrecondition, isMissingTableError } from './chunk-V34A6R5V.js';
14
+ import { isKnownKind } from './chunk-S4KQ5LV4.js';
15
+ import { nowIso, validateOptionalCanonicalIsoDate } from './chunk-KCO5EFJU.js';
16
+ import { generateIndexDDL } from './chunk-FL5UQRES.js';
17
+ import { SYSTEM_INDEX_DECLARATIONS, resolveSystemIndexTableName, systemIndexName, resolveSystemIndexNames, generateSystemIndexDDL } from './chunk-QLUXRWKL.js';
18
+ import { NODE_META_KEYS, EDGE_META_KEYS } from './chunk-FLEQ2HBK.js';
19
19
  import { sha256Hex, fnv1aBase36 } from './chunk-K34OPSJK.js';
20
20
  import { DEFAULT_PAGINATION_LIMIT, DEFAULT_STREAM_BATCH_SIZE, SQLITE_PATH_DELIMITER, PG_ARRAY_START, PG_ARRAY_END, PG_PATH_ELEMENT_SEPARATOR, MAX_PG_IDENTIFIER_LENGTH } from './chunk-2EBMPJBO.js';
21
- import { getDialect, assertVectorMinScore, vectorScoreExpression, vectorMinScoreCondition } from './chunk-42XYPKZU.js';
22
- import { isSqlPlaceholder, bindSqlValue, markAnnIndexScan, asCompiledSelectSql, isRawExecutable, annIndexScanTypes, sql, asCompiledRowsSql, markForceCustomPlan, asCompiledTemporaryStatementSql, asCompiledStatementSql } from './chunk-M4GYQF2H.js';
21
+ import { getDialect, assertVectorMinScore, vectorScoreExpression, vectorMinScoreCondition } from './chunk-PVUI6KGR.js';
22
+ import { isSqlPlaceholder, bindSqlValue, markAnnIndexScan, asCompiledSelectSql, isRawExecutable, renderSql, annIndexScanTypes, sql, asCompiledRowsSql, markForceCustomPlan, asCompiledTemporaryStatementSql, asCompiledStatementSql } from './chunk-6DCB664D.js';
23
23
  import { createSchemaIntrospector } from './chunk-D7PG5D5K.js';
24
24
  import { requireDefined, isPresent } from './chunk-QMQLUA66.js';
25
25
  import { getSearchableFields, resolveEmbeddingFields, resolveGraphVectorSlots, resolveDeclaredFulltextLanguage } from './chunk-PC2UBAUB.js';
26
- import { IncompatibleChangeError, RemoveCompileTimeKindError, KindHasReferentsError } from './chunk-EQOQOT55.js';
27
- import { validateProjectionField } from './chunk-4WYFRACU.js';
28
- import { ConfigurationError, UnsupportedPredicateError, ValidationError, KindNotFoundError, EndpointError, EagerMaterializationError, CompilerInvariantError, CardinalityError, EdgeNotFoundError, DatabaseOperationError, UnsupportedBackendCapabilityError, GraphAlgorithmConvergenceError, EndpointNotFoundError, InvalidEdgeWeightError } from './chunk-OYJSYDIH.js';
26
+ import { IncompatibleChangeError } from './chunk-4GUBTVPV.js';
27
+ import { validateProjectionField } from './chunk-42PYUGLS.js';
28
+ import { ConfigurationError, UnsupportedPredicateError, ValidationError, KindNotFoundError, EndpointError, EagerMaterializationError, CompilerInvariantError, CardinalityError, EdgeNotFoundError, DatabaseOperationError, UnsupportedBackendCapabilityError, GraphAlgorithmConvergenceError, EndpointNotFoundError, InvalidEdgeWeightError } from './chunk-4MB3AQAQ.js';
29
29
  import { jsonPointer, parseJsonPointer, resolveJsonPointer } from './chunk-G6Q5UM7U.js';
30
30
 
31
31
  // src/store/collection-surface.ts
@@ -38,6 +38,7 @@ var NODE_WRITE_NAMES = [
38
38
  "create",
39
39
  "createFromRecord",
40
40
  "update",
41
+ "updateWhere",
41
42
  "delete",
42
43
  "hardDelete",
43
44
  "upsertById",
@@ -170,7 +171,7 @@ function createCurrentOnlyRefusal(entity, method, coordinate) {
170
171
  function createBatchReadRefusal(entity, method, coordinate) {
171
172
  return () => {
172
173
  throw new ConfigurationError(
173
- `'${method}' is not available on a read-only StoreView (${describeCoordinate(coordinate)}). Batch endpoint reads resolve through store.batch(...), which a view does not expose \u2014 use the live Store's batch loader, or the view's findFrom / findTo / findByEndpoints for single reads.`,
174
+ `'${method}' is not available on a read-only StoreView (${describeCoordinate(coordinate)}). Batch endpoint reads resolve through store.batch(...), which a view does not expose \u2014 use the live Store's batch(...), or the view's findFrom / findTo / findByEndpoints for single reads.`,
174
175
  {
175
176
  code: "STORE_VIEW_BATCH_UNAVAILABLE",
176
177
  entity,
@@ -264,6 +265,8 @@ function pinnedEdgeCollection(live, coordinate) {
264
265
  count: (filter) => live.count(filter, temporal),
265
266
  findFrom: (from) => live.findFrom(from, temporal),
266
267
  findTo: (to) => live.findTo(to, temporal),
268
+ bulkFindFrom: (froms, options) => live.bulkFindFrom(froms, { ...options, ...temporal }),
269
+ bulkFindTo: (tos, options) => live.bulkFindTo(tos, { ...options, ...temporal }),
267
270
  findByEndpoints: (from, to, options) => live.findByEndpoints(from, to, options, temporal)
268
271
  };
269
272
  return readOnlyCollectionProxy(reads, live, coordinate, "edge");
@@ -568,6 +571,13 @@ var StoreView = class extends CoordinatePinnedView {
568
571
  );
569
572
  return this.#edges;
570
573
  }
574
+ /** Heterogeneous multi-kind edge read pinned to this view's coordinate. */
575
+ bulkFindEdgesFrom(params, options) {
576
+ return this.store.bulkFindEdgesFrom(params, {
577
+ ...options,
578
+ ...withValidCoordinate(this.coordinate)
579
+ });
580
+ }
571
581
  /**
572
582
  * Read-only search facade. On a `current` view the read methods
573
583
  * (`fulltext` / `vector` / `hybrid`) delegate to the live `store.search`,
@@ -4910,7 +4920,7 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
4910
4920
  ...vectorPredicate === void 0 ? {} : { vectorPredicate },
4911
4921
  ...fulltextPredicate === void 0 ? {} : { fulltextPredicate }
4912
4922
  });
4913
- const groupBy = buildStandardGroupBy({ ast, dialect });
4923
+ const groupBy2 = buildStandardGroupBy({ ast, dialect });
4914
4924
  const having2 = buildStandardHaving({ ast, ctx });
4915
4925
  const orderBy = selectStandardOrderBy({
4916
4926
  ast,
@@ -4927,7 +4937,7 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
4927
4937
  return emitStandardQuerySql({
4928
4938
  ctes,
4929
4939
  fromClause,
4930
- ...groupBy === void 0 ? {} : { groupBy },
4940
+ ...groupBy2 === void 0 ? {} : { groupBy: groupBy2 },
4931
4941
  ...having2 === void 0 ? {} : { having: having2 },
4932
4942
  ...orderBy === void 0 ? {} : { orderBy },
4933
4943
  ...limitOffset === void 0 ? {} : { limitOffset },
@@ -5859,7 +5869,8 @@ function buildQueryTemplate(ast, graphId, compileOptions, backend) {
5859
5869
  needsReadInstant: queryAstNeedsCurrentReadInstant(ast)
5860
5870
  });
5861
5871
  }
5862
- function fillTemplateParams(params, bindings, dialect) {
5872
+ var EMPTY_LIST_PARAMETERS = /* @__PURE__ */ new Map();
5873
+ function fillTemplateParams(params, bindings, dialect, listParameters = EMPTY_LIST_PARAMETERS) {
5863
5874
  let readInstant;
5864
5875
  return params.map((parameter) => {
5865
5876
  if (!isSqlPlaceholder(parameter)) return parameter;
@@ -5874,9 +5885,20 @@ function fillTemplateParams(params, bindings, dialect) {
5874
5885
  parameterName: name
5875
5886
  });
5876
5887
  }
5888
+ if (listParameters.has(name)) {
5889
+ assertListBinding(name, value);
5890
+ return getDialect(dialect).packListValue(value);
5891
+ }
5877
5892
  return bindSqlValue(value, dialect);
5878
5893
  });
5879
5894
  }
5895
+ function assertListBinding(name, value) {
5896
+ if (Array.isArray(value)) return;
5897
+ throw new ConfigurationError(
5898
+ `Parameter "${name}" must be an array for in()/notIn()`,
5899
+ { parameterName: name, actualType: typeof value }
5900
+ );
5901
+ }
5880
5902
 
5881
5903
  // src/query/builder/prepared-query.ts
5882
5904
  function toLiteral(value) {
@@ -5903,20 +5925,21 @@ function toLiteral(value) {
5903
5925
  { parameterName: "value", actualType: typeof value }
5904
5926
  );
5905
5927
  }
5928
+ function isListComparisonOp(op) {
5929
+ return op === "in" || op === "notIn";
5930
+ }
5931
+ function toLiteralList(parameterName, value) {
5932
+ assertListBinding(parameterName, value);
5933
+ return value.map((element) => toLiteral(element));
5934
+ }
5906
5935
  function substitutePredicateExpression(expr, bindings) {
5907
5936
  switch (expr.__type) {
5908
5937
  case "comparison": {
5909
5938
  if (isParameterRef(expr.right)) {
5910
- const value = bindings[expr.right.name];
5911
- if (value === void 0) {
5912
- throw new ConfigurationError(
5913
- `Missing binding for parameter "${expr.right.name}"`,
5914
- { parameterName: expr.right.name }
5915
- );
5916
- }
5939
+ const value = resolveBinding(bindings, expr.right.name);
5917
5940
  return {
5918
5941
  ...expr,
5919
- right: toLiteral(value)
5942
+ right: isListComparisonOp(expr.op) ? toLiteralList(expr.right.name, value) : toLiteral(value)
5920
5943
  };
5921
5944
  }
5922
5945
  return expr;
@@ -6029,6 +6052,7 @@ var PreparedQuery = class {
6029
6052
  #selectFn;
6030
6053
  #schemaIntrospector;
6031
6054
  #parameterMetadata;
6055
+ #selectiveExecutionDisabled = false;
6032
6056
  /**
6033
6057
  * Per-AST cached placeholder template, keyed by AST reference so the
6034
6058
  * optimized (`#ast`) and unoptimized (`#unoptimizedAst`) variants cache
@@ -6049,6 +6073,7 @@ var PreparedQuery = class {
6049
6073
  this.#selectFn = config.selectFn;
6050
6074
  this.#schemaIntrospector = config.schemaIntrospector;
6051
6075
  this.#parameterMetadata = collectParameterMetadata(this.#ast);
6076
+ assertDistinctParameterRoles(this.#parameterMetadata);
6052
6077
  }
6053
6078
  /**
6054
6079
  * The cached placeholder template for `ast`, or `undefined` when no fast
@@ -6082,7 +6107,7 @@ var PreparedQuery = class {
6082
6107
  */
6083
6108
  async execute(bindings = {}) {
6084
6109
  validateBindings(bindings, this.#parameterMetadata);
6085
- if (this.#selectiveFields !== void 0) {
6110
+ if (this.#selectiveFields !== void 0 && !this.#selectiveExecutionDisabled) {
6086
6111
  try {
6087
6112
  const rows = await this.#executeSelectiveRows(bindings);
6088
6113
  return mapSelectiveResults(
@@ -6093,7 +6118,11 @@ var PreparedQuery = class {
6093
6118
  this.#selectFn
6094
6119
  );
6095
6120
  } catch (error) {
6096
- if (error instanceof MissingSelectiveFieldError || error instanceof UnsupportedPredicateError) {
6121
+ if (error instanceof MissingSelectiveFieldError) {
6122
+ this.#selectiveExecutionDisabled = true;
6123
+ return this.#executeUnoptimized(bindings);
6124
+ }
6125
+ if (error instanceof UnsupportedPredicateError) {
6097
6126
  return this.#executeUnoptimized(bindings);
6098
6127
  }
6099
6128
  throw error;
@@ -6128,7 +6157,8 @@ var PreparedQuery = class {
6128
6157
  const params = fillTemplateParams(
6129
6158
  template.params,
6130
6159
  bindings,
6131
- this.#dialect
6160
+ this.#dialect,
6161
+ this.#parameterMetadata.listParameters
6132
6162
  );
6133
6163
  const rawRows2 = await executeRaw(
6134
6164
  template.sql,
@@ -6147,10 +6177,46 @@ var PreparedQuery = class {
6147
6177
  }
6148
6178
  };
6149
6179
  function collectParameterMetadata(ast) {
6150
- const names = /* @__PURE__ */ new Set();
6151
- const stringOpParameters = /* @__PURE__ */ new Set();
6152
- collectParameterMetadataFromAst(ast, names, stringOpParameters);
6153
- return { names, stringOpParameters };
6180
+ const accumulator = {
6181
+ names: /* @__PURE__ */ new Set(),
6182
+ stringOpParameters: /* @__PURE__ */ new Set(),
6183
+ listParameters: /* @__PURE__ */ new Map(),
6184
+ scalarParameters: /* @__PURE__ */ new Set(),
6185
+ conflictingElementTypes: /* @__PURE__ */ new Set()
6186
+ };
6187
+ collectParameterMetadataFromAst(ast, accumulator);
6188
+ return accumulator;
6189
+ }
6190
+ function assertDistinctParameterRoles(metadata) {
6191
+ if (metadata.conflictingElementTypes.size > 0) {
6192
+ const names = [...metadata.conflictingElementTypes];
6193
+ throw new ConfigurationError(
6194
+ `Parameter${names.length === 1 ? "" : "s"} ${names.map((name) => `"${name}"`).join(", ")} bound as an in()/notIn() list against fields of different types; one list cannot satisfy both`,
6195
+ { conflictingParameters: names }
6196
+ );
6197
+ }
6198
+ const conflicting = [...metadata.listParameters.keys()].filter(
6199
+ (name) => metadata.scalarParameters.has(name)
6200
+ );
6201
+ if (conflicting.length === 0) return;
6202
+ throw new ConfigurationError(
6203
+ `Parameter${conflicting.length === 1 ? "" : "s"} ${conflicting.map((name) => `"${name}"`).join(", ")} used both as an in()/notIn() list and as a scalar value`,
6204
+ { conflictingParameters: conflicting }
6205
+ );
6206
+ }
6207
+ function recordListElementType(accumulator, name, elementType) {
6208
+ if (!accumulator.listParameters.has(name)) {
6209
+ accumulator.listParameters.set(name, elementType);
6210
+ return;
6211
+ }
6212
+ const existing = accumulator.listParameters.get(name);
6213
+ if (existing === void 0) {
6214
+ accumulator.listParameters.set(name, elementType);
6215
+ return;
6216
+ }
6217
+ if (elementType !== void 0 && elementType !== existing) {
6218
+ accumulator.conflictingElementTypes.add(name);
6219
+ }
6154
6220
  }
6155
6221
  function hasParameterReferences(ast) {
6156
6222
  return collectParameterMetadata(ast).names.size > 0;
@@ -6161,63 +6227,58 @@ function composableQueryHasParameterReferences(query) {
6161
6227
  }
6162
6228
  return hasParameterReferences(query);
6163
6229
  }
6164
- function collectParameterMetadataFromAst(ast, names, stringOpParameters) {
6230
+ function collectParameterMetadataFromAst(ast, accumulator) {
6165
6231
  for (const predicate of ast.predicates) {
6166
- collectParameterMetadataFromExpression(
6167
- predicate.expression,
6168
- names,
6169
- stringOpParameters
6170
- );
6232
+ collectParameterMetadataFromExpression(predicate.expression, accumulator);
6171
6233
  }
6172
6234
  if (ast.having !== void 0) {
6173
- collectParameterMetadataFromExpression(
6174
- ast.having,
6175
- names,
6176
- stringOpParameters
6177
- );
6235
+ collectParameterMetadataFromExpression(ast.having, accumulator);
6178
6236
  }
6179
6237
  }
6180
- function collectParameterMetadataFromExpression(expression, names, stringOpParameters) {
6238
+ function collectParameterMetadataFromExpression(expression, accumulator) {
6181
6239
  switch (expression.__type) {
6182
6240
  case "comparison": {
6183
6241
  if (isParameterRef(expression.right)) {
6184
- names.add(expression.right.name);
6242
+ const name = expression.right.name;
6243
+ accumulator.names.add(name);
6244
+ if (isListComparisonOp(expression.op)) {
6245
+ recordListElementType(
6246
+ accumulator,
6247
+ name,
6248
+ resolveParameterValueType(expression.left, expression.right)
6249
+ );
6250
+ } else {
6251
+ accumulator.scalarParameters.add(name);
6252
+ }
6185
6253
  }
6186
6254
  return;
6187
6255
  }
6188
6256
  case "string_op": {
6189
6257
  if (isParameterRef(expression.pattern)) {
6190
- names.add(expression.pattern.name);
6191
- stringOpParameters.add(expression.pattern.name);
6258
+ accumulator.names.add(expression.pattern.name);
6259
+ accumulator.scalarParameters.add(expression.pattern.name);
6260
+ accumulator.stringOpParameters.add(expression.pattern.name);
6192
6261
  }
6193
6262
  return;
6194
6263
  }
6195
6264
  case "between": {
6196
- if (isParameterRef(expression.lower)) {
6197
- names.add(expression.lower.name);
6198
- }
6199
- if (isParameterRef(expression.upper)) {
6200
- names.add(expression.upper.name);
6265
+ for (const bound of [expression.lower, expression.upper]) {
6266
+ if (isParameterRef(bound)) {
6267
+ accumulator.names.add(bound.name);
6268
+ accumulator.scalarParameters.add(bound.name);
6269
+ }
6201
6270
  }
6202
6271
  return;
6203
6272
  }
6204
6273
  case "and":
6205
6274
  case "or": {
6206
6275
  for (const predicate of expression.predicates) {
6207
- collectParameterMetadataFromExpression(
6208
- predicate,
6209
- names,
6210
- stringOpParameters
6211
- );
6276
+ collectParameterMetadataFromExpression(predicate, accumulator);
6212
6277
  }
6213
6278
  return;
6214
6279
  }
6215
6280
  case "not": {
6216
- collectParameterMetadataFromExpression(
6217
- expression.predicate,
6218
- names,
6219
- stringOpParameters
6220
- );
6281
+ collectParameterMetadataFromExpression(expression.predicate, accumulator);
6221
6282
  return;
6222
6283
  }
6223
6284
  case "null_check":
@@ -6228,26 +6289,15 @@ function collectParameterMetadataFromExpression(expression, names, stringOpParam
6228
6289
  case "fulltext_match": {
6229
6290
  return;
6230
6291
  }
6231
- case "exists": {
6232
- collectParameterMetadataFromAst(
6233
- expression.subquery,
6234
- names,
6235
- stringOpParameters
6236
- );
6237
- return;
6238
- }
6292
+ case "exists":
6239
6293
  case "in_subquery": {
6240
- collectParameterMetadataFromAst(
6241
- expression.subquery,
6242
- names,
6243
- stringOpParameters
6244
- );
6294
+ collectParameterMetadataFromAst(expression.subquery, accumulator);
6245
6295
  return;
6246
6296
  }
6247
6297
  }
6248
6298
  }
6249
6299
  function validateBindings(bindings, metadata) {
6250
- const { names: expectedNames, stringOpParameters } = metadata;
6300
+ const { names: expectedNames, stringOpParameters, listParameters } = metadata;
6251
6301
  const missing = [];
6252
6302
  for (const name of expectedNames) {
6253
6303
  if (bindings[name] === void 0) {
@@ -6271,9 +6321,53 @@ function validateBindings(bindings, metadata) {
6271
6321
  }
6272
6322
  for (const name of expectedNames) {
6273
6323
  const value = bindings[name];
6324
+ if (listParameters.has(name)) {
6325
+ validateListBinding(name, value, listParameters.get(name));
6326
+ continue;
6327
+ }
6274
6328
  validateBindingValue(name, value, stringOpParameters.has(name));
6275
6329
  }
6276
6330
  }
6331
+ function validateListBinding(name, value, elementType) {
6332
+ assertListBinding(name, value);
6333
+ for (const element of value) {
6334
+ validateBindingValue(name, element, false);
6335
+ if (elementType === void 0) continue;
6336
+ if (matchesElementType(element, elementType)) continue;
6337
+ throw new ConfigurationError(
6338
+ `Parameter "${name}" is bound against a ${elementType} field, so every element must be a ${elementType}; got ${describeBindingType(element)}`,
6339
+ { parameterName: name, valueType: elementType }
6340
+ );
6341
+ }
6342
+ }
6343
+ function matchesElementType(value, elementType) {
6344
+ switch (elementType) {
6345
+ case "string": {
6346
+ return typeof value === "string";
6347
+ }
6348
+ case "number": {
6349
+ return typeof value === "number";
6350
+ }
6351
+ case "boolean": {
6352
+ return typeof value === "boolean";
6353
+ }
6354
+ case "date": {
6355
+ return value instanceof Date || typeof value === "string";
6356
+ }
6357
+ // No element cast is emitted for these, so there is no divergence to
6358
+ // prevent — `array`/`object` are rejected earlier, at compile time.
6359
+ case "array":
6360
+ case "object":
6361
+ case "embedding":
6362
+ case "unknown": {
6363
+ return true;
6364
+ }
6365
+ }
6366
+ }
6367
+ function describeBindingType(value) {
6368
+ if (value instanceof Date) return "date";
6369
+ return typeof value;
6370
+ }
6277
6371
  function validateBindingValue(name, value, isStringOp) {
6278
6372
  if (value === null) {
6279
6373
  throw new ConfigurationError(
@@ -6290,7 +6384,16 @@ function validateBindingValue(name, value, isStringOp) {
6290
6384
  }
6291
6385
  return;
6292
6386
  }
6293
- if (value instanceof Date || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
6387
+ if (typeof value === "number") {
6388
+ if (!Number.isFinite(value)) {
6389
+ throw new ConfigurationError(
6390
+ `Parameter "${name}" must be a finite number, got ${String(value)}`,
6391
+ { parameterName: name, actualType: "number" }
6392
+ );
6393
+ }
6394
+ return;
6395
+ }
6396
+ if (value instanceof Date || typeof value === "string" || typeof value === "boolean") {
6294
6397
  return;
6295
6398
  }
6296
6399
  throw new ConfigurationError(
@@ -6867,7 +6970,9 @@ var ExecutableQuery = class _ExecutableQuery {
6867
6970
  * validates the AST once (a malformed query fails fast, here, instead of on
6868
6971
  * first use); the prepared query then compiles once into a reusable template
6869
6972
  * and fills a fresh read instant per execute() — see PreparedQuery's class
6870
- * doc comment.
6973
+ * doc comment, which also covers the two cases that recompile per call
6974
+ * instead (no `executeRaw`, or a statement whose semantics ride on the SQL
6975
+ * object rather than its text).
6871
6976
  *
6872
6977
  * Use `param("name")` in predicates to create parameterized slots,
6873
6978
  * then pass values via `prepared.execute({ name: "value" })`.
@@ -7024,9 +7129,15 @@ var ExecutableQuery = class _ExecutableQuery {
7024
7129
  /**
7025
7130
  * Executes the query against a provided backend.
7026
7131
  *
7027
- * Used by `store.batch()` to run multiple queries over a single connection
7028
- * (e.g., within a transaction). The full compile → execute → transform
7029
- * pipeline runs identically to `execute()`, but against the given backend.
7132
+ * Used by `store.batch()` to run several queries in sequence against one
7133
+ * target — a transaction on backends that have them, the backend itself
7134
+ * otherwise. The full compile → execute → transform pipeline runs
7135
+ * identically to `execute()`, but against the given backend.
7136
+ *
7137
+ * Costs one statement, or two when the selective-field path runs and its
7138
+ * mapping then falls back: `#tryOptimizedExecutionOn` detects that only
7139
+ * after its statement has executed, and the caller re-runs the full fetch.
7140
+ * The fallback clears the fast path for this instance.
7030
7141
  */
7031
7142
  async executeOn(backend) {
7032
7143
  const ast = this.toAst();
@@ -7133,29 +7244,15 @@ var ExecutableQuery = class _ExecutableQuery {
7133
7244
  const hasOptionalTraversal = this.#state.traversals.some(
7134
7245
  (traversal) => traversal.optional
7135
7246
  );
7136
- const trackingRuns = hasOptionalTraversal ? [
7137
- {
7138
- mode: "truthy",
7139
- optionalTraversalAliases: "present"
7140
- },
7141
- {
7142
- mode: "falsy",
7143
- optionalTraversalAliases: "present"
7144
- },
7145
- {
7146
- mode: "falsy",
7147
- optionalTraversalAliases: "absent"
7148
- }
7149
- ] : [
7150
- {
7151
- mode: "truthy",
7152
- optionalTraversalAliases: "present"
7153
- },
7154
- {
7155
- mode: "falsy",
7156
- optionalTraversalAliases: "present"
7157
- }
7247
+ const presentTrackingRuns = [
7248
+ { mode: "truthy", optionalTraversalAliases: "present" },
7249
+ { mode: "max", optionalTraversalAliases: "present" },
7250
+ { mode: "falsy", optionalTraversalAliases: "present" }
7158
7251
  ];
7252
+ const trackingRuns = hasOptionalTraversal ? [
7253
+ ...presentTrackingRuns,
7254
+ { mode: "falsy", optionalTraversalAliases: "absent" }
7255
+ ] : presentTrackingRuns;
7159
7256
  for (const run of trackingRuns) {
7160
7257
  const trackingContext = createTrackingContext(this.#state, tracker, {
7161
7258
  schemaIntrospector: this.#config.schemaIntrospector,
@@ -9160,7 +9257,11 @@ var UnionableQuery = class _UnionableQuery {
9160
9257
  /**
9161
9258
  * Executes the combined query against a provided backend.
9162
9259
  *
9163
- * Used by `store.batch()` to run multiple queries over a single connection.
9260
+ * Used by `store.batch()` to run several queries in sequence against one
9261
+ * target — a transaction on backends that have them, the backend itself
9262
+ * otherwise. A set operation compiles to one statement; whether that target
9263
+ * is a shared connection is the adapter's business, not a function of
9264
+ * transaction support.
9164
9265
  */
9165
9266
  async executeOn(backend) {
9166
9267
  const ast = this.toAst();
@@ -10701,183 +10802,6 @@ function classifyUnique(kind, existing, next, recorders) {
10701
10802
  }
10702
10803
  }
10703
10804
 
10704
- // src/graph-extension/remove.ts
10705
- function planRemovals(graph, names) {
10706
- const document = graph.extension;
10707
- const namesSet = new Set(names);
10708
- if (namesSet.size === 0) {
10709
- return { document, removedNodeKinds: [], removedEdgeKinds: [] };
10710
- }
10711
- const { nodes: runtimeNodeNames, edges: runtimeEdgeNames } = extensionKindNames(document);
10712
- const compileTimeNodeNames = new Set(
10713
- Object.keys(graph.nodes).filter((name) => !runtimeNodeNames.has(name))
10714
- );
10715
- const compileTimeEdgeNames = new Set(
10716
- Object.keys(graph.edges).filter((name) => !runtimeEdgeNames.has(name))
10717
- );
10718
- for (const name of namesSet) {
10719
- if (compileTimeNodeNames.has(name)) {
10720
- throw new RemoveCompileTimeKindError(name, "node", graph.id);
10721
- }
10722
- if (compileTimeEdgeNames.has(name)) {
10723
- throw new RemoveCompileTimeKindError(name, "edge", graph.id);
10724
- }
10725
- }
10726
- const removedNodeKinds = [...namesSet].filter(
10727
- (name) => runtimeNodeNames.has(name)
10728
- );
10729
- const explicitlyRemovedEdgeKinds = [...namesSet].filter(
10730
- (name) => runtimeEdgeNames.has(name)
10731
- );
10732
- const referentsByKind = buildCompileTimeReferentIndex(
10733
- graph,
10734
- runtimeEdgeNames
10735
- );
10736
- for (const kindName of removedNodeKinds) {
10737
- const referents = referentsByKind.get(kindName);
10738
- if (referents !== void 0 && referents.length > 0) {
10739
- throw new KindHasReferentsError(kindName, referents, graph.id);
10740
- }
10741
- }
10742
- if (document === void 0) {
10743
- return {
10744
- document: void 0,
10745
- removedNodeKinds: [],
10746
- removedEdgeKinds: []
10747
- };
10748
- }
10749
- const removedNodeKindsSet = new Set(removedNodeKinds);
10750
- const explicitlyRemovedEdgeKindsSet = new Set(explicitlyRemovedEdgeKinds);
10751
- const cascadeEdges = /* @__PURE__ */ new Set();
10752
- const updatedEdges = {};
10753
- for (const [edgeName, edgeDocument] of Object.entries(document.edges ?? {})) {
10754
- if (explicitlyRemovedEdgeKindsSet.has(edgeName)) {
10755
- cascadeEdges.add(edgeName);
10756
- continue;
10757
- }
10758
- const newFrom = edgeDocument.from.filter(
10759
- (kind) => !removedNodeKindsSet.has(kind)
10760
- );
10761
- const newTo = edgeDocument.to.filter(
10762
- (kind) => !removedNodeKindsSet.has(kind)
10763
- );
10764
- if (newFrom.length === 0 || newTo.length === 0) {
10765
- cascadeEdges.add(edgeName);
10766
- continue;
10767
- }
10768
- updatedEdges[edgeName] = {
10769
- ...edgeDocument,
10770
- from: newFrom,
10771
- to: newTo
10772
- };
10773
- }
10774
- const updatedNodes = {};
10775
- for (const [nodeName, nodeDocument] of Object.entries(document.nodes ?? {})) {
10776
- if (removedNodeKindsSet.has(nodeName)) continue;
10777
- updatedNodes[nodeName] = nodeDocument;
10778
- }
10779
- const survivingOntology = (document.ontology ?? []).filter(
10780
- (relation) => !removedNodeKindsSet.has(relation.from) && !removedNodeKindsSet.has(relation.to)
10781
- );
10782
- const allRemovedKinds = /* @__PURE__ */ new Set([
10783
- ...removedNodeKindsSet,
10784
- ...cascadeEdges,
10785
- ...explicitlyRemovedEdgeKindsSet
10786
- ]);
10787
- const survivingIndexes = (document.indexes ?? []).filter(
10788
- (index) => !allRemovedKinds.has(index.kind)
10789
- );
10790
- const newDocument = Object.freeze({
10791
- ...document.version === void 0 ? {} : { version: document.version },
10792
- ...Object.keys(updatedNodes).length === 0 ? {} : { nodes: updatedNodes },
10793
- ...Object.keys(updatedEdges).length === 0 ? {} : { edges: updatedEdges },
10794
- ...survivingOntology.length === 0 ? {} : { ontology: survivingOntology },
10795
- ...survivingIndexes.length === 0 ? {} : { indexes: survivingIndexes }
10796
- });
10797
- return {
10798
- document: newDocument,
10799
- removedNodeKinds,
10800
- removedEdgeKinds: [
10801
- ...explicitlyRemovedEdgeKinds,
10802
- ...[...cascadeEdges].filter(
10803
- (name) => !explicitlyRemovedEdgeKindsSet.has(name)
10804
- )
10805
- ]
10806
- };
10807
- }
10808
- function stripGraphExtension(graph) {
10809
- const document = graph.extension;
10810
- if (document === void 0) return graph;
10811
- const { nodes: runtimeNodeNames, edges: runtimeEdgeNames } = extensionKindNames(document);
10812
- const runtimeOntologyKeys = buildGraphExtensionOntologyKeySet(document);
10813
- const compileNodes = {};
10814
- for (const [name, registration] of Object.entries(graph.nodes)) {
10815
- if (runtimeNodeNames.has(name)) continue;
10816
- compileNodes[name] = registration;
10817
- }
10818
- const compileEdges = {};
10819
- for (const [name, registration] of Object.entries(graph.edges)) {
10820
- if (runtimeEdgeNames.has(name)) continue;
10821
- compileEdges[name] = registration;
10822
- }
10823
- const compileOntology = graph.ontology.filter(
10824
- (relation) => !runtimeOntologyKeys.has(compileTimeOntologyKey(relation))
10825
- );
10826
- const compileIndexes = (graph.indexes ?? []).filter(
10827
- (index) => index.origin !== "runtime"
10828
- );
10829
- return Object.freeze({
10830
- ...graph,
10831
- nodes: compileNodes,
10832
- edges: compileEdges,
10833
- ontology: compileOntology,
10834
- indexes: compileIndexes.length === 0 ? void 0 : compileIndexes,
10835
- extension: void 0
10836
- });
10837
- }
10838
- function buildCompileTimeReferentIndex(graph, runtimeEdgeNames) {
10839
- const index = /* @__PURE__ */ new Map();
10840
- const append = (kindName, referent) => {
10841
- const existing = index.get(kindName);
10842
- if (existing === void 0) index.set(kindName, [referent]);
10843
- else existing.push(referent);
10844
- };
10845
- for (const [edgeName, registration] of Object.entries(graph.edges)) {
10846
- if (runtimeEdgeNames.has(edgeName)) continue;
10847
- const reg = registration;
10848
- const referent = {
10849
- type: "compile-time-edge",
10850
- name: edgeName
10851
- };
10852
- const seen = /* @__PURE__ */ new Set();
10853
- for (const endpoint of reg.from ?? []) {
10854
- if (seen.has(endpoint.kind)) continue;
10855
- seen.add(endpoint.kind);
10856
- append(endpoint.kind, referent);
10857
- }
10858
- for (const endpoint of reg.to ?? []) {
10859
- if (seen.has(endpoint.kind)) continue;
10860
- seen.add(endpoint.kind);
10861
- append(endpoint.kind, referent);
10862
- }
10863
- }
10864
- const runtimeOntologyKeys = buildGraphExtensionOntologyKeySet(
10865
- graph.extension
10866
- );
10867
- for (const relation of graph.ontology) {
10868
- if (runtimeOntologyKeys.has(compileTimeOntologyKey(relation))) continue;
10869
- const fromName = getTypeName(relation.from);
10870
- const toName = getTypeName(relation.to);
10871
- const referent = {
10872
- type: "compile-time-ontology",
10873
- name: `${relation.metaEdge.name}(${fromName}, ${toName})`
10874
- };
10875
- append(fromName, referent);
10876
- if (toName !== fromName) append(toName, referent);
10877
- }
10878
- return index;
10879
- }
10880
-
10881
10805
  // src/store/algorithms/context.ts
10882
10806
  var DEFAULT_ALGORITHM_MAX_HOPS = 10;
10883
10807
  var DEFAULT_NEIGHBOR_DEPTH = 1;
@@ -13530,6 +13454,36 @@ function buildUpdateEdgeInput(id, props, options) {
13530
13454
  if (options?.validTo !== void 0) input.validTo = options.validTo;
13531
13455
  return input;
13532
13456
  }
13457
+ function endpointKey(endpointKind, id) {
13458
+ return `${endpointKind}\0${id}`;
13459
+ }
13460
+ function groupEndpointIdsByKind(references) {
13461
+ const referencesByKind = groupBy(references, (ref) => ref.kind);
13462
+ return new Map(
13463
+ [...referencesByKind].map(([endpointKind, group]) => [
13464
+ endpointKind,
13465
+ group.map((ref) => ref.id)
13466
+ ])
13467
+ );
13468
+ }
13469
+ function assertLimitPerInput(kind, limitPerInput) {
13470
+ if (limitPerInput === void 0) return;
13471
+ if (Number.isInteger(limitPerInput) && limitPerInput > 0) return;
13472
+ throw new ValidationError(
13473
+ "bulk endpoint reads require limitPerInput to be a positive integer",
13474
+ {
13475
+ entityType: "edge",
13476
+ kind,
13477
+ issues: [
13478
+ {
13479
+ path: "limitPerInput",
13480
+ message: `Expected a positive integer, received ${String(limitPerInput)}`,
13481
+ code: "invalid_value"
13482
+ }
13483
+ ]
13484
+ }
13485
+ );
13486
+ }
13533
13487
  function mapBulkEdgeInputs(kind, items) {
13534
13488
  return items.map(
13535
13489
  (item) => buildCreateEdgeInput(kind, item.from, item.to, item.props ?? {}, item)
@@ -13552,29 +13506,74 @@ function createEdgeCollection(config) {
13552
13506
  temporalRowMatcher
13553
13507
  } = config;
13554
13508
  const mapRows = (rows) => rows.map((row) => narrowEdge(rowToEdge2(row)));
13555
- function buildEndpointFindParams(endpoint, options) {
13556
- return {
13557
- graphId,
13558
- kind,
13559
- ...endpoint,
13560
- ...resolveTemporalReadParams(options, defaultTemporalMode)
13561
- };
13509
+ function buildEndpointFindParams(endpoint, temporal) {
13510
+ return { graphId, kind, ...endpoint, ...temporal };
13562
13511
  }
13563
13512
  async function findEdgesFrom(from, target, options) {
13564
13513
  const rows = await target.findEdgesByKind(
13565
13514
  buildEndpointFindParams(
13566
13515
  { fromKind: from.kind, fromId: from.id },
13567
- options
13516
+ resolveTemporalReadParams(options, defaultTemporalMode)
13568
13517
  )
13569
13518
  );
13570
13519
  return mapRows(rows);
13571
13520
  }
13572
13521
  async function findEdgesTo(to, target, options) {
13573
13522
  const rows = await target.findEdgesByKind(
13574
- buildEndpointFindParams({ toKind: to.kind, toId: to.id }, options)
13523
+ buildEndpointFindParams(
13524
+ { toKind: to.kind, toId: to.id },
13525
+ resolveTemporalReadParams(options, defaultTemporalMode)
13526
+ )
13575
13527
  );
13576
13528
  return mapRows(rows);
13577
13529
  }
13530
+ async function findEdgesByEndpointSet(side, references, options) {
13531
+ if (references.length === 0) return [];
13532
+ const method = side === "from" ? "bulkFindFrom" : "bulkFindTo";
13533
+ const readEndpointSet = backend.findEdgesByEndpointSet;
13534
+ if (readEndpointSet === void 0) {
13535
+ throw new ConfigurationError(
13536
+ `store.edges.${kind}.${method}() requires a backend that can read a set of endpoints with set-oriented statements, and this backend does not implement findEdgesByEndpointSet.`,
13537
+ {
13538
+ backend: backend.dialect,
13539
+ capability: "findEdgesByEndpointSet",
13540
+ kind,
13541
+ operation: method
13542
+ },
13543
+ {
13544
+ suggestion: `Falling back to one findFrom/findTo per endpoint is deliberately NOT done here: a caller reaching for a bulk endpoint read is asking for a set-oriented read, and silently issuing N singleton statements is the cost surprise this method exists to avoid. Loop over findFrom/findTo explicitly if that trade is acceptable.`
13545
+ }
13546
+ );
13547
+ }
13548
+ const limitPerInput = options?.limitPerInput;
13549
+ assertLimitPerInput(kind, limitPerInput);
13550
+ const temporal = resolveTemporalReadParams(options, defaultTemporalMode);
13551
+ const limitPerEndpoint = limitPerInput !== void 0 && backend.capabilities.windowFunctions ? { limitPerEndpoint: limitPerInput } : {};
13552
+ const edgesByEndpoint = /* @__PURE__ */ new Map();
13553
+ for (const [endpointKind, endpointIds] of groupEndpointIdsByKind(
13554
+ references
13555
+ )) {
13556
+ const rows = await readEndpointSet({
13557
+ graphId,
13558
+ kind,
13559
+ side,
13560
+ endpointKind,
13561
+ endpointIds,
13562
+ ...limitPerEndpoint,
13563
+ ...temporal
13564
+ });
13565
+ for (const edge of mapRows(rows)) {
13566
+ const key = side === "from" ? endpointKey(edge.fromKind, edge.fromId) : endpointKey(edge.toKind, edge.toId);
13567
+ const bucket = edgesByEndpoint.get(key);
13568
+ if (bucket === void 0) edgesByEndpoint.set(key, [edge]);
13569
+ else bucket.push(edge);
13570
+ }
13571
+ }
13572
+ return references.map((ref) => {
13573
+ const bucket = edgesByEndpoint.get(endpointKey(ref.kind, ref.id)) ?? [];
13574
+ return limitPerInput === void 0 ? [...bucket] : bucket.slice(0, limitPerInput);
13575
+ });
13576
+ }
13578
13577
  function buildFindByEndpointsOptions(options, temporal) {
13579
13578
  const result = { ...resolveTemporalReadParams(temporal, defaultTemporalMode) };
13580
13579
  if (options?.matchOn !== void 0)
@@ -13622,6 +13621,12 @@ function createEdgeCollection(config) {
13622
13621
  async findTo(to, options) {
13623
13622
  return findEdgesTo(to, backend, options);
13624
13623
  },
13624
+ async bulkFindFrom(froms, options) {
13625
+ return findEdgesByEndpointSet("from", froms, options);
13626
+ },
13627
+ async bulkFindTo(tos, options) {
13628
+ return findEdgesByEndpointSet("to", tos, options);
13629
+ },
13625
13630
  batchFindFrom(from, options) {
13626
13631
  return { executeOn: (target) => findEdgesFrom(from, target, options) };
13627
13632
  },
@@ -13914,6 +13919,35 @@ function narrowNode(node) {
13914
13919
  function narrowNodes(nodes) {
13915
13920
  return nodes;
13916
13921
  }
13922
+ function createFieldMember(accessor) {
13923
+ const selectField = (name) => accessor.field(name);
13924
+ return new Proxy(selectField, {
13925
+ get(target, property, receiver) {
13926
+ if (Reflect.has(target, property)) {
13927
+ const ownProperty = Reflect.get(target, property, receiver);
13928
+ return ownProperty;
13929
+ }
13930
+ return accessor.field("field")[property];
13931
+ }
13932
+ });
13933
+ }
13934
+ function evaluateNodePredicate(accessor, predicate) {
13935
+ const collectionAccessor = new Proxy(
13936
+ {},
13937
+ {
13938
+ get(_target, property) {
13939
+ if (typeof property === "symbol") return;
13940
+ if (property === "then" || property === "toJSON") return;
13941
+ if (property === "id" || property === "kind" || property === "$fulltext") {
13942
+ return accessor[property];
13943
+ }
13944
+ if (property === "field") return createFieldMember(accessor);
13945
+ return accessor.field(property);
13946
+ }
13947
+ }
13948
+ );
13949
+ return predicate(collectionAccessor);
13950
+ }
13917
13951
  function buildCreateInput(kind, props, options) {
13918
13952
  const input = { kind, props };
13919
13953
  if (options?.id !== void 0) input.id = options.id;
@@ -13940,6 +13974,7 @@ function createNodeCollection(config) {
13940
13974
  executeCreateNoReturnBatch: executeNodeCreateNoReturnBatch2,
13941
13975
  executeCreateBatch: executeNodeCreateBatch2,
13942
13976
  executeUpdate: executeNodeUpdate2,
13977
+ executeUpdateWhere: executeNodeUpdateWhere2,
13943
13978
  executeUpsertUpdate: executeNodeUpsertUpdate2,
13944
13979
  executeDelete: executeNodeDelete2,
13945
13980
  executeHardDelete: executeNodeHardDelete2,
@@ -13986,6 +14021,85 @@ function createNodeCollection(config) {
13986
14021
  );
13987
14022
  return narrowNode(result);
13988
14023
  },
14024
+ async updateWhere(params) {
14025
+ if (createQuery === void 0) {
14026
+ throw new ConfigurationError(
14027
+ `store.nodes.${kind}.updateWhere() requires a query-capable store`,
14028
+ { kind, operation: "updateWhere" }
14029
+ );
14030
+ }
14031
+ const exists = params.exists ?? [];
14032
+ if (params.where === void 0 && exists.length === 0 && !params.all) {
14033
+ throw new ConfigurationError(
14034
+ `store.nodes.${kind}.updateWhere() requires where, exists, or explicit all: true`,
14035
+ { kind, operation: "updateWhere" }
14036
+ );
14037
+ }
14038
+ const rootAlias = "update_candidate";
14039
+ const readInstant = nowIso();
14040
+ let base = createQuery().fromDynamic(kind, rootAlias).temporal("asOf", readInstant);
14041
+ const where = params.where;
14042
+ if (where !== void 0) {
14043
+ base = base.whereNode(
14044
+ rootAlias,
14045
+ (accessor) => evaluateNodePredicate(accessor, where)
14046
+ );
14047
+ }
14048
+ const candidateIdColumn = `${rootAlias}_id`;
14049
+ const compiledBranches = [];
14050
+ for (const [index, relation] of exists.entries()) {
14051
+ const edgeAlias = `update_edge_${index}`;
14052
+ const relatedAlias = `update_related_${index}`;
14053
+ const relationRoot = createQuery().fromDynamic(kind, rootAlias).temporal("asOf", readInstant);
14054
+ let traversal = relationRoot.traverseDynamic(
14055
+ relation.edgeKind,
14056
+ edgeAlias,
14057
+ {
14058
+ direction: relation.direction,
14059
+ expand: "none"
14060
+ }
14061
+ );
14062
+ if (relation.whereEdge !== void 0) {
14063
+ traversal = traversal.whereEdge(edgeAlias, relation.whereEdge);
14064
+ }
14065
+ let related = traversal.toDynamic(relation.relatedKind, relatedAlias);
14066
+ if (relation.whereRelated !== void 0) {
14067
+ related = related.whereNode(relatedAlias, relation.whereRelated);
14068
+ }
14069
+ compiledBranches.push(
14070
+ related.select(
14071
+ (ctx) => ctx[rootAlias]?.id
14072
+ ).compile()
14073
+ );
14074
+ }
14075
+ compiledBranches.unshift(
14076
+ base.select((ctx) => ctx[rootAlias]?.id).compile()
14077
+ );
14078
+ const projectCandidateId = (branch, index) => sql`
14079
+ SELECT ${sql.identifier(candidateIdColumn)}
14080
+ FROM (${branch}) AS ${sql.identifier(`update_branch_${index}`)}
14081
+ `;
14082
+ let combinedCandidates = projectCandidateId(
14083
+ requireDefined(compiledBranches[0]),
14084
+ 0
14085
+ );
14086
+ for (let index = 1; index < compiledBranches.length; index++) {
14087
+ combinedCandidates = sql`${combinedCandidates} INTERSECT ${projectCandidateId(
14088
+ requireDefined(compiledBranches[index]),
14089
+ index
14090
+ )}`;
14091
+ }
14092
+ const compiledCandidates = asCompiledSelectSql(combinedCandidates);
14093
+ const result = await executeNodeUpdateWhere2(
14094
+ kind,
14095
+ params.patch,
14096
+ compiledCandidates,
14097
+ candidateIdColumn,
14098
+ backend
14099
+ );
14100
+ await config.maybeRefreshStatisticsAfterBulk?.(result.affectedCount);
14101
+ return result;
14102
+ },
13989
14103
  async delete(id) {
13990
14104
  await executeNodeDelete2(kind, id, backend);
13991
14105
  },
@@ -14326,6 +14440,8 @@ var HISTORY_STORE_BACKEND_KEYS = [
14326
14440
  "claimIndexMaterialization",
14327
14441
  "close",
14328
14442
  "commitSchemaVersion",
14443
+ "commitSchemaVersionIfKindsEmpty",
14444
+ "lockSchemaVersionForWrite",
14329
14445
  "compileSql",
14330
14446
  "countEdgesByKind",
14331
14447
  "countEdgesFrom",
@@ -14334,10 +14450,12 @@ var HISTORY_STORE_BACKEND_KEYS = [
14334
14450
  "deleteEdge",
14335
14451
  "deleteEdgesBatch",
14336
14452
  "deleteEmbedding",
14453
+ "deleteEmbeddingBatch",
14337
14454
  "deleteFulltext",
14338
14455
  "deleteFulltextBatch",
14339
14456
  "deleteNode",
14340
14457
  "deleteUnique",
14458
+ "hardDeleteUniquesByNodeIds",
14341
14459
  "deleteVectorSlotContribution",
14342
14460
  "dialect",
14343
14461
  "dropVectorIndex",
@@ -14354,6 +14472,8 @@ var HISTORY_STORE_BACKEND_KEYS = [
14354
14472
  "execute",
14355
14473
  "executeTemporaryStatement",
14356
14474
  "findEdgesByKind",
14475
+ "findEdgesByEndpointSet",
14476
+ "findEdgesByHeterogeneousEndpointSet",
14357
14477
  "findEdgesConnectedTo",
14358
14478
  "findNodesByKind",
14359
14479
  "fulltextSearch",
@@ -14373,6 +14493,7 @@ var HISTORY_STORE_BACKEND_KEYS = [
14373
14493
  "hardDeleteEdge",
14374
14494
  "hardDeleteEdgesBatch",
14375
14495
  "hardDeleteNode",
14496
+ "hardDeleteUniquesByNodeIds",
14376
14497
  "hybridSearch",
14377
14498
  "insertEdge",
14378
14499
  "insertEdgeNoReturn",
@@ -14394,12 +14515,14 @@ var HISTORY_STORE_BACKEND_KEYS = [
14394
14515
  "tableNames",
14395
14516
  "updateEdge",
14396
14517
  "updateNode",
14518
+ "updateNodeSet",
14397
14519
  "upsertEmbedding",
14398
14520
  "upsertEmbeddingBatch",
14399
14521
  "upsertFulltext",
14400
14522
  "upsertFulltextBatch",
14401
14523
  "vectorSearch",
14402
- "vectorStrategy"
14524
+ "vectorStrategy",
14525
+ "verifyContributions"
14403
14526
  ];
14404
14527
  function createHistoryStoreBackendProjection(backend) {
14405
14528
  return Object.freeze(
@@ -14501,18 +14624,6 @@ async function runBucketedMaterialization(items, options, bucketKey, runOne) {
14501
14624
  );
14502
14625
  return results;
14503
14626
  }
14504
- async function runMaterialization(items, options, runOne) {
14505
- if (options.stopOnError === true) {
14506
- const results = [];
14507
- for (const item of items) {
14508
- const entry2 = await runOne(item);
14509
- results.push(entry2);
14510
- if (entry2.status === "failed") break;
14511
- }
14512
- return results;
14513
- }
14514
- return Promise.all(items.map((item) => runOne(item)));
14515
- }
14516
14627
 
14517
14628
  // src/store/materialize-indexes.ts
14518
14629
  var CLAIM_LEASE_MS = 15 * 6e4;
@@ -15216,21 +15327,38 @@ function buildPendingKindRemoval(args) {
15216
15327
  }
15217
15328
  async function materializeRemovals(context, options = {}) {
15218
15329
  const { backend, graphId } = context;
15219
- if (backend.executeDdl === void 0 || backend.recordKindRemoval === void 0 || backend.getPendingKindRemovals === void 0) {
15330
+ if (backend.recordKindRemoval === void 0 || backend.getPendingKindRemovals === void 0) {
15220
15331
  throw new ConfigurationError(
15221
- "store.materializeRemovals() requires a backend with kind-removal primitives (executeDdl, recordKindRemoval, getPendingKindRemovals). The bundled SQLite and Postgres backends provide them.",
15332
+ "store.materializeRemovals() requires a backend with kind-removal primitives (recordKindRemoval, getPendingKindRemovals). The bundled SQLite and Postgres backends provide them.",
15222
15333
  { code: "MATERIALIZE_REMOVALS_BACKEND_UNSUPPORTED" }
15223
15334
  );
15224
15335
  }
15225
15336
  await ensureFocusedStatusTable(backend, backend.ensureKindRemovalsTable);
15226
15337
  await reconcilePendingRemovals(context);
15227
- const reclaimedVectorFields = await reclaimRemovedVectorFieldTables(context);
15338
+ const activeRow = await backend.getActiveSchema(graphId);
15339
+ const activeSchema = activeRow === void 0 ? void 0 : parseSerializedSchema(activeRow.schema_doc);
15340
+ const reclaimedVectorFields = await reclaimRemovedVectorFieldTables(
15341
+ context,
15342
+ activeRow
15343
+ );
15228
15344
  const pending = await backend.getPendingKindRemovals(graphId);
15345
+ const liveKinds = liveKindNamesFrom(activeSchema);
15229
15346
  const kindFilter = options.kinds === void 0 ? void 0 : new Set(options.kinds);
15230
- const candidates = pending.filter(
15231
- (row) => kindFilter === void 0 ? true : kindFilter.has(row.kindName)
15347
+ const selected = pending.filter(
15348
+ (row) => kindFilter === void 0 || kindFilter.has(row.kindName)
15349
+ );
15350
+ const candidates = selected.filter(
15351
+ (row) => !liveKinds[row.entity].has(row.kindName)
15232
15352
  );
15233
- if (candidates.length === 0) return { results: [], reclaimedVectorFields };
15353
+ const skipped = selected.filter((row) => liveKinds[row.entity].has(row.kindName)).map((row) => ({
15354
+ kind: row.kindName,
15355
+ entity: row.entity,
15356
+ status: "skipped",
15357
+ reason: "kind-is-live"
15358
+ }));
15359
+ if (candidates.length === 0) {
15360
+ return { results: skipped, reclaimedVectorFields };
15361
+ }
15234
15362
  const tableNames = backend.tableNames;
15235
15363
  const nodesTable = tableNames?.nodes ?? "typegraph_nodes";
15236
15364
  const edgesTable = tableNames?.edges ?? "typegraph_edges";
@@ -15247,14 +15375,13 @@ async function materializeRemovals(context, options = {}) {
15247
15375
  captureRecordedRemovals,
15248
15376
  recordedSchema: captureRecordedRemovals ? context.recordedSchema ?? createSqlSchema(backend.tableNames) : void 0
15249
15377
  };
15250
- return {
15251
- results: await runMaterialization(
15252
- candidates,
15253
- options,
15254
- (removal) => materializeOne2(removal, ctx)
15255
- ),
15256
- reclaimedVectorFields
15257
- };
15378
+ const materialized = [];
15379
+ for (const candidate of candidates) {
15380
+ const entry2 = await materializeOne2(candidate, ctx);
15381
+ materialized.push(entry2);
15382
+ if (options.stopOnError === true && entry2.status === "failed") break;
15383
+ }
15384
+ return { results: [...materialized, ...skipped], reclaimedVectorFields };
15258
15385
  }
15259
15386
  async function reconcilePendingRemovals(context) {
15260
15387
  const { backend, graphId } = context;
@@ -15322,14 +15449,49 @@ async function reconcilePendingRemovals(context) {
15322
15449
  await backend.setReconciliationMarker(graphId, activeRow.version);
15323
15450
  }
15324
15451
  }
15452
+ function liveKindNamesFrom(schema) {
15453
+ if (schema === void 0) {
15454
+ return { node: /* @__PURE__ */ new Set(), edge: /* @__PURE__ */ new Set() };
15455
+ }
15456
+ return {
15457
+ node: new Set(Object.keys(schema.nodes)),
15458
+ edge: new Set(Object.keys(schema.edges))
15459
+ };
15460
+ }
15325
15461
  function kindRemovalKey(entity, kindName, version) {
15326
15462
  return `${entity}|${kindName}|${version}`;
15327
15463
  }
15328
15464
  async function materializeOne2(row, ctx) {
15329
15465
  const recordKindRemoval = requireDefined(ctx.backend.recordKindRemoval);
15466
+ const schemaWriteTransaction = ctx.backend.schemaWriteTransaction;
15467
+ if (schemaWriteTransaction === void 0) {
15468
+ throw new ConfigurationError(
15469
+ "store.materializeRemovals() requires a backend that can hold the schema-write lock across the live-kind check and cleanup.",
15470
+ { code: "MATERIALIZE_REMOVALS_SCHEMA_FENCE_UNSUPPORTED" }
15471
+ );
15472
+ }
15330
15473
  try {
15331
- await closeRecordedAndDeleteLiveRows(ctx, row);
15332
- await Promise.all(buildEmbeddingTableCleanup(ctx, row));
15474
+ const outcome = await schemaWriteTransaction(
15475
+ ctx.graphId,
15476
+ async (target) => {
15477
+ const activeRow = await target.getActiveSchema(ctx.graphId);
15478
+ const activeSchema = activeRow === void 0 ? void 0 : parseSerializedSchema(activeRow.schema_doc);
15479
+ if (liveKindNamesFrom(activeSchema)[row.entity].has(row.kindName)) {
15480
+ return "skipped";
15481
+ }
15482
+ await closeRecordedAndDeleteLiveRows(ctx, row, target);
15483
+ await dropEmbeddingTableStorage(ctx, row, target);
15484
+ return "removed";
15485
+ }
15486
+ );
15487
+ if (outcome === "skipped") {
15488
+ return {
15489
+ kind: row.kindName,
15490
+ entity: row.entity,
15491
+ status: "skipped",
15492
+ reason: "kind-is-live"
15493
+ };
15494
+ }
15333
15495
  const removedAt = nowIso();
15334
15496
  await recordKindRemoval({
15335
15497
  graphId: ctx.graphId,
@@ -15364,28 +15526,33 @@ async function materializeOne2(row, ctx) {
15364
15526
  };
15365
15527
  }
15366
15528
  }
15367
- async function closeRecordedAndDeleteLiveRows(ctx, row) {
15529
+ async function closeRecordedAndDeleteLiveRows(ctx, row, target) {
15368
15530
  const deleteStatements = buildRemovedKindLiveDeleteStatements(ctx, row);
15369
15531
  if (!ctx.captureRecordedRemovals || ctx.recordedSchema === void 0) {
15370
- await executeDeleteStatements(ctx.backend, deleteStatements);
15532
+ await executeDeleteStatements(target, deleteStatements);
15371
15533
  return;
15372
15534
  }
15373
15535
  const recordedSchema = ctx.recordedSchema;
15374
- try {
15375
- await ctx.backend.transaction(async (target) => {
15376
- await closeRecordedHardDeletedKind(
15377
- target,
15378
- recordedSchema,
15379
- ctx.graphId,
15380
- { entity: row.entity, kind: row.kindName },
15381
- false
15382
- );
15383
- await executeDeleteStatements(target, deleteStatements);
15384
- });
15385
- } catch (error) {
15386
- if (!isMissingTableError(error)) throw error;
15387
- await executeDeleteStatements(ctx.backend, deleteStatements);
15536
+ const requiredRecordedTables = [
15537
+ recordedSchema.tables.recordedClock,
15538
+ recordedSchema.tables.recordedEdges,
15539
+ ...row.entity === "node" ? [recordedSchema.tables.recordedNodes] : []
15540
+ ];
15541
+ const recordedTablesExist = await Promise.all(
15542
+ requiredRecordedTables.map((tableName) => target.tableExists(tableName))
15543
+ );
15544
+ if (recordedTablesExist.some((exists) => !exists)) {
15545
+ await executeDeleteStatements(target, deleteStatements);
15546
+ return;
15388
15547
  }
15548
+ await closeRecordedHardDeletedKind(
15549
+ target,
15550
+ recordedSchema,
15551
+ ctx.graphId,
15552
+ { entity: row.entity, kind: row.kindName },
15553
+ false
15554
+ );
15555
+ await executeDeleteStatements(target, deleteStatements);
15389
15556
  }
15390
15557
  function buildRemovedKindLiveDeleteStatements(ctx, row) {
15391
15558
  const graphLit = literal(ctx.graphId);
@@ -15403,41 +15570,22 @@ function buildRemovedKindLiveDeleteStatements(ctx, row) {
15403
15570
  ];
15404
15571
  }
15405
15572
  async function executeDeleteStatements(target, statements) {
15406
- if (target.executeStatement !== void 0) {
15407
- await Promise.all(
15408
- statements.map(
15409
- (statement) => requireDefined(target.executeStatement)(
15410
- asCompiledStatementSql(sql.raw(statement))
15411
- )
15412
- )
15413
- );
15414
- return;
15415
- }
15416
- if (target.executeDdl === void 0) {
15417
- throw new ConfigurationError(
15418
- "store.materializeRemovals() requires a backend that can execute cleanup statements.",
15419
- { code: "MATERIALIZE_REMOVALS_BACKEND_UNSUPPORTED" }
15420
- );
15573
+ for (const statement of statements) {
15574
+ await target.executeStatement(asCompiledStatementSql(sql.raw(statement)));
15421
15575
  }
15422
- await Promise.all(
15423
- statements.map((statement) => requireDefined(target.executeDdl)(statement))
15424
- );
15425
15576
  }
15426
- function buildEmbeddingTableCleanup(ctx, row) {
15577
+ async function dropEmbeddingTableStorage(ctx, row, target) {
15427
15578
  const vectorStrategy = ctx.backend.vectorStrategy;
15428
- if (vectorStrategy === void 0) return [];
15429
- const executeDdl = requireDefined(ctx.backend.executeDdl);
15430
- const cleanup = (async () => {
15431
- const slots = await resolveRemovedKindEmbeddingSlots(ctx.backend, row);
15432
- await Promise.all(
15433
- slots.map(
15434
- (slot) => dropVectorSlotStorage(ctx.backend, vectorStrategy, executeDdl, slot)
15435
- )
15436
- );
15437
- })();
15438
- return [cleanup];
15579
+ if (vectorStrategy === void 0) return;
15580
+ const executeDdl = target.executeSchemaDdl;
15581
+ const deleteContribution = target.deleteSchemaVectorSlotContribution;
15582
+ const slots = await resolveRemovedKindEmbeddingSlots(target, row);
15583
+ for (const slot of slots) {
15584
+ await dropVectorSlotStorage(vectorStrategy, executeDdl, slot);
15585
+ await deleteContribution(slot);
15586
+ }
15439
15587
  }
15440
- async function dropVectorSlotStorage(backend, strategy, executeDdl, slot) {
15588
+ async function dropVectorSlotStorage(strategy, executeDdl, slot) {
15441
15589
  try {
15442
15590
  for (const ddl of strategy.buildDropStorage(slot)) {
15443
15591
  await executeDdl(ddl);
@@ -15445,7 +15593,6 @@ async function dropVectorSlotStorage(backend, strategy, executeDdl, slot) {
15445
15593
  } catch (error) {
15446
15594
  if (!isMissingTableError(error)) throw error;
15447
15595
  }
15448
- await backend.deleteVectorSlotContribution?.(slot);
15449
15596
  }
15450
15597
  async function resolveRemovedKindEmbeddingSlots(backend, row) {
15451
15598
  const priorVersion = row.schemaVersion - 1;
@@ -15471,26 +15618,26 @@ async function resolveRemovedKindEmbeddingSlots(backend, row) {
15471
15618
  function vectorFieldKey(kind, fieldPath) {
15472
15619
  return `${kind}\0${fieldPath}`;
15473
15620
  }
15474
- async function reclaimRemovedVectorFieldTables(context) {
15621
+ function vectorFieldKeysFrom(schema) {
15622
+ const keys = /* @__PURE__ */ new Set();
15623
+ for (const declaration of schema.indexes ?? []) {
15624
+ if (declaration.entity === "vector") {
15625
+ keys.add(vectorFieldKey(declaration.kind, declaration.fieldPath));
15626
+ }
15627
+ }
15628
+ return keys;
15629
+ }
15630
+ async function reclaimRemovedVectorFieldTables(context, activeRow) {
15475
15631
  const { backend, graphId } = context;
15476
15632
  const vectorStrategy = backend.vectorStrategy;
15477
- const executeDdl = backend.executeDdl;
15478
- if (vectorStrategy === void 0 || executeDdl === void 0) return [];
15479
- const activeRow = await backend.getActiveSchema(graphId);
15633
+ if (vectorStrategy === void 0) return [];
15480
15634
  if (activeRow === void 0) return [];
15481
15635
  const cacheKey = `${graphId}\0${activeRow.version}`;
15482
15636
  let perBackend = reclaimCache.get(backend);
15483
15637
  const cached = perBackend?.get(cacheKey);
15484
15638
  if (cached !== void 0) return cached;
15485
15639
  const activeSchema = parseSerializedSchema(activeRow.schema_doc);
15486
- const activeVectorFields = /* @__PURE__ */ new Set();
15487
- for (const declaration of activeSchema.indexes ?? []) {
15488
- if (declaration.entity === "vector") {
15489
- activeVectorFields.add(
15490
- vectorFieldKey(declaration.kind, declaration.fieldPath)
15491
- );
15492
- }
15493
- }
15640
+ const activeVectorFields = vectorFieldKeysFrom(activeSchema);
15494
15641
  const survivingKinds = new Set(Object.keys(activeSchema.nodes));
15495
15642
  const historical = /* @__PURE__ */ new Map();
15496
15643
  for (let version = activeRow.version - 1; version >= 1; version -= 1) {
@@ -15519,14 +15666,43 @@ async function reclaimRemovedVectorFieldTables(context) {
15519
15666
  (field2) => !activeVectorFields.has(vectorFieldKey(field2.kind, field2.fieldPath)) && survivingKinds.has(field2.kind)
15520
15667
  );
15521
15668
  const results = [];
15669
+ let skippedAfterLockedRecheck = false;
15670
+ const schemaWriteTransaction = backend.schemaWriteTransaction;
15671
+ if (orphans.length > 0 && schemaWriteTransaction === void 0) {
15672
+ throw new ConfigurationError(
15673
+ "store.materializeRemovals() requires a backend that can hold the schema-write lock across the vector-field liveness check and cleanup.",
15674
+ { code: "MATERIALIZE_REMOVALS_SCHEMA_FENCE_UNSUPPORTED" }
15675
+ );
15676
+ }
15522
15677
  for (const field2 of orphans) {
15523
15678
  try {
15524
- await dropVectorSlotStorage(
15525
- backend,
15526
- vectorStrategy,
15527
- executeDdl,
15528
- field2.slot
15679
+ const reclaimed = await requireDefined(schemaWriteTransaction)(
15680
+ graphId,
15681
+ async (target) => {
15682
+ const lockedActiveRow = await target.getActiveSchema(graphId);
15683
+ if (lockedActiveRow === void 0) return false;
15684
+ const lockedActiveSchema = parseSerializedSchema(
15685
+ lockedActiveRow.schema_doc
15686
+ );
15687
+ const lockedVectorFields = vectorFieldKeysFrom(lockedActiveSchema);
15688
+ if (lockedVectorFields.has(
15689
+ vectorFieldKey(field2.kind, field2.fieldPath)
15690
+ ) || !Object.hasOwn(lockedActiveSchema.nodes, field2.kind)) {
15691
+ return false;
15692
+ }
15693
+ await dropVectorSlotStorage(
15694
+ vectorStrategy,
15695
+ target.executeSchemaDdl,
15696
+ field2.slot
15697
+ );
15698
+ await target.deleteSchemaVectorSlotContribution(field2.slot);
15699
+ return true;
15700
+ }
15529
15701
  );
15702
+ if (!reclaimed) {
15703
+ skippedAfterLockedRecheck = true;
15704
+ continue;
15705
+ }
15530
15706
  results.push({
15531
15707
  kind: field2.kind,
15532
15708
  fieldPath: field2.fieldPath,
@@ -15541,7 +15717,7 @@ async function reclaimRemovedVectorFieldTables(context) {
15541
15717
  });
15542
15718
  }
15543
15719
  }
15544
- if (results.every((entry2) => entry2.status === "reclaimed")) {
15720
+ if (!skippedAfterLockedRecheck && results.every((entry2) => entry2.status === "reclaimed")) {
15545
15721
  if (perBackend === void 0) {
15546
15722
  perBackend = /* @__PURE__ */ new Map();
15547
15723
  reclaimCache.set(backend, perBackend);
@@ -16211,7 +16387,7 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
16211
16387
  validatedProps,
16212
16388
  matchOn
16213
16389
  );
16214
- const endpointKey = buildEndpointPairKey(
16390
+ const endpointKey2 = buildEndpointPairKey(
16215
16391
  item.fromKind,
16216
16392
  item.fromId,
16217
16393
  item.toKind,
@@ -16224,7 +16400,7 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
16224
16400
  toId: item.toId,
16225
16401
  validatedProps,
16226
16402
  compositeKey,
16227
- endpointKey,
16403
+ endpointKey: endpointKey2,
16228
16404
  ...validFrom !== void 0 && { validFrom },
16229
16405
  ...validTo !== void 0 && { validTo }
16230
16406
  });
@@ -16242,7 +16418,7 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
16242
16418
  }
16243
16419
  async function fetchRowsByEndpoint(reader) {
16244
16420
  const rowsByEndpoint = /* @__PURE__ */ new Map();
16245
- for (const [endpointKey, endpoint] of uniqueEndpoints) {
16421
+ for (const [endpointKey2, endpoint] of uniqueEndpoints) {
16246
16422
  const rows = await reader.findEdgesByKind({
16247
16423
  graphId: ctx.graphId,
16248
16424
  kind,
@@ -16253,7 +16429,7 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
16253
16429
  excludeDeleted: false,
16254
16430
  temporalMode: "includeTombstones"
16255
16431
  });
16256
- rowsByEndpoint.set(endpointKey, rows);
16432
+ rowsByEndpoint.set(endpointKey2, rows);
16257
16433
  }
16258
16434
  return rowsByEndpoint;
16259
16435
  }
@@ -16695,6 +16871,7 @@ var NODE_WRITE_INTENT_COUNTERS = {
16695
16871
  create: countSingleWrite,
16696
16872
  createFromRecord: countSingleWrite,
16697
16873
  update: countSingleWrite,
16874
+ updateWhere: countSingleWrite,
16698
16875
  delete: countSingleWrite,
16699
16876
  hardDelete: countSingleWrite,
16700
16877
  upsertById: countSingleWrite,
@@ -16875,6 +17052,10 @@ var CAUGHT_UP_VERB_DETAILS = {
16875
17052
  reembed: {
16876
17053
  phrase: "re-embed a vector field on",
16877
17054
  code: "REEMBED_BEFORE_INITIALIZE"
17055
+ },
17056
+ repair: {
17057
+ phrase: "repair contributions for",
17058
+ code: "REPAIR_CONTRIBUTIONS_BEFORE_INITIALIZE"
16878
17059
  }
16879
17060
  };
16880
17061
  var ROW_MAPPER_CONFIGS = {
@@ -16914,6 +17095,39 @@ function syncStoreReplacementRef(ref, replacement) {
16914
17095
  if (ref === void 0) return;
16915
17096
  ref.current = replacement;
16916
17097
  }
17098
+ async function commitEvolvedSchemaWhenRequiredKindsAreEmpty(backend, graph, currentVersion, classification) {
17099
+ const result = await commitNewSchemaVersionIfKindsEmpty(
17100
+ backend,
17101
+ graph,
17102
+ currentVersion,
17103
+ classification.requireEmpty.map((entry2) => ({
17104
+ entity: entry2.entity,
17105
+ kind: entry2.kindName
17106
+ }))
17107
+ );
17108
+ if (result.status === "committed") return result.row;
17109
+ const populatedKeys = new Set(
17110
+ result.kinds.map((entry2) => `${entry2.entity}:${entry2.kind}`)
17111
+ );
17112
+ const nonEmpty = new Set(
17113
+ classification.requireEmpty.filter(
17114
+ (entry2) => populatedKeys.has(`${entry2.entity}:${entry2.kindName}`)
17115
+ )
17116
+ );
17117
+ const error = buildIncompatibleChangeError(
17118
+ classification,
17119
+ nonEmpty,
17120
+ graph.id
17121
+ );
17122
+ if (error !== void 0) throw error;
17123
+ throw new ConfigurationError(
17124
+ "Schema emptiness guard reported populated kinds that were not part of the compatibility classification.",
17125
+ {
17126
+ graphId: graph.id,
17127
+ populatedKinds: result.kinds.map((entry2) => entry2.kind)
17128
+ }
17129
+ );
17130
+ }
16917
17131
  var StoreImplementation = class _StoreImplementation {
16918
17132
  [STORE_RUNTIME];
16919
17133
  #graph;
@@ -17206,8 +17420,9 @@ var StoreImplementation = class _StoreImplementation {
17206
17420
  * `KindNotFoundError` when the kind is not registered.
17207
17421
  *
17208
17422
  * The dominant graph-extension-kind access pattern: `await store.evolve(...)`
17209
- * returns a new store, the caller immediately operates on the new
17210
- * kind, and the null-check the optional variant requires is busywork.
17423
+ * returns the Store for the resulting schema, the caller immediately
17424
+ * operates on the new kind, and the null-check the optional variant requires
17425
+ * is busywork.
17211
17426
  */
17212
17427
  getNodeCollectionOrThrow(kind) {
17213
17428
  const collection = this.getNodeCollection(kind);
@@ -17370,6 +17585,14 @@ var StoreImplementation = class _StoreImplementation {
17370
17585
  executeCreateBatch: (inputs, backend) => executeNodeCreateBatch(ctx, inputs, backend),
17371
17586
  executeCreateNoReturnBatch: (inputs, backend) => executeNodeCreateNoReturnBatch(ctx, inputs, backend),
17372
17587
  executeUpdate: (input, backend, options) => executeNodeUpdate(ctx, { ...input, id: input.id }, backend, options),
17588
+ executeUpdateWhere: (kind, patch, candidateIds, candidateIdColumn, backend) => executeNodeUpdateWhere(
17589
+ ctx,
17590
+ kind,
17591
+ patch,
17592
+ candidateIds,
17593
+ candidateIdColumn,
17594
+ backend
17595
+ ),
17373
17596
  executeUpsertUpdate: (input, backend, options) => executeNodeUpsertUpdate(
17374
17597
  ctx,
17375
17598
  { ...input, id: input.id },
@@ -17759,19 +17982,54 @@ var StoreImplementation = class _StoreImplementation {
17759
17982
  }
17760
17983
  // === Batch Query Execution ===
17761
17984
  /**
17762
- * Executes multiple queries and returns a typed tuple of results.
17985
+ * Runs several queries in sequence, returning a typed tuple. The portable
17986
+ * guarantee is N serialized query executions — never one round trip.
17987
+ *
17988
+ * **Cost.** At least one statement per query, sometimes two: a query whose
17989
+ * selective-field mapping falls back re-runs as a full fetch, and that
17990
+ * fallback is detected *after* the selective statement has already
17991
+ * executed. It clears the fast path, so a reused query instance pays the
17992
+ * double only once — but the builder is immutable, so a query rebuilt per
17993
+ * request pays it every request.
17994
+ *
17995
+ * With `backend.capabilities.transactions` the queries share one
17996
+ * transaction; how that reaches the wire is the adapter's business. A SQL
17997
+ * backend frames them with `begin`/`commit`, putting a networked one at
17998
+ * N+2 round trips *at best*, while Durable Objects use an ambient storage
17999
+ * transaction with no framing statements. Without transactions there is no
18000
+ * framing. Connection reuse is a separate question from transaction
18001
+ * support: the no-transaction path passes the same backend object, so an
18002
+ * adapter may reuse one client there too. The portable guarantee is only
18003
+ * that at most one query is in flight at a time.
17763
18004
  *
17764
- * Each query preserves its own result type, projection, filtering, sorting,
17765
- * and pagination.
18005
+ * **Not a snapshot — and there is no way to make it one.** PostgreSQL
18006
+ * defaults to read-committed isolation, so a later query can observe a
18007
+ * commit the earlier ones did not. `store.transaction()` takes an
18008
+ * `isolationLevel`, but its context exposes only `nodes` / `edges`: there is
18009
+ * no public way to run a fluent query or a batch inside a transaction, so a
18010
+ * snapshot across fluent queries is not available today. Collection reads
18011
+ * can have one — `store.transaction(fn, { isolationLevel: "repeatable_read" })`
18012
+ * reading through `tx.nodes` / `tx.edges` — but only where the backend has
18013
+ * transactions (others ignore the option entirely), and a history-enabled
18014
+ * store on PostgreSQL additionally requires `accessMode: "read_only"` or the
18015
+ * call throws.
17766
18016
  *
17767
- * **Snapshot consistency is conditional.** When
17768
- * `backend.capabilities.transactions` is `true`, queries run sequentially
17769
- * on a single connection inside an implicit transaction and observe the
17770
- * same database snapshot. When transactions are unavailable
17771
- * (Cloudflare D1, `drizzle-orm/neon-http`), queries run sequentially over
17772
- * independent connections and may observe writes that landed between them.
17773
- * Branch on `backend.capabilities.transactions` if you need a guaranteed
17774
- * snapshot.
18017
+ * **Will not fix an N+1.** Serializing N queries does not reduce their
18018
+ * number. The alternatives are set-oriented or chunked rather than
18019
+ * fixed-cost: `.traverse()` compiles a whole chain to one statement;
18020
+ * `store.subgraph()` costs 2 statements on SQLite and 3 on PostgreSQL
18021
+ * however large the result; `getByIds()` issues one statement per
18022
+ * bind-limit chunk, falling back to one per distinct id where the backend
18023
+ * exposes no batch read; `bulkFindByIndex()` costs one probe plus that same
18024
+ * chunked hydration.
18025
+ *
18026
+ * **Versus `Promise.all`.** Workload- and adapter-dependent in both
18027
+ * directions. `Promise.all` overlaps its queries against a pool with idle
18028
+ * capacity, but it does not necessarily hold N connections, and against a
18029
+ * single client or a saturated pool it queues. `batch()` keeps at most one
18030
+ * query in flight, so it pays the sum of their latencies — but it can still
18031
+ * come out ahead where connection acquisition dominates. Measure rather
18032
+ * than assume.
17775
18033
  *
17776
18034
  * Read-only — use `bulkCreate`, `bulkInsert`, etc. for write batching.
17777
18035
  *
@@ -17796,14 +18054,105 @@ var StoreImplementation = class _StoreImplementation {
17796
18054
  */
17797
18055
  async batch(...queries) {
17798
18056
  return runOptionallyInTransaction(this.#baseBackend, async (target) => {
18057
+ const queryBackend = this.#createHookedQueryBackend(target);
17799
18058
  const results = [];
17800
18059
  for (const query of queries) {
17801
- const result = await query.executeOn(target);
18060
+ const result = await query.executeOn(queryBackend);
17802
18061
  results.push(result);
17803
18062
  }
17804
18063
  return results;
17805
18064
  });
17806
18065
  }
18066
+ /**
18067
+ * Reads several edge kinds from heterogeneous source nodes with round trips
18068
+ * independent of the number of licensed edge/source-kind combinations.
18069
+ *
18070
+ * Results are flattened in source-group/id order. Repeated sources receive
18071
+ * independent edge arrays, and sources with no matching edges remain present
18072
+ * with an empty array. Inputs that exceed the backend bind budget are split
18073
+ * into source chunks without splitting one source across statements.
18074
+ */
18075
+ async bulkFindEdgesFrom(params, options) {
18076
+ const sources = params.sources.flatMap(
18077
+ (group) => {
18078
+ if (!Object.hasOwn(this.#graph.nodes, group.kind)) {
18079
+ throw new KindNotFoundError(group.kind, "node", {
18080
+ graphId: this.graphId
18081
+ });
18082
+ }
18083
+ return group.ids.map((id) => ({ kind: group.kind, id }));
18084
+ }
18085
+ );
18086
+ for (const edgeKind of params.edgeKinds) {
18087
+ if (!Object.hasOwn(this.#graph.edges, edgeKind)) {
18088
+ throw new KindNotFoundError(edgeKind, "edge", {
18089
+ graphId: this.graphId
18090
+ });
18091
+ }
18092
+ }
18093
+ if (sources.length === 0 || params.edgeKinds.length === 0) {
18094
+ return sources.map((source) => ({ source, edges: [] }));
18095
+ }
18096
+ const readEndpointSet = this.#baseBackend.findEdgesByHeterogeneousEndpointSet;
18097
+ if (readEndpointSet === void 0) {
18098
+ throw new ConfigurationError(
18099
+ "store.bulkFindEdgesFrom() requires a backend that can read heterogeneous endpoint and edge-kind sets in set-oriented statements.",
18100
+ {
18101
+ backend: this.#baseBackend.dialect,
18102
+ capability: "findEdgesByHeterogeneousEndpointSet",
18103
+ operation: "bulkFindEdgesFrom"
18104
+ },
18105
+ {
18106
+ suggestion: "Use per-edge-kind bulkFindFrom calls explicitly if that round-trip tradeoff is acceptable."
18107
+ }
18108
+ );
18109
+ }
18110
+ const limitPerInput = options?.limitPerInput;
18111
+ if (limitPerInput !== void 0 && (!Number.isInteger(limitPerInput) || limitPerInput <= 0)) {
18112
+ throw new ValidationError(
18113
+ "bulk endpoint reads require limitPerInput to be a positive integer",
18114
+ {
18115
+ entityType: "edge",
18116
+ kind: params.edgeKinds.join(","),
18117
+ issues: [
18118
+ {
18119
+ path: "limitPerInput",
18120
+ message: `Expected a positive integer, received ${String(limitPerInput)}`,
18121
+ code: "invalid_value"
18122
+ }
18123
+ ]
18124
+ }
18125
+ );
18126
+ }
18127
+ const temporal = resolveTemporalReadParams(
18128
+ options,
18129
+ this.#graph.defaults.temporalMode
18130
+ );
18131
+ const endpoints = sources;
18132
+ const rows = await readEndpointSet({
18133
+ graphId: this.graphId,
18134
+ side: "from",
18135
+ endpoints,
18136
+ edgeKinds: params.edgeKinds,
18137
+ ...limitPerInput !== void 0 && this.#baseBackend.capabilities.windowFunctions && {
18138
+ limitPerEndpoint: limitPerInput
18139
+ },
18140
+ ...temporal
18141
+ });
18142
+ const edgesBySource = /* @__PURE__ */ new Map();
18143
+ for (const row of rows) {
18144
+ const edge = rowToEdge(row);
18145
+ const key = `${edge.fromKind}\0${edge.fromId}`;
18146
+ const bucket = edgesBySource.get(key);
18147
+ if (bucket === void 0) edgesBySource.set(key, [edge]);
18148
+ else bucket.push(edge);
18149
+ }
18150
+ return sources.map((source) => {
18151
+ const bucket = edgesBySource.get(`${source.kind}\0${source.id}`) ?? [];
18152
+ const edges = limitPerInput === void 0 ? [...bucket] : bucket.slice(0, limitPerInput);
18153
+ return { source, edges };
18154
+ });
18155
+ }
17807
18156
  // === Subgraph Extraction ===
17808
18157
  /**
17809
18158
  * Extracts a typed subgraph by traversing from a root node.
@@ -17945,6 +18294,7 @@ var StoreImplementation = class _StoreImplementation {
17945
18294
  }
17946
18295
  const pending = [];
17947
18296
  const runHooks = this.#createBufferedHookRunner(pending);
18297
+ const runBulkHooks = this.#createBufferedBulkHookRunner(pending);
17948
18298
  let recordedByGraph;
17949
18299
  const transactionOptions = receiptRecorder !== void 0 && this.#captureEnabled ? withRecordedFlushObserver(backendOptions, (instants) => {
17950
18300
  recordedByGraph = instants;
@@ -17955,7 +18305,8 @@ var StoreImplementation = class _StoreImplementation {
17955
18305
  txBackend,
17956
18306
  nativeTransaction,
17957
18307
  runHooks,
17958
- receiptRecorder
18308
+ receiptRecorder,
18309
+ runBulkHooks
17959
18310
  )
17960
18311
  );
17961
18312
  const result = this.#captureEnabled || this.#adapterBackend === void 0 ? await this.#backend.transaction(
@@ -17966,9 +18317,16 @@ var StoreImplementation = class _StoreImplementation {
17966
18317
  transactionOptions
17967
18318
  );
17968
18319
  for (const outcome of pending) {
17969
- this.#hooks.onOperationEnd?.(outcome.ctx, {
17970
- durationMs: outcome.durationMs
17971
- });
18320
+ if (outcome.type === "bulkOperation") {
18321
+ this.#hooks.onBulkOperationEnd?.(outcome.ctx, {
18322
+ affectedCount: outcome.affectedCount,
18323
+ durationMs: outcome.durationMs
18324
+ });
18325
+ } else {
18326
+ this.#hooks.onOperationEnd?.(outcome.ctx, {
18327
+ durationMs: outcome.durationMs
18328
+ });
18329
+ }
17972
18330
  }
17973
18331
  return { result, recordedByGraph };
17974
18332
  } catch (error) {
@@ -18080,6 +18438,13 @@ var StoreImplementation = class _StoreImplementation {
18080
18438
  const txBackend = adopt(externalTx);
18081
18439
  if (this.#captureEnabled) {
18082
18440
  await assertRecordedCaptureTransactionIsolation(txBackend);
18441
+ await lockSchemaVersionForStoreWrite(
18442
+ {
18443
+ graphId: this.graphId,
18444
+ schemaVersion: this.#schemaMetadata.schemaVersion
18445
+ },
18446
+ txBackend
18447
+ );
18083
18448
  }
18084
18449
  const scope = this.#captureEnabled ? createRecordedTransactionScope(txBackend, this.#sqlSchema()) : {
18085
18450
  backend: txBackend,
@@ -18151,9 +18516,11 @@ var StoreImplementation = class _StoreImplementation {
18151
18516
  * (#140); when history capture is enabled it is replaced with a fail-loud
18152
18517
  * guard because raw graph writes would bypass recorded-time capture.
18153
18518
  */
18154
- #buildTransactionContext(txBackend, sql2, runHooks = this.#immediateHookRunner(), receiptRecorder) {
18519
+ #buildTransactionContext(txBackend, sql2, runHooks = this.#immediateHookRunner(), receiptRecorder, runBulkHooks = this.#immediateBulkHookRunner()) {
18155
18520
  const txNodeOperations = {
18156
- ...this.#buildNodeOperations(this.#createNodeOperationContext(runHooks)),
18521
+ ...this.#buildNodeOperations(
18522
+ this.#createNodeOperationContext(runHooks, runBulkHooks)
18523
+ ),
18157
18524
  createQuery: () => this.#createQueryForBackend(txBackend),
18158
18525
  maybeRefreshStatisticsAfterBulk: void 0
18159
18526
  };
@@ -18249,6 +18616,7 @@ var StoreImplementation = class _StoreImplementation {
18249
18616
  };
18250
18617
  await (this.#baseBackend.capabilities.transactions ? this.#baseBackend.transaction(async (tx) => doClear(tx)) : doClear(this.#baseBackend));
18251
18618
  await this.#clearVectorStorage();
18619
+ this.#schemaMetadata = UNKNOWN_SCHEMA_METADATA;
18252
18620
  this.#nodeCollections = void 0;
18253
18621
  this.#edgeCollections = void 0;
18254
18622
  this.#algorithms = void 0;
@@ -18320,12 +18688,14 @@ var StoreImplementation = class _StoreImplementation {
18320
18688
  /**
18321
18689
  * Evolves the graph at runtime by merging a graph extension into the
18322
18690
  * current schema, atomically committing a new schema version, and
18323
- * returning a fresh `Store` constructed against the merged graph.
18691
+ * returning the `Store` for the merged graph.
18324
18692
  *
18325
18693
  * The `Store` is immutable — its registry, collections, and operation
18326
- * contexts close over the graph at construction time — so callers
18327
- * must use the returned store (or pass a `ref` to be re-pointed) for
18328
- * any work involving the new kinds.
18694
+ * contexts close over the graph at construction time. After `evolve()`
18695
+ * resolves, callers must use the returned Store (or the re-pointed
18696
+ * `ref.current`) for every subsequent operation in the same request. A
18697
+ * Store captured before the schema commit remains pinned to the old version,
18698
+ * and its next managed write is rejected by the schema fence.
18329
18699
  *
18330
18700
  * **Cost for purely additive extensions is proportional to schema
18331
18701
  * document size, not row count.** The commit is a single CAS write.
@@ -18343,10 +18713,10 @@ var StoreImplementation = class _StoreImplementation {
18343
18713
  *
18344
18714
  * @param extension - Graph extension produced by
18345
18715
  * `defineGraphExtension(...)`.
18346
- * @param options.ref - Optional handle whose `current` is overwritten
18347
- * atomically with the schema commit. Long-lived consumers
18348
- * (request handlers, background workers) that dereference through
18349
- * the ref see the new kinds on the *next* call.
18716
+ * @param options.ref - Optional handle whose `current` is overwritten with
18717
+ * the replacement before a successful call resolves. Code awaiting this
18718
+ * call can use the returned Store or `ref.current` immediately. A
18719
+ * previously captured Store is not mutated.
18350
18720
  *
18351
18721
  * @throws {GraphExtensionValidationError} when the extension is
18352
18722
  * structurally invalid.
@@ -18385,6 +18755,7 @@ var StoreImplementation = class _StoreImplementation {
18385
18755
  }
18386
18756
  return caughtUp;
18387
18757
  }
18758
+ await this.#assertNoPendingRemovalFor(merged, baseline);
18388
18759
  const baselineDocument = baseline.extension ?? Object.freeze({});
18389
18760
  const classification = classifyModifications(baselineDocument, extension);
18390
18761
  if (classification.incompatible.length > 0) {
@@ -18393,20 +18764,12 @@ var StoreImplementation = class _StoreImplementation {
18393
18764
  this.graphId
18394
18765
  );
18395
18766
  }
18396
- if (classification.requireEmpty.length > 0) {
18397
- const nonEmpty = await this.#probeEmptyKinds(classification.requireEmpty);
18398
- const error = buildIncompatibleChangeError(
18399
- classification,
18400
- nonEmpty,
18401
- this.graphId
18402
- );
18403
- if (error !== void 0) throw error;
18404
- }
18405
- const committed = await commitNewSchemaVersion(
18767
+ const committed = classification.requireEmpty.length > 0 ? await commitEvolvedSchemaWhenRequiredKindsAreEmpty(
18406
18768
  this.#backend,
18407
18769
  merged,
18408
- activeRow.version
18409
- );
18770
+ activeRow.version,
18771
+ classification
18772
+ ) : await commitNewSchemaVersion(this.#backend, merged, activeRow.version);
18410
18773
  await materializeVectorContributions(this.#backend, merged);
18411
18774
  const evolved = this.#cloneWithGraph(
18412
18775
  merged,
@@ -18437,8 +18800,8 @@ var StoreImplementation = class _StoreImplementation {
18437
18800
  * kind that's already marked is a no-op (no version bump).
18438
18801
  *
18439
18802
  * @param names - Node or edge kind names to mark as deprecated.
18440
- * @param options.ref - Optional handle to be re-pointed atomically
18441
- * with the schema commit, mirroring `evolve()`.
18803
+ * @param options.ref - Optional handle to be re-pointed to the replacement
18804
+ * Store before a successful call resolves, mirroring `evolve()`.
18442
18805
  *
18443
18806
  * @throws {ConfigurationError} on `DEPRECATE_BEFORE_INITIALIZE` (no
18444
18807
  * schema yet) or `DEPRECATE_UNKNOWN_KIND` (name not on the graph).
@@ -18459,8 +18822,8 @@ var StoreImplementation = class _StoreImplementation {
18459
18822
  *
18460
18823
  * @param names - Node or edge kind names to remove from the
18461
18824
  * deprecated set.
18462
- * @param options.ref - Optional handle to be re-pointed atomically
18463
- * with the schema commit.
18825
+ * @param options.ref - Optional handle to be re-pointed to the replacement
18826
+ * Store before a successful call resolves.
18464
18827
  *
18465
18828
  * @throws {ConfigurationError} on `DEPRECATE_BEFORE_INITIALIZE`.
18466
18829
  * @throws {StaleVersionError} on a CAS race with another writer.
@@ -18681,6 +19044,98 @@ var StoreImplementation = class _StoreImplementation {
18681
19044
  }
18682
19045
  return { recreated: true, reembedded };
18683
19046
  }
19047
+ /**
19048
+ * Diagnostic: compare each contribution currently expected by this graph
19049
+ * and the backend strategies with its durable marker and the physical
19050
+ * catalog. Reports detected unusable contributions, including a recorded
19051
+ * failed materialization whose absent table agrees with the marker.
19052
+ * Contributions with neither marker nor table and retired marker rows are
19053
+ * omitted, so an empty array is not proof that storage was initialized.
19054
+ *
19055
+ * Opening a store never probes the catalog — `ensureRuntimeContributions`
19056
+ * and the runtime asserts short-circuit on a per-instance signature cache
19057
+ * and then on the marker row alone, which is the right default for a hot
19058
+ * path. The cost is that a database whose contribution tables were dropped
19059
+ * out of band (a partial restore, a hand-run `DROP`, a schema-scoped
19060
+ * restore that missed them) opens completely clean and then fails at the
19061
+ * first read of the affected slot. This is the explicit, operator-invoked
19062
+ * check for that state; it is not, and should not become, a boot step.
19063
+ *
19064
+ * Purely read-only: one existence query per distinct contribution table
19065
+ * plus one marker read per graph, no DDL and no writes, so it is safe to
19066
+ * run under a least-privilege runtime role and safe to run on a live
19067
+ * store. Each entry carries identity resolved from the active contribution
19068
+ * declaration and matching the marker contract, so callers can route to a
19069
+ * repair without reconstructing any internal naming contract.
19070
+ *
19071
+ * Route on `state`, NOT on whether the entry is a vector slot: the
19072
+ * repairs differ per state and the wrong one destroys data.
19073
+ * {@link Store.reembedVectorField} drops and recreates storage, so
19074
+ * applying it to a `missing-marker` — table intact, only the marker
19075
+ * wrong — discards every embedding to fix bookkeeping. See
19076
+ * {@link ContributionDiagnostic} and the per-state repair tables in the
19077
+ * troubleshooting guide.
19078
+ *
19079
+ * Vector slots are enumerated from the graph's declared embedding fields
19080
+ * and are considered only when the backend advertises vector support; a
19081
+ * backend without it never materialized them, so there is nothing to
19082
+ * compare. Current fulltext contributions are always considered. For a
19083
+ * readiness check, first construct the Store through a verified attach so
19084
+ * initialization is established independently.
19085
+ *
19086
+ * @throws {ConfigurationError} when the backend cannot probe its own
19087
+ * catalog. Reporting "no problems found" on a backend that never
19088
+ * looked would be the one answer this diagnostic must never give.
19089
+ */
19090
+ async verifyContributions() {
19091
+ const backend = this.#baseBackend;
19092
+ const verify = backend.verifyContributions;
19093
+ if (verify === void 0) {
19094
+ throw new ConfigurationError(
19095
+ "verifyContributions requires a backend that can probe its catalog for contribution tables.",
19096
+ {
19097
+ backend: backend.dialect,
19098
+ capability: "contributions",
19099
+ operation: "verify"
19100
+ }
19101
+ );
19102
+ }
19103
+ const vectorSlots = backend.capabilities.vector?.supported === true ? resolveGraphVectorSlots(this.#graph) : [];
19104
+ return verify(this.graphId, vectorSlots);
19105
+ }
19106
+ /**
19107
+ * Non-destructively repairs contribution states whose physical storage can
19108
+ * be preserved: `missing-marker` and `failed-materialization`.
19109
+ * `orphaned-marker` and `stale` findings are returned as
19110
+ * `requires-rebuild`; this method never drops contribution tables or
19111
+ * fabricates the data needed to rebuild them.
19112
+ *
19113
+ * The repair re-audits inside the backend and resolves every declaration
19114
+ * from the committed schema. Callers do not supply diagnostics, physical
19115
+ * names, or DDL. A stale Store is caught up to the active persisted graph
19116
+ * before its vector slots are enumerated, so repair does not use declarations
19117
+ * from the Store's stale in-memory graph snapshot.
19118
+ *
19119
+ * @throws {ConfigurationError} when no schema has been initialized or the
19120
+ * backend cannot probe and repair strategy-owned contributions.
19121
+ */
19122
+ async repairContributions() {
19123
+ const backend = this.#baseBackend;
19124
+ const repair = backend.repairContributions;
19125
+ if (repair === void 0) {
19126
+ throw new ConfigurationError(
19127
+ "repairContributions requires a backend that can probe and repair strategy-owned contribution tables.",
19128
+ {
19129
+ backend: backend.dialect,
19130
+ capability: "contributions",
19131
+ operation: "repair"
19132
+ }
19133
+ );
19134
+ }
19135
+ const { baseline } = await this.#loadCaughtUp("repair");
19136
+ const vectorSlots = backend.capabilities.vector?.supported === true ? resolveGraphVectorSlots(baseline) : [];
19137
+ return repair(this.graphId, vectorSlots);
19138
+ }
18684
19139
  /**
18685
19140
  * Removes extension kinds from the schema with cascading edge and
18686
19141
  * ontology cleanup. Two-phase by design:
@@ -18735,9 +19190,10 @@ var StoreImplementation = class _StoreImplementation {
18735
19190
  );
18736
19191
  const recordKindRemoval = this.#backend.recordKindRemoval;
18737
19192
  if (recordKindRemoval !== void 0) {
18738
- if (this.#backend.ensureKindRemovalsTable !== void 0) {
18739
- await this.#backend.ensureKindRemovalsTable();
18740
- }
19193
+ await ensureFocusedStatusTable(
19194
+ this.#backend,
19195
+ this.#backend.ensureKindRemovalsTable
19196
+ );
18741
19197
  const attemptedAt = nowIso();
18742
19198
  const newSchemaVersion = committedRow.version;
18743
19199
  const queue = (kindName, entity) => recordKindRemoval(
@@ -18861,42 +19317,40 @@ var StoreImplementation = class _StoreImplementation {
18861
19317
  return { activeRow, storedSchema, baseline };
18862
19318
  }
18863
19319
  /**
18864
- * Probes each `requireEmpty` entry for any rows. Returns the set of
18865
- * composite keys (`${entity}:${kindName}`) that have at least one
18866
- * row — those entries need to be promoted from "allowed-on-empty"
18867
- * to incompatible. Dispatches to `countNodesByKind` for `node`
18868
- * entries and `countEdgesByKind` for `edge` entries (a single-
18869
- * primitive probe would always return 0 for the wrong-entity case
18870
- * and silently bypass the gate).
19320
+ * Refuses an evolve that re-adds a kind whose data cleanup is still pending.
18871
19321
  *
18872
- * Probes run in parallel; each entry is independent. Race window
18873
- * (probe → CAS commit): another writer can insert a row into a
18874
- * previously-empty kind. The schema commit still succeeds (CAS
18875
- * guards on schema version, not row count); the new schema rejects
18876
- * the inserted row at next read, which the operator inspects and
18877
- * either deletes or reverts. Rare in practice; tighter elimination
18878
- * would require `SELECT FOR UPDATE` on the rows table, too
18879
- * heavyweight for a millisecond-budget operation.
19322
+ * Returns silently on backends without the removal queue: they cannot have
19323
+ * a pending row, so there is nothing to conflict with.
18880
19324
  */
18881
- async #probeEmptyKinds(requireEmpty) {
18882
- const probes = requireEmpty.map(
18883
- async (entry2) => {
18884
- const count2 = entry2.entity === "node" ? await this.#backend.countNodesByKind({
18885
- graphId: this.graphId,
18886
- kind: entry2.kindName
18887
- }) : await this.#backend.countEdgesByKind({
18888
- graphId: this.graphId,
18889
- kind: entry2.kindName
18890
- });
18891
- return [entry2, count2];
19325
+ async #assertNoPendingRemovalFor(merged, baseline) {
19326
+ const getPendingKindRemovals = this.#backend.getPendingKindRemovals;
19327
+ if (getPendingKindRemovals === void 0) return;
19328
+ const addedNodes = Object.keys(merged.nodes).filter(
19329
+ (kind) => !(kind in baseline.nodes)
19330
+ );
19331
+ const addedEdges = Object.keys(merged.edges).filter(
19332
+ (kind) => !(kind in baseline.edges)
19333
+ );
19334
+ if (addedNodes.length === 0 && addedEdges.length === 0) return;
19335
+ await ensureFocusedStatusTable(
19336
+ this.#backend,
19337
+ this.#backend.ensureKindRemovalsTable
19338
+ );
19339
+ const pending = await getPendingKindRemovals(this.graphId);
19340
+ if (pending.length === 0) return;
19341
+ const blocked = pending.filter(
19342
+ (row) => row.entity === "node" ? addedNodes.includes(row.kindName) : addedEdges.includes(row.kindName)
19343
+ );
19344
+ if (blocked.length === 0) return;
19345
+ const named = blocked.map((row) => `${row.entity} "${row.kindName}"`).join(", ");
19346
+ throw new ConfigurationError(
19347
+ `Cannot re-add ${named} for graph "${this.graphId}": the previous removal's data cleanup has not run, so the old rows are still in the database and would become visible again alongside the new ones. Run store.materializeRemovals() first, then evolve.`,
19348
+ {
19349
+ code: "KIND_READD_BLOCKED_BY_PENDING_REMOVAL",
19350
+ graphId: this.graphId,
19351
+ kinds: blocked.map((row) => row.kindName)
18892
19352
  }
18893
19353
  );
18894
- const results = await Promise.all(probes);
18895
- const nonEmpty = /* @__PURE__ */ new Set();
18896
- for (const [entry2, count2] of results) {
18897
- if (count2 > 0) nonEmpty.add(entry2);
18898
- }
18899
- return nonEmpty;
18900
19354
  }
18901
19355
  #cloneWithGraph(graph, ref, schemaMetadata = this.#schemaMetadata) {
18902
19356
  const next = this.#adapterBackend === void 0 ? new _StoreImplementation(
@@ -18928,22 +19382,34 @@ var StoreImplementation = class _StoreImplementation {
18928
19382
  #immediateHookRunner() {
18929
19383
  return (ctx, fn) => this.#withOperationHooks(ctx, fn);
18930
19384
  }
18931
- #createNodeOperationContext(runHooks = this.#immediateHookRunner()) {
19385
+ #immediateBulkHookRunner() {
19386
+ return (ctx, fn) => this.#withBulkOperationHooks(ctx, fn);
19387
+ }
19388
+ #createNodeOperationContext(runHooks = this.#immediateHookRunner(), runBulkHooks = this.#immediateBulkHookRunner()) {
18932
19389
  return {
18933
19390
  graph: this.#graph,
18934
19391
  graphId: this.graphId,
19392
+ schemaVersion: this.#schemaMetadata.schemaVersion,
18935
19393
  historyEnabled: this.#captureEnabled,
18936
19394
  revisionTrackingEnabled: this.#revisionTrackingEnabled,
18937
19395
  revisionSchema: this.#sqlSchema(),
18938
19396
  registry: this.#registry,
18939
19397
  createOperationContext: (operation, entity, kind, id) => this.#createOperationContext(operation, entity, kind, id),
18940
- withOperationHooks: runHooks
19398
+ withOperationHooks: runHooks,
19399
+ createBulkOperationContext: (operation, kind) => ({
19400
+ ...this.#createHookContext(),
19401
+ operation,
19402
+ entity: "node",
19403
+ kind
19404
+ }),
19405
+ withBulkOperationHooks: runBulkHooks
18941
19406
  };
18942
19407
  }
18943
19408
  #createEdgeOperationContext(runHooks = this.#immediateHookRunner()) {
18944
19409
  return {
18945
19410
  graph: this.#graph,
18946
19411
  graphId: this.graphId,
19412
+ schemaVersion: this.#schemaMetadata.schemaVersion,
18947
19413
  historyEnabled: this.#captureEnabled,
18948
19414
  revisionTrackingEnabled: this.#revisionTrackingEnabled,
18949
19415
  revisionSchema: this.#sqlSchema(),
@@ -18953,6 +19419,57 @@ var StoreImplementation = class _StoreImplementation {
18953
19419
  };
18954
19420
  }
18955
19421
  // === Internal: Hook Helpers ===
19422
+ /**
19423
+ * Decorates the query execution port so hooks observe each statement the
19424
+ * query builder submits to the backend. A selective-projection retry
19425
+ * therefore emits two independent start/end pairs with their actual SQL.
19426
+ */
19427
+ #createHookedQueryBackend(backend) {
19428
+ if (this.#hooks.onQueryStart === void 0 && this.#hooks.onQueryEnd === void 0 && this.#hooks.onError === void 0) {
19429
+ return backend;
19430
+ }
19431
+ const executeRaw = backend.executeRaw;
19432
+ const compileSql = backend.compileSql;
19433
+ const projected = createGraphBackendProjection(backend);
19434
+ return {
19435
+ ...projected,
19436
+ execute: (query) => {
19437
+ const compiled = compileSql === void 0 ? renderSql(query, backend.dialect) : compileSql(query);
19438
+ return this.#withQueryHooks(
19439
+ compiled.sql,
19440
+ compiled.params,
19441
+ () => backend.execute(query)
19442
+ );
19443
+ },
19444
+ ...executeRaw === void 0 ? {} : {
19445
+ executeRaw: (sqlText, params) => this.#withQueryHooks(
19446
+ sqlText,
19447
+ params,
19448
+ () => executeRaw(sqlText, params)
19449
+ )
19450
+ }
19451
+ };
19452
+ }
19453
+ async #withQueryHooks(sql2, params, execute) {
19454
+ const ctx = {
19455
+ ...this.#createHookContext(),
19456
+ sql: sql2,
19457
+ params
19458
+ };
19459
+ this.#hooks.onQueryStart?.(ctx);
19460
+ const startTime = Date.now();
19461
+ try {
19462
+ const rows = await execute();
19463
+ this.#hooks.onQueryEnd?.(ctx, {
19464
+ rowCount: rows.length,
19465
+ durationMs: Date.now() - startTime
19466
+ });
19467
+ return rows;
19468
+ } catch (error) {
19469
+ this.#hooks.onError?.(ctx, asError(error));
19470
+ throw error;
19471
+ }
19472
+ }
18956
19473
  #createHookContext() {
18957
19474
  return {
18958
19475
  operationId: generateId(),
@@ -18983,6 +19500,21 @@ var StoreImplementation = class _StoreImplementation {
18983
19500
  throw error;
18984
19501
  }
18985
19502
  }
19503
+ async #withBulkOperationHooks(ctx, fn) {
19504
+ this.#hooks.onBulkOperationStart?.(ctx);
19505
+ const startTime = Date.now();
19506
+ try {
19507
+ const result = await fn();
19508
+ this.#hooks.onBulkOperationEnd?.(ctx, {
19509
+ affectedCount: result.affectedCount,
19510
+ durationMs: Date.now() - startTime
19511
+ });
19512
+ return result;
19513
+ } catch (error) {
19514
+ this.#hooks.onError?.(ctx, asError(error));
19515
+ throw error;
19516
+ }
19517
+ }
18986
19518
  /**
18987
19519
  * A hook runner for operations that execute INSIDE an explicit
18988
19520
  * `store.transaction`: `onOperationStart` (and a failed operation's
@@ -18999,7 +19531,31 @@ var StoreImplementation = class _StoreImplementation {
18999
19531
  const startTime = Date.now();
19000
19532
  try {
19001
19533
  const result = await fn();
19002
- pending.push({ ctx, durationMs: Date.now() - startTime });
19534
+ pending.push({
19535
+ type: "operation",
19536
+ ctx,
19537
+ durationMs: Date.now() - startTime
19538
+ });
19539
+ return result;
19540
+ } catch (error) {
19541
+ this.#hooks.onError?.(ctx, asError(error));
19542
+ throw error;
19543
+ }
19544
+ };
19545
+ }
19546
+ /** Buffered counterpart for set-based operations inside `transaction()`. */
19547
+ #createBufferedBulkHookRunner(pending) {
19548
+ return async (ctx, fn) => {
19549
+ this.#hooks.onBulkOperationStart?.(ctx);
19550
+ const startTime = Date.now();
19551
+ try {
19552
+ const result = await fn();
19553
+ pending.push({
19554
+ type: "bulkOperation",
19555
+ ctx,
19556
+ affectedCount: result.affectedCount,
19557
+ durationMs: Date.now() - startTime
19558
+ });
19003
19559
  return result;
19004
19560
  } catch (error) {
19005
19561
  this.#hooks.onError?.(ctx, asError(error));
@@ -19034,13 +19590,14 @@ var StoreImplementation = class _StoreImplementation {
19034
19590
  };
19035
19591
  }
19036
19592
  #createQueryForBackend(backend, sealedCoordinate) {
19593
+ const queryBackend = this.#createHookedQueryBackend(backend);
19037
19594
  return createInternalQueryBuilder(
19038
19595
  this.graphId,
19039
19596
  this.#registry,
19040
19597
  {
19041
19598
  // TransactionBackend omits transaction/close, but query execution only needs
19042
19599
  // the read-path/query capabilities shared with GraphBackend.
19043
- backend,
19600
+ backend: queryBackend,
19044
19601
  dialect: backend.dialect,
19045
19602
  defaultTraversalExpansion: this.#defaultTraversalExpansion,
19046
19603
  ...this.#schema !== void 0 && { schema: this.#schema },
@@ -19353,5 +19910,5 @@ async function createVerifiedAdapterStore(graph, backend, options) {
19353
19910
  }
19354
19911
 
19355
19912
  export { ExecutableAggregateQuery, ExecutableQuery, MAX_EXPLICIT_RECURSIVE_DEPTH, MAX_RECURSIVE_DEPTH, PreparedQuery, QueryBuilder, RecordedStoreView, StoreSearch, StoreView, UnionableQuery, avg, composeFragments, count, countDistinct, countDistinctEdges, countEdges, createAdapterStore, createAdapterStoreWithSchema, createFragment, createQueryBuilder, createStore, createStoreWithSchema, createVerifiedAdapterStore, createVerifiedStore, defineSubgraphProject, field, having, havingEq, havingGt, havingGte, havingLt, havingLte, limitFragment, max, min, offsetFragment, orderByFragment, sum };
19356
- //# sourceMappingURL=chunk-JNXZQBN3.js.map
19357
- //# sourceMappingURL=chunk-JNXZQBN3.js.map
19913
+ //# sourceMappingURL=chunk-ID4WXTKL.js.map
19914
+ //# sourceMappingURL=chunk-ID4WXTKL.js.map