@nicia-ai/typegraph 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/drizzle/indexes.cjs +11 -11
- package/dist/backend/drizzle/indexes.d.cts +1 -1
- package/dist/backend/drizzle/indexes.d.ts +1 -1
- package/dist/backend/drizzle/indexes.js +7 -7
- package/dist/backend/index.cjs +53 -54
- package/dist/backend/index.d.cts +3 -3
- package/dist/backend/index.d.ts +3 -3
- package/dist/backend/index.js +13 -14
- package/dist/backend/postgres/index.cjs +29 -30
- package/dist/backend/postgres/index.d.cts +7 -7
- package/dist/backend/postgres/index.d.ts +7 -7
- package/dist/backend/postgres/index.js +16 -17
- package/dist/backend/postgres/pglite-store.cjs +48 -43
- package/dist/backend/postgres/pglite-store.cjs.map +1 -1
- package/dist/backend/postgres/pglite-store.d.cts +15 -9
- package/dist/backend/postgres/pglite-store.d.ts +15 -9
- package/dist/backend/postgres/pglite-store.js +44 -39
- package/dist/backend/postgres/pglite-store.js.map +1 -1
- package/dist/backend/postgres/pglite.cjs +18 -19
- package/dist/backend/postgres/pglite.d.cts +4 -4
- package/dist/backend/postgres/pglite.d.ts +4 -4
- package/dist/backend/postgres/pglite.js +17 -18
- package/dist/backend/sqlite/index.cjs +26 -27
- package/dist/backend/sqlite/index.d.cts +6 -6
- package/dist/backend/sqlite/index.d.ts +6 -6
- package/dist/backend/sqlite/index.js +14 -15
- package/dist/backend/sqlite/libsql.cjs +21 -22
- package/dist/backend/sqlite/libsql.cjs.map +1 -1
- package/dist/backend/sqlite/libsql.d.cts +15 -8
- package/dist/backend/sqlite/libsql.d.ts +15 -8
- package/dist/backend/sqlite/libsql.js +17 -18
- package/dist/backend/sqlite/libsql.js.map +1 -1
- package/dist/backend/sqlite/local-store.cjs +49 -44
- package/dist/backend/sqlite/local-store.cjs.map +1 -1
- package/dist/backend/sqlite/local-store.d.cts +15 -10
- package/dist/backend/sqlite/local-store.d.ts +15 -10
- package/dist/backend/sqlite/local-store.js +45 -40
- package/dist/backend/sqlite/local-store.js.map +1 -1
- package/dist/backend/sqlite/local.cjs +19 -20
- package/dist/backend/sqlite/local.d.cts +3 -3
- package/dist/backend/sqlite/local.d.ts +3 -3
- package/dist/backend/sqlite/local.js +17 -18
- package/dist/{chunk-XMYJY7NI.js → chunk-2LG2XB2M.js} +3 -3
- package/dist/{chunk-XMYJY7NI.js.map → chunk-2LG2XB2M.js.map} +1 -1
- package/dist/{chunk-QGKILWGZ.cjs → chunk-2NA5DYLO.cjs} +4 -4
- package/dist/{chunk-QGKILWGZ.cjs.map → chunk-2NA5DYLO.cjs.map} +1 -1
- package/dist/{chunk-5MUSU4ZP.cjs → chunk-3DHZCOT7.cjs} +20 -20
- package/dist/chunk-3DHZCOT7.cjs.map +1 -0
- package/dist/{chunk-OVUUTCPJ.cjs → chunk-4UGOKMI5.cjs} +268 -150
- package/dist/chunk-4UGOKMI5.cjs.map +1 -0
- package/dist/{chunk-FRHHDHKH.js → chunk-5262ZMTR.js} +26 -5
- package/dist/chunk-5262ZMTR.js.map +1 -0
- package/dist/{chunk-HOIFFY4M.js → chunk-5763DULU.js} +248 -76
- package/dist/chunk-5763DULU.js.map +1 -0
- package/dist/{chunk-7G32LIQM.js → chunk-5UVRGXD3.js} +277 -7
- package/dist/chunk-5UVRGXD3.js.map +1 -0
- package/dist/{chunk-IIT5K7SK.cjs → chunk-62ZP23AW.cjs} +15 -15
- package/dist/{chunk-IIT5K7SK.cjs.map → chunk-62ZP23AW.cjs.map} +1 -1
- package/dist/{chunk-S4KQ5LV4.js → chunk-775A4ZMN.js} +40 -6
- package/dist/chunk-775A4ZMN.js.map +1 -0
- package/dist/{chunk-QYWINYEA.cjs → chunk-7BQXPCGN.cjs} +830 -170
- package/dist/chunk-7BQXPCGN.cjs.map +1 -0
- package/dist/{chunk-FJMPR3OH.cjs → chunk-7EO3TCQB.cjs} +33 -7
- package/dist/chunk-7EO3TCQB.cjs.map +1 -0
- package/dist/chunk-7GT72YHH.cjs +1979 -0
- package/dist/chunk-7GT72YHH.cjs.map +1 -0
- package/dist/{chunk-SQRD2CYF.js → chunk-7VQXLT5O.js} +717 -76
- package/dist/chunk-7VQXLT5O.js.map +1 -0
- package/dist/{chunk-BCP7LLOY.js → chunk-7Z5OR7KO.js} +2706 -625
- package/dist/chunk-7Z5OR7KO.js.map +1 -0
- package/dist/chunk-A4OC4DVN.cjs +12 -0
- package/dist/{chunk-4SZ6XPTG.cjs.map → chunk-A4OC4DVN.cjs.map} +1 -1
- package/dist/{chunk-TDXIBCGY.cjs → chunk-A7J2YDDI.cjs} +5 -3
- package/dist/chunk-A7J2YDDI.cjs.map +1 -0
- package/dist/{chunk-FMMIX6N4.js → chunk-AKLS3BYZ.js} +56 -5
- package/dist/chunk-AKLS3BYZ.js.map +1 -0
- package/dist/{chunk-D7PG5D5K.js → chunk-AMKPPFUO.js} +32 -6
- package/dist/chunk-AMKPPFUO.js.map +1 -0
- package/dist/{chunk-PAW2XUZN.js → chunk-ASTI57H3.js} +3 -3
- package/dist/{chunk-PAW2XUZN.js.map → chunk-ASTI57H3.js.map} +1 -1
- package/dist/{chunk-FMGEZBAQ.js → chunk-BKCUOV7A.js} +27 -5
- package/dist/chunk-BKCUOV7A.js.map +1 -0
- package/dist/chunk-BSFJMMV3.cjs +268 -0
- package/dist/chunk-BSFJMMV3.cjs.map +1 -0
- package/dist/{chunk-63KCKSSH.js → chunk-C23WSN5E.js} +209 -24
- package/dist/chunk-C23WSN5E.js.map +1 -0
- package/dist/{chunk-JRP3VGHS.js → chunk-CBTIUB76.js} +3 -3
- package/dist/{chunk-JRP3VGHS.js.map → chunk-CBTIUB76.js.map} +1 -1
- package/dist/chunk-CNV4TXJG.js +58 -0
- package/dist/chunk-CNV4TXJG.js.map +1 -0
- package/dist/{chunk-QB6VMOJ2.cjs → chunk-CXBHOOIQ.cjs} +45 -10
- package/dist/chunk-CXBHOOIQ.cjs.map +1 -0
- package/dist/{chunk-46GDII45.js → chunk-DCQVHAYQ.js} +5 -5
- package/dist/{chunk-46GDII45.js.map → chunk-DCQVHAYQ.js.map} +1 -1
- package/dist/chunk-DLNROMQ7.js +306 -0
- package/dist/chunk-DLNROMQ7.js.map +1 -0
- package/dist/chunk-DYATYRY4.js +47 -0
- package/dist/chunk-DYATYRY4.js.map +1 -0
- package/dist/chunk-E4WNQBEF.cjs +217 -0
- package/dist/chunk-E4WNQBEF.cjs.map +1 -0
- package/dist/{chunk-G6Q5UM7U.js → chunk-FWJKWH6U.js} +5 -3
- package/dist/chunk-FWJKWH6U.js.map +1 -0
- package/dist/{chunk-BNUFUFAU.js → chunk-HFHTMECK.js} +7 -7
- package/dist/chunk-HFHTMECK.js.map +1 -0
- package/dist/{chunk-TFMVL4QH.js → chunk-I5MOXA4H.js} +20 -14
- package/dist/chunk-I5MOXA4H.js.map +1 -0
- package/dist/{chunk-4MB3AQAQ.js → chunk-J3WZ3FA2.js} +77 -3
- package/dist/chunk-J3WZ3FA2.js.map +1 -0
- package/dist/{chunk-UR7W5YQK.js → chunk-JBQQ7THH.js} +5 -3
- package/dist/chunk-JBQQ7THH.js.map +1 -0
- package/dist/chunk-JIVMTW7W.js +3393 -0
- package/dist/chunk-JIVMTW7W.js.map +1 -0
- package/dist/{chunk-2Y4IFKW7.js → chunk-JXA2ZP2Q.js} +6 -17
- package/dist/chunk-JXA2ZP2Q.js.map +1 -0
- package/dist/{chunk-GYA4JRP5.js → chunk-JXXDZTMN.js} +2 -2
- package/dist/chunk-JXXDZTMN.js.map +1 -0
- package/dist/chunk-JZUR7ZWE.js +254 -0
- package/dist/chunk-JZUR7ZWE.js.map +1 -0
- package/dist/chunk-K5ELX2GT.js +248 -0
- package/dist/chunk-K5ELX2GT.js.map +1 -0
- package/dist/chunk-LBJKZXDE.cjs +257 -0
- package/dist/chunk-LBJKZXDE.cjs.map +1 -0
- package/dist/{chunk-FGO5JFVJ.cjs → chunk-M4BDU5RX.cjs} +12 -12
- package/dist/{chunk-FGO5JFVJ.cjs.map → chunk-M4BDU5RX.cjs.map} +1 -1
- package/dist/{chunk-MIJKEVV7.js → chunk-MSY7FSX4.js} +37 -4
- package/dist/chunk-MSY7FSX4.js.map +1 -0
- package/dist/{chunk-ST3LPB2V.cjs → chunk-MUK4BU7K.cjs} +788 -146
- package/dist/chunk-MUK4BU7K.cjs.map +1 -0
- package/dist/{chunk-MCHP7RHZ.cjs → chunk-MXJDTH5B.cjs} +64 -41
- package/dist/chunk-MXJDTH5B.cjs.map +1 -0
- package/dist/{chunk-2VLBGQBY.cjs → chunk-N3257XE6.cjs} +724 -577
- package/dist/chunk-N3257XE6.cjs.map +1 -0
- package/dist/chunk-N66HCGCY.cjs +57 -0
- package/dist/chunk-N66HCGCY.cjs.map +1 -0
- package/dist/{chunk-CPEL3YIR.cjs → chunk-NFCVHQ5P.cjs} +55 -22
- package/dist/chunk-NFCVHQ5P.cjs.map +1 -0
- package/dist/{chunk-C4F7VJ5D.cjs → chunk-NI72YOJB.cjs} +84 -2
- package/dist/chunk-NI72YOJB.cjs.map +1 -0
- package/dist/{chunk-EE7N5XXQ.cjs → chunk-NK5Q7UNE.cjs} +10 -21
- package/dist/chunk-NK5Q7UNE.cjs.map +1 -0
- package/dist/{chunk-PHXITZE4.js → chunk-NMWDXFPH.js} +4 -4
- package/dist/{chunk-PHXITZE4.js.map → chunk-NMWDXFPH.js.map} +1 -1
- package/dist/{chunk-FSXTPBRN.js → chunk-NQ6BRJBE.js} +416 -850
- package/dist/chunk-NQ6BRJBE.js.map +1 -0
- package/dist/chunk-OH5E5KIO.js +2057 -0
- package/dist/chunk-OH5E5KIO.js.map +1 -0
- package/dist/chunk-ONU3HIED.cjs +2082 -0
- package/dist/chunk-ONU3HIED.cjs.map +1 -0
- package/dist/{chunk-STQ3BSED.cjs → chunk-PNN7RHVR.cjs} +66 -44
- package/dist/chunk-PNN7RHVR.cjs.map +1 -0
- package/dist/{chunk-6DCB664D.js → chunk-PQBQG7IM.js} +3 -3
- package/dist/{chunk-6DCB664D.js.map → chunk-PQBQG7IM.js.map} +1 -1
- package/dist/{chunk-ACSVZPK7.cjs → chunk-PWLJ77UV.cjs} +5 -3
- package/dist/chunk-PWLJ77UV.cjs.map +1 -0
- package/dist/chunk-Q7Q4WSLJ.cjs +328 -0
- package/dist/chunk-Q7Q4WSLJ.cjs.map +1 -0
- package/dist/{chunk-BEFM74L2.js → chunk-QLRESYPU.js} +637 -493
- package/dist/chunk-QLRESYPU.js.map +1 -0
- package/dist/{chunk-SBPC5IP3.js → chunk-QWX5YA3K.js} +784 -202
- package/dist/chunk-QWX5YA3K.js.map +1 -0
- package/dist/{chunk-TCRIQMBU.js → chunk-RJS7DECT.js} +8 -9
- package/dist/chunk-RJS7DECT.js.map +1 -0
- package/dist/{chunk-6JZUSDY2.cjs → chunk-RMQLSPA2.cjs} +297 -27
- package/dist/chunk-RMQLSPA2.cjs.map +1 -0
- package/dist/{chunk-SJDMVITW.cjs → chunk-RT5ZY4XA.cjs} +6 -5
- package/dist/chunk-RT5ZY4XA.cjs.map +1 -0
- package/dist/{chunk-IJTLXNGJ.js → chunk-T4XNKYXB.js} +780 -127
- package/dist/chunk-T4XNKYXB.js.map +1 -0
- package/dist/{chunk-PDGEXGS6.cjs → chunk-TQR4KBY2.cjs} +354 -182
- package/dist/chunk-TQR4KBY2.cjs.map +1 -0
- package/dist/chunk-TTAITEPJ.cjs +755 -0
- package/dist/chunk-TTAITEPJ.cjs.map +1 -0
- package/dist/{chunk-NN3QSOVS.cjs → chunk-U5SON7R2.cjs} +27 -27
- package/dist/{chunk-NN3QSOVS.cjs.map → chunk-U5SON7R2.cjs.map} +1 -1
- package/dist/{chunk-A2I2XO52.cjs → chunk-U63GDNRC.cjs} +32 -26
- package/dist/chunk-U63GDNRC.cjs.map +1 -0
- package/dist/{chunk-YNULOIR5.cjs → chunk-UDISNXDL.cjs} +64 -43
- package/dist/chunk-UDISNXDL.cjs.map +1 -0
- package/dist/{chunk-GWEDD3DH.js → chunk-UV3SN74I.js} +5 -5
- package/dist/{chunk-GWEDD3DH.js.map → chunk-UV3SN74I.js.map} +1 -1
- package/dist/{chunk-U5W4LKZV.cjs → chunk-VCRRKBLN.cjs} +9 -9
- package/dist/{chunk-U5W4LKZV.cjs.map → chunk-VCRRKBLN.cjs.map} +1 -1
- package/dist/{chunk-EFELJVLA.js → chunk-VGTJPTIC.js} +28 -5
- package/dist/chunk-VGTJPTIC.js.map +1 -0
- package/dist/chunk-VQH4VAWD.cjs +12 -0
- package/dist/{chunk-EPTSMFH7.cjs.map → chunk-VQH4VAWD.cjs.map} +1 -1
- package/dist/{chunk-SNXVDZAJ.js → chunk-W6OG3HDG.js} +5 -4
- package/dist/chunk-W6OG3HDG.js.map +1 -0
- package/dist/chunk-WDGA7IYB.js +207 -0
- package/dist/chunk-WDGA7IYB.js.map +1 -0
- package/dist/chunk-WEVQJ5LH.js +736 -0
- package/dist/chunk-WEVQJ5LH.js.map +1 -0
- package/dist/{chunk-3PRKZW6D.cjs → chunk-XBYVV3MP.cjs} +60 -5
- package/dist/chunk-XBYVV3MP.cjs.map +1 -0
- package/dist/{chunk-GFRGG2US.cjs → chunk-XCAGZAKP.cjs} +7 -7
- package/dist/{chunk-GFRGG2US.cjs.map → chunk-XCAGZAKP.cjs.map} +1 -1
- package/dist/{chunk-XR4YZFKW.cjs → chunk-XDF2UPEQ.cjs} +3864 -1783
- package/dist/chunk-XDF2UPEQ.cjs.map +1 -0
- package/dist/{chunk-7V2FGGI2.cjs → chunk-XMQSEJCF.cjs} +632 -1080
- package/dist/chunk-XMQSEJCF.cjs.map +1 -0
- package/dist/chunk-XNLIZYRZ.cjs +3432 -0
- package/dist/chunk-XNLIZYRZ.cjs.map +1 -0
- package/dist/{chunk-66UVLHQA.cjs → chunk-XNSI2FJO.cjs} +99 -100
- package/dist/chunk-XNSI2FJO.cjs.map +1 -0
- package/dist/chunk-XQSCL77R.cjs +60 -0
- package/dist/chunk-XQSCL77R.cjs.map +1 -0
- package/dist/{chunk-SVJ5GEXW.cjs → chunk-XUO3KQFO.cjs} +2 -2
- package/dist/chunk-XUO3KQFO.cjs.map +1 -0
- package/dist/{chunk-HJH3RMXG.cjs → chunk-YAAM3M2S.cjs} +10 -10
- package/dist/{chunk-HJH3RMXG.cjs.map → chunk-YAAM3M2S.cjs.map} +1 -1
- package/dist/{chunk-ATLN63JA.js → chunk-YBFHZUXX.js} +6 -6
- package/dist/{chunk-ATLN63JA.js.map → chunk-YBFHZUXX.js.map} +1 -1
- package/dist/{chunk-K3BUWSFR.js → chunk-YDFDBE6D.js} +119 -6
- package/dist/chunk-YDFDBE6D.js.map +1 -0
- package/dist/{chunk-OSZPLZIV.cjs → chunk-YVWGEQJE.cjs} +318 -132
- package/dist/chunk-YVWGEQJE.cjs.map +1 -0
- package/dist/{chunk-QT6V3YRH.js → chunk-YWGVVALJ.js} +3 -3
- package/dist/{chunk-QT6V3YRH.js.map → chunk-YWGVVALJ.js.map} +1 -1
- package/dist/core/index.cjs +40 -41
- package/dist/core/index.d.cts +4 -5
- package/dist/core/index.d.ts +4 -5
- package/dist/core/index.js +8 -9
- package/dist/{ddl-eWg7hx6R.d.cts → ddl-BJcOp4WZ.d.cts} +3 -3
- package/dist/{ddl-D5369kOY.d.ts → ddl-BXfGHbPN.d.ts} +3 -3
- package/dist/graph-extension/index.cjs +26 -23
- package/dist/graph-extension/index.d.cts +16 -6
- package/dist/graph-extension/index.d.ts +16 -6
- package/dist/graph-extension/index.js +7 -8
- package/dist/graph-merge/index.cjs +2459 -655
- package/dist/graph-merge/index.cjs.map +1 -1
- package/dist/graph-merge/index.d.cts +170 -33
- package/dist/graph-merge/index.d.ts +170 -33
- package/dist/graph-merge/index.js +2269 -468
- package/dist/graph-merge/index.js.map +1 -1
- package/dist/{index-By89Sezh.d.ts → index-BSHvKfok.d.ts} +221 -10
- package/dist/{index-DcQ3Sxs-.d.cts → index-DxaYCv8Y.d.cts} +221 -10
- package/dist/index.cjs +330 -269
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +590 -576
- package/dist/index.d.ts +590 -576
- package/dist/index.js +73 -50
- package/dist/index.js.map +1 -1
- package/dist/indexes/index.cjs +17 -17
- package/dist/indexes/index.d.cts +4 -4
- package/dist/indexes/index.d.ts +4 -4
- package/dist/indexes/index.js +10 -10
- package/dist/interchange/index.cjs +165 -50
- package/dist/interchange/index.cjs.map +1 -1
- package/dist/interchange/index.d.cts +261 -16
- package/dist/interchange/index.d.ts +261 -16
- package/dist/interchange/index.js +128 -24
- package/dist/interchange/index.js.map +1 -1
- package/dist/{manager-B0KjKE93.d.ts → manager-CfZAimti.d.ts} +36 -5
- package/dist/{manager-Cn0NFIhN.d.cts → manager-HGk6E_HW.d.cts} +36 -5
- package/dist/{materialize-indexes-BD4V3svD.d.ts → materialize-indexes-6A7dWGtb.d.cts} +10 -2
- package/dist/{materialize-indexes-DVRhd5h4.d.cts → materialize-indexes-BMJP6Tms.d.ts} +10 -2
- package/dist/{postgres-DaEWvN4x.d.cts → postgres-DFYWENdR.d.cts} +1961 -439
- package/dist/{postgres-u0a0HN2D.d.ts → postgres-e7a9TdvR.d.ts} +1961 -439
- package/dist/profiler/index.cjs +15 -15
- package/dist/profiler/index.d.cts +9 -10
- package/dist/profiler/index.d.ts +9 -10
- package/dist/profiler/index.js +4 -4
- package/dist/provenance/index.cjs +46 -48
- package/dist/provenance/index.cjs.map +1 -1
- package/dist/provenance/index.d.cts +7 -7
- package/dist/provenance/index.d.ts +7 -7
- package/dist/provenance/index.js +12 -14
- package/dist/provenance/index.js.map +1 -1
- package/dist/schema/index.cjs +50 -49
- package/dist/schema/index.d.cts +9 -16
- package/dist/schema/index.d.ts +9 -16
- package/dist/schema/index.js +23 -22
- package/dist/{searchable-CnYEancP.d.ts → searchable-9OQoPuRs.d.ts} +1 -2
- package/dist/{searchable-BT7j9_IK.d.cts → searchable-CIje5XYD.d.cts} +1 -2
- package/dist/{sqlite-BrMoSsI7.d.cts → sqlite-DerU5tc7.d.ts} +2029 -347
- package/dist/{sqlite-CHhZUyO5.d.ts → sqlite-DitnISa9.d.cts} +2029 -347
- package/dist/{store-view-Bvdku0Ht.d.ts → store-DawaWWjJ.d.ts} +3145 -2556
- package/dist/{store-view-w-md0nQ4.d.cts → store-RwTJx8LX.d.cts} +3145 -2556
- package/dist/{temporal-BCORwUau.d.cts → temporal-Bn-Fi8FJ.d.cts} +1 -1
- package/dist/{temporal--x9T8K4S.d.ts → temporal-BtM4UALv.d.ts} +1 -1
- package/dist/{types-6-WJmSD4.d.cts → types-CoIx8HX5.d.cts} +1 -1
- package/dist/{types-Cjvkj0jA.d.ts → types-HkveCCx0.d.cts} +866 -21
- package/dist/{types-Cjvkj0jA.d.cts → types-HkveCCx0.d.ts} +866 -21
- package/dist/{types-COODtTJU.d.ts → types-KFfk-8Ah.d.ts} +1 -1
- package/dist/{where-CUQmCR6d.d.cts → where--fk7_0kv.d.cts} +1 -1
- package/dist/{where-5xVawAwL.d.ts → where-ws5hf-Ov.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-2BIG7U6E.cjs +0 -83
- package/dist/chunk-2BIG7U6E.cjs.map +0 -1
- package/dist/chunk-2L54C2C2.js +0 -144
- package/dist/chunk-2L54C2C2.js.map +0 -1
- package/dist/chunk-2VLBGQBY.cjs.map +0 -1
- package/dist/chunk-2WDD2NO3.js +0 -59
- package/dist/chunk-2WDD2NO3.js.map +0 -1
- package/dist/chunk-2Y4IFKW7.js.map +0 -1
- package/dist/chunk-35S6P5ZU.js +0 -27
- package/dist/chunk-35S6P5ZU.js.map +0 -1
- package/dist/chunk-3PRKZW6D.cjs.map +0 -1
- package/dist/chunk-4MB3AQAQ.js.map +0 -1
- package/dist/chunk-4SZ6XPTG.cjs +0 -12
- package/dist/chunk-5MUSU4ZP.cjs.map +0 -1
- package/dist/chunk-63KCKSSH.js.map +0 -1
- package/dist/chunk-66UVLHQA.cjs.map +0 -1
- package/dist/chunk-6JZUSDY2.cjs.map +0 -1
- package/dist/chunk-764JHTLT.cjs +0 -15
- package/dist/chunk-764JHTLT.cjs.map +0 -1
- package/dist/chunk-7G32LIQM.js.map +0 -1
- package/dist/chunk-7V2FGGI2.cjs.map +0 -1
- package/dist/chunk-A2I2XO52.cjs.map +0 -1
- package/dist/chunk-A4PBRX4C.cjs +0 -100
- package/dist/chunk-A4PBRX4C.cjs.map +0 -1
- package/dist/chunk-ACSVZPK7.cjs.map +0 -1
- package/dist/chunk-ALFUGRYB.cjs +0 -1282
- package/dist/chunk-ALFUGRYB.cjs.map +0 -1
- package/dist/chunk-B75XRV3O.js +0 -125
- package/dist/chunk-B75XRV3O.js.map +0 -1
- package/dist/chunk-BCP7LLOY.js.map +0 -1
- package/dist/chunk-BEFM74L2.js.map +0 -1
- package/dist/chunk-BNUFUFAU.js.map +0 -1
- package/dist/chunk-C4F7VJ5D.cjs.map +0 -1
- package/dist/chunk-CPEL3YIR.cjs.map +0 -1
- package/dist/chunk-D7PG5D5K.js.map +0 -1
- package/dist/chunk-DI74SMXS.cjs +0 -29
- package/dist/chunk-DI74SMXS.cjs.map +0 -1
- package/dist/chunk-DK2S42XB.js +0 -77
- package/dist/chunk-DK2S42XB.js.map +0 -1
- package/dist/chunk-DRACN6XG.js +0 -27
- package/dist/chunk-DRACN6XG.js.map +0 -1
- package/dist/chunk-EE7N5XXQ.cjs.map +0 -1
- package/dist/chunk-EFELJVLA.js.map +0 -1
- package/dist/chunk-EPTSMFH7.cjs +0 -12
- package/dist/chunk-EQ7JKLZO.cjs +0 -157
- package/dist/chunk-EQ7JKLZO.cjs.map +0 -1
- package/dist/chunk-FJMPR3OH.cjs.map +0 -1
- package/dist/chunk-FMGEZBAQ.js.map +0 -1
- package/dist/chunk-FMMIX6N4.js.map +0 -1
- package/dist/chunk-FRHHDHKH.js.map +0 -1
- package/dist/chunk-FSXTPBRN.js.map +0 -1
- package/dist/chunk-G6Q5UM7U.js.map +0 -1
- package/dist/chunk-GYA4JRP5.js.map +0 -1
- package/dist/chunk-HOHAJ2NR.cjs +0 -61
- package/dist/chunk-HOHAJ2NR.cjs.map +0 -1
- package/dist/chunk-HOIFFY4M.js.map +0 -1
- package/dist/chunk-IIMQJYAM.js +0 -81
- package/dist/chunk-IIMQJYAM.js.map +0 -1
- package/dist/chunk-IJTLXNGJ.js.map +0 -1
- package/dist/chunk-ITE4IXAK.js +0 -25
- package/dist/chunk-ITE4IXAK.js.map +0 -1
- package/dist/chunk-K3BUWSFR.js.map +0 -1
- package/dist/chunk-KCO5EFJU.js +0 -79
- package/dist/chunk-KCO5EFJU.js.map +0 -1
- package/dist/chunk-KKYELPZ2.cjs +0 -83
- package/dist/chunk-KKYELPZ2.cjs.map +0 -1
- package/dist/chunk-MCHP7RHZ.cjs.map +0 -1
- package/dist/chunk-MIJKEVV7.js.map +0 -1
- package/dist/chunk-NCX65HBY.cjs +0 -1396
- package/dist/chunk-NCX65HBY.cjs.map +0 -1
- package/dist/chunk-OSZPLZIV.cjs.map +0 -1
- package/dist/chunk-OVUUTCPJ.cjs.map +0 -1
- package/dist/chunk-PDGEXGS6.cjs.map +0 -1
- package/dist/chunk-QB6VMOJ2.cjs.map +0 -1
- package/dist/chunk-QMQLUA66.js +0 -12
- package/dist/chunk-QMQLUA66.js.map +0 -1
- package/dist/chunk-QYWINYEA.cjs.map +0 -1
- package/dist/chunk-S4KQ5LV4.js.map +0 -1
- package/dist/chunk-SBPC5IP3.js.map +0 -1
- package/dist/chunk-SJDMVITW.cjs.map +0 -1
- package/dist/chunk-SNXVDZAJ.js.map +0 -1
- package/dist/chunk-SQRD2CYF.js.map +0 -1
- package/dist/chunk-ST3LPB2V.cjs.map +0 -1
- package/dist/chunk-STQ3BSED.cjs.map +0 -1
- package/dist/chunk-SVJ5GEXW.cjs.map +0 -1
- package/dist/chunk-TCRIQMBU.js.map +0 -1
- package/dist/chunk-TDXIBCGY.cjs.map +0 -1
- package/dist/chunk-TFMVL4QH.js.map +0 -1
- package/dist/chunk-TRF4EBJT.cjs +0 -30
- package/dist/chunk-TRF4EBJT.cjs.map +0 -1
- package/dist/chunk-TVLKA4AY.js +0 -94
- package/dist/chunk-TVLKA4AY.js.map +0 -1
- package/dist/chunk-UR7W5YQK.js.map +0 -1
- package/dist/chunk-VITTKBWF.js +0 -1263
- package/dist/chunk-VITTKBWF.js.map +0 -1
- package/dist/chunk-WBUFJ7BS.cjs +0 -131
- package/dist/chunk-WBUFJ7BS.cjs.map +0 -1
- package/dist/chunk-XR4YZFKW.cjs.map +0 -1
- package/dist/chunk-YNULOIR5.cjs.map +0 -1
- package/dist/chunk-ZDH3DX3C.cjs +0 -30
- package/dist/chunk-ZDH3DX3C.cjs.map +0 -1
- package/dist/chunk-ZTAJL4DT.cjs +0 -85
- package/dist/chunk-ZTAJL4DT.cjs.map +0 -1
- package/dist/define-graph-DVF-oN1i.d.cts +0 -173
- package/dist/define-graph-SvYXOl78.d.ts +0 -173
|
@@ -0,0 +1,3432 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkXMQSEJCF_cjs = require('./chunk-XMQSEJCF.cjs');
|
|
4
|
+
var chunkBSFJMMV3_cjs = require('./chunk-BSFJMMV3.cjs');
|
|
5
|
+
var chunkXBYVV3MP_cjs = require('./chunk-XBYVV3MP.cjs');
|
|
6
|
+
var chunkQ7Q4WSLJ_cjs = require('./chunk-Q7Q4WSLJ.cjs');
|
|
7
|
+
var chunk4UGOKMI5_cjs = require('./chunk-4UGOKMI5.cjs');
|
|
8
|
+
var chunkVCRRKBLN_cjs = require('./chunk-VCRRKBLN.cjs');
|
|
9
|
+
var chunkNI72YOJB_cjs = require('./chunk-NI72YOJB.cjs');
|
|
10
|
+
var chunkN66HCGCY_cjs = require('./chunk-N66HCGCY.cjs');
|
|
11
|
+
|
|
12
|
+
// src/errors/validation.ts
|
|
13
|
+
function zodIssuesToValidationIssues(error) {
|
|
14
|
+
return error.issues.map((issue) => ({
|
|
15
|
+
path: issue.path.join("."),
|
|
16
|
+
message: issue.message,
|
|
17
|
+
code: issue.code
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
function buildLocationString(context) {
|
|
21
|
+
if (context.id) {
|
|
22
|
+
return `${context.kind}/${context.id}`;
|
|
23
|
+
}
|
|
24
|
+
return `new ${context.kind}`;
|
|
25
|
+
}
|
|
26
|
+
function validateProps(schema, props, context) {
|
|
27
|
+
const result = schema.safeParse(props);
|
|
28
|
+
if (result.success) {
|
|
29
|
+
return result.data;
|
|
30
|
+
}
|
|
31
|
+
const issues = zodIssuesToValidationIssues(result.error);
|
|
32
|
+
const location = buildLocationString(context);
|
|
33
|
+
throw new chunkNI72YOJB_cjs.ValidationError(
|
|
34
|
+
`Invalid ${context.entityType} props for ${location}: ${result.error.message}`,
|
|
35
|
+
{
|
|
36
|
+
entityType: context.entityType,
|
|
37
|
+
kind: context.kind,
|
|
38
|
+
operation: context.operation,
|
|
39
|
+
...context.id !== void 0 && { id: context.id },
|
|
40
|
+
issues
|
|
41
|
+
},
|
|
42
|
+
{ cause: result.error }
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function validateNodeProps(schema, props, context) {
|
|
46
|
+
return validateProps(schema, props, {
|
|
47
|
+
entityType: "node",
|
|
48
|
+
...context
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function validateEdgeProps(schema, props, context) {
|
|
52
|
+
return validateProps(schema, props, {
|
|
53
|
+
entityType: "edge",
|
|
54
|
+
...context
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function wrapZodError(error, context) {
|
|
58
|
+
const issues = zodIssuesToValidationIssues(error);
|
|
59
|
+
const location = buildLocationString(context);
|
|
60
|
+
return new chunkNI72YOJB_cjs.ValidationError(
|
|
61
|
+
`Validation failed for ${context.entityType} ${location}: ${error.message}`,
|
|
62
|
+
{
|
|
63
|
+
entityType: context.entityType,
|
|
64
|
+
kind: context.kind,
|
|
65
|
+
operation: context.operation,
|
|
66
|
+
...context.id !== void 0 && { id: context.id },
|
|
67
|
+
issues
|
|
68
|
+
},
|
|
69
|
+
{ cause: error }
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
function createValidationError(message, issues, context) {
|
|
73
|
+
return new chunkNI72YOJB_cjs.ValidationError(message, {
|
|
74
|
+
...context?.entityType !== void 0 && {
|
|
75
|
+
entityType: context.entityType
|
|
76
|
+
},
|
|
77
|
+
...context?.kind !== void 0 && { kind: context.kind },
|
|
78
|
+
...context?.operation !== void 0 && { operation: context.operation },
|
|
79
|
+
...context?.id !== void 0 && { id: context.id },
|
|
80
|
+
issues
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/utils/tuple-key.ts
|
|
85
|
+
function encodeTupleKey(values) {
|
|
86
|
+
return JSON.stringify(values);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/identity/row-codec.ts
|
|
90
|
+
function toCanonicalIdentityTimestamp(value) {
|
|
91
|
+
const canonical = chunkQ7Q4WSLJ_cjs.canonicalizeDatabaseTimestamp(value);
|
|
92
|
+
if (canonical === void 0) {
|
|
93
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
94
|
+
"Identity relation returned a timestamp that is not a representable instant.",
|
|
95
|
+
{ value },
|
|
96
|
+
{
|
|
97
|
+
suggestion: "Inspect the identity assertion rows for a corrupt timestamp column."
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return canonical;
|
|
102
|
+
}
|
|
103
|
+
function optionalIdentityTimestamp(value) {
|
|
104
|
+
return value === void 0 || value === null ? void 0 : toCanonicalIdentityTimestamp(value);
|
|
105
|
+
}
|
|
106
|
+
function normalizeIdentityAssertionRow(row) {
|
|
107
|
+
return {
|
|
108
|
+
graph_id: row.graph_id,
|
|
109
|
+
id: row.id,
|
|
110
|
+
rel: row.rel,
|
|
111
|
+
a_kind: row.a_kind,
|
|
112
|
+
a_id: row.a_id,
|
|
113
|
+
b_kind: row.b_kind,
|
|
114
|
+
b_id: row.b_id,
|
|
115
|
+
valid_from: toCanonicalIdentityTimestamp(row.valid_from),
|
|
116
|
+
valid_to: optionalIdentityTimestamp(row.valid_to),
|
|
117
|
+
created_at: toCanonicalIdentityTimestamp(row.created_at),
|
|
118
|
+
updated_at: toCanonicalIdentityTimestamp(row.updated_at),
|
|
119
|
+
deleted_at: optionalIdentityTimestamp(row.deleted_at),
|
|
120
|
+
ended_by_kind: row.ended_by_kind ?? void 0,
|
|
121
|
+
ended_by_id: row.ended_by_id ?? void 0
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function toTransferAssertion(row) {
|
|
125
|
+
return {
|
|
126
|
+
id: row.id,
|
|
127
|
+
relation: row.rel,
|
|
128
|
+
a: { kind: row.a_kind, id: row.a_id },
|
|
129
|
+
b: { kind: row.b_kind, id: row.b_id },
|
|
130
|
+
validFrom: row.valid_from,
|
|
131
|
+
...row.valid_to === void 0 ? {} : { validTo: row.valid_to },
|
|
132
|
+
...row.ended_by_kind === void 0 || row.ended_by_id === void 0 ? {} : { endedBy: { kind: row.ended_by_kind, id: row.ended_by_id } }
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/identity/reference.ts
|
|
137
|
+
function identityReferenceKey(ref) {
|
|
138
|
+
return encodeTupleKey([ref.kind, ref.id]);
|
|
139
|
+
}
|
|
140
|
+
function compareIdentityReferences(left, right) {
|
|
141
|
+
const kindOrder = chunkXMQSEJCF_cjs.compareCodePoints(left.kind, right.kind);
|
|
142
|
+
return kindOrder === 0 ? chunkXMQSEJCF_cjs.compareCodePoints(left.id, right.id) : kindOrder;
|
|
143
|
+
}
|
|
144
|
+
function normalizeIdentityPair(first, second) {
|
|
145
|
+
return compareIdentityReferences(first, second) <= 0 ? [first, second] : [second, first];
|
|
146
|
+
}
|
|
147
|
+
function identityReferencesContain(members, ref) {
|
|
148
|
+
const key = identityReferenceKey(ref);
|
|
149
|
+
return members.some((member) => identityReferenceKey(member) === key);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/identity/different-assertion.ts
|
|
153
|
+
function spanningDifferentAssertion(assertions, first, second) {
|
|
154
|
+
const firstKeys = new Set(
|
|
155
|
+
first.map((reference) => identityReferenceKey(reference))
|
|
156
|
+
);
|
|
157
|
+
const secondKeys = new Set(
|
|
158
|
+
second.map((reference) => identityReferenceKey(reference))
|
|
159
|
+
);
|
|
160
|
+
return assertions.find((assertion) => {
|
|
161
|
+
if (assertion.rel !== "different") return false;
|
|
162
|
+
const firstEndpoint = identityReferenceKey({
|
|
163
|
+
kind: assertion.a_kind,
|
|
164
|
+
id: assertion.a_id
|
|
165
|
+
});
|
|
166
|
+
const secondEndpoint = identityReferenceKey({
|
|
167
|
+
kind: assertion.b_kind,
|
|
168
|
+
id: assertion.b_id
|
|
169
|
+
});
|
|
170
|
+
return firstKeys.has(firstEndpoint) && secondKeys.has(secondEndpoint) || firstKeys.has(secondEndpoint) && secondKeys.has(firstEndpoint);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/identity/sql-target.ts
|
|
175
|
+
var MAX_REFERENCE_CHUNK_SIZE = 200;
|
|
176
|
+
function identityChunkSize(target, input) {
|
|
177
|
+
const parameterLimit = chunkXMQSEJCF_cjs.recordedBindParamBudget(target);
|
|
178
|
+
const chunkSize = Math.floor(
|
|
179
|
+
(parameterLimit - input.fixedParameters) / input.parametersPerItem
|
|
180
|
+
);
|
|
181
|
+
if (chunkSize < 1) {
|
|
182
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
183
|
+
"Operational Identity cannot fit this statement within the backend bind-parameter limit.",
|
|
184
|
+
{
|
|
185
|
+
code: "IDENTITY_BIND_BUDGET_TOO_SMALL",
|
|
186
|
+
parameterLimit,
|
|
187
|
+
fixedParameters: input.fixedParameters,
|
|
188
|
+
parametersPerItem: input.parametersPerItem
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return Math.min(input.maxItems, chunkSize);
|
|
193
|
+
}
|
|
194
|
+
function requireStatementTarget(target) {
|
|
195
|
+
if (target.executeStatement === void 0) {
|
|
196
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
197
|
+
"Operational Identity requires statement execution support.",
|
|
198
|
+
{ code: "IDENTITY_REQUIRES_STATEMENT_EXECUTION" },
|
|
199
|
+
{
|
|
200
|
+
suggestion: "Use a built-in transactional SQLite or PostgreSQL backend."
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function identityWriterSlotError(cause) {
|
|
206
|
+
return new chunkNI72YOJB_cjs.ConfigurationError(
|
|
207
|
+
"Operational Identity could not take the SQLite writer slot: this transaction was begun DEFERRED and another connection committed before the identity write, so its read snapshot is stale.",
|
|
208
|
+
{
|
|
209
|
+
code: "IDENTITY_TRANSACTION_NOT_WRITE_FENCED",
|
|
210
|
+
sqliteCode: "SQLITE_BUSY_SNAPSHOT"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
cause,
|
|
214
|
+
suggestion: "Roll back and re-run the transaction (SQLite cannot upgrade a stale snapshot in place). Identity mutations serialize on the writer slot, so an adopted transaction must be opened with BEGIN IMMEDIATE \u2014 or run the writes through store.transaction(), which already does."
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
async function executeIdentityStatement(target, statement) {
|
|
219
|
+
requireStatementTarget(target);
|
|
220
|
+
try {
|
|
221
|
+
await target.executeStatement(chunkVCRRKBLN_cjs.asCompiledStatementSql(statement));
|
|
222
|
+
} catch (error) {
|
|
223
|
+
if (!chunkBSFJMMV3_cjs.isSqliteStaleSnapshotError(error)) throw error;
|
|
224
|
+
throw identityWriterSlotError(error);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/identity/service-read.ts
|
|
229
|
+
var MAX_CLOSURE_INSERT_CHUNK_SIZE = 100;
|
|
230
|
+
var MAX_ASSERTION_INSERT_CHUNK_SIZE = 50;
|
|
231
|
+
function plainRef(ref) {
|
|
232
|
+
return { kind: ref.kind, id: ref.id };
|
|
233
|
+
}
|
|
234
|
+
function registeredPlainRef(ctx, ref) {
|
|
235
|
+
const result = plainRef(ref);
|
|
236
|
+
if (!ctx.registry.nodeKinds.has(result.kind)) {
|
|
237
|
+
throw new chunkNI72YOJB_cjs.KindNotFoundError(result.kind, "node", {
|
|
238
|
+
graphId: ctx.graphId
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
function refKey(ref) {
|
|
244
|
+
return identityReferenceKey(ref);
|
|
245
|
+
}
|
|
246
|
+
function containsRef(members, ref) {
|
|
247
|
+
return identityReferencesContain(members, ref);
|
|
248
|
+
}
|
|
249
|
+
function compareReferences(left, right) {
|
|
250
|
+
return compareIdentityReferences(left, right);
|
|
251
|
+
}
|
|
252
|
+
function normalizePair(first, second) {
|
|
253
|
+
return normalizeIdentityPair(first, second);
|
|
254
|
+
}
|
|
255
|
+
function clampValidTo(timestamp, validFrom) {
|
|
256
|
+
return chunkXMQSEJCF_cjs.compareCodePoints(timestamp, validFrom) < 0 ? validFrom : timestamp;
|
|
257
|
+
}
|
|
258
|
+
function publicAssertion(row) {
|
|
259
|
+
return {
|
|
260
|
+
id: row.id,
|
|
261
|
+
relation: row.rel,
|
|
262
|
+
a: publicNodeRef({ kind: row.a_kind, id: row.a_id }),
|
|
263
|
+
b: publicNodeRef({ kind: row.b_kind, id: row.b_id }),
|
|
264
|
+
validFrom: row.valid_from,
|
|
265
|
+
...row.valid_to === void 0 ? {} : { validTo: row.valid_to }
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function assertionResult(assertion, action) {
|
|
269
|
+
return { assertion, action };
|
|
270
|
+
}
|
|
271
|
+
function publicNodeRef(ref) {
|
|
272
|
+
return ref;
|
|
273
|
+
}
|
|
274
|
+
async function lockIdentityGraph(target, graphId) {
|
|
275
|
+
if (target.dialect !== "postgres") return;
|
|
276
|
+
await target.execute(
|
|
277
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
278
|
+
SELECT pg_advisory_xact_lock(
|
|
279
|
+
hashtext('typegraph:identity'),
|
|
280
|
+
hashtext(${graphId})
|
|
281
|
+
)
|
|
282
|
+
`)
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
async function lockIdentityEnablementNodes(target, schema) {
|
|
286
|
+
if (target.dialect !== "postgres") return;
|
|
287
|
+
await executeIdentityStatement(
|
|
288
|
+
target,
|
|
289
|
+
chunkVCRRKBLN_cjs.sql`LOCK TABLE ${schema.nodesTable} IN SHARE MODE`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
async function loadNodeSnapshot(target, schema, graphId, coordinate) {
|
|
293
|
+
const sqlCoordinate = chunkXMQSEJCF_cjs.identitySqlCoordinate(coordinate, chunkQ7Q4WSLJ_cjs.nowIso());
|
|
294
|
+
const rows = await target.execute(
|
|
295
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(
|
|
296
|
+
chunkXMQSEJCF_cjs.identityNodeSnapshotSource(schema, graphId, sqlCoordinate)
|
|
297
|
+
)
|
|
298
|
+
);
|
|
299
|
+
return rows.map((row) => ({
|
|
300
|
+
ref: { kind: row.kind, id: row.id },
|
|
301
|
+
validFrom: optionalIdentityTimestamp(row.valid_from),
|
|
302
|
+
validTo: optionalIdentityTimestamp(row.valid_to),
|
|
303
|
+
createdAt: toCanonicalIdentityTimestamp(row.created_at),
|
|
304
|
+
deletedAt: optionalIdentityTimestamp(row.deleted_at)
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
function isCurrentClosureCoordinate(coordinate) {
|
|
308
|
+
return coordinate?.recorded === void 0 && (coordinate?.valid.mode ?? "current") === "current";
|
|
309
|
+
}
|
|
310
|
+
async function loadCurrentStructuralClasses(target, schema, graphId, references) {
|
|
311
|
+
const uniqueByKey = /* @__PURE__ */ new Map();
|
|
312
|
+
for (const ref of references) uniqueByKey.set(refKey(ref), ref);
|
|
313
|
+
const uniqueReferences = [...uniqueByKey.values()];
|
|
314
|
+
if (uniqueReferences.length === 0) return /* @__PURE__ */ new Map();
|
|
315
|
+
const chunkSize = identityChunkSize(target, {
|
|
316
|
+
fixedParameters: 2,
|
|
317
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
318
|
+
parametersPerItem: 2
|
|
319
|
+
});
|
|
320
|
+
if (uniqueReferences.length > chunkSize) {
|
|
321
|
+
const combined = /* @__PURE__ */ new Map();
|
|
322
|
+
for (const refChunk of chunkBSFJMMV3_cjs.chunk(uniqueReferences, chunkSize)) {
|
|
323
|
+
const classes2 = await loadCurrentStructuralClasses(
|
|
324
|
+
target,
|
|
325
|
+
schema,
|
|
326
|
+
graphId,
|
|
327
|
+
refChunk
|
|
328
|
+
);
|
|
329
|
+
for (const [key, members] of classes2) combined.set(key, members);
|
|
330
|
+
}
|
|
331
|
+
return combined;
|
|
332
|
+
}
|
|
333
|
+
const seedRows = chunkVCRRKBLN_cjs.sql.join(
|
|
334
|
+
uniqueReferences.map((ref) => chunkVCRRKBLN_cjs.sql`(${ref.kind}, ${ref.id})`),
|
|
335
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
336
|
+
);
|
|
337
|
+
const rows = await target.execute(
|
|
338
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
339
|
+
WITH seeds(seed_kind, seed_id) AS (
|
|
340
|
+
VALUES ${seedRows}
|
|
341
|
+
), anchors AS (
|
|
342
|
+
SELECT seeds.seed_kind, seeds.seed_id,
|
|
343
|
+
COALESCE(anchor.class_kind, seeds.seed_kind) AS class_kind,
|
|
344
|
+
COALESCE(anchor.class_id, seeds.seed_id) AS class_id
|
|
345
|
+
FROM seeds
|
|
346
|
+
LEFT JOIN ${schema.identityClosureTable} anchor
|
|
347
|
+
ON anchor.graph_id = ${graphId}
|
|
348
|
+
AND anchor.member_kind = seeds.seed_kind
|
|
349
|
+
AND anchor.member_id = seeds.seed_id
|
|
350
|
+
)
|
|
351
|
+
SELECT anchors.seed_kind, anchors.seed_id,
|
|
352
|
+
COALESCE(member.member_kind, anchors.seed_kind) AS member_kind,
|
|
353
|
+
COALESCE(member.member_id, anchors.seed_id) AS member_id
|
|
354
|
+
FROM anchors
|
|
355
|
+
LEFT JOIN ${schema.identityClosureTable} member
|
|
356
|
+
ON member.graph_id = ${graphId}
|
|
357
|
+
AND member.class_kind = anchors.class_kind
|
|
358
|
+
AND member.class_id = anchors.class_id
|
|
359
|
+
`)
|
|
360
|
+
);
|
|
361
|
+
const classes = /* @__PURE__ */ new Map();
|
|
362
|
+
for (const row of rows) {
|
|
363
|
+
const seedKey = refKey({ kind: row.seed_kind, id: row.seed_id });
|
|
364
|
+
const members = classes.get(seedKey) ?? [];
|
|
365
|
+
members.push({ kind: row.member_kind, id: row.member_id });
|
|
366
|
+
classes.set(seedKey, members);
|
|
367
|
+
}
|
|
368
|
+
return new Map(
|
|
369
|
+
[...classes].map(([seedKey, members]) => [
|
|
370
|
+
seedKey,
|
|
371
|
+
members.toSorted((left, right) => compareReferences(left, right))
|
|
372
|
+
])
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
async function loadCurrentVisibleMembers(target, schema, graphId, ref) {
|
|
376
|
+
const now = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
377
|
+
const coordinate = chunkXMQSEJCF_cjs.identitySqlCoordinate(void 0, now);
|
|
378
|
+
const rows = await target.execute(
|
|
379
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
380
|
+
WITH anchor AS (
|
|
381
|
+
SELECT class_kind, class_id
|
|
382
|
+
FROM ${schema.identityClosureTable}
|
|
383
|
+
WHERE graph_id = ${graphId}
|
|
384
|
+
AND member_kind = ${ref.kind}
|
|
385
|
+
AND member_id = ${ref.id}
|
|
386
|
+
), members(kind, id) AS (
|
|
387
|
+
SELECT closure.member_kind, closure.member_id
|
|
388
|
+
FROM anchor
|
|
389
|
+
JOIN ${schema.identityClosureTable} closure
|
|
390
|
+
ON closure.graph_id = ${graphId}
|
|
391
|
+
AND closure.class_kind = anchor.class_kind
|
|
392
|
+
AND closure.class_id = anchor.class_id
|
|
393
|
+
UNION ALL
|
|
394
|
+
SELECT ${ref.kind}, ${ref.id}
|
|
395
|
+
WHERE NOT EXISTS (SELECT 1 FROM anchor)
|
|
396
|
+
)
|
|
397
|
+
SELECT n.kind, n.id
|
|
398
|
+
FROM members m
|
|
399
|
+
CROSS JOIN ${schema.nodesTable} n
|
|
400
|
+
WHERE n.graph_id = ${graphId}
|
|
401
|
+
AND n.kind = m.kind
|
|
402
|
+
AND n.id = m.id
|
|
403
|
+
AND ${chunkXMQSEJCF_cjs.identityNodeVisibilitySql(coordinate, "n")}
|
|
404
|
+
`)
|
|
405
|
+
);
|
|
406
|
+
const members = rows.map((row) => ({ kind: row.kind, id: row.id })).toSorted((left, right) => compareReferences(left, right));
|
|
407
|
+
return containsRef(members, ref) ? members : [];
|
|
408
|
+
}
|
|
409
|
+
async function loadHistoricalVisibleMembers(target, schema, graphId, ref, coordinate, sameIdAcrossKinds) {
|
|
410
|
+
const classes = await loadHistoricalClasses(
|
|
411
|
+
target,
|
|
412
|
+
schema,
|
|
413
|
+
graphId,
|
|
414
|
+
[ref],
|
|
415
|
+
coordinate,
|
|
416
|
+
sameIdAcrossKinds
|
|
417
|
+
);
|
|
418
|
+
return chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(ref))).visible;
|
|
419
|
+
}
|
|
420
|
+
async function loadHistoricalClasses(target, schema, graphId, references, coordinate, sameIdAcrossKinds) {
|
|
421
|
+
const uniqueByKey = /* @__PURE__ */ new Map();
|
|
422
|
+
for (const ref of references) uniqueByKey.set(refKey(ref), ref);
|
|
423
|
+
const uniqueReferences = [...uniqueByKey.values()];
|
|
424
|
+
const emptyClasses = new Map(
|
|
425
|
+
uniqueReferences.map((ref) => [
|
|
426
|
+
refKey(ref),
|
|
427
|
+
{ structural: [], visible: [] }
|
|
428
|
+
])
|
|
429
|
+
);
|
|
430
|
+
if (uniqueReferences.length === 0) return emptyClasses;
|
|
431
|
+
const chunkSize = identityChunkSize(target, {
|
|
432
|
+
fixedParameters: 24,
|
|
433
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
434
|
+
parametersPerItem: 2
|
|
435
|
+
});
|
|
436
|
+
if (uniqueReferences.length > chunkSize) {
|
|
437
|
+
const combined = /* @__PURE__ */ new Map();
|
|
438
|
+
for (const refChunk of chunkBSFJMMV3_cjs.chunk(uniqueReferences, chunkSize)) {
|
|
439
|
+
const classes = await loadHistoricalClasses(
|
|
440
|
+
target,
|
|
441
|
+
schema,
|
|
442
|
+
graphId,
|
|
443
|
+
refChunk,
|
|
444
|
+
coordinate,
|
|
445
|
+
sameIdAcrossKinds
|
|
446
|
+
);
|
|
447
|
+
for (const [key, value] of classes) combined.set(key, value);
|
|
448
|
+
}
|
|
449
|
+
return combined;
|
|
450
|
+
}
|
|
451
|
+
const currentInstant = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
452
|
+
const sqlCoordinate = chunkXMQSEJCF_cjs.identitySqlCoordinate(coordinate, currentInstant);
|
|
453
|
+
const seeds = chunkVCRRKBLN_cjs.sql.join(
|
|
454
|
+
uniqueReferences.map((ref) => chunkVCRRKBLN_cjs.sql`(${ref.kind}, ${ref.id})`),
|
|
455
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
456
|
+
);
|
|
457
|
+
const reconstruction = chunkXMQSEJCF_cjs.historicalIdentityReconstructionCtes({
|
|
458
|
+
schema,
|
|
459
|
+
graphId,
|
|
460
|
+
coordinate: sqlCoordinate,
|
|
461
|
+
seedSource: chunkVCRRKBLN_cjs.sql`VALUES ${seeds}`,
|
|
462
|
+
sameIdAcrossKinds
|
|
463
|
+
});
|
|
464
|
+
const rows = await target.execute(
|
|
465
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
466
|
+
WITH RECURSIVE
|
|
467
|
+
${reconstruction}
|
|
468
|
+
SELECT member.seed_kind, member.seed_id,
|
|
469
|
+
member.kind AS member_kind, member.id AS member_id,
|
|
470
|
+
CASE WHEN ${chunkXMQSEJCF_cjs.identityNodeVisibilitySql(sqlCoordinate, "n")}
|
|
471
|
+
THEN 1 ELSE 0 END AS is_visible
|
|
472
|
+
FROM identity_members member
|
|
473
|
+
JOIN node_snapshot n ON n.kind = member.kind AND n.id = member.id
|
|
474
|
+
`)
|
|
475
|
+
);
|
|
476
|
+
const structuralBySeed = /* @__PURE__ */ new Map();
|
|
477
|
+
const visibleBySeed = /* @__PURE__ */ new Map();
|
|
478
|
+
for (const row of rows) {
|
|
479
|
+
const seedKey = refKey({ kind: row.seed_kind, id: row.seed_id });
|
|
480
|
+
const member = { kind: row.member_kind, id: row.member_id };
|
|
481
|
+
const structural = structuralBySeed.get(seedKey) ?? [];
|
|
482
|
+
structural.push(member);
|
|
483
|
+
structuralBySeed.set(seedKey, structural);
|
|
484
|
+
if (!row.is_visible) continue;
|
|
485
|
+
const visible = visibleBySeed.get(seedKey) ?? [];
|
|
486
|
+
visible.push(member);
|
|
487
|
+
visibleBySeed.set(seedKey, visible);
|
|
488
|
+
}
|
|
489
|
+
return new Map(
|
|
490
|
+
uniqueReferences.map((ref) => {
|
|
491
|
+
const key = refKey(ref);
|
|
492
|
+
return [
|
|
493
|
+
key,
|
|
494
|
+
{
|
|
495
|
+
structural: (structuralBySeed.get(key) ?? []).toSorted(
|
|
496
|
+
(left, right) => compareReferences(left, right)
|
|
497
|
+
),
|
|
498
|
+
visible: (visibleBySeed.get(key) ?? []).toSorted(
|
|
499
|
+
(left, right) => compareReferences(left, right)
|
|
500
|
+
)
|
|
501
|
+
}
|
|
502
|
+
];
|
|
503
|
+
})
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
function visibleMembersAtCoordinate(ctx, ref) {
|
|
507
|
+
const { coordinate } = ctx;
|
|
508
|
+
if (coordinate === void 0 || isCurrentClosureCoordinate(coordinate)) {
|
|
509
|
+
return loadCurrentVisibleMembers(ctx.backend, ctx.schema, ctx.graphId, ref);
|
|
510
|
+
}
|
|
511
|
+
return loadHistoricalVisibleMembers(
|
|
512
|
+
ctx.backend,
|
|
513
|
+
ctx.schema,
|
|
514
|
+
ctx.graphId,
|
|
515
|
+
ref,
|
|
516
|
+
coordinate,
|
|
517
|
+
ctx.sameIdAcrossKinds
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
async function loadAssertions(target, schema, graphId, coordinate, currentInstant) {
|
|
521
|
+
const source = chunkXMQSEJCF_cjs.identityAssertionSnapshotSource(
|
|
522
|
+
schema,
|
|
523
|
+
graphId,
|
|
524
|
+
chunkXMQSEJCF_cjs.identitySqlCoordinate(coordinate, currentInstant),
|
|
525
|
+
void 0
|
|
526
|
+
);
|
|
527
|
+
const rows = await target.execute(
|
|
528
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(source)
|
|
529
|
+
);
|
|
530
|
+
return rows.map((row) => normalizeIdentityAssertionRow(row));
|
|
531
|
+
}
|
|
532
|
+
function referenceCondition(kindColumn, idColumn, references) {
|
|
533
|
+
if (references.length === 0) return chunkVCRRKBLN_cjs.sql`1 = 0`;
|
|
534
|
+
return chunkVCRRKBLN_cjs.sql`(${chunkVCRRKBLN_cjs.sql.join(
|
|
535
|
+
references.map(
|
|
536
|
+
(ref) => chunkVCRRKBLN_cjs.sql`(${kindColumn} = ${ref.kind} AND ${idColumn} = ${ref.id})`
|
|
537
|
+
),
|
|
538
|
+
chunkVCRRKBLN_cjs.sql` OR `
|
|
539
|
+
)})`;
|
|
540
|
+
}
|
|
541
|
+
async function loadAssertionsTouching(target, schema, graphId, references, coordinate, relation) {
|
|
542
|
+
if (references.length === 0) return [];
|
|
543
|
+
const chunkSize = identityChunkSize(target, {
|
|
544
|
+
fixedParameters: 16,
|
|
545
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
546
|
+
parametersPerItem: 4
|
|
547
|
+
});
|
|
548
|
+
if (references.length > chunkSize) {
|
|
549
|
+
const byId = /* @__PURE__ */ new Map();
|
|
550
|
+
for (const refChunk of chunkBSFJMMV3_cjs.chunk(references, chunkSize)) {
|
|
551
|
+
const assertions = await loadAssertionsTouching(
|
|
552
|
+
target,
|
|
553
|
+
schema,
|
|
554
|
+
graphId,
|
|
555
|
+
refChunk,
|
|
556
|
+
coordinate,
|
|
557
|
+
relation
|
|
558
|
+
);
|
|
559
|
+
for (const assertion of assertions) byId.set(assertion.id, assertion);
|
|
560
|
+
}
|
|
561
|
+
return [...byId.values()];
|
|
562
|
+
}
|
|
563
|
+
const source = chunkXMQSEJCF_cjs.identityAssertionSnapshotSource(
|
|
564
|
+
schema,
|
|
565
|
+
graphId,
|
|
566
|
+
chunkXMQSEJCF_cjs.identitySqlCoordinate(coordinate, chunkQ7Q4WSLJ_cjs.nowIso()),
|
|
567
|
+
relation
|
|
568
|
+
);
|
|
569
|
+
const aMatches = referenceCondition(
|
|
570
|
+
chunkVCRRKBLN_cjs.sql`identity_assertions.a_kind`,
|
|
571
|
+
chunkVCRRKBLN_cjs.sql`identity_assertions.a_id`,
|
|
572
|
+
references
|
|
573
|
+
);
|
|
574
|
+
const bMatches = referenceCondition(
|
|
575
|
+
chunkVCRRKBLN_cjs.sql`identity_assertions.b_kind`,
|
|
576
|
+
chunkVCRRKBLN_cjs.sql`identity_assertions.b_id`,
|
|
577
|
+
references
|
|
578
|
+
);
|
|
579
|
+
const rows = await target.execute(
|
|
580
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
581
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
582
|
+
FROM (${source}) identity_assertions
|
|
583
|
+
WHERE ${aMatches} OR ${bMatches}
|
|
584
|
+
`)
|
|
585
|
+
);
|
|
586
|
+
return rows.map((row) => normalizeIdentityAssertionRow(row));
|
|
587
|
+
}
|
|
588
|
+
async function loadSpanningDifferentAssertion(target, schema, graphId, firstClass, secondClass, coordinate) {
|
|
589
|
+
const assertions = await loadAssertionsTouching(
|
|
590
|
+
target,
|
|
591
|
+
schema,
|
|
592
|
+
graphId,
|
|
593
|
+
firstClass,
|
|
594
|
+
coordinate,
|
|
595
|
+
"different"
|
|
596
|
+
);
|
|
597
|
+
return spanningDifferentAssertion(assertions, firstClass, secondClass);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/identity/interchange-read.ts
|
|
601
|
+
function codePointOrderedAssertionId(target) {
|
|
602
|
+
return chunk4UGOKMI5_cjs.getDialect(target.dialect).binaryText(chunkVCRRKBLN_cjs.sql`identity_assertions.id`);
|
|
603
|
+
}
|
|
604
|
+
async function readIdentityAssertionPageAtTarget(ctx, target, mode, options) {
|
|
605
|
+
if (!Number.isSafeInteger(options.limit) || options.limit <= 0) {
|
|
606
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
607
|
+
"Identity assertion page limit must be a positive safe integer.",
|
|
608
|
+
{ limit: options.limit }
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
const nodeKinds = options.nodeKinds === void 0 ? void 0 : [...new Set(options.nodeKinds)];
|
|
612
|
+
const kindFilterChunkSize = nodeKinds === void 0 || nodeKinds.length === 0 ? MAX_REFERENCE_CHUNK_SIZE : identityChunkSize(target, {
|
|
613
|
+
fixedParameters: 16,
|
|
614
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
615
|
+
parametersPerItem: 2
|
|
616
|
+
});
|
|
617
|
+
const filterKindsInMemory = nodeKinds !== void 0 && nodeKinds.length > kindFilterChunkSize;
|
|
618
|
+
const kindFilter = nodeKinds === void 0 ? chunkVCRRKBLN_cjs.sql`` : nodeKinds.length === 0 ? chunkVCRRKBLN_cjs.sql`AND 1 = 0` : filterKindsInMemory ? chunkVCRRKBLN_cjs.sql`` : chunkVCRRKBLN_cjs.sql`
|
|
619
|
+
AND identity_assertions.a_kind IN (${chunkVCRRKBLN_cjs.sql.join(
|
|
620
|
+
nodeKinds.map((kind) => chunkVCRRKBLN_cjs.sql`${kind}`),
|
|
621
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
622
|
+
)})
|
|
623
|
+
AND identity_assertions.b_kind IN (${chunkVCRRKBLN_cjs.sql.join(
|
|
624
|
+
nodeKinds.map((kind) => chunkVCRRKBLN_cjs.sql`${kind}`),
|
|
625
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
626
|
+
)})
|
|
627
|
+
`;
|
|
628
|
+
const liveEndpointJoins = options.includeDeleted === false ? chunkVCRRKBLN_cjs.sql`
|
|
629
|
+
JOIN ${ctx.schema.nodesTable} identity_a_node
|
|
630
|
+
ON identity_a_node.graph_id = identity_assertions.graph_id
|
|
631
|
+
AND identity_a_node.kind = identity_assertions.a_kind
|
|
632
|
+
AND identity_a_node.id = identity_assertions.a_id
|
|
633
|
+
AND identity_a_node.deleted_at IS NULL
|
|
634
|
+
JOIN ${ctx.schema.nodesTable} identity_b_node
|
|
635
|
+
ON identity_b_node.graph_id = identity_assertions.graph_id
|
|
636
|
+
AND identity_b_node.kind = identity_assertions.b_kind
|
|
637
|
+
AND identity_b_node.id = identity_assertions.b_id
|
|
638
|
+
AND identity_b_node.deleted_at IS NULL
|
|
639
|
+
` : chunkVCRRKBLN_cjs.sql``;
|
|
640
|
+
const assertionIdKey = codePointOrderedAssertionId(target);
|
|
641
|
+
const rows = await target.execute(
|
|
642
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
643
|
+
SELECT identity_assertions.graph_id AS graph_id,
|
|
644
|
+
identity_assertions.id AS id,
|
|
645
|
+
identity_assertions.rel AS rel,
|
|
646
|
+
identity_assertions.a_kind AS a_kind,
|
|
647
|
+
identity_assertions.a_id AS a_id,
|
|
648
|
+
identity_assertions.b_kind AS b_kind,
|
|
649
|
+
identity_assertions.b_id AS b_id,
|
|
650
|
+
identity_assertions.valid_from AS valid_from,
|
|
651
|
+
identity_assertions.valid_to AS valid_to,
|
|
652
|
+
identity_assertions.created_at AS created_at,
|
|
653
|
+
identity_assertions.updated_at AS updated_at,
|
|
654
|
+
identity_assertions.deleted_at AS deleted_at,
|
|
655
|
+
identity_assertions.ended_by_kind AS ended_by_kind,
|
|
656
|
+
identity_assertions.ended_by_id AS ended_by_id
|
|
657
|
+
FROM ${ctx.schema.identityAssertionsTable} identity_assertions
|
|
658
|
+
${liveEndpointJoins}
|
|
659
|
+
WHERE identity_assertions.graph_id = ${ctx.graphId}
|
|
660
|
+
AND identity_assertions.deleted_at IS NULL
|
|
661
|
+
${options.after === void 0 ? chunkVCRRKBLN_cjs.sql`` : chunkVCRRKBLN_cjs.sql`AND ${assertionIdKey} > ${options.after}`}
|
|
662
|
+
${mode === "state" ? chunkVCRRKBLN_cjs.sql`AND identity_assertions.valid_to IS NULL` : chunkVCRRKBLN_cjs.sql``}
|
|
663
|
+
${kindFilter}
|
|
664
|
+
ORDER BY ${assertionIdKey} ASC
|
|
665
|
+
LIMIT ${options.limit}
|
|
666
|
+
`)
|
|
667
|
+
);
|
|
668
|
+
const allowedKinds = filterKindsInMemory ? new Set(nodeKinds) : void 0;
|
|
669
|
+
const assertions = rows.filter(
|
|
670
|
+
(row) => allowedKinds === void 0 || allowedKinds.has(row.a_kind) && allowedKinds.has(row.b_kind)
|
|
671
|
+
).map((row) => toTransferAssertion(normalizeIdentityAssertionRow(row)));
|
|
672
|
+
const nextAfter = rows.at(-1)?.id;
|
|
673
|
+
return {
|
|
674
|
+
assertions,
|
|
675
|
+
...nextAfter === void 0 ? {} : { nextAfter },
|
|
676
|
+
done: rows.length < options.limit
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
async function readIdentityAssertionsForInterchange(ctx, mode, options) {
|
|
680
|
+
const page = await readIdentityAssertionPageAtTarget(ctx, ctx.backend, mode, {
|
|
681
|
+
...options,
|
|
682
|
+
limit: 2147483647
|
|
683
|
+
});
|
|
684
|
+
return page.assertions;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// src/store/operations/write-transaction.ts
|
|
688
|
+
var writeTransactionSessions = /* @__PURE__ */ new WeakMap();
|
|
689
|
+
var heldGraphWriteLocks = /* @__PURE__ */ new WeakMap();
|
|
690
|
+
async function withWriteTransactionSession(target, ctx, fn) {
|
|
691
|
+
const session = {
|
|
692
|
+
lock: void 0,
|
|
693
|
+
wrote: false
|
|
694
|
+
};
|
|
695
|
+
writeTransactionSessions.set(target, session);
|
|
696
|
+
try {
|
|
697
|
+
const result = await fn();
|
|
698
|
+
if (session.wrote && ctx.revisionTrackingEnabled && !ctx.historyEnabled) {
|
|
699
|
+
await chunkXMQSEJCF_cjs.advanceRevisionClock(target, ctx.revisionSchema, ctx.graphId, true);
|
|
700
|
+
}
|
|
701
|
+
return result;
|
|
702
|
+
} finally {
|
|
703
|
+
writeTransactionSessions.delete(target);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
async function lockSchemaVersionForStoreWrite(ctx, backend) {
|
|
707
|
+
const expectedVersion = ctx.schemaVersion;
|
|
708
|
+
if (expectedVersion === void 0) return;
|
|
709
|
+
if ("transaction" in backend && !backend.capabilities.transactions) {
|
|
710
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
711
|
+
"Schema-managed Store writes require a transactional backend so schema changes and entity writes can share one fence.",
|
|
712
|
+
{
|
|
713
|
+
code: "SCHEMA_WRITE_FENCE_UNSUPPORTED",
|
|
714
|
+
graphId: ctx.graphId
|
|
715
|
+
}
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
const lockSchemaVersionForWrite = backend.lockSchemaVersionForWrite;
|
|
719
|
+
if (lockSchemaVersionForWrite === void 0) {
|
|
720
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
721
|
+
"This backend cannot fence schema-managed Store writes against a concurrent schema change.",
|
|
722
|
+
{
|
|
723
|
+
code: "SCHEMA_WRITE_FENCE_UNSUPPORTED",
|
|
724
|
+
graphId: ctx.graphId
|
|
725
|
+
}
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
await lockSchemaVersionForWrite({
|
|
729
|
+
graphId: ctx.graphId,
|
|
730
|
+
expectedVersion
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
var CONSTRAINT_FENCE_ADVICE = {
|
|
734
|
+
edgeCardinality: 'declare the edge `cardinality: "many"` and enforce the limit in application code',
|
|
735
|
+
edgeMatchKeyConvergence: "use `create` with a caller-chosen id, whose uniqueness the edges primary key enforces, instead of `getOrCreateByEndpoints`",
|
|
736
|
+
nodeDisjointness: "drop the `disjointWith` axiom and keep ids distinct across those kinds yourself",
|
|
737
|
+
nodeUniquenessScope: 'scope the unique constraint to `"kind"`, which the uniques primary key enforces on its own'
|
|
738
|
+
};
|
|
739
|
+
function graphWriteFenceRefusal(ctx, backend, reason) {
|
|
740
|
+
if (!("transaction" in backend) || backend.capabilities.transactions) {
|
|
741
|
+
return void 0;
|
|
742
|
+
}
|
|
743
|
+
return new chunkNI72YOJB_cjs.ConfigurationError(
|
|
744
|
+
"This backend cannot fence a constrained write: enforcing a declared constraint requires a transaction to scope the per-graph write lock to, and this backend has no transactions.",
|
|
745
|
+
{
|
|
746
|
+
code: "CONSTRAINT_WRITE_FENCE_UNSUPPORTED",
|
|
747
|
+
graphId: ctx.graphId,
|
|
748
|
+
constraint: reason
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
suggestion: `Use a transactional backend, or ${CONSTRAINT_FENCE_ADVICE[reason]}. Unconstrained writes need no fence and keep working on this backend.`
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
function runInWriteTransaction(ctx, backend, fn, options) {
|
|
756
|
+
const ownsWriteLock = "transaction" in backend && backend.capabilities.transactions;
|
|
757
|
+
const fenceReason = options?.fencesConstraintProbe;
|
|
758
|
+
const refusal = fenceReason === void 0 ? void 0 : graphWriteFenceRefusal(ctx, backend, fenceReason);
|
|
759
|
+
if (refusal !== void 0) return Promise.reject(refusal);
|
|
760
|
+
const needsGraphWriteLock = ctx.historyEnabled || ctx.revisionTrackingEnabled || fenceReason !== void 0;
|
|
761
|
+
return chunkXBYVV3MP_cjs.runOptionallyInTransaction(backend, async (target) => {
|
|
762
|
+
await lockSchemaVersionForStoreWrite(ctx, target);
|
|
763
|
+
const session = needsGraphWriteLock ? writeTransactionSessions.get(target) : void 0;
|
|
764
|
+
const held = heldGraphWriteLocks.get(target) ?? /* @__PURE__ */ new Set();
|
|
765
|
+
heldGraphWriteLocks.set(target, held);
|
|
766
|
+
const acquiresLock = needsGraphWriteLock && session?.lock === void 0 && !held.has(ctx.graphId);
|
|
767
|
+
if (acquiresLock) held.add(ctx.graphId);
|
|
768
|
+
const lock = acquiresLock ? await chunkXMQSEJCF_cjs.lockRecordedGraphWrite(target, ctx.graphId).catch(
|
|
769
|
+
(error) => {
|
|
770
|
+
held.delete(ctx.graphId);
|
|
771
|
+
throw error;
|
|
772
|
+
}
|
|
773
|
+
) : session?.lock ?? chunkXMQSEJCF_cjs.uncapturedGraphWriteLock();
|
|
774
|
+
if (session !== void 0) session.lock = lock;
|
|
775
|
+
const result = await (acquiresLock ? fn(target, lock).finally(() => held.delete(ctx.graphId)) : fn(target, lock));
|
|
776
|
+
if (session !== void 0) {
|
|
777
|
+
session.wrote ||= options?.didWrite?.(result) ?? true;
|
|
778
|
+
return result;
|
|
779
|
+
}
|
|
780
|
+
if (ctx.revisionTrackingEnabled && !ctx.historyEnabled && (options?.didWrite?.(result) ?? true)) {
|
|
781
|
+
await chunkXMQSEJCF_cjs.advanceRevisionClock(
|
|
782
|
+
target,
|
|
783
|
+
ctx.revisionSchema,
|
|
784
|
+
ctx.graphId,
|
|
785
|
+
ownsWriteLock
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
return result;
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
function runHookedWriteOperation(ctx, opContext, backend, body, options) {
|
|
792
|
+
return ctx.withOperationHooks(
|
|
793
|
+
opContext,
|
|
794
|
+
() => runInWriteTransaction(ctx, backend, body, options)
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/identity/service-components.ts
|
|
799
|
+
var UnionFind = class {
|
|
800
|
+
#parents = /* @__PURE__ */ new Map();
|
|
801
|
+
#sizes = /* @__PURE__ */ new Map();
|
|
802
|
+
#refs = /* @__PURE__ */ new Map();
|
|
803
|
+
add(ref) {
|
|
804
|
+
const key = refKey(ref);
|
|
805
|
+
if (this.#parents.has(key)) return;
|
|
806
|
+
this.#parents.set(key, key);
|
|
807
|
+
this.#sizes.set(key, 1);
|
|
808
|
+
this.#refs.set(key, ref);
|
|
809
|
+
}
|
|
810
|
+
// Iterative walk-then-compress: an adversarially ordered chain of unions can
|
|
811
|
+
// build O(N) depth, which a recursive find would blow the stack on.
|
|
812
|
+
#find(key) {
|
|
813
|
+
let root = key;
|
|
814
|
+
for (; ; ) {
|
|
815
|
+
const parent = this.#parents.get(root);
|
|
816
|
+
if (parent === void 0) {
|
|
817
|
+
throw new Error(`Unknown identity member ${root}`);
|
|
818
|
+
}
|
|
819
|
+
if (parent === root) break;
|
|
820
|
+
root = parent;
|
|
821
|
+
}
|
|
822
|
+
let cursor = key;
|
|
823
|
+
while (cursor !== root) {
|
|
824
|
+
const next = chunkN66HCGCY_cjs.requireDefined(
|
|
825
|
+
this.#parents.get(cursor),
|
|
826
|
+
`Unknown identity member ${cursor}`
|
|
827
|
+
);
|
|
828
|
+
this.#parents.set(cursor, root);
|
|
829
|
+
cursor = next;
|
|
830
|
+
}
|
|
831
|
+
return root;
|
|
832
|
+
}
|
|
833
|
+
// Union by size keeps trees shallow. Canonical member selection is
|
|
834
|
+
// independent of root identity — components() sorts each group and takes the
|
|
835
|
+
// code-point-least member — so linking by size never changes the closure.
|
|
836
|
+
union(first, second) {
|
|
837
|
+
this.add(first);
|
|
838
|
+
this.add(second);
|
|
839
|
+
const firstRoot = this.#find(refKey(first));
|
|
840
|
+
const secondRoot = this.#find(refKey(second));
|
|
841
|
+
if (firstRoot === secondRoot) return;
|
|
842
|
+
const firstSize = chunkN66HCGCY_cjs.requireDefined(this.#sizes.get(firstRoot));
|
|
843
|
+
const secondSize = chunkN66HCGCY_cjs.requireDefined(this.#sizes.get(secondRoot));
|
|
844
|
+
const [root, child] = firstSize >= secondSize ? [firstRoot, secondRoot] : [secondRoot, firstRoot];
|
|
845
|
+
this.#parents.set(child, root);
|
|
846
|
+
this.#sizes.set(root, firstSize + secondSize);
|
|
847
|
+
}
|
|
848
|
+
// Public root accessor for callers that maintain their own member index
|
|
849
|
+
// incrementally (bulkAssertPairs) rather than re-deriving components().
|
|
850
|
+
root(ref) {
|
|
851
|
+
return this.#find(refKey(ref));
|
|
852
|
+
}
|
|
853
|
+
components() {
|
|
854
|
+
const groups = /* @__PURE__ */ new Map();
|
|
855
|
+
for (const [key, ref] of this.#refs) {
|
|
856
|
+
const root = this.#find(key);
|
|
857
|
+
const group = groups.get(root) ?? [];
|
|
858
|
+
group.push(ref);
|
|
859
|
+
groups.set(root, group);
|
|
860
|
+
}
|
|
861
|
+
const byMember = /* @__PURE__ */ new Map();
|
|
862
|
+
for (const group of groups.values()) {
|
|
863
|
+
const sorted = group.toSorted(
|
|
864
|
+
(left, right) => compareReferences(left, right)
|
|
865
|
+
);
|
|
866
|
+
for (const member of sorted) byMember.set(refKey(member), sorted);
|
|
867
|
+
}
|
|
868
|
+
return byMember;
|
|
869
|
+
}
|
|
870
|
+
};
|
|
871
|
+
function buildComponents(structuralNodes, assertions, sameIdAcrossKinds) {
|
|
872
|
+
const unionFind = new UnionFind();
|
|
873
|
+
const byId = /* @__PURE__ */ new Map();
|
|
874
|
+
for (const ref of structuralNodes) {
|
|
875
|
+
unionFind.add(ref);
|
|
876
|
+
const group = byId.get(ref.id) ?? [];
|
|
877
|
+
group.push(ref);
|
|
878
|
+
byId.set(ref.id, group);
|
|
879
|
+
}
|
|
880
|
+
if (sameIdAcrossKinds === "fold") {
|
|
881
|
+
for (const group of byId.values()) {
|
|
882
|
+
const first = group[0];
|
|
883
|
+
if (first === void 0) continue;
|
|
884
|
+
for (const member of group.slice(1)) unionFind.union(first, member);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
for (const assertion of assertions) {
|
|
888
|
+
if (assertion.rel !== "same") continue;
|
|
889
|
+
unionFind.union(
|
|
890
|
+
{ kind: assertion.a_kind, id: assertion.a_id },
|
|
891
|
+
{ kind: assertion.b_kind, id: assertion.b_id }
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
return unionFind.components();
|
|
895
|
+
}
|
|
896
|
+
function identityActiveKinds(registry) {
|
|
897
|
+
return new Set(registry.nodeKinds.keys());
|
|
898
|
+
}
|
|
899
|
+
async function loadSnapshot(target, schema, graphId, coordinate, allowedKinds, sameIdAcrossKinds = "fold") {
|
|
900
|
+
const currentInstant = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
901
|
+
const [nodes, assertions] = await Promise.all([
|
|
902
|
+
loadNodeSnapshot(target, schema, graphId, coordinate),
|
|
903
|
+
loadAssertions(target, schema, graphId, coordinate, currentInstant)
|
|
904
|
+
]);
|
|
905
|
+
const scopedNodes = allowedKinds === void 0 ? nodes : nodes.filter((node) => allowedKinds.has(node.ref.kind));
|
|
906
|
+
const scopedAssertions = allowedKinds === void 0 ? assertions : assertions.filter(
|
|
907
|
+
(assertion) => allowedKinds.has(assertion.a_kind) && allowedKinds.has(assertion.b_kind)
|
|
908
|
+
);
|
|
909
|
+
const structuralNodes = scopedNodes.filter((node) => node.deletedAt === void 0).map((node) => node.ref);
|
|
910
|
+
return {
|
|
911
|
+
nodes: scopedNodes,
|
|
912
|
+
structuralNodes,
|
|
913
|
+
assertions: scopedAssertions,
|
|
914
|
+
components: buildComponents(
|
|
915
|
+
structuralNodes,
|
|
916
|
+
scopedAssertions,
|
|
917
|
+
sameIdAcrossKinds
|
|
918
|
+
)
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
function componentFor(snapshot, ref) {
|
|
922
|
+
return snapshot.components.get(refKey(ref)) ?? [ref];
|
|
923
|
+
}
|
|
924
|
+
function sameComponent(snapshot, first, second) {
|
|
925
|
+
return containsRef(componentFor(snapshot, first), second);
|
|
926
|
+
}
|
|
927
|
+
function kindsOf(members) {
|
|
928
|
+
return new Set(members.map((member) => member.kind));
|
|
929
|
+
}
|
|
930
|
+
function classHasDisjointKinds(registry, first, second) {
|
|
931
|
+
return kindSetsHaveDisjointKinds(registry, kindsOf(first), kindsOf(second));
|
|
932
|
+
}
|
|
933
|
+
function kindSetsHaveDisjointKinds(registry, first, second) {
|
|
934
|
+
for (const left of first) {
|
|
935
|
+
for (const right of second) {
|
|
936
|
+
if (registry.areDisjoint(left, right)) return [left, right];
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
return void 0;
|
|
940
|
+
}
|
|
941
|
+
function indexDifferentAssertion(index, firstRoot, secondRoot, assertion) {
|
|
942
|
+
const firstNeighbors = index.get(firstRoot) ?? /* @__PURE__ */ new Map();
|
|
943
|
+
const secondNeighbors = index.get(secondRoot) ?? /* @__PURE__ */ new Map();
|
|
944
|
+
if (!firstNeighbors.has(secondRoot)) {
|
|
945
|
+
firstNeighbors.set(secondRoot, assertion);
|
|
946
|
+
}
|
|
947
|
+
if (!secondNeighbors.has(firstRoot)) {
|
|
948
|
+
secondNeighbors.set(firstRoot, assertion);
|
|
949
|
+
}
|
|
950
|
+
index.set(firstRoot, firstNeighbors);
|
|
951
|
+
index.set(secondRoot, secondNeighbors);
|
|
952
|
+
}
|
|
953
|
+
function mergeDifferentAssertionRoots(index, survivingRoot, retiredRoot) {
|
|
954
|
+
const survivingNeighbors = index.get(survivingRoot) ?? /* @__PURE__ */ new Map();
|
|
955
|
+
const retiredNeighbors = index.get(retiredRoot);
|
|
956
|
+
survivingNeighbors.delete(retiredRoot);
|
|
957
|
+
if (retiredNeighbors !== void 0) {
|
|
958
|
+
for (const [neighborRoot, assertion] of retiredNeighbors) {
|
|
959
|
+
if (neighborRoot === survivingRoot) continue;
|
|
960
|
+
const canonicalAssertion = survivingNeighbors.get(neighborRoot) ?? assertion;
|
|
961
|
+
survivingNeighbors.set(neighborRoot, canonicalAssertion);
|
|
962
|
+
const neighborMap = index.get(neighborRoot);
|
|
963
|
+
if (neighborMap !== void 0) {
|
|
964
|
+
neighborMap.delete(retiredRoot);
|
|
965
|
+
neighborMap.set(survivingRoot, canonicalAssertion);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
index.delete(retiredRoot);
|
|
970
|
+
if (survivingNeighbors.size === 0) {
|
|
971
|
+
index.delete(survivingRoot);
|
|
972
|
+
} else {
|
|
973
|
+
index.set(survivingRoot, survivingNeighbors);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
function validateSnapshotIntegrity(snapshot, registry, graphId) {
|
|
977
|
+
const structuralKeys = new Set(
|
|
978
|
+
snapshot.structuralNodes.map((ref) => refKey(ref))
|
|
979
|
+
);
|
|
980
|
+
for (const assertion of snapshot.assertions) {
|
|
981
|
+
const a = { kind: assertion.a_kind, id: assertion.a_id };
|
|
982
|
+
const b = { kind: assertion.b_kind, id: assertion.b_id };
|
|
983
|
+
if (!structuralKeys.has(refKey(a)) || !structuralKeys.has(refKey(b))) {
|
|
984
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
985
|
+
"Operational Identity contains a current assertion with a missing or deleted endpoint.",
|
|
986
|
+
{
|
|
987
|
+
code: "IDENTITY_SCHEMA_CONTRADICTION",
|
|
988
|
+
graphId,
|
|
989
|
+
assertionId: assertion.id,
|
|
990
|
+
a,
|
|
991
|
+
b
|
|
992
|
+
}
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
if (assertion.rel === "different" && sameComponent(snapshot, a, b)) {
|
|
996
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
997
|
+
"Operational Identity contains a different assertion within one identity class.",
|
|
998
|
+
{
|
|
999
|
+
code: "IDENTITY_SCHEMA_CONTRADICTION",
|
|
1000
|
+
graphId,
|
|
1001
|
+
assertionId: assertion.id,
|
|
1002
|
+
a,
|
|
1003
|
+
b
|
|
1004
|
+
}
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1009
|
+
for (const [memberKey, component] of snapshot.components) {
|
|
1010
|
+
if (visited.has(memberKey)) continue;
|
|
1011
|
+
for (const member of component) visited.add(refKey(member));
|
|
1012
|
+
const conflictingKinds = classHasDisjointKinds(
|
|
1013
|
+
registry,
|
|
1014
|
+
component,
|
|
1015
|
+
component
|
|
1016
|
+
);
|
|
1017
|
+
if (conflictingKinds !== void 0) {
|
|
1018
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
1019
|
+
"Operational Identity class conflicts with ontology disjointness.",
|
|
1020
|
+
{
|
|
1021
|
+
code: "IDENTITY_SCHEMA_CONTRADICTION",
|
|
1022
|
+
graphId,
|
|
1023
|
+
classMembers: component,
|
|
1024
|
+
conflictingKinds
|
|
1025
|
+
}
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
function closureMismatchError(graphId, detail) {
|
|
1031
|
+
return new chunkNI72YOJB_cjs.ConfigurationError(
|
|
1032
|
+
"Operational Identity materialized closure does not match computed identity components.",
|
|
1033
|
+
{ code: "IDENTITY_SCHEMA_CONTRADICTION", graphId, ...detail },
|
|
1034
|
+
{
|
|
1035
|
+
suggestion: "Run rebuildIdentityClosure(store) to rebuild the materialized identity closure."
|
|
1036
|
+
}
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
async function assertClosureMatchesComponents(target, schema, graphId, components) {
|
|
1040
|
+
const expected = /* @__PURE__ */ new Map();
|
|
1041
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
1042
|
+
for (const [memberKey, component] of components) {
|
|
1043
|
+
if (emitted.has(memberKey) || component.length < 2) continue;
|
|
1044
|
+
const canonical = chunkN66HCGCY_cjs.requireDefined(component[0]);
|
|
1045
|
+
for (const member of component) {
|
|
1046
|
+
const key = refKey(member);
|
|
1047
|
+
emitted.add(key);
|
|
1048
|
+
expected.set(key, { member, classRef: canonical });
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const rows = await target.execute(
|
|
1052
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1053
|
+
SELECT member_kind, member_id, class_kind, class_id
|
|
1054
|
+
FROM ${schema.identityClosureTable}
|
|
1055
|
+
WHERE graph_id = ${graphId}
|
|
1056
|
+
`)
|
|
1057
|
+
);
|
|
1058
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1059
|
+
for (const row of rows) {
|
|
1060
|
+
const member = { kind: row.member_kind, id: row.member_id };
|
|
1061
|
+
const memberKey = refKey(member);
|
|
1062
|
+
const match = expected.get(memberKey);
|
|
1063
|
+
if (match?.classRef.kind !== row.class_kind || match.classRef.id !== row.class_id) {
|
|
1064
|
+
throw closureMismatchError(graphId, {
|
|
1065
|
+
member,
|
|
1066
|
+
class: { kind: row.class_kind, id: row.class_id },
|
|
1067
|
+
expectedClass: match?.classRef
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
seen.add(memberKey);
|
|
1071
|
+
}
|
|
1072
|
+
for (const [memberKey, { member, classRef }] of expected) {
|
|
1073
|
+
if (seen.has(memberKey)) continue;
|
|
1074
|
+
throw closureMismatchError(graphId, {
|
|
1075
|
+
member,
|
|
1076
|
+
expectedClass: classRef,
|
|
1077
|
+
reason: "missing-closure-row"
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
function selfAssertionError(relation) {
|
|
1082
|
+
return new chunkNI72YOJB_cjs.ValidationError(
|
|
1083
|
+
`Identity ${relation} assertions require two distinct node references.`,
|
|
1084
|
+
{
|
|
1085
|
+
issues: [
|
|
1086
|
+
{
|
|
1087
|
+
path: "pair",
|
|
1088
|
+
message: "Identity self-assertions are not allowed",
|
|
1089
|
+
code: "IDENTITY_SELF_ASSERTION"
|
|
1090
|
+
}
|
|
1091
|
+
]
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
suggestion: "Filter reflexive pairs before calling an identity assertion method."
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
async function requireLiveEndpoint(target, graphId, ref) {
|
|
1099
|
+
const row = await target.getNode(graphId, ref.kind, ref.id);
|
|
1100
|
+
if (row === void 0 || row.deleted_at !== void 0) {
|
|
1101
|
+
throw new chunkNI72YOJB_cjs.NodeNotFoundError(ref.kind, ref.id);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
async function loadLiveReferences(target, schema, graphId, references) {
|
|
1105
|
+
if (references.length === 0) return [];
|
|
1106
|
+
const chunkSize = identityChunkSize(target, {
|
|
1107
|
+
fixedParameters: 1,
|
|
1108
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1109
|
+
parametersPerItem: 2
|
|
1110
|
+
});
|
|
1111
|
+
if (references.length > chunkSize) {
|
|
1112
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1113
|
+
for (const refChunk of chunkBSFJMMV3_cjs.chunk(references, chunkSize)) {
|
|
1114
|
+
const live = await loadLiveReferences(target, schema, graphId, refChunk);
|
|
1115
|
+
for (const ref of live) byKey.set(refKey(ref), ref);
|
|
1116
|
+
}
|
|
1117
|
+
return [...byKey.values()];
|
|
1118
|
+
}
|
|
1119
|
+
const matches = referenceCondition(chunkVCRRKBLN_cjs.sql`kind`, chunkVCRRKBLN_cjs.sql`id`, references);
|
|
1120
|
+
const rows = await target.execute(
|
|
1121
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1122
|
+
SELECT kind, id
|
|
1123
|
+
FROM ${schema.nodesTable}
|
|
1124
|
+
WHERE graph_id = ${graphId}
|
|
1125
|
+
AND deleted_at IS NULL
|
|
1126
|
+
AND ${matches}
|
|
1127
|
+
`)
|
|
1128
|
+
);
|
|
1129
|
+
return rows.map((row) => ({ kind: row.kind, id: row.id }));
|
|
1130
|
+
}
|
|
1131
|
+
async function requireLiveEndpoints(target, schema, graphId, references) {
|
|
1132
|
+
const uniqueByKey = /* @__PURE__ */ new Map();
|
|
1133
|
+
for (const ref of references) uniqueByKey.set(refKey(ref), ref);
|
|
1134
|
+
const live = await loadLiveReferences(target, schema, graphId, references);
|
|
1135
|
+
const liveKeys = new Set(live.map((ref) => refKey(ref)));
|
|
1136
|
+
for (const [key, ref] of uniqueByKey) {
|
|
1137
|
+
if (!liveKeys.has(key)) throw new chunkNI72YOJB_cjs.NodeNotFoundError(ref.kind, ref.id);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
async function requireStructuralEndpoints(target, schema, graphId, references) {
|
|
1141
|
+
if (references.length === 0) return;
|
|
1142
|
+
const uniqueByKey = /* @__PURE__ */ new Map();
|
|
1143
|
+
for (const ref of references) uniqueByKey.set(refKey(ref), ref);
|
|
1144
|
+
const unique = [...uniqueByKey.values()];
|
|
1145
|
+
const chunkSize = identityChunkSize(target, {
|
|
1146
|
+
fixedParameters: 1,
|
|
1147
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1148
|
+
parametersPerItem: 2
|
|
1149
|
+
});
|
|
1150
|
+
const presentKeys = /* @__PURE__ */ new Set();
|
|
1151
|
+
for (const refChunk of chunkBSFJMMV3_cjs.chunk(unique, chunkSize)) {
|
|
1152
|
+
const matches = referenceCondition(chunkVCRRKBLN_cjs.sql`kind`, chunkVCRRKBLN_cjs.sql`id`, refChunk);
|
|
1153
|
+
const rows = await target.execute(
|
|
1154
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1155
|
+
SELECT kind, id
|
|
1156
|
+
FROM ${schema.nodesTable}
|
|
1157
|
+
WHERE graph_id = ${graphId}
|
|
1158
|
+
AND ${matches}
|
|
1159
|
+
`)
|
|
1160
|
+
);
|
|
1161
|
+
for (const row of rows) {
|
|
1162
|
+
presentKeys.add(refKey({ kind: row.kind, id: row.id }));
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
for (const [key, ref] of uniqueByKey) {
|
|
1166
|
+
if (!presentKeys.has(key)) throw new chunkNI72YOJB_cjs.NodeNotFoundError(ref.kind, ref.id);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
// src/identity/separation.ts
|
|
1171
|
+
var MAX_SEPARATION_INSERT_CHUNK_SIZE = 100;
|
|
1172
|
+
function identityClassKey(ref) {
|
|
1173
|
+
return encodeTupleKey([ref.kind, ref.id]);
|
|
1174
|
+
}
|
|
1175
|
+
var PAIR_KEY_SEPARATOR = "\0";
|
|
1176
|
+
function pairKey(pair) {
|
|
1177
|
+
return `${pair.low}${PAIR_KEY_SEPARATOR}${pair.high}`;
|
|
1178
|
+
}
|
|
1179
|
+
function orderedPair(first, second) {
|
|
1180
|
+
return chunkXMQSEJCF_cjs.compareCodePoints(first, second) <= 0 ? { low: first, high: second } : { low: second, high: first };
|
|
1181
|
+
}
|
|
1182
|
+
function buildSeparationProjection(assertions, classKeyOf) {
|
|
1183
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
1184
|
+
const collapsed = [];
|
|
1185
|
+
for (const assertion of assertions) {
|
|
1186
|
+
if (assertion.rel !== "different") continue;
|
|
1187
|
+
const a = { kind: assertion.a_kind, id: assertion.a_id };
|
|
1188
|
+
const b = { kind: assertion.b_kind, id: assertion.b_id };
|
|
1189
|
+
const pair = orderedPair(classKeyOf(a), classKeyOf(b));
|
|
1190
|
+
pairs.set(pairKey(pair), pair);
|
|
1191
|
+
if (pair.low === pair.high) {
|
|
1192
|
+
collapsed.push({
|
|
1193
|
+
classKey: pair.low,
|
|
1194
|
+
assertionId: assertion.id,
|
|
1195
|
+
a,
|
|
1196
|
+
b
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return { pairs: [...pairs.values()], collapsed };
|
|
1201
|
+
}
|
|
1202
|
+
async function deleteSeparationForGraph(target, schema, graphId) {
|
|
1203
|
+
await executeIdentityStatement(
|
|
1204
|
+
target,
|
|
1205
|
+
chunkVCRRKBLN_cjs.sql`DELETE FROM ${schema.identitySeparationTable} WHERE graph_id = ${graphId}`
|
|
1206
|
+
);
|
|
1207
|
+
}
|
|
1208
|
+
async function deleteSeparationForClassKeys(target, schema, graphId, classKeys) {
|
|
1209
|
+
const unique = [...new Set(classKeys)];
|
|
1210
|
+
if (unique.length === 0) return;
|
|
1211
|
+
const chunkSize = identityChunkSize(target, {
|
|
1212
|
+
fixedParameters: 1,
|
|
1213
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1214
|
+
parametersPerItem: 2
|
|
1215
|
+
});
|
|
1216
|
+
for (const keyChunk of chunkBSFJMMV3_cjs.chunk(unique, chunkSize)) {
|
|
1217
|
+
const keyList = chunkVCRRKBLN_cjs.sql.join(
|
|
1218
|
+
keyChunk.map((key) => chunkVCRRKBLN_cjs.sql`${key}`),
|
|
1219
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
1220
|
+
);
|
|
1221
|
+
await executeIdentityStatement(
|
|
1222
|
+
target,
|
|
1223
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1224
|
+
DELETE FROM ${schema.identitySeparationTable}
|
|
1225
|
+
WHERE graph_id = ${graphId}
|
|
1226
|
+
AND (class_key_low IN (${keyList}) OR class_key_high IN (${keyList}))
|
|
1227
|
+
`
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
async function isSeparated(target, schema, graphId, firstClassKey, secondClassKey, registry) {
|
|
1232
|
+
if (firstClassKey === secondClassKey) return false;
|
|
1233
|
+
const probe = await probeSeparationPair(
|
|
1234
|
+
target,
|
|
1235
|
+
schema,
|
|
1236
|
+
graphId,
|
|
1237
|
+
orderedPair(firstClassKey, secondClassKey)
|
|
1238
|
+
);
|
|
1239
|
+
if (probe.pairSeparated) return true;
|
|
1240
|
+
if (probe.graphHasRows) return false;
|
|
1241
|
+
if (separationReadinessProven(registry, graphId)) return false;
|
|
1242
|
+
if (await hasLiveDifferentAssertions(target, schema, graphId, registry)) {
|
|
1243
|
+
throw separationUnfilledError(graphId, schema);
|
|
1244
|
+
}
|
|
1245
|
+
proveSeparationReadiness(registry, graphId);
|
|
1246
|
+
return false;
|
|
1247
|
+
}
|
|
1248
|
+
var provenSeparationReadiness = /* @__PURE__ */ new WeakMap();
|
|
1249
|
+
function separationReadinessProven(registry, graphId) {
|
|
1250
|
+
return provenSeparationReadiness.get(registry)?.has(graphId) === true;
|
|
1251
|
+
}
|
|
1252
|
+
function proveSeparationReadiness(registry, graphId) {
|
|
1253
|
+
const proven = provenSeparationReadiness.get(registry) ?? /* @__PURE__ */ new Set();
|
|
1254
|
+
proven.add(graphId);
|
|
1255
|
+
provenSeparationReadiness.set(registry, proven);
|
|
1256
|
+
}
|
|
1257
|
+
async function probeSeparationPair(target, schema, graphId, pair) {
|
|
1258
|
+
try {
|
|
1259
|
+
const rows = await target.execute(
|
|
1260
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1261
|
+
SELECT
|
|
1262
|
+
(
|
|
1263
|
+
SELECT COUNT(*) FROM ${schema.identitySeparationTable}
|
|
1264
|
+
WHERE graph_id = ${graphId}
|
|
1265
|
+
AND class_key_low = ${pair.low}
|
|
1266
|
+
AND class_key_high = ${pair.high}
|
|
1267
|
+
) AS pair_rows,
|
|
1268
|
+
(
|
|
1269
|
+
SELECT COUNT(*) FROM (
|
|
1270
|
+
SELECT 1 AS present FROM ${schema.identitySeparationTable}
|
|
1271
|
+
WHERE graph_id = ${graphId}
|
|
1272
|
+
LIMIT 1
|
|
1273
|
+
) graph_probe
|
|
1274
|
+
) AS graph_rows
|
|
1275
|
+
`)
|
|
1276
|
+
);
|
|
1277
|
+
const row = rows[0];
|
|
1278
|
+
return {
|
|
1279
|
+
graphHasRows: countOf(row, "graph_rows") > 0,
|
|
1280
|
+
pairSeparated: countOf(row, "pair_rows") > 0
|
|
1281
|
+
};
|
|
1282
|
+
} catch (error) {
|
|
1283
|
+
if (!chunkBSFJMMV3_cjs.isMissingTableError(error)) throw error;
|
|
1284
|
+
throw separationUnreadableError(graphId, schema, error);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
function countOf(row, column) {
|
|
1288
|
+
return Number(row?.[column] ?? 0);
|
|
1289
|
+
}
|
|
1290
|
+
function separationUnreadableError(graphId, schema, cause) {
|
|
1291
|
+
return new chunkNI72YOJB_cjs.ConfigurationError(
|
|
1292
|
+
"Operational Identity could not read the materialized separation relation.",
|
|
1293
|
+
{
|
|
1294
|
+
code: "IDENTITY_STORAGE_MISSING",
|
|
1295
|
+
graphId,
|
|
1296
|
+
tables: [schema.tables.identitySeparation]
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
cause,
|
|
1300
|
+
suggestion: "Recreate the identity separation relation with the standard TypeGraph DDL, open the Store, and run rebuildIdentityClosure(store) before serving traffic."
|
|
1301
|
+
}
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
function separationUnfilledError(graphId, schema) {
|
|
1305
|
+
return new chunkNI72YOJB_cjs.ConfigurationError(
|
|
1306
|
+
"Operational Identity found the separation relation present but never filled for this graph.",
|
|
1307
|
+
{
|
|
1308
|
+
code: "IDENTITY_STORAGE_MISSING",
|
|
1309
|
+
graphId,
|
|
1310
|
+
reason: "unfilled",
|
|
1311
|
+
tables: [schema.tables.identitySeparation]
|
|
1312
|
+
},
|
|
1313
|
+
{
|
|
1314
|
+
suggestion: "Reopen the Store (createStoreWithSchema rebuilds the derived identity relations when they are missing rows), or run rebuildIdentityClosure(store) before serving traffic. A Store handle opened while the relation did not exist keeps failing until it is reopened."
|
|
1315
|
+
}
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
function unexpectedSeparationError(graphId, firstClassKey, secondClassKey) {
|
|
1319
|
+
return separationMismatchError(graphId, {
|
|
1320
|
+
unexpected: orderedPair(firstClassKey, secondClassKey)
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
async function separationRebuildRequired(target, schema, graphId, options) {
|
|
1324
|
+
if (options.relationExists && await hasSeparationRows(target, schema, graphId)) {
|
|
1325
|
+
return false;
|
|
1326
|
+
}
|
|
1327
|
+
return hasLiveDifferentAssertions(target, schema, graphId, options.registry);
|
|
1328
|
+
}
|
|
1329
|
+
async function hasSeparationRows(target, schema, graphId) {
|
|
1330
|
+
const rows = await target.execute(
|
|
1331
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1332
|
+
SELECT 1 AS present
|
|
1333
|
+
FROM ${schema.identitySeparationTable}
|
|
1334
|
+
WHERE graph_id = ${graphId}
|
|
1335
|
+
LIMIT 1
|
|
1336
|
+
`)
|
|
1337
|
+
);
|
|
1338
|
+
return rows.length > 0;
|
|
1339
|
+
}
|
|
1340
|
+
async function hasLiveDifferentAssertions(target, schema, graphId, registry) {
|
|
1341
|
+
if (!await probeAnyLiveDifferent(target, schema, graphId)) return false;
|
|
1342
|
+
const activeKinds = [...identityActiveKinds(registry)];
|
|
1343
|
+
if (activeKinds.length === 0) return false;
|
|
1344
|
+
const kindChunks = chunkBSFJMMV3_cjs.chunk(activeKinds, owedProbeChunkSize(target));
|
|
1345
|
+
for (const first of kindChunks) {
|
|
1346
|
+
for (const second of kindChunks) {
|
|
1347
|
+
if (await probeOwedSeparation(target, schema, graphId, [first, second])) {
|
|
1348
|
+
return true;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
return false;
|
|
1353
|
+
}
|
|
1354
|
+
var IDENTITY_SNAPSHOT_PARAMETERS = 4;
|
|
1355
|
+
var OWED_SEPARATION_PROBE_PARAMETERS = IDENTITY_SNAPSHOT_PARAMETERS + 2;
|
|
1356
|
+
async function probeAnyLiveDifferent(target, schema, graphId) {
|
|
1357
|
+
const rows = await target.execute(
|
|
1358
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1359
|
+
SELECT 1 AS present
|
|
1360
|
+
FROM (${liveDifferentSource(schema, graphId)}) live_different
|
|
1361
|
+
LIMIT 1
|
|
1362
|
+
`)
|
|
1363
|
+
);
|
|
1364
|
+
return rows.length > 0;
|
|
1365
|
+
}
|
|
1366
|
+
async function probeOwedSeparation(target, schema, graphId, kinds) {
|
|
1367
|
+
const rows = await target.execute(
|
|
1368
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1369
|
+
SELECT 1 AS present
|
|
1370
|
+
FROM (${liveDifferentSource(schema, graphId)}) live_different
|
|
1371
|
+
LEFT JOIN ${schema.identityClosureTable} class_a
|
|
1372
|
+
ON class_a.graph_id = ${graphId}
|
|
1373
|
+
AND class_a.member_kind = live_different.a_kind
|
|
1374
|
+
AND class_a.member_id = live_different.a_id
|
|
1375
|
+
LEFT JOIN ${schema.identityClosureTable} class_b
|
|
1376
|
+
ON class_b.graph_id = ${graphId}
|
|
1377
|
+
AND class_b.member_kind = live_different.b_kind
|
|
1378
|
+
AND class_b.member_id = live_different.b_id
|
|
1379
|
+
WHERE live_different.a_kind IN (${kindList(kinds[0])})
|
|
1380
|
+
AND live_different.b_kind IN (${kindList(kinds[1])})
|
|
1381
|
+
AND (
|
|
1382
|
+
COALESCE(class_a.class_kind, live_different.a_kind)
|
|
1383
|
+
<> COALESCE(class_b.class_kind, live_different.b_kind)
|
|
1384
|
+
OR COALESCE(class_a.class_id, live_different.a_id)
|
|
1385
|
+
<> COALESCE(class_b.class_id, live_different.b_id)
|
|
1386
|
+
)
|
|
1387
|
+
LIMIT 1
|
|
1388
|
+
`)
|
|
1389
|
+
);
|
|
1390
|
+
return rows.length > 0;
|
|
1391
|
+
}
|
|
1392
|
+
function owedProbeChunkSize(target) {
|
|
1393
|
+
return identityChunkSize(target, {
|
|
1394
|
+
fixedParameters: OWED_SEPARATION_PROBE_PARAMETERS,
|
|
1395
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1396
|
+
parametersPerItem: 2
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
function liveDifferentSource(schema, graphId) {
|
|
1400
|
+
return chunkXMQSEJCF_cjs.identityAssertionSnapshotSource(
|
|
1401
|
+
schema,
|
|
1402
|
+
graphId,
|
|
1403
|
+
chunkXMQSEJCF_cjs.identitySqlCoordinate(void 0, chunkQ7Q4WSLJ_cjs.nowIso()),
|
|
1404
|
+
"different"
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
function kindList(kinds) {
|
|
1408
|
+
return chunkVCRRKBLN_cjs.sql.join(
|
|
1409
|
+
kinds.map((kind) => chunkVCRRKBLN_cjs.sql`${kind}`),
|
|
1410
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
async function readSeparationForGraph(target, schema, graphId) {
|
|
1414
|
+
const rows = await target.execute(
|
|
1415
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1416
|
+
SELECT class_key_low, class_key_high
|
|
1417
|
+
FROM ${schema.identitySeparationTable}
|
|
1418
|
+
WHERE graph_id = ${graphId}
|
|
1419
|
+
`)
|
|
1420
|
+
);
|
|
1421
|
+
return rows.map((row) => ({
|
|
1422
|
+
low: row.class_key_low,
|
|
1423
|
+
high: row.class_key_high
|
|
1424
|
+
}));
|
|
1425
|
+
}
|
|
1426
|
+
async function insertSeparationRows(target, schema, graphId, projection) {
|
|
1427
|
+
const chunkSize = identityChunkSize(target, {
|
|
1428
|
+
fixedParameters: 0,
|
|
1429
|
+
maxItems: MAX_SEPARATION_INSERT_CHUNK_SIZE,
|
|
1430
|
+
parametersPerItem: 3
|
|
1431
|
+
});
|
|
1432
|
+
for (const pairChunk of chunkBSFJMMV3_cjs.chunk(projection.pairs, chunkSize)) {
|
|
1433
|
+
const values = pairChunk.map(
|
|
1434
|
+
(pair) => chunkVCRRKBLN_cjs.sql`(${graphId}, ${pair.low}, ${pair.high})`
|
|
1435
|
+
);
|
|
1436
|
+
try {
|
|
1437
|
+
await executeIdentityStatement(
|
|
1438
|
+
target,
|
|
1439
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1440
|
+
INSERT INTO ${schema.identitySeparationTable} (
|
|
1441
|
+
graph_id, class_key_low, class_key_high
|
|
1442
|
+
) VALUES ${chunkVCRRKBLN_cjs.sql.join(values, chunkVCRRKBLN_cjs.sql`, `)}
|
|
1443
|
+
`
|
|
1444
|
+
);
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
const collapsed = collapsedIn(projection, pairChunk);
|
|
1447
|
+
if (collapsed === void 0) throw error;
|
|
1448
|
+
throw new chunkNI72YOJB_cjs.IdentitySeparationViolationError(
|
|
1449
|
+
{ graphId, enforcedBy: "database", ...collapsed },
|
|
1450
|
+
{ cause: error }
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
const accepted = projection.collapsed[0];
|
|
1455
|
+
if (accepted === void 0) return;
|
|
1456
|
+
throw new chunkNI72YOJB_cjs.IdentitySeparationViolationError({
|
|
1457
|
+
graphId,
|
|
1458
|
+
enforcedBy: "writer",
|
|
1459
|
+
...accepted
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1462
|
+
function collapsedIn(projection, pairChunk) {
|
|
1463
|
+
const keys = new Set(pairChunk.map((pair) => pairKey(pair)));
|
|
1464
|
+
return projection.collapsed.find(
|
|
1465
|
+
(collapsed) => keys.has(pairKey({ low: collapsed.classKey, high: collapsed.classKey }))
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1468
|
+
function assertSeparationMatchesProjection(graphId, persisted, projection) {
|
|
1469
|
+
const expected = new Map(
|
|
1470
|
+
projection.pairs.map((pair) => [pairKey(pair), pair])
|
|
1471
|
+
);
|
|
1472
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1473
|
+
for (const pair of persisted) {
|
|
1474
|
+
const key = pairKey(pair);
|
|
1475
|
+
if (!expected.has(key)) {
|
|
1476
|
+
throw separationMismatchError(graphId, { unexpected: pair });
|
|
1477
|
+
}
|
|
1478
|
+
seen.add(key);
|
|
1479
|
+
}
|
|
1480
|
+
for (const [key, pair] of expected) {
|
|
1481
|
+
if (seen.has(key)) continue;
|
|
1482
|
+
throw separationMismatchError(graphId, { missing: pair });
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
function separationMismatchError(graphId, detail) {
|
|
1486
|
+
return new chunkNI72YOJB_cjs.ConfigurationError(
|
|
1487
|
+
"Operational Identity materialized separation relation does not match the assertion ledger.",
|
|
1488
|
+
{ code: "IDENTITY_SCHEMA_CONTRADICTION", graphId, ...detail },
|
|
1489
|
+
{
|
|
1490
|
+
suggestion: "Run rebuildIdentityClosure(store) to rebuild the materialized identity relations."
|
|
1491
|
+
}
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// src/identity/service-mutation.ts
|
|
1496
|
+
async function validateCurrentRelation(ctx, target, relation, operation, a, b) {
|
|
1497
|
+
const classes = await loadCurrentStructuralClasses(
|
|
1498
|
+
target,
|
|
1499
|
+
ctx.schema,
|
|
1500
|
+
ctx.graphId,
|
|
1501
|
+
[a, b]
|
|
1502
|
+
);
|
|
1503
|
+
const aClass = chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(a)));
|
|
1504
|
+
const bClass = chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(b)));
|
|
1505
|
+
if (relation === "different") {
|
|
1506
|
+
if (!containsRef(aClass, b)) return;
|
|
1507
|
+
throw new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
1508
|
+
operation,
|
|
1509
|
+
a,
|
|
1510
|
+
b,
|
|
1511
|
+
reason: "same-class"
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
const aKey = currentClassKey(aClass);
|
|
1515
|
+
const bKey = currentClassKey(bClass);
|
|
1516
|
+
if (await isSeparated(target, ctx.schema, ctx.graphId, aKey, bKey, ctx.registry)) {
|
|
1517
|
+
const different = await loadSpanningDifferentAssertion(
|
|
1518
|
+
target,
|
|
1519
|
+
ctx.schema,
|
|
1520
|
+
ctx.graphId,
|
|
1521
|
+
aClass,
|
|
1522
|
+
bClass
|
|
1523
|
+
);
|
|
1524
|
+
if (different === void 0)
|
|
1525
|
+
throw unexpectedSeparationError(ctx.graphId, aKey, bKey);
|
|
1526
|
+
throw new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
1527
|
+
operation,
|
|
1528
|
+
a,
|
|
1529
|
+
b,
|
|
1530
|
+
reason: "different-assertion",
|
|
1531
|
+
conflictingAssertionId: different.id
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
const disjointKinds = classHasDisjointKinds(ctx.registry, aClass, bClass);
|
|
1535
|
+
if (disjointKinds === void 0) return;
|
|
1536
|
+
throw new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
1537
|
+
operation,
|
|
1538
|
+
a,
|
|
1539
|
+
b,
|
|
1540
|
+
reason: "disjoint-kinds",
|
|
1541
|
+
conflictingKinds: disjointKinds
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
async function currentAssertionForPair(target, schema, graphId, relation, a, b) {
|
|
1545
|
+
const rows = await target.execute(
|
|
1546
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1547
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
1548
|
+
FROM ${schema.identityAssertionsTable}
|
|
1549
|
+
WHERE graph_id = ${graphId}
|
|
1550
|
+
AND rel = ${relation}
|
|
1551
|
+
AND a_kind = ${a.kind}
|
|
1552
|
+
AND a_id = ${a.id}
|
|
1553
|
+
AND b_kind = ${b.kind}
|
|
1554
|
+
AND b_id = ${b.id}
|
|
1555
|
+
AND valid_to IS NULL
|
|
1556
|
+
AND deleted_at IS NULL
|
|
1557
|
+
LIMIT 1
|
|
1558
|
+
`)
|
|
1559
|
+
);
|
|
1560
|
+
return rows[0] === void 0 ? void 0 : normalizeIdentityAssertionRow(rows[0]);
|
|
1561
|
+
}
|
|
1562
|
+
async function insertAssertion(target, schema, graphId, relation, a, b, timestamp, touch, preserved) {
|
|
1563
|
+
const row = buildAssertionRow(graphId, relation, a, b, timestamp, preserved);
|
|
1564
|
+
await insertAssertionRows(target, schema, [row]);
|
|
1565
|
+
touch(graphId, row.id, row);
|
|
1566
|
+
return row;
|
|
1567
|
+
}
|
|
1568
|
+
function buildAssertionRow(graphId, relation, a, b, timestamp, preserved) {
|
|
1569
|
+
return {
|
|
1570
|
+
graph_id: graphId,
|
|
1571
|
+
id: preserved?.id ?? chunkXMQSEJCF_cjs.generateId(),
|
|
1572
|
+
rel: relation,
|
|
1573
|
+
a_kind: a.kind,
|
|
1574
|
+
a_id: a.id,
|
|
1575
|
+
b_kind: b.kind,
|
|
1576
|
+
b_id: b.id,
|
|
1577
|
+
valid_from: preserved?.validFrom ?? timestamp,
|
|
1578
|
+
valid_to: void 0,
|
|
1579
|
+
created_at: timestamp,
|
|
1580
|
+
updated_at: timestamp,
|
|
1581
|
+
deleted_at: void 0,
|
|
1582
|
+
ended_by_kind: void 0,
|
|
1583
|
+
ended_by_id: void 0
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
function nullableAssertionValue(value) {
|
|
1587
|
+
return value === void 0 ? chunkVCRRKBLN_cjs.sql`NULL` : chunkVCRRKBLN_cjs.sql`${value}`;
|
|
1588
|
+
}
|
|
1589
|
+
async function insertAssertionRows(target, schema, rows) {
|
|
1590
|
+
if (rows.length === 0) return;
|
|
1591
|
+
const chunkSize = identityChunkSize(target, {
|
|
1592
|
+
fixedParameters: 0,
|
|
1593
|
+
maxItems: MAX_ASSERTION_INSERT_CHUNK_SIZE,
|
|
1594
|
+
parametersPerItem: 14
|
|
1595
|
+
});
|
|
1596
|
+
for (const rowChunk of chunkBSFJMMV3_cjs.chunk(rows, chunkSize)) {
|
|
1597
|
+
const values = rowChunk.map(
|
|
1598
|
+
(row) => chunkVCRRKBLN_cjs.sql`
|
|
1599
|
+
(
|
|
1600
|
+
${row.graph_id}, ${row.id}, ${row.rel}, ${row.a_kind}, ${row.a_id},
|
|
1601
|
+
${row.b_kind}, ${row.b_id}, ${row.valid_from},
|
|
1602
|
+
${nullableAssertionValue(row.valid_to)},
|
|
1603
|
+
${row.created_at}, ${row.updated_at},
|
|
1604
|
+
${nullableAssertionValue(row.deleted_at)},
|
|
1605
|
+
${nullableAssertionValue(row.ended_by_kind)},
|
|
1606
|
+
${nullableAssertionValue(row.ended_by_id)}
|
|
1607
|
+
)
|
|
1608
|
+
`
|
|
1609
|
+
);
|
|
1610
|
+
await executeIdentityStatement(
|
|
1611
|
+
target,
|
|
1612
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1613
|
+
INSERT INTO ${schema.identityAssertionsTable} (${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}) VALUES ${chunkVCRRKBLN_cjs.sql.join(values, chunkVCRRKBLN_cjs.sql`, `)}
|
|
1614
|
+
`
|
|
1615
|
+
);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
async function loadAssertionsByIds(target, schema, graphId, ids) {
|
|
1619
|
+
const uniqueIds = [...new Set(ids)];
|
|
1620
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1621
|
+
if (uniqueIds.length === 0) return byId;
|
|
1622
|
+
const chunkSize = identityChunkSize(target, {
|
|
1623
|
+
fixedParameters: 1,
|
|
1624
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1625
|
+
parametersPerItem: 1
|
|
1626
|
+
});
|
|
1627
|
+
for (const idChunk of chunkBSFJMMV3_cjs.chunk(uniqueIds, chunkSize)) {
|
|
1628
|
+
const idList = chunkVCRRKBLN_cjs.sql.join(
|
|
1629
|
+
idChunk.map((id) => chunkVCRRKBLN_cjs.sql`${id}`),
|
|
1630
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
1631
|
+
);
|
|
1632
|
+
const rows = await target.execute(
|
|
1633
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1634
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
1635
|
+
FROM ${schema.identityAssertionsTable}
|
|
1636
|
+
WHERE graph_id = ${graphId} AND id IN (${idList})
|
|
1637
|
+
`)
|
|
1638
|
+
);
|
|
1639
|
+
for (const row of rows) {
|
|
1640
|
+
byId.set(row.id, normalizeIdentityAssertionRow(row));
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
return byId;
|
|
1644
|
+
}
|
|
1645
|
+
async function loadCurrentClassAnchors(target, schema, graphId, references) {
|
|
1646
|
+
const uniqueByKey = /* @__PURE__ */ new Map();
|
|
1647
|
+
for (const ref of references) uniqueByKey.set(refKey(ref), ref);
|
|
1648
|
+
const uniqueReferences = [...uniqueByKey.values()];
|
|
1649
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
1650
|
+
if (uniqueReferences.length === 0) return anchors;
|
|
1651
|
+
const chunkSize = identityChunkSize(target, {
|
|
1652
|
+
fixedParameters: 1,
|
|
1653
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1654
|
+
parametersPerItem: 2
|
|
1655
|
+
});
|
|
1656
|
+
for (const refChunk of chunkBSFJMMV3_cjs.chunk(uniqueReferences, chunkSize)) {
|
|
1657
|
+
const seedRows = chunkVCRRKBLN_cjs.sql.join(
|
|
1658
|
+
refChunk.map((ref) => chunkVCRRKBLN_cjs.sql`(${ref.kind}, ${ref.id})`),
|
|
1659
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
1660
|
+
);
|
|
1661
|
+
const rows = await target.execute(
|
|
1662
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
1663
|
+
WITH seeds(seed_kind, seed_id) AS (
|
|
1664
|
+
VALUES ${seedRows}
|
|
1665
|
+
)
|
|
1666
|
+
SELECT seeds.seed_kind, seeds.seed_id,
|
|
1667
|
+
COALESCE(anchor.class_kind, seeds.seed_kind) AS class_kind,
|
|
1668
|
+
COALESCE(anchor.class_id, seeds.seed_id) AS class_id
|
|
1669
|
+
FROM seeds
|
|
1670
|
+
LEFT JOIN ${schema.identityClosureTable} anchor
|
|
1671
|
+
ON anchor.graph_id = ${graphId}
|
|
1672
|
+
AND anchor.member_kind = seeds.seed_kind
|
|
1673
|
+
AND anchor.member_id = seeds.seed_id
|
|
1674
|
+
`)
|
|
1675
|
+
);
|
|
1676
|
+
for (const row of rows) {
|
|
1677
|
+
anchors.set(refKey({ kind: row.seed_kind, id: row.seed_id }), {
|
|
1678
|
+
kind: row.class_kind,
|
|
1679
|
+
id: row.class_id
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
return anchors;
|
|
1684
|
+
}
|
|
1685
|
+
function currentClassKey(members) {
|
|
1686
|
+
return identityClassKey(chunkN66HCGCY_cjs.requireDefined(members[0]));
|
|
1687
|
+
}
|
|
1688
|
+
function snapshotClassKey(snapshot, ref) {
|
|
1689
|
+
return identityClassKey(chunkN66HCGCY_cjs.requireDefined(componentFor(snapshot, ref)[0]));
|
|
1690
|
+
}
|
|
1691
|
+
async function replaceSeparationForMembers(target, schema, graphId, members) {
|
|
1692
|
+
const uniqueByKey = /* @__PURE__ */ new Map();
|
|
1693
|
+
for (const member of members) uniqueByKey.set(refKey(member), member);
|
|
1694
|
+
const unique = [...uniqueByKey.values()];
|
|
1695
|
+
if (unique.length === 0) return;
|
|
1696
|
+
await deleteSeparationForClassKeys(
|
|
1697
|
+
target,
|
|
1698
|
+
schema,
|
|
1699
|
+
graphId,
|
|
1700
|
+
unique.map((member) => identityClassKey(member))
|
|
1701
|
+
);
|
|
1702
|
+
const assertions = await loadAssertionsTouching(
|
|
1703
|
+
target,
|
|
1704
|
+
schema,
|
|
1705
|
+
graphId,
|
|
1706
|
+
unique,
|
|
1707
|
+
void 0,
|
|
1708
|
+
"different"
|
|
1709
|
+
);
|
|
1710
|
+
if (assertions.length === 0) return;
|
|
1711
|
+
const endpoints = assertions.flatMap((assertion) => [
|
|
1712
|
+
{ kind: assertion.a_kind, id: assertion.a_id },
|
|
1713
|
+
{ kind: assertion.b_kind, id: assertion.b_id }
|
|
1714
|
+
]);
|
|
1715
|
+
const anchors = await loadCurrentClassAnchors(
|
|
1716
|
+
target,
|
|
1717
|
+
schema,
|
|
1718
|
+
graphId,
|
|
1719
|
+
endpoints
|
|
1720
|
+
);
|
|
1721
|
+
await insertSeparationRows(
|
|
1722
|
+
target,
|
|
1723
|
+
schema,
|
|
1724
|
+
graphId,
|
|
1725
|
+
buildSeparationProjection(
|
|
1726
|
+
assertions,
|
|
1727
|
+
(ref) => identityClassKey(chunkN66HCGCY_cjs.requireDefined(anchors.get(refKey(ref))))
|
|
1728
|
+
)
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1731
|
+
async function replaceSeparationForReferences(target, schema, graphId, references) {
|
|
1732
|
+
if (references.length === 0) return;
|
|
1733
|
+
const classes = await loadCurrentStructuralClasses(
|
|
1734
|
+
target,
|
|
1735
|
+
schema,
|
|
1736
|
+
graphId,
|
|
1737
|
+
references
|
|
1738
|
+
);
|
|
1739
|
+
await replaceSeparationForMembers(
|
|
1740
|
+
target,
|
|
1741
|
+
schema,
|
|
1742
|
+
graphId,
|
|
1743
|
+
[...classes.values()].flat()
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
async function replaceClosure(target, schema, graphId, allowedKinds, sameIdAcrossKinds = "fold") {
|
|
1747
|
+
const snapshot = await loadSnapshot(
|
|
1748
|
+
target,
|
|
1749
|
+
schema,
|
|
1750
|
+
graphId,
|
|
1751
|
+
void 0,
|
|
1752
|
+
allowedKinds,
|
|
1753
|
+
sameIdAcrossKinds
|
|
1754
|
+
);
|
|
1755
|
+
await executeIdentityStatement(
|
|
1756
|
+
target,
|
|
1757
|
+
chunkVCRRKBLN_cjs.sql`DELETE FROM ${schema.identityClosureTable} WHERE graph_id = ${graphId}`
|
|
1758
|
+
);
|
|
1759
|
+
await insertClosureComponents(target, schema, graphId, snapshot.components);
|
|
1760
|
+
await deleteSeparationForGraph(target, schema, graphId);
|
|
1761
|
+
await insertSeparationRows(
|
|
1762
|
+
target,
|
|
1763
|
+
schema,
|
|
1764
|
+
graphId,
|
|
1765
|
+
buildSeparationProjection(
|
|
1766
|
+
snapshot.assertions,
|
|
1767
|
+
(ref) => snapshotClassKey(snapshot, ref)
|
|
1768
|
+
)
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
async function insertClosureComponents(target, schema, graphId, components) {
|
|
1772
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
1773
|
+
const values = [];
|
|
1774
|
+
for (const [memberKey, component] of components) {
|
|
1775
|
+
if (emitted.has(memberKey) || component.length < 2) continue;
|
|
1776
|
+
const canonical = chunkN66HCGCY_cjs.requireDefined(component[0]);
|
|
1777
|
+
for (const member of component) {
|
|
1778
|
+
emitted.add(refKey(member));
|
|
1779
|
+
values.push(
|
|
1780
|
+
chunkVCRRKBLN_cjs.sql`(${graphId}, ${member.kind}, ${member.id}, ${canonical.kind}, ${canonical.id})`
|
|
1781
|
+
);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1784
|
+
if (values.length === 0) return;
|
|
1785
|
+
const chunkSize = identityChunkSize(target, {
|
|
1786
|
+
fixedParameters: 0,
|
|
1787
|
+
maxItems: MAX_CLOSURE_INSERT_CHUNK_SIZE,
|
|
1788
|
+
parametersPerItem: 5
|
|
1789
|
+
});
|
|
1790
|
+
for (const valueChunk of chunkBSFJMMV3_cjs.chunk(values, chunkSize)) {
|
|
1791
|
+
await executeIdentityStatement(
|
|
1792
|
+
target,
|
|
1793
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1794
|
+
INSERT INTO ${schema.identityClosureTable} (
|
|
1795
|
+
graph_id, member_kind, member_id, class_kind, class_id
|
|
1796
|
+
) VALUES ${chunkVCRRKBLN_cjs.sql.join(valueChunk, chunkVCRRKBLN_cjs.sql`, `)}
|
|
1797
|
+
`
|
|
1798
|
+
);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
async function replaceAffectedClosure(target, schema, graphId, references, sameIdAcrossKinds = "fold") {
|
|
1802
|
+
if (references.length === 0) return;
|
|
1803
|
+
const affectedByKey = /* @__PURE__ */ new Map();
|
|
1804
|
+
const classes = await loadCurrentStructuralClasses(
|
|
1805
|
+
target,
|
|
1806
|
+
schema,
|
|
1807
|
+
graphId,
|
|
1808
|
+
references
|
|
1809
|
+
);
|
|
1810
|
+
for (const ref of references) {
|
|
1811
|
+
for (const member of chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(ref)))) {
|
|
1812
|
+
affectedByKey.set(refKey(member), member);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
const affected = [...affectedByKey.values()];
|
|
1816
|
+
const structuralNodes = await loadLiveReferences(
|
|
1817
|
+
target,
|
|
1818
|
+
schema,
|
|
1819
|
+
graphId,
|
|
1820
|
+
affected
|
|
1821
|
+
);
|
|
1822
|
+
const assertions = await loadAssertionsTouching(
|
|
1823
|
+
target,
|
|
1824
|
+
schema,
|
|
1825
|
+
graphId,
|
|
1826
|
+
affected,
|
|
1827
|
+
void 0,
|
|
1828
|
+
"same"
|
|
1829
|
+
);
|
|
1830
|
+
const chunkSize = identityChunkSize(target, {
|
|
1831
|
+
fixedParameters: 1,
|
|
1832
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
1833
|
+
parametersPerItem: 2
|
|
1834
|
+
});
|
|
1835
|
+
for (const affectedChunk of chunkBSFJMMV3_cjs.chunk(affected, chunkSize)) {
|
|
1836
|
+
const matches = referenceCondition(
|
|
1837
|
+
chunkVCRRKBLN_cjs.sql`member_kind`,
|
|
1838
|
+
chunkVCRRKBLN_cjs.sql`member_id`,
|
|
1839
|
+
affectedChunk
|
|
1840
|
+
);
|
|
1841
|
+
await executeIdentityStatement(
|
|
1842
|
+
target,
|
|
1843
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1844
|
+
DELETE FROM ${schema.identityClosureTable}
|
|
1845
|
+
WHERE graph_id = ${graphId} AND ${matches}
|
|
1846
|
+
`
|
|
1847
|
+
);
|
|
1848
|
+
}
|
|
1849
|
+
const components = buildComponents(
|
|
1850
|
+
structuralNodes,
|
|
1851
|
+
assertions,
|
|
1852
|
+
sameIdAcrossKinds
|
|
1853
|
+
);
|
|
1854
|
+
await insertClosureComponents(target, schema, graphId, components);
|
|
1855
|
+
const separationMembers = [...affected, ...[...components.values()].flat()];
|
|
1856
|
+
await replaceSeparationForMembers(target, schema, graphId, separationMembers);
|
|
1857
|
+
}
|
|
1858
|
+
async function mergeCurrentClasses(target, schema, graphId, a, b) {
|
|
1859
|
+
const classes = await loadCurrentStructuralClasses(target, schema, graphId, [
|
|
1860
|
+
a,
|
|
1861
|
+
b
|
|
1862
|
+
]);
|
|
1863
|
+
const aClass = chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(a)));
|
|
1864
|
+
const bClass = chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(b)));
|
|
1865
|
+
if (containsRef(aClass, b)) return;
|
|
1866
|
+
const fusedMembers = [...aClass, ...bClass];
|
|
1867
|
+
const [smaller, larger] = aClass.length <= bClass.length ? [aClass, bClass] : [bClass, aClass];
|
|
1868
|
+
const canonical = chunkN66HCGCY_cjs.requireDefined(
|
|
1869
|
+
[...aClass, ...bClass].toSorted(
|
|
1870
|
+
(left, right) => compareReferences(left, right)
|
|
1871
|
+
)[0]
|
|
1872
|
+
);
|
|
1873
|
+
async function relabelExistingClass(members) {
|
|
1874
|
+
if (members.length < 2) return;
|
|
1875
|
+
const previousCanonical = chunkN66HCGCY_cjs.requireDefined(members[0]);
|
|
1876
|
+
if (refKey(previousCanonical) === refKey(canonical)) return;
|
|
1877
|
+
await executeIdentityStatement(
|
|
1878
|
+
target,
|
|
1879
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1880
|
+
UPDATE ${schema.identityClosureTable}
|
|
1881
|
+
SET class_kind = ${canonical.kind}, class_id = ${canonical.id}
|
|
1882
|
+
WHERE graph_id = ${graphId}
|
|
1883
|
+
AND class_kind = ${previousCanonical.kind}
|
|
1884
|
+
AND class_id = ${previousCanonical.id}
|
|
1885
|
+
`
|
|
1886
|
+
);
|
|
1887
|
+
}
|
|
1888
|
+
await relabelExistingClass(smaller);
|
|
1889
|
+
await relabelExistingClass(larger);
|
|
1890
|
+
const singletonMembers = [smaller, larger].flatMap(
|
|
1891
|
+
(members) => members.length === 1 ? members : []
|
|
1892
|
+
);
|
|
1893
|
+
if (singletonMembers.length > 0) {
|
|
1894
|
+
const values = singletonMembers.map(
|
|
1895
|
+
(member) => chunkVCRRKBLN_cjs.sql`(${graphId}, ${member.kind}, ${member.id}, ${canonical.kind}, ${canonical.id})`
|
|
1896
|
+
);
|
|
1897
|
+
await executeIdentityStatement(
|
|
1898
|
+
target,
|
|
1899
|
+
chunkVCRRKBLN_cjs.sql`
|
|
1900
|
+
INSERT INTO ${schema.identityClosureTable} (
|
|
1901
|
+
graph_id, member_kind, member_id, class_kind, class_id
|
|
1902
|
+
) VALUES ${chunkVCRRKBLN_cjs.sql.join(values, chunkVCRRKBLN_cjs.sql`, `)}
|
|
1903
|
+
`
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
await replaceSeparationForMembers(target, schema, graphId, fusedMembers);
|
|
1907
|
+
}
|
|
1908
|
+
async function assertPair(ctx, target, relation, firstInput, secondInput, touch) {
|
|
1909
|
+
const first = registeredPlainRef(ctx, firstInput);
|
|
1910
|
+
const second = registeredPlainRef(ctx, secondInput);
|
|
1911
|
+
if (refKey(first) === refKey(second)) throw selfAssertionError(relation);
|
|
1912
|
+
const [a, b] = normalizePair(first, second);
|
|
1913
|
+
await Promise.all([
|
|
1914
|
+
requireLiveEndpoint(target, ctx.graphId, a),
|
|
1915
|
+
requireLiveEndpoint(target, ctx.graphId, b)
|
|
1916
|
+
]);
|
|
1917
|
+
const existing = await currentAssertionForPair(
|
|
1918
|
+
target,
|
|
1919
|
+
ctx.schema,
|
|
1920
|
+
ctx.graphId,
|
|
1921
|
+
relation,
|
|
1922
|
+
a,
|
|
1923
|
+
b
|
|
1924
|
+
);
|
|
1925
|
+
if (existing !== void 0) {
|
|
1926
|
+
return assertionResult(publicAssertion(existing), "existing");
|
|
1927
|
+
}
|
|
1928
|
+
await validateCurrentRelation(
|
|
1929
|
+
ctx,
|
|
1930
|
+
target,
|
|
1931
|
+
relation,
|
|
1932
|
+
relation === "same" ? "assertSame" : "assertDifferent",
|
|
1933
|
+
a,
|
|
1934
|
+
b
|
|
1935
|
+
);
|
|
1936
|
+
const row = await insertAssertion(
|
|
1937
|
+
target,
|
|
1938
|
+
ctx.schema,
|
|
1939
|
+
ctx.graphId,
|
|
1940
|
+
relation,
|
|
1941
|
+
a,
|
|
1942
|
+
b,
|
|
1943
|
+
chunkQ7Q4WSLJ_cjs.nowIso(),
|
|
1944
|
+
touch
|
|
1945
|
+
);
|
|
1946
|
+
if (relation === "same") {
|
|
1947
|
+
await mergeCurrentClasses(target, ctx.schema, ctx.graphId, a, b);
|
|
1948
|
+
} else {
|
|
1949
|
+
await replaceSeparationForReferences(target, ctx.schema, ctx.graphId, [
|
|
1950
|
+
a,
|
|
1951
|
+
b
|
|
1952
|
+
]);
|
|
1953
|
+
}
|
|
1954
|
+
return assertionResult(publicAssertion(row), "created");
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
// src/identity/assertion-key.ts
|
|
1958
|
+
function identityAssertionSemanticKey(relation, a, b) {
|
|
1959
|
+
return encodeTupleKey([relation, a.kind, a.id, b.kind, b.id]);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
// src/identity/service-facade.ts
|
|
1963
|
+
function assertionSemanticKey(relation, a, b) {
|
|
1964
|
+
return identityAssertionSemanticKey(relation, a, b);
|
|
1965
|
+
}
|
|
1966
|
+
async function bulkAssertPairs(ctx, target, relation, pairs, touch) {
|
|
1967
|
+
if (pairs.length === 0) return [];
|
|
1968
|
+
const normalizedPairs = pairs.map((pair) => {
|
|
1969
|
+
const first = registeredPlainRef(ctx, pair.a);
|
|
1970
|
+
const second = registeredPlainRef(ctx, pair.b);
|
|
1971
|
+
if (refKey(first) === refKey(second)) throw selfAssertionError(relation);
|
|
1972
|
+
return normalizePair(first, second);
|
|
1973
|
+
});
|
|
1974
|
+
const endpoints = normalizedPairs.flatMap(([a, b]) => [a, b]);
|
|
1975
|
+
await requireLiveEndpoints(target, ctx.schema, ctx.graphId, endpoints);
|
|
1976
|
+
const classes = await loadCurrentStructuralClasses(
|
|
1977
|
+
target,
|
|
1978
|
+
ctx.schema,
|
|
1979
|
+
ctx.graphId,
|
|
1980
|
+
endpoints
|
|
1981
|
+
);
|
|
1982
|
+
const structuralByKey = /* @__PURE__ */ new Map();
|
|
1983
|
+
for (const members of classes.values()) {
|
|
1984
|
+
for (const member of members) structuralByKey.set(refKey(member), member);
|
|
1985
|
+
}
|
|
1986
|
+
const structuralNodes = [...structuralByKey.values()];
|
|
1987
|
+
const persistedAssertions = await loadAssertionsTouching(
|
|
1988
|
+
target,
|
|
1989
|
+
ctx.schema,
|
|
1990
|
+
ctx.graphId,
|
|
1991
|
+
structuralNodes,
|
|
1992
|
+
void 0
|
|
1993
|
+
);
|
|
1994
|
+
const bySemanticKey = new Map(
|
|
1995
|
+
persistedAssertions.map((assertion) => [
|
|
1996
|
+
assertionSemanticKey(
|
|
1997
|
+
assertion.rel,
|
|
1998
|
+
{ kind: assertion.a_kind, id: assertion.a_id },
|
|
1999
|
+
{ kind: assertion.b_kind, id: assertion.b_id }
|
|
2000
|
+
),
|
|
2001
|
+
assertion
|
|
2002
|
+
])
|
|
2003
|
+
);
|
|
2004
|
+
const unionFind = new UnionFind();
|
|
2005
|
+
const allReferences = /* @__PURE__ */ new Map();
|
|
2006
|
+
const byId = /* @__PURE__ */ new Map();
|
|
2007
|
+
for (const ref of structuralNodes) {
|
|
2008
|
+
unionFind.add(ref);
|
|
2009
|
+
allReferences.set(refKey(ref), ref);
|
|
2010
|
+
const group = byId.get(ref.id) ?? [];
|
|
2011
|
+
group.push(ref);
|
|
2012
|
+
byId.set(ref.id, group);
|
|
2013
|
+
}
|
|
2014
|
+
if (ctx.sameIdAcrossKinds === "fold") {
|
|
2015
|
+
for (const group of byId.values()) {
|
|
2016
|
+
const first = group[0];
|
|
2017
|
+
if (first === void 0) continue;
|
|
2018
|
+
for (const member of group.slice(1)) unionFind.union(first, member);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
for (const assertion of persistedAssertions) {
|
|
2022
|
+
const endpointA = { kind: assertion.a_kind, id: assertion.a_id };
|
|
2023
|
+
const endpointB = { kind: assertion.b_kind, id: assertion.b_id };
|
|
2024
|
+
if (assertion.rel === "same") {
|
|
2025
|
+
unionFind.union(endpointA, endpointB);
|
|
2026
|
+
} else {
|
|
2027
|
+
unionFind.add(endpointA);
|
|
2028
|
+
unionFind.add(endpointB);
|
|
2029
|
+
}
|
|
2030
|
+
allReferences.set(refKey(endpointA), endpointA);
|
|
2031
|
+
allReferences.set(refKey(endpointB), endpointB);
|
|
2032
|
+
}
|
|
2033
|
+
const kindsByRoot = /* @__PURE__ */ new Map();
|
|
2034
|
+
for (const ref of allReferences.values()) {
|
|
2035
|
+
const root = unionFind.root(ref);
|
|
2036
|
+
const kinds = kindsByRoot.get(root) ?? /* @__PURE__ */ new Set();
|
|
2037
|
+
kinds.add(ref.kind);
|
|
2038
|
+
kindsByRoot.set(root, kinds);
|
|
2039
|
+
}
|
|
2040
|
+
const differentByRoot = /* @__PURE__ */ new Map();
|
|
2041
|
+
for (const assertion of persistedAssertions) {
|
|
2042
|
+
if (assertion.rel !== "different") continue;
|
|
2043
|
+
const rootA = unionFind.root({
|
|
2044
|
+
kind: assertion.a_kind,
|
|
2045
|
+
id: assertion.a_id
|
|
2046
|
+
});
|
|
2047
|
+
const rootB = unionFind.root({
|
|
2048
|
+
kind: assertion.b_kind,
|
|
2049
|
+
id: assertion.b_id
|
|
2050
|
+
});
|
|
2051
|
+
indexDifferentAssertion(differentByRoot, rootA, rootB, assertion);
|
|
2052
|
+
}
|
|
2053
|
+
const createdRows = [];
|
|
2054
|
+
const results = [];
|
|
2055
|
+
const closureReferences = [];
|
|
2056
|
+
const timestamp = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
2057
|
+
const operation = relation === "same" ? "assertSame" : "assertDifferent";
|
|
2058
|
+
for (const [a, b] of normalizedPairs) {
|
|
2059
|
+
const semanticKey = assertionSemanticKey(relation, a, b);
|
|
2060
|
+
const existing = bySemanticKey.get(semanticKey);
|
|
2061
|
+
if (existing !== void 0) {
|
|
2062
|
+
results.push(assertionResult(publicAssertion(existing), "existing"));
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
const rootA = unionFind.root(a);
|
|
2066
|
+
const rootB = unionFind.root(b);
|
|
2067
|
+
if (relation === "different") {
|
|
2068
|
+
if (rootA === rootB) {
|
|
2069
|
+
throw new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
2070
|
+
operation,
|
|
2071
|
+
a,
|
|
2072
|
+
b,
|
|
2073
|
+
reason: "same-class"
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
} else {
|
|
2077
|
+
const spanning = differentByRoot.get(rootA)?.get(rootB);
|
|
2078
|
+
if (spanning !== void 0) {
|
|
2079
|
+
throw new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
2080
|
+
operation,
|
|
2081
|
+
a,
|
|
2082
|
+
b,
|
|
2083
|
+
reason: "different-assertion",
|
|
2084
|
+
conflictingAssertionId: spanning.id
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
const disjointKinds = kindSetsHaveDisjointKinds(
|
|
2088
|
+
ctx.registry,
|
|
2089
|
+
kindsByRoot.get(rootA) ?? /* @__PURE__ */ new Set([a.kind]),
|
|
2090
|
+
kindsByRoot.get(rootB) ?? /* @__PURE__ */ new Set([b.kind])
|
|
2091
|
+
);
|
|
2092
|
+
if (disjointKinds !== void 0) {
|
|
2093
|
+
throw new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
2094
|
+
operation,
|
|
2095
|
+
a,
|
|
2096
|
+
b,
|
|
2097
|
+
reason: "disjoint-kinds",
|
|
2098
|
+
conflictingKinds: disjointKinds
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
const row = buildAssertionRow(ctx.graphId, relation, a, b, timestamp);
|
|
2103
|
+
createdRows.push(row);
|
|
2104
|
+
bySemanticKey.set(semanticKey, row);
|
|
2105
|
+
results.push(assertionResult(publicAssertion(row), "created"));
|
|
2106
|
+
if (relation === "same") {
|
|
2107
|
+
closureReferences.push(a, b);
|
|
2108
|
+
if (rootA !== rootB) {
|
|
2109
|
+
unionFind.union(a, b);
|
|
2110
|
+
const survivingRoot = unionFind.root(a);
|
|
2111
|
+
const retiredRoot = survivingRoot === rootA ? rootB : rootA;
|
|
2112
|
+
const survivingKinds = kindsByRoot.get(survivingRoot) ?? /* @__PURE__ */ new Set();
|
|
2113
|
+
const retiredKinds = kindsByRoot.get(retiredRoot);
|
|
2114
|
+
if (retiredKinds !== void 0) {
|
|
2115
|
+
for (const kind of retiredKinds) survivingKinds.add(kind);
|
|
2116
|
+
}
|
|
2117
|
+
kindsByRoot.delete(retiredRoot);
|
|
2118
|
+
kindsByRoot.set(survivingRoot, survivingKinds);
|
|
2119
|
+
mergeDifferentAssertionRoots(
|
|
2120
|
+
differentByRoot,
|
|
2121
|
+
survivingRoot,
|
|
2122
|
+
retiredRoot
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
await insertAssertionRows(target, ctx.schema, createdRows);
|
|
2128
|
+
for (const row of createdRows) touch(ctx.graphId, row.id, row);
|
|
2129
|
+
if (closureReferences.length > 0) {
|
|
2130
|
+
await replaceAffectedClosure(
|
|
2131
|
+
target,
|
|
2132
|
+
ctx.schema,
|
|
2133
|
+
ctx.graphId,
|
|
2134
|
+
closureReferences,
|
|
2135
|
+
ctx.sameIdAcrossKinds
|
|
2136
|
+
);
|
|
2137
|
+
} else {
|
|
2138
|
+
await replaceSeparationForReferences(
|
|
2139
|
+
target,
|
|
2140
|
+
ctx.schema,
|
|
2141
|
+
ctx.graphId,
|
|
2142
|
+
createdRows.flatMap((row) => [
|
|
2143
|
+
{ kind: row.a_kind, id: row.a_id },
|
|
2144
|
+
{ kind: row.b_kind, id: row.b_id }
|
|
2145
|
+
])
|
|
2146
|
+
);
|
|
2147
|
+
}
|
|
2148
|
+
return results;
|
|
2149
|
+
}
|
|
2150
|
+
async function findCurrentAssertionById(target, schema, graphId, id) {
|
|
2151
|
+
const rows = await target.execute(
|
|
2152
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
2153
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
2154
|
+
FROM ${schema.identityAssertionsTable}
|
|
2155
|
+
WHERE graph_id = ${graphId}
|
|
2156
|
+
AND id = ${id}
|
|
2157
|
+
AND valid_to IS NULL
|
|
2158
|
+
AND deleted_at IS NULL
|
|
2159
|
+
LIMIT 1
|
|
2160
|
+
`)
|
|
2161
|
+
);
|
|
2162
|
+
return rows[0] === void 0 ? void 0 : normalizeIdentityAssertionRow(rows[0]);
|
|
2163
|
+
}
|
|
2164
|
+
async function retractById(ctx, target, id, touch) {
|
|
2165
|
+
const existing = await findCurrentAssertionById(
|
|
2166
|
+
target,
|
|
2167
|
+
ctx.schema,
|
|
2168
|
+
ctx.graphId,
|
|
2169
|
+
id
|
|
2170
|
+
);
|
|
2171
|
+
if (existing === void 0) return void 0;
|
|
2172
|
+
const now = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
2173
|
+
const validTo = clampValidTo(now, existing.valid_from);
|
|
2174
|
+
const ended = { ...existing, valid_to: validTo, updated_at: now };
|
|
2175
|
+
await executeIdentityStatement(
|
|
2176
|
+
target,
|
|
2177
|
+
chunkVCRRKBLN_cjs.sql`
|
|
2178
|
+
UPDATE ${ctx.schema.identityAssertionsTable}
|
|
2179
|
+
SET valid_to = ${validTo}, updated_at = ${now}
|
|
2180
|
+
WHERE graph_id = ${ctx.graphId}
|
|
2181
|
+
AND id = ${id}
|
|
2182
|
+
AND valid_to IS NULL
|
|
2183
|
+
`
|
|
2184
|
+
);
|
|
2185
|
+
touch(ctx.graphId, id, ended);
|
|
2186
|
+
return ended;
|
|
2187
|
+
}
|
|
2188
|
+
async function retractByIds(ctx, target, ids, touch) {
|
|
2189
|
+
const uniqueIds = [...new Set(ids)];
|
|
2190
|
+
if (uniqueIds.length === 0) return [];
|
|
2191
|
+
const current = [];
|
|
2192
|
+
const readChunkSize = identityChunkSize(target, {
|
|
2193
|
+
fixedParameters: 1,
|
|
2194
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
2195
|
+
parametersPerItem: 1
|
|
2196
|
+
});
|
|
2197
|
+
for (const idChunk of chunkBSFJMMV3_cjs.chunk(uniqueIds, readChunkSize)) {
|
|
2198
|
+
const placeholders = chunkVCRRKBLN_cjs.sql.join(
|
|
2199
|
+
idChunk.map((id) => chunkVCRRKBLN_cjs.sql`${id}`),
|
|
2200
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
2201
|
+
);
|
|
2202
|
+
const rows = await target.execute(
|
|
2203
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
2204
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
2205
|
+
FROM ${ctx.schema.identityAssertionsTable}
|
|
2206
|
+
WHERE graph_id = ${ctx.graphId}
|
|
2207
|
+
AND id IN (${placeholders})
|
|
2208
|
+
AND valid_to IS NULL
|
|
2209
|
+
AND deleted_at IS NULL
|
|
2210
|
+
`)
|
|
2211
|
+
);
|
|
2212
|
+
current.push(...rows.map((row) => normalizeIdentityAssertionRow(row)));
|
|
2213
|
+
}
|
|
2214
|
+
if (current.length === 0) return [];
|
|
2215
|
+
const now = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
2216
|
+
const byValidTo = /* @__PURE__ */ new Map();
|
|
2217
|
+
const endedById = /* @__PURE__ */ new Map();
|
|
2218
|
+
for (const row of current) {
|
|
2219
|
+
const validTo = clampValidTo(now, row.valid_from);
|
|
2220
|
+
endedById.set(row.id, validTo);
|
|
2221
|
+
const group = byValidTo.get(validTo) ?? [];
|
|
2222
|
+
group.push(row.id);
|
|
2223
|
+
byValidTo.set(validTo, group);
|
|
2224
|
+
}
|
|
2225
|
+
const updateChunkSize = identityChunkSize(target, {
|
|
2226
|
+
fixedParameters: 3,
|
|
2227
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
2228
|
+
parametersPerItem: 1
|
|
2229
|
+
});
|
|
2230
|
+
for (const [validTo, ids2] of byValidTo) {
|
|
2231
|
+
for (const idChunk of chunkBSFJMMV3_cjs.chunk(ids2, updateChunkSize)) {
|
|
2232
|
+
const placeholders = chunkVCRRKBLN_cjs.sql.join(
|
|
2233
|
+
idChunk.map((id) => chunkVCRRKBLN_cjs.sql`${id}`),
|
|
2234
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
2235
|
+
);
|
|
2236
|
+
await executeIdentityStatement(
|
|
2237
|
+
target,
|
|
2238
|
+
chunkVCRRKBLN_cjs.sql`
|
|
2239
|
+
UPDATE ${ctx.schema.identityAssertionsTable}
|
|
2240
|
+
SET valid_to = ${validTo}, updated_at = ${now}
|
|
2241
|
+
WHERE graph_id = ${ctx.graphId}
|
|
2242
|
+
AND id IN (${placeholders})
|
|
2243
|
+
AND valid_to IS NULL
|
|
2244
|
+
`
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
const currentById = new Map(current.map((row) => [row.id, row]));
|
|
2249
|
+
const ended = uniqueIds.flatMap((id) => {
|
|
2250
|
+
const row = currentById.get(id);
|
|
2251
|
+
if (row === void 0) return [];
|
|
2252
|
+
return [
|
|
2253
|
+
{
|
|
2254
|
+
...row,
|
|
2255
|
+
valid_to: chunkN66HCGCY_cjs.requireDefined(endedById.get(row.id)),
|
|
2256
|
+
updated_at: now
|
|
2257
|
+
}
|
|
2258
|
+
];
|
|
2259
|
+
});
|
|
2260
|
+
for (const row of ended) {
|
|
2261
|
+
touch(ctx.graphId, row.id, { ...row });
|
|
2262
|
+
}
|
|
2263
|
+
return ended;
|
|
2264
|
+
}
|
|
2265
|
+
async function runIdentityMutation(ctx, fn) {
|
|
2266
|
+
let touched = false;
|
|
2267
|
+
return runInWriteTransaction(
|
|
2268
|
+
{
|
|
2269
|
+
graphId: ctx.graphId,
|
|
2270
|
+
schemaVersion: ctx.schemaVersion,
|
|
2271
|
+
historyEnabled: ctx.historyEnabled,
|
|
2272
|
+
revisionTrackingEnabled: ctx.revisionTrackingEnabled,
|
|
2273
|
+
revisionSchema: ctx.schema
|
|
2274
|
+
},
|
|
2275
|
+
ctx.backend,
|
|
2276
|
+
async (target) => {
|
|
2277
|
+
await lockIdentityGraph(target, ctx.graphId);
|
|
2278
|
+
return chunkXMQSEJCF_cjs.withRecordedIdentityMutationTarget(
|
|
2279
|
+
target,
|
|
2280
|
+
(rawTarget, touch) => fn(
|
|
2281
|
+
rawTarget,
|
|
2282
|
+
(graphId, id, afterImage) => {
|
|
2283
|
+
touched = true;
|
|
2284
|
+
touch(graphId, id, afterImage);
|
|
2285
|
+
},
|
|
2286
|
+
() => {
|
|
2287
|
+
touched = true;
|
|
2288
|
+
}
|
|
2289
|
+
)
|
|
2290
|
+
);
|
|
2291
|
+
},
|
|
2292
|
+
{ didWrite: () => touched }
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
2295
|
+
function createIdentityReadFacade(ctx) {
|
|
2296
|
+
return {
|
|
2297
|
+
async representativeOf(input) {
|
|
2298
|
+
const members = await visibleMembersAtCoordinate(
|
|
2299
|
+
ctx,
|
|
2300
|
+
registeredPlainRef(ctx, input)
|
|
2301
|
+
);
|
|
2302
|
+
return members[0] === void 0 ? void 0 : publicNodeRef(members[0]);
|
|
2303
|
+
},
|
|
2304
|
+
async membersOf(input) {
|
|
2305
|
+
const members = await visibleMembersAtCoordinate(
|
|
2306
|
+
ctx,
|
|
2307
|
+
registeredPlainRef(ctx, input)
|
|
2308
|
+
);
|
|
2309
|
+
return members.map((member) => publicNodeRef(member));
|
|
2310
|
+
},
|
|
2311
|
+
async nodesOf(input) {
|
|
2312
|
+
const members = await visibleMembersAtCoordinate(
|
|
2313
|
+
ctx,
|
|
2314
|
+
registeredPlainRef(ctx, input)
|
|
2315
|
+
);
|
|
2316
|
+
const nodes = await ctx.loadNodes(members, ctx.coordinate);
|
|
2317
|
+
return nodes.filter((node) => node !== void 0);
|
|
2318
|
+
},
|
|
2319
|
+
async areSame(firstInput, secondInput) {
|
|
2320
|
+
const first = registeredPlainRef(ctx, firstInput);
|
|
2321
|
+
const second = registeredPlainRef(ctx, secondInput);
|
|
2322
|
+
const members = await visibleMembersAtCoordinate(ctx, first);
|
|
2323
|
+
return containsRef(members, second);
|
|
2324
|
+
},
|
|
2325
|
+
async areDifferent(firstInput, secondInput) {
|
|
2326
|
+
const first = registeredPlainRef(ctx, firstInput);
|
|
2327
|
+
const second = registeredPlainRef(ctx, secondInput);
|
|
2328
|
+
const { coordinate } = ctx;
|
|
2329
|
+
if (coordinate === void 0 || isCurrentClosureCoordinate(coordinate)) {
|
|
2330
|
+
const [firstVisible, secondVisible] = await Promise.all([
|
|
2331
|
+
loadCurrentVisibleMembers(
|
|
2332
|
+
ctx.backend,
|
|
2333
|
+
ctx.schema,
|
|
2334
|
+
ctx.graphId,
|
|
2335
|
+
first
|
|
2336
|
+
),
|
|
2337
|
+
loadCurrentVisibleMembers(
|
|
2338
|
+
ctx.backend,
|
|
2339
|
+
ctx.schema,
|
|
2340
|
+
ctx.graphId,
|
|
2341
|
+
second
|
|
2342
|
+
)
|
|
2343
|
+
]);
|
|
2344
|
+
if (firstVisible.length === 0 || secondVisible.length === 0)
|
|
2345
|
+
return false;
|
|
2346
|
+
const classes2 = await loadCurrentStructuralClasses(
|
|
2347
|
+
ctx.backend,
|
|
2348
|
+
ctx.schema,
|
|
2349
|
+
ctx.graphId,
|
|
2350
|
+
[first, second]
|
|
2351
|
+
);
|
|
2352
|
+
const firstClass2 = chunkN66HCGCY_cjs.requireDefined(classes2.get(refKey(first)));
|
|
2353
|
+
const secondClass2 = chunkN66HCGCY_cjs.requireDefined(classes2.get(refKey(second)));
|
|
2354
|
+
const separated = await isSeparated(
|
|
2355
|
+
ctx.backend,
|
|
2356
|
+
ctx.schema,
|
|
2357
|
+
ctx.graphId,
|
|
2358
|
+
currentClassKey(firstClass2),
|
|
2359
|
+
currentClassKey(secondClass2),
|
|
2360
|
+
ctx.registry
|
|
2361
|
+
);
|
|
2362
|
+
return separated || classHasDisjointKinds(ctx.registry, firstClass2, secondClass2) !== void 0;
|
|
2363
|
+
}
|
|
2364
|
+
const classes = await loadHistoricalClasses(
|
|
2365
|
+
ctx.backend,
|
|
2366
|
+
ctx.schema,
|
|
2367
|
+
ctx.graphId,
|
|
2368
|
+
[first, second],
|
|
2369
|
+
coordinate,
|
|
2370
|
+
ctx.sameIdAcrossKinds
|
|
2371
|
+
);
|
|
2372
|
+
const firstClass = chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(first)));
|
|
2373
|
+
const secondClass = chunkN66HCGCY_cjs.requireDefined(classes.get(refKey(second)));
|
|
2374
|
+
if (firstClass.visible.length === 0 || secondClass.visible.length === 0)
|
|
2375
|
+
return false;
|
|
2376
|
+
const different = await loadSpanningDifferentAssertion(
|
|
2377
|
+
ctx.backend,
|
|
2378
|
+
ctx.schema,
|
|
2379
|
+
ctx.graphId,
|
|
2380
|
+
firstClass.structural,
|
|
2381
|
+
secondClass.structural,
|
|
2382
|
+
ctx.coordinate
|
|
2383
|
+
);
|
|
2384
|
+
return different !== void 0 || classHasDisjointKinds(
|
|
2385
|
+
ctx.registry,
|
|
2386
|
+
firstClass.structural,
|
|
2387
|
+
secondClass.structural
|
|
2388
|
+
) !== void 0;
|
|
2389
|
+
},
|
|
2390
|
+
async assertionsOf(input) {
|
|
2391
|
+
const ref = registeredPlainRef(ctx, input);
|
|
2392
|
+
const members = await visibleMembersAtCoordinate(ctx, ref);
|
|
2393
|
+
if (members.length === 0) return [];
|
|
2394
|
+
const assertions = await loadAssertionsTouching(
|
|
2395
|
+
ctx.backend,
|
|
2396
|
+
ctx.schema,
|
|
2397
|
+
ctx.graphId,
|
|
2398
|
+
[ref],
|
|
2399
|
+
ctx.coordinate
|
|
2400
|
+
);
|
|
2401
|
+
return assertions.filter(
|
|
2402
|
+
(assertion) => assertion.a_kind === ref.kind && assertion.a_id === ref.id || assertion.b_kind === ref.kind && assertion.b_id === ref.id
|
|
2403
|
+
).toSorted((left, right) => chunkXMQSEJCF_cjs.compareCodePoints(left.id, right.id)).map((assertion) => publicAssertion(assertion));
|
|
2404
|
+
}
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
function partitionRetractedEndpoints(retracted) {
|
|
2408
|
+
const closureReferences = [];
|
|
2409
|
+
const separationReferences = [];
|
|
2410
|
+
for (const ended of retracted) {
|
|
2411
|
+
const endpoints = [
|
|
2412
|
+
{ kind: ended.a_kind, id: ended.a_id },
|
|
2413
|
+
{ kind: ended.b_kind, id: ended.b_id }
|
|
2414
|
+
];
|
|
2415
|
+
if (ended.rel === "same") {
|
|
2416
|
+
closureReferences.push(...endpoints);
|
|
2417
|
+
} else {
|
|
2418
|
+
separationReferences.push(...endpoints);
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
return { closureReferences, separationReferences };
|
|
2422
|
+
}
|
|
2423
|
+
function createIdentityFacade(ctx) {
|
|
2424
|
+
return {
|
|
2425
|
+
...createIdentityReadFacade(ctx),
|
|
2426
|
+
assertSame(a, b) {
|
|
2427
|
+
return runIdentityMutation(
|
|
2428
|
+
ctx,
|
|
2429
|
+
(target, touch) => assertPair(ctx, target, "same", a, b, touch)
|
|
2430
|
+
);
|
|
2431
|
+
},
|
|
2432
|
+
assertDifferent(a, b) {
|
|
2433
|
+
return runIdentityMutation(
|
|
2434
|
+
ctx,
|
|
2435
|
+
(target, touch) => assertPair(ctx, target, "different", a, b, touch)
|
|
2436
|
+
);
|
|
2437
|
+
},
|
|
2438
|
+
bulkAssertSame(pairs) {
|
|
2439
|
+
return runIdentityMutation(
|
|
2440
|
+
ctx,
|
|
2441
|
+
(target, touch) => bulkAssertPairs(ctx, target, "same", pairs, touch)
|
|
2442
|
+
);
|
|
2443
|
+
},
|
|
2444
|
+
bulkAssertDifferent(pairs) {
|
|
2445
|
+
return runIdentityMutation(
|
|
2446
|
+
ctx,
|
|
2447
|
+
(target, touch) => bulkAssertPairs(ctx, target, "different", pairs, touch)
|
|
2448
|
+
);
|
|
2449
|
+
},
|
|
2450
|
+
retractAssertion(id) {
|
|
2451
|
+
return runIdentityMutation(ctx, async (target, touch) => {
|
|
2452
|
+
const ended = await retractById(ctx, target, id, touch);
|
|
2453
|
+
if (ended !== void 0) {
|
|
2454
|
+
const endpoints = [
|
|
2455
|
+
{ kind: ended.a_kind, id: ended.a_id },
|
|
2456
|
+
{ kind: ended.b_kind, id: ended.b_id }
|
|
2457
|
+
];
|
|
2458
|
+
if (ended.rel === "same") {
|
|
2459
|
+
await replaceAffectedClosure(
|
|
2460
|
+
target,
|
|
2461
|
+
ctx.schema,
|
|
2462
|
+
ctx.graphId,
|
|
2463
|
+
endpoints,
|
|
2464
|
+
ctx.sameIdAcrossKinds
|
|
2465
|
+
);
|
|
2466
|
+
} else {
|
|
2467
|
+
await replaceSeparationForReferences(
|
|
2468
|
+
target,
|
|
2469
|
+
ctx.schema,
|
|
2470
|
+
ctx.graphId,
|
|
2471
|
+
endpoints
|
|
2472
|
+
);
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
return ended === void 0 ? void 0 : publicAssertion(ended);
|
|
2476
|
+
});
|
|
2477
|
+
},
|
|
2478
|
+
retractSameAssertion(firstInput, secondInput) {
|
|
2479
|
+
return runIdentityMutation(ctx, async (target, touch) => {
|
|
2480
|
+
const [a, b] = normalizePair(
|
|
2481
|
+
registeredPlainRef(ctx, firstInput),
|
|
2482
|
+
registeredPlainRef(ctx, secondInput)
|
|
2483
|
+
);
|
|
2484
|
+
const existing = await currentAssertionForPair(
|
|
2485
|
+
target,
|
|
2486
|
+
ctx.schema,
|
|
2487
|
+
ctx.graphId,
|
|
2488
|
+
"same",
|
|
2489
|
+
a,
|
|
2490
|
+
b
|
|
2491
|
+
);
|
|
2492
|
+
if (existing === void 0) return;
|
|
2493
|
+
const ended = await retractById(ctx, target, existing.id, touch);
|
|
2494
|
+
await replaceAffectedClosure(
|
|
2495
|
+
target,
|
|
2496
|
+
ctx.schema,
|
|
2497
|
+
ctx.graphId,
|
|
2498
|
+
[a, b],
|
|
2499
|
+
ctx.sameIdAcrossKinds
|
|
2500
|
+
);
|
|
2501
|
+
return ended === void 0 ? void 0 : publicAssertion(ended);
|
|
2502
|
+
});
|
|
2503
|
+
},
|
|
2504
|
+
retractDifferentAssertion(firstInput, secondInput) {
|
|
2505
|
+
return runIdentityMutation(ctx, async (target, touch) => {
|
|
2506
|
+
const [a, b] = normalizePair(
|
|
2507
|
+
registeredPlainRef(ctx, firstInput),
|
|
2508
|
+
registeredPlainRef(ctx, secondInput)
|
|
2509
|
+
);
|
|
2510
|
+
const existing = await currentAssertionForPair(
|
|
2511
|
+
target,
|
|
2512
|
+
ctx.schema,
|
|
2513
|
+
ctx.graphId,
|
|
2514
|
+
"different",
|
|
2515
|
+
a,
|
|
2516
|
+
b
|
|
2517
|
+
);
|
|
2518
|
+
if (existing === void 0) return;
|
|
2519
|
+
const ended = await retractById(ctx, target, existing.id, touch);
|
|
2520
|
+
await replaceSeparationForReferences(target, ctx.schema, ctx.graphId, [
|
|
2521
|
+
a,
|
|
2522
|
+
b
|
|
2523
|
+
]);
|
|
2524
|
+
return ended === void 0 ? void 0 : publicAssertion(ended);
|
|
2525
|
+
});
|
|
2526
|
+
},
|
|
2527
|
+
bulkRetractAssertions(ids) {
|
|
2528
|
+
return runIdentityMutation(ctx, async (target, touch) => {
|
|
2529
|
+
const retracted = await retractByIds(ctx, target, ids, touch);
|
|
2530
|
+
const { closureReferences, separationReferences } = partitionRetractedEndpoints(retracted);
|
|
2531
|
+
if (closureReferences.length > 0) {
|
|
2532
|
+
await replaceAffectedClosure(
|
|
2533
|
+
target,
|
|
2534
|
+
ctx.schema,
|
|
2535
|
+
ctx.graphId,
|
|
2536
|
+
closureReferences,
|
|
2537
|
+
ctx.sameIdAcrossKinds
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
await replaceSeparationForReferences(
|
|
2541
|
+
target,
|
|
2542
|
+
ctx.schema,
|
|
2543
|
+
ctx.graphId,
|
|
2544
|
+
separationReferences
|
|
2545
|
+
);
|
|
2546
|
+
return retracted.map((assertion) => publicAssertion(assertion));
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
// src/identity/service-interchange-write.ts
|
|
2553
|
+
function transferShapeError(assertion, message, issue) {
|
|
2554
|
+
return new chunkNI72YOJB_cjs.ValidationError(message, {
|
|
2555
|
+
issues: [
|
|
2556
|
+
{
|
|
2557
|
+
path: "identity.assertions",
|
|
2558
|
+
assertionId: assertion.id,
|
|
2559
|
+
message: issue.message,
|
|
2560
|
+
code: issue.code
|
|
2561
|
+
}
|
|
2562
|
+
]
|
|
2563
|
+
});
|
|
2564
|
+
}
|
|
2565
|
+
function validateTransferShape(ctx, assertion, mode) {
|
|
2566
|
+
if (!ctx.registry.nodeKinds.has(assertion.a.kind) || !ctx.registry.nodeKinds.has(assertion.b.kind)) {
|
|
2567
|
+
throw transferShapeError(
|
|
2568
|
+
assertion,
|
|
2569
|
+
"Identity import references an unknown node kind.",
|
|
2570
|
+
{
|
|
2571
|
+
message: `Unknown identity endpoint kind in assertion ${assertion.id}`,
|
|
2572
|
+
code: "IDENTITY_IMPORT_UNKNOWN_KIND"
|
|
2573
|
+
}
|
|
2574
|
+
);
|
|
2575
|
+
}
|
|
2576
|
+
if (refKey(assertion.a) === refKey(assertion.b)) {
|
|
2577
|
+
throw transferShapeError(
|
|
2578
|
+
assertion,
|
|
2579
|
+
`Identity ${assertion.relation} assertions require two distinct node references.`,
|
|
2580
|
+
{
|
|
2581
|
+
message: `Assertion ${assertion.id} relates a node to itself`,
|
|
2582
|
+
code: "IDENTITY_SELF_ASSERTION"
|
|
2583
|
+
}
|
|
2584
|
+
);
|
|
2585
|
+
}
|
|
2586
|
+
const normalized = normalizePair(assertion.a, assertion.b);
|
|
2587
|
+
if (refKey(normalized[0]) !== refKey(assertion.a) || refKey(normalized[1]) !== refKey(assertion.b)) {
|
|
2588
|
+
throw transferShapeError(
|
|
2589
|
+
assertion,
|
|
2590
|
+
"Identity import pairs must be normalized.",
|
|
2591
|
+
{
|
|
2592
|
+
message: `Assertion ${assertion.id} endpoints are not in code-point order`,
|
|
2593
|
+
code: "IDENTITY_IMPORT_PAIR_NOT_NORMALIZED"
|
|
2594
|
+
}
|
|
2595
|
+
);
|
|
2596
|
+
}
|
|
2597
|
+
if (mode === "state" && assertion.validTo !== void 0) {
|
|
2598
|
+
throw transferShapeError(
|
|
2599
|
+
assertion,
|
|
2600
|
+
"State identity import cannot contain ended assertions.",
|
|
2601
|
+
{
|
|
2602
|
+
message: `Assertion ${assertion.id} is ended`,
|
|
2603
|
+
code: "IDENTITY_STATE_IMPORT_ENDED_ASSERTION"
|
|
2604
|
+
}
|
|
2605
|
+
);
|
|
2606
|
+
}
|
|
2607
|
+
const now = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
2608
|
+
if (assertion.validTo === void 0 && chunkXMQSEJCF_cjs.compareCodePoints(assertion.validFrom, now) > 0) {
|
|
2609
|
+
throw transferShapeError(
|
|
2610
|
+
assertion,
|
|
2611
|
+
"Identity import cannot contain future-dated open assertions.",
|
|
2612
|
+
{
|
|
2613
|
+
message: `Assertion ${assertion.id} validFrom is in the future`,
|
|
2614
|
+
code: "IDENTITY_IMPORT_FUTURE_VALID_FROM"
|
|
2615
|
+
}
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
if (assertion.validTo !== void 0 && chunkXMQSEJCF_cjs.compareCodePoints(assertion.validTo, assertion.validFrom) < 0) {
|
|
2619
|
+
throw transferShapeError(
|
|
2620
|
+
assertion,
|
|
2621
|
+
"Identity assertion validity window is empty.",
|
|
2622
|
+
{
|
|
2623
|
+
message: `Assertion ${assertion.id} validTo must not precede validFrom`,
|
|
2624
|
+
code: "IDENTITY_IMPORT_INVALID_WINDOW"
|
|
2625
|
+
}
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2628
|
+
if (assertion.endedBy !== void 0) {
|
|
2629
|
+
if (assertion.validTo === void 0) {
|
|
2630
|
+
throw transferShapeError(
|
|
2631
|
+
assertion,
|
|
2632
|
+
"Identity import cannot name an ending cause on an open assertion.",
|
|
2633
|
+
{
|
|
2634
|
+
message: `Assertion ${assertion.id} carries endedBy without validTo`,
|
|
2635
|
+
code: "IDENTITY_IMPORT_ENDED_BY_WITHOUT_END"
|
|
2636
|
+
}
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
2639
|
+
const endedByKey = refKey(assertion.endedBy);
|
|
2640
|
+
if (endedByKey !== refKey(assertion.a) && endedByKey !== refKey(assertion.b)) {
|
|
2641
|
+
throw transferShapeError(
|
|
2642
|
+
assertion,
|
|
2643
|
+
"Identity import ending cause must name one of the assertion's endpoints.",
|
|
2644
|
+
{
|
|
2645
|
+
message: `Assertion ${assertion.id} endedBy is not an endpoint of the assertion`,
|
|
2646
|
+
code: "IDENTITY_IMPORT_ENDED_BY_NOT_ENDPOINT"
|
|
2647
|
+
}
|
|
2648
|
+
);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
if (assertion.validTo !== void 0 && chunkXMQSEJCF_cjs.compareCodePoints(assertion.validTo, now) > 0) {
|
|
2652
|
+
throw transferShapeError(
|
|
2653
|
+
assertion,
|
|
2654
|
+
"Identity import cannot contain assertions that end in the future.",
|
|
2655
|
+
{
|
|
2656
|
+
message: `Assertion ${assertion.id} validTo is in the future`,
|
|
2657
|
+
code: "IDENTITY_IMPORT_FUTURE_VALID_TO"
|
|
2658
|
+
}
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
return normalized;
|
|
2662
|
+
}
|
|
2663
|
+
var IDENTITY_IMPORT_FAILED_ASSERTION = /* @__PURE__ */ Symbol(
|
|
2664
|
+
"typegraph.identity.failedAssertionId"
|
|
2665
|
+
);
|
|
2666
|
+
var IDENTITY_IMPORT_PROGRESS = /* @__PURE__ */ Symbol(
|
|
2667
|
+
"typegraph.identity.importProgress"
|
|
2668
|
+
);
|
|
2669
|
+
function rethrowTaggedWithAssertion(error, assertionId, progress) {
|
|
2670
|
+
if (typeof error === "object" && error !== null) {
|
|
2671
|
+
Object.defineProperty(error, IDENTITY_IMPORT_FAILED_ASSERTION, {
|
|
2672
|
+
value: assertionId,
|
|
2673
|
+
enumerable: false,
|
|
2674
|
+
configurable: true
|
|
2675
|
+
});
|
|
2676
|
+
Object.defineProperty(error, IDENTITY_IMPORT_PROGRESS, {
|
|
2677
|
+
value: progress,
|
|
2678
|
+
enumerable: false,
|
|
2679
|
+
configurable: true
|
|
2680
|
+
});
|
|
2681
|
+
}
|
|
2682
|
+
throw error;
|
|
2683
|
+
}
|
|
2684
|
+
async function importIdentityAssertionsIntoTarget(ctx, target, assertions, mode) {
|
|
2685
|
+
let created = 0;
|
|
2686
|
+
let skipped = 0;
|
|
2687
|
+
await chunkXMQSEJCF_cjs.withRecordedIdentityMutationTarget(target, async (rawTarget, touch) => {
|
|
2688
|
+
const normalized = assertions.map((assertion) => ({
|
|
2689
|
+
assertion,
|
|
2690
|
+
endpoints: validateTransferShape(ctx, assertion, mode)
|
|
2691
|
+
}));
|
|
2692
|
+
const existingById = await loadAssertionsByIds(
|
|
2693
|
+
rawTarget,
|
|
2694
|
+
ctx.schema,
|
|
2695
|
+
ctx.graphId,
|
|
2696
|
+
assertions.map((assertion) => assertion.id)
|
|
2697
|
+
);
|
|
2698
|
+
const currentEndpoints = [];
|
|
2699
|
+
const endedEndpoints = [];
|
|
2700
|
+
for (const { assertion, endpoints } of normalized) {
|
|
2701
|
+
const [a, b] = endpoints;
|
|
2702
|
+
if (assertion.validTo === void 0) {
|
|
2703
|
+
currentEndpoints.push(a, b);
|
|
2704
|
+
} else {
|
|
2705
|
+
endedEndpoints.push(a, b);
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
const attributeMissingEndpoint = (error, ended) => {
|
|
2709
|
+
if (error instanceof chunkNI72YOJB_cjs.NodeNotFoundError) {
|
|
2710
|
+
const missing = { kind: error.details.kind, id: error.details.id };
|
|
2711
|
+
const failing = normalized.find(
|
|
2712
|
+
({ assertion, endpoints }) => assertion.validTo !== void 0 === ended && endpoints.some(
|
|
2713
|
+
(endpoint) => endpoint.kind === missing.kind && endpoint.id === missing.id
|
|
2714
|
+
)
|
|
2715
|
+
);
|
|
2716
|
+
if (failing !== void 0) {
|
|
2717
|
+
rethrowTaggedWithAssertion(error, failing.assertion.id, {
|
|
2718
|
+
created,
|
|
2719
|
+
skipped
|
|
2720
|
+
});
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
throw error;
|
|
2724
|
+
};
|
|
2725
|
+
try {
|
|
2726
|
+
await requireLiveEndpoints(
|
|
2727
|
+
rawTarget,
|
|
2728
|
+
ctx.schema,
|
|
2729
|
+
ctx.graphId,
|
|
2730
|
+
currentEndpoints
|
|
2731
|
+
);
|
|
2732
|
+
} catch (error) {
|
|
2733
|
+
attributeMissingEndpoint(error, false);
|
|
2734
|
+
}
|
|
2735
|
+
try {
|
|
2736
|
+
await requireStructuralEndpoints(
|
|
2737
|
+
rawTarget,
|
|
2738
|
+
ctx.schema,
|
|
2739
|
+
ctx.graphId,
|
|
2740
|
+
endedEndpoints
|
|
2741
|
+
);
|
|
2742
|
+
} catch (error) {
|
|
2743
|
+
attributeMissingEndpoint(error, true);
|
|
2744
|
+
}
|
|
2745
|
+
for (const { assertion, endpoints } of normalized) {
|
|
2746
|
+
const [a, b] = endpoints;
|
|
2747
|
+
try {
|
|
2748
|
+
const sameId = existingById.get(assertion.id);
|
|
2749
|
+
if (sameId !== void 0) {
|
|
2750
|
+
const exact = sameId.rel === assertion.relation && sameId.a_kind === a.kind && sameId.a_id === a.id && sameId.b_kind === b.kind && sameId.b_id === b.id && sameId.valid_from === assertion.validFrom && sameId.valid_to === assertion.validTo && sameId.ended_by_kind === assertion.endedBy?.kind && sameId.ended_by_id === assertion.endedBy?.id;
|
|
2751
|
+
if (exact) {
|
|
2752
|
+
skipped += 1;
|
|
2753
|
+
continue;
|
|
2754
|
+
}
|
|
2755
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
2756
|
+
`Identity assertion id ${assertion.id} already identifies different truth.`,
|
|
2757
|
+
{
|
|
2758
|
+
code: "IDENTITY_IMPORT_ID_CONFLICT",
|
|
2759
|
+
graphId: ctx.graphId,
|
|
2760
|
+
assertionId: assertion.id
|
|
2761
|
+
}
|
|
2762
|
+
);
|
|
2763
|
+
}
|
|
2764
|
+
if (assertion.validTo !== void 0) {
|
|
2765
|
+
const timestamp = assertion.validFrom;
|
|
2766
|
+
const row = {
|
|
2767
|
+
graph_id: ctx.graphId,
|
|
2768
|
+
id: assertion.id,
|
|
2769
|
+
rel: assertion.relation,
|
|
2770
|
+
a_kind: a.kind,
|
|
2771
|
+
a_id: a.id,
|
|
2772
|
+
b_kind: b.kind,
|
|
2773
|
+
b_id: b.id,
|
|
2774
|
+
valid_from: assertion.validFrom,
|
|
2775
|
+
valid_to: assertion.validTo,
|
|
2776
|
+
created_at: timestamp,
|
|
2777
|
+
updated_at: assertion.validTo,
|
|
2778
|
+
deleted_at: void 0,
|
|
2779
|
+
ended_by_kind: assertion.endedBy?.kind,
|
|
2780
|
+
ended_by_id: assertion.endedBy?.id
|
|
2781
|
+
};
|
|
2782
|
+
await insertAssertionRows(rawTarget, ctx.schema, [row]);
|
|
2783
|
+
touch(ctx.graphId, row.id, row);
|
|
2784
|
+
existingById.set(row.id, row);
|
|
2785
|
+
created += 1;
|
|
2786
|
+
continue;
|
|
2787
|
+
}
|
|
2788
|
+
const existing = await currentAssertionForPair(
|
|
2789
|
+
rawTarget,
|
|
2790
|
+
ctx.schema,
|
|
2791
|
+
ctx.graphId,
|
|
2792
|
+
assertion.relation,
|
|
2793
|
+
a,
|
|
2794
|
+
b
|
|
2795
|
+
);
|
|
2796
|
+
if (existing !== void 0) {
|
|
2797
|
+
skipped += 1;
|
|
2798
|
+
continue;
|
|
2799
|
+
}
|
|
2800
|
+
await validateCurrentRelation(
|
|
2801
|
+
ctx,
|
|
2802
|
+
rawTarget,
|
|
2803
|
+
assertion.relation,
|
|
2804
|
+
"import",
|
|
2805
|
+
a,
|
|
2806
|
+
b
|
|
2807
|
+
);
|
|
2808
|
+
const inserted = await insertAssertion(
|
|
2809
|
+
rawTarget,
|
|
2810
|
+
ctx.schema,
|
|
2811
|
+
ctx.graphId,
|
|
2812
|
+
assertion.relation,
|
|
2813
|
+
a,
|
|
2814
|
+
b,
|
|
2815
|
+
chunkQ7Q4WSLJ_cjs.nowIso(),
|
|
2816
|
+
touch,
|
|
2817
|
+
{ id: assertion.id, validFrom: assertion.validFrom }
|
|
2818
|
+
);
|
|
2819
|
+
existingById.set(inserted.id, inserted);
|
|
2820
|
+
created += 1;
|
|
2821
|
+
if (assertion.relation === "same") {
|
|
2822
|
+
await mergeCurrentClasses(rawTarget, ctx.schema, ctx.graphId, a, b);
|
|
2823
|
+
} else {
|
|
2824
|
+
await replaceSeparationForReferences(
|
|
2825
|
+
rawTarget,
|
|
2826
|
+
ctx.schema,
|
|
2827
|
+
ctx.graphId,
|
|
2828
|
+
[a, b]
|
|
2829
|
+
);
|
|
2830
|
+
}
|
|
2831
|
+
} catch (error) {
|
|
2832
|
+
rethrowTaggedWithAssertion(error, assertion.id, { created, skipped });
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
return { created, skipped };
|
|
2837
|
+
}
|
|
2838
|
+
async function applyIdentityChangesForContext(ctx, retractionIds, assertions) {
|
|
2839
|
+
if (retractionIds.length === 0 && assertions.length === 0) {
|
|
2840
|
+
return { created: 0, retracted: 0 };
|
|
2841
|
+
}
|
|
2842
|
+
return runIdentityMutation(ctx, async (target, touch, markWritten) => {
|
|
2843
|
+
const retracted = await retractByIds(ctx, target, retractionIds, touch);
|
|
2844
|
+
const { closureReferences, separationReferences } = partitionRetractedEndpoints(retracted);
|
|
2845
|
+
if (closureReferences.length > 0) {
|
|
2846
|
+
await replaceAffectedClosure(
|
|
2847
|
+
target,
|
|
2848
|
+
ctx.schema,
|
|
2849
|
+
ctx.graphId,
|
|
2850
|
+
closureReferences,
|
|
2851
|
+
ctx.sameIdAcrossKinds
|
|
2852
|
+
);
|
|
2853
|
+
}
|
|
2854
|
+
await replaceSeparationForReferences(
|
|
2855
|
+
target,
|
|
2856
|
+
ctx.schema,
|
|
2857
|
+
ctx.graphId,
|
|
2858
|
+
separationReferences
|
|
2859
|
+
);
|
|
2860
|
+
const summary = await importIdentityAssertionsIntoTarget(
|
|
2861
|
+
ctx,
|
|
2862
|
+
target,
|
|
2863
|
+
assertions,
|
|
2864
|
+
"state"
|
|
2865
|
+
);
|
|
2866
|
+
if (summary.created > 0) markWritten();
|
|
2867
|
+
return { created: summary.created, retracted: retracted.length };
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
// src/identity/service-maintenance.ts
|
|
2872
|
+
function requireAtomicIdentityBackend(backend, graphId) {
|
|
2873
|
+
if (!backend.capabilities.transactions) {
|
|
2874
|
+
throw new chunkNI72YOJB_cjs.ConfigurationError(
|
|
2875
|
+
"Operational Identity requires atomic transaction support.",
|
|
2876
|
+
{ code: "IDENTITY_REQUIRES_ATOMIC_BACKEND", graphId }
|
|
2877
|
+
);
|
|
2878
|
+
}
|
|
2879
|
+
}
|
|
2880
|
+
async function runOnTransactionIfSupported(backend, fn) {
|
|
2881
|
+
if ("transaction" in backend) {
|
|
2882
|
+
await backend.transaction(async (target) => fn(target));
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2885
|
+
await fn(backend);
|
|
2886
|
+
}
|
|
2887
|
+
async function rebuildIdentityClosureForContext(ctx) {
|
|
2888
|
+
requireAtomicIdentityBackend(ctx.backend, ctx.graphId);
|
|
2889
|
+
async function rebuildAtTarget(target) {
|
|
2890
|
+
await lockIdentityGraph(target, ctx.graphId);
|
|
2891
|
+
await chunkXMQSEJCF_cjs.withRecordedIdentityMutationTarget(target, async (rawTarget) => {
|
|
2892
|
+
const activeKinds = identityActiveKinds(ctx.registry);
|
|
2893
|
+
const snapshot = await loadSnapshot(
|
|
2894
|
+
rawTarget,
|
|
2895
|
+
ctx.schema,
|
|
2896
|
+
ctx.graphId,
|
|
2897
|
+
void 0,
|
|
2898
|
+
activeKinds,
|
|
2899
|
+
ctx.sameIdAcrossKinds
|
|
2900
|
+
);
|
|
2901
|
+
validateSnapshotIntegrity(snapshot, ctx.registry, ctx.graphId);
|
|
2902
|
+
await replaceClosure(
|
|
2903
|
+
rawTarget,
|
|
2904
|
+
ctx.schema,
|
|
2905
|
+
ctx.graphId,
|
|
2906
|
+
activeKinds,
|
|
2907
|
+
ctx.sameIdAcrossKinds
|
|
2908
|
+
);
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
await runOnTransactionIfSupported(
|
|
2912
|
+
ctx.backend,
|
|
2913
|
+
async (target) => rebuildAtTarget(target)
|
|
2914
|
+
);
|
|
2915
|
+
}
|
|
2916
|
+
async function validateIdentityForContext(ctx) {
|
|
2917
|
+
requireAtomicIdentityBackend(ctx.backend, ctx.graphId);
|
|
2918
|
+
async function validateAtTarget(target) {
|
|
2919
|
+
await lockIdentityGraph(target, ctx.graphId);
|
|
2920
|
+
const activeKinds = identityActiveKinds(ctx.registry);
|
|
2921
|
+
const snapshot = await loadSnapshot(
|
|
2922
|
+
target,
|
|
2923
|
+
ctx.schema,
|
|
2924
|
+
ctx.graphId,
|
|
2925
|
+
void 0,
|
|
2926
|
+
activeKinds,
|
|
2927
|
+
ctx.sameIdAcrossKinds
|
|
2928
|
+
);
|
|
2929
|
+
validateSnapshotIntegrity(snapshot, ctx.registry, ctx.graphId);
|
|
2930
|
+
await assertClosureMatchesComponents(
|
|
2931
|
+
target,
|
|
2932
|
+
ctx.schema,
|
|
2933
|
+
ctx.graphId,
|
|
2934
|
+
snapshot.components
|
|
2935
|
+
);
|
|
2936
|
+
assertSeparationMatchesProjection(
|
|
2937
|
+
ctx.graphId,
|
|
2938
|
+
await readSeparationForGraph(target, ctx.schema, ctx.graphId),
|
|
2939
|
+
buildSeparationProjection(
|
|
2940
|
+
snapshot.assertions,
|
|
2941
|
+
(ref) => snapshotClassKey(snapshot, ref)
|
|
2942
|
+
)
|
|
2943
|
+
);
|
|
2944
|
+
}
|
|
2945
|
+
await runOnTransactionIfSupported(
|
|
2946
|
+
ctx.backend,
|
|
2947
|
+
async (target) => validateAtTarget(target)
|
|
2948
|
+
);
|
|
2949
|
+
}
|
|
2950
|
+
async function loadAffectedIdentityClasses(ctx, target, seeds) {
|
|
2951
|
+
const classes = await loadCurrentStructuralClasses(
|
|
2952
|
+
target,
|
|
2953
|
+
ctx.schema,
|
|
2954
|
+
ctx.graphId,
|
|
2955
|
+
seeds
|
|
2956
|
+
);
|
|
2957
|
+
const byClassKey = /* @__PURE__ */ new Map();
|
|
2958
|
+
const classKeyByMember = /* @__PURE__ */ new Map();
|
|
2959
|
+
const members = /* @__PURE__ */ new Map();
|
|
2960
|
+
for (const classMembers of classes.values()) {
|
|
2961
|
+
const classKey = refKey(chunkN66HCGCY_cjs.requireDefined(classMembers[0]));
|
|
2962
|
+
byClassKey.set(classKey, classMembers);
|
|
2963
|
+
for (const member of classMembers) {
|
|
2964
|
+
const memberKey = refKey(member);
|
|
2965
|
+
classKeyByMember.set(memberKey, classKey);
|
|
2966
|
+
members.set(memberKey, member);
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
return { byClassKey, classKeyByMember, members: [...members.values()] };
|
|
2970
|
+
}
|
|
2971
|
+
function firstMemberOfKind(members, kind) {
|
|
2972
|
+
return chunkN66HCGCY_cjs.requireDefined(
|
|
2973
|
+
members.find((member) => member.kind === kind),
|
|
2974
|
+
`Identity class carries no ${kind} member`
|
|
2975
|
+
);
|
|
2976
|
+
}
|
|
2977
|
+
async function findAffectedClassInconsistency(ctx, target, seeds) {
|
|
2978
|
+
const classes = await loadAffectedIdentityClasses(ctx, target, seeds);
|
|
2979
|
+
for (const members of classes.byClassKey.values()) {
|
|
2980
|
+
const conflictingKinds = classHasDisjointKinds(
|
|
2981
|
+
ctx.registry,
|
|
2982
|
+
members,
|
|
2983
|
+
members
|
|
2984
|
+
);
|
|
2985
|
+
if (conflictingKinds === void 0) continue;
|
|
2986
|
+
const [leftKind, rightKind] = conflictingKinds;
|
|
2987
|
+
return {
|
|
2988
|
+
kind: "contradiction",
|
|
2989
|
+
error: new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
2990
|
+
operation: "merge",
|
|
2991
|
+
a: firstMemberOfKind(members, leftKind),
|
|
2992
|
+
b: firstMemberOfKind(members, rightKind),
|
|
2993
|
+
reason: "disjoint-kinds",
|
|
2994
|
+
conflictingKinds
|
|
2995
|
+
})
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
const assertions = await loadAssertionsTouching(
|
|
2999
|
+
target,
|
|
3000
|
+
ctx.schema,
|
|
3001
|
+
ctx.graphId,
|
|
3002
|
+
classes.members,
|
|
3003
|
+
void 0
|
|
3004
|
+
);
|
|
3005
|
+
const unmerged = [];
|
|
3006
|
+
for (const assertion of assertions) {
|
|
3007
|
+
const a = { kind: assertion.a_kind, id: assertion.a_id };
|
|
3008
|
+
const b = { kind: assertion.b_kind, id: assertion.b_id };
|
|
3009
|
+
const aClassKey = classes.classKeyByMember.get(refKey(a));
|
|
3010
|
+
const bClassKey = classes.classKeyByMember.get(refKey(b));
|
|
3011
|
+
if (assertion.rel === "different") {
|
|
3012
|
+
if (aClassKey === void 0 || aClassKey !== bClassKey) continue;
|
|
3013
|
+
return {
|
|
3014
|
+
kind: "contradiction",
|
|
3015
|
+
error: new chunkNI72YOJB_cjs.IdentityContradictionError({
|
|
3016
|
+
operation: "merge",
|
|
3017
|
+
a,
|
|
3018
|
+
b,
|
|
3019
|
+
reason: "same-class",
|
|
3020
|
+
conflictingAssertionId: assertion.id
|
|
3021
|
+
})
|
|
3022
|
+
};
|
|
3023
|
+
}
|
|
3024
|
+
if (aClassKey !== void 0 && bClassKey !== void 0) {
|
|
3025
|
+
if (aClassKey === bClassKey) continue;
|
|
3026
|
+
return {
|
|
3027
|
+
kind: "stale-closure",
|
|
3028
|
+
detail: { assertionId: assertion.id, a, b }
|
|
3029
|
+
};
|
|
3030
|
+
}
|
|
3031
|
+
unmerged.push({
|
|
3032
|
+
assertionId: assertion.id,
|
|
3033
|
+
a,
|
|
3034
|
+
b,
|
|
3035
|
+
outside: aClassKey === void 0 ? a : b
|
|
3036
|
+
});
|
|
3037
|
+
}
|
|
3038
|
+
if (unmerged.length > 0) {
|
|
3039
|
+
const liveOutside = await loadLiveReferences(
|
|
3040
|
+
target,
|
|
3041
|
+
ctx.schema,
|
|
3042
|
+
ctx.graphId,
|
|
3043
|
+
unmerged.map((row) => row.outside)
|
|
3044
|
+
);
|
|
3045
|
+
const liveKeys = new Set(liveOutside.map((ref) => refKey(ref)));
|
|
3046
|
+
const lagging = unmerged.find((row) => liveKeys.has(refKey(row.outside)));
|
|
3047
|
+
if (lagging !== void 0) {
|
|
3048
|
+
return {
|
|
3049
|
+
kind: "stale-closure",
|
|
3050
|
+
detail: {
|
|
3051
|
+
assertionId: lagging.assertionId,
|
|
3052
|
+
a: lagging.a,
|
|
3053
|
+
b: lagging.b
|
|
3054
|
+
}
|
|
3055
|
+
};
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
if (ctx.sameIdAcrossKinds !== "fold") return void 0;
|
|
3059
|
+
const liveKindsById = await liveNodeKindsSharingIds(
|
|
3060
|
+
ctx,
|
|
3061
|
+
target,
|
|
3062
|
+
classes.members.map((member) => member.id)
|
|
3063
|
+
);
|
|
3064
|
+
for (const [id, kinds] of liveKindsById) {
|
|
3065
|
+
const classKeys = /* @__PURE__ */ new Set();
|
|
3066
|
+
for (const kind of kinds) {
|
|
3067
|
+
classKeys.add(classes.classKeyByMember.get(refKey({ kind, id })));
|
|
3068
|
+
}
|
|
3069
|
+
if (classKeys.size > 1) {
|
|
3070
|
+
return {
|
|
3071
|
+
kind: "stale-closure",
|
|
3072
|
+
detail: { sharedId: id, kinds: [...kinds] }
|
|
3073
|
+
};
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
return void 0;
|
|
3077
|
+
}
|
|
3078
|
+
async function assertAffectedIdentityClassesConsistent(ctx, target, seeds) {
|
|
3079
|
+
if (seeds.length === 0) return;
|
|
3080
|
+
await lockIdentityGraph(target, ctx.graphId);
|
|
3081
|
+
const observed = await findAffectedClassInconsistency(ctx, target, seeds);
|
|
3082
|
+
if (observed === void 0) return;
|
|
3083
|
+
await chunkXMQSEJCF_cjs.withRecordedIdentityMutationTarget(target, async (rawTarget) => {
|
|
3084
|
+
await replaceClosure(
|
|
3085
|
+
rawTarget,
|
|
3086
|
+
ctx.schema,
|
|
3087
|
+
ctx.graphId,
|
|
3088
|
+
identityActiveKinds(ctx.registry),
|
|
3089
|
+
ctx.sameIdAcrossKinds
|
|
3090
|
+
);
|
|
3091
|
+
});
|
|
3092
|
+
const rebuilt = await findAffectedClassInconsistency(ctx, target, seeds);
|
|
3093
|
+
if (rebuilt === void 0) return;
|
|
3094
|
+
if (rebuilt.kind === "contradiction") throw rebuilt.error;
|
|
3095
|
+
throw closureMismatchError(ctx.graphId, rebuilt.detail);
|
|
3096
|
+
}
|
|
3097
|
+
async function deleteAssertionsTouchingKinds(target, schema, graphId, kinds, touch) {
|
|
3098
|
+
const removedKinds = [...new Set(kinds)];
|
|
3099
|
+
if (removedKinds.length === 0) return;
|
|
3100
|
+
const matched = /* @__PURE__ */ new Map();
|
|
3101
|
+
const kindChunkSize = identityChunkSize(target, {
|
|
3102
|
+
fixedParameters: 1,
|
|
3103
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
3104
|
+
parametersPerItem: 2
|
|
3105
|
+
});
|
|
3106
|
+
for (const kindChunk of chunkBSFJMMV3_cjs.chunk(removedKinds, kindChunkSize)) {
|
|
3107
|
+
const kindList2 = chunkVCRRKBLN_cjs.sql.join(
|
|
3108
|
+
kindChunk.map((kind) => chunkVCRRKBLN_cjs.sql`${kind}`),
|
|
3109
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
3110
|
+
);
|
|
3111
|
+
const rows = await target.execute(
|
|
3112
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3113
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
3114
|
+
FROM ${schema.identityAssertionsTable}
|
|
3115
|
+
WHERE graph_id = ${graphId}
|
|
3116
|
+
AND (a_kind IN (${kindList2}) OR b_kind IN (${kindList2}))
|
|
3117
|
+
`)
|
|
3118
|
+
);
|
|
3119
|
+
for (const rawRow of rows) {
|
|
3120
|
+
matched.set(rawRow.id, normalizeIdentityAssertionRow(rawRow));
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
const ids = [...matched.keys()];
|
|
3124
|
+
if (ids.length > 0) {
|
|
3125
|
+
const idChunkSize = identityChunkSize(target, {
|
|
3126
|
+
fixedParameters: 1,
|
|
3127
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
3128
|
+
parametersPerItem: 1
|
|
3129
|
+
});
|
|
3130
|
+
for (const idChunk of chunkBSFJMMV3_cjs.chunk(ids, idChunkSize)) {
|
|
3131
|
+
const idList = chunkVCRRKBLN_cjs.sql.join(
|
|
3132
|
+
idChunk.map((id) => chunkVCRRKBLN_cjs.sql`${id}`),
|
|
3133
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
3134
|
+
);
|
|
3135
|
+
await executeIdentityStatement(
|
|
3136
|
+
target,
|
|
3137
|
+
chunkVCRRKBLN_cjs.sql`
|
|
3138
|
+
DELETE FROM ${schema.identityAssertionsTable}
|
|
3139
|
+
WHERE graph_id = ${graphId} AND id IN (${idList})
|
|
3140
|
+
`
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
for (const row of matched.values()) touch(graphId, row.id);
|
|
3145
|
+
}
|
|
3146
|
+
async function hasAssertionsTouchingKinds(target, schema, graphId, kinds) {
|
|
3147
|
+
const probedKinds = [...new Set(kinds)];
|
|
3148
|
+
if (probedKinds.length === 0) return false;
|
|
3149
|
+
const kindChunkSize = identityChunkSize(target, {
|
|
3150
|
+
fixedParameters: 1,
|
|
3151
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
3152
|
+
parametersPerItem: 2
|
|
3153
|
+
});
|
|
3154
|
+
for (const kindChunk of chunkBSFJMMV3_cjs.chunk(probedKinds, kindChunkSize)) {
|
|
3155
|
+
const kindList2 = chunkVCRRKBLN_cjs.sql.join(
|
|
3156
|
+
kindChunk.map((kind) => chunkVCRRKBLN_cjs.sql`${kind}`),
|
|
3157
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
3158
|
+
);
|
|
3159
|
+
const rows = await target.execute(
|
|
3160
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3161
|
+
SELECT id
|
|
3162
|
+
FROM ${schema.identityAssertionsTable}
|
|
3163
|
+
WHERE graph_id = ${graphId}
|
|
3164
|
+
AND (a_kind IN (${kindList2}) OR b_kind IN (${kindList2}))
|
|
3165
|
+
LIMIT 1
|
|
3166
|
+
`)
|
|
3167
|
+
);
|
|
3168
|
+
if (rows.length > 0) return true;
|
|
3169
|
+
}
|
|
3170
|
+
return false;
|
|
3171
|
+
}
|
|
3172
|
+
async function purgeAssertionsWithUnregisteredKinds(target, schema, graphId, registeredKinds, touch) {
|
|
3173
|
+
const pairs = await target.execute(
|
|
3174
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3175
|
+
SELECT DISTINCT a_kind, b_kind
|
|
3176
|
+
FROM ${schema.identityAssertionsTable}
|
|
3177
|
+
WHERE graph_id = ${graphId}
|
|
3178
|
+
`)
|
|
3179
|
+
);
|
|
3180
|
+
const unregistered = /* @__PURE__ */ new Set();
|
|
3181
|
+
for (const pair of pairs) {
|
|
3182
|
+
if (!registeredKinds.has(pair.a_kind)) unregistered.add(pair.a_kind);
|
|
3183
|
+
if (!registeredKinds.has(pair.b_kind)) unregistered.add(pair.b_kind);
|
|
3184
|
+
}
|
|
3185
|
+
if (unregistered.size === 0) return;
|
|
3186
|
+
await deleteAssertionsTouchingKinds(
|
|
3187
|
+
target,
|
|
3188
|
+
schema,
|
|
3189
|
+
graphId,
|
|
3190
|
+
[...unregistered],
|
|
3191
|
+
touch
|
|
3192
|
+
);
|
|
3193
|
+
}
|
|
3194
|
+
async function removeIdentityKindsForContext(ctx, kinds, options) {
|
|
3195
|
+
if (kinds.length === 0) return;
|
|
3196
|
+
const removedKinds = [...new Set(kinds)];
|
|
3197
|
+
await runIdentityMutation(ctx, async (target, touch) => {
|
|
3198
|
+
await deleteAssertionsTouchingKinds(
|
|
3199
|
+
target,
|
|
3200
|
+
ctx.schema,
|
|
3201
|
+
ctx.graphId,
|
|
3202
|
+
removedKinds,
|
|
3203
|
+
touch
|
|
3204
|
+
);
|
|
3205
|
+
if (options?.repairClosure === false) return;
|
|
3206
|
+
await replaceClosure(
|
|
3207
|
+
target,
|
|
3208
|
+
ctx.schema,
|
|
3209
|
+
ctx.graphId,
|
|
3210
|
+
identityActiveKinds(ctx.registry),
|
|
3211
|
+
ctx.sameIdAcrossKinds
|
|
3212
|
+
);
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
async function liveNodeKindsSharingIds(ctx, target, ids) {
|
|
3216
|
+
const uniqueIds = [...new Set(ids)];
|
|
3217
|
+
const liveKindsById = /* @__PURE__ */ new Map();
|
|
3218
|
+
if (uniqueIds.length === 0) return liveKindsById;
|
|
3219
|
+
const chunkSize = identityChunkSize(target, {
|
|
3220
|
+
fixedParameters: 1,
|
|
3221
|
+
maxItems: MAX_REFERENCE_CHUNK_SIZE,
|
|
3222
|
+
parametersPerItem: 1
|
|
3223
|
+
});
|
|
3224
|
+
for (const idChunk of chunkBSFJMMV3_cjs.chunk(uniqueIds, chunkSize)) {
|
|
3225
|
+
const idList = chunkVCRRKBLN_cjs.sql.join(
|
|
3226
|
+
idChunk.map((id) => chunkVCRRKBLN_cjs.sql`${id}`),
|
|
3227
|
+
chunkVCRRKBLN_cjs.sql`, `
|
|
3228
|
+
);
|
|
3229
|
+
const rows = await target.execute(
|
|
3230
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3231
|
+
SELECT kind, id
|
|
3232
|
+
FROM ${ctx.schema.nodesTable}
|
|
3233
|
+
WHERE graph_id = ${ctx.graphId}
|
|
3234
|
+
AND id IN (${idList})
|
|
3235
|
+
AND deleted_at IS NULL
|
|
3236
|
+
`)
|
|
3237
|
+
);
|
|
3238
|
+
for (const row of rows) {
|
|
3239
|
+
if (!ctx.registry.nodeKinds.has(row.kind)) continue;
|
|
3240
|
+
const kinds = liveKindsById.get(row.id) ?? /* @__PURE__ */ new Set();
|
|
3241
|
+
kinds.add(row.kind);
|
|
3242
|
+
liveKindsById.set(row.id, kinds);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
return liveKindsById;
|
|
3246
|
+
}
|
|
3247
|
+
async function foldIdentityForCreatedNodes(ctx, target, references) {
|
|
3248
|
+
if (references.length === 0 || ctx.sameIdAcrossKinds === "ignore") return;
|
|
3249
|
+
await lockIdentityGraph(target, ctx.graphId);
|
|
3250
|
+
await chunkXMQSEJCF_cjs.withRecordedIdentityMutationTarget(target, async (rawTarget) => {
|
|
3251
|
+
const liveKindsById = await liveNodeKindsSharingIds(
|
|
3252
|
+
ctx,
|
|
3253
|
+
rawTarget,
|
|
3254
|
+
references.map((ref) => ref.id)
|
|
3255
|
+
);
|
|
3256
|
+
const closureReferences = [];
|
|
3257
|
+
for (const ref of references) {
|
|
3258
|
+
const liveKinds = liveKindsById.get(ref.id);
|
|
3259
|
+
const peers = [];
|
|
3260
|
+
if (liveKinds !== void 0) {
|
|
3261
|
+
for (const kind of ctx.registry.nodeKinds.keys()) {
|
|
3262
|
+
if (kind === ref.kind || !liveKinds.has(kind)) continue;
|
|
3263
|
+
peers.push({ kind, id: ref.id });
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
if (peers.length === 0) continue;
|
|
3267
|
+
for (const peer of peers) {
|
|
3268
|
+
await validateCurrentRelation(
|
|
3269
|
+
ctx,
|
|
3270
|
+
rawTarget,
|
|
3271
|
+
"same",
|
|
3272
|
+
"fold",
|
|
3273
|
+
ref,
|
|
3274
|
+
peer
|
|
3275
|
+
);
|
|
3276
|
+
}
|
|
3277
|
+
closureReferences.push(ref, ...peers);
|
|
3278
|
+
}
|
|
3279
|
+
await replaceAffectedClosure(
|
|
3280
|
+
rawTarget,
|
|
3281
|
+
ctx.schema,
|
|
3282
|
+
ctx.graphId,
|
|
3283
|
+
closureReferences,
|
|
3284
|
+
ctx.sameIdAcrossKinds
|
|
3285
|
+
);
|
|
3286
|
+
});
|
|
3287
|
+
}
|
|
3288
|
+
async function hasMaterializedIdentityClass(target, schema, graphId, ref) {
|
|
3289
|
+
const rows = await target.execute(
|
|
3290
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3291
|
+
SELECT member_kind, member_id
|
|
3292
|
+
FROM ${schema.identityClosureTable}
|
|
3293
|
+
WHERE graph_id = ${graphId}
|
|
3294
|
+
AND member_kind = ${ref.kind}
|
|
3295
|
+
AND member_id = ${ref.id}
|
|
3296
|
+
LIMIT 1
|
|
3297
|
+
`)
|
|
3298
|
+
);
|
|
3299
|
+
return rows.length > 0;
|
|
3300
|
+
}
|
|
3301
|
+
async function readNodeDeletionInstant(target, schema, graphId, ref) {
|
|
3302
|
+
const rows = await target.execute(
|
|
3303
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3304
|
+
SELECT deleted_at
|
|
3305
|
+
FROM ${schema.nodesTable}
|
|
3306
|
+
WHERE graph_id = ${graphId}
|
|
3307
|
+
AND kind = ${ref.kind}
|
|
3308
|
+
AND id = ${ref.id}
|
|
3309
|
+
LIMIT 1
|
|
3310
|
+
`)
|
|
3311
|
+
);
|
|
3312
|
+
const row = rows.at(0);
|
|
3313
|
+
return row === void 0 ? void 0 : optionalIdentityTimestamp(row.deleted_at);
|
|
3314
|
+
}
|
|
3315
|
+
async function detachIdentityForNode(ctx, target, ref, mode) {
|
|
3316
|
+
await lockIdentityGraph(target, ctx.graphId);
|
|
3317
|
+
await chunkXMQSEJCF_cjs.withRecordedIdentityMutationTarget(target, async (rawTarget, touch) => {
|
|
3318
|
+
const touchesNode = chunkVCRRKBLN_cjs.sql`
|
|
3319
|
+
(
|
|
3320
|
+
(a_kind = ${ref.kind} AND a_id = ${ref.id})
|
|
3321
|
+
OR (b_kind = ${ref.kind} AND b_id = ${ref.id})
|
|
3322
|
+
)
|
|
3323
|
+
`;
|
|
3324
|
+
const scope = mode === "hard" ? chunkVCRRKBLN_cjs.sql`` : chunkVCRRKBLN_cjs.sql`AND valid_to IS NULL AND deleted_at IS NULL`;
|
|
3325
|
+
const rows = await rawTarget.execute(
|
|
3326
|
+
chunkVCRRKBLN_cjs.asCompiledRowsSql(chunkVCRRKBLN_cjs.sql`
|
|
3327
|
+
SELECT ${chunkXMQSEJCF_cjs.IDENTITY_ASSERTION_COLUMNS}
|
|
3328
|
+
FROM ${ctx.schema.identityAssertionsTable}
|
|
3329
|
+
WHERE graph_id = ${ctx.graphId}
|
|
3330
|
+
${scope}
|
|
3331
|
+
AND ${touchesNode}
|
|
3332
|
+
`)
|
|
3333
|
+
);
|
|
3334
|
+
if (rows.length === 0 && !await hasMaterializedIdentityClass(
|
|
3335
|
+
rawTarget,
|
|
3336
|
+
ctx.schema,
|
|
3337
|
+
ctx.graphId,
|
|
3338
|
+
ref
|
|
3339
|
+
)) {
|
|
3340
|
+
return;
|
|
3341
|
+
}
|
|
3342
|
+
const now = chunkQ7Q4WSLJ_cjs.nowIso();
|
|
3343
|
+
const cascadeInstant = mode === "hard" || rows.length === 0 ? now : await readNodeDeletionInstant(
|
|
3344
|
+
rawTarget,
|
|
3345
|
+
ctx.schema,
|
|
3346
|
+
ctx.graphId,
|
|
3347
|
+
ref
|
|
3348
|
+
) ?? now;
|
|
3349
|
+
for (const rawRow of rows) {
|
|
3350
|
+
const row = normalizeIdentityAssertionRow(rawRow);
|
|
3351
|
+
if (mode === "hard") {
|
|
3352
|
+
await executeIdentityStatement(
|
|
3353
|
+
rawTarget,
|
|
3354
|
+
chunkVCRRKBLN_cjs.sql`
|
|
3355
|
+
DELETE FROM ${ctx.schema.identityAssertionsTable}
|
|
3356
|
+
WHERE graph_id = ${ctx.graphId} AND id = ${row.id}
|
|
3357
|
+
`
|
|
3358
|
+
);
|
|
3359
|
+
touch(ctx.graphId, row.id);
|
|
3360
|
+
} else {
|
|
3361
|
+
const validTo = clampValidTo(cascadeInstant, row.valid_from);
|
|
3362
|
+
const ended = {
|
|
3363
|
+
...row,
|
|
3364
|
+
valid_to: validTo,
|
|
3365
|
+
updated_at: now,
|
|
3366
|
+
ended_by_kind: ref.kind,
|
|
3367
|
+
ended_by_id: ref.id
|
|
3368
|
+
};
|
|
3369
|
+
await executeIdentityStatement(
|
|
3370
|
+
rawTarget,
|
|
3371
|
+
chunkVCRRKBLN_cjs.sql`
|
|
3372
|
+
UPDATE ${ctx.schema.identityAssertionsTable}
|
|
3373
|
+
SET valid_to = ${validTo},
|
|
3374
|
+
updated_at = ${now},
|
|
3375
|
+
ended_by_kind = ${ref.kind},
|
|
3376
|
+
ended_by_id = ${ref.id}
|
|
3377
|
+
WHERE graph_id = ${ctx.graphId} AND id = ${row.id}
|
|
3378
|
+
`
|
|
3379
|
+
);
|
|
3380
|
+
touch(ctx.graphId, row.id, ended);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
await replaceAffectedClosure(
|
|
3384
|
+
rawTarget,
|
|
3385
|
+
ctx.schema,
|
|
3386
|
+
ctx.graphId,
|
|
3387
|
+
[ref],
|
|
3388
|
+
ctx.sameIdAcrossKinds
|
|
3389
|
+
);
|
|
3390
|
+
});
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
exports.IDENTITY_IMPORT_FAILED_ASSERTION = IDENTITY_IMPORT_FAILED_ASSERTION;
|
|
3394
|
+
exports.IDENTITY_IMPORT_PROGRESS = IDENTITY_IMPORT_PROGRESS;
|
|
3395
|
+
exports.applyIdentityChangesForContext = applyIdentityChangesForContext;
|
|
3396
|
+
exports.assertAffectedIdentityClassesConsistent = assertAffectedIdentityClassesConsistent;
|
|
3397
|
+
exports.createIdentityFacade = createIdentityFacade;
|
|
3398
|
+
exports.createIdentityReadFacade = createIdentityReadFacade;
|
|
3399
|
+
exports.createValidationError = createValidationError;
|
|
3400
|
+
exports.deleteAssertionsTouchingKinds = deleteAssertionsTouchingKinds;
|
|
3401
|
+
exports.detachIdentityForNode = detachIdentityForNode;
|
|
3402
|
+
exports.encodeTupleKey = encodeTupleKey;
|
|
3403
|
+
exports.foldIdentityForCreatedNodes = foldIdentityForCreatedNodes;
|
|
3404
|
+
exports.hasAssertionsTouchingKinds = hasAssertionsTouchingKinds;
|
|
3405
|
+
exports.identityAssertionSemanticKey = identityAssertionSemanticKey;
|
|
3406
|
+
exports.identityReferenceKey = identityReferenceKey;
|
|
3407
|
+
exports.importIdentityAssertionsIntoTarget = importIdentityAssertionsIntoTarget;
|
|
3408
|
+
exports.liveNodeKindsSharingIds = liveNodeKindsSharingIds;
|
|
3409
|
+
exports.loadAssertionsByIds = loadAssertionsByIds;
|
|
3410
|
+
exports.loadCurrentStructuralClasses = loadCurrentStructuralClasses;
|
|
3411
|
+
exports.lockIdentityEnablementNodes = lockIdentityEnablementNodes;
|
|
3412
|
+
exports.lockIdentityGraph = lockIdentityGraph;
|
|
3413
|
+
exports.lockSchemaVersionForStoreWrite = lockSchemaVersionForStoreWrite;
|
|
3414
|
+
exports.normalizeIdentityPair = normalizeIdentityPair;
|
|
3415
|
+
exports.purgeAssertionsWithUnregisteredKinds = purgeAssertionsWithUnregisteredKinds;
|
|
3416
|
+
exports.readIdentityAssertionPageAtTarget = readIdentityAssertionPageAtTarget;
|
|
3417
|
+
exports.readIdentityAssertionsForInterchange = readIdentityAssertionsForInterchange;
|
|
3418
|
+
exports.rebuildIdentityClosureForContext = rebuildIdentityClosureForContext;
|
|
3419
|
+
exports.refKey = refKey;
|
|
3420
|
+
exports.removeIdentityKindsForContext = removeIdentityKindsForContext;
|
|
3421
|
+
exports.runHookedWriteOperation = runHookedWriteOperation;
|
|
3422
|
+
exports.runInWriteTransaction = runInWriteTransaction;
|
|
3423
|
+
exports.separationRebuildRequired = separationRebuildRequired;
|
|
3424
|
+
exports.toTransferAssertion = toTransferAssertion;
|
|
3425
|
+
exports.validateEdgeProps = validateEdgeProps;
|
|
3426
|
+
exports.validateIdentityForContext = validateIdentityForContext;
|
|
3427
|
+
exports.validateNodeProps = validateNodeProps;
|
|
3428
|
+
exports.validateProps = validateProps;
|
|
3429
|
+
exports.withWriteTransactionSession = withWriteTransactionSession;
|
|
3430
|
+
exports.wrapZodError = wrapZodError;
|
|
3431
|
+
//# sourceMappingURL=chunk-XNLIZYRZ.cjs.map
|
|
3432
|
+
//# sourceMappingURL=chunk-XNLIZYRZ.cjs.map
|