@nicia-ai/typegraph 0.41.0 → 0.42.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/drizzle/indexes.cjs +9 -9
- package/dist/backend/drizzle/indexes.d.cts +1 -2
- package/dist/backend/drizzle/indexes.d.ts +1 -2
- package/dist/backend/drizzle/indexes.js +5 -5
- package/dist/backend/index.cjs +50 -50
- package/dist/backend/index.d.cts +3 -4
- package/dist/backend/index.d.ts +3 -4
- package/dist/backend/index.js +11 -11
- package/dist/backend/postgres/index.cjs +26 -26
- package/dist/backend/postgres/index.d.cts +5 -6
- package/dist/backend/postgres/index.d.ts +5 -6
- package/dist/backend/postgres/index.js +13 -13
- package/dist/backend/postgres/pglite-store.cjs +34 -34
- package/dist/backend/postgres/pglite-store.d.cts +7 -8
- package/dist/backend/postgres/pglite-store.d.ts +7 -8
- package/dist/backend/postgres/pglite-store.js +30 -30
- package/dist/backend/postgres/pglite.cjs +15 -15
- package/dist/backend/postgres/pglite.d.cts +2 -3
- package/dist/backend/postgres/pglite.d.ts +2 -3
- package/dist/backend/postgres/pglite.js +14 -14
- package/dist/backend/sqlite/index.cjs +23 -23
- package/dist/backend/sqlite/index.d.cts +5 -6
- package/dist/backend/sqlite/index.d.ts +5 -6
- package/dist/backend/sqlite/index.js +11 -11
- package/dist/backend/sqlite/libsql.cjs +17 -17
- package/dist/backend/sqlite/libsql.d.cts +2 -3
- package/dist/backend/sqlite/libsql.d.ts +2 -3
- package/dist/backend/sqlite/libsql.js +13 -13
- package/dist/backend/sqlite/local-store.cjs +35 -35
- package/dist/backend/sqlite/local-store.d.cts +7 -8
- package/dist/backend/sqlite/local-store.d.ts +7 -8
- package/dist/backend/sqlite/local-store.js +31 -31
- package/dist/backend/sqlite/local.cjs +16 -16
- package/dist/backend/sqlite/local.d.cts +2 -3
- package/dist/backend/sqlite/local.d.ts +2 -3
- package/dist/backend/sqlite/local.js +14 -14
- package/dist/{chunk-LOKG3KQV.cjs → chunk-277UZV7X.cjs} +1113 -1089
- package/dist/chunk-277UZV7X.cjs.map +1 -0
- package/dist/{chunk-2I3DNNBU.js → chunk-2G6ZEGYO.js} +4 -4
- package/dist/{chunk-2I3DNNBU.js.map → chunk-2G6ZEGYO.js.map} +1 -1
- package/dist/{chunk-76HE7DJP.js → chunk-2HKIID5K.js} +5 -5
- package/dist/{chunk-76HE7DJP.js.map → chunk-2HKIID5K.js.map} +1 -1
- package/dist/{chunk-QOHTVDHU.js → chunk-2OOY4OYT.js} +4 -4
- package/dist/{chunk-QOHTVDHU.js.map → chunk-2OOY4OYT.js.map} +1 -1
- package/dist/{chunk-UCHW2MGP.cjs → chunk-2SO5I5AI.cjs} +196 -196
- package/dist/{chunk-UCHW2MGP.cjs.map → chunk-2SO5I5AI.cjs.map} +1 -1
- package/dist/{chunk-LFFVD5ZR.cjs → chunk-33PAKPED.cjs} +41 -41
- package/dist/{chunk-LFFVD5ZR.cjs.map → chunk-33PAKPED.cjs.map} +1 -1
- package/dist/{chunk-QCKD3RCI.cjs → chunk-3RPQDGUE.cjs} +5 -5
- package/dist/{chunk-QCKD3RCI.cjs.map → chunk-3RPQDGUE.cjs.map} +1 -1
- package/dist/{chunk-PH4IJ3V5.js → chunk-3V6D5DEC.js} +3 -3
- package/dist/{chunk-PH4IJ3V5.js.map → chunk-3V6D5DEC.js.map} +1 -1
- package/dist/{chunk-Y5UC3IXF.js → chunk-42XYPKZU.js} +3 -3
- package/dist/{chunk-Y5UC3IXF.js.map → chunk-42XYPKZU.js.map} +1 -1
- package/dist/{chunk-XZA3Y4YH.js → chunk-4WYFRACU.js} +3 -3
- package/dist/{chunk-XZA3Y4YH.js.map → chunk-4WYFRACU.js.map} +1 -1
- package/dist/{chunk-AQVDAKXH.js → chunk-4XRP2N6B.js} +3 -3
- package/dist/{chunk-AQVDAKXH.js.map → chunk-4XRP2N6B.js.map} +1 -1
- package/dist/{chunk-PWXGB77L.cjs → chunk-5AERZSHC.cjs} +4 -4
- package/dist/{chunk-PWXGB77L.cjs.map → chunk-5AERZSHC.cjs.map} +1 -1
- package/dist/{chunk-K6CD6W5J.js → chunk-5C75HQYQ.js} +5 -5
- package/dist/{chunk-K6CD6W5J.js.map → chunk-5C75HQYQ.js.map} +1 -1
- package/dist/{chunk-2J5NMMVR.cjs → chunk-5GV4JQNA.cjs} +43 -43
- package/dist/{chunk-2J5NMMVR.cjs.map → chunk-5GV4JQNA.cjs.map} +1 -1
- package/dist/{chunk-KHNKYSGP.cjs → chunk-5P6IPIT6.cjs} +41 -41
- package/dist/{chunk-KHNKYSGP.cjs.map → chunk-5P6IPIT6.cjs.map} +1 -1
- package/dist/{chunk-M2RPZS7J.cjs → chunk-5Q3P6OIC.cjs} +12 -12
- package/dist/{chunk-M2RPZS7J.cjs.map → chunk-5Q3P6OIC.cjs.map} +1 -1
- package/dist/{chunk-QXKVUJLI.cjs → chunk-5ZPRE4CV.cjs} +206 -166
- package/dist/chunk-5ZPRE4CV.cjs.map +1 -0
- package/dist/{chunk-53BSOG3O.js → chunk-6NB73BXV.js} +11 -11
- package/dist/{chunk-53BSOG3O.js.map → chunk-6NB73BXV.js.map} +1 -1
- package/dist/{chunk-SE422RES.cjs → chunk-6TJ6PKPS.cjs} +27 -27
- package/dist/{chunk-SE422RES.cjs.map → chunk-6TJ6PKPS.cjs.map} +1 -1
- package/dist/{chunk-7WLEQIHA.cjs → chunk-7Y6BV3TK.cjs} +100 -100
- package/dist/{chunk-7WLEQIHA.cjs.map → chunk-7Y6BV3TK.cjs.map} +1 -1
- package/dist/{chunk-HP6LWBLB.cjs → chunk-AO2WPYFZ.cjs} +4 -4
- package/dist/{chunk-HP6LWBLB.cjs.map → chunk-AO2WPYFZ.cjs.map} +1 -1
- package/dist/{chunk-7UTUKH4E.cjs → chunk-AQR6BHB3.cjs} +10 -10
- package/dist/{chunk-7UTUKH4E.cjs.map → chunk-AQR6BHB3.cjs.map} +1 -1
- package/dist/{chunk-X4PVHAZ6.cjs → chunk-ARN3ZODS.cjs} +6 -6
- package/dist/{chunk-X4PVHAZ6.cjs.map → chunk-ARN3ZODS.cjs.map} +1 -1
- package/dist/{chunk-YYLMXERH.js → chunk-CDYRPI5U.js} +4 -4
- package/dist/{chunk-YYLMXERH.js.map → chunk-CDYRPI5U.js.map} +1 -1
- package/dist/{chunk-3LKL3S6X.js → chunk-CI5NPLXX.js} +3 -3
- package/dist/{chunk-3LKL3S6X.js.map → chunk-CI5NPLXX.js.map} +1 -1
- package/dist/{chunk-UUIBACKJ.js → chunk-CUPJL6TS.js} +3 -3
- package/dist/{chunk-UUIBACKJ.js.map → chunk-CUPJL6TS.js.map} +1 -1
- package/dist/{chunk-JZYMOHHM.cjs → chunk-CVK4T34X.cjs} +22 -22
- package/dist/{chunk-JZYMOHHM.cjs.map → chunk-CVK4T34X.cjs.map} +1 -1
- package/dist/{chunk-L3DDZUZP.js → chunk-CVNGKTHO.js} +4 -4
- package/dist/{chunk-L3DDZUZP.js.map → chunk-CVNGKTHO.js.map} +1 -1
- package/dist/{chunk-RW24SAHI.cjs → chunk-DMZEVJGL.cjs} +13 -13
- package/dist/{chunk-RW24SAHI.cjs.map → chunk-DMZEVJGL.cjs.map} +1 -1
- package/dist/{chunk-MQBF3XGY.js → chunk-DP7KC6CL.js} +47 -23
- package/dist/chunk-DP7KC6CL.js.map +1 -0
- package/dist/{chunk-QYDUCWD2.cjs → chunk-ECU53PMN.cjs} +4 -4
- package/dist/{chunk-QYDUCWD2.cjs.map → chunk-ECU53PMN.cjs.map} +1 -1
- package/dist/{chunk-SCTZRFW5.js → chunk-EQOQOT55.js} +5 -5
- package/dist/{chunk-SCTZRFW5.js.map → chunk-EQOQOT55.js.map} +1 -1
- package/dist/{chunk-JHK6NPFV.js → chunk-EVFL2ZY5.js} +9 -9
- package/dist/{chunk-JHK6NPFV.js.map → chunk-EVFL2ZY5.js.map} +1 -1
- package/dist/{chunk-SAMJLDGG.cjs → chunk-F2KVJ6FF.cjs} +112 -112
- package/dist/{chunk-SAMJLDGG.cjs.map → chunk-F2KVJ6FF.cjs.map} +1 -1
- package/dist/{chunk-NMQ6C6TS.cjs → chunk-F7TDKSVB.cjs} +4 -4
- package/dist/{chunk-NMQ6C6TS.cjs.map → chunk-F7TDKSVB.cjs.map} +1 -1
- package/dist/{chunk-HQRZEYYB.cjs → chunk-FFQGI67R.cjs} +44 -44
- package/dist/{chunk-HQRZEYYB.cjs.map → chunk-FFQGI67R.cjs.map} +1 -1
- package/dist/{chunk-YIRLBUNN.js → chunk-FMPZPOUD.js} +3 -3
- package/dist/{chunk-YIRLBUNN.js.map → chunk-FMPZPOUD.js.map} +1 -1
- package/dist/{chunk-LL5D5T5W.cjs → chunk-FSCJOTHF.cjs} +10 -10
- package/dist/{chunk-LL5D5T5W.cjs.map → chunk-FSCJOTHF.cjs.map} +1 -1
- package/dist/{chunk-2X73QTIC.cjs → chunk-FY4VY5EV.cjs} +20 -20
- package/dist/{chunk-2X73QTIC.cjs.map → chunk-FY4VY5EV.cjs.map} +1 -1
- package/dist/{chunk-3SHAUJRB.js → chunk-GT7NEXSU.js} +3 -3
- package/dist/{chunk-3SHAUJRB.js.map → chunk-GT7NEXSU.js.map} +1 -1
- package/dist/{chunk-W66YCXWT.js → chunk-HHBKGPEI.js} +11 -10
- package/dist/chunk-HHBKGPEI.js.map +1 -0
- package/dist/{chunk-CKFBZ4LV.cjs → chunk-I73ATSAH.cjs} +4 -4
- package/dist/{chunk-CKFBZ4LV.cjs.map → chunk-I73ATSAH.cjs.map} +1 -1
- package/dist/{chunk-ELA3V6UN.js → chunk-JOYPNY33.js} +9 -9
- package/dist/{chunk-ELA3V6UN.js.map → chunk-JOYPNY33.js.map} +1 -1
- package/dist/{chunk-YIX3BEBR.cjs → chunk-K2HHCWZO.cjs} +108 -108
- package/dist/{chunk-YIX3BEBR.cjs.map → chunk-K2HHCWZO.cjs.map} +1 -1
- package/dist/{chunk-SAFZ6JTI.cjs → chunk-KTBTSHU6.cjs} +19 -2
- package/dist/chunk-KTBTSHU6.cjs.map +1 -0
- package/dist/{chunk-KOI7UEI5.js → chunk-LDCWO5B6.js} +3 -3
- package/dist/{chunk-KOI7UEI5.js.map → chunk-LDCWO5B6.js.map} +1 -1
- package/dist/{chunk-I5CRUPKO.js → chunk-LQLVJWUH.js} +7 -7
- package/dist/{chunk-I5CRUPKO.js.map → chunk-LQLVJWUH.js.map} +1 -1
- package/dist/{chunk-6N7QBIWN.js → chunk-M4GYQF2H.js} +3 -3
- package/dist/{chunk-6N7QBIWN.js.map → chunk-M4GYQF2H.js.map} +1 -1
- package/dist/{chunk-ZE7E46IZ.js → chunk-NXIZL7ZZ.js} +6 -6
- package/dist/{chunk-ZE7E46IZ.js.map → chunk-NXIZL7ZZ.js.map} +1 -1
- package/dist/{chunk-XRU7V7FF.cjs → chunk-O2GZM7UK.cjs} +7 -7
- package/dist/{chunk-XRU7V7FF.cjs.map → chunk-O2GZM7UK.cjs.map} +1 -1
- package/dist/{chunk-ZE6NVENI.js → chunk-O3USVVWS.js} +3 -3
- package/dist/{chunk-ZE6NVENI.js.map → chunk-O3USVVWS.js.map} +1 -1
- package/dist/{chunk-UDS5DZNY.cjs → chunk-O7XVCLXW.cjs} +68 -67
- package/dist/chunk-O7XVCLXW.cjs.map +1 -0
- package/dist/{chunk-KLR77R5A.cjs → chunk-OM6RIOA5.cjs} +13 -13
- package/dist/{chunk-KLR77R5A.cjs.map → chunk-OM6RIOA5.cjs.map} +1 -1
- package/dist/{chunk-LLHMAHG4.cjs → chunk-OMQ2NBOR.cjs} +27 -27
- package/dist/{chunk-LLHMAHG4.cjs.map → chunk-OMQ2NBOR.cjs.map} +1 -1
- package/dist/{chunk-DPNA466P.js → chunk-OYJSYDIH.js} +19 -3
- package/dist/chunk-OYJSYDIH.js.map +1 -0
- package/dist/{chunk-V3S74J44.js → chunk-RAWG2FEU.js} +134 -22
- package/dist/chunk-RAWG2FEU.js.map +1 -0
- package/dist/{chunk-TAUGGLNQ.js → chunk-RXOAXO3R.js} +3 -3
- package/dist/{chunk-TAUGGLNQ.js.map → chunk-RXOAXO3R.js.map} +1 -1
- package/dist/{chunk-LLE25NRD.cjs → chunk-TRC646QQ.cjs} +7 -7
- package/dist/{chunk-LLE25NRD.cjs.map → chunk-TRC646QQ.cjs.map} +1 -1
- package/dist/chunk-U3YRCZ5L.cjs +12 -0
- package/dist/{chunk-IMQKXL4E.cjs.map → chunk-U3YRCZ5L.cjs.map} +1 -1
- package/dist/{chunk-ZVME6OSV.js → chunk-UJRWOV5B.js} +5 -5
- package/dist/{chunk-ZVME6OSV.js.map → chunk-UJRWOV5B.js.map} +1 -1
- package/dist/{chunk-HAQVISUF.cjs → chunk-UTTW2Q3M.cjs} +133 -133
- package/dist/{chunk-HAQVISUF.cjs.map → chunk-UTTW2Q3M.cjs.map} +1 -1
- package/dist/{chunk-L5ET7FYQ.js → chunk-UZLEQFTV.js} +3 -3
- package/dist/{chunk-L5ET7FYQ.js.map → chunk-UZLEQFTV.js.map} +1 -1
- package/dist/{chunk-JP5EICR6.cjs → chunk-V2GZBPY2.cjs} +179 -65
- package/dist/chunk-V2GZBPY2.cjs.map +1 -0
- package/dist/{chunk-BUZWMDNL.js → chunk-VC26BUNP.js} +5 -5
- package/dist/{chunk-BUZWMDNL.js.map → chunk-VC26BUNP.js.map} +1 -1
- package/dist/chunk-VGMNGWBR.cjs +12 -0
- package/dist/{chunk-5YBDB7UG.cjs.map → chunk-VGMNGWBR.cjs.map} +1 -1
- package/dist/{chunk-XMEYZYGE.js → chunk-WYQILW5V.js} +8 -8
- package/dist/{chunk-XMEYZYGE.js.map → chunk-WYQILW5V.js.map} +1 -1
- package/dist/{chunk-YX3H63VV.cjs → chunk-X2XOQZT3.cjs} +9 -9
- package/dist/{chunk-YX3H63VV.cjs.map → chunk-X2XOQZT3.cjs.map} +1 -1
- package/dist/{chunk-N2V3HJFV.cjs → chunk-XDMPDUKL.cjs} +9 -9
- package/dist/{chunk-N2V3HJFV.cjs.map → chunk-XDMPDUKL.cjs.map} +1 -1
- package/dist/{chunk-EFZ4S22A.js → chunk-YPVQYM3L.js} +107 -67
- package/dist/chunk-YPVQYM3L.js.map +1 -0
- package/dist/{chunk-5J4VNCUD.js → chunk-Z3WIL6S3.js} +5 -5
- package/dist/{chunk-5J4VNCUD.js.map → chunk-Z3WIL6S3.js.map} +1 -1
- package/dist/{chunk-MNURF4RF.cjs → chunk-ZBV4LQD2.cjs} +4 -4
- package/dist/{chunk-MNURF4RF.cjs.map → chunk-ZBV4LQD2.cjs.map} +1 -1
- package/dist/{chunk-YGX4PMG6.js → chunk-ZGOUVMVS.js} +5 -5
- package/dist/{chunk-YGX4PMG6.js.map → chunk-ZGOUVMVS.js.map} +1 -1
- package/dist/{chunk-QZYGZVUI.js → chunk-ZIRC2U6G.js} +11 -11
- package/dist/{chunk-QZYGZVUI.js.map → chunk-ZIRC2U6G.js.map} +1 -1
- package/dist/{chunk-6QP4QXBR.js → chunk-ZOHCFYXE.js} +3 -3
- package/dist/{chunk-6QP4QXBR.js.map → chunk-ZOHCFYXE.js.map} +1 -1
- package/dist/{chunk-VWEFXG73.js → chunk-ZP2KPDNN.js} +3 -3
- package/dist/{chunk-VWEFXG73.js.map → chunk-ZP2KPDNN.js.map} +1 -1
- package/dist/{chunk-NT6ILURI.cjs → chunk-ZPCKPLMX.cjs} +8 -8
- package/dist/{chunk-NT6ILURI.cjs.map → chunk-ZPCKPLMX.cjs.map} +1 -1
- package/dist/core/index.cjs +28 -28
- package/dist/core/index.d.cts +5 -6
- package/dist/core/index.d.ts +5 -6
- package/dist/core/index.js +8 -8
- package/dist/{ddl-BCXFRLWg.d.cts → ddl-3unqC-kg.d.cts} +3 -3
- package/dist/{ddl-ByLmGgn9.d.ts → ddl-Bc4Dl8fu.d.ts} +3 -3
- package/dist/{define-graph-BSviZubs.d.ts → define-graph-Byslw2OO.d.cts} +1 -2
- package/dist/{define-graph-XyJheaFm.d.cts → define-graph-DBFnc7u_.d.ts} +1 -2
- package/dist/graph-extension/index.cjs +20 -20
- package/dist/graph-extension/index.d.cts +4 -4
- package/dist/graph-extension/index.d.ts +4 -4
- package/dist/graph-extension/index.js +5 -5
- package/dist/graph-merge/index.cjs +105 -105
- package/dist/graph-merge/index.d.cts +8 -9
- package/dist/graph-merge/index.d.ts +8 -9
- package/dist/graph-merge/index.js +25 -25
- package/dist/{index-BD_3TCgh.d.ts → index-DHXw7QAl.d.cts} +19 -4
- package/dist/{index-BihFPsPu.d.cts → index-DQzVJBHa.d.ts} +19 -4
- package/dist/index.cjs +206 -202
- package/dist/index.d.cts +13 -15
- package/dist/index.d.ts +13 -15
- package/dist/index.js +35 -35
- package/dist/indexes/index.cjs +13 -13
- package/dist/indexes/index.d.cts +4 -5
- package/dist/indexes/index.d.ts +4 -5
- package/dist/indexes/index.js +6 -6
- package/dist/interchange/index.cjs +40 -40
- package/dist/interchange/index.d.cts +9 -10
- package/dist/interchange/index.d.ts +9 -10
- package/dist/interchange/index.js +14 -14
- package/dist/{manager-C7iC5bk_.d.ts → manager-Dl0-er1G.d.ts} +21 -156
- package/dist/{manager-Dm6MCYO7.d.cts → manager-U9_zopqr.d.cts} +21 -156
- package/dist/materialize-indexes-BM3u0aXE.d.ts +258 -0
- package/dist/materialize-indexes-DzMCetZe.d.cts +258 -0
- package/dist/{postgres-DZxwzCQ8.d.cts → postgres-C5-WMKFA.d.ts} +1 -1
- package/dist/{postgres-Cb6ceh4-.d.ts → postgres-DpJqtbSX.d.cts} +1 -1
- package/dist/profiler/index.d.cts +9 -10
- package/dist/profiler/index.d.ts +9 -10
- package/dist/provenance/index.cjs +39 -39
- package/dist/provenance/index.d.cts +7 -8
- package/dist/provenance/index.d.ts +7 -8
- package/dist/provenance/index.js +9 -9
- package/dist/schema/index.cjs +48 -39
- package/dist/schema/index.d.cts +7 -8
- package/dist/schema/index.d.ts +7 -8
- package/dist/schema/index.js +15 -14
- package/dist/{searchable-aUaKh3_r.d.cts → searchable-B4mUXZT6.d.cts} +2 -2
- package/dist/{searchable-Cet4Oztt.d.ts → searchable-C7jmPNLT.d.ts} +2 -2
- package/dist/{sqlite-Cb3Ilj9_.d.ts → sqlite-Ch5tSYQY.d.ts} +1 -1
- package/dist/{sqlite-Dxklpizv.d.cts → sqlite-Da7jiYu9.d.cts} +1 -1
- package/dist/{store-view-PCT7vTKH.d.cts → store-view-6C2vTWqf.d.ts} +8 -7
- package/dist/{store-view-BDjGFjpN.d.ts → store-view-CNcOG8bQ.d.cts} +8 -7
- package/dist/{temporal-CyFsSPe8.d.ts → temporal-BtrTYTiB.d.ts} +1 -1
- package/dist/{temporal-Dn_JADWY.d.cts → temporal-CMpigMCW.d.cts} +1 -1
- package/dist/{types-CFZiEEPh.d.ts → types-D2rU5Taq.d.ts} +1 -2
- package/dist/{types-D-vOo_pM.d.ts → types-Dh-EgT-w.d.cts} +569 -2
- package/dist/{types-ho4DJJb_.d.cts → types-Dh-EgT-w.d.ts} +569 -2
- package/dist/{types-CsaG00wS.d.cts → types-G4sVM-76.d.cts} +1 -2
- package/dist/{where-DLYaXa4L.d.ts → where-B8Y21kig.d.ts} +1 -2
- package/dist/{where-udes1WRA.d.cts → where-DbZ9XDOI.d.cts} +1 -2
- package/package.json +1 -1
- package/dist/chunk-5YBDB7UG.cjs +0 -12
- package/dist/chunk-DPNA466P.js.map +0 -1
- package/dist/chunk-EFZ4S22A.js.map +0 -1
- package/dist/chunk-IMQKXL4E.cjs +0 -12
- package/dist/chunk-JP5EICR6.cjs.map +0 -1
- package/dist/chunk-LOKG3KQV.cjs.map +0 -1
- package/dist/chunk-MQBF3XGY.js.map +0 -1
- package/dist/chunk-QXKVUJLI.cjs.map +0 -1
- package/dist/chunk-SAFZ6JTI.cjs.map +0 -1
- package/dist/chunk-UDS5DZNY.cjs.map +0 -1
- package/dist/chunk-V3S74J44.js.map +0 -1
- package/dist/chunk-W66YCXWT.js.map +0 -1
- package/dist/extension-types-BLEVH4SG.d.cts +0 -571
- package/dist/extension-types-BLEVH4SG.d.ts +0 -571
- package/dist/materialize-indexes-D4iei4Kp.d.ts +0 -90
- package/dist/materialize-indexes-ExQ6OrAh.d.cts +0 -90
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkX2XOQZT3_cjs = require('./chunk-X2XOQZT3.cjs');
|
|
4
4
|
|
|
5
5
|
// src/backend/types.ts
|
|
6
6
|
function normalizeGraphAnalyticsCapabilities(capabilities) {
|
|
@@ -24,7 +24,7 @@ function isLiveNodeRow(row) {
|
|
|
24
24
|
function isTombstonedNodeRow(row) {
|
|
25
25
|
return row.deleted_at !== void 0;
|
|
26
26
|
}
|
|
27
|
-
var INTERNAL_TEMPORARY_WRITES =
|
|
27
|
+
var INTERNAL_TEMPORARY_WRITES = chunkX2XOQZT3_cjs.typeGraphGlobalSymbol(
|
|
28
28
|
"internal-temporary-writes-v1"
|
|
29
29
|
);
|
|
30
30
|
function createTransactionReadBackend(backend) {
|
|
@@ -208,5 +208,5 @@ exports.rowPropsToJsonText = rowPropsToJsonText;
|
|
|
208
208
|
exports.rowPropsToObject = rowPropsToObject;
|
|
209
209
|
exports.runOptionallyInTransaction = runOptionallyInTransaction;
|
|
210
210
|
exports.wrapWithManagedClose = wrapWithManagedClose;
|
|
211
|
-
//# sourceMappingURL=chunk-
|
|
212
|
-
//# sourceMappingURL=chunk-
|
|
211
|
+
//# sourceMappingURL=chunk-ECU53PMN.cjs.map
|
|
212
|
+
//# sourceMappingURL=chunk-ECU53PMN.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/backend/types.ts"],"names":["typeGraphGlobalSymbol"],"mappings":"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","file":"chunk-QYDUCWD2.cjs","sourcesContent":["/**\n * Backend interface types for TypeGraph storage.\n *\n * The backend abstracts database operations, allowing different\n * SQL implementations (SQLite, PostgreSQL) behind a common interface.\n */\nimport {\n type IndexEntity,\n type KindEntity,\n type TemporalMode,\n} from \"../core/types\";\nimport { type SqlTableNames } from \"../query/compiler/schema\";\nimport { type FulltextStrategy } from \"../query/dialect/fulltext-strategy\";\nimport {\n type VectorSlot,\n type VectorStrategy,\n} from \"../query/dialect/vector-strategy\";\nimport { type SqlFragment } from \"../query/sql-fragment\";\nimport {\n type CompiledRowsSql,\n type CompiledStatementSql,\n type CompiledTemporaryStatementSql,\n} from \"../query/sql-intent\";\nimport { type SerializedSchema } from \"../schema/types\";\nimport { typeGraphGlobalSymbol } from \"../utils/global-symbol\";\n\n// ============================================================\n// Vector Search Types\n// ============================================================\n\n/**\n * Supported vector similarity metrics.\n */\nexport type VectorMetric = \"cosine\" | \"l2\" | \"inner_product\";\n\n/**\n * Supported vector index types.\n */\nexport type VectorIndexType = \"hnsw\" | \"ivfflat\" | \"none\";\n\n/**\n * The mechanism a strategy uses to combine a row filter with an *approximate*\n * (ANN) vector search.\n *\n * Every approximate search TypeGraph issues carries at least one filter: the\n * liveness predicate that excludes soft-deleted and out-of-validity rows. Add\n * a `.where(...)` predicate and it narrows further. Engines differ in where\n * they apply it relative to the index traversal:\n *\n * - `\"filter-pushdown\"` — the filter constrains the ANN candidate set itself.\n * sqlite-vec's `vec0` KNN accepts primary-key `IN (SELECT …)` pushdown.\n * - `\"iterative-scan\"` — the engine re-enters the index, gathering more\n * candidates until `LIMIT` rows survive the filter *or* it hits its own scan\n * bound. pgvector >= 0.8 (`hnsw.iterative_scan` / `ivfflat.iterative_scan`,\n * applied automatically by the backend).\n * - `\"post-filter\"` — the engine retrieves a fixed multiple of the page from\n * the ANN index and applies the filter afterwards. libSQL's DiskANN\n * `vector_top_k` is a table function with no filter pushdown, so this is the\n * only shape available to it.\n *\n * This names what the strategy *asks the engine to do*. Whether the engine can\n * honor it — and whether honoring it is enough to fill a page — is\n * {@link FilteredApproximateSearch.guaranteesFullPage}.\n */\nexport type FilteredApproximateSearchMode =\n \"filter-pushdown\" | \"iterative-scan\" | \"post-filter\";\n\n/**\n * How a filtered approximate (ANN) vector search behaves, and whether it can\n * silently return fewer rows than `limit` while more matches exist.\n *\n * Read `guaranteesFullPage` — not `mode` — to decide whether a short page is\n * possible. Only `\"filter-pushdown\"` guarantees a full page:\n *\n * - **sqlite-vec** pushes the filter into the KNN. Exact.\n * - **pgvector** re-enters the index, but the iterative scan stops at\n * `hnsw.max_scan_tuples` / `ivfflat.max_probes`, and on **pgvector < 0.8**\n * there is no iterative scan at all — the backend detects that at runtime,\n * warns once, and the search stays `ef_search`-bounded, behaving like\n * `\"post-filter\"`. Neither case is visible in a statically-declared `mode`,\n * which is exactly why the guarantee is a separate field.\n * - **libSQL** over-fetches a fixed multiple of the page and filters\n * afterwards, so it under-fills once more than that headroom is filtered out.\n *\n * A store with heavy tombstone drift — routine in a temporal store — is what\n * turns a short page from a theoretical caveat into an observed one. Exact\n * (`approximate: false`) searches are unaffected on every engine: they scan, so\n * the filter reaches every row.\n */\nexport type FilteredApproximateSearch = Readonly<{\n mode: FilteredApproximateSearchMode;\n /**\n * `true` only when a filtered approximate search is guaranteed to return\n * `limit` rows whenever `limit` matching rows exist — no engine-side scan\n * bound, no version dependence, no over-fetch headroom to exhaust.\n */\n guaranteesFullPage: boolean;\n}>;\n\n/**\n * Vector search capabilities.\n */\nexport type VectorCapabilities = Readonly<{\n /** Whether the backend supports vector operations */\n supported: boolean;\n /** Supported similarity metrics */\n metrics: readonly VectorMetric[];\n /** Supported index types */\n indexTypes: readonly VectorIndexType[];\n /** Maximum dimensions supported */\n maxDimensions: number;\n /**\n * How a filtered approximate search bounds recall — and whether it can\n * silently return a short page. See {@link FilteredApproximateSearch}.\n *\n * Required, so a new vector strategy cannot omit the declaration and inherit\n * an engine promise it does not keep.\n */\n filteredApproximateSearch: FilteredApproximateSearch;\n}>;\n\n// ============================================================\n// Fulltext Search Types\n// ============================================================\n\n/**\n * Query modes for fulltext search.\n *\n * - \"websearch\": Google-style syntax (quoted phrases, +required, -excluded).\n * Postgres: `websearch_to_tsquery`. SQLite: translated to FTS5 MATCH.\n * - \"phrase\": treats the whole query as a phrase.\n * Postgres: `phraseto_tsquery`. SQLite: FTS5 `\"...\"` phrase.\n * - \"plain\": splits on whitespace and ANDs terms.\n * Postgres: `plainto_tsquery`. SQLite: default FTS5 AND.\n * - \"raw\": dialect-native syntax passed through unchanged.\n */\nexport type FulltextQueryMode = \"websearch\" | \"phrase\" | \"plain\" | \"raw\";\n\n/**\n * Fulltext search capabilities declared by a backend.\n */\nexport type FulltextCapabilities = Readonly<{\n /** Whether the backend supports fulltext operations */\n supported: boolean;\n /**\n * Language / tokenizer names understood by this backend.\n * Postgres: installed regconfigs (english, simple, ...).\n * SQLite FTS5: tokenizer names (unicode61, porter, trigram).\n */\n languages: readonly string[];\n /** Whether phrase queries are supported. */\n phraseQueries: boolean;\n /** Whether prefix (`foo*`) queries are supported. */\n prefixQueries: boolean;\n /** Whether highlighting / snippets are supported. */\n highlighting: boolean;\n}>;\n\n/**\n * Whole-graph analytics capabilities declared by a backend.\n *\n * `supported` means the backend can pin one transactional connection while\n * an algorithm creates, updates, and drops session-local temporary state.\n * `mathFunctions` records whether transcendental SQL functions needed by\n * deferred algorithms such as MCL/spectral are available; exact WCC does not\n * require them.\n */\nexport type GraphAnalyticsCapabilities = Readonly<{\n supported: boolean;\n mathFunctions: boolean;\n}>;\n\n// ============================================================\n// SQL Dialect & Capabilities\n// ============================================================\n\nimport { type SqlDialect } from \"../query/dialect/types\";\n\nexport type { SqlDialect } from \"../query/dialect/types\";\n\n/**\n * Backend capabilities that vary by dialect.\n */\nexport type BackendCapabilities = Readonly<{\n /** Whether the backend supports atomic transactions (D1 does not) */\n transactions: boolean;\n /** Whether the backend supports SQL window functions such as ROW_NUMBER() */\n windowFunctions: boolean;\n /**\n * Whether the backend's `execute()` supports `UPDATE … RETURNING`. Absent or\n * `true` means supported (every engine TypeGraph ships — SQLite ≥ 3.35,\n * PostgreSQL ≥ 8.2 — supports it). A custom backend whose engine cannot run\n * `RETURNING` must set this to `false` so recorded-time history capture\n * (`history: true`), which relies on `UPDATE … RETURNING` on its hot path,\n * is refused up front instead of failing mid-flush.\n */\n returning?: boolean;\n /**\n * Maximum number of bound parameters the engine accepts in one statement.\n * SQLite defaults to 999 (raisable at compile time via\n * `SQLITE_MAX_VARIABLE_NUMBER`), while hosted SQLite runtimes may impose a\n * lower platform ceiling; PostgreSQL's wire protocol caps it at 65535.\n * Recorded-time capture and recorded point reads size their multi-row\n * statements to this ceiling — the same budget the backend's own batched\n * inserts use — instead of a conservative dialect-blind constant. Custom\n * runtimes can override a detected or probed limit here, but hosted platform\n * hard ceilings may only be lowered. Absent means the recorded-time fallback\n * budget applies.\n */\n maxBindParameters?: number;\n /** Vector search capabilities (undefined if not configured) */\n vector?: VectorCapabilities | undefined;\n /** Fulltext search capabilities (undefined if not configured) */\n fulltext?: FulltextCapabilities | undefined;\n /** Whole-graph analytics capabilities (undefined when unavailable). */\n graphAnalytics?: GraphAnalyticsCapabilities | undefined;\n}>;\n\n/** Keeps session-scoped analytics honest when a required SQL feature is absent. */\nexport function normalizeGraphAnalyticsCapabilities(\n capabilities: BackendCapabilities,\n): BackendCapabilities {\n if (\n capabilities.graphAnalytics?.supported !== true ||\n (capabilities.transactions &&\n capabilities.windowFunctions &&\n capabilities.returning !== false)\n ) {\n return capabilities;\n }\n return {\n ...capabilities,\n graphAnalytics: { ...capabilities.graphAnalytics, supported: false },\n };\n}\n\n// ============================================================\n// Row Types (Database Records)\n// ============================================================\n\n/**\n * A node/edge row's `props` column as the driver returned it: SQLite always\n * yields the JSON text; PostgreSQL drivers yield the jsonb value already\n * parsed. Keeping the driver's shape avoids a per-row\n * parse→stringify→re-parse round trip on the PostgreSQL read path —\n * consumers normalize through {@link rowPropsToObject} /\n * {@link rowPropsToJsonText} at the point of use.\n */\nexport type RowProps = string | Readonly<Record<string, unknown>>;\n\n/** The row's props as an object, parsing only when the driver gave text. */\nexport function rowPropsToObject(props: RowProps): Record<string, unknown> {\n return typeof props === \"string\" ?\n (JSON.parse(props) as Record<string, unknown>)\n : props;\n}\n\n/** The row's props as JSON text, serializing only when the driver gave an object. */\nexport function rowPropsToJsonText(props: RowProps): string {\n return typeof props === \"string\" ? props : JSON.stringify(props);\n}\n\n/**\n * A row from the typegraph_nodes table.\n */\nexport type NodeRow = Readonly<{\n graph_id: string;\n kind: string;\n id: string;\n props: RowProps;\n version: number;\n valid_from: string | undefined;\n valid_to: string | undefined;\n created_at: string;\n updated_at: string;\n deleted_at: string | undefined;\n}>;\n\n/**\n * A {@link NodeRow} proven live (not soft-deleted). Functions that must only\n * ever touch live rows — the live-row update pipeline, soft delete — take\n * this type so a caller holding a possibly-tombstoned row is forced through\n * {@link isLiveNodeRow} first, instead of silently running live-row side\n * effects (uniqueness reservations, embedding/fulltext sync) for a row that\n * stays invisible.\n */\nexport type LiveNodeRow = NodeRow & Readonly<{ deleted_at: undefined }>;\n\n/**\n * A {@link NodeRow} proven soft-deleted. A resurrect targets exactly this\n * shape; see {@link isTombstonedNodeRow}.\n */\nexport type TombstonedNodeRow = NodeRow & Readonly<{ deleted_at: string }>;\n\nexport function isLiveNodeRow(row: NodeRow): row is LiveNodeRow {\n return row.deleted_at === undefined;\n}\n\nexport function isTombstonedNodeRow(row: NodeRow): row is TombstonedNodeRow {\n return row.deleted_at !== undefined;\n}\n\n/**\n * The read-only slice of a backend. Give this type to code that is\n * semantically a read — probes, gates, support-graph loads — so a read path\n * structurally CANNOT open a write transaction, mutate rows, or execute raw\n * SQL: those members do not exist on the type. Extend the pick as read paths\n * need more of the read surface.\n */\nexport type GraphReadBackend = Pick<\n GraphBackend,\n | \"dialect\"\n | \"getNode\"\n | \"getEdge\"\n | \"findNodesByKind\"\n | \"findEdgesByKind\"\n | \"findEdgesConnectedTo\"\n>;\n\n/**\n * A row from the typegraph_edges table.\n */\nexport type EdgeRow = Readonly<{\n graph_id: string;\n id: string;\n kind: string;\n from_kind: string;\n from_id: string;\n to_kind: string;\n to_id: string;\n props: RowProps;\n valid_from: string | undefined;\n valid_to: string | undefined;\n created_at: string;\n updated_at: string;\n deleted_at: string | undefined;\n}>;\n\n/**\n * A row from the typegraph_node_uniques table.\n */\nexport type UniqueRow = Readonly<{\n graph_id: string;\n node_kind: string;\n constraint_name: string;\n key: string;\n node_id: string;\n concrete_kind: string;\n deleted_at: string | undefined;\n}>;\n\n/**\n * A row from the typegraph_schema_versions table.\n */\nexport type SchemaVersionRow = Readonly<{\n graph_id: string;\n version: number;\n schema_hash: string;\n schema_doc: string; // JSON string\n created_at: string;\n is_active: boolean;\n}>;\n\n// ============================================================\n// Insert Parameters\n// ============================================================\n\n/**\n * Parameters for inserting a node.\n */\nexport type InsertNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n props: Readonly<Record<string, unknown>>;\n /**\n * Omitted (`undefined`): defaults to the insert's creation timestamp.\n * `null`: preserves an explicit open-left validity window (no lower\n * bound) — used by interchange import to round-trip a row that was\n * already NULL, instead of re-stamping it to the import's own timestamp.\n */\n validFrom?: string | null;\n validTo?: string;\n}>;\n\n/**\n * Parameters for updating a node.\n */\nexport type UpdateNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n props: Readonly<Record<string, unknown>>;\n validTo?: string;\n incrementVersion?: boolean;\n /** If true, clears deleted_at (un-deletes the node). Used by upsert. */\n clearDeleted?: boolean;\n}>;\n\n/**\n * Parameters for deleting a node (soft delete).\n */\nexport type DeleteNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n}>;\n\n/**\n * Parameters for inserting an edge.\n */\nexport type InsertEdgeParams = Readonly<{\n graphId: string;\n id: string;\n kind: string;\n fromKind: string;\n fromId: string;\n toKind: string;\n toId: string;\n props: Readonly<Record<string, unknown>>;\n /**\n * Omitted (`undefined`): defaults to the insert's creation timestamp.\n * `null`: preserves an explicit open-left validity window (no lower\n * bound) — used by interchange import to round-trip a row that was\n * already NULL, instead of re-stamping it to the import's own timestamp.\n */\n validFrom?: string | null;\n validTo?: string;\n}>;\n\n/**\n * Write-only session exposed inside {@link GraphBackend.trustedImport}.\n *\n * The caller has accepted the trusted-import contract: properties, endpoint\n * references, uniqueness, and cardinality are not validated. Backends may\n * therefore use engine-native ingestion primitives that bypass the normal\n * store write pipeline.\n */\nexport type TrustedImportSession = Readonly<{\n insertNodes: (params: readonly InsertNodeParams[]) => Promise<void>;\n insertEdges: (params: readonly InsertEdgeParams[]) => Promise<void>;\n}>;\n\n/**\n * Parameters for updating an edge.\n */\nexport type UpdateEdgeParams = Readonly<{\n graphId: string;\n id: string;\n props: Readonly<Record<string, unknown>>;\n validTo?: string;\n clearDeleted?: boolean;\n}>;\n\n/**\n * Parameters for deleting an edge (soft delete).\n */\nexport type DeleteEdgeParams = Readonly<{\n graphId: string;\n id: string;\n}>;\n\n/**\n * Parameters for hard deleting a node (permanent removal).\n */\nexport type HardDeleteNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n}>;\n\n/**\n * Parameters for hard deleting an edge (permanent removal).\n */\nexport type HardDeleteEdgeParams = Readonly<{\n graphId: string;\n id: string;\n}>;\n\n/** Parameters for a batched edge delete (soft or hard). */\nexport type DeleteEdgesBatchParams = Readonly<{\n graphId: string;\n ids: readonly string[];\n}>;\n\n// ============================================================\n// Embedding Parameters\n// ============================================================\n\n/**\n * Parameters for inserting or updating an embedding.\n *\n * `dimensions`, `metric`, and `indexType` together resolve the slot's\n * typed per-`(nodeKind, fieldPath)` storage (the strategy needs the fixed\n * dimension for the column type, and the metric/index type to address the\n * right ANN structure). The store populates them from the schema's\n * `embedding()` declaration via `getEmbeddingDimensions()` /\n * `getEmbeddingIndex()`; the backend constructs a `VectorSlot` from them\n * and stays graph-agnostic.\n */\nexport type UpsertEmbeddingParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n fieldPath: string;\n embedding: readonly number[];\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n}>;\n\n/**\n * One row of a batched embedding upsert.\n */\nexport type UpsertEmbeddingBatchRow = Readonly<{\n nodeId: string;\n embedding: readonly number[];\n}>;\n\n/**\n * Parameters for a batched embedding upsert. Homogeneous per vector slot:\n * one graph, one node kind, one field, many nodes. Duplicate `nodeId`\n * values within a batch are deduplicated last-write-wins by the backend\n * (a multi-row upsert cannot affect one row twice).\n */\nexport type UpsertEmbeddingBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n rows: readonly UpsertEmbeddingBatchRow[];\n}>;\n\n/**\n * Parameters for deleting an embedding.\n *\n * `dimensions` / `metric` / `indexType` mirror {@link UpsertEmbeddingParams}\n * so the backend can resolve the slot's typed per-`(nodeKind, fieldPath)`\n * storage and idempotently ensure it exists before the DELETE. That\n * matters because a delete can run before any embedding was ever written\n * (e.g. a node hard-deleted having never carried one), and on Postgres a\n * DELETE against a missing relation inside a transaction aborts the whole\n * transaction. The store populates them from the schema's `embedding()`\n * declaration, exactly as for upserts.\n */\nexport type DeleteEmbeddingParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n fieldPath: string;\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n}>;\n\n/**\n * Parameters for vector similarity search.\n */\nexport type VectorSearchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n queryEmbedding: readonly number[];\n metric: VectorMetric;\n /**\n * Fixed vector dimension `N` for the searched `(nodeKind, fieldPath)`\n * slot. The store populates it from the schema's `embedding()`\n * declaration via `getEmbeddingDimensions()`; the backend uses it to\n * construct the `VectorSlot` whose typed storage the strategy scans.\n */\n dimensions: number;\n /**\n * Index type materialized for this slot. `\"none\"` means brute-force\n * only; otherwise the strategy may route through its ANN structure.\n * The store populates it from `getEmbeddingIndex()`.\n */\n indexType: VectorIndexType;\n limit: number;\n minScore?: number;\n /**\n * Subquery of eligible node ids (single column, exposed as `node_id`).\n * When present, the search statement computes top-k over this candidate\n * set — the store passes its compiled current-read query here so\n * `where` predicates push down into the search SQL. Exact on engines\n * whose search form takes the filter inside retrieval (pgvector,\n * sqlite-vec, tsvector, FTS5); libSQL's DiskANN cannot pre-filter, so\n * it post-filters an over-fetched ANN set and recall against the\n * candidate set is bounded by that headroom. When absent, the backend\n * restricts to CURRENT nodes of the kind — non-tombstoned AND inside\n * their validity window — matching a `current` read.\n */\n candidates?: SqlFragment;\n /**\n * Rows to skip AFTER ranking (pagination). The engine fetches\n * `limit + offset` ranked candidates and discards the first `offset`.\n */\n offset?: number;\n /**\n * HNSW search frontier for this query (pgvector `hnsw.ef_search`).\n * Sizes the dynamic candidate list the index scan maintains: higher\n * trades latency for recall. The floor for the over-fetch to fill its\n * candidate set is `efSearch >= limit`; ~2–4× is the high-recall\n * target. Applied transaction-locally (`SET LOCAL`) on the Postgres\n * HNSW path only. No-op on backends without an HNSW frontier knob\n * (sqlite-vec) and ignored — with a one-time warning — on Postgres\n * backends without transactions (e.g. `drizzle-orm/neon-http`).\n */\n efSearch?: number;\n}>;\n\n/**\n * Result from a vector similarity search.\n */\nexport type VectorSearchResult = Readonly<{\n nodeId: string;\n /**\n * Cosine metric returns similarity score (higher is better).\n * L2 and inner_product return raw distance (lower is better).\n */\n score: number;\n}>;\n\n/**\n * Parameters for a single-statement hybrid (vector + fulltext, RRF-fused)\n * search. The store facade resolves every default before calling — the\n * per-source candidate depths (`k`), the fusion constants, and the shared\n * `candidates` subquery — so the backend composes `SqlFragment` values without policy.\n */\nexport type HybridSearchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n vector: Readonly<{\n fieldPath: string;\n queryEmbedding: readonly number[];\n metric: VectorMetric;\n dimensions: number;\n indexType: VectorIndexType;\n /** Candidate depth of the vector source (rows entering fusion). */\n k: number;\n minScore?: number;\n efSearch?: number;\n }>;\n fulltext: Readonly<{\n query: string;\n mode?: FulltextQueryMode;\n language?: string;\n /** Candidate depth of the fulltext source (rows entering fusion). */\n k: number;\n minScore?: number;\n includeSnippets?: boolean;\n }>;\n fusion: Readonly<{\n /** RRF rank constant (`1 / (k + rank)`). */\n k: number;\n vectorWeight: number;\n fulltextWeight: number;\n }>;\n /** Fused rows to return after `offset`. */\n limit: number;\n /** Fused rows to skip (rank-relative pagination). */\n offset?: number;\n /** See {@link VectorSearchParams.candidates}; applies to both sources. */\n candidates?: SqlFragment;\n}>;\n\n/**\n * One fused hybrid hit, hydrated in the same statement: the node row\n * rides along so the caller needs no follow-up id fetch.\n */\nexport type HybridSearchRow = Readonly<{\n node: NodeRow;\n fusedScore: number;\n vectorRank?: number;\n vectorScore?: number;\n fulltextRank?: number;\n fulltextScore?: number;\n snippet?: string;\n}>;\n\n/**\n * Parameters for creating a vector index.\n */\nexport type CreateVectorIndexParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n /** Index-specific parameters */\n indexParams?: Readonly<{\n /** HNSW: max connections per layer */\n m?: number;\n /** HNSW: construction search depth */\n efConstruction?: number;\n /** IVFFlat: number of lists */\n lists?: number;\n }>;\n /**\n * Build the index without taking an `AccessExclusiveLock` on live\n * tables (Postgres `CREATE INDEX CONCURRENTLY`). Mirrors the\n * `concurrent` flag the relational DDL path uses inside\n * `materializeIndexes()`. Cannot be set inside a transaction —\n * callers (`materializeIndexes()`) run at top level. Backends that\n * don't have a CONCURRENTLY equivalent (SQLite) ignore this flag.\n */\n concurrent?: boolean;\n}>;\n\n/**\n * Parameters for dropping a vector index.\n */\nexport type DropVectorIndexParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n}>;\n\n// ============================================================\n// Fulltext Parameters\n// ============================================================\n\n/**\n * Parameters for inserting or updating a fulltext entry.\n *\n * One row per node. Callers concatenate the searchable fields into\n * `content` so a single MATCH query can find terms spread across fields.\n *\n * Note: `createFulltextIndex` / `dropFulltextIndex` were removed as\n * dead code in #PR_E. The fulltext table's canonical index (Postgres\n * GIN on `tsv`, SQLite FTS5 virtual table) is created with the table\n * itself by `bootstrapTables` per the active `FulltextStrategy`;\n * per-kind fulltext indexes are an \"advanced strategy\" surface that\n * doesn't fit the relational-style declaration model and is reserved\n * for future work.\n */\nexport type UpsertFulltextParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n content: string;\n language: string;\n}>;\n\n/**\n * Parameters for deleting a single fulltext entry.\n */\nexport type DeleteFulltextParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n}>;\n\n/**\n * A single row in a fulltext batch upsert.\n */\nexport type FulltextBatchRow = Readonly<{\n nodeId: string;\n content: string;\n language: string;\n}>;\n\n/**\n * Parameters for a batched fulltext upsert.\n *\n * Homogeneous: one graph, one node kind, many nodes. Duplicate `nodeId`\n * values within a single batch are deduplicated last-write-wins by the\n * builders before SQL generation — Postgres `ON CONFLICT` errors on\n * repeated conflict keys in one statement, and SQLite `DELETE + INSERT`\n * would create duplicate virtual-table rows otherwise.\n */\nexport type UpsertFulltextBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n rows: readonly FulltextBatchRow[];\n}>;\n\n/**\n * Parameters for a batched fulltext delete.\n */\nexport type DeleteFulltextBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeIds: readonly string[];\n}>;\n\n/**\n * Parameters for fulltext search.\n */\nexport type FulltextSearchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n /** The user-supplied query string. */\n query: string;\n /** How to parse `query`. Default: \"websearch\". */\n mode?: FulltextQueryMode;\n /**\n * Language for query parsing. The store facade resolves the kind's\n * declared language and passes it here, so the tsquery is a plan-time\n * constant (GIN-servable); when absent the backend falls back to the\n * per-row language column.\n * Postgres: passed as the regconfig to `to_tsquery` / `websearch_to_tsquery`.\n * SQLite: informational only (FTS5 tokenizer is fixed at table-create time).\n */\n language?: string;\n /** Max rows to return. */\n limit: number;\n /** Minimum rank to include (backend-dependent units). */\n minScore?: number;\n /** Whether to return a highlighted snippet per match. */\n includeSnippets?: boolean;\n /**\n * Subquery of eligible node ids (single column). When present, the\n * search statement computes top-k over this candidate set — the store\n * passes its compiled current-read query here so `where` predicates,\n * subclass expansion, and valid-time currency all push down into the\n * search SQL. Exact on engines whose search form takes the filter\n * inside retrieval (pgvector, sqlite-vec, tsvector, FTS5); libSQL's\n * DiskANN cannot pre-filter, so it post-filters an over-fetched ANN\n * set and recall against the candidate set is bounded by that\n * headroom. When absent, the backend restricts to CURRENT nodes of\n * the kind — non-tombstoned AND inside their validity window —\n * matching a `current` read.\n */\n candidates?: SqlFragment;\n /**\n * Rows to skip AFTER ranking (pagination). The engine fetches\n * `limit + offset` ranked candidates and discards the first `offset`.\n */\n offset?: number;\n}>;\n\n/**\n * Result from a fulltext search.\n *\n * Score semantics differ by backend; prefer `rank` (1-based) when fusing\n * with another source via RRF.\n */\nexport type FulltextSearchResult = Readonly<{\n nodeId: string;\n /**\n * Backend-native relevance score.\n * Postgres: `ts_rank_cd` (higher is better).\n * SQLite FTS5: negated `bm25()` (higher is better; FTS5 returns lower-is-better).\n */\n score: number;\n /** 1-based rank within the result set, suitable for RRF. */\n rank: number;\n /** Highlighted snippet of the content (if `includeSnippets` was set). */\n snippet?: string;\n}>;\n\n/**\n * Parameters for creating a fulltext index.\n *\n * The canonical index (Postgres GIN on `tsv`, SQLite FTS5 virtual table)\n * is created when the fulltext table itself is created. This is reserved\n * for advanced per-kind specializations.\n */\n\n// ============================================================\n// Index Materialization Status\n// ============================================================\n\n/**\n * Per-deployment record for a single declared index.\n *\n * Identified by `indexName` because SQL index names are physical,\n * database-global identifiers — `graphId` is provenance, not identity.\n * `materializedAt` is null until the first successful CREATE INDEX\n * completes; `lastAttemptedAt` is always set, even on failure.\n */\n/**\n * Parameters for atomically claiming an index build (see\n * `claimIndexMaterialization`). The declaration fields ride along so a\n * fresh claim row is honest while the build is in flight.\n */\nexport type ClaimIndexMaterializationParams = Readonly<{\n indexName: string;\n graphId: string;\n entity: IndexEntity;\n kind: string;\n signature: string;\n schemaVersion: number;\n /** Opaque claim identity; release is token-guarded. */\n token: string;\n /** A claim older than this is stale and may be taken over. */\n leaseMs: number;\n}>;\n\n/** Parameters for releasing a build claim (token-guarded). */\nexport type ReleaseIndexMaterializationClaimParams = Readonly<{\n indexName: string;\n token: string;\n}>;\n\nexport type IndexMaterializationRow = Readonly<{\n indexName: string;\n graphId: string;\n entity: IndexEntity;\n kind: string;\n signature: string;\n schemaVersion: number;\n materializedAt: string | undefined;\n lastAttemptedAt: string;\n lastError: string | undefined;\n}>;\n\n/**\n * Parameters for upserting a materialization attempt.\n *\n * On success: pass `materializedAt` (ISO timestamp) and undefined `error`.\n * On failure: pass undefined `materializedAt` (preserve any existing\n * timestamp from a prior success) and the error message.\n */\nexport type RecordIndexMaterializationParams = Readonly<{\n indexName: string;\n graphId: string;\n entity: IndexEntity;\n kind: string;\n signature: string;\n schemaVersion: number;\n attemptedAt: string;\n /** ISO timestamp on success; undefined on failure (preserves existing). */\n materializedAt: string | undefined;\n /** Error message on failure; undefined on success (clears existing). */\n error: string | undefined;\n}>;\n\n// ============================================================\n// Contribution Materializations (#135 — durable strategy-owned\n// storage marker, sibling of index materializations)\n// ============================================================\n\n/**\n * Durable identity of a strategy-owned table contribution (#129),\n * scoped to a graph. This is the primary key of\n * `typegraph_contribution_materializations`.\n *\n * `logicalName` is the stable slot (\"fulltext\"); `owner` is the\n * producing strategy (\"tsvector\" / \"fts5\"); `tableName` is the resolved\n * physical name (custom per-deployment names must be distinguishable).\n * `graphId` is part of identity here — unlike the index status table\n * where the physical index name is database-global, two graphs can each\n * own a logically-identical fulltext contribution.\n */\nexport type ContributionMaterializationIdentity = Readonly<{\n graphId: string;\n logicalName: string;\n owner: string;\n tableName: string;\n}>;\n\n/**\n * Per-deployment record that a strategy-owned contribution has been\n * durably materialized against this database.\n *\n * `signature` is intentionally NOT part of the identity: a row with the\n * same identity but a different signature means \"materialized artifact\n * is stale/drifted\" — a loud error on the hot path, never a silent\n * re-materialize. `materializedAt` is undefined until the first\n * successful materialization; `lastAttemptedAt` is always set.\n */\nexport type ContributionMaterializationRow = Readonly<{\n graphId: string;\n logicalName: string;\n owner: string;\n tableName: string;\n signature: string;\n materializedAt: string | undefined;\n lastAttemptedAt: string;\n lastError: string | undefined;\n}>;\n\n/**\n * Parameters for upserting a contribution-materialization attempt.\n * Same success/failure contract as\n * {@link RecordIndexMaterializationParams}: on failure pass undefined\n * `materializedAt` so a prior successful timestamp is preserved via\n * COALESCE, and the error message.\n */\nexport type RecordContributionMaterializationParams = Readonly<{\n graphId: string;\n logicalName: string;\n owner: string;\n tableName: string;\n signature: string;\n attemptedAt: string;\n /** ISO timestamp on success; undefined on failure (preserves existing). */\n materializedAt: string | undefined;\n /** Error message on failure; undefined on success (clears existing). */\n error: string | undefined;\n}>;\n\n// ============================================================\n// Kind Removals (data-cleanup status)\n// ============================================================\n\n/**\n * One row of the per-deployment `typegraph_kind_removals` table:\n * a graph-extension kind that has been removed from the schema and whose\n * data may or may not have been cleaned up yet.\n */\nexport type KindRemovalRow = Readonly<{\n graphId: string;\n kindName: string;\n entity: KindEntity;\n schemaVersion: number;\n /** ISO timestamp when the data-cleanup pass succeeded; undefined while pending. */\n removedAt: string | undefined;\n lastAttemptedAt: string;\n lastError: string | undefined;\n}>;\n\n/**\n * Upsert payload for a kind-removal status row. On removal-commit:\n * pass `removedAt: undefined` (the pending state). On successful\n * data-cleanup: pass `removedAt` set and `error: undefined`. On\n * cleanup failure: pass `removedAt: undefined` (preserves any prior\n * timestamp from a partial success on a different replica) and the\n * error message.\n */\nexport type RecordKindRemovalParams = Readonly<{\n graphId: string;\n kindName: string;\n entity: KindEntity;\n schemaVersion: number;\n attemptedAt: string;\n /** ISO timestamp on success; undefined while pending or on failure. */\n removedAt: string | undefined;\n /** Error message on failure; undefined on success or while pending. */\n error: string | undefined;\n}>;\n\n// ============================================================\n// Query Types\n// ============================================================\n\n/** @internal Capability token for connection-local temporary writes. */\nexport const INTERNAL_TEMPORARY_WRITES: unique symbol = typeGraphGlobalSymbol(\n \"internal-temporary-writes-v1\",\n);\n\n/**\n * Transaction options.\n */\nexport type TransactionOptions = Readonly<{\n /** Transaction isolation level (if supported) */\n isolationLevel?:\n \"read_uncommitted\" | \"read_committed\" | \"repeatable_read\" | \"serializable\";\n /**\n * Transaction access mode (if supported). `read_only` is intended for\n * multi-statement reads that need one snapshot and must not perform writes.\n */\n accessMode?: \"read_only\" | \"read_write\";\n}>;\n\n/** @internal Transaction options available only to TypeGraph-owned execution. */\nexport type InternalTransactionOptions = TransactionOptions &\n Readonly<{\n /**\n * Permit writes only to connection-local temporary state. The iterative\n * operation primitive uses this when an engine rejects temporary DDL in a\n * read-only transaction.\n */\n temporaryWrites?: typeof INTERNAL_TEMPORARY_WRITES;\n }>;\n\n// ============================================================\n// Backend Interface\n// ============================================================\n\n/**\n * The GraphBackend interface abstracts database operations.\n *\n * Implementations should provide:\n * - SQLite backend via better-sqlite3 or libsql\n * - PostgreSQL backend via pg or postgres\n *\n * Every function is receiver-free (`this: void`). Implementations must close\n * over their state instead of reading `this`, which makes saved optional\n * capabilities and other detached port calls safe by construction.\n */\nexport type GraphBackend = Readonly<{\n /** The SQL dialect */\n dialect: SqlDialect;\n /** Backend capabilities */\n capabilities: BackendCapabilities;\n /** Table names used by this backend (for query schema auto-derivation) */\n tableNames?: SqlTableNames | undefined;\n /**\n * Optional fulltext strategy override. When present, both the compiler\n * (for `$fulltext.matches()` in query builder) and backend-direct\n * search paths use this instead of the dialect's default strategy —\n * allowing a Postgres backend to ship pg_trgm, ParadeDB, pgroonga etc.\n * When absent, the dialect's default strategy is used.\n */\n fulltextStrategy?: FulltextStrategy | undefined;\n /**\n * Optional vector strategy this backend is wired with. The query\n * compiler reads it (via `compileQuery` options) to emit per-`(kind,\n * field)` relevance scans for `field.similarTo(...)` predicates, and\n * the index-materialization / removal paths read its deterministic\n * `tableName(...)` to address the right physical per-field storage.\n * `undefined` when the backend has no vector support (e.g. a generic\n * SQLite backend without sqlite-vec).\n */\n vectorStrategy?: VectorStrategy | undefined;\n\n // === Node Operations ===\n insertNode: (this: void, params: InsertNodeParams) => Promise<NodeRow>;\n insertNodeNoReturn?: (this: void, params: InsertNodeParams) => Promise<void>;\n insertNodesBatch?: (\n this: void,\n params: readonly InsertNodeParams[],\n ) => Promise<void>;\n insertNodesBatchReturning?: (\n this: void,\n params: readonly InsertNodeParams[],\n ) => Promise<readonly NodeRow[]>;\n updateNode: (this: void, params: UpdateNodeParams) => Promise<NodeRow>;\n deleteNode: (this: void, params: DeleteNodeParams) => Promise<void>;\n hardDeleteNode: (this: void, params: HardDeleteNodeParams) => Promise<void>;\n getNode: (\n this: void,\n graphId: string,\n kind: string,\n id: string,\n ) => Promise<NodeRow | undefined>;\n getNodes?: (\n this: void,\n graphId: string,\n kind: string,\n ids: readonly string[],\n ) => Promise<readonly NodeRow[]>;\n\n // === Edge Operations ===\n insertEdge: (this: void, params: InsertEdgeParams) => Promise<EdgeRow>;\n insertEdgeNoReturn?: (this: void, params: InsertEdgeParams) => Promise<void>;\n insertEdgesBatch?: (\n this: void,\n params: readonly InsertEdgeParams[],\n ) => Promise<void>;\n insertEdgesBatchReturning?: (\n this: void,\n params: readonly InsertEdgeParams[],\n ) => Promise<readonly EdgeRow[]>;\n updateEdge: (this: void, params: UpdateEdgeParams) => Promise<EdgeRow>;\n deleteEdge: (this: void, params: DeleteEdgeParams) => Promise<void>;\n hardDeleteEdge: (this: void, params: HardDeleteEdgeParams) => Promise<void>;\n /**\n * Batched {@link deleteEdge}: one soft-delete statement per bind-budget\n * chunk instead of one per edge. Optional — cascade deletes fall back to\n * the per-edge form when unset. Same per-row semantics (idempotent on\n * already-tombstoned rows).\n */\n deleteEdgesBatch?: (\n this: void,\n params: DeleteEdgesBatchParams,\n ) => Promise<void>;\n /** Batched {@link hardDeleteEdge}; see {@link deleteEdgesBatch}. */\n hardDeleteEdgesBatch?: (\n this: void,\n params: DeleteEdgesBatchParams,\n ) => Promise<void>;\n getEdge: (\n this: void,\n graphId: string,\n id: string,\n ) => Promise<EdgeRow | undefined>;\n getEdges?: (\n this: void,\n graphId: string,\n ids: readonly string[],\n ) => Promise<readonly EdgeRow[]>;\n\n // === Edge Cardinality Operations ===\n countEdgesFrom: (this: void, params: CountEdgesFromParams) => Promise<number>;\n edgeExistsBetween: (\n this: void,\n params: EdgeExistsBetweenParams,\n ) => Promise<boolean>;\n\n // === Edge Query Operations ===\n findEdgesConnectedTo: (\n this: void,\n params: FindEdgesConnectedToParams,\n ) => Promise<readonly EdgeRow[]>;\n\n // === Collection Query Operations ===\n findNodesByKind: (\n this: void,\n params: FindNodesByKindParams,\n ) => Promise<readonly NodeRow[]>;\n countNodesByKind: (\n this: void,\n params: CountNodesByKindParams,\n ) => Promise<number>;\n findEdgesByKind: (\n this: void,\n params: FindEdgesByKindParams,\n ) => Promise<readonly EdgeRow[]>;\n countEdgesByKind: (\n this: void,\n params: CountEdgesByKindParams,\n ) => Promise<number>;\n\n // === Unique Constraint Operations ===\n insertUnique: (this: void, params: InsertUniqueParams) => Promise<void>;\n /**\n * Batched variant of `insertUnique`: one multi-row statement per chunk\n * with the same per-entry conflict semantics (throws `UniquenessError`\n * for the first entry whose key a different live node holds). Optional —\n * callers fall back to per-entry `insertUnique` when unset.\n */\n insertUniqueBatch?: (\n this: void,\n entries: readonly InsertUniqueParams[],\n ) => Promise<void>;\n deleteUnique: (this: void, params: DeleteUniqueParams) => Promise<void>;\n checkUnique: (\n this: void,\n params: CheckUniqueParams,\n ) => Promise<UniqueRow | undefined>;\n checkUniqueBatch?: (\n this: void,\n params: CheckUniqueBatchParams,\n ) => Promise<readonly UniqueRow[]>;\n\n // === Schema Operations ===\n getActiveSchema: (\n this: void,\n graphId: string,\n ) => Promise<SchemaVersionRow | undefined>;\n getSchemaVersion: (\n this: void,\n graphId: string,\n version: number,\n ) => Promise<SchemaVersionRow | undefined>;\n /**\n * Atomically inserts a new schema version and activates it as a single\n * transactional unit, with optimistic compare-and-swap on the currently\n * active version.\n *\n * - If `expected.kind === \"active\"` and the actual active version\n * differs, throws `StaleVersionError` (caller should refetch and\n * retry).\n * - If a row already exists at `params.version` with the same\n * `schemaHash`, returns it idempotently — reactivating it if it was\n * left inactive by an earlier crashed commit.\n * - If a row already exists at `params.version` with a different\n * `schemaHash`, throws `SchemaContentConflictError`.\n *\n * Requires `capabilities.transactions === true`. On non-transactional\n * backends (e.g. Cloudflare D1, drizzle-orm/neon-http) this method\n * throws `ConfigurationError` rather than running with degraded\n * atomicity that would silently re-introduce the orphan-row crash\n * window the primitive exists to eliminate.\n */\n commitSchemaVersion: (\n this: void,\n params: CommitSchemaVersionParams,\n ) => Promise<SchemaVersionRow>;\n /**\n * Atomically flips the active schema pointer to an existing version,\n * with optimistic compare-and-swap on the currently active version.\n * Used by `rollbackSchema` and any other \"promote/demote existing\n * version\" workflow. Throws `StaleVersionError` on CAS mismatch and\n * `MigrationError` if the target version row does not exist.\n *\n * Same transactional requirements as `commitSchemaVersion`.\n */\n setActiveVersion: (\n this: void,\n params: SetActiveVersionParams,\n ) => Promise<void>;\n\n // === Embedding Operations (optional - depends on vector capabilities) ===\n upsertEmbedding?: (\n this: void,\n params: UpsertEmbeddingParams,\n ) => Promise<void>;\n /**\n * Batched variant of `upsertEmbedding` for one vector slot. Optional —\n * callers fall back to per-row `upsertEmbedding` when unset.\n */\n upsertEmbeddingBatch?: (\n this: void,\n params: UpsertEmbeddingBatchParams,\n ) => Promise<void>;\n deleteEmbedding?: (\n this: void,\n params: DeleteEmbeddingParams,\n ) => Promise<void>;\n /**\n * KNN search over one `(nodeKind, fieldPath)` slot. Top-k is computed\n * over CURRENT nodes only — non-tombstoned AND inside their validity\n * window, matching a `current` read — so index drift (embedding rows\n * whose node was deleted or expired outside the store pipeline) can\n * neither surface nor crowd current rows out of the top-k. Custom\n * backends implementing this member must honor the same contract. Exact on pgvector >= 0.8 (HNSW via\n * `hnsw.iterative_scan = strict_order`; IVFFlat via\n * `ivfflat.iterative_scan = relaxed_order` plus a re-sort of the\n * bounded set; probe-bounded below 0.8) and sqlite-vec;\n * libSQL's DiskANN over-fetches 4x and post-filters (recall bounded by\n * that headroom).\n */\n vectorSearch?: (\n this: void,\n params: VectorSearchParams,\n ) => Promise<readonly VectorSearchResult[]>;\n createVectorIndex?: (\n this: void,\n params: CreateVectorIndexParams,\n ) => Promise<void>;\n dropVectorIndex?: (\n this: void,\n params: DropVectorIndexParams,\n ) => Promise<void>;\n /**\n * Single-statement hybrid search: both sources, RRF fusion, liveness\n * join, and node hydration composed into ONE statement — replacing the\n * facade's two search round trips plus id-hydration fetch. Optional;\n * the store falls back to the multi-statement path when unset (custom\n * backends, engines without window functions). Same liveness contract\n * as `vectorSearch` / `fulltextSearch`.\n */\n hybridSearch?: (\n this: void,\n params: HybridSearchParams,\n ) => Promise<readonly HybridSearchRow[]>;\n\n // === Fulltext Operations (optional - depends on fulltext capabilities) ===\n upsertFulltext?: (this: void, params: UpsertFulltextParams) => Promise<void>;\n deleteFulltext?: (this: void, params: DeleteFulltextParams) => Promise<void>;\n /**\n * Batched variant of `upsertFulltext`. Optional — callers fall back to\n * per-row `upsertFulltext` when unset.\n */\n upsertFulltextBatch?: (\n this: void,\n params: UpsertFulltextBatchParams,\n ) => Promise<void>;\n /**\n * Batched variant of `deleteFulltext`. Optional — callers fall back to\n * per-row `deleteFulltext` when unset.\n */\n deleteFulltextBatch?: (\n this: void,\n params: DeleteFulltextBatchParams,\n ) => Promise<void>;\n /**\n * Ranked fulltext search over one node kind. Like `vectorSearch`, top-k\n * is computed over CURRENT nodes only — non-tombstoned AND inside their\n * validity window (exact on both engines — plain WHERE, no top-k table\n * function involved). Custom backends implementing this member must\n * honor the same contract.\n */\n fulltextSearch?: (\n this: void,\n params: FulltextSearchParams,\n ) => Promise<readonly FulltextSearchResult[]>;\n\n // === Index Materialization (used by store.materializeIndexes) ===\n /**\n * Idempotently ensure ONLY the `typegraph_index_materializations`\n * table exists — separate from `bootstrapTables` so that\n * `materializeIndexes` doesn't pull in the full base-table DDL set\n * just to access the status table.\n *\n * Why focused: `bootstrapTables` issues 20+ `CREATE TABLE / CREATE\n * INDEX IF NOT EXISTS` statements covering every base table. Two\n * concurrent calls (e.g. two replicas of the same `schema_doc` both\n * starting up and calling `materializeIndexes`) race on\n * Postgres SHARE locks and DEADLOCK. Restricting the ensure-step to\n * the single status table eliminates the cross-table race entirely\n * — concurrent `CREATE TABLE IF NOT EXISTS` for one specific table\n * is well-behaved on Postgres.\n */\n ensureIndexMaterializationsTable?: (this: void) => Promise<void>;\n\n /**\n * Idempotently ensure ONLY the `typegraph_revision_origins` table exists.\n *\n * Revision-tracked stores use this per-graph, durable random origin together\n * with the recorded clock to prevent two independent stores with coincident\n * timestamps from sharing a merge base anchor. It is focused rather than\n * using `bootstrapTables` so existing deployments can adopt revision anchors\n * without replaying all base-table DDL during a merge read.\n */\n ensureRevisionOriginsTable?: (this: void) => Promise<void>;\n\n /**\n * Look up a recorded materialization for a declared index by its\n * physical SQL index name. Returns `undefined` if no row exists.\n */\n getIndexMaterialization?: (\n this: void,\n indexName: string,\n ) => Promise<IndexMaterializationRow | undefined>;\n /**\n * Bulk variant of `getIndexMaterialization`: load every recorded\n * materialization whose `indexName` (status key) is in `statusKeys`,\n * in a single round-trip. Returned rows are unordered — callers index\n * by `indexName`. Optional; consumers fall back to per-key\n * `getIndexMaterialization` when unset.\n */\n getIndexMaterializations?: (\n this: void,\n statusKeys: readonly string[],\n ) => Promise<readonly IndexMaterializationRow[]>;\n /**\n * Upsert a materialization attempt — success or failure. Failure rows\n * preserve any prior `materializedAt` so the historical successful\n * timestamp survives across error windows.\n */\n recordIndexMaterialization?: (\n this: void,\n params: RecordIndexMaterializationParams,\n ) => Promise<void>;\n /**\n * Atomically claims the build of one index across every materializer\n * (process- and pool-safe: the status row's own atomicity is the mutex).\n * Returns true when this caller now holds the claim. Backends whose\n * index builds cannot deadlock across callers (SQLite: engine-level\n * write serialization, no CONCURRENTLY) omit it; `materializeIndexes`\n * then builds without a claim, exactly as before.\n */\n claimIndexMaterialization?: (\n this: void,\n params: ClaimIndexMaterializationParams,\n ) => Promise<boolean>;\n /** Releases a claim taken by `claimIndexMaterialization` (token-guarded). */\n releaseIndexMaterializationClaim?: (\n this: void,\n params: ReleaseIndexMaterializationClaimParams,\n ) => Promise<void>;\n\n // === Contribution Materialization (#135 — durable strategy-owned\n // storage marker, sibling of the index status table) ===\n\n /**\n * Idempotently ensure ONLY the\n * `typegraph_contribution_materializations` table exists. Same\n * focused-bootstrap rationale as `ensureIndexMaterializationsTable`:\n * a single `CREATE TABLE IF NOT EXISTS` is concurrency-safe under\n * replica startup, where the full `bootstrapTables` set risks a\n * Postgres SHARE-lock deadlock.\n */\n ensureContributionMaterializationsTable?: (this: void) => Promise<void>;\n\n /**\n * Look up the durable materialization marker for one strategy-owned\n * contribution identity. Returns `undefined` when no row exists\n * (\"never initialized\").\n */\n getContributionMaterialization?: (\n this: void,\n identity: ContributionMaterializationIdentity,\n ) => Promise<ContributionMaterializationRow | undefined>;\n\n /**\n * Upsert a contribution-materialization attempt — success or failure.\n * Failure rows preserve any prior `materializedAt` via COALESCE so a\n * later failed re-attempt doesn't erase the historical success.\n */\n recordContributionMaterialization?: (\n this: void,\n params: RecordContributionMaterializationParams,\n ) => Promise<void>;\n\n /**\n * Resolve (once per backend instance, cached) and assert the durable\n * materialization markers for every `runtimeEnsure` contribution this\n * backend's strategy declares, for `graphId`. Throws\n * `StoreNotInitializedError` when a marker is missing, stale\n * (signature drift), or recorded a failed last attempt.\n *\n * This is the single read-side gate the fulltext hot-path wrappers\n * and `store.transaction()` consult. It performs ZERO DDL and ZERO\n * marker writes — initialization is the exclusive job of the async\n * boot path (`createStoreWithSchema` → `ensureRuntimeContributions`).\n */\n assertRuntimeContributionsInitialized?: (\n this: void,\n graphId: string,\n ) => Promise<void>;\n\n // === Kind Removal Status ===\n\n /**\n * Bootstraps the per-deployment `typegraph_kind_removals` table so\n * `store.removeKinds()` and `store.materializeRemovals()` can persist\n * removal status. Mirrors the focused-bootstrap rationale documented\n * on `ensureIndexMaterializationsTable` — the full `bootstrapTables`\n * touches every base table and risks Postgres SHARE-lock deadlock\n * under concurrent replica startup.\n */\n ensureKindRemovalsTable?: (this: void) => Promise<void>;\n\n /**\n * List graph-extension kind removals whose data-cleanup pass has not yet\n * succeeded for this `graphId`. Returns rows with\n * `removedAt: undefined`. Order is unspecified; callers materialize\n * one-at-a-time and don't depend on it.\n */\n getPendingKindRemovals?: (\n this: void,\n graphId: string,\n ) => Promise<readonly KindRemovalRow[]>;\n\n /**\n * List ALL kind-removal rows for a `graphId` — pending and completed.\n * Used by `materializeRemovals()` reconciliation to detect rows that\n * are missing entirely (the `removeKinds()` crash window) versus\n * already completed. Without this distinction the reconciler would\n * have to upsert every expected historical removal on every call,\n * churning `last_attempted_at` on rows that long since succeeded.\n * Order is unspecified.\n */\n getAllKindRemovals?: (\n this: void,\n graphId: string,\n ) => Promise<readonly KindRemovalRow[]>;\n\n /**\n * Upsert a kind-removal status row. `removedAt: undefined` records\n * the pending state at schema-commit time; `removedAt: <iso>`\n * marks the data cleanup successful. The COALESCE rule on `removedAt`\n * mirrors `recordIndexMaterialization` so a later failure doesn't\n * clobber the historical successful timestamp from another replica.\n */\n recordKindRemoval?: (\n this: void,\n params: RecordKindRemovalParams,\n ) => Promise<void>;\n\n // === Reconciliation Watermark ===\n\n /**\n * Bootstraps the per-deployment `typegraph_reconciliation_markers`\n * table so `materializeRemovals()` can persist reconciliation\n * progress. Same focused-bootstrap rationale as the other status\n * tables — full `bootstrapTables` risks Postgres SHARE-lock\n * deadlock under concurrent replica startup.\n */\n ensureReconciliationMarkersTable?: (this: void) => Promise<void>;\n\n // === Table Contributions (#129) ===\n\n /**\n * Materializes every contribution flagged `runtimeEnsure` — the\n * strategy-owned runtime tables (fulltext today) that drizzle-kit-\n * managed setups don't create. Called once after a successful schema\n * load. Deliberately scoped: base/drizzle-visible tables are\n * `runtimeEnsure: false`, so this does not regress startup into\n * broad DDL/probing across every table.\n *\n * The canonical durable-marker writer (#135): for each runtime\n * contribution it short-circuits when the marker already records a\n * matching signature, otherwise runs the idempotent `createDdl` and\n * records the marker (success or failure) keyed by `graphId`.\n */\n ensureRuntimeContributions?: (this: void, graphId: string) => Promise<void>;\n\n /**\n * Privileged materializer for one embedding `(kind, field)` slot's\n * `ownedTables` contribution(s): creates the per-field vector table and\n * records its durable marker, idempotently. The vector counterpart of\n * `ensureRuntimeContributions` — vectors are per-`(kind, field)` and\n * graph-derived, so the store enumerates slots (via\n * `resolveEmbeddingFields`) and uses the batch counterpart at boot under\n * the privileged role. Pass `{ force: true }` to overwrite the marker\n * at the current signature, bypassing the drift-guard — the sanctioned\n * path `store.reembedVectorField()` uses after recreating storage at a\n * new dimension. Pass `{ onDrift: \"skip\" }` to leave an\n * already-provisioned slot whose shape has since changed untouched\n * (warn + no-op) instead of refusing — the boot/evolve path, so a\n * declared dimension change never blocks startup before the operator\n * can run `reembedVectorField`. Present only on backends wired with a\n * vector strategy.\n */\n ensureVectorSlotContribution?: (\n this: void,\n slot: VectorSlot,\n options?: Readonly<{ force?: boolean; onDrift?: \"throw\" | \"skip\" }>,\n ) => Promise<void>;\n\n /**\n * Batch form of `ensureVectorSlotContribution`, used by privileged boot to\n * resolve every slot's durable markers with one graph-scoped query. The\n * singular method remains available for re-embedding and compatibility.\n */\n ensureVectorSlotContributions?: (\n this: void,\n slots: readonly VectorSlot[],\n options?: Readonly<{ force?: boolean; onDrift?: \"throw\" | \"skip\" }>,\n ) => Promise<void>;\n\n /**\n * SELECT-only gate for one embedding `(kind, field)` slot: asserts the\n * durable marker(s) for the slot's `ownedTables` contribution(s),\n * cached per backend instance. Throws `StoreNotInitializedError` when\n * the slot is missing, stale (signature drift), or recorded a failed\n * last attempt. The vector counterpart of\n * `assertRuntimeContributionsInitialized`, consulted by the verified\n * runtime attach. Performs ZERO DDL and ZERO writes. Present only on\n * backends wired with a vector strategy.\n */\n assertVectorSlotInitialized?: (this: void, slot: VectorSlot) => Promise<void>;\n\n /**\n * Batch form of `assertVectorSlotInitialized`, used by verified attach to\n * resolve every slot's durable markers with one graph-scoped query.\n */\n assertVectorSlotsInitialized?: (\n this: void,\n slots: readonly VectorSlot[],\n ) => Promise<void>;\n\n /**\n * Forget one embedding `(kind, field)` slot's durable contribution\n * marker(s). Called after the slot's per-field table is dropped\n * (vector-field reclaim) so a later `ensureVectorSlotContribution`\n * re-creates the table instead of trusting an orphaned \"initialized\"\n * marker. Does NOT drop the table itself (the caller already did).\n * Present only on backends wired with a vector strategy.\n */\n deleteVectorSlotContribution?: (\n this: void,\n slot: VectorSlot,\n ) => Promise<void>;\n\n /**\n * Bootstraps the fulltext storage table the active `FulltextStrategy`\n * owns. Same focused-bootstrap rationale as the other `ensure*Table`\n * methods: idempotent and concurrency-safe under replica startup.\n *\n * Superseded by `ensureRuntimeContributions()` (#129); retained as\n * a thin back-compat wrapper for backends/callers predating #129. Not\n * machine-`@deprecated` because the manager still calls it as the\n * pre-#129 fallback. #135 removed the remaining hot-path callers and\n * routed this through the durable-marker writer.\n */\n ensureFulltextTable?: (this: void, graphId: string) => Promise<void>;\n\n /**\n * Read the high-water mark schema version for which\n * `materializeRemovals` reconciliation has already verified history\n * for `graphId`. Returns `undefined` when no marker has been\n * recorded yet. Used to skip already-checked transitions in the\n * recovery walk.\n */\n getReconciliationMarker?: (\n this: void,\n graphId: string,\n ) => Promise<number | undefined>;\n\n /**\n * Persist the reconciliation high-water mark for `graphId`. Called\n * after `materializeRemovals` completes a clean walk; subsequent\n * calls walk only versions newer than this marker. Idempotent\n * upsert by `graphId`.\n */\n setReconciliationMarker?: (\n this: void,\n graphId: string,\n version: number,\n ) => Promise<void>;\n\n // === Graph Lifecycle ===\n /**\n * Hard-deletes all data for a graph (nodes, edges, uniques, embeddings, schema versions).\n * Intended for import-replacement workflows. No hooks, no per-row logic.\n */\n clearGraph: (this: void, graphId: string) => Promise<void>;\n\n /**\n * Creates the base TypeGraph tables if they don't already exist.\n *\n * Called automatically by `createStoreWithSchema()` when a fresh database\n * is detected. Users who manage DDL themselves via `createStore()` never\n * hit this path.\n */\n bootstrapTables?: (this: void) => Promise<void>;\n\n /**\n * Refreshes the backend's query-planner statistics.\n *\n * Call this once after a large initial import or bulk backfill. Without\n * up-to-date statistics, the planner can pick suboptimal execution plans\n * — on PostgreSQL this is the difference between a 0.5ms and a 5ms\n * forward traversal; on SQLite it's the difference between 0.9ms and\n * 23ms fulltext search. Autovacuum / background statistics collection\n * will catch up eventually, but calling this explicitly after a bulk\n * load gives you correct latencies immediately.\n *\n * Implementations:\n * - SQLite runs `ANALYZE`, which populates `sqlite_stat1`\n * - PostgreSQL runs `ANALYZE` on the TypeGraph-managed tables\n *\n * Safe to call at any time; costs a few tens of milliseconds on the\n * sizes this library is designed for.\n */\n refreshStatistics: (this: void) => Promise<void>;\n\n /**\n * Runs an intentionally trusted, all-or-nothing initial import.\n *\n * Optional because only backends that can pin one transaction and use a\n * native high-throughput write path expose it. Implementations must reject\n * a database whose TypeGraph node or edge tables already contain rows. They\n * may temporarily remove rebuildable secondary indexes, but must restore\n * them before committing. Any callback, insert, or rebuild failure rolls the\n * entire operation back.\n *\n * This is a top-level-only lifecycle operation and is deliberately absent\n * from {@link TransactionBackend}.\n */\n trustedImport?: <T>(\n this: void,\n fn: (session: TrustedImportSession) => Promise<T>,\n ) => Promise<T>;\n\n // === Query Execution ===\n execute: <T>(this: void, query: CompiledRowsSql) => Promise<readonly T[]>;\n\n /**\n * Execute a non-row-returning SQL statement bound to this backend or\n * transaction. Optional because custom backends may only expose the public\n * row-returning query path; features that need statement execution must\n * capability-check and fail loudly.\n */\n executeStatement?: (this: void, query: CompiledStatementSql) => Promise<void>;\n\n /**\n * Execute an internally compiled statement against connection-local\n * temporary state. History wrappers preserve this path because it cannot\n * mutate graph or history tables; callers cannot construct its branded\n * input through the public API.\n */\n executeTemporaryStatement?: (\n this: void,\n query: CompiledTemporaryStatementSql,\n ) => Promise<void>;\n\n /** Execute pre-compiled SQL text with bound parameters. Available on sync SQLite and pg backends. */\n executeRaw?: <T>(\n this: void,\n sqlText: string,\n params: readonly unknown[],\n ) => Promise<readonly T[]>;\n\n /** Compile a TypeGraph `SqlFragment` to `{ sql, params }` without executing. */\n compileSql?: (\n this: void,\n query: SqlFragment,\n ) => Readonly<{ sql: string; params: readonly unknown[] }>;\n\n /**\n * Execute a DDL statement that returns no rows (CREATE INDEX,\n * CREATE TABLE, ALTER TABLE, etc.). Separate from `executeRaw`\n * because some drivers (better-sqlite3) require `.run()` for DDL\n * and `.all()` for queries — the ambiguity can't be resolved by\n * inspecting the SQL string portably.\n *\n * Postgres path can use this for `CREATE INDEX CONCURRENTLY`, which\n * cannot run inside a transaction. Implementations must execute the\n * statement outside `transaction(...)`.\n */\n executeDdl?: (this: void, ddl: string) => Promise<void>;\n\n // === Transaction ===\n /** Runs TypeGraph operations inside a backend-owned transaction. */\n transaction: <T>(\n this: void,\n fn: (tx: TransactionBackend) => Promise<T>,\n options?: TransactionOptions,\n ) => Promise<T>;\n\n // === Lifecycle ===\n close: (this: void) => Promise<void>;\n}>;\n\n/**\n * Adapter-native transaction interoperability layered on top of the portable\n * TypeGraph backend. Only adapter entrypoints expose this capability.\n */\nexport type AdapterBackend<TNativeTransaction> = GraphBackend &\n Readonly<{\n /**\n * Runs TypeGraph operations and exposes the exact adapter-native handle\n * bound to the same transaction.\n */\n transactionWithNative: <T>(\n this: void,\n fn: (\n tx: TransactionBackend,\n nativeTransaction: TNativeTransaction,\n ) => Promise<T>,\n options?: TransactionOptions,\n ) => Promise<T>;\n /** Adopts a caller-owned, already-open adapter transaction. */\n adoptTransaction: (\n this: void,\n externalTransaction: TNativeTransaction,\n ) => TransactionBackend;\n }>;\n\nexport type BackendIdentity = Pick<\n GraphBackend,\n | \"dialect\"\n | \"capabilities\"\n | \"tableNames\"\n | \"fulltextStrategy\"\n | \"vectorStrategy\"\n>;\n\nexport type NodeEntityReadBackend = Pick<\n GraphBackend,\n \"getNode\" | \"getNodes\" | \"findNodesByKind\" | \"countNodesByKind\"\n>;\n\nexport type NodeEntityWriteBackend = Pick<\n GraphBackend,\n | \"insertNode\"\n | \"insertNodeNoReturn\"\n | \"insertNodesBatch\"\n | \"insertNodesBatchReturning\"\n | \"updateNode\"\n | \"deleteNode\"\n | \"hardDeleteNode\"\n>;\n\nexport type EdgeEntityReadBackend = Pick<\n GraphBackend,\n | \"getEdge\"\n | \"getEdges\"\n | \"countEdgesFrom\"\n | \"edgeExistsBetween\"\n | \"findEdgesConnectedTo\"\n | \"findEdgesByKind\"\n | \"countEdgesByKind\"\n>;\n\nexport type EdgeEntityWriteBackend = Pick<\n GraphBackend,\n | \"insertEdge\"\n | \"insertEdgeNoReturn\"\n | \"insertEdgesBatch\"\n | \"insertEdgesBatchReturning\"\n | \"updateEdge\"\n | \"deleteEdge\"\n | \"deleteEdgesBatch\"\n | \"hardDeleteEdge\"\n | \"hardDeleteEdgesBatch\"\n>;\n\nexport type GraphEntityReadBackend = NodeEntityReadBackend &\n EdgeEntityReadBackend;\n\nexport type GraphEntityWriteBackend = NodeEntityWriteBackend &\n EdgeEntityWriteBackend;\n\nexport type UniqueConstraintBackend = Pick<\n GraphBackend,\n | \"insertUnique\"\n | \"insertUniqueBatch\"\n | \"deleteUnique\"\n | \"checkUnique\"\n | \"checkUniqueBatch\"\n>;\n\nexport type SchemaReadBackend = Pick<\n GraphBackend,\n \"getActiveSchema\" | \"getSchemaVersion\"\n>;\n\nexport type SchemaCommitBackend = Pick<\n GraphBackend,\n \"commitSchemaVersion\" | \"setActiveVersion\"\n>;\n\nexport type VectorOperationBackend = Pick<\n GraphBackend,\n | \"upsertEmbedding\"\n | \"upsertEmbeddingBatch\"\n | \"deleteEmbedding\"\n | \"vectorSearch\"\n | \"createVectorIndex\"\n | \"dropVectorIndex\"\n>;\n\nexport type FulltextOperationBackend = Pick<\n GraphBackend,\n | \"upsertFulltext\"\n | \"deleteFulltext\"\n | \"upsertFulltextBatch\"\n | \"deleteFulltextBatch\"\n | \"fulltextSearch\"\n>;\n\nexport type IndexMaterializationBackend = Pick<\n GraphBackend,\n | \"ensureIndexMaterializationsTable\"\n | \"getIndexMaterialization\"\n | \"getIndexMaterializations\"\n | \"recordIndexMaterialization\"\n>;\n\nexport type ContributionMaterializationBackend = Pick<\n GraphBackend,\n | \"ensureContributionMaterializationsTable\"\n | \"getContributionMaterialization\"\n | \"recordContributionMaterialization\"\n | \"assertRuntimeContributionsInitialized\"\n | \"ensureRuntimeContributions\"\n | \"ensureFulltextTable\"\n>;\n\nexport type RemovalMaterializationBackend = Pick<\n GraphBackend,\n | \"ensureKindRemovalsTable\"\n | \"getPendingKindRemovals\"\n | \"getAllKindRemovals\"\n | \"recordKindRemoval\"\n | \"ensureReconciliationMarkersTable\"\n | \"getReconciliationMarker\"\n | \"setReconciliationMarker\"\n>;\n\nexport type GraphLifecycleBackend = Pick<\n GraphBackend,\n \"clearGraph\" | \"bootstrapTables\"\n>;\n\nexport type QueryExecutionBackend = Pick<GraphBackend, \"execute\">;\n\nexport type RawQueryExecutionBackend = Pick<\n GraphBackend,\n \"executeRaw\" | \"compileSql\"\n>;\n\nexport type SqlCompilationBackend = Pick<GraphBackend, \"compileSql\">;\n\nexport type RawStatementExecutionBackend = Pick<\n GraphBackend,\n \"executeStatement\" | \"executeTemporaryStatement\" | \"executeDdl\"\n>;\n\nexport type BackendMaintenance = Pick<GraphBackend, \"refreshStatistics\">;\n\nexport type BackendTransactions = Pick<GraphBackend, \"transaction\">;\n\nexport type AdapterBackendTransactions<TNativeTransaction> = Pick<\n AdapterBackend<TNativeTransaction>,\n \"transactionWithNative\" | \"adoptTransaction\"\n>;\n\nexport type BackendLifecycle = Pick<GraphBackend, \"close\">;\n\n/**\n * Read-oriented transaction projection exposed by portable transaction\n * contexts. It preserves snapshot-aware graph reads and TypeGraph-compiled\n * row queries while excluding graph writes, arbitrary raw SQL, DDL,\n * transaction adoption, and lifecycle control.\n */\nexport type TransactionReadBackend = Readonly<\n BackendIdentity &\n GraphEntityReadBackend &\n SchemaReadBackend &\n QueryExecutionBackend &\n SqlCompilationBackend\n>;\n\n/**\n * Transaction backend — a backend scoped to a transaction.\n *\n * This is an explicit facet composition, not `Omit<GraphBackend, ...>`.\n * New top-level-only backend methods therefore do not silently appear on\n * transaction-scoped backends. `commitSchemaVersion`, `setActiveVersion`,\n * `refreshStatistics`, `transaction`, `adoptTransaction`, and `close` stay\n * deliberately absent: their guarantees depend on the top-level backend or\n * lifecycle owner rather than an already-open transaction.\n */\nexport type TransactionBackend = Readonly<\n BackendIdentity &\n GraphEntityReadBackend &\n GraphEntityWriteBackend &\n UniqueConstraintBackend &\n SchemaReadBackend &\n VectorOperationBackend &\n FulltextOperationBackend &\n IndexMaterializationBackend &\n ContributionMaterializationBackend &\n RemovalMaterializationBackend &\n GraphLifecycleBackend &\n QueryExecutionBackend &\n RawQueryExecutionBackend &\n RawStatementExecutionBackend\n>;\n\n/**\n * Builds the actual runtime projection exposed as `TransactionContext.backend`.\n * This is an explicit object rather than a type-only narrowing so portable\n * callers cannot discover write or arbitrary-SQL methods on the underlying\n * transaction backend at runtime.\n *\n * @internal\n */\nexport function createTransactionReadBackend(\n backend: TransactionBackend,\n): TransactionReadBackend {\n const getNodes = backend.getNodes;\n const getEdges = backend.getEdges;\n const compileSql = backend.compileSql;\n\n return Object.freeze({\n dialect: backend.dialect,\n capabilities: backend.capabilities,\n ...(backend.tableNames === undefined ?\n {}\n : { tableNames: backend.tableNames }),\n ...(backend.fulltextStrategy === undefined ?\n {}\n : { fulltextStrategy: backend.fulltextStrategy }),\n ...(backend.vectorStrategy === undefined ?\n {}\n : { vectorStrategy: backend.vectorStrategy }),\n getNode: (graphId, kind, id) => backend.getNode(graphId, kind, id),\n ...(getNodes === undefined ?\n {}\n : {\n getNodes: (graphId: string, kind: string, ids: readonly string[]) =>\n getNodes(graphId, kind, ids),\n }),\n getEdge: (graphId, id) => backend.getEdge(graphId, id),\n ...(getEdges === undefined ?\n {}\n : {\n getEdges: (graphId: string, ids: readonly string[]) =>\n getEdges(graphId, ids),\n }),\n countEdgesFrom: (params) => backend.countEdgesFrom(params),\n edgeExistsBetween: (params) => backend.edgeExistsBetween(params),\n findEdgesConnectedTo: (params) => backend.findEdgesConnectedTo(params),\n findNodesByKind: (params) => backend.findNodesByKind(params),\n countNodesByKind: (params) => backend.countNodesByKind(params),\n findEdgesByKind: (params) => backend.findEdgesByKind(params),\n countEdgesByKind: (params) => backend.countEdgesByKind(params),\n getActiveSchema: (graphId) => backend.getActiveSchema(graphId),\n getSchemaVersion: (graphId, version) =>\n backend.getSchemaVersion(graphId, version),\n execute: <T>(query: CompiledRowsSql) => backend.execute<T>(query),\n ...(compileSql === undefined ?\n {}\n : { compileSql: (query: SqlFragment) => compileSql(query) }),\n });\n}\n\ntype ExactBackendOverlay<T extends object, O extends Partial<T>> = O &\n Readonly<Record<Exclude<keyof O, keyof T>, never>>;\n\n// ============================================================\n// Managed Backend Helper\n// ============================================================\n\n/**\n * Overlays selected backend methods without copying the backend object.\n *\n * This is a decoration primitive: every non-overridden target property remains\n * reachable. Never use it to narrow a capability surface; construct an\n * explicit allowlist projection first, then decorate that projection.\n *\n * Backend wrappers use this instead of object spread so proxy backends keep\n * getters and non-enumerable members. GraphBackend functions are receiver-free\n * by contract, so delegated methods are returned unchanged.\n */\nexport function createBackendOverlay<\n T extends GraphBackend | TransactionBackend,\n const O extends Partial<T> = Partial<T>,\n>(target: T, overlay: ExactBackendOverlay<T, O>): T {\n function hasOverlayProperty(property: PropertyKey): boolean {\n return Object.hasOwn(overlay, property);\n }\n\n return new Proxy(target, {\n get(targetObject, property) {\n if (hasOverlayProperty(property)) {\n return Reflect.get(overlay, property, overlay);\n }\n return Reflect.get(targetObject, property, targetObject);\n },\n\n has(targetObject, property) {\n return (\n hasOverlayProperty(property) || Reflect.has(targetObject, property)\n );\n },\n\n ownKeys(targetObject) {\n return [\n ...new Set([\n ...Reflect.ownKeys(targetObject),\n ...Reflect.ownKeys(overlay),\n ]),\n ];\n },\n\n getOwnPropertyDescriptor(targetObject, property) {\n if (hasOverlayProperty(property)) {\n const descriptor = Reflect.getOwnPropertyDescriptor(overlay, property);\n if (descriptor === undefined) return;\n return { ...descriptor, configurable: true };\n }\n return Reflect.getOwnPropertyDescriptor(targetObject, property);\n },\n\n set(targetObject, property, value) {\n if (hasOverlayProperty(property)) {\n return Reflect.set(overlay, property, value, overlay);\n }\n return Reflect.set(targetObject, property, value, targetObject);\n },\n\n defineProperty(targetObject, property, attributes) {\n if (hasOverlayProperty(property)) {\n return Reflect.defineProperty(overlay, property, attributes);\n }\n return Reflect.defineProperty(targetObject, property, attributes);\n },\n\n deleteProperty(targetObject, property) {\n if (hasOverlayProperty(property)) {\n return Reflect.deleteProperty(overlay, property);\n }\n return Reflect.deleteProperty(targetObject, property);\n },\n });\n}\n\n/**\n * Wraps a GraphBackend with idempotent close that also runs a teardown\n * callback (e.g. closing the underlying database connection).\n */\nexport function wrapWithManagedClose<TNativeTransaction>(\n backend: AdapterBackend<TNativeTransaction>,\n teardown: () => void | Promise<void>,\n): AdapterBackend<TNativeTransaction>;\nexport function wrapWithManagedClose(\n backend: GraphBackend,\n teardown: () => void | Promise<void>,\n): GraphBackend;\nexport function wrapWithManagedClose(\n backend: GraphBackend,\n teardown: () => void | Promise<void>,\n): GraphBackend {\n let backendClosed = false;\n let teardownComplete = false;\n let closeInFlight: Promise<void> | undefined;\n\n async function closeManagedResources(): Promise<void> {\n const errors: unknown[] = [];\n if (!backendClosed) {\n try {\n await backend.close();\n backendClosed = true;\n } catch (error) {\n errors.push(error);\n }\n }\n if (!teardownComplete) {\n try {\n await teardown();\n teardownComplete = true;\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) {\n throw new AggregateError(\n errors,\n \"The backend and its managed resource both failed to close.\",\n );\n }\n }\n\n const closeOverlay: Pick<GraphBackend, \"close\"> = {\n async close(): Promise<void> {\n if (backendClosed && teardownComplete) return;\n closeInFlight ??= closeManagedResources().finally(() => {\n closeInFlight = undefined;\n });\n await closeInFlight;\n },\n };\n return createBackendOverlay(backend, closeOverlay);\n}\n\n/**\n * Closes an owned resource after provisioning fails without replacing the\n * original domain error with a secondary cleanup failure.\n */\nexport async function closeAfterFailure(\n resource: Readonly<{ close: () => void | Promise<void> }>,\n provisioningError: unknown,\n): Promise<never> {\n try {\n await resource.close();\n } catch {\n // The provisioning failure remains the actionable error. Managed close is\n // retryable when the resource is returned, but a failed factory has no\n // handle it can safely expose for a second attempt.\n }\n throw provisioningError;\n}\n\n/**\n * Runs `fn` inside a transaction when given a top-level backend that supports\n * one, falling through to a direct invocation otherwise. Lets call sites benefit\n * from atomicity on backends that have transactions while staying functional on\n * backends that don't (Cloudflare D1, `drizzle-orm/neon-http` over HTTP), and\n * avoids opening nested transactions when the caller already holds a\n * transaction-scoped backend. The single-statement race window is already\n * implicit on any backend that reports `transactions: false`; callers that\n * cannot tolerate it must branch on the capability themselves.\n *\n * Pass `fallback` only when the toplevel backend method would recurse\n * — pass the operation-level backend so the no-tx path doesn't loop\n * back through the same toplevel method.\n */\nexport async function runOptionallyInTransaction<T>(\n backend: GraphBackend | TransactionBackend,\n fn: (target: GraphBackend | TransactionBackend) => Promise<T>,\n fallback?: GraphBackend | TransactionBackend,\n): Promise<T> {\n if (\"transaction\" in backend && backend.capabilities.transactions) {\n return backend.transaction((tx) => fn(tx));\n }\n return fn(fallback ?? backend);\n}\n\n// ============================================================\n// Additional Parameter Types\n// ============================================================\n\n/**\n * Parameters for inserting a unique constraint entry.\n */\nexport type InsertUniqueParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n key: string;\n nodeId: string;\n concreteKind: string;\n}>;\n\n/**\n * Parameters for deleting a unique constraint entry.\n */\nexport type DeleteUniqueParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n key: string;\n}>;\n\n/**\n * Parameters for checking a unique constraint.\n */\nexport type CheckUniqueParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n key: string;\n /** If true, also returns soft-deleted entries. Used by get-or-create operations. */\n includeDeleted?: boolean;\n}>;\n\n/**\n * Parameters for batch-checking unique constraints.\n */\nexport type CheckUniqueBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n keys: readonly string[];\n /** If true, also returns soft-deleted entries. Used by get-or-create operations. */\n includeDeleted?: boolean;\n}>;\n\n/**\n * Parameters for inserting a schema version.\n *\n * Used internally by backend implementations. Public callers go through\n * `commitSchemaVersion`, which handles the insert + activate atomically\n * with CAS guarantees.\n */\nexport type InsertSchemaParams = Readonly<{\n graphId: string;\n version: number;\n schemaHash: string;\n schemaDoc: SerializedSchema;\n isActive: boolean;\n}>;\n\n/**\n * The caller's claim about the currently-active schema version, used as\n * the optimistic compare-and-swap guard for `commitSchemaVersion`.\n *\n * - `{ kind: \"initial\" }` — caller is committing the first-ever version\n * for this graph and asserts no active version exists yet.\n * - `{ kind: \"active\", version: N }` — caller observed version N as\n * active and is committing version N+1 against that baseline. The\n * commit fails with `StaleVersionError` if some other writer has\n * advanced or rolled back the pointer in the meantime.\n *\n * Tagged-union form (rather than a magic `version: 0` sentinel) because\n * the two cases have materially different semantics: the initial path\n * skips the \"deactivate prior\" UPDATE, and the no-active-row state is\n * a *valid* expected state, not an out-of-band signal.\n */\nexport type CommitSchemaVersionExpected =\n Readonly<{ kind: \"initial\" }> | Readonly<{ kind: \"active\"; version: number }>;\n\n/**\n * Parameters for `commitSchemaVersion`.\n */\nexport type CommitSchemaVersionParams = Readonly<{\n graphId: string;\n /** CAS guard — see `CommitSchemaVersionExpected`. */\n expected: CommitSchemaVersionExpected;\n /** The new version to insert and activate. */\n version: number;\n schemaHash: string;\n schemaDoc: SerializedSchema;\n}>;\n\n/**\n * Parameters for `setActiveVersion`.\n *\n * Flips the active pointer from `expected` to `version` for an existing\n * row. CAS prevents overwriting a concurrent rollback or commit.\n */\nexport type SetActiveVersionParams = Readonly<{\n graphId: string;\n /** CAS guard. Same semantics as `commitSchemaVersion.expected`. */\n expected: CommitSchemaVersionExpected;\n /** The version to mark active. Must already exist. */\n version: number;\n}>;\n\n/**\n * Parameters for counting edges from a source node.\n */\nexport type CountEdgesFromParams = Readonly<{\n graphId: string;\n edgeKind: string;\n fromKind: string;\n fromId: string;\n /** If true, only count edges where valid_to IS NULL */\n activeOnly?: boolean;\n}>;\n\n/**\n * Parameters for checking if an edge exists between two nodes.\n */\nexport type EdgeExistsBetweenParams = Readonly<{\n graphId: string;\n edgeKind: string;\n fromKind: string;\n fromId: string;\n toKind: string;\n toId: string;\n}>;\n\n/**\n * Parameters for finding edges connected to a node.\n */\nexport type FindEdgesConnectedToParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n}>;\n\n/**\n * Parameters for finding nodes by kind.\n */\nexport type FindNodesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n /** Max rows to return. */\n limit?: number;\n /** Offset. Present for backward compat; rebuild uses `after` instead. */\n offset?: number;\n /** If true, exclude deleted nodes. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n /**\n * Stable ordering for keyset pagination. Default: \"created_at\" (existing\n * behavior). Rebuild should use \"id\" for iteration that is stable under\n * concurrent writes and shared timestamps.\n */\n orderBy?: \"id\" | \"created_at\";\n /**\n * Keyset cursor. Returns rows strictly greater (by `orderBy`) than this\n * value. When `orderBy: \"id\"`, compared lexicographically. Mutually\n * exclusive with `offset` — callers pick one.\n */\n after?: string;\n}>;\n\n/**\n * Parameters for counting nodes by kind.\n */\nexport type CountNodesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n /** If true, exclude deleted nodes. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n}>;\n\n/**\n * Parameters for finding edges by kind.\n */\nexport type FindEdgesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n fromKind?: string;\n fromId?: string;\n toKind?: string;\n toId?: string;\n limit?: number;\n offset?: number;\n /** If true, exclude deleted edges. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n /**\n * Stable ordering for keyset pagination. Default: \"created_at\" (existing\n * behavior). Use \"id\" for iteration that is stable under shared `created_at`\n * timestamps — the offset path orders by the NON-unique `created_at`, so a\n * full enumeration must page by the unique `id` to avoid skipping a row at a\n * page boundary. Mirrors {@link FindNodesByKindParams.orderBy}.\n */\n orderBy?: \"id\" | \"created_at\";\n /**\n * Keyset cursor. Returns rows strictly greater (by `orderBy`) than this value.\n * When `orderBy: \"id\"`, compared lexicographically. Mutually exclusive with\n * `offset` — callers pick one. Mirrors {@link FindNodesByKindParams.after}.\n */\n after?: string;\n}>;\n\n/**\n * Parameters for counting edges by kind.\n */\nexport type CountEdgesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n fromKind?: string;\n fromId?: string;\n toKind?: string;\n toId?: string;\n /** If true, exclude deleted edges. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n}>;\n\n// ============================================================\n// Default Capabilities\n// ============================================================\n\n/**\n * Conservative per-statement bound-parameter floor for SQLite. The\n * compiled-in `SQLITE_MAX_VARIABLE_NUMBER` defaulted to 999 before SQLite\n * 3.32.0; drivers whose real ceiling cannot be probed (async/remote\n * connections) keep this floor. Single source of truth for\n * {@link SQLITE_CAPABILITIES} and the SQLite backend's batch math fallback.\n */\nexport const SQLITE_MAX_BIND_PARAMETERS = 999;\n\n/**\n * `SQLITE_MAX_VARIABLE_NUMBER` default since SQLite 3.32.0 (better-sqlite3\n * also compiles it in explicitly). Used when a synchronous driver's probe\n * confirms a modern build.\n */\nexport const MODERN_SQLITE_MAX_BIND_PARAMETERS = 32_766;\n\n/**\n * Cloudflare D1's documented per-statement bound-parameter ceiling. Far\n * below the classic SQLite floor, so D1 detection must cap the budget or\n * batched writes fail at runtime.\n */\nexport const D1_MAX_BIND_PARAMETERS = 100;\n\n/**\n * Cloudflare SQLite-backed Durable Objects' documented per-statement\n * bound-parameter ceiling. The resolved `do-sqlite` execution profile must\n * advertise this limit so every capability-driven batch path stays below it.\n */\nexport const DURABLE_OBJECT_MAX_BIND_PARAMETERS = 100;\n\n/**\n * PostgreSQL's wire-protocol bound-parameter ceiling (a 16-bit count). Single\n * source of truth for {@link POSTGRES_CAPABILITIES} and the Postgres backend's\n * batch math.\n */\nexport const POSTGRES_MAX_BIND_PARAMETERS = 65_535;\n\n/**\n * Default capabilities for SQLite.\n */\nexport const SQLITE_CAPABILITIES: BackendCapabilities = Object.freeze({\n transactions: true, // SQLite supports transactions\n windowFunctions: true, // SQLite has supported window functions since 3.25.0\n returning: true, // SQLite has supported RETURNING since 3.35.0\n maxBindParameters: SQLITE_MAX_BIND_PARAMETERS,\n // Generic SQLite builds do not guarantee ENABLE_MATH_FUNCTIONS. The local\n // better-sqlite3 factory overrides this flag for its bundled build contract.\n graphAnalytics: Object.freeze({ supported: true, mathFunctions: false }),\n});\n\n/**\n * Default capabilities for PostgreSQL.\n */\nexport const POSTGRES_CAPABILITIES: BackendCapabilities = Object.freeze({\n transactions: true, // PostgreSQL supports transactions\n windowFunctions: true, // PostgreSQL supports ROW_NUMBER() and related windows\n returning: true, // PostgreSQL has supported RETURNING since 8.2\n maxBindParameters: POSTGRES_MAX_BIND_PARAMETERS,\n graphAnalytics: Object.freeze({ supported: true, mathFunctions: true }),\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/backend/types.ts"],"names":["typeGraphGlobalSymbol"],"mappings":"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","file":"chunk-ECU53PMN.cjs","sourcesContent":["/**\n * Backend interface types for TypeGraph storage.\n *\n * The backend abstracts database operations, allowing different\n * SQL implementations (SQLite, PostgreSQL) behind a common interface.\n */\nimport {\n type IndexEntity,\n type KindEntity,\n type TemporalMode,\n} from \"../core/types\";\nimport { type SqlTableNames } from \"../query/compiler/schema\";\nimport { type FulltextStrategy } from \"../query/dialect/fulltext-strategy\";\nimport {\n type VectorSlot,\n type VectorStrategy,\n} from \"../query/dialect/vector-strategy\";\nimport { type SqlFragment } from \"../query/sql-fragment\";\nimport {\n type CompiledRowsSql,\n type CompiledStatementSql,\n type CompiledTemporaryStatementSql,\n} from \"../query/sql-intent\";\nimport { type SerializedSchema } from \"../schema/types\";\nimport { typeGraphGlobalSymbol } from \"../utils/global-symbol\";\n\n// ============================================================\n// Vector Search Types\n// ============================================================\n\n/**\n * Supported vector similarity metrics.\n */\nexport type VectorMetric = \"cosine\" | \"l2\" | \"inner_product\";\n\n/**\n * Supported vector index types.\n */\nexport type VectorIndexType = \"hnsw\" | \"ivfflat\" | \"none\";\n\n/**\n * The mechanism a strategy uses to combine a row filter with an *approximate*\n * (ANN) vector search.\n *\n * Every approximate search TypeGraph issues carries at least one filter: the\n * liveness predicate that excludes soft-deleted and out-of-validity rows. Add\n * a `.where(...)` predicate and it narrows further. Engines differ in where\n * they apply it relative to the index traversal:\n *\n * - `\"filter-pushdown\"` — the filter constrains the ANN candidate set itself.\n * sqlite-vec's `vec0` KNN accepts primary-key `IN (SELECT …)` pushdown.\n * - `\"iterative-scan\"` — the engine re-enters the index, gathering more\n * candidates until `LIMIT` rows survive the filter *or* it hits its own scan\n * bound. pgvector >= 0.8 (`hnsw.iterative_scan` / `ivfflat.iterative_scan`,\n * applied automatically by the backend).\n * - `\"post-filter\"` — the engine retrieves a fixed multiple of the page from\n * the ANN index and applies the filter afterwards. libSQL's DiskANN\n * `vector_top_k` is a table function with no filter pushdown, so this is the\n * only shape available to it.\n *\n * This names what the strategy *asks the engine to do*. Whether the engine can\n * honor it — and whether honoring it is enough to fill a page — is\n * {@link FilteredApproximateSearch.guaranteesFullPage}.\n */\nexport type FilteredApproximateSearchMode =\n \"filter-pushdown\" | \"iterative-scan\" | \"post-filter\";\n\n/**\n * How a filtered approximate (ANN) vector search behaves, and whether it can\n * silently return fewer rows than `limit` while more matches exist.\n *\n * Read `guaranteesFullPage` — not `mode` — to decide whether a short page is\n * possible. Only `\"filter-pushdown\"` guarantees a full page:\n *\n * - **sqlite-vec** pushes the filter into the KNN. Exact.\n * - **pgvector** re-enters the index, but the iterative scan stops at\n * `hnsw.max_scan_tuples` / `ivfflat.max_probes`, and on **pgvector < 0.8**\n * there is no iterative scan at all — the backend detects that at runtime,\n * warns once, and the search stays `ef_search`-bounded, behaving like\n * `\"post-filter\"`. Neither case is visible in a statically-declared `mode`,\n * which is exactly why the guarantee is a separate field.\n * - **libSQL** over-fetches a fixed multiple of the page and filters\n * afterwards, so it under-fills once more than that headroom is filtered out.\n *\n * A store with heavy tombstone drift — routine in a temporal store — is what\n * turns a short page from a theoretical caveat into an observed one. Exact\n * (`approximate: false`) searches are unaffected on every engine: they scan, so\n * the filter reaches every row.\n */\nexport type FilteredApproximateSearch = Readonly<{\n mode: FilteredApproximateSearchMode;\n /**\n * `true` only when a filtered approximate search is guaranteed to return\n * `limit` rows whenever `limit` matching rows exist — no engine-side scan\n * bound, no version dependence, no over-fetch headroom to exhaust.\n */\n guaranteesFullPage: boolean;\n}>;\n\n/**\n * Vector search capabilities.\n */\nexport type VectorCapabilities = Readonly<{\n /** Whether the backend supports vector operations */\n supported: boolean;\n /** Supported similarity metrics */\n metrics: readonly VectorMetric[];\n /** Supported index types */\n indexTypes: readonly VectorIndexType[];\n /** Maximum dimensions supported */\n maxDimensions: number;\n /**\n * How a filtered approximate search bounds recall — and whether it can\n * silently return a short page. See {@link FilteredApproximateSearch}.\n *\n * Required, so a new vector strategy cannot omit the declaration and inherit\n * an engine promise it does not keep.\n */\n filteredApproximateSearch: FilteredApproximateSearch;\n}>;\n\n// ============================================================\n// Fulltext Search Types\n// ============================================================\n\n/**\n * Query modes for fulltext search.\n *\n * - \"websearch\": Google-style syntax (quoted phrases, +required, -excluded).\n * Postgres: `websearch_to_tsquery`. SQLite: translated to FTS5 MATCH.\n * - \"phrase\": treats the whole query as a phrase.\n * Postgres: `phraseto_tsquery`. SQLite: FTS5 `\"...\"` phrase.\n * - \"plain\": splits on whitespace and ANDs terms.\n * Postgres: `plainto_tsquery`. SQLite: default FTS5 AND.\n * - \"raw\": dialect-native syntax passed through unchanged.\n */\nexport type FulltextQueryMode = \"websearch\" | \"phrase\" | \"plain\" | \"raw\";\n\n/**\n * Fulltext search capabilities declared by a backend.\n */\nexport type FulltextCapabilities = Readonly<{\n /** Whether the backend supports fulltext operations */\n supported: boolean;\n /**\n * Language / tokenizer names understood by this backend.\n * Postgres: installed regconfigs (english, simple, ...).\n * SQLite FTS5: tokenizer names (unicode61, porter, trigram).\n */\n languages: readonly string[];\n /** Whether phrase queries are supported. */\n phraseQueries: boolean;\n /** Whether prefix (`foo*`) queries are supported. */\n prefixQueries: boolean;\n /** Whether highlighting / snippets are supported. */\n highlighting: boolean;\n}>;\n\n/**\n * Whole-graph analytics capabilities declared by a backend.\n *\n * `supported` means the backend can pin one transactional connection while\n * an algorithm creates, updates, and drops session-local temporary state.\n * `mathFunctions` records whether transcendental SQL functions needed by\n * deferred algorithms such as MCL/spectral are available; exact WCC does not\n * require them.\n */\nexport type GraphAnalyticsCapabilities = Readonly<{\n supported: boolean;\n mathFunctions: boolean;\n}>;\n\n// ============================================================\n// SQL Dialect & Capabilities\n// ============================================================\n\nimport { type SqlDialect } from \"../query/dialect/types\";\n\nexport type { SqlDialect } from \"../query/dialect/types\";\n\n/**\n * Backend capabilities that vary by dialect.\n */\nexport type BackendCapabilities = Readonly<{\n /** Whether the backend supports atomic transactions (D1 does not) */\n transactions: boolean;\n /** Whether the backend supports SQL window functions such as ROW_NUMBER() */\n windowFunctions: boolean;\n /**\n * Whether the backend's `execute()` supports `UPDATE … RETURNING`. Absent or\n * `true` means supported (every engine TypeGraph ships — SQLite ≥ 3.35,\n * PostgreSQL ≥ 8.2 — supports it). A custom backend whose engine cannot run\n * `RETURNING` must set this to `false` so recorded-time history capture\n * (`history: true`), which relies on `UPDATE … RETURNING` on its hot path,\n * is refused up front instead of failing mid-flush.\n */\n returning?: boolean;\n /**\n * Maximum number of bound parameters the engine accepts in one statement.\n * SQLite defaults to 999 (raisable at compile time via\n * `SQLITE_MAX_VARIABLE_NUMBER`), while hosted SQLite runtimes may impose a\n * lower platform ceiling; PostgreSQL's wire protocol caps it at 65535.\n * Recorded-time capture and recorded point reads size their multi-row\n * statements to this ceiling — the same budget the backend's own batched\n * inserts use — instead of a conservative dialect-blind constant. Custom\n * runtimes can override a detected or probed limit here, but hosted platform\n * hard ceilings may only be lowered. Absent means the recorded-time fallback\n * budget applies.\n */\n maxBindParameters?: number;\n /** Vector search capabilities (undefined if not configured) */\n vector?: VectorCapabilities | undefined;\n /** Fulltext search capabilities (undefined if not configured) */\n fulltext?: FulltextCapabilities | undefined;\n /** Whole-graph analytics capabilities (undefined when unavailable). */\n graphAnalytics?: GraphAnalyticsCapabilities | undefined;\n}>;\n\n/** Keeps session-scoped analytics honest when a required SQL feature is absent. */\nexport function normalizeGraphAnalyticsCapabilities(\n capabilities: BackendCapabilities,\n): BackendCapabilities {\n if (\n capabilities.graphAnalytics?.supported !== true ||\n (capabilities.transactions &&\n capabilities.windowFunctions &&\n capabilities.returning !== false)\n ) {\n return capabilities;\n }\n return {\n ...capabilities,\n graphAnalytics: { ...capabilities.graphAnalytics, supported: false },\n };\n}\n\n// ============================================================\n// Row Types (Database Records)\n// ============================================================\n\n/**\n * A node/edge row's `props` column as the driver returned it: SQLite always\n * yields the JSON text; PostgreSQL drivers yield the jsonb value already\n * parsed. Keeping the driver's shape avoids a per-row\n * parse→stringify→re-parse round trip on the PostgreSQL read path —\n * consumers normalize through {@link rowPropsToObject} /\n * {@link rowPropsToJsonText} at the point of use.\n */\nexport type RowProps = string | Readonly<Record<string, unknown>>;\n\n/** The row's props as an object, parsing only when the driver gave text. */\nexport function rowPropsToObject(props: RowProps): Record<string, unknown> {\n return typeof props === \"string\" ?\n (JSON.parse(props) as Record<string, unknown>)\n : props;\n}\n\n/** The row's props as JSON text, serializing only when the driver gave an object. */\nexport function rowPropsToJsonText(props: RowProps): string {\n return typeof props === \"string\" ? props : JSON.stringify(props);\n}\n\n/**\n * A row from the typegraph_nodes table.\n */\nexport type NodeRow = Readonly<{\n graph_id: string;\n kind: string;\n id: string;\n props: RowProps;\n version: number;\n valid_from: string | undefined;\n valid_to: string | undefined;\n created_at: string;\n updated_at: string;\n deleted_at: string | undefined;\n}>;\n\n/**\n * A {@link NodeRow} proven live (not soft-deleted). Functions that must only\n * ever touch live rows — the live-row update pipeline, soft delete — take\n * this type so a caller holding a possibly-tombstoned row is forced through\n * {@link isLiveNodeRow} first, instead of silently running live-row side\n * effects (uniqueness reservations, embedding/fulltext sync) for a row that\n * stays invisible.\n */\nexport type LiveNodeRow = NodeRow & Readonly<{ deleted_at: undefined }>;\n\n/**\n * A {@link NodeRow} proven soft-deleted. A resurrect targets exactly this\n * shape; see {@link isTombstonedNodeRow}.\n */\nexport type TombstonedNodeRow = NodeRow & Readonly<{ deleted_at: string }>;\n\nexport function isLiveNodeRow(row: NodeRow): row is LiveNodeRow {\n return row.deleted_at === undefined;\n}\n\nexport function isTombstonedNodeRow(row: NodeRow): row is TombstonedNodeRow {\n return row.deleted_at !== undefined;\n}\n\n/**\n * The read-only slice of a backend. Give this type to code that is\n * semantically a read — probes, gates, support-graph loads — so a read path\n * structurally CANNOT open a write transaction, mutate rows, or execute raw\n * SQL: those members do not exist on the type. Extend the pick as read paths\n * need more of the read surface.\n */\nexport type GraphReadBackend = Pick<\n GraphBackend,\n | \"dialect\"\n | \"getNode\"\n | \"getEdge\"\n | \"findNodesByKind\"\n | \"findEdgesByKind\"\n | \"findEdgesConnectedTo\"\n>;\n\n/**\n * A row from the typegraph_edges table.\n */\nexport type EdgeRow = Readonly<{\n graph_id: string;\n id: string;\n kind: string;\n from_kind: string;\n from_id: string;\n to_kind: string;\n to_id: string;\n props: RowProps;\n valid_from: string | undefined;\n valid_to: string | undefined;\n created_at: string;\n updated_at: string;\n deleted_at: string | undefined;\n}>;\n\n/**\n * A row from the typegraph_node_uniques table.\n */\nexport type UniqueRow = Readonly<{\n graph_id: string;\n node_kind: string;\n constraint_name: string;\n key: string;\n node_id: string;\n concrete_kind: string;\n deleted_at: string | undefined;\n}>;\n\n/**\n * A row from the typegraph_schema_versions table.\n */\nexport type SchemaVersionRow = Readonly<{\n graph_id: string;\n version: number;\n schema_hash: string;\n schema_doc: string; // JSON string\n created_at: string;\n is_active: boolean;\n}>;\n\n// ============================================================\n// Insert Parameters\n// ============================================================\n\n/**\n * Parameters for inserting a node.\n */\nexport type InsertNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n props: Readonly<Record<string, unknown>>;\n /**\n * Omitted (`undefined`): defaults to the insert's creation timestamp.\n * `null`: preserves an explicit open-left validity window (no lower\n * bound) — used by interchange import to round-trip a row that was\n * already NULL, instead of re-stamping it to the import's own timestamp.\n */\n validFrom?: string | null;\n validTo?: string;\n}>;\n\n/**\n * Parameters for updating a node.\n */\nexport type UpdateNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n props: Readonly<Record<string, unknown>>;\n validTo?: string;\n incrementVersion?: boolean;\n /** If true, clears deleted_at (un-deletes the node). Used by upsert. */\n clearDeleted?: boolean;\n}>;\n\n/**\n * Parameters for deleting a node (soft delete).\n */\nexport type DeleteNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n}>;\n\n/**\n * Parameters for inserting an edge.\n */\nexport type InsertEdgeParams = Readonly<{\n graphId: string;\n id: string;\n kind: string;\n fromKind: string;\n fromId: string;\n toKind: string;\n toId: string;\n props: Readonly<Record<string, unknown>>;\n /**\n * Omitted (`undefined`): defaults to the insert's creation timestamp.\n * `null`: preserves an explicit open-left validity window (no lower\n * bound) — used by interchange import to round-trip a row that was\n * already NULL, instead of re-stamping it to the import's own timestamp.\n */\n validFrom?: string | null;\n validTo?: string;\n}>;\n\n/**\n * Write-only session exposed inside {@link GraphBackend.trustedImport}.\n *\n * The caller has accepted the trusted-import contract: properties, endpoint\n * references, uniqueness, and cardinality are not validated. Backends may\n * therefore use engine-native ingestion primitives that bypass the normal\n * store write pipeline.\n */\nexport type TrustedImportSession = Readonly<{\n insertNodes: (params: readonly InsertNodeParams[]) => Promise<void>;\n insertEdges: (params: readonly InsertEdgeParams[]) => Promise<void>;\n}>;\n\n/**\n * Parameters for updating an edge.\n */\nexport type UpdateEdgeParams = Readonly<{\n graphId: string;\n id: string;\n props: Readonly<Record<string, unknown>>;\n validTo?: string;\n clearDeleted?: boolean;\n}>;\n\n/**\n * Parameters for deleting an edge (soft delete).\n */\nexport type DeleteEdgeParams = Readonly<{\n graphId: string;\n id: string;\n}>;\n\n/**\n * Parameters for hard deleting a node (permanent removal).\n */\nexport type HardDeleteNodeParams = Readonly<{\n graphId: string;\n kind: string;\n id: string;\n}>;\n\n/**\n * Parameters for hard deleting an edge (permanent removal).\n */\nexport type HardDeleteEdgeParams = Readonly<{\n graphId: string;\n id: string;\n}>;\n\n/** Parameters for a batched edge delete (soft or hard). */\nexport type DeleteEdgesBatchParams = Readonly<{\n graphId: string;\n ids: readonly string[];\n}>;\n\n// ============================================================\n// Embedding Parameters\n// ============================================================\n\n/**\n * Parameters for inserting or updating an embedding.\n *\n * `dimensions`, `metric`, and `indexType` together resolve the slot's\n * typed per-`(nodeKind, fieldPath)` storage (the strategy needs the fixed\n * dimension for the column type, and the metric/index type to address the\n * right ANN structure). The store populates them from the schema's\n * `embedding()` declaration via `getEmbeddingDimensions()` /\n * `getEmbeddingIndex()`; the backend constructs a `VectorSlot` from them\n * and stays graph-agnostic.\n */\nexport type UpsertEmbeddingParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n fieldPath: string;\n embedding: readonly number[];\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n}>;\n\n/**\n * One row of a batched embedding upsert.\n */\nexport type UpsertEmbeddingBatchRow = Readonly<{\n nodeId: string;\n embedding: readonly number[];\n}>;\n\n/**\n * Parameters for a batched embedding upsert. Homogeneous per vector slot:\n * one graph, one node kind, one field, many nodes. Duplicate `nodeId`\n * values within a batch are deduplicated last-write-wins by the backend\n * (a multi-row upsert cannot affect one row twice).\n */\nexport type UpsertEmbeddingBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n rows: readonly UpsertEmbeddingBatchRow[];\n}>;\n\n/**\n * Parameters for deleting an embedding.\n *\n * `dimensions` / `metric` / `indexType` mirror {@link UpsertEmbeddingParams}\n * so the backend can resolve the slot's typed per-`(nodeKind, fieldPath)`\n * storage and idempotently ensure it exists before the DELETE. That\n * matters because a delete can run before any embedding was ever written\n * (e.g. a node hard-deleted having never carried one), and on Postgres a\n * DELETE against a missing relation inside a transaction aborts the whole\n * transaction. The store populates them from the schema's `embedding()`\n * declaration, exactly as for upserts.\n */\nexport type DeleteEmbeddingParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n fieldPath: string;\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n}>;\n\n/**\n * Parameters for vector similarity search.\n */\nexport type VectorSearchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n queryEmbedding: readonly number[];\n metric: VectorMetric;\n /**\n * Fixed vector dimension `N` for the searched `(nodeKind, fieldPath)`\n * slot. The store populates it from the schema's `embedding()`\n * declaration via `getEmbeddingDimensions()`; the backend uses it to\n * construct the `VectorSlot` whose typed storage the strategy scans.\n */\n dimensions: number;\n /**\n * Index type materialized for this slot. `\"none\"` means brute-force\n * only; otherwise the strategy may route through its ANN structure.\n * The store populates it from `getEmbeddingIndex()`.\n */\n indexType: VectorIndexType;\n limit: number;\n minScore?: number;\n /**\n * Subquery of eligible node ids (single column, exposed as `node_id`).\n * When present, the search statement computes top-k over this candidate\n * set — the store passes its compiled current-read query here so\n * `where` predicates push down into the search SQL. Exact on engines\n * whose search form takes the filter inside retrieval (pgvector,\n * sqlite-vec, tsvector, FTS5); libSQL's DiskANN cannot pre-filter, so\n * it post-filters an over-fetched ANN set and recall against the\n * candidate set is bounded by that headroom. When absent, the backend\n * restricts to CURRENT nodes of the kind — non-tombstoned AND inside\n * their validity window — matching a `current` read.\n */\n candidates?: SqlFragment;\n /**\n * Rows to skip AFTER ranking (pagination). The engine fetches\n * `limit + offset` ranked candidates and discards the first `offset`.\n */\n offset?: number;\n /**\n * HNSW search frontier for this query (pgvector `hnsw.ef_search`).\n * Sizes the dynamic candidate list the index scan maintains: higher\n * trades latency for recall. The floor for the over-fetch to fill its\n * candidate set is `efSearch >= limit`; ~2–4× is the high-recall\n * target. Applied transaction-locally (`SET LOCAL`) on the Postgres\n * HNSW path only. No-op on backends without an HNSW frontier knob\n * (sqlite-vec) and ignored — with a one-time warning — on Postgres\n * backends without transactions (e.g. `drizzle-orm/neon-http`).\n */\n efSearch?: number;\n}>;\n\n/**\n * Result from a vector similarity search.\n */\nexport type VectorSearchResult = Readonly<{\n nodeId: string;\n /**\n * Cosine metric returns similarity score (higher is better).\n * L2 and inner_product return raw distance (lower is better).\n */\n score: number;\n}>;\n\n/**\n * Parameters for a single-statement hybrid (vector + fulltext, RRF-fused)\n * search. The store facade resolves every default before calling — the\n * per-source candidate depths (`k`), the fusion constants, and the shared\n * `candidates` subquery — so the backend composes `SqlFragment` values without policy.\n */\nexport type HybridSearchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n vector: Readonly<{\n fieldPath: string;\n queryEmbedding: readonly number[];\n metric: VectorMetric;\n dimensions: number;\n indexType: VectorIndexType;\n /** Candidate depth of the vector source (rows entering fusion). */\n k: number;\n minScore?: number;\n efSearch?: number;\n }>;\n fulltext: Readonly<{\n query: string;\n mode?: FulltextQueryMode;\n language?: string;\n /** Candidate depth of the fulltext source (rows entering fusion). */\n k: number;\n minScore?: number;\n includeSnippets?: boolean;\n }>;\n fusion: Readonly<{\n /** RRF rank constant (`1 / (k + rank)`). */\n k: number;\n vectorWeight: number;\n fulltextWeight: number;\n }>;\n /** Fused rows to return after `offset`. */\n limit: number;\n /** Fused rows to skip (rank-relative pagination). */\n offset?: number;\n /** See {@link VectorSearchParams.candidates}; applies to both sources. */\n candidates?: SqlFragment;\n}>;\n\n/**\n * One fused hybrid hit, hydrated in the same statement: the node row\n * rides along so the caller needs no follow-up id fetch.\n */\nexport type HybridSearchRow = Readonly<{\n node: NodeRow;\n fusedScore: number;\n vectorRank?: number;\n vectorScore?: number;\n fulltextRank?: number;\n fulltextScore?: number;\n snippet?: string;\n}>;\n\n/**\n * Parameters for creating a vector index.\n */\nexport type CreateVectorIndexParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n dimensions: number;\n metric: VectorMetric;\n indexType: VectorIndexType;\n /** Index-specific parameters */\n indexParams?: Readonly<{\n /** HNSW: max connections per layer */\n m?: number;\n /** HNSW: construction search depth */\n efConstruction?: number;\n /** IVFFlat: number of lists */\n lists?: number;\n }>;\n /**\n * Build the index without taking an `AccessExclusiveLock` on live\n * tables (Postgres `CREATE INDEX CONCURRENTLY`). Mirrors the\n * `concurrent` flag the relational DDL path uses inside\n * `materializeIndexes()`. Cannot be set inside a transaction —\n * callers (`materializeIndexes()`) run at top level. Backends that\n * don't have a CONCURRENTLY equivalent (SQLite) ignore this flag.\n */\n concurrent?: boolean;\n}>;\n\n/**\n * Parameters for dropping a vector index.\n */\nexport type DropVectorIndexParams = Readonly<{\n graphId: string;\n nodeKind: string;\n fieldPath: string;\n}>;\n\n// ============================================================\n// Fulltext Parameters\n// ============================================================\n\n/**\n * Parameters for inserting or updating a fulltext entry.\n *\n * One row per node. Callers concatenate the searchable fields into\n * `content` so a single MATCH query can find terms spread across fields.\n *\n * Note: `createFulltextIndex` / `dropFulltextIndex` were removed as\n * dead code in #PR_E. The fulltext table's canonical index (Postgres\n * GIN on `tsv`, SQLite FTS5 virtual table) is created with the table\n * itself by `bootstrapTables` per the active `FulltextStrategy`;\n * per-kind fulltext indexes are an \"advanced strategy\" surface that\n * doesn't fit the relational-style declaration model and is reserved\n * for future work.\n */\nexport type UpsertFulltextParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n content: string;\n language: string;\n}>;\n\n/**\n * Parameters for deleting a single fulltext entry.\n */\nexport type DeleteFulltextParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n}>;\n\n/**\n * A single row in a fulltext batch upsert.\n */\nexport type FulltextBatchRow = Readonly<{\n nodeId: string;\n content: string;\n language: string;\n}>;\n\n/**\n * Parameters for a batched fulltext upsert.\n *\n * Homogeneous: one graph, one node kind, many nodes. Duplicate `nodeId`\n * values within a single batch are deduplicated last-write-wins by the\n * builders before SQL generation — Postgres `ON CONFLICT` errors on\n * repeated conflict keys in one statement, and SQLite `DELETE + INSERT`\n * would create duplicate virtual-table rows otherwise.\n */\nexport type UpsertFulltextBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n rows: readonly FulltextBatchRow[];\n}>;\n\n/**\n * Parameters for a batched fulltext delete.\n */\nexport type DeleteFulltextBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeIds: readonly string[];\n}>;\n\n/**\n * Parameters for fulltext search.\n */\nexport type FulltextSearchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n /** The user-supplied query string. */\n query: string;\n /** How to parse `query`. Default: \"websearch\". */\n mode?: FulltextQueryMode;\n /**\n * Language for query parsing. The store facade resolves the kind's\n * declared language and passes it here, so the tsquery is a plan-time\n * constant (GIN-servable); when absent the backend falls back to the\n * per-row language column.\n * Postgres: passed as the regconfig to `to_tsquery` / `websearch_to_tsquery`.\n * SQLite: informational only (FTS5 tokenizer is fixed at table-create time).\n */\n language?: string;\n /** Max rows to return. */\n limit: number;\n /** Minimum rank to include (backend-dependent units). */\n minScore?: number;\n /** Whether to return a highlighted snippet per match. */\n includeSnippets?: boolean;\n /**\n * Subquery of eligible node ids (single column). When present, the\n * search statement computes top-k over this candidate set — the store\n * passes its compiled current-read query here so `where` predicates,\n * subclass expansion, and valid-time currency all push down into the\n * search SQL. Exact on engines whose search form takes the filter\n * inside retrieval (pgvector, sqlite-vec, tsvector, FTS5); libSQL's\n * DiskANN cannot pre-filter, so it post-filters an over-fetched ANN\n * set and recall against the candidate set is bounded by that\n * headroom. When absent, the backend restricts to CURRENT nodes of\n * the kind — non-tombstoned AND inside their validity window —\n * matching a `current` read.\n */\n candidates?: SqlFragment;\n /**\n * Rows to skip AFTER ranking (pagination). The engine fetches\n * `limit + offset` ranked candidates and discards the first `offset`.\n */\n offset?: number;\n}>;\n\n/**\n * Result from a fulltext search.\n *\n * Score semantics differ by backend; prefer `rank` (1-based) when fusing\n * with another source via RRF.\n */\nexport type FulltextSearchResult = Readonly<{\n nodeId: string;\n /**\n * Backend-native relevance score.\n * Postgres: `ts_rank_cd` (higher is better).\n * SQLite FTS5: negated `bm25()` (higher is better; FTS5 returns lower-is-better).\n */\n score: number;\n /** 1-based rank within the result set, suitable for RRF. */\n rank: number;\n /** Highlighted snippet of the content (if `includeSnippets` was set). */\n snippet?: string;\n}>;\n\n/**\n * Parameters for creating a fulltext index.\n *\n * The canonical index (Postgres GIN on `tsv`, SQLite FTS5 virtual table)\n * is created when the fulltext table itself is created. This is reserved\n * for advanced per-kind specializations.\n */\n\n// ============================================================\n// Index Materialization Status\n// ============================================================\n\n/**\n * Per-deployment record for a single declared index.\n *\n * Identified by `indexName` because SQL index names are physical,\n * database-global identifiers — `graphId` is provenance, not identity.\n * `materializedAt` is null until the first successful CREATE INDEX\n * completes; `lastAttemptedAt` is always set, even on failure.\n */\n/**\n * Parameters for atomically claiming an index build (see\n * `claimIndexMaterialization`). The declaration fields ride along so a\n * fresh claim row is honest while the build is in flight.\n */\nexport type ClaimIndexMaterializationParams = Readonly<{\n indexName: string;\n graphId: string;\n entity: IndexEntity;\n kind: string;\n signature: string;\n schemaVersion: number;\n /** Opaque claim identity; release is token-guarded. */\n token: string;\n /** A claim older than this is stale and may be taken over. */\n leaseMs: number;\n}>;\n\n/** Parameters for releasing a build claim (token-guarded). */\nexport type ReleaseIndexMaterializationClaimParams = Readonly<{\n indexName: string;\n token: string;\n}>;\n\nexport type IndexMaterializationRow = Readonly<{\n indexName: string;\n graphId: string;\n entity: IndexEntity;\n kind: string;\n signature: string;\n schemaVersion: number;\n materializedAt: string | undefined;\n lastAttemptedAt: string;\n lastError: string | undefined;\n}>;\n\n/**\n * Parameters for upserting a materialization attempt.\n *\n * On success: pass `materializedAt` (ISO timestamp) and undefined `error`.\n * On failure: pass undefined `materializedAt` (preserve any existing\n * timestamp from a prior success) and the error message.\n */\nexport type RecordIndexMaterializationParams = Readonly<{\n indexName: string;\n graphId: string;\n entity: IndexEntity;\n kind: string;\n signature: string;\n schemaVersion: number;\n attemptedAt: string;\n /** ISO timestamp on success; undefined on failure (preserves existing). */\n materializedAt: string | undefined;\n /** Error message on failure; undefined on success (clears existing). */\n error: string | undefined;\n}>;\n\n// ============================================================\n// Contribution Materializations (#135 — durable strategy-owned\n// storage marker, sibling of index materializations)\n// ============================================================\n\n/**\n * Durable identity of a strategy-owned table contribution (#129),\n * scoped to a graph. This is the primary key of\n * `typegraph_contribution_materializations`.\n *\n * `logicalName` is the stable slot (\"fulltext\"); `owner` is the\n * producing strategy (\"tsvector\" / \"fts5\"); `tableName` is the resolved\n * physical name (custom per-deployment names must be distinguishable).\n * `graphId` is part of identity here — unlike the index status table\n * where the physical index name is database-global, two graphs can each\n * own a logically-identical fulltext contribution.\n */\nexport type ContributionMaterializationIdentity = Readonly<{\n graphId: string;\n logicalName: string;\n owner: string;\n tableName: string;\n}>;\n\n/**\n * Per-deployment record that a strategy-owned contribution has been\n * durably materialized against this database.\n *\n * `signature` is intentionally NOT part of the identity: a row with the\n * same identity but a different signature means \"materialized artifact\n * is stale/drifted\" — a loud error on the hot path, never a silent\n * re-materialize. `materializedAt` is undefined until the first\n * successful materialization; `lastAttemptedAt` is always set.\n */\nexport type ContributionMaterializationRow = Readonly<{\n graphId: string;\n logicalName: string;\n owner: string;\n tableName: string;\n signature: string;\n materializedAt: string | undefined;\n lastAttemptedAt: string;\n lastError: string | undefined;\n}>;\n\n/**\n * Parameters for upserting a contribution-materialization attempt.\n * Same success/failure contract as\n * {@link RecordIndexMaterializationParams}: on failure pass undefined\n * `materializedAt` so a prior successful timestamp is preserved via\n * COALESCE, and the error message.\n */\nexport type RecordContributionMaterializationParams = Readonly<{\n graphId: string;\n logicalName: string;\n owner: string;\n tableName: string;\n signature: string;\n attemptedAt: string;\n /** ISO timestamp on success; undefined on failure (preserves existing). */\n materializedAt: string | undefined;\n /** Error message on failure; undefined on success (clears existing). */\n error: string | undefined;\n}>;\n\n// ============================================================\n// Kind Removals (data-cleanup status)\n// ============================================================\n\n/**\n * One row of the per-deployment `typegraph_kind_removals` table:\n * a graph-extension kind that has been removed from the schema and whose\n * data may or may not have been cleaned up yet.\n */\nexport type KindRemovalRow = Readonly<{\n graphId: string;\n kindName: string;\n entity: KindEntity;\n schemaVersion: number;\n /** ISO timestamp when the data-cleanup pass succeeded; undefined while pending. */\n removedAt: string | undefined;\n lastAttemptedAt: string;\n lastError: string | undefined;\n}>;\n\n/**\n * Upsert payload for a kind-removal status row. On removal-commit:\n * pass `removedAt: undefined` (the pending state). On successful\n * data-cleanup: pass `removedAt` set and `error: undefined`. On\n * cleanup failure: pass `removedAt: undefined` (preserves any prior\n * timestamp from a partial success on a different replica) and the\n * error message.\n */\nexport type RecordKindRemovalParams = Readonly<{\n graphId: string;\n kindName: string;\n entity: KindEntity;\n schemaVersion: number;\n attemptedAt: string;\n /** ISO timestamp on success; undefined while pending or on failure. */\n removedAt: string | undefined;\n /** Error message on failure; undefined on success or while pending. */\n error: string | undefined;\n}>;\n\n// ============================================================\n// Query Types\n// ============================================================\n\n/** @internal Capability token for connection-local temporary writes. */\nexport const INTERNAL_TEMPORARY_WRITES: unique symbol = typeGraphGlobalSymbol(\n \"internal-temporary-writes-v1\",\n);\n\n/**\n * Transaction options.\n */\nexport type TransactionOptions = Readonly<{\n /** Transaction isolation level (if supported) */\n isolationLevel?:\n \"read_uncommitted\" | \"read_committed\" | \"repeatable_read\" | \"serializable\";\n /**\n * Transaction access mode (if supported). `read_only` is intended for\n * multi-statement reads that need one snapshot and must not perform writes.\n */\n accessMode?: \"read_only\" | \"read_write\";\n}>;\n\n/** @internal Transaction options available only to TypeGraph-owned execution. */\nexport type InternalTransactionOptions = TransactionOptions &\n Readonly<{\n /**\n * Permit writes only to connection-local temporary state. The iterative\n * operation primitive uses this when an engine rejects temporary DDL in a\n * read-only transaction.\n */\n temporaryWrites?: typeof INTERNAL_TEMPORARY_WRITES;\n }>;\n\n// ============================================================\n// Backend Interface\n// ============================================================\n\n/**\n * The GraphBackend interface abstracts database operations.\n *\n * Implementations should provide:\n * - SQLite backend via better-sqlite3 or libsql\n * - PostgreSQL backend via pg or postgres\n *\n * Every function is receiver-free (`this: void`). Implementations must close\n * over their state instead of reading `this`, which makes saved optional\n * capabilities and other detached port calls safe by construction.\n */\nexport type GraphBackend = Readonly<{\n /** The SQL dialect */\n dialect: SqlDialect;\n /** Backend capabilities */\n capabilities: BackendCapabilities;\n /** Table names used by this backend (for query schema auto-derivation) */\n tableNames?: SqlTableNames | undefined;\n /**\n * Optional fulltext strategy override. When present, both the compiler\n * (for `$fulltext.matches()` in query builder) and backend-direct\n * search paths use this instead of the dialect's default strategy —\n * allowing a Postgres backend to ship pg_trgm, ParadeDB, pgroonga etc.\n * When absent, the dialect's default strategy is used.\n */\n fulltextStrategy?: FulltextStrategy | undefined;\n /**\n * Optional vector strategy this backend is wired with. The query\n * compiler reads it (via `compileQuery` options) to emit per-`(kind,\n * field)` relevance scans for `field.similarTo(...)` predicates, and\n * the index-materialization / removal paths read its deterministic\n * `tableName(...)` to address the right physical per-field storage.\n * `undefined` when the backend has no vector support (e.g. a generic\n * SQLite backend without sqlite-vec).\n */\n vectorStrategy?: VectorStrategy | undefined;\n\n // === Node Operations ===\n insertNode: (this: void, params: InsertNodeParams) => Promise<NodeRow>;\n insertNodeNoReturn?: (this: void, params: InsertNodeParams) => Promise<void>;\n insertNodesBatch?: (\n this: void,\n params: readonly InsertNodeParams[],\n ) => Promise<void>;\n insertNodesBatchReturning?: (\n this: void,\n params: readonly InsertNodeParams[],\n ) => Promise<readonly NodeRow[]>;\n updateNode: (this: void, params: UpdateNodeParams) => Promise<NodeRow>;\n deleteNode: (this: void, params: DeleteNodeParams) => Promise<void>;\n hardDeleteNode: (this: void, params: HardDeleteNodeParams) => Promise<void>;\n getNode: (\n this: void,\n graphId: string,\n kind: string,\n id: string,\n ) => Promise<NodeRow | undefined>;\n getNodes?: (\n this: void,\n graphId: string,\n kind: string,\n ids: readonly string[],\n ) => Promise<readonly NodeRow[]>;\n\n // === Edge Operations ===\n insertEdge: (this: void, params: InsertEdgeParams) => Promise<EdgeRow>;\n insertEdgeNoReturn?: (this: void, params: InsertEdgeParams) => Promise<void>;\n insertEdgesBatch?: (\n this: void,\n params: readonly InsertEdgeParams[],\n ) => Promise<void>;\n insertEdgesBatchReturning?: (\n this: void,\n params: readonly InsertEdgeParams[],\n ) => Promise<readonly EdgeRow[]>;\n updateEdge: (this: void, params: UpdateEdgeParams) => Promise<EdgeRow>;\n deleteEdge: (this: void, params: DeleteEdgeParams) => Promise<void>;\n hardDeleteEdge: (this: void, params: HardDeleteEdgeParams) => Promise<void>;\n /**\n * Batched {@link deleteEdge}: one soft-delete statement per bind-budget\n * chunk instead of one per edge. Optional — cascade deletes fall back to\n * the per-edge form when unset. Same per-row semantics (idempotent on\n * already-tombstoned rows).\n */\n deleteEdgesBatch?: (\n this: void,\n params: DeleteEdgesBatchParams,\n ) => Promise<void>;\n /** Batched {@link hardDeleteEdge}; see {@link deleteEdgesBatch}. */\n hardDeleteEdgesBatch?: (\n this: void,\n params: DeleteEdgesBatchParams,\n ) => Promise<void>;\n getEdge: (\n this: void,\n graphId: string,\n id: string,\n ) => Promise<EdgeRow | undefined>;\n getEdges?: (\n this: void,\n graphId: string,\n ids: readonly string[],\n ) => Promise<readonly EdgeRow[]>;\n\n // === Edge Cardinality Operations ===\n countEdgesFrom: (this: void, params: CountEdgesFromParams) => Promise<number>;\n edgeExistsBetween: (\n this: void,\n params: EdgeExistsBetweenParams,\n ) => Promise<boolean>;\n\n // === Edge Query Operations ===\n findEdgesConnectedTo: (\n this: void,\n params: FindEdgesConnectedToParams,\n ) => Promise<readonly EdgeRow[]>;\n\n // === Collection Query Operations ===\n findNodesByKind: (\n this: void,\n params: FindNodesByKindParams,\n ) => Promise<readonly NodeRow[]>;\n countNodesByKind: (\n this: void,\n params: CountNodesByKindParams,\n ) => Promise<number>;\n findEdgesByKind: (\n this: void,\n params: FindEdgesByKindParams,\n ) => Promise<readonly EdgeRow[]>;\n countEdgesByKind: (\n this: void,\n params: CountEdgesByKindParams,\n ) => Promise<number>;\n\n // === Unique Constraint Operations ===\n insertUnique: (this: void, params: InsertUniqueParams) => Promise<void>;\n /**\n * Batched variant of `insertUnique`: one multi-row statement per chunk\n * with the same per-entry conflict semantics (throws `UniquenessError`\n * for the first entry whose key a different live node holds). Optional —\n * callers fall back to per-entry `insertUnique` when unset.\n */\n insertUniqueBatch?: (\n this: void,\n entries: readonly InsertUniqueParams[],\n ) => Promise<void>;\n deleteUnique: (this: void, params: DeleteUniqueParams) => Promise<void>;\n checkUnique: (\n this: void,\n params: CheckUniqueParams,\n ) => Promise<UniqueRow | undefined>;\n checkUniqueBatch?: (\n this: void,\n params: CheckUniqueBatchParams,\n ) => Promise<readonly UniqueRow[]>;\n\n // === Schema Operations ===\n getActiveSchema: (\n this: void,\n graphId: string,\n ) => Promise<SchemaVersionRow | undefined>;\n getSchemaVersion: (\n this: void,\n graphId: string,\n version: number,\n ) => Promise<SchemaVersionRow | undefined>;\n /**\n * Atomically inserts a new schema version and activates it as a single\n * transactional unit, with optimistic compare-and-swap on the currently\n * active version.\n *\n * - If `expected.kind === \"active\"` and the actual active version\n * differs, throws `StaleVersionError` (caller should refetch and\n * retry).\n * - If a row already exists at `params.version` with the same\n * `schemaHash`, returns it idempotently — reactivating it if it was\n * left inactive by an earlier crashed commit.\n * - If a row already exists at `params.version` with a different\n * `schemaHash`, throws `SchemaContentConflictError`.\n *\n * Requires `capabilities.transactions === true`. On non-transactional\n * backends (e.g. Cloudflare D1, drizzle-orm/neon-http) this method\n * throws `ConfigurationError` rather than running with degraded\n * atomicity that would silently re-introduce the orphan-row crash\n * window the primitive exists to eliminate.\n */\n commitSchemaVersion: (\n this: void,\n params: CommitSchemaVersionParams,\n ) => Promise<SchemaVersionRow>;\n /**\n * Atomically flips the active schema pointer to an existing version,\n * with optimistic compare-and-swap on the currently active version.\n * Used by `rollbackSchema` and any other \"promote/demote existing\n * version\" workflow. Throws `StaleVersionError` on CAS mismatch and\n * `MigrationError` if the target version row does not exist.\n *\n * Same transactional requirements as `commitSchemaVersion`.\n */\n setActiveVersion: (\n this: void,\n params: SetActiveVersionParams,\n ) => Promise<void>;\n\n // === Embedding Operations (optional - depends on vector capabilities) ===\n upsertEmbedding?: (\n this: void,\n params: UpsertEmbeddingParams,\n ) => Promise<void>;\n /**\n * Batched variant of `upsertEmbedding` for one vector slot. Optional —\n * callers fall back to per-row `upsertEmbedding` when unset.\n */\n upsertEmbeddingBatch?: (\n this: void,\n params: UpsertEmbeddingBatchParams,\n ) => Promise<void>;\n deleteEmbedding?: (\n this: void,\n params: DeleteEmbeddingParams,\n ) => Promise<void>;\n /**\n * KNN search over one `(nodeKind, fieldPath)` slot. Top-k is computed\n * over CURRENT nodes only — non-tombstoned AND inside their validity\n * window, matching a `current` read — so index drift (embedding rows\n * whose node was deleted or expired outside the store pipeline) can\n * neither surface nor crowd current rows out of the top-k. Custom\n * backends implementing this member must honor the same contract. Exact on pgvector >= 0.8 (HNSW via\n * `hnsw.iterative_scan = strict_order`; IVFFlat via\n * `ivfflat.iterative_scan = relaxed_order` plus a re-sort of the\n * bounded set; probe-bounded below 0.8) and sqlite-vec;\n * libSQL's DiskANN over-fetches 4x and post-filters (recall bounded by\n * that headroom).\n */\n vectorSearch?: (\n this: void,\n params: VectorSearchParams,\n ) => Promise<readonly VectorSearchResult[]>;\n createVectorIndex?: (\n this: void,\n params: CreateVectorIndexParams,\n ) => Promise<void>;\n dropVectorIndex?: (\n this: void,\n params: DropVectorIndexParams,\n ) => Promise<void>;\n /**\n * Single-statement hybrid search: both sources, RRF fusion, liveness\n * join, and node hydration composed into ONE statement — replacing the\n * facade's two search round trips plus id-hydration fetch. Optional;\n * the store falls back to the multi-statement path when unset (custom\n * backends, engines without window functions). Same liveness contract\n * as `vectorSearch` / `fulltextSearch`.\n */\n hybridSearch?: (\n this: void,\n params: HybridSearchParams,\n ) => Promise<readonly HybridSearchRow[]>;\n\n // === Fulltext Operations (optional - depends on fulltext capabilities) ===\n upsertFulltext?: (this: void, params: UpsertFulltextParams) => Promise<void>;\n deleteFulltext?: (this: void, params: DeleteFulltextParams) => Promise<void>;\n /**\n * Batched variant of `upsertFulltext`. Optional — callers fall back to\n * per-row `upsertFulltext` when unset.\n */\n upsertFulltextBatch?: (\n this: void,\n params: UpsertFulltextBatchParams,\n ) => Promise<void>;\n /**\n * Batched variant of `deleteFulltext`. Optional — callers fall back to\n * per-row `deleteFulltext` when unset.\n */\n deleteFulltextBatch?: (\n this: void,\n params: DeleteFulltextBatchParams,\n ) => Promise<void>;\n /**\n * Ranked fulltext search over one node kind. Like `vectorSearch`, top-k\n * is computed over CURRENT nodes only — non-tombstoned AND inside their\n * validity window (exact on both engines — plain WHERE, no top-k table\n * function involved). Custom backends implementing this member must\n * honor the same contract.\n */\n fulltextSearch?: (\n this: void,\n params: FulltextSearchParams,\n ) => Promise<readonly FulltextSearchResult[]>;\n\n // === Index Materialization (used by store.materializeIndexes) ===\n /**\n * Idempotently ensure ONLY the `typegraph_index_materializations`\n * table exists — separate from `bootstrapTables` so that\n * `materializeIndexes` doesn't pull in the full base-table DDL set\n * just to access the status table.\n *\n * Why focused: `bootstrapTables` issues 20+ `CREATE TABLE / CREATE\n * INDEX IF NOT EXISTS` statements covering every base table. Two\n * concurrent calls (e.g. two replicas of the same `schema_doc` both\n * starting up and calling `materializeIndexes`) race on\n * Postgres SHARE locks and DEADLOCK. Restricting the ensure-step to\n * the single status table eliminates the cross-table race entirely\n * — concurrent `CREATE TABLE IF NOT EXISTS` for one specific table\n * is well-behaved on Postgres.\n */\n ensureIndexMaterializationsTable?: (this: void) => Promise<void>;\n\n /**\n * Idempotently ensure ONLY the `typegraph_revision_origins` table exists.\n *\n * Revision-tracked stores use this per-graph, durable random origin together\n * with the recorded clock to prevent two independent stores with coincident\n * timestamps from sharing a merge base anchor. It is focused rather than\n * using `bootstrapTables` so existing deployments can adopt revision anchors\n * without replaying all base-table DDL during a merge read.\n */\n ensureRevisionOriginsTable?: (this: void) => Promise<void>;\n\n /**\n * Look up a recorded materialization for a declared index by its\n * physical SQL index name. Returns `undefined` if no row exists.\n */\n getIndexMaterialization?: (\n this: void,\n indexName: string,\n ) => Promise<IndexMaterializationRow | undefined>;\n /**\n * Bulk variant of `getIndexMaterialization`: load every recorded\n * materialization whose `indexName` (status key) is in `statusKeys`,\n * in a single round-trip. Returned rows are unordered — callers index\n * by `indexName`. Optional; consumers fall back to per-key\n * `getIndexMaterialization` when unset.\n */\n getIndexMaterializations?: (\n this: void,\n statusKeys: readonly string[],\n ) => Promise<readonly IndexMaterializationRow[]>;\n /**\n * Upsert a materialization attempt — success or failure. Failure rows\n * preserve any prior `materializedAt` so the historical successful\n * timestamp survives across error windows.\n */\n recordIndexMaterialization?: (\n this: void,\n params: RecordIndexMaterializationParams,\n ) => Promise<void>;\n /**\n * Atomically claims the build of one index across every materializer\n * (process- and pool-safe: the status row's own atomicity is the mutex).\n * Returns true when this caller now holds the claim. Backends whose\n * index builds cannot deadlock across callers (SQLite: engine-level\n * write serialization, no CONCURRENTLY) omit it; `materializeIndexes`\n * then builds without a claim, exactly as before.\n */\n claimIndexMaterialization?: (\n this: void,\n params: ClaimIndexMaterializationParams,\n ) => Promise<boolean>;\n /** Releases a claim taken by `claimIndexMaterialization` (token-guarded). */\n releaseIndexMaterializationClaim?: (\n this: void,\n params: ReleaseIndexMaterializationClaimParams,\n ) => Promise<void>;\n\n // === Contribution Materialization (#135 — durable strategy-owned\n // storage marker, sibling of the index status table) ===\n\n /**\n * Idempotently ensure ONLY the\n * `typegraph_contribution_materializations` table exists. Same\n * focused-bootstrap rationale as `ensureIndexMaterializationsTable`:\n * a single `CREATE TABLE IF NOT EXISTS` is concurrency-safe under\n * replica startup, where the full `bootstrapTables` set risks a\n * Postgres SHARE-lock deadlock.\n */\n ensureContributionMaterializationsTable?: (this: void) => Promise<void>;\n\n /**\n * Look up the durable materialization marker for one strategy-owned\n * contribution identity. Returns `undefined` when no row exists\n * (\"never initialized\").\n */\n getContributionMaterialization?: (\n this: void,\n identity: ContributionMaterializationIdentity,\n ) => Promise<ContributionMaterializationRow | undefined>;\n\n /**\n * Upsert a contribution-materialization attempt — success or failure.\n * Failure rows preserve any prior `materializedAt` via COALESCE so a\n * later failed re-attempt doesn't erase the historical success.\n */\n recordContributionMaterialization?: (\n this: void,\n params: RecordContributionMaterializationParams,\n ) => Promise<void>;\n\n /**\n * Resolve (once per backend instance, cached) and assert the durable\n * materialization markers for every `runtimeEnsure` contribution this\n * backend's strategy declares, for `graphId`. Throws\n * `StoreNotInitializedError` when a marker is missing, stale\n * (signature drift), or recorded a failed last attempt.\n *\n * This is the single read-side gate the fulltext hot-path wrappers\n * and `store.transaction()` consult. It performs ZERO DDL and ZERO\n * marker writes — initialization is the exclusive job of the async\n * boot path (`createStoreWithSchema` → `ensureRuntimeContributions`).\n */\n assertRuntimeContributionsInitialized?: (\n this: void,\n graphId: string,\n ) => Promise<void>;\n\n // === Kind Removal Status ===\n\n /**\n * Bootstraps the per-deployment `typegraph_kind_removals` table so\n * `store.removeKinds()` and `store.materializeRemovals()` can persist\n * removal status. Mirrors the focused-bootstrap rationale documented\n * on `ensureIndexMaterializationsTable` — the full `bootstrapTables`\n * touches every base table and risks Postgres SHARE-lock deadlock\n * under concurrent replica startup.\n */\n ensureKindRemovalsTable?: (this: void) => Promise<void>;\n\n /**\n * List graph-extension kind removals whose data-cleanup pass has not yet\n * succeeded for this `graphId`. Returns rows with\n * `removedAt: undefined`. Order is unspecified; callers materialize\n * one-at-a-time and don't depend on it.\n */\n getPendingKindRemovals?: (\n this: void,\n graphId: string,\n ) => Promise<readonly KindRemovalRow[]>;\n\n /**\n * List ALL kind-removal rows for a `graphId` — pending and completed.\n * Used by `materializeRemovals()` reconciliation to detect rows that\n * are missing entirely (the `removeKinds()` crash window) versus\n * already completed. Without this distinction the reconciler would\n * have to upsert every expected historical removal on every call,\n * churning `last_attempted_at` on rows that long since succeeded.\n * Order is unspecified.\n */\n getAllKindRemovals?: (\n this: void,\n graphId: string,\n ) => Promise<readonly KindRemovalRow[]>;\n\n /**\n * Upsert a kind-removal status row. `removedAt: undefined` records\n * the pending state at schema-commit time; `removedAt: <iso>`\n * marks the data cleanup successful. The COALESCE rule on `removedAt`\n * mirrors `recordIndexMaterialization` so a later failure doesn't\n * clobber the historical successful timestamp from another replica.\n */\n recordKindRemoval?: (\n this: void,\n params: RecordKindRemovalParams,\n ) => Promise<void>;\n\n // === Reconciliation Watermark ===\n\n /**\n * Bootstraps the per-deployment `typegraph_reconciliation_markers`\n * table so `materializeRemovals()` can persist reconciliation\n * progress. Same focused-bootstrap rationale as the other status\n * tables — full `bootstrapTables` risks Postgres SHARE-lock\n * deadlock under concurrent replica startup.\n */\n ensureReconciliationMarkersTable?: (this: void) => Promise<void>;\n\n // === Table Contributions (#129) ===\n\n /**\n * Materializes every contribution flagged `runtimeEnsure` — the\n * strategy-owned runtime tables (fulltext today) that drizzle-kit-\n * managed setups don't create. Called once after a successful schema\n * load. Deliberately scoped: base/drizzle-visible tables are\n * `runtimeEnsure: false`, so this does not regress startup into\n * broad DDL/probing across every table.\n *\n * The canonical durable-marker writer (#135): for each runtime\n * contribution it short-circuits when the marker already records a\n * matching signature, otherwise runs the idempotent `createDdl` and\n * records the marker (success or failure) keyed by `graphId`.\n */\n ensureRuntimeContributions?: (this: void, graphId: string) => Promise<void>;\n\n /**\n * Privileged materializer for one embedding `(kind, field)` slot's\n * `ownedTables` contribution(s): creates the per-field vector table and\n * records its durable marker, idempotently. The vector counterpart of\n * `ensureRuntimeContributions` — vectors are per-`(kind, field)` and\n * graph-derived, so the store enumerates slots (via\n * `resolveEmbeddingFields`) and uses the batch counterpart at boot under\n * the privileged role. Pass `{ force: true }` to overwrite the marker\n * at the current signature, bypassing the drift-guard — the sanctioned\n * path `store.reembedVectorField()` uses after recreating storage at a\n * new dimension. Pass `{ onDrift: \"skip\" }` to leave an\n * already-provisioned slot whose shape has since changed untouched\n * (warn + no-op) instead of refusing — the boot/evolve path, so a\n * declared dimension change never blocks startup before the operator\n * can run `reembedVectorField`. Present only on backends wired with a\n * vector strategy.\n */\n ensureVectorSlotContribution?: (\n this: void,\n slot: VectorSlot,\n options?: Readonly<{ force?: boolean; onDrift?: \"throw\" | \"skip\" }>,\n ) => Promise<void>;\n\n /**\n * Batch form of `ensureVectorSlotContribution`, used by privileged boot to\n * resolve every slot's durable markers with one graph-scoped query. The\n * singular method remains available for re-embedding and compatibility.\n */\n ensureVectorSlotContributions?: (\n this: void,\n slots: readonly VectorSlot[],\n options?: Readonly<{ force?: boolean; onDrift?: \"throw\" | \"skip\" }>,\n ) => Promise<void>;\n\n /**\n * SELECT-only gate for one embedding `(kind, field)` slot: asserts the\n * durable marker(s) for the slot's `ownedTables` contribution(s),\n * cached per backend instance. Throws `StoreNotInitializedError` when\n * the slot is missing, stale (signature drift), or recorded a failed\n * last attempt. The vector counterpart of\n * `assertRuntimeContributionsInitialized`, consulted by the verified\n * runtime attach. Performs ZERO DDL and ZERO writes. Present only on\n * backends wired with a vector strategy.\n */\n assertVectorSlotInitialized?: (this: void, slot: VectorSlot) => Promise<void>;\n\n /**\n * Batch form of `assertVectorSlotInitialized`, used by verified attach to\n * resolve every slot's durable markers with one graph-scoped query.\n */\n assertVectorSlotsInitialized?: (\n this: void,\n slots: readonly VectorSlot[],\n ) => Promise<void>;\n\n /**\n * Forget one embedding `(kind, field)` slot's durable contribution\n * marker(s). Called after the slot's per-field table is dropped\n * (vector-field reclaim) so a later `ensureVectorSlotContribution`\n * re-creates the table instead of trusting an orphaned \"initialized\"\n * marker. Does NOT drop the table itself (the caller already did).\n * Present only on backends wired with a vector strategy.\n */\n deleteVectorSlotContribution?: (\n this: void,\n slot: VectorSlot,\n ) => Promise<void>;\n\n /**\n * Bootstraps the fulltext storage table the active `FulltextStrategy`\n * owns. Same focused-bootstrap rationale as the other `ensure*Table`\n * methods: idempotent and concurrency-safe under replica startup.\n *\n * Superseded by `ensureRuntimeContributions()` (#129); retained as\n * a thin back-compat wrapper for backends/callers predating #129. Not\n * machine-`@deprecated` because the manager still calls it as the\n * pre-#129 fallback. #135 removed the remaining hot-path callers and\n * routed this through the durable-marker writer.\n */\n ensureFulltextTable?: (this: void, graphId: string) => Promise<void>;\n\n /**\n * Read the high-water mark schema version for which\n * `materializeRemovals` reconciliation has already verified history\n * for `graphId`. Returns `undefined` when no marker has been\n * recorded yet. Used to skip already-checked transitions in the\n * recovery walk.\n */\n getReconciliationMarker?: (\n this: void,\n graphId: string,\n ) => Promise<number | undefined>;\n\n /**\n * Persist the reconciliation high-water mark for `graphId`. Called\n * after `materializeRemovals` completes a clean walk; subsequent\n * calls walk only versions newer than this marker. Idempotent\n * upsert by `graphId`.\n */\n setReconciliationMarker?: (\n this: void,\n graphId: string,\n version: number,\n ) => Promise<void>;\n\n // === Graph Lifecycle ===\n /**\n * Hard-deletes all data for a graph (nodes, edges, uniques, embeddings, schema versions).\n * Intended for import-replacement workflows. No hooks, no per-row logic.\n */\n clearGraph: (this: void, graphId: string) => Promise<void>;\n\n /**\n * Creates the base TypeGraph tables if they don't already exist.\n *\n * Called automatically by `createStoreWithSchema()` when a fresh database\n * is detected. Users who manage DDL themselves via `createStore()` never\n * hit this path.\n */\n bootstrapTables?: (this: void) => Promise<void>;\n\n /**\n * Refreshes the backend's query-planner statistics.\n *\n * Call this once after a large initial import or bulk backfill. Without\n * up-to-date statistics, the planner can pick suboptimal execution plans\n * — on PostgreSQL this is the difference between a 0.5ms and a 5ms\n * forward traversal; on SQLite it's the difference between 0.9ms and\n * 23ms fulltext search. Autovacuum / background statistics collection\n * will catch up eventually, but calling this explicitly after a bulk\n * load gives you correct latencies immediately.\n *\n * Implementations:\n * - SQLite runs `ANALYZE`, which populates `sqlite_stat1`\n * - PostgreSQL runs `ANALYZE` on the TypeGraph-managed tables\n *\n * Safe to call at any time; costs a few tens of milliseconds on the\n * sizes this library is designed for.\n */\n refreshStatistics: (this: void) => Promise<void>;\n\n /**\n * Runs an intentionally trusted, all-or-nothing initial import.\n *\n * Optional because only backends that can pin one transaction and use a\n * native high-throughput write path expose it. Implementations must reject\n * a database whose TypeGraph node or edge tables already contain rows. They\n * may temporarily remove rebuildable secondary indexes, but must restore\n * them before committing. Any callback, insert, or rebuild failure rolls the\n * entire operation back.\n *\n * This is a top-level-only lifecycle operation and is deliberately absent\n * from {@link TransactionBackend}.\n */\n trustedImport?: <T>(\n this: void,\n fn: (session: TrustedImportSession) => Promise<T>,\n ) => Promise<T>;\n\n // === Query Execution ===\n execute: <T>(this: void, query: CompiledRowsSql) => Promise<readonly T[]>;\n\n /**\n * Execute a non-row-returning SQL statement bound to this backend or\n * transaction. Optional because custom backends may only expose the public\n * row-returning query path; features that need statement execution must\n * capability-check and fail loudly.\n */\n executeStatement?: (this: void, query: CompiledStatementSql) => Promise<void>;\n\n /**\n * Execute an internally compiled statement against connection-local\n * temporary state. History wrappers preserve this path because it cannot\n * mutate graph or history tables; callers cannot construct its branded\n * input through the public API.\n */\n executeTemporaryStatement?: (\n this: void,\n query: CompiledTemporaryStatementSql,\n ) => Promise<void>;\n\n /** Execute pre-compiled SQL text with bound parameters. Available on sync SQLite and pg backends. */\n executeRaw?: <T>(\n this: void,\n sqlText: string,\n params: readonly unknown[],\n ) => Promise<readonly T[]>;\n\n /** Compile a TypeGraph `SqlFragment` to `{ sql, params }` without executing. */\n compileSql?: (\n this: void,\n query: SqlFragment,\n ) => Readonly<{ sql: string; params: readonly unknown[] }>;\n\n /**\n * Execute a DDL statement that returns no rows (CREATE INDEX,\n * CREATE TABLE, ALTER TABLE, etc.). Separate from `executeRaw`\n * because some drivers (better-sqlite3) require `.run()` for DDL\n * and `.all()` for queries — the ambiguity can't be resolved by\n * inspecting the SQL string portably.\n *\n * Postgres path can use this for `CREATE INDEX CONCURRENTLY`, which\n * cannot run inside a transaction. Implementations must execute the\n * statement outside `transaction(...)`.\n */\n executeDdl?: (this: void, ddl: string) => Promise<void>;\n\n // === Transaction ===\n /** Runs TypeGraph operations inside a backend-owned transaction. */\n transaction: <T>(\n this: void,\n fn: (tx: TransactionBackend) => Promise<T>,\n options?: TransactionOptions,\n ) => Promise<T>;\n\n // === Lifecycle ===\n close: (this: void) => Promise<void>;\n}>;\n\n/**\n * Adapter-native transaction interoperability layered on top of the portable\n * TypeGraph backend. Only adapter entrypoints expose this capability.\n */\nexport type AdapterBackend<TNativeTransaction> = GraphBackend &\n Readonly<{\n /**\n * Runs TypeGraph operations and exposes the exact adapter-native handle\n * bound to the same transaction.\n */\n transactionWithNative: <T>(\n this: void,\n fn: (\n tx: TransactionBackend,\n nativeTransaction: TNativeTransaction,\n ) => Promise<T>,\n options?: TransactionOptions,\n ) => Promise<T>;\n /** Adopts a caller-owned, already-open adapter transaction. */\n adoptTransaction: (\n this: void,\n externalTransaction: TNativeTransaction,\n ) => TransactionBackend;\n }>;\n\nexport type BackendIdentity = Pick<\n GraphBackend,\n | \"dialect\"\n | \"capabilities\"\n | \"tableNames\"\n | \"fulltextStrategy\"\n | \"vectorStrategy\"\n>;\n\nexport type NodeEntityReadBackend = Pick<\n GraphBackend,\n \"getNode\" | \"getNodes\" | \"findNodesByKind\" | \"countNodesByKind\"\n>;\n\nexport type NodeEntityWriteBackend = Pick<\n GraphBackend,\n | \"insertNode\"\n | \"insertNodeNoReturn\"\n | \"insertNodesBatch\"\n | \"insertNodesBatchReturning\"\n | \"updateNode\"\n | \"deleteNode\"\n | \"hardDeleteNode\"\n>;\n\nexport type EdgeEntityReadBackend = Pick<\n GraphBackend,\n | \"getEdge\"\n | \"getEdges\"\n | \"countEdgesFrom\"\n | \"edgeExistsBetween\"\n | \"findEdgesConnectedTo\"\n | \"findEdgesByKind\"\n | \"countEdgesByKind\"\n>;\n\nexport type EdgeEntityWriteBackend = Pick<\n GraphBackend,\n | \"insertEdge\"\n | \"insertEdgeNoReturn\"\n | \"insertEdgesBatch\"\n | \"insertEdgesBatchReturning\"\n | \"updateEdge\"\n | \"deleteEdge\"\n | \"deleteEdgesBatch\"\n | \"hardDeleteEdge\"\n | \"hardDeleteEdgesBatch\"\n>;\n\nexport type GraphEntityReadBackend = NodeEntityReadBackend &\n EdgeEntityReadBackend;\n\nexport type GraphEntityWriteBackend = NodeEntityWriteBackend &\n EdgeEntityWriteBackend;\n\nexport type UniqueConstraintBackend = Pick<\n GraphBackend,\n | \"insertUnique\"\n | \"insertUniqueBatch\"\n | \"deleteUnique\"\n | \"checkUnique\"\n | \"checkUniqueBatch\"\n>;\n\nexport type SchemaReadBackend = Pick<\n GraphBackend,\n \"getActiveSchema\" | \"getSchemaVersion\"\n>;\n\nexport type SchemaCommitBackend = Pick<\n GraphBackend,\n \"commitSchemaVersion\" | \"setActiveVersion\"\n>;\n\nexport type VectorOperationBackend = Pick<\n GraphBackend,\n | \"upsertEmbedding\"\n | \"upsertEmbeddingBatch\"\n | \"deleteEmbedding\"\n | \"vectorSearch\"\n | \"createVectorIndex\"\n | \"dropVectorIndex\"\n>;\n\nexport type FulltextOperationBackend = Pick<\n GraphBackend,\n | \"upsertFulltext\"\n | \"deleteFulltext\"\n | \"upsertFulltextBatch\"\n | \"deleteFulltextBatch\"\n | \"fulltextSearch\"\n>;\n\nexport type IndexMaterializationBackend = Pick<\n GraphBackend,\n | \"ensureIndexMaterializationsTable\"\n | \"getIndexMaterialization\"\n | \"getIndexMaterializations\"\n | \"recordIndexMaterialization\"\n>;\n\nexport type ContributionMaterializationBackend = Pick<\n GraphBackend,\n | \"ensureContributionMaterializationsTable\"\n | \"getContributionMaterialization\"\n | \"recordContributionMaterialization\"\n | \"assertRuntimeContributionsInitialized\"\n | \"ensureRuntimeContributions\"\n | \"ensureFulltextTable\"\n>;\n\nexport type RemovalMaterializationBackend = Pick<\n GraphBackend,\n | \"ensureKindRemovalsTable\"\n | \"getPendingKindRemovals\"\n | \"getAllKindRemovals\"\n | \"recordKindRemoval\"\n | \"ensureReconciliationMarkersTable\"\n | \"getReconciliationMarker\"\n | \"setReconciliationMarker\"\n>;\n\nexport type GraphLifecycleBackend = Pick<\n GraphBackend,\n \"clearGraph\" | \"bootstrapTables\"\n>;\n\nexport type QueryExecutionBackend = Pick<GraphBackend, \"execute\">;\n\nexport type RawQueryExecutionBackend = Pick<\n GraphBackend,\n \"executeRaw\" | \"compileSql\"\n>;\n\nexport type SqlCompilationBackend = Pick<GraphBackend, \"compileSql\">;\n\nexport type RawStatementExecutionBackend = Pick<\n GraphBackend,\n \"executeStatement\" | \"executeTemporaryStatement\" | \"executeDdl\"\n>;\n\nexport type BackendMaintenance = Pick<GraphBackend, \"refreshStatistics\">;\n\nexport type BackendTransactions = Pick<GraphBackend, \"transaction\">;\n\nexport type AdapterBackendTransactions<TNativeTransaction> = Pick<\n AdapterBackend<TNativeTransaction>,\n \"transactionWithNative\" | \"adoptTransaction\"\n>;\n\nexport type BackendLifecycle = Pick<GraphBackend, \"close\">;\n\n/**\n * Read-oriented transaction projection exposed by portable transaction\n * contexts. It preserves snapshot-aware graph reads and TypeGraph-compiled\n * row queries while excluding graph writes, arbitrary raw SQL, DDL,\n * transaction adoption, and lifecycle control.\n */\nexport type TransactionReadBackend = Readonly<\n BackendIdentity &\n GraphEntityReadBackend &\n SchemaReadBackend &\n QueryExecutionBackend &\n SqlCompilationBackend\n>;\n\n/**\n * Transaction backend — a backend scoped to a transaction.\n *\n * This is an explicit facet composition, not `Omit<GraphBackend, ...>`.\n * New top-level-only backend methods therefore do not silently appear on\n * transaction-scoped backends. `commitSchemaVersion`, `setActiveVersion`,\n * `refreshStatistics`, `transaction`, `adoptTransaction`, and `close` stay\n * deliberately absent: their guarantees depend on the top-level backend or\n * lifecycle owner rather than an already-open transaction.\n */\nexport type TransactionBackend = Readonly<\n BackendIdentity &\n GraphEntityReadBackend &\n GraphEntityWriteBackend &\n UniqueConstraintBackend &\n SchemaReadBackend &\n VectorOperationBackend &\n FulltextOperationBackend &\n IndexMaterializationBackend &\n ContributionMaterializationBackend &\n RemovalMaterializationBackend &\n GraphLifecycleBackend &\n QueryExecutionBackend &\n RawQueryExecutionBackend &\n RawStatementExecutionBackend\n>;\n\n/**\n * Builds the actual runtime projection exposed as `TransactionContext.backend`.\n * This is an explicit object rather than a type-only narrowing so portable\n * callers cannot discover write or arbitrary-SQL methods on the underlying\n * transaction backend at runtime.\n *\n * @internal\n */\nexport function createTransactionReadBackend(\n backend: TransactionBackend,\n): TransactionReadBackend {\n const getNodes = backend.getNodes;\n const getEdges = backend.getEdges;\n const compileSql = backend.compileSql;\n\n return Object.freeze({\n dialect: backend.dialect,\n capabilities: backend.capabilities,\n ...(backend.tableNames === undefined ?\n {}\n : { tableNames: backend.tableNames }),\n ...(backend.fulltextStrategy === undefined ?\n {}\n : { fulltextStrategy: backend.fulltextStrategy }),\n ...(backend.vectorStrategy === undefined ?\n {}\n : { vectorStrategy: backend.vectorStrategy }),\n getNode: (graphId, kind, id) => backend.getNode(graphId, kind, id),\n ...(getNodes === undefined ?\n {}\n : {\n getNodes: (graphId: string, kind: string, ids: readonly string[]) =>\n getNodes(graphId, kind, ids),\n }),\n getEdge: (graphId, id) => backend.getEdge(graphId, id),\n ...(getEdges === undefined ?\n {}\n : {\n getEdges: (graphId: string, ids: readonly string[]) =>\n getEdges(graphId, ids),\n }),\n countEdgesFrom: (params) => backend.countEdgesFrom(params),\n edgeExistsBetween: (params) => backend.edgeExistsBetween(params),\n findEdgesConnectedTo: (params) => backend.findEdgesConnectedTo(params),\n findNodesByKind: (params) => backend.findNodesByKind(params),\n countNodesByKind: (params) => backend.countNodesByKind(params),\n findEdgesByKind: (params) => backend.findEdgesByKind(params),\n countEdgesByKind: (params) => backend.countEdgesByKind(params),\n getActiveSchema: (graphId) => backend.getActiveSchema(graphId),\n getSchemaVersion: (graphId, version) =>\n backend.getSchemaVersion(graphId, version),\n execute: <T>(query: CompiledRowsSql) => backend.execute<T>(query),\n ...(compileSql === undefined ?\n {}\n : { compileSql: (query: SqlFragment) => compileSql(query) }),\n });\n}\n\ntype ExactBackendOverlay<T extends object, O extends Partial<T>> = O &\n Readonly<Record<Exclude<keyof O, keyof T>, never>>;\n\n// ============================================================\n// Managed Backend Helper\n// ============================================================\n\n/**\n * Overlays selected backend methods without copying the backend object.\n *\n * This is a decoration primitive: every non-overridden target property remains\n * reachable. Never use it to narrow a capability surface; construct an\n * explicit allowlist projection first, then decorate that projection.\n *\n * Backend wrappers use this instead of object spread so proxy backends keep\n * getters and non-enumerable members. GraphBackend functions are receiver-free\n * by contract, so delegated methods are returned unchanged.\n */\nexport function createBackendOverlay<\n T extends GraphBackend | TransactionBackend,\n const O extends Partial<T> = Partial<T>,\n>(target: T, overlay: ExactBackendOverlay<T, O>): T {\n function hasOverlayProperty(property: PropertyKey): boolean {\n return Object.hasOwn(overlay, property);\n }\n\n return new Proxy(target, {\n get(targetObject, property) {\n if (hasOverlayProperty(property)) {\n return Reflect.get(overlay, property, overlay);\n }\n return Reflect.get(targetObject, property, targetObject);\n },\n\n has(targetObject, property) {\n return (\n hasOverlayProperty(property) || Reflect.has(targetObject, property)\n );\n },\n\n ownKeys(targetObject) {\n return [\n ...new Set([\n ...Reflect.ownKeys(targetObject),\n ...Reflect.ownKeys(overlay),\n ]),\n ];\n },\n\n getOwnPropertyDescriptor(targetObject, property) {\n if (hasOverlayProperty(property)) {\n const descriptor = Reflect.getOwnPropertyDescriptor(overlay, property);\n if (descriptor === undefined) return;\n return { ...descriptor, configurable: true };\n }\n return Reflect.getOwnPropertyDescriptor(targetObject, property);\n },\n\n set(targetObject, property, value) {\n if (hasOverlayProperty(property)) {\n return Reflect.set(overlay, property, value, overlay);\n }\n return Reflect.set(targetObject, property, value, targetObject);\n },\n\n defineProperty(targetObject, property, attributes) {\n if (hasOverlayProperty(property)) {\n return Reflect.defineProperty(overlay, property, attributes);\n }\n return Reflect.defineProperty(targetObject, property, attributes);\n },\n\n deleteProperty(targetObject, property) {\n if (hasOverlayProperty(property)) {\n return Reflect.deleteProperty(overlay, property);\n }\n return Reflect.deleteProperty(targetObject, property);\n },\n });\n}\n\n/**\n * Wraps a GraphBackend with idempotent close that also runs a teardown\n * callback (e.g. closing the underlying database connection).\n */\nexport function wrapWithManagedClose<TNativeTransaction>(\n backend: AdapterBackend<TNativeTransaction>,\n teardown: () => void | Promise<void>,\n): AdapterBackend<TNativeTransaction>;\nexport function wrapWithManagedClose(\n backend: GraphBackend,\n teardown: () => void | Promise<void>,\n): GraphBackend;\nexport function wrapWithManagedClose(\n backend: GraphBackend,\n teardown: () => void | Promise<void>,\n): GraphBackend {\n let backendClosed = false;\n let teardownComplete = false;\n let closeInFlight: Promise<void> | undefined;\n\n async function closeManagedResources(): Promise<void> {\n const errors: unknown[] = [];\n if (!backendClosed) {\n try {\n await backend.close();\n backendClosed = true;\n } catch (error) {\n errors.push(error);\n }\n }\n if (!teardownComplete) {\n try {\n await teardown();\n teardownComplete = true;\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length === 1) throw errors[0];\n if (errors.length > 1) {\n throw new AggregateError(\n errors,\n \"The backend and its managed resource both failed to close.\",\n );\n }\n }\n\n const closeOverlay: Pick<GraphBackend, \"close\"> = {\n async close(): Promise<void> {\n if (backendClosed && teardownComplete) return;\n closeInFlight ??= closeManagedResources().finally(() => {\n closeInFlight = undefined;\n });\n await closeInFlight;\n },\n };\n return createBackendOverlay(backend, closeOverlay);\n}\n\n/**\n * Closes an owned resource after provisioning fails without replacing the\n * original domain error with a secondary cleanup failure.\n */\nexport async function closeAfterFailure(\n resource: Readonly<{ close: () => void | Promise<void> }>,\n provisioningError: unknown,\n): Promise<never> {\n try {\n await resource.close();\n } catch {\n // The provisioning failure remains the actionable error. Managed close is\n // retryable when the resource is returned, but a failed factory has no\n // handle it can safely expose for a second attempt.\n }\n throw provisioningError;\n}\n\n/**\n * Runs `fn` inside a transaction when given a top-level backend that supports\n * one, falling through to a direct invocation otherwise. Lets call sites benefit\n * from atomicity on backends that have transactions while staying functional on\n * backends that don't (Cloudflare D1, `drizzle-orm/neon-http` over HTTP), and\n * avoids opening nested transactions when the caller already holds a\n * transaction-scoped backend. The single-statement race window is already\n * implicit on any backend that reports `transactions: false`; callers that\n * cannot tolerate it must branch on the capability themselves.\n *\n * Pass `fallback` only when the toplevel backend method would recurse\n * — pass the operation-level backend so the no-tx path doesn't loop\n * back through the same toplevel method.\n */\nexport async function runOptionallyInTransaction<T>(\n backend: GraphBackend | TransactionBackend,\n fn: (target: GraphBackend | TransactionBackend) => Promise<T>,\n fallback?: GraphBackend | TransactionBackend,\n): Promise<T> {\n if (\"transaction\" in backend && backend.capabilities.transactions) {\n return backend.transaction((tx) => fn(tx));\n }\n return fn(fallback ?? backend);\n}\n\n// ============================================================\n// Additional Parameter Types\n// ============================================================\n\n/**\n * Parameters for inserting a unique constraint entry.\n */\nexport type InsertUniqueParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n key: string;\n nodeId: string;\n concreteKind: string;\n}>;\n\n/**\n * Parameters for deleting a unique constraint entry.\n */\nexport type DeleteUniqueParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n key: string;\n}>;\n\n/**\n * Parameters for checking a unique constraint.\n */\nexport type CheckUniqueParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n key: string;\n /** If true, also returns soft-deleted entries. Used by get-or-create operations. */\n includeDeleted?: boolean;\n}>;\n\n/**\n * Parameters for batch-checking unique constraints.\n */\nexport type CheckUniqueBatchParams = Readonly<{\n graphId: string;\n nodeKind: string;\n constraintName: string;\n keys: readonly string[];\n /** If true, also returns soft-deleted entries. Used by get-or-create operations. */\n includeDeleted?: boolean;\n}>;\n\n/**\n * Parameters for inserting a schema version.\n *\n * Used internally by backend implementations. Public callers go through\n * `commitSchemaVersion`, which handles the insert + activate atomically\n * with CAS guarantees.\n */\nexport type InsertSchemaParams = Readonly<{\n graphId: string;\n version: number;\n schemaHash: string;\n schemaDoc: SerializedSchema;\n isActive: boolean;\n}>;\n\n/**\n * The caller's claim about the currently-active schema version, used as\n * the optimistic compare-and-swap guard for `commitSchemaVersion`.\n *\n * - `{ kind: \"initial\" }` — caller is committing the first-ever version\n * for this graph and asserts no active version exists yet.\n * - `{ kind: \"active\", version: N }` — caller observed version N as\n * active and is committing version N+1 against that baseline. The\n * commit fails with `StaleVersionError` if some other writer has\n * advanced or rolled back the pointer in the meantime.\n *\n * Tagged-union form (rather than a magic `version: 0` sentinel) because\n * the two cases have materially different semantics: the initial path\n * skips the \"deactivate prior\" UPDATE, and the no-active-row state is\n * a *valid* expected state, not an out-of-band signal.\n */\nexport type CommitSchemaVersionExpected =\n Readonly<{ kind: \"initial\" }> | Readonly<{ kind: \"active\"; version: number }>;\n\n/**\n * Parameters for `commitSchemaVersion`.\n */\nexport type CommitSchemaVersionParams = Readonly<{\n graphId: string;\n /** CAS guard — see `CommitSchemaVersionExpected`. */\n expected: CommitSchemaVersionExpected;\n /** The new version to insert and activate. */\n version: number;\n schemaHash: string;\n schemaDoc: SerializedSchema;\n}>;\n\n/**\n * Parameters for `setActiveVersion`.\n *\n * Flips the active pointer from `expected` to `version` for an existing\n * row. CAS prevents overwriting a concurrent rollback or commit.\n */\nexport type SetActiveVersionParams = Readonly<{\n graphId: string;\n /** CAS guard. Same semantics as `commitSchemaVersion.expected`. */\n expected: CommitSchemaVersionExpected;\n /** The version to mark active. Must already exist. */\n version: number;\n}>;\n\n/**\n * Parameters for counting edges from a source node.\n */\nexport type CountEdgesFromParams = Readonly<{\n graphId: string;\n edgeKind: string;\n fromKind: string;\n fromId: string;\n /** If true, only count edges where valid_to IS NULL */\n activeOnly?: boolean;\n}>;\n\n/**\n * Parameters for checking if an edge exists between two nodes.\n */\nexport type EdgeExistsBetweenParams = Readonly<{\n graphId: string;\n edgeKind: string;\n fromKind: string;\n fromId: string;\n toKind: string;\n toId: string;\n}>;\n\n/**\n * Parameters for finding edges connected to a node.\n */\nexport type FindEdgesConnectedToParams = Readonly<{\n graphId: string;\n nodeKind: string;\n nodeId: string;\n}>;\n\n/**\n * Parameters for finding nodes by kind.\n */\nexport type FindNodesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n /** Max rows to return. */\n limit?: number;\n /** Offset. Present for backward compat; rebuild uses `after` instead. */\n offset?: number;\n /** If true, exclude deleted nodes. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n /**\n * Stable ordering for keyset pagination. Default: \"created_at\" (existing\n * behavior). Rebuild should use \"id\" for iteration that is stable under\n * concurrent writes and shared timestamps.\n */\n orderBy?: \"id\" | \"created_at\";\n /**\n * Keyset cursor. Returns rows strictly greater (by `orderBy`) than this\n * value. When `orderBy: \"id\"`, compared lexicographically. Mutually\n * exclusive with `offset` — callers pick one.\n */\n after?: string;\n}>;\n\n/**\n * Parameters for counting nodes by kind.\n */\nexport type CountNodesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n /** If true, exclude deleted nodes. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n}>;\n\n/**\n * Parameters for finding edges by kind.\n */\nexport type FindEdgesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n fromKind?: string;\n fromId?: string;\n toKind?: string;\n toId?: string;\n limit?: number;\n offset?: number;\n /** If true, exclude deleted edges. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n /**\n * Stable ordering for keyset pagination. Default: \"created_at\" (existing\n * behavior). Use \"id\" for iteration that is stable under shared `created_at`\n * timestamps — the offset path orders by the NON-unique `created_at`, so a\n * full enumeration must page by the unique `id` to avoid skipping a row at a\n * page boundary. Mirrors {@link FindNodesByKindParams.orderBy}.\n */\n orderBy?: \"id\" | \"created_at\";\n /**\n * Keyset cursor. Returns rows strictly greater (by `orderBy`) than this value.\n * When `orderBy: \"id\"`, compared lexicographically. Mutually exclusive with\n * `offset` — callers pick one. Mirrors {@link FindNodesByKindParams.after}.\n */\n after?: string;\n}>;\n\n/**\n * Parameters for counting edges by kind.\n */\nexport type CountEdgesByKindParams = Readonly<{\n graphId: string;\n kind: string;\n fromKind?: string;\n fromId?: string;\n toKind?: string;\n toId?: string;\n /** If true, exclude deleted edges. Default true. */\n excludeDeleted?: boolean;\n /** Temporal mode for filtering by validity period. */\n temporalMode?: TemporalMode;\n /** Timestamp for \"current\" and \"asOf\" temporal modes. */\n asOf?: string;\n}>;\n\n// ============================================================\n// Default Capabilities\n// ============================================================\n\n/**\n * Conservative per-statement bound-parameter floor for SQLite. The\n * compiled-in `SQLITE_MAX_VARIABLE_NUMBER` defaulted to 999 before SQLite\n * 3.32.0; drivers whose real ceiling cannot be probed (async/remote\n * connections) keep this floor. Single source of truth for\n * {@link SQLITE_CAPABILITIES} and the SQLite backend's batch math fallback.\n */\nexport const SQLITE_MAX_BIND_PARAMETERS = 999;\n\n/**\n * `SQLITE_MAX_VARIABLE_NUMBER` default since SQLite 3.32.0 (better-sqlite3\n * also compiles it in explicitly). Used when a synchronous driver's probe\n * confirms a modern build.\n */\nexport const MODERN_SQLITE_MAX_BIND_PARAMETERS = 32_766;\n\n/**\n * Cloudflare D1's documented per-statement bound-parameter ceiling. Far\n * below the classic SQLite floor, so D1 detection must cap the budget or\n * batched writes fail at runtime.\n */\nexport const D1_MAX_BIND_PARAMETERS = 100;\n\n/**\n * Cloudflare SQLite-backed Durable Objects' documented per-statement\n * bound-parameter ceiling. The resolved `do-sqlite` execution profile must\n * advertise this limit so every capability-driven batch path stays below it.\n */\nexport const DURABLE_OBJECT_MAX_BIND_PARAMETERS = 100;\n\n/**\n * PostgreSQL's wire-protocol bound-parameter ceiling (a 16-bit count). Single\n * source of truth for {@link POSTGRES_CAPABILITIES} and the Postgres backend's\n * batch math.\n */\nexport const POSTGRES_MAX_BIND_PARAMETERS = 65_535;\n\n/**\n * Default capabilities for SQLite.\n */\nexport const SQLITE_CAPABILITIES: BackendCapabilities = Object.freeze({\n transactions: true, // SQLite supports transactions\n windowFunctions: true, // SQLite has supported window functions since 3.25.0\n returning: true, // SQLite has supported RETURNING since 3.35.0\n maxBindParameters: SQLITE_MAX_BIND_PARAMETERS,\n // Generic SQLite builds do not guarantee ENABLE_MATH_FUNCTIONS. The local\n // better-sqlite3 factory overrides this flag for its bundled build contract.\n graphAnalytics: Object.freeze({ supported: true, mathFunctions: false }),\n});\n\n/**\n * Default capabilities for PostgreSQL.\n */\nexport const POSTGRES_CAPABILITIES: BackendCapabilities = Object.freeze({\n transactions: true, // PostgreSQL supports transactions\n windowFunctions: true, // PostgreSQL supports ROW_NUMBER() and related windows\n returning: true, // PostgreSQL has supported RETURNING since 8.2\n maxBindParameters: POSTGRES_MAX_BIND_PARAMETERS,\n graphAnalytics: Object.freeze({ supported: true, mathFunctions: true }),\n});\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ALL_META_EDGE_NAMES } from './chunk-GYA4JRP5.js';
|
|
2
|
-
import { assertJsonValue } from './chunk-
|
|
2
|
+
import { assertJsonValue } from './chunk-RXOAXO3R.js';
|
|
3
3
|
import { isPlainObject, compactUndefined, freezeDeep } from './chunk-ITE4IXAK.js';
|
|
4
|
-
import { RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS } from './chunk-
|
|
5
|
-
import { TypeGraphError, ConfigurationError } from './chunk-
|
|
4
|
+
import { RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS } from './chunk-4WYFRACU.js';
|
|
5
|
+
import { TypeGraphError, ConfigurationError } from './chunk-OYJSYDIH.js';
|
|
6
6
|
import { encodeJsonPointerSegment } from './chunk-G6Q5UM7U.js';
|
|
7
7
|
|
|
8
8
|
// src/ontology/closures.ts
|
|
@@ -1843,5 +1843,5 @@ function freezeDocument(input) {
|
|
|
1843
1843
|
}
|
|
1844
1844
|
|
|
1845
1845
|
export { CURRENT_GRAPH_EXTENSION_VERSION, GRAPH_EXTENSION_ISSUE_CODES, GRAPH_EXTENSION_TOP_LEVEL_KEYS, GraphExtensionError, GraphExtensionUnresolvedEndpointError, GraphExtensionValidationError, GraphExtensionVersionUnsupportedError, INCOMPATIBLE_CHANGE_TYPES, IncompatibleChangeError, KindCollisionError, KindHasReferentsError, LEGACY_GRAPH_EXTENSION_VERSION, RemoveCompileTimeKindError, computeTransitiveClosure, err, invertClosure, isErr, isOk, isReachable, ok, unwrap, validateGraphExtension };
|
|
1846
|
-
//# sourceMappingURL=chunk-
|
|
1847
|
-
//# sourceMappingURL=chunk-
|
|
1846
|
+
//# sourceMappingURL=chunk-EQOQOT55.js.map
|
|
1847
|
+
//# sourceMappingURL=chunk-EQOQOT55.js.map
|