@nicia-ai/typegraph 0.46.2 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/README.md +20 -1
  2. package/dist/backend/drizzle/indexes.cjs +9 -9
  3. package/dist/backend/drizzle/indexes.d.cts +1 -1
  4. package/dist/backend/drizzle/indexes.d.ts +1 -1
  5. package/dist/backend/drizzle/indexes.js +5 -5
  6. package/dist/backend/index.cjs +58 -49
  7. package/dist/backend/index.d.cts +37 -55
  8. package/dist/backend/index.d.ts +37 -55
  9. package/dist/backend/index.js +11 -10
  10. package/dist/backend/postgres/index.cjs +27 -26
  11. package/dist/backend/postgres/index.d.cts +21 -7
  12. package/dist/backend/postgres/index.d.ts +21 -7
  13. package/dist/backend/postgres/index.js +14 -13
  14. package/dist/backend/postgres/pglite-store.cjs +34 -33
  15. package/dist/backend/postgres/pglite-store.cjs.map +1 -1
  16. package/dist/backend/postgres/pglite-store.d.cts +8 -8
  17. package/dist/backend/postgres/pglite-store.d.ts +8 -8
  18. package/dist/backend/postgres/pglite-store.js +30 -29
  19. package/dist/backend/postgres/pglite-store.js.map +1 -1
  20. package/dist/backend/postgres/pglite.cjs +16 -15
  21. package/dist/backend/postgres/pglite.d.cts +3 -3
  22. package/dist/backend/postgres/pglite.d.ts +3 -3
  23. package/dist/backend/postgres/pglite.js +15 -14
  24. package/dist/backend/sqlite/index.cjs +24 -23
  25. package/dist/backend/sqlite/index.d.cts +20 -7
  26. package/dist/backend/sqlite/index.d.ts +20 -7
  27. package/dist/backend/sqlite/index.js +12 -11
  28. package/dist/backend/sqlite/libsql.cjs +19 -18
  29. package/dist/backend/sqlite/libsql.cjs.map +1 -1
  30. package/dist/backend/sqlite/libsql.d.cts +3 -3
  31. package/dist/backend/sqlite/libsql.d.ts +3 -3
  32. package/dist/backend/sqlite/libsql.js +14 -13
  33. package/dist/backend/sqlite/libsql.js.map +1 -1
  34. package/dist/backend/sqlite/local-store.cjs +35 -34
  35. package/dist/backend/sqlite/local-store.cjs.map +1 -1
  36. package/dist/backend/sqlite/local-store.d.cts +8 -8
  37. package/dist/backend/sqlite/local-store.d.ts +8 -8
  38. package/dist/backend/sqlite/local-store.js +31 -30
  39. package/dist/backend/sqlite/local-store.js.map +1 -1
  40. package/dist/backend/sqlite/local.cjs +17 -16
  41. package/dist/backend/sqlite/local.d.cts +3 -3
  42. package/dist/backend/sqlite/local.d.ts +3 -3
  43. package/dist/backend/sqlite/local.js +15 -14
  44. package/dist/{chunk-TCT66A7N.cjs → chunk-26YKDNUD.cjs} +10 -10
  45. package/dist/{chunk-TCT66A7N.cjs.map → chunk-26YKDNUD.cjs.map} +1 -1
  46. package/dist/{chunk-E4OSGBCM.cjs → chunk-2HIYYMWY.cjs} +139 -136
  47. package/dist/chunk-2HIYYMWY.cjs.map +1 -0
  48. package/dist/chunk-2QGYQBS2.cjs +161 -0
  49. package/dist/chunk-2QGYQBS2.cjs.map +1 -0
  50. package/dist/{chunk-GWXXHOLU.js → chunk-2SYZXD54.js} +21 -18
  51. package/dist/chunk-2SYZXD54.js.map +1 -0
  52. package/dist/{chunk-KA4L2NZ3.js → chunk-2TYSSBU5.js} +14 -14
  53. package/dist/{chunk-KA4L2NZ3.js.map → chunk-2TYSSBU5.js.map} +1 -1
  54. package/dist/{chunk-QOJ2L2AD.js → chunk-3DMMGT6S.js} +3 -3
  55. package/dist/{chunk-QOJ2L2AD.js.map → chunk-3DMMGT6S.js.map} +1 -1
  56. package/dist/{chunk-F36KZDFX.cjs → chunk-3FPR224C.cjs} +91 -91
  57. package/dist/{chunk-F36KZDFX.cjs.map → chunk-3FPR224C.cjs.map} +1 -1
  58. package/dist/{chunk-32UETY6S.cjs → chunk-3KOY4FH3.cjs} +207 -28
  59. package/dist/chunk-3KOY4FH3.cjs.map +1 -0
  60. package/dist/{chunk-QU7QLJA4.cjs → chunk-3U5ABFDW.cjs} +26 -26
  61. package/dist/{chunk-QU7QLJA4.cjs.map → chunk-3U5ABFDW.cjs.map} +1 -1
  62. package/dist/{chunk-RFDEYLIK.js → chunk-4WMMBDS5.js} +7 -7
  63. package/dist/chunk-4WMMBDS5.js.map +1 -0
  64. package/dist/{chunk-R7EWHKID.js → chunk-5K2BKEBD.js} +19 -145
  65. package/dist/chunk-5K2BKEBD.js.map +1 -0
  66. package/dist/chunk-5PRKMB24.cjs +124 -0
  67. package/dist/chunk-5PRKMB24.cjs.map +1 -0
  68. package/dist/chunk-6LN7FIVU.js +107 -0
  69. package/dist/chunk-6LN7FIVU.js.map +1 -0
  70. package/dist/{chunk-D6GCNNMK.cjs → chunk-6NGW27EO.cjs} +10 -10
  71. package/dist/{chunk-D6GCNNMK.cjs.map → chunk-6NGW27EO.cjs.map} +1 -1
  72. package/dist/{chunk-WHS2Y43J.js → chunk-6SWPJEYN.js} +5 -5
  73. package/dist/{chunk-WHS2Y43J.js.map → chunk-6SWPJEYN.js.map} +1 -1
  74. package/dist/{chunk-7TKNK32B.js → chunk-7SQSZN2J.js} +5 -5
  75. package/dist/{chunk-7TKNK32B.js.map → chunk-7SQSZN2J.js.map} +1 -1
  76. package/dist/{chunk-UTVQPZPN.cjs → chunk-7XUYFFR4.cjs} +20 -20
  77. package/dist/chunk-7XUYFFR4.cjs.map +1 -0
  78. package/dist/{chunk-KXSMF6PL.js → chunk-ACGSAMD3.js} +39 -34
  79. package/dist/chunk-ACGSAMD3.js.map +1 -0
  80. package/dist/{chunk-PYKF7UIL.cjs → chunk-AOSSQDVO.cjs} +13 -13
  81. package/dist/{chunk-PYKF7UIL.cjs.map → chunk-AOSSQDVO.cjs.map} +1 -1
  82. package/dist/{chunk-AT3MLMJV.js → chunk-AX6JGVTZ.js} +91 -20
  83. package/dist/chunk-AX6JGVTZ.js.map +1 -0
  84. package/dist/{chunk-WA64ZSCA.cjs → chunk-BFUOME67.cjs} +11 -11
  85. package/dist/{chunk-WA64ZSCA.cjs.map → chunk-BFUOME67.cjs.map} +1 -1
  86. package/dist/{chunk-YQ4JONWE.js → chunk-BRRP76WO.js} +401 -131
  87. package/dist/chunk-BRRP76WO.js.map +1 -0
  88. package/dist/{chunk-FCIZNUW5.js → chunk-CHAOFCHV.js} +3 -3
  89. package/dist/{chunk-FCIZNUW5.js.map → chunk-CHAOFCHV.js.map} +1 -1
  90. package/dist/chunk-CICO5GXD.cjs +12 -0
  91. package/dist/{chunk-73MWKDFK.cjs.map → chunk-CICO5GXD.cjs.map} +1 -1
  92. package/dist/{chunk-S3G5VLSW.js → chunk-CT3ZKTOF.js} +7 -6
  93. package/dist/chunk-CT3ZKTOF.js.map +1 -0
  94. package/dist/{chunk-SXWLLQ3D.js → chunk-D5R42W5D.js} +4 -4
  95. package/dist/{chunk-SXWLLQ3D.js.map → chunk-D5R42W5D.js.map} +1 -1
  96. package/dist/{chunk-BZZI7B43.cjs → chunk-DO7SAMEK.cjs} +47 -47
  97. package/dist/{chunk-BZZI7B43.cjs.map → chunk-DO7SAMEK.cjs.map} +1 -1
  98. package/dist/chunk-DZAICA5J.js +147 -0
  99. package/dist/chunk-DZAICA5J.js.map +1 -0
  100. package/dist/{chunk-2ZWM2RFH.cjs → chunk-EDN4Y4ZG.cjs} +9 -9
  101. package/dist/{chunk-2ZWM2RFH.cjs.map → chunk-EDN4Y4ZG.cjs.map} +1 -1
  102. package/dist/{chunk-A4R3H7RU.cjs → chunk-EZEEWCFJ.cjs} +264 -361
  103. package/dist/chunk-EZEEWCFJ.cjs.map +1 -0
  104. package/dist/{chunk-BEB4OFZF.cjs → chunk-FA2AFWLP.cjs} +51 -59
  105. package/dist/chunk-FA2AFWLP.cjs.map +1 -0
  106. package/dist/{chunk-ZBVZ7HXD.cjs → chunk-FQPEMEWX.cjs} +12 -12
  107. package/dist/{chunk-ZBVZ7HXD.cjs.map → chunk-FQPEMEWX.cjs.map} +1 -1
  108. package/dist/{chunk-LNIWCQR4.js → chunk-GLHXM7C4.js} +3 -3
  109. package/dist/{chunk-LNIWCQR4.js.map → chunk-GLHXM7C4.js.map} +1 -1
  110. package/dist/{chunk-6BD6ZBKT.cjs → chunk-GYEG3ZLZ.cjs} +10 -10
  111. package/dist/{chunk-6BD6ZBKT.cjs.map → chunk-GYEG3ZLZ.cjs.map} +1 -1
  112. package/dist/{chunk-A7NMUYEL.cjs → chunk-HDL2ARHX.cjs} +27 -27
  113. package/dist/{chunk-A7NMUYEL.cjs.map → chunk-HDL2ARHX.cjs.map} +1 -1
  114. package/dist/{chunk-5ZJOB5YS.js → chunk-HEV35TGT.js} +4 -4
  115. package/dist/{chunk-5ZJOB5YS.js.map → chunk-HEV35TGT.js.map} +1 -1
  116. package/dist/{chunk-LHYSY6SE.js → chunk-I4GAZH5Z.js} +186 -9
  117. package/dist/chunk-I4GAZH5Z.js.map +1 -0
  118. package/dist/{chunk-BQM5P2NO.cjs → chunk-JB6T4GLL.cjs} +260 -223
  119. package/dist/chunk-JB6T4GLL.cjs.map +1 -0
  120. package/dist/{chunk-QPOQX2DI.cjs → chunk-JFRT7S3B.cjs} +1026 -369
  121. package/dist/chunk-JFRT7S3B.cjs.map +1 -0
  122. package/dist/{chunk-JCNTKRAK.js → chunk-JONXFAPO.js} +5 -5
  123. package/dist/{chunk-JCNTKRAK.js.map → chunk-JONXFAPO.js.map} +1 -1
  124. package/dist/{chunk-WEJHA7AD.js → chunk-KF6K7TGH.js} +109 -75
  125. package/dist/chunk-KF6K7TGH.js.map +1 -0
  126. package/dist/{chunk-EDJDDY6H.js → chunk-KKBDXCLQ.js} +4 -4
  127. package/dist/{chunk-EDJDDY6H.js.map → chunk-KKBDXCLQ.js.map} +1 -1
  128. package/dist/{chunk-ZHOAZD7Q.cjs → chunk-L3LQNR34.cjs} +161 -161
  129. package/dist/{chunk-ZHOAZD7Q.cjs.map → chunk-L3LQNR34.cjs.map} +1 -1
  130. package/dist/{chunk-AF3TWL5C.cjs → chunk-LRQKXRXO.cjs} +4 -4
  131. package/dist/{chunk-AF3TWL5C.cjs.map → chunk-LRQKXRXO.cjs.map} +1 -1
  132. package/dist/chunk-MKJ4KXL5.cjs +12 -0
  133. package/dist/{chunk-6LAXM4J2.cjs.map → chunk-MKJ4KXL5.cjs.map} +1 -1
  134. package/dist/{chunk-KCH7WQA5.cjs → chunk-MRDBBHIZ.cjs} +48 -2
  135. package/dist/chunk-MRDBBHIZ.cjs.map +1 -0
  136. package/dist/{chunk-FXNHZFZV.js → chunk-MYKHJI2J.js} +3 -3
  137. package/dist/{chunk-FXNHZFZV.js.map → chunk-MYKHJI2J.js.map} +1 -1
  138. package/dist/{chunk-Z43KWLZF.js → chunk-NACVVDWB.js} +213 -12
  139. package/dist/chunk-NACVVDWB.js.map +1 -0
  140. package/dist/{chunk-72WUT4GG.js → chunk-NVY5CJFP.js} +4 -4
  141. package/dist/{chunk-72WUT4GG.js.map → chunk-NVY5CJFP.js.map} +1 -1
  142. package/dist/{chunk-WYFB7BN3.js → chunk-OD4SSY2U.js} +166 -48
  143. package/dist/chunk-OD4SSY2U.js.map +1 -0
  144. package/dist/{chunk-ZIH42CRX.cjs → chunk-OI2GQ25X.cjs} +7 -7
  145. package/dist/{chunk-ZIH42CRX.cjs.map → chunk-OI2GQ25X.cjs.map} +1 -1
  146. package/dist/{chunk-AU3IJNNP.js → chunk-OMZ37BM2.js} +5 -5
  147. package/dist/{chunk-AU3IJNNP.js.map → chunk-OMZ37BM2.js.map} +1 -1
  148. package/dist/{chunk-C4DYN2SD.cjs → chunk-OORXGFL5.cjs} +48 -48
  149. package/dist/{chunk-C4DYN2SD.cjs.map → chunk-OORXGFL5.cjs.map} +1 -1
  150. package/dist/{chunk-HNYLMPQQ.cjs → chunk-OTUPEF2W.cjs} +149 -78
  151. package/dist/chunk-OTUPEF2W.cjs.map +1 -0
  152. package/dist/{chunk-BRN3RGD2.js → chunk-OVI7IXYX.js} +3 -3
  153. package/dist/{chunk-BRN3RGD2.js.map → chunk-OVI7IXYX.js.map} +1 -1
  154. package/dist/{chunk-WMKEGJG4.js → chunk-P6YLZTRE.js} +3 -3
  155. package/dist/{chunk-WMKEGJG4.js.map → chunk-P6YLZTRE.js.map} +1 -1
  156. package/dist/{chunk-C2ZP5YS6.cjs → chunk-PFBRJBUL.cjs} +278 -160
  157. package/dist/chunk-PFBRJBUL.cjs.map +1 -0
  158. package/dist/{chunk-EJSYWAEV.js → chunk-QTD6HX4O.js} +5 -5
  159. package/dist/{chunk-EJSYWAEV.js.map → chunk-QTD6HX4O.js.map} +1 -1
  160. package/dist/{chunk-JL5UEBWT.cjs → chunk-ROR5ZR6A.cjs} +45 -45
  161. package/dist/{chunk-JL5UEBWT.cjs.map → chunk-ROR5ZR6A.cjs.map} +1 -1
  162. package/dist/{chunk-EDHV4CBU.js → chunk-S5TERQVW.js} +37 -134
  163. package/dist/chunk-S5TERQVW.js.map +1 -0
  164. package/dist/{chunk-FSLTU57P.js → chunk-SDBBMD4N.js} +3 -3
  165. package/dist/{chunk-FSLTU57P.js.map → chunk-SDBBMD4N.js.map} +1 -1
  166. package/dist/{chunk-36LIJXWC.js → chunk-SHFBB23Q.js} +4 -4
  167. package/dist/{chunk-36LIJXWC.js.map → chunk-SHFBB23Q.js.map} +1 -1
  168. package/dist/chunk-SIT26LAZ.cjs +614 -0
  169. package/dist/chunk-SIT26LAZ.cjs.map +1 -0
  170. package/dist/{chunk-C6KE2HSQ.cjs → chunk-SR725PWF.cjs} +1662 -1392
  171. package/dist/chunk-SR725PWF.cjs.map +1 -0
  172. package/dist/{chunk-S7WIRFNS.cjs → chunk-TKZXMWQF.cjs} +13 -12
  173. package/dist/chunk-TKZXMWQF.cjs.map +1 -0
  174. package/dist/{chunk-5PDSCELM.cjs → chunk-TQHGE7UC.cjs} +29 -164
  175. package/dist/chunk-TQHGE7UC.cjs.map +1 -0
  176. package/dist/{chunk-XBHRKLZU.cjs → chunk-TUNPBZY3.cjs} +4 -4
  177. package/dist/{chunk-XBHRKLZU.cjs.map → chunk-TUNPBZY3.cjs.map} +1 -1
  178. package/dist/{chunk-KOAI3KIV.cjs → chunk-TZEGUG6D.cjs} +4 -4
  179. package/dist/{chunk-KOAI3KIV.cjs.map → chunk-TZEGUG6D.cjs.map} +1 -1
  180. package/dist/chunk-UGHG7PGX.js +592 -0
  181. package/dist/chunk-UGHG7PGX.js.map +1 -0
  182. package/dist/{chunk-N3QTGPC7.cjs → chunk-UMGZDVOA.cjs} +303 -101
  183. package/dist/chunk-UMGZDVOA.cjs.map +1 -0
  184. package/dist/{chunk-RHDOAQCT.cjs → chunk-WCCATHMB.cjs} +140 -135
  185. package/dist/chunk-WCCATHMB.cjs.map +1 -0
  186. package/dist/{chunk-DYPRZ53S.cjs → chunk-WODMN3Q2.cjs} +27 -27
  187. package/dist/{chunk-DYPRZ53S.cjs.map → chunk-WODMN3Q2.cjs.map} +1 -1
  188. package/dist/{chunk-OZJCH7ZS.js → chunk-XVWOYKIK.js} +3 -3
  189. package/dist/{chunk-OZJCH7ZS.js.map → chunk-XVWOYKIK.js.map} +1 -1
  190. package/dist/{chunk-IHRDX7K6.js → chunk-YIURNGXI.js} +46 -56
  191. package/dist/chunk-YIURNGXI.js.map +1 -0
  192. package/dist/{chunk-GWUWRZXW.js → chunk-YVF2EM7B.js} +3 -3
  193. package/dist/{chunk-GWUWRZXW.js.map → chunk-YVF2EM7B.js.map} +1 -1
  194. package/dist/{chunk-EAMVXR5B.js → chunk-ZDKTPBGV.js} +4 -4
  195. package/dist/{chunk-EAMVXR5B.js.map → chunk-ZDKTPBGV.js.map} +1 -1
  196. package/dist/{chunk-A2LJG5GM.js → chunk-ZFMCDJGB.js} +803 -148
  197. package/dist/chunk-ZFMCDJGB.js.map +1 -0
  198. package/dist/{chunk-62ZXBMSD.js → chunk-ZLONH2UD.js} +46 -3
  199. package/dist/chunk-ZLONH2UD.js.map +1 -0
  200. package/dist/core/index.cjs +28 -27
  201. package/dist/core/index.d.cts +4 -4
  202. package/dist/core/index.d.ts +4 -4
  203. package/dist/core/index.js +8 -7
  204. package/dist/ddl-BL1NZLMY.d.cts +78 -0
  205. package/dist/ddl-D_oW-EVO.d.ts +78 -0
  206. package/dist/graph-extension/index.cjs +20 -20
  207. package/dist/graph-extension/index.d.cts +4 -4
  208. package/dist/graph-extension/index.d.ts +4 -4
  209. package/dist/graph-extension/index.js +4 -4
  210. package/dist/graph-merge/index.cjs +3418 -706
  211. package/dist/graph-merge/index.cjs.map +1 -1
  212. package/dist/graph-merge/index.d.cts +550 -58
  213. package/dist/graph-merge/index.d.ts +550 -58
  214. package/dist/graph-merge/index.js +3191 -497
  215. package/dist/graph-merge/index.js.map +1 -1
  216. package/dist/{index-Deyu8IXL.d.ts → index-COs_z6nV.d.cts} +47 -3
  217. package/dist/{index-DrRS51Ld.d.cts → index-D7d1u2gr.d.ts} +47 -3
  218. package/dist/index.cjs +233 -216
  219. package/dist/index.cjs.map +1 -1
  220. package/dist/index.d.cts +12 -12
  221. package/dist/index.d.ts +12 -12
  222. package/dist/index.js +35 -34
  223. package/dist/index.js.map +1 -1
  224. package/dist/indexes/index.cjs +13 -13
  225. package/dist/indexes/index.d.cts +4 -4
  226. package/dist/indexes/index.d.ts +4 -4
  227. package/dist/indexes/index.js +6 -6
  228. package/dist/interchange/index.cjs +53 -52
  229. package/dist/interchange/index.cjs.map +1 -1
  230. package/dist/interchange/index.d.cts +17 -13
  231. package/dist/interchange/index.d.ts +17 -13
  232. package/dist/interchange/index.js +17 -16
  233. package/dist/interchange/index.js.map +1 -1
  234. package/dist/{manager-ptr3JLRP.d.cts → manager-CYaff3n3.d.cts} +2 -2
  235. package/dist/{manager-DX983gJ0.d.ts → manager-D9eRT_ns.d.ts} +2 -2
  236. package/dist/{materialize-indexes-CpXoggWU.d.ts → materialize-indexes-DJ3ykH59.d.ts} +1 -1
  237. package/dist/{materialize-indexes-BXz77YqO.d.cts → materialize-indexes-DTtAnvfY.d.cts} +1 -1
  238. package/dist/{postgres-DwgEXSPI.d.cts → postgres-CcL4bAHS.d.ts} +1 -1
  239. package/dist/{postgres-QdOMHTBz.d.ts → postgres-DMj39MEu.d.cts} +1 -1
  240. package/dist/profiler/index.d.cts +9 -9
  241. package/dist/profiler/index.d.ts +9 -9
  242. package/dist/provenance/index.cjs +46 -46
  243. package/dist/provenance/index.cjs.map +1 -1
  244. package/dist/provenance/index.d.cts +7 -7
  245. package/dist/provenance/index.d.ts +7 -7
  246. package/dist/provenance/index.js +13 -13
  247. package/dist/provenance/index.js.map +1 -1
  248. package/dist/repair-validity-windows-BFNZvd_H.d.cts +166 -0
  249. package/dist/repair-validity-windows-DlUSqwCg.d.ts +166 -0
  250. package/dist/schema/index.cjs +45 -44
  251. package/dist/schema/index.d.cts +6 -6
  252. package/dist/schema/index.d.ts +6 -6
  253. package/dist/schema/index.js +18 -17
  254. package/dist/{searchable-BOUuA83f.d.ts → searchable-DHJMh_nj.d.cts} +1 -1
  255. package/dist/{searchable-BrUh0pdc.d.cts → searchable-bpE1bBfc.d.ts} +1 -1
  256. package/dist/{sqlite-BfYcV61E.d.cts → sqlite-D7Oz0SQh.d.ts} +1 -1
  257. package/dist/{sqlite-DK40XVR1.d.ts → sqlite-YppHrNFb.d.cts} +1 -1
  258. package/dist/{store-FTqBpuJD.d.cts → store-JUVvtmR4.d.cts} +228 -92
  259. package/dist/{store-Bo1psfVZ.d.ts → store-UzrGvZOo.d.ts} +228 -92
  260. package/dist/{temporal-DPtn0HOu.d.ts → temporal-5GqpYCk2.d.cts} +1 -1
  261. package/dist/{temporal-CXewwLTB.d.cts → temporal-CbnLzTmM.d.ts} +1 -1
  262. package/dist/{types-Du78EvpN.d.ts → types-BqFZTQmV.d.cts} +60 -9
  263. package/dist/{types-Du78EvpN.d.cts → types-BqFZTQmV.d.ts} +60 -9
  264. package/dist/{types-CeT7xM4M.d.ts → types-Bx74kaTt.d.ts} +1 -1
  265. package/dist/{types-XR1nHERK.d.cts → types-CXAhpW-c.d.cts} +1 -1
  266. package/dist/{where-CJsp-YUf.d.cts → where-DI_Fqz-X.d.cts} +1 -1
  267. package/dist/{where-CMbFiWwp.d.ts → where-O-k2wgYm.d.ts} +1 -1
  268. package/package.json +1 -1
  269. package/dist/chunk-32UETY6S.cjs.map +0 -1
  270. package/dist/chunk-5PDSCELM.cjs.map +0 -1
  271. package/dist/chunk-62ZXBMSD.js.map +0 -1
  272. package/dist/chunk-6LAXM4J2.cjs +0 -12
  273. package/dist/chunk-73MWKDFK.cjs +0 -12
  274. package/dist/chunk-A2LJG5GM.js.map +0 -1
  275. package/dist/chunk-A4R3H7RU.cjs.map +0 -1
  276. package/dist/chunk-ANKOXPCC.cjs +0 -267
  277. package/dist/chunk-ANKOXPCC.cjs.map +0 -1
  278. package/dist/chunk-AT3MLMJV.js.map +0 -1
  279. package/dist/chunk-BEB4OFZF.cjs.map +0 -1
  280. package/dist/chunk-BQM5P2NO.cjs.map +0 -1
  281. package/dist/chunk-C2ZP5YS6.cjs.map +0 -1
  282. package/dist/chunk-C6KE2HSQ.cjs.map +0 -1
  283. package/dist/chunk-DSAWGCMP.js +0 -254
  284. package/dist/chunk-DSAWGCMP.js.map +0 -1
  285. package/dist/chunk-E4OSGBCM.cjs.map +0 -1
  286. package/dist/chunk-EDHV4CBU.js.map +0 -1
  287. package/dist/chunk-FA6Z7B5L.js +0 -244
  288. package/dist/chunk-FA6Z7B5L.js.map +0 -1
  289. package/dist/chunk-GVAMRRZR.cjs +0 -268
  290. package/dist/chunk-GVAMRRZR.cjs.map +0 -1
  291. package/dist/chunk-GWXXHOLU.js.map +0 -1
  292. package/dist/chunk-HNYLMPQQ.cjs.map +0 -1
  293. package/dist/chunk-IHRDX7K6.js.map +0 -1
  294. package/dist/chunk-KCH7WQA5.cjs.map +0 -1
  295. package/dist/chunk-KXSMF6PL.js.map +0 -1
  296. package/dist/chunk-LHYSY6SE.js.map +0 -1
  297. package/dist/chunk-N3QTGPC7.cjs.map +0 -1
  298. package/dist/chunk-QPOQX2DI.cjs.map +0 -1
  299. package/dist/chunk-R7EWHKID.js.map +0 -1
  300. package/dist/chunk-RFDEYLIK.js.map +0 -1
  301. package/dist/chunk-RHDOAQCT.cjs.map +0 -1
  302. package/dist/chunk-S3G5VLSW.js.map +0 -1
  303. package/dist/chunk-S7WIRFNS.cjs.map +0 -1
  304. package/dist/chunk-UTVQPZPN.cjs.map +0 -1
  305. package/dist/chunk-WEJHA7AD.js.map +0 -1
  306. package/dist/chunk-WYFB7BN3.js.map +0 -1
  307. package/dist/chunk-YQ4JONWE.js.map +0 -1
  308. package/dist/chunk-Z43KWLZF.js.map +0 -1
  309. package/dist/ddl-mE07h_EM.d.cts +0 -38
  310. package/dist/ddl-opIn8DfX.d.ts +0 -38
@@ -1,21 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkANKOXPCC_cjs = require('./chunk-ANKOXPCC.cjs');
4
- var chunkKCH7WQA5_cjs = require('./chunk-KCH7WQA5.cjs');
3
+ var chunk5PRKMB24_cjs = require('./chunk-5PRKMB24.cjs');
4
+ var chunkTQHGE7UC_cjs = require('./chunk-TQHGE7UC.cjs');
5
+ var chunkMRDBBHIZ_cjs = require('./chunk-MRDBBHIZ.cjs');
5
6
 
6
7
  // src/backend/row-mappers.ts
7
- function requireTimestamp(value, field) {
8
- if (value === void 0) {
9
- throw new chunkKCH7WQA5_cjs.DatabaseOperationError(`Expected non-null ${field} timestamp`, {
10
- operation: "select",
11
- entity: "row"
12
- });
13
- }
14
- return value;
15
- }
16
8
  function asString(value, field) {
17
9
  if (typeof value !== "string") {
18
- throw new chunkKCH7WQA5_cjs.DatabaseOperationError(
10
+ throw new chunkMRDBBHIZ_cjs.DatabaseOperationError(
19
11
  `Expected ${field} to be string, got ${typeof value}`,
20
12
  { operation: "select", entity: "row" }
21
13
  );
@@ -24,7 +16,7 @@ function asString(value, field) {
24
16
  }
25
17
  function asNumber(value, field) {
26
18
  if (typeof value !== "number") {
27
- throw new chunkKCH7WQA5_cjs.DatabaseOperationError(
19
+ throw new chunkMRDBBHIZ_cjs.DatabaseOperationError(
28
20
  `Expected ${field} to be number, got ${typeof value}`,
29
21
  { operation: "select", entity: "row" }
30
22
  );
@@ -34,9 +26,6 @@ function asNumber(value, field) {
34
26
  function nowIso() {
35
27
  return (/* @__PURE__ */ new Date()).toISOString();
36
28
  }
37
- function nullToUndefined(value) {
38
- return value ?? void 0;
39
- }
40
29
  function formatPostgresTimestamp(value) {
41
30
  if (value === null || value === void 0) return void 0;
42
31
  if (value instanceof Date) return value.toISOString();
@@ -48,6 +37,27 @@ function formatPostgresTimestamp(value) {
48
37
  }
49
38
  return void 0;
50
39
  }
40
+ function normalizeRowTimestamp(value, field) {
41
+ if (value === null || value === void 0) return void 0;
42
+ const canonical = chunkTQHGE7UC_cjs.canonicalizeDatabaseTimestamp(value);
43
+ if (canonical === void 0) {
44
+ throw new chunkMRDBBHIZ_cjs.DatabaseOperationError(
45
+ `Expected ${field} to be a database timestamp, got ${typeof value}`,
46
+ { operation: "select", entity: "row" }
47
+ );
48
+ }
49
+ return canonical;
50
+ }
51
+ function normalizeRequiredRowTimestamp(value, field) {
52
+ const timestamp = normalizeRowTimestamp(value, field);
53
+ if (timestamp === void 0) {
54
+ throw new chunkMRDBBHIZ_cjs.DatabaseOperationError(`Expected non-null ${field} timestamp`, {
55
+ operation: "select",
56
+ entity: "row"
57
+ });
58
+ }
59
+ return timestamp;
60
+ }
51
61
  function coerceNumericScore(value) {
52
62
  if (typeof value === "number") return value;
53
63
  const parsed = Number.parseFloat(value);
@@ -66,19 +76,9 @@ function normalizeJsonColumn(value) {
66
76
  return JSON.stringify(value ?? {});
67
77
  }
68
78
  var SQLITE_ROW_MAPPER_CONFIG = {
69
- formatTimestamp: (value) => {
70
- if (value === null || value === void 0) return;
71
- if (typeof value !== "string") {
72
- throw new chunkKCH7WQA5_cjs.DatabaseOperationError(
73
- `Expected timestamp to be string, got ${typeof value}`,
74
- { operation: "select", entity: "row" }
75
- );
76
- }
77
- return value;
78
- },
79
79
  normalizeJson: (value) => {
80
80
  if (typeof value !== "string") {
81
- throw new chunkKCH7WQA5_cjs.DatabaseOperationError(
81
+ throw new chunkMRDBBHIZ_cjs.DatabaseOperationError(
82
82
  `Expected JSON column to be string, got ${typeof value}`,
83
83
  { operation: "select", entity: "row" }
84
84
  );
@@ -87,7 +87,6 @@ var SQLITE_ROW_MAPPER_CONFIG = {
87
87
  }
88
88
  };
89
89
  var POSTGRES_ROW_MAPPER_CONFIG = {
90
- formatTimestamp: formatPostgresTimestamp,
91
90
  normalizeJson: normalizeJsonColumn
92
91
  };
93
92
  function createNodeRowMapper(config) {
@@ -97,17 +96,11 @@ function createNodeRowMapper(config) {
97
96
  id: asString(row["id"], "id"),
98
97
  props: config.normalizeJson(row["props"]),
99
98
  version: asNumber(row["version"], "version"),
100
- valid_from: nullToUndefined(config.formatTimestamp(row["valid_from"])),
101
- valid_to: nullToUndefined(config.formatTimestamp(row["valid_to"])),
102
- created_at: requireTimestamp(
103
- config.formatTimestamp(row["created_at"]),
104
- "created_at"
105
- ),
106
- updated_at: requireTimestamp(
107
- config.formatTimestamp(row["updated_at"]),
108
- "updated_at"
109
- ),
110
- deleted_at: nullToUndefined(config.formatTimestamp(row["deleted_at"]))
99
+ valid_from: normalizeRowTimestamp(row["valid_from"], "valid_from"),
100
+ valid_to: normalizeRowTimestamp(row["valid_to"], "valid_to"),
101
+ created_at: normalizeRequiredRowTimestamp(row["created_at"], "created_at"),
102
+ updated_at: normalizeRequiredRowTimestamp(row["updated_at"], "updated_at"),
103
+ deleted_at: normalizeRowTimestamp(row["deleted_at"], "deleted_at")
111
104
  });
112
105
  }
113
106
  function createEdgeRowMapper(config) {
@@ -120,29 +113,26 @@ function createEdgeRowMapper(config) {
120
113
  to_kind: asString(row["to_kind"], "to_kind"),
121
114
  to_id: asString(row["to_id"], "to_id"),
122
115
  props: config.normalizeJson(row["props"]),
123
- valid_from: nullToUndefined(config.formatTimestamp(row["valid_from"])),
124
- valid_to: nullToUndefined(config.formatTimestamp(row["valid_to"])),
125
- created_at: requireTimestamp(
126
- config.formatTimestamp(row["created_at"]),
127
- "created_at"
128
- ),
129
- updated_at: requireTimestamp(
130
- config.formatTimestamp(row["updated_at"]),
131
- "updated_at"
132
- ),
133
- deleted_at: nullToUndefined(config.formatTimestamp(row["deleted_at"]))
116
+ valid_from: normalizeRowTimestamp(row["valid_from"], "valid_from"),
117
+ valid_to: normalizeRowTimestamp(row["valid_to"], "valid_to"),
118
+ created_at: normalizeRequiredRowTimestamp(row["created_at"], "created_at"),
119
+ updated_at: normalizeRequiredRowTimestamp(row["updated_at"], "updated_at"),
120
+ deleted_at: normalizeRowTimestamp(row["deleted_at"], "deleted_at")
134
121
  });
135
122
  }
136
- function createUniqueRowMapper(config) {
137
- return (row) => ({
123
+ function mapUniqueRow(row) {
124
+ return {
138
125
  graph_id: asString(row["graph_id"], "graph_id"),
139
126
  node_kind: asString(row["node_kind"], "node_kind"),
140
127
  constraint_name: asString(row["constraint_name"], "constraint_name"),
141
128
  key: asString(row["key"], "key"),
142
129
  node_id: asString(row["node_id"], "node_id"),
143
130
  concrete_kind: asString(row["concrete_kind"], "concrete_kind"),
144
- deleted_at: nullToUndefined(config.formatTimestamp(row["deleted_at"]))
145
- });
131
+ deleted_at: normalizeRowTimestamp(row["deleted_at"], "deleted_at")
132
+ };
133
+ }
134
+ function createUniqueRowMapper(_config) {
135
+ return mapUniqueRow;
146
136
  }
147
137
  function createSchemaVersionRowMapper(config) {
148
138
  return (row) => {
@@ -152,9 +142,9 @@ function createSchemaVersionRowMapper(config) {
152
142
  graph_id: asString(row["graph_id"], "graph_id"),
153
143
  version: asNumber(row["version"], "version"),
154
144
  schema_hash: asString(row["schema_hash"], "schema_hash"),
155
- schema_doc: chunkANKOXPCC_cjs.rowPropsToJsonText(config.normalizeJson(row["schema_doc"])),
156
- created_at: requireTimestamp(
157
- config.formatTimestamp(row["created_at"]),
145
+ schema_doc: chunk5PRKMB24_cjs.rowPropsToJsonText(config.normalizeJson(row["schema_doc"])),
146
+ created_at: normalizeRequiredRowTimestamp(
147
+ row["created_at"],
158
148
  "created_at"
159
149
  ),
160
150
  is_active: isActive
@@ -170,6 +160,8 @@ exports.createNodeRowMapper = createNodeRowMapper;
170
160
  exports.createSchemaVersionRowMapper = createSchemaVersionRowMapper;
171
161
  exports.createUniqueRowMapper = createUniqueRowMapper;
172
162
  exports.formatPostgresTimestamp = formatPostgresTimestamp;
163
+ exports.normalizeRequiredRowTimestamp = normalizeRequiredRowTimestamp;
164
+ exports.normalizeRowTimestamp = normalizeRowTimestamp;
173
165
  exports.nowIso = nowIso;
174
- //# sourceMappingURL=chunk-BEB4OFZF.cjs.map
175
- //# sourceMappingURL=chunk-BEB4OFZF.cjs.map
166
+ //# sourceMappingURL=chunk-FA2AFWLP.cjs.map
167
+ //# sourceMappingURL=chunk-FA2AFWLP.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/backend/row-mappers.ts"],"names":["DatabaseOperationError","canonicalizeDatabaseTimestamp","rowPropsToJsonText"],"mappings":";;;;;;;AAcA,SAAS,QAAA,CAAS,OAAgB,KAAA,EAAuB;AACvD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAM,IAAIA,wCAAA;AAAA,MACR,CAAA,SAAA,EAAY,KAAK,CAAA,mBAAA,EAAsB,OAAO,KAAK,CAAA,CAAA;AAAA,MACnD,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAQ,KAAA;AAAM,KACvC;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,QAAA,CAAS,OAAgB,KAAA,EAAuB;AACvD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,MAAM,IAAIA,wCAAA;AAAA,MACR,CAAA,SAAA,EAAY,KAAK,CAAA,mBAAA,EAAsB,OAAO,KAAK,CAAA,CAAA;AAAA,MACnD,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAQ,KAAA;AAAM,KACvC;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,MAAA,GAAiB;AAC/B,EAAA,OAAA,iBAAO,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAChC;AAMO,SAAS,wBAAwB,KAAA,EAAoC;AAC1E,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,MAAA;AAClD,EAAA,IAAI,KAAA,YAAiB,IAAA,EAAM,OAAO,KAAA,CAAM,WAAA,EAAY;AACpD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,IAAI,KAAA,CAAM,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,KAAA;AAChC,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,KAAK,CAAA;AAC3B,IAAA,IAAI,CAAC,OAAO,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA,EAAG,OAAO,IAAA,CAAK,WAAA,EAAY;AAC3D,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA;AACT;AAOO,SAAS,qBAAA,CACd,OACA,KAAA,EACoB;AACpB,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,MAAA;AAClD,EAAA,MAAM,SAAA,GAAYC,gDAA8B,KAAK,CAAA;AACrD,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA,MAAM,IAAID,wCAAA;AAAA,MACR,CAAA,SAAA,EAAY,KAAK,CAAA,iCAAA,EAAoC,OAAO,KAAK,CAAA,CAAA;AAAA,MACjE,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAQ,KAAA;AAAM,KACvC;AAAA,EACF;AACA,EAAA,OAAO,SAAA;AACT;AAEO,SAAS,6BAAA,CACd,OACA,KAAA,EACQ;AACR,EAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,KAAA,EAAO,KAAK,CAAA;AACpD,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA,MAAM,IAAIA,wCAAA,CAAuB,CAAA,kBAAA,EAAqB,KAAK,CAAA,UAAA,CAAA,EAAc;AAAA,MACvE,SAAA,EAAW,QAAA;AAAA,MACX,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AACA,EAAA,OAAO,SAAA;AACT;AAUO,SAAS,mBAAmB,KAAA,EAAgC;AACjE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA;AACtC,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,MAAM,CAAA,EAAG;AACxB,IAAA,MAAM,IAAI,SAAA;AAAA,MACR,CAAA,6CAAA,EAAgD,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AAAA,KACvE;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AASA,SAAS,oBAAoB,KAAA,EAAkD;AAC7E,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,QAAA,EAAU;AAC/C,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAA,IAAS,EAAE,CAAA;AACnC;AAgBO,IAAM,wBAAA,GAAmD;AAAA,EAC9D,aAAA,EAAe,CAAC,KAAA,KAAU;AACxB,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,MAAM,IAAIA,wCAAA;AAAA,QACR,CAAA,uCAAA,EAA0C,OAAO,KAAK,CAAA,CAAA;AAAA,QACtD,EAAE,SAAA,EAAW,QAAA,EAAU,MAAA,EAAQ,KAAA;AAAM,OACvC;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAKO,IAAM,0BAAA,GAAqD;AAAA,EAChE,aAAA,EAAe;AACjB;AAMO,SAAS,oBACd,MAAA,EAC2C;AAC3C,EAAA,OAAO,CAAC,GAAA,MAAS;AAAA,IACf,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,UAAU,GAAG,UAAU,CAAA;AAAA,IAC9C,IAAA,EAAM,QAAA,CAAS,GAAA,CAAI,MAAM,GAAG,MAAM,CAAA;AAAA,IAClC,EAAA,EAAI,QAAA,CAAS,GAAA,CAAI,IAAI,GAAG,IAAI,CAAA;AAAA,IAC5B,KAAA,EAAO,MAAA,CAAO,aAAA,CAAc,GAAA,CAAI,OAAO,CAAC,CAAA;AAAA,IACxC,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,SAAS,GAAG,SAAS,CAAA;AAAA,IAC3C,UAAA,EAAY,qBAAA,CAAsB,GAAA,CAAI,YAAY,GAAG,YAAY,CAAA;AAAA,IACjE,QAAA,EAAU,qBAAA,CAAsB,GAAA,CAAI,UAAU,GAAG,UAAU,CAAA;AAAA,IAC3D,UAAA,EAAY,6BAAA,CAA8B,GAAA,CAAI,YAAY,GAAG,YAAY,CAAA;AAAA,IACzE,UAAA,EAAY,6BAAA,CAA8B,GAAA,CAAI,YAAY,GAAG,YAAY,CAAA;AAAA,IACzE,UAAA,EAAY,qBAAA,CAAsB,GAAA,CAAI,YAAY,GAAG,YAAY;AAAA,GACnE,CAAA;AACF;AAEO,SAAS,oBACd,MAAA,EAC2C;AAC3C,EAAA,OAAO,CAAC,GAAA,MAAS;AAAA,IACf,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,UAAU,GAAG,UAAU,CAAA;AAAA,IAC9C,EAAA,EAAI,QAAA,CAAS,GAAA,CAAI,IAAI,GAAG,IAAI,CAAA;AAAA,IAC5B,IAAA,EAAM,QAAA,CAAS,GAAA,CAAI,MAAM,GAAG,MAAM,CAAA;AAAA,IAClC,SAAA,EAAW,QAAA,CAAS,GAAA,CAAI,WAAW,GAAG,WAAW,CAAA;AAAA,IACjD,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,SAAS,GAAG,SAAS,CAAA;AAAA,IAC3C,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,SAAS,GAAG,SAAS,CAAA;AAAA,IAC3C,KAAA,EAAO,QAAA,CAAS,GAAA,CAAI,OAAO,GAAG,OAAO,CAAA;AAAA,IACrC,KAAA,EAAO,MAAA,CAAO,aAAA,CAAc,GAAA,CAAI,OAAO,CAAC,CAAA;AAAA,IACxC,UAAA,EAAY,qBAAA,CAAsB,GAAA,CAAI,YAAY,GAAG,YAAY,CAAA;AAAA,IACjE,QAAA,EAAU,qBAAA,CAAsB,GAAA,CAAI,UAAU,GAAG,UAAU,CAAA;AAAA,IAC3D,UAAA,EAAY,6BAAA,CAA8B,GAAA,CAAI,YAAY,GAAG,YAAY,CAAA;AAAA,IACzE,UAAA,EAAY,6BAAA,CAA8B,GAAA,CAAI,YAAY,GAAG,YAAY,CAAA;AAAA,IACzE,UAAA,EAAY,qBAAA,CAAsB,GAAA,CAAI,YAAY,GAAG,YAAY;AAAA,GACnE,CAAA;AACF;AAEA,SAAS,aAAa,GAAA,EAAyC;AAC7D,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,UAAU,GAAG,UAAU,CAAA;AAAA,IAC9C,SAAA,EAAW,QAAA,CAAS,GAAA,CAAI,WAAW,GAAG,WAAW,CAAA;AAAA,IACjD,eAAA,EAAiB,QAAA,CAAS,GAAA,CAAI,iBAAiB,GAAG,iBAAiB,CAAA;AAAA,IACnE,GAAA,EAAK,QAAA,CAAS,GAAA,CAAI,KAAK,GAAG,KAAK,CAAA;AAAA,IAC/B,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,SAAS,GAAG,SAAS,CAAA;AAAA,IAC3C,aAAA,EAAe,QAAA,CAAS,GAAA,CAAI,eAAe,GAAG,eAAe,CAAA;AAAA,IAC7D,UAAA,EAAY,qBAAA,CAAsB,GAAA,CAAI,YAAY,GAAG,YAAY;AAAA,GACnE;AACF;AAEO,SAAS,sBACd,OAAA,EAC6C;AAC7C,EAAA,OAAO,YAAA;AACT;AAEO,SAAS,6BACd,MAAA,EACoD;AACpD,EAAA,OAAO,CAAC,GAAA,KAAQ;AACd,IAAA,MAAM,aAAA,GAAgB,IAAI,WAAW,CAAA;AACrC,IAAA,MAAM,QAAA,GACJ,aAAA,KAAkB,IAAA,IAAQ,aAAA,KAAkB,KAAK,aAAA,KAAkB,GAAA;AAErE,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,UAAU,GAAG,UAAU,CAAA;AAAA,MAC9C,OAAA,EAAS,QAAA,CAAS,GAAA,CAAI,SAAS,GAAG,SAAS,CAAA;AAAA,MAC3C,WAAA,EAAa,QAAA,CAAS,GAAA,CAAI,aAAa,GAAG,aAAa,CAAA;AAAA,MACvD,YAAYE,oCAAA,CAAmB,MAAA,CAAO,cAAc,GAAA,CAAI,YAAY,CAAC,CAAC,CAAA;AAAA,MACtE,UAAA,EAAY,6BAAA;AAAA,QACV,IAAI,YAAY,CAAA;AAAA,QAChB;AAAA,OACF;AAAA,MACA,SAAA,EAAW;AAAA,KACb;AAAA,EACF,CAAA;AACF","file":"chunk-FA2AFWLP.cjs","sourcesContent":["/**\n * Shared database row-mapping utilities.\n */\n\nimport { DatabaseOperationError } from \"../errors\";\nimport { canonicalizeDatabaseTimestamp } from \"../utils/date\";\nimport {\n type EdgeRow,\n type NodeRow,\n rowPropsToJsonText,\n type SchemaVersionRow,\n type UniqueRow,\n} from \"./types\";\n\nfunction asString(value: unknown, field: string): string {\n if (typeof value !== \"string\") {\n throw new DatabaseOperationError(\n `Expected ${field} to be string, got ${typeof value}`,\n { operation: \"select\", entity: \"row\" },\n );\n }\n return value;\n}\n\nfunction asNumber(value: unknown, field: string): number {\n if (typeof value !== \"number\") {\n throw new DatabaseOperationError(\n `Expected ${field} to be number, got ${typeof value}`,\n { operation: \"select\", entity: \"row\" },\n );\n }\n return value;\n}\n\nexport function nowIso(): string {\n return new Date().toISOString();\n}\n\n/**\n * Formats PostgreSQL timestamps used by internal status-table adapters.\n * Row metadata uses the stricter {@link normalizeRowTimestamp} contract.\n */\nexport function formatPostgresTimestamp(value: unknown): string | undefined {\n if (value === null || value === undefined) return undefined;\n if (value instanceof Date) return value.toISOString();\n if (typeof value === \"string\") {\n if (value.includes(\"T\")) return value;\n const date = new Date(value);\n if (!Number.isNaN(date.getTime())) return date.toISOString();\n return value;\n }\n return undefined;\n}\n\n/**\n * Canonicalizes database-driver timestamp values at the row-mapping boundary.\n * Every store and compiled-query metadata projection uses this owner so driver\n * rendering differences cannot become public values.\n */\nexport function normalizeRowTimestamp(\n value: unknown,\n field: string,\n): string | undefined {\n if (value === null || value === undefined) return undefined;\n const canonical = canonicalizeDatabaseTimestamp(value);\n if (canonical === undefined) {\n throw new DatabaseOperationError(\n `Expected ${field} to be a database timestamp, got ${typeof value}`,\n { operation: \"select\", entity: \"row\" },\n );\n }\n return canonical;\n}\n\nexport function normalizeRequiredRowTimestamp(\n value: unknown,\n field: string,\n): string {\n const timestamp = normalizeRowTimestamp(value, field);\n if (timestamp === undefined) {\n throw new DatabaseOperationError(`Expected non-null ${field} timestamp`, {\n operation: \"select\",\n entity: \"row\",\n });\n }\n return timestamp;\n}\n\n/**\n * Coerce a fulltext relevance score to `number` at the backend\n * boundary. Postgres returns `numeric` as a string to preserve\n * precision; a custom `FulltextStrategy` on either dialect could\n * likewise yield a string. Shared so both backends enforce the same\n * `FulltextSearchResult.score: number` contract and reject garbage\n * loudly instead of propagating `NaN`.\n */\nexport function coerceNumericScore(value: number | string): number {\n if (typeof value === \"number\") return value;\n const parsed = Number.parseFloat(value);\n if (Number.isNaN(parsed)) {\n throw new TypeError(\n `Backend returned non-numeric fulltext score: ${JSON.stringify(value)}`,\n );\n }\n return parsed;\n}\n\n/**\n * Normalizes a JSON column that may be returned as a parsed object (JSONB)\n * or string. PostgreSQL drivers hand jsonb back already parsed — keep the\n * object instead of re-stringifying it, so the read path pays zero JSON\n * work per row (consumers normalize via rowPropsToObject /\n * rowPropsToJsonText at the point of use). SQLite text passes through.\n */\nfunction normalizeJsonColumn(value: unknown): string | Record<string, unknown> {\n if (typeof value === \"string\") return value;\n if (value !== null && typeof value === \"object\") {\n return value as Record<string, unknown>;\n }\n return JSON.stringify(value ?? {});\n}\n\n/**\n * Dialect-specific configuration for row mappers.\n *\n * Row mapper factories accept this config to produce dialect-appropriate\n * mappers. Timestamp normalization is dialect-independent and owned by\n * {@link normalizeRowTimestamp}; only JSON columns need dialect configuration.\n */\ntype DialectRowMapperConfig = Readonly<{\n normalizeJson: (value: unknown) => string | Record<string, unknown>;\n}>;\n\n/**\n * SQLite row mapper config. JSON is stored as TEXT.\n */\nexport const SQLITE_ROW_MAPPER_CONFIG: DialectRowMapperConfig = {\n normalizeJson: (value) => {\n if (typeof value !== \"string\") {\n throw new DatabaseOperationError(\n `Expected JSON column to be string, got ${typeof value}`,\n { operation: \"select\", entity: \"row\" },\n );\n }\n return value;\n },\n};\n\n/**\n * PostgreSQL row mapper config. JSONB is returned as parsed objects.\n */\nexport const POSTGRES_ROW_MAPPER_CONFIG: DialectRowMapperConfig = {\n normalizeJson: normalizeJsonColumn,\n};\n\n// Trust boundary: Drizzle raw SQL returns Record<string, unknown> rows.\n// The field access patterns below are intentional unsafe casts at the\n// database driver boundary where we know the column shapes.\n\nexport function createNodeRowMapper(\n config: DialectRowMapperConfig,\n): (row: Record<string, unknown>) => NodeRow {\n return (row) => ({\n graph_id: asString(row[\"graph_id\"], \"graph_id\"),\n kind: asString(row[\"kind\"], \"kind\"),\n id: asString(row[\"id\"], \"id\"),\n props: config.normalizeJson(row[\"props\"]),\n version: asNumber(row[\"version\"], \"version\"),\n valid_from: normalizeRowTimestamp(row[\"valid_from\"], \"valid_from\"),\n valid_to: normalizeRowTimestamp(row[\"valid_to\"], \"valid_to\"),\n created_at: normalizeRequiredRowTimestamp(row[\"created_at\"], \"created_at\"),\n updated_at: normalizeRequiredRowTimestamp(row[\"updated_at\"], \"updated_at\"),\n deleted_at: normalizeRowTimestamp(row[\"deleted_at\"], \"deleted_at\"),\n });\n}\n\nexport function createEdgeRowMapper(\n config: DialectRowMapperConfig,\n): (row: Record<string, unknown>) => EdgeRow {\n return (row) => ({\n graph_id: asString(row[\"graph_id\"], \"graph_id\"),\n id: asString(row[\"id\"], \"id\"),\n kind: asString(row[\"kind\"], \"kind\"),\n from_kind: asString(row[\"from_kind\"], \"from_kind\"),\n from_id: asString(row[\"from_id\"], \"from_id\"),\n to_kind: asString(row[\"to_kind\"], \"to_kind\"),\n to_id: asString(row[\"to_id\"], \"to_id\"),\n props: config.normalizeJson(row[\"props\"]),\n valid_from: normalizeRowTimestamp(row[\"valid_from\"], \"valid_from\"),\n valid_to: normalizeRowTimestamp(row[\"valid_to\"], \"valid_to\"),\n created_at: normalizeRequiredRowTimestamp(row[\"created_at\"], \"created_at\"),\n updated_at: normalizeRequiredRowTimestamp(row[\"updated_at\"], \"updated_at\"),\n deleted_at: normalizeRowTimestamp(row[\"deleted_at\"], \"deleted_at\"),\n });\n}\n\nfunction mapUniqueRow(row: Record<string, unknown>): UniqueRow {\n return {\n graph_id: asString(row[\"graph_id\"], \"graph_id\"),\n node_kind: asString(row[\"node_kind\"], \"node_kind\"),\n constraint_name: asString(row[\"constraint_name\"], \"constraint_name\"),\n key: asString(row[\"key\"], \"key\"),\n node_id: asString(row[\"node_id\"], \"node_id\"),\n concrete_kind: asString(row[\"concrete_kind\"], \"concrete_kind\"),\n deleted_at: normalizeRowTimestamp(row[\"deleted_at\"], \"deleted_at\"),\n };\n}\n\nexport function createUniqueRowMapper(\n _config: DialectRowMapperConfig,\n): (row: Record<string, unknown>) => UniqueRow {\n return mapUniqueRow;\n}\n\nexport function createSchemaVersionRowMapper(\n config: DialectRowMapperConfig,\n): (row: Record<string, unknown>) => SchemaVersionRow {\n return (row) => {\n const isActiveValue = row[\"is_active\"];\n const isActive =\n isActiveValue === true || isActiveValue === 1 || isActiveValue === \"1\";\n\n return {\n graph_id: asString(row[\"graph_id\"], \"graph_id\"),\n version: asNumber(row[\"version\"], \"version\"),\n schema_hash: asString(row[\"schema_hash\"], \"schema_hash\"),\n schema_doc: rowPropsToJsonText(config.normalizeJson(row[\"schema_doc\"])),\n created_at: normalizeRequiredRowTimestamp(\n row[\"created_at\"],\n \"created_at\",\n ),\n is_active: isActive,\n };\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkKCH7WQA5_cjs = require('./chunk-KCH7WQA5.cjs');
3
+ var chunkMRDBBHIZ_cjs = require('./chunk-MRDBBHIZ.cjs');
4
4
  var chunkN66HCGCY_cjs = require('./chunk-N66HCGCY.cjs');
5
5
 
6
6
  // src/constraints/index.ts
@@ -23,7 +23,7 @@ function checkWherePredicate(constraint, props) {
23
23
  }
24
24
  const predicate = captureWherePredicate(constraint.where);
25
25
  if (predicate === void 0) {
26
- throw new chunkKCH7WQA5_cjs.ConfigurationError(
26
+ throw new chunkMRDBBHIZ_cjs.ConfigurationError(
27
27
  `Unique constraint "${constraint.name}" has a \`where\` callback that does not return a predicate.`,
28
28
  { constraintName: constraint.name, fields: [...constraint.fields] },
29
29
  {
@@ -52,7 +52,7 @@ function assertWhereFieldDeclared(kind, constraint, shape) {
52
52
  if (!constraint.where) return;
53
53
  const predicate = captureWherePredicate(constraint.where);
54
54
  if (predicate === void 0) {
55
- throw new chunkKCH7WQA5_cjs.ConfigurationError(
55
+ throw new chunkMRDBBHIZ_cjs.ConfigurationError(
56
56
  `Unique constraint "${constraint.name}" on node kind "${kind}" has a \`where\` callback that does not return a predicate.`,
57
57
  { kind, constraintName: constraint.name },
58
58
  {
@@ -61,7 +61,7 @@ function assertWhereFieldDeclared(kind, constraint, shape) {
61
61
  );
62
62
  }
63
63
  if (!chunkN66HCGCY_cjs.hasOwnKey(shape, predicate.field)) {
64
- throw new chunkKCH7WQA5_cjs.ConfigurationError(
64
+ throw new chunkMRDBBHIZ_cjs.ConfigurationError(
65
65
  `Unique constraint "${constraint.name}" on node kind "${kind}" has a \`where\` clause on field "${predicate.field}", which is not declared in the kind's schema.`,
66
66
  {
67
67
  kind,
@@ -131,7 +131,7 @@ function checkCardinality(edgeKind, fromKind, fromId, cardinality, existingEdgeC
131
131
  }
132
132
  case "one": {
133
133
  if (existingEdgeCount > 0) {
134
- return new chunkKCH7WQA5_cjs.CardinalityError({
134
+ return new chunkMRDBBHIZ_cjs.CardinalityError({
135
135
  edgeKind,
136
136
  fromKind,
137
137
  fromId,
@@ -146,7 +146,7 @@ function checkCardinality(edgeKind, fromKind, fromId, cardinality, existingEdgeC
146
146
  }
147
147
  case "oneActive": {
148
148
  if (hasActiveEdge) {
149
- return new chunkKCH7WQA5_cjs.CardinalityError({
149
+ return new chunkMRDBBHIZ_cjs.CardinalityError({
150
150
  edgeKind,
151
151
  fromKind,
152
152
  fromId,
@@ -160,7 +160,7 @@ function checkCardinality(edgeKind, fromKind, fromId, cardinality, existingEdgeC
160
160
  }
161
161
  function checkUniqueEdge(edgeKind, fromKind, fromId, _toKind, _toId, existingCount) {
162
162
  if (existingCount > 0) {
163
- return new chunkKCH7WQA5_cjs.CardinalityError({
163
+ return new chunkMRDBBHIZ_cjs.CardinalityError({
164
164
  edgeKind,
165
165
  fromKind,
166
166
  fromId,
@@ -173,7 +173,7 @@ function checkUniqueEdge(edgeKind, fromKind, fromId, _toKind, _toId, existingCou
173
173
  function validateEdgeEndpoints(edgeKind, fromKind, toKind, registration, registry) {
174
174
  const validFromKinds = registration.from.map((node) => node.kind);
175
175
  if (!registry.isAssignableToAny(fromKind, validFromKinds)) {
176
- return new chunkKCH7WQA5_cjs.EndpointError({
176
+ return new chunkMRDBBHIZ_cjs.EndpointError({
177
177
  edgeKind,
178
178
  endpoint: "from",
179
179
  actualKind: fromKind,
@@ -182,7 +182,7 @@ function validateEdgeEndpoints(edgeKind, fromKind, toKind, registration, registr
182
182
  }
183
183
  const validToKinds = registration.to.map((node) => node.kind);
184
184
  if (!registry.isAssignableToAny(toKind, validToKinds)) {
185
- return new chunkKCH7WQA5_cjs.EndpointError({
185
+ return new chunkMRDBBHIZ_cjs.EndpointError({
186
186
  edgeKind,
187
187
  endpoint: "to",
188
188
  actualKind: toKind,
@@ -194,7 +194,7 @@ function validateEdgeEndpoints(edgeKind, fromKind, toKind, registration, registr
194
194
  function checkDisjointness(nodeId, nodeKind, existingKinds, registry) {
195
195
  for (const existingKind of existingKinds) {
196
196
  if (registry.areDisjoint(nodeKind, existingKind)) {
197
- return new chunkKCH7WQA5_cjs.DisjointError({
197
+ return new chunkMRDBBHIZ_cjs.DisjointError({
198
198
  nodeId,
199
199
  attemptedKind: nodeKind,
200
200
  conflictingKind: existingKind
@@ -213,5 +213,5 @@ exports.checkWherePredicate = checkWherePredicate;
213
213
  exports.computeUniqueKey = computeUniqueKey;
214
214
  exports.getKindsForUniquenessCheck = getKindsForUniquenessCheck;
215
215
  exports.validateEdgeEndpoints = validateEdgeEndpoints;
216
- //# sourceMappingURL=chunk-ZBVZ7HXD.cjs.map
217
- //# sourceMappingURL=chunk-ZBVZ7HXD.cjs.map
216
+ //# sourceMappingURL=chunk-FQPEMEWX.cjs.map
217
+ //# sourceMappingURL=chunk-FQPEMEWX.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constraints/index.ts"],"names":["readOwnProperty","ConfigurationError","hasOwnKey","isPresent","CardinalityError","EndpointError","DisjointError"],"mappings":"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","file":"chunk-ZBVZ7HXD.cjs","sourcesContent":["/**\n * Constraint validation module.\n *\n * Provides validation functions for enforcing graph constraints:\n * - Uniqueness constraints on node properties\n * - Cardinality constraints on edges\n * - Endpoint type constraints on edges\n * - Disjointness constraints between node kinds\n */\n\n/**\n * Separator used between field values in composite unique keys.\n * Uses ASCII Record Separator (0x1E) — valid UTF-8 and safe for PostgreSQL\n * TEXT columns (unlike \\0 which PostgreSQL rejects).\n */\nconst UNIQUE_KEY_SEPARATOR = \"\\u001E\";\n\n/** Marker for undefined/null field values in unique keys. */\nconst UNIQUE_KEY_NULL_MARKER = \"\\u001F\"; // ASCII Unit Separator\nimport {\n type Cardinality,\n type Collation,\n type EdgeRegistration,\n type NullCheckOp,\n type UniqueConstraint,\n type UniquenessScope,\n} from \"../core/types\";\nimport {\n CardinalityError,\n ConfigurationError,\n DisjointError,\n EndpointError,\n UniquenessError,\n} from \"../errors\";\nimport { type KindRegistry } from \"../registry/kind-registry\";\nimport { hasOwnKey, readOwnProperty } from \"../utils/object\";\nimport { isPresent } from \"../utils/presence\";\n\n// ============================================================\n// Uniqueness Validation\n// ============================================================\n\n/**\n * Computes the unique key for a node's uniqueness constraint.\n *\n * The key is built by concatenating the specified field values,\n * optionally normalized for case-insensitive comparison.\n *\n * Field values are read by declared OWN key ({@link readOwnProperty}): a\n * constraint may name a field that a props bag does not carry (an absent\n * optional field), and a plain `props[field]` read would answer such a field\n * with the inherited `Object.prototype` member when the field is named after\n * one. A constraint over a field named `toString` then keyed on the inherited\n * function — `\"\"` under `binary` (the function stringified and dropped by\n * `JSON.stringify`) and a `TypeError` under `caseInsensitive` — instead of the\n * null marker every other absent value gets.\n */\nexport function computeUniqueKey(\n props: Record<string, unknown>,\n fields: readonly string[],\n collation: Collation,\n): string {\n const values = fields.map((field) => {\n const value = readOwnProperty(props, field);\n if (value === undefined || value === null) {\n return UNIQUE_KEY_NULL_MARKER;\n }\n // Convert to string, handling primitives safely\n const stringValue =\n typeof value === \"string\" ? value\n : typeof value === \"number\" || typeof value === \"boolean\" ?\n value.toString()\n : JSON.stringify(value);\n return collation === \"caseInsensitive\" ?\n stringValue.toLowerCase()\n : stringValue;\n });\n return values.join(UNIQUE_KEY_SEPARATOR);\n}\n\n/**\n * Checks if a uniqueness constraint's where predicate passes.\n *\n * A `where` callback that does not return a predicate is REFUSED here, not\n * treated as \"the constraint always applies\". The same malformed clause is a\n * hard `ConfigurationError` at definition time ({@link assertWhereFieldDeclared})\n * and at persistence time (`serializeWherePredicate`); a third reading that\n * silently widened a partial constraint to a total one would let the three\n * sites disagree about the same clause — the divergence\n * {@link captureWherePredicate} exists to prevent.\n *\n * The arm SHOULD be unreachable: `defineGraph` refuses a non-predicate callback\n * before any write can evaluate it, `validateGraphExtension` refuses the\n * document form, and a constraint reconstructed from a persisted schema carries\n * a callback this module built itself. It is reachable only by handing the\n * store a constraint object that never passed a definition gate — for which\n * failing loudly is the correct answer, since the alternative is enforcing\n * uniqueness over rows the author meant to exclude.\n */\nexport function checkWherePredicate(\n constraint: UniqueConstraint,\n props: Record<string, unknown>,\n): boolean {\n if (!constraint.where) {\n return true; // No where clause, always applies\n }\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" has a \\`where\\` callback that does not return a predicate.`,\n { constraintName: constraint.name, fields: [...constraint.fields] },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${constraint.fields[0] ?? \"someField\"}.isNotNull()\\`. A constraint built outside \\`defineGraph\\` bypasses the definition-time check that normally reports this.`,\n },\n );\n }\n\n return evaluatePredicate(predicate, props);\n}\n\ntype UniquePredicate = Readonly<{\n __type: \"unique_predicate\";\n field: string;\n op: NullCheckOp;\n}>;\n\n/**\n * The `where` callback as every caller of {@link captureWherePredicate} sees it:\n * a per-field builder in, whatever the author returned out.\n *\n * Deliberately looser than `UniqueConstraint[\"where\"]`, whose builder type is\n * generic in the kind's schema — the capture is the same operation whether the\n * callback came from a typed `defineGraph` registration, a compiled\n * graph-extension document, or an untyped JavaScript caller.\n */\ntype UniqueWhereCallback = (\n builder: Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n >,\n) => unknown;\n\n/**\n * Runs a `where` callback against the shared builder and returns the predicate\n * it named, or `undefined` when the callback returned something that is not a\n * predicate.\n *\n * The single owner of \"what does this `where` clause say\": constraint\n * EVALUATION ({@link checkWherePredicate}), definition-time VALIDATION\n * ({@link assertWhereFieldDeclared}), and persistence-time CAPTURE\n * (`serializeWherePredicate` in src/schema/serializer.ts) all read the clause\n * through this one function, so a persisted `where`, a validated `where`, and\n * an evaluated `where` cannot disagree about which field the author named.\n */\nexport function captureWherePredicate(\n where: UniqueWhereCallback,\n): UniquePredicate | undefined {\n const predicate = where(buildPredicateContext());\n if (\n typeof predicate !== \"object\" ||\n predicate === null ||\n !(\"__type\" in predicate)\n ) {\n return undefined;\n }\n\n const candidate = predicate as {\n __type: unknown;\n field: unknown;\n op: unknown;\n };\n if (\n candidate.__type !== \"unique_predicate\" ||\n typeof candidate.field !== \"string\" ||\n (candidate.op !== \"isNull\" && candidate.op !== \"isNotNull\")\n ) {\n return undefined;\n }\n\n return {\n __type: \"unique_predicate\",\n field: candidate.field,\n op: candidate.op,\n };\n}\n\n/**\n * Refuses a uniqueness constraint whose `where` clause names a field the kind\n * does not declare.\n *\n * The runtime half of the builder's guard. {@link buildPredicateContext} is\n * total by design — it must answer for a DECLARED-but-absent field, which is\n * the whole point of a partial constraint — so a typo'd name cannot be caught\n * there, and the type system catches it only for typed callers\n * (`UniqueConstraintPredicateBuilder` declares exactly the schema's fields and\n * has no index signature). An untyped caller naming an undeclared field\n * otherwise gets a predicate that quietly never applies.\n *\n * Called once per constraint at graph-definition time — the single point every\n * constraint passes through before any write can evaluate it — rather than at\n * each of the write paths' `checkWherePredicate` call sites, so the refusal\n * covers every path uniformly and costs nothing per write. Mirrors\n * `validateGraphExtension`'s `UNKNOWN_UNIQUE_WHERE_FIELD` refusal, which\n * already holds the same invariant for kinds declared as JSON documents.\n */\nexport function assertWhereFieldDeclared(\n kind: string,\n constraint: UniqueConstraint,\n shape: Readonly<Record<string, unknown>>,\n): void {\n if (!constraint.where) return;\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` callback that does not return a predicate.`,\n { kind, constraintName: constraint.name },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${Object.keys(shape)[0] ?? \"someField\"}.isNotNull()\\`.`,\n },\n );\n }\n\n if (!hasOwnKey(shape, predicate.field)) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` clause on field \"${predicate.field}\", which is not declared in the kind's schema.`,\n {\n kind,\n constraintName: constraint.name,\n field: predicate.field,\n declaredFields: Object.keys(shape),\n },\n {\n suggestion: `Name a declared field (${Object.keys(shape).join(\", \")}) or add \"${predicate.field}\" to the schema.`,\n },\n );\n }\n}\n\ntype PredicateContext = Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n>;\n\n/**\n * Builds the context a constraint's `where` callback names fields on.\n *\n * EVERY field name gets a member, because the builder type declares every\n * schema field as required (`-?` in `UniqueConstraintPredicateBuilder`) —\n * precisely so a partial constraint can ask whether an OPTIONAL field is\n * present. Populating the context from the props bag's own keys instead left a\n * declared-but-absent field with no member, and the callback's access then hit\n * whatever the context's prototype offered: `Object.prototype.toString` for a\n * field named `toString` (so naming it threw \"isNull is not a function\"), and\n * `undefined` for an ordinary field (so the everyday partial constraint over\n * `externalId` threw — \"Cannot read properties of undefined\", or \"Expected a\n * defined value\" through `requireDefined` — for every node written without it).\n *\n * Answering every name is safe because a name comes from the predicate author\n * (the code), never from data, and the field's VALUE is still read from the\n * props bag by own key when the predicate is evaluated — so an absent field\n * evaluates as null, which is what a partial constraint means by absent. Every\n * reader of a `where` clause goes through {@link captureWherePredicate}, which\n * builds this one context, so a persisted `where`, a validated `where`, and an\n * evaluated `where` cannot see different builders.\n *\n * The guard against a TYPO'D field name is NOT this Proxy — it must stay total\n * or a declared-but-absent field loses its member. It is\n * {@link assertWhereFieldDeclared}, which every constraint passes at\n * graph-definition time: an undeclared name is refused there with a typed\n * `ConfigurationError`, so no `where` clause naming one ever reaches\n * evaluation, from a typed or an untyped caller.\n */\nfunction buildPredicateContext(): PredicateContext {\n return new Proxy<PredicateContext>(\n {},\n {\n get(_target, property) {\n if (typeof property === \"symbol\") return;\n return {\n isNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNull\" as const,\n }),\n isNotNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNotNull\" as const,\n }),\n };\n },\n },\n );\n}\n\n/**\n * Evaluates a uniqueness predicate.\n *\n * Takes a CAPTURED predicate, not an `unknown`: the \"is this really a\n * predicate?\" question belongs to {@link captureWherePredicate}, which is its\n * single owner. The defensive `return true` arms this function used to carry\n * were a second, quieter answer to that question — and they answered it the\n * opposite way, widening a partial constraint into a total one where the owner\n * refuses.\n */\nfunction evaluatePredicate(\n pred: UniquePredicate,\n props: Record<string, unknown>,\n): boolean {\n // Own-key read: `pred.field` is a schema field name, and a props bag that\n // does not carry it must read as absent rather than as the inherited\n // `Object.prototype` member a field named after one would otherwise find\n // (which reads as present, inverting both `isNull` and `isNotNull`).\n const value = readOwnProperty(props, pred.field);\n if (pred.op === \"isNull\") {\n return value === null || value === undefined;\n }\n return isPresent(value);\n}\n\n/**\n * Gets all kinds that should be checked for a uniqueness constraint.\n *\n * For \"kindWithSubClasses\" scope, includes the entire subclass hierarchy:\n * - The kind itself\n * - All ancestors (parent classes)\n * - All descendants of those ancestors (sibling classes)\n *\n * For \"kind\" scope, only the specific kind.\n */\nexport function getKindsForUniquenessCheck(\n baseKind: string,\n scope: UniquenessScope,\n registry: KindRegistry,\n): readonly string[] {\n if (scope === \"kind\") {\n return [baseKind];\n }\n\n // Get the entire connected subclass hierarchy by finding the root ancestor\n const root = findRootAncestor(baseKind, registry);\n\n // Return the root and all its descendants (which includes baseKind and siblings)\n return registry.expandSubClasses(root);\n}\n\n/**\n * Finds the topmost ancestor of a kind, or the kind itself if it has no ancestors.\n */\nfunction findRootAncestor(kind: string, registry: KindRegistry): string {\n const ancestors = registry.getAncestors(kind);\n\n if (ancestors.size === 0) {\n return kind;\n }\n\n // Find an ancestor with no ancestors (the root)\n for (const ancestor of ancestors) {\n if (registry.getAncestors(ancestor).size === 0) {\n return ancestor;\n }\n }\n\n // If all ancestors have ancestors, recurse up\n const firstAncestor = [...ancestors][0];\n return firstAncestor ? findRootAncestor(firstAncestor, registry) : kind;\n}\n\n/**\n * Creates a uniqueness error.\n */\nexport function createUniquenessError(\n constraintName: string,\n kind: string,\n existingId: string,\n newId: string,\n fields: readonly string[],\n): UniquenessError {\n return new UniquenessError({\n constraintName,\n kind,\n existingId,\n newId,\n fields: [...fields],\n });\n}\n\n// ============================================================\n// Cardinality Validation\n// ============================================================\n\n/**\n * Checks if adding an edge would violate cardinality constraints.\n *\n * @param edgeKind - The edge kind being added\n * @param fromKind - The source node kind\n * @param fromId - The source node ID\n * @param cardinality - The cardinality constraint\n * @param existingEdgeCount - Number of existing edges of this kind from this source\n * @param hasActiveEdge - Whether there's an active (valid_to IS NULL) edge\n * @returns Error if violation, undefined if valid\n */\nexport function checkCardinality(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n cardinality: Cardinality,\n existingEdgeCount: number,\n hasActiveEdge: boolean,\n): CardinalityError | undefined {\n switch (cardinality) {\n case \"many\": {\n // No constraint\n return undefined;\n }\n case \"one\": {\n // At most one edge of this kind from any source node\n if (existingEdgeCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"one\",\n existingCount: existingEdgeCount,\n });\n }\n return undefined;\n }\n case \"unique\": {\n // unique is checked separately per (source, target) pair\n return undefined;\n }\n case \"oneActive\": {\n // At most one edge with valid_to IS NULL from any source\n if (hasActiveEdge) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"oneActive\",\n existingCount: 1,\n });\n }\n return undefined;\n }\n }\n}\n\n/**\n * Checks unique edge constraint (at most one edge between any source-target pair).\n */\nexport function checkUniqueEdge(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n _toKind: string,\n _toId: string,\n existingCount: number,\n): CardinalityError | undefined {\n if (existingCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"unique\",\n existingCount,\n });\n }\n return undefined;\n}\n\n// ============================================================\n// Endpoint Validation\n// ============================================================\n\n/**\n * Validates that an edge's endpoints are valid node kinds.\n */\nexport function validateEdgeEndpoints(\n edgeKind: string,\n fromKind: string,\n toKind: string,\n registration: EdgeRegistration,\n registry: KindRegistry,\n): EndpointError | undefined {\n // Check from kinds\n const validFromKinds = registration.from.map((node) => node.kind);\n if (!registry.isAssignableToAny(fromKind, validFromKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"from\",\n actualKind: fromKind,\n expectedKinds: validFromKinds,\n });\n }\n\n // Check to kinds\n const validToKinds = registration.to.map((node) => node.kind);\n if (!registry.isAssignableToAny(toKind, validToKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"to\",\n actualKind: toKind,\n expectedKinds: validToKinds,\n });\n }\n\n return undefined;\n}\n\n// ============================================================\n// Disjointness Validation\n// ============================================================\n\n/**\n * Checks if creating a node would violate disjointness constraints.\n *\n * @param nodeId - The node ID being created\n * @param nodeKind - The kind of the new node\n * @param existingKinds - Kinds of existing nodes with the same ID\n * @param registry - The kind registry for disjointness checks\n * @returns Error if disjoint violation, undefined if valid\n */\nexport function checkDisjointness(\n nodeId: string,\n nodeKind: string,\n existingKinds: readonly string[],\n registry: KindRegistry,\n): DisjointError | undefined {\n for (const existingKind of existingKinds) {\n if (registry.areDisjoint(nodeKind, existingKind)) {\n return new DisjointError({\n nodeId,\n attemptedKind: nodeKind,\n conflictingKind: existingKind,\n });\n }\n }\n return undefined;\n}\n\n/**\n * Gets all disjoint kinds for a given kind.\n */\nexport function getDisjointKinds(\n kind: string,\n registry: KindRegistry,\n): readonly string[] {\n return registry.getDisjointKinds(kind);\n}\n"]}
1
+ {"version":3,"sources":["../src/constraints/index.ts"],"names":["readOwnProperty","ConfigurationError","hasOwnKey","isPresent","CardinalityError","EndpointError","DisjointError"],"mappings":"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","file":"chunk-FQPEMEWX.cjs","sourcesContent":["/**\n * Constraint validation module.\n *\n * Provides validation functions for enforcing graph constraints:\n * - Uniqueness constraints on node properties\n * - Cardinality constraints on edges\n * - Endpoint type constraints on edges\n * - Disjointness constraints between node kinds\n */\n\n/**\n * Separator used between field values in composite unique keys.\n * Uses ASCII Record Separator (0x1E) — valid UTF-8 and safe for PostgreSQL\n * TEXT columns (unlike \\0 which PostgreSQL rejects).\n */\nconst UNIQUE_KEY_SEPARATOR = \"\\u001E\";\n\n/** Marker for undefined/null field values in unique keys. */\nconst UNIQUE_KEY_NULL_MARKER = \"\\u001F\"; // ASCII Unit Separator\nimport {\n type Cardinality,\n type Collation,\n type EdgeRegistration,\n type NullCheckOp,\n type UniqueConstraint,\n type UniquenessScope,\n} from \"../core/types\";\nimport {\n CardinalityError,\n ConfigurationError,\n DisjointError,\n EndpointError,\n UniquenessError,\n} from \"../errors\";\nimport { type KindRegistry } from \"../registry/kind-registry\";\nimport { hasOwnKey, readOwnProperty } from \"../utils/object\";\nimport { isPresent } from \"../utils/presence\";\n\n// ============================================================\n// Uniqueness Validation\n// ============================================================\n\n/**\n * Computes the unique key for a node's uniqueness constraint.\n *\n * The key is built by concatenating the specified field values,\n * optionally normalized for case-insensitive comparison.\n *\n * Field values are read by declared OWN key ({@link readOwnProperty}): a\n * constraint may name a field that a props bag does not carry (an absent\n * optional field), and a plain `props[field]` read would answer such a field\n * with the inherited `Object.prototype` member when the field is named after\n * one. A constraint over a field named `toString` then keyed on the inherited\n * function — `\"\"` under `binary` (the function stringified and dropped by\n * `JSON.stringify`) and a `TypeError` under `caseInsensitive` — instead of the\n * null marker every other absent value gets.\n */\nexport function computeUniqueKey(\n props: Record<string, unknown>,\n fields: readonly string[],\n collation: Collation,\n): string {\n const values = fields.map((field) => {\n const value = readOwnProperty(props, field);\n if (value === undefined || value === null) {\n return UNIQUE_KEY_NULL_MARKER;\n }\n // Convert to string, handling primitives safely\n const stringValue =\n typeof value === \"string\" ? value\n : typeof value === \"number\" || typeof value === \"boolean\" ?\n value.toString()\n : JSON.stringify(value);\n return collation === \"caseInsensitive\" ?\n stringValue.toLowerCase()\n : stringValue;\n });\n return values.join(UNIQUE_KEY_SEPARATOR);\n}\n\n/**\n * Checks if a uniqueness constraint's where predicate passes.\n *\n * A `where` callback that does not return a predicate is REFUSED here, not\n * treated as \"the constraint always applies\". The same malformed clause is a\n * hard `ConfigurationError` at definition time ({@link assertWhereFieldDeclared})\n * and at persistence time (`serializeWherePredicate`); a third reading that\n * silently widened a partial constraint to a total one would let the three\n * sites disagree about the same clause — the divergence\n * {@link captureWherePredicate} exists to prevent.\n *\n * The arm SHOULD be unreachable: `defineGraph` refuses a non-predicate callback\n * before any write can evaluate it, `validateGraphExtension` refuses the\n * document form, and a constraint reconstructed from a persisted schema carries\n * a callback this module built itself. It is reachable only by handing the\n * store a constraint object that never passed a definition gate — for which\n * failing loudly is the correct answer, since the alternative is enforcing\n * uniqueness over rows the author meant to exclude.\n */\nexport function checkWherePredicate(\n constraint: UniqueConstraint,\n props: Record<string, unknown>,\n): boolean {\n if (!constraint.where) {\n return true; // No where clause, always applies\n }\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" has a \\`where\\` callback that does not return a predicate.`,\n { constraintName: constraint.name, fields: [...constraint.fields] },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${constraint.fields[0] ?? \"someField\"}.isNotNull()\\`. A constraint built outside \\`defineGraph\\` bypasses the definition-time check that normally reports this.`,\n },\n );\n }\n\n return evaluatePredicate(predicate, props);\n}\n\ntype UniquePredicate = Readonly<{\n __type: \"unique_predicate\";\n field: string;\n op: NullCheckOp;\n}>;\n\n/**\n * The `where` callback as every caller of {@link captureWherePredicate} sees it:\n * a per-field builder in, whatever the author returned out.\n *\n * Deliberately looser than `UniqueConstraint[\"where\"]`, whose builder type is\n * generic in the kind's schema — the capture is the same operation whether the\n * callback came from a typed `defineGraph` registration, a compiled\n * graph-extension document, or an untyped JavaScript caller.\n */\ntype UniqueWhereCallback = (\n builder: Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n >,\n) => unknown;\n\n/**\n * Runs a `where` callback against the shared builder and returns the predicate\n * it named, or `undefined` when the callback returned something that is not a\n * predicate.\n *\n * The single owner of \"what does this `where` clause say\": constraint\n * EVALUATION ({@link checkWherePredicate}), definition-time VALIDATION\n * ({@link assertWhereFieldDeclared}), and persistence-time CAPTURE\n * (`serializeWherePredicate` in src/schema/serializer.ts) all read the clause\n * through this one function, so a persisted `where`, a validated `where`, and\n * an evaluated `where` cannot disagree about which field the author named.\n */\nexport function captureWherePredicate(\n where: UniqueWhereCallback,\n): UniquePredicate | undefined {\n const predicate = where(buildPredicateContext());\n if (\n typeof predicate !== \"object\" ||\n predicate === null ||\n !(\"__type\" in predicate)\n ) {\n return undefined;\n }\n\n const candidate = predicate as {\n __type: unknown;\n field: unknown;\n op: unknown;\n };\n if (\n candidate.__type !== \"unique_predicate\" ||\n typeof candidate.field !== \"string\" ||\n (candidate.op !== \"isNull\" && candidate.op !== \"isNotNull\")\n ) {\n return undefined;\n }\n\n return {\n __type: \"unique_predicate\",\n field: candidate.field,\n op: candidate.op,\n };\n}\n\n/**\n * Refuses a uniqueness constraint whose `where` clause names a field the kind\n * does not declare.\n *\n * The runtime half of the builder's guard. {@link buildPredicateContext} is\n * total by design — it must answer for a DECLARED-but-absent field, which is\n * the whole point of a partial constraint — so a typo'd name cannot be caught\n * there, and the type system catches it only for typed callers\n * (`UniqueConstraintPredicateBuilder` declares exactly the schema's fields and\n * has no index signature). An untyped caller naming an undeclared field\n * otherwise gets a predicate that quietly never applies.\n *\n * Called once per constraint at graph-definition time — the single point every\n * constraint passes through before any write can evaluate it — rather than at\n * each of the write paths' `checkWherePredicate` call sites, so the refusal\n * covers every path uniformly and costs nothing per write. Mirrors\n * `validateGraphExtension`'s `UNKNOWN_UNIQUE_WHERE_FIELD` refusal, which\n * already holds the same invariant for kinds declared as JSON documents.\n */\nexport function assertWhereFieldDeclared(\n kind: string,\n constraint: UniqueConstraint,\n shape: Readonly<Record<string, unknown>>,\n): void {\n if (!constraint.where) return;\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` callback that does not return a predicate.`,\n { kind, constraintName: constraint.name },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${Object.keys(shape)[0] ?? \"someField\"}.isNotNull()\\`.`,\n },\n );\n }\n\n if (!hasOwnKey(shape, predicate.field)) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` clause on field \"${predicate.field}\", which is not declared in the kind's schema.`,\n {\n kind,\n constraintName: constraint.name,\n field: predicate.field,\n declaredFields: Object.keys(shape),\n },\n {\n suggestion: `Name a declared field (${Object.keys(shape).join(\", \")}) or add \"${predicate.field}\" to the schema.`,\n },\n );\n }\n}\n\ntype PredicateContext = Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n>;\n\n/**\n * Builds the context a constraint's `where` callback names fields on.\n *\n * EVERY field name gets a member, because the builder type declares every\n * schema field as required (`-?` in `UniqueConstraintPredicateBuilder`) —\n * precisely so a partial constraint can ask whether an OPTIONAL field is\n * present. Populating the context from the props bag's own keys instead left a\n * declared-but-absent field with no member, and the callback's access then hit\n * whatever the context's prototype offered: `Object.prototype.toString` for a\n * field named `toString` (so naming it threw \"isNull is not a function\"), and\n * `undefined` for an ordinary field (so the everyday partial constraint over\n * `externalId` threw — \"Cannot read properties of undefined\", or \"Expected a\n * defined value\" through `requireDefined` — for every node written without it).\n *\n * Answering every name is safe because a name comes from the predicate author\n * (the code), never from data, and the field's VALUE is still read from the\n * props bag by own key when the predicate is evaluated — so an absent field\n * evaluates as null, which is what a partial constraint means by absent. Every\n * reader of a `where` clause goes through {@link captureWherePredicate}, which\n * builds this one context, so a persisted `where`, a validated `where`, and an\n * evaluated `where` cannot see different builders.\n *\n * The guard against a TYPO'D field name is NOT this Proxy — it must stay total\n * or a declared-but-absent field loses its member. It is\n * {@link assertWhereFieldDeclared}, which every constraint passes at\n * graph-definition time: an undeclared name is refused there with a typed\n * `ConfigurationError`, so no `where` clause naming one ever reaches\n * evaluation, from a typed or an untyped caller.\n */\nfunction buildPredicateContext(): PredicateContext {\n return new Proxy<PredicateContext>(\n {},\n {\n get(_target, property) {\n if (typeof property === \"symbol\") return;\n return {\n isNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNull\" as const,\n }),\n isNotNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNotNull\" as const,\n }),\n };\n },\n },\n );\n}\n\n/**\n * Evaluates a uniqueness predicate.\n *\n * Takes a CAPTURED predicate, not an `unknown`: the \"is this really a\n * predicate?\" question belongs to {@link captureWherePredicate}, which is its\n * single owner. The defensive `return true` arms this function used to carry\n * were a second, quieter answer to that question — and they answered it the\n * opposite way, widening a partial constraint into a total one where the owner\n * refuses.\n */\nfunction evaluatePredicate(\n pred: UniquePredicate,\n props: Record<string, unknown>,\n): boolean {\n // Own-key read: `pred.field` is a schema field name, and a props bag that\n // does not carry it must read as absent rather than as the inherited\n // `Object.prototype` member a field named after one would otherwise find\n // (which reads as present, inverting both `isNull` and `isNotNull`).\n const value = readOwnProperty(props, pred.field);\n if (pred.op === \"isNull\") {\n return value === null || value === undefined;\n }\n return isPresent(value);\n}\n\n/**\n * Gets all kinds that should be checked for a uniqueness constraint.\n *\n * For \"kindWithSubClasses\" scope, includes the entire subclass hierarchy:\n * - The kind itself\n * - All ancestors (parent classes)\n * - All descendants of those ancestors (sibling classes)\n *\n * For \"kind\" scope, only the specific kind.\n */\nexport function getKindsForUniquenessCheck(\n baseKind: string,\n scope: UniquenessScope,\n registry: KindRegistry,\n): readonly string[] {\n if (scope === \"kind\") {\n return [baseKind];\n }\n\n // Get the entire connected subclass hierarchy by finding the root ancestor\n const root = findRootAncestor(baseKind, registry);\n\n // Return the root and all its descendants (which includes baseKind and siblings)\n return registry.expandSubClasses(root);\n}\n\n/**\n * Finds the topmost ancestor of a kind, or the kind itself if it has no ancestors.\n */\nfunction findRootAncestor(kind: string, registry: KindRegistry): string {\n const ancestors = registry.getAncestors(kind);\n\n if (ancestors.size === 0) {\n return kind;\n }\n\n // Find an ancestor with no ancestors (the root)\n for (const ancestor of ancestors) {\n if (registry.getAncestors(ancestor).size === 0) {\n return ancestor;\n }\n }\n\n // If all ancestors have ancestors, recurse up\n const firstAncestor = [...ancestors][0];\n return firstAncestor ? findRootAncestor(firstAncestor, registry) : kind;\n}\n\n/**\n * Creates a uniqueness error.\n */\nexport function createUniquenessError(\n constraintName: string,\n kind: string,\n existingId: string,\n newId: string,\n fields: readonly string[],\n): UniquenessError {\n return new UniquenessError({\n constraintName,\n kind,\n existingId,\n newId,\n fields: [...fields],\n });\n}\n\n// ============================================================\n// Cardinality Validation\n// ============================================================\n\n/**\n * Checks if adding an edge would violate cardinality constraints.\n *\n * @param edgeKind - The edge kind being added\n * @param fromKind - The source node kind\n * @param fromId - The source node ID\n * @param cardinality - The cardinality constraint\n * @param existingEdgeCount - Number of existing edges of this kind from this source\n * @param hasActiveEdge - Whether there's an active (valid_to IS NULL) edge\n * @returns Error if violation, undefined if valid\n */\nexport function checkCardinality(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n cardinality: Cardinality,\n existingEdgeCount: number,\n hasActiveEdge: boolean,\n): CardinalityError | undefined {\n switch (cardinality) {\n case \"many\": {\n // No constraint\n return undefined;\n }\n case \"one\": {\n // At most one edge of this kind from any source node\n if (existingEdgeCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"one\",\n existingCount: existingEdgeCount,\n });\n }\n return undefined;\n }\n case \"unique\": {\n // unique is checked separately per (source, target) pair\n return undefined;\n }\n case \"oneActive\": {\n // At most one edge with valid_to IS NULL from any source\n if (hasActiveEdge) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"oneActive\",\n existingCount: 1,\n });\n }\n return undefined;\n }\n }\n}\n\n/**\n * Checks unique edge constraint (at most one edge between any source-target pair).\n */\nexport function checkUniqueEdge(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n _toKind: string,\n _toId: string,\n existingCount: number,\n): CardinalityError | undefined {\n if (existingCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"unique\",\n existingCount,\n });\n }\n return undefined;\n}\n\n// ============================================================\n// Endpoint Validation\n// ============================================================\n\n/**\n * Validates that an edge's endpoints are valid node kinds.\n */\nexport function validateEdgeEndpoints(\n edgeKind: string,\n fromKind: string,\n toKind: string,\n registration: EdgeRegistration,\n registry: KindRegistry,\n): EndpointError | undefined {\n // Check from kinds\n const validFromKinds = registration.from.map((node) => node.kind);\n if (!registry.isAssignableToAny(fromKind, validFromKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"from\",\n actualKind: fromKind,\n expectedKinds: validFromKinds,\n });\n }\n\n // Check to kinds\n const validToKinds = registration.to.map((node) => node.kind);\n if (!registry.isAssignableToAny(toKind, validToKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"to\",\n actualKind: toKind,\n expectedKinds: validToKinds,\n });\n }\n\n return undefined;\n}\n\n// ============================================================\n// Disjointness Validation\n// ============================================================\n\n/**\n * Checks if creating a node would violate disjointness constraints.\n *\n * @param nodeId - The node ID being created\n * @param nodeKind - The kind of the new node\n * @param existingKinds - Kinds of existing nodes with the same ID\n * @param registry - The kind registry for disjointness checks\n * @returns Error if disjoint violation, undefined if valid\n */\nexport function checkDisjointness(\n nodeId: string,\n nodeKind: string,\n existingKinds: readonly string[],\n registry: KindRegistry,\n): DisjointError | undefined {\n for (const existingKind of existingKinds) {\n if (registry.areDisjoint(nodeKind, existingKind)) {\n return new DisjointError({\n nodeId,\n attemptedKind: nodeKind,\n conflictingKind: existingKind,\n });\n }\n }\n return undefined;\n}\n\n/**\n * Gets all disjoint kinds for a given kind.\n */\nexport function getDisjointKinds(\n kind: string,\n registry: KindRegistry,\n): readonly string[] {\n return registry.getDisjointKinds(kind);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { ConfigurationError, CardinalityError, EndpointError, DisjointError } from './chunk-62ZXBMSD.js';
1
+ import { ConfigurationError, CardinalityError, EndpointError, DisjointError } from './chunk-ZLONH2UD.js';
2
2
  import { readOwnProperty, hasOwnKey, isPresent } from './chunk-DYATYRY4.js';
3
3
 
4
4
  // src/constraints/index.ts
@@ -203,5 +203,5 @@ function checkDisjointness(nodeId, nodeKind, existingKinds, registry) {
203
203
  }
204
204
 
205
205
  export { assertWhereFieldDeclared, captureWherePredicate, checkCardinality, checkDisjointness, checkUniqueEdge, checkWherePredicate, computeUniqueKey, getKindsForUniquenessCheck, validateEdgeEndpoints };
206
- //# sourceMappingURL=chunk-LNIWCQR4.js.map
207
- //# sourceMappingURL=chunk-LNIWCQR4.js.map
206
+ //# sourceMappingURL=chunk-GLHXM7C4.js.map
207
+ //# sourceMappingURL=chunk-GLHXM7C4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constraints/index.ts"],"names":[],"mappings":"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","file":"chunk-LNIWCQR4.js","sourcesContent":["/**\n * Constraint validation module.\n *\n * Provides validation functions for enforcing graph constraints:\n * - Uniqueness constraints on node properties\n * - Cardinality constraints on edges\n * - Endpoint type constraints on edges\n * - Disjointness constraints between node kinds\n */\n\n/**\n * Separator used between field values in composite unique keys.\n * Uses ASCII Record Separator (0x1E) — valid UTF-8 and safe for PostgreSQL\n * TEXT columns (unlike \\0 which PostgreSQL rejects).\n */\nconst UNIQUE_KEY_SEPARATOR = \"\\u001E\";\n\n/** Marker for undefined/null field values in unique keys. */\nconst UNIQUE_KEY_NULL_MARKER = \"\\u001F\"; // ASCII Unit Separator\nimport {\n type Cardinality,\n type Collation,\n type EdgeRegistration,\n type NullCheckOp,\n type UniqueConstraint,\n type UniquenessScope,\n} from \"../core/types\";\nimport {\n CardinalityError,\n ConfigurationError,\n DisjointError,\n EndpointError,\n UniquenessError,\n} from \"../errors\";\nimport { type KindRegistry } from \"../registry/kind-registry\";\nimport { hasOwnKey, readOwnProperty } from \"../utils/object\";\nimport { isPresent } from \"../utils/presence\";\n\n// ============================================================\n// Uniqueness Validation\n// ============================================================\n\n/**\n * Computes the unique key for a node's uniqueness constraint.\n *\n * The key is built by concatenating the specified field values,\n * optionally normalized for case-insensitive comparison.\n *\n * Field values are read by declared OWN key ({@link readOwnProperty}): a\n * constraint may name a field that a props bag does not carry (an absent\n * optional field), and a plain `props[field]` read would answer such a field\n * with the inherited `Object.prototype` member when the field is named after\n * one. A constraint over a field named `toString` then keyed on the inherited\n * function — `\"\"` under `binary` (the function stringified and dropped by\n * `JSON.stringify`) and a `TypeError` under `caseInsensitive` — instead of the\n * null marker every other absent value gets.\n */\nexport function computeUniqueKey(\n props: Record<string, unknown>,\n fields: readonly string[],\n collation: Collation,\n): string {\n const values = fields.map((field) => {\n const value = readOwnProperty(props, field);\n if (value === undefined || value === null) {\n return UNIQUE_KEY_NULL_MARKER;\n }\n // Convert to string, handling primitives safely\n const stringValue =\n typeof value === \"string\" ? value\n : typeof value === \"number\" || typeof value === \"boolean\" ?\n value.toString()\n : JSON.stringify(value);\n return collation === \"caseInsensitive\" ?\n stringValue.toLowerCase()\n : stringValue;\n });\n return values.join(UNIQUE_KEY_SEPARATOR);\n}\n\n/**\n * Checks if a uniqueness constraint's where predicate passes.\n *\n * A `where` callback that does not return a predicate is REFUSED here, not\n * treated as \"the constraint always applies\". The same malformed clause is a\n * hard `ConfigurationError` at definition time ({@link assertWhereFieldDeclared})\n * and at persistence time (`serializeWherePredicate`); a third reading that\n * silently widened a partial constraint to a total one would let the three\n * sites disagree about the same clause — the divergence\n * {@link captureWherePredicate} exists to prevent.\n *\n * The arm SHOULD be unreachable: `defineGraph` refuses a non-predicate callback\n * before any write can evaluate it, `validateGraphExtension` refuses the\n * document form, and a constraint reconstructed from a persisted schema carries\n * a callback this module built itself. It is reachable only by handing the\n * store a constraint object that never passed a definition gate — for which\n * failing loudly is the correct answer, since the alternative is enforcing\n * uniqueness over rows the author meant to exclude.\n */\nexport function checkWherePredicate(\n constraint: UniqueConstraint,\n props: Record<string, unknown>,\n): boolean {\n if (!constraint.where) {\n return true; // No where clause, always applies\n }\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" has a \\`where\\` callback that does not return a predicate.`,\n { constraintName: constraint.name, fields: [...constraint.fields] },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${constraint.fields[0] ?? \"someField\"}.isNotNull()\\`. A constraint built outside \\`defineGraph\\` bypasses the definition-time check that normally reports this.`,\n },\n );\n }\n\n return evaluatePredicate(predicate, props);\n}\n\ntype UniquePredicate = Readonly<{\n __type: \"unique_predicate\";\n field: string;\n op: NullCheckOp;\n}>;\n\n/**\n * The `where` callback as every caller of {@link captureWherePredicate} sees it:\n * a per-field builder in, whatever the author returned out.\n *\n * Deliberately looser than `UniqueConstraint[\"where\"]`, whose builder type is\n * generic in the kind's schema — the capture is the same operation whether the\n * callback came from a typed `defineGraph` registration, a compiled\n * graph-extension document, or an untyped JavaScript caller.\n */\ntype UniqueWhereCallback = (\n builder: Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n >,\n) => unknown;\n\n/**\n * Runs a `where` callback against the shared builder and returns the predicate\n * it named, or `undefined` when the callback returned something that is not a\n * predicate.\n *\n * The single owner of \"what does this `where` clause say\": constraint\n * EVALUATION ({@link checkWherePredicate}), definition-time VALIDATION\n * ({@link assertWhereFieldDeclared}), and persistence-time CAPTURE\n * (`serializeWherePredicate` in src/schema/serializer.ts) all read the clause\n * through this one function, so a persisted `where`, a validated `where`, and\n * an evaluated `where` cannot disagree about which field the author named.\n */\nexport function captureWherePredicate(\n where: UniqueWhereCallback,\n): UniquePredicate | undefined {\n const predicate = where(buildPredicateContext());\n if (\n typeof predicate !== \"object\" ||\n predicate === null ||\n !(\"__type\" in predicate)\n ) {\n return undefined;\n }\n\n const candidate = predicate as {\n __type: unknown;\n field: unknown;\n op: unknown;\n };\n if (\n candidate.__type !== \"unique_predicate\" ||\n typeof candidate.field !== \"string\" ||\n (candidate.op !== \"isNull\" && candidate.op !== \"isNotNull\")\n ) {\n return undefined;\n }\n\n return {\n __type: \"unique_predicate\",\n field: candidate.field,\n op: candidate.op,\n };\n}\n\n/**\n * Refuses a uniqueness constraint whose `where` clause names a field the kind\n * does not declare.\n *\n * The runtime half of the builder's guard. {@link buildPredicateContext} is\n * total by design — it must answer for a DECLARED-but-absent field, which is\n * the whole point of a partial constraint — so a typo'd name cannot be caught\n * there, and the type system catches it only for typed callers\n * (`UniqueConstraintPredicateBuilder` declares exactly the schema's fields and\n * has no index signature). An untyped caller naming an undeclared field\n * otherwise gets a predicate that quietly never applies.\n *\n * Called once per constraint at graph-definition time — the single point every\n * constraint passes through before any write can evaluate it — rather than at\n * each of the write paths' `checkWherePredicate` call sites, so the refusal\n * covers every path uniformly and costs nothing per write. Mirrors\n * `validateGraphExtension`'s `UNKNOWN_UNIQUE_WHERE_FIELD` refusal, which\n * already holds the same invariant for kinds declared as JSON documents.\n */\nexport function assertWhereFieldDeclared(\n kind: string,\n constraint: UniqueConstraint,\n shape: Readonly<Record<string, unknown>>,\n): void {\n if (!constraint.where) return;\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` callback that does not return a predicate.`,\n { kind, constraintName: constraint.name },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${Object.keys(shape)[0] ?? \"someField\"}.isNotNull()\\`.`,\n },\n );\n }\n\n if (!hasOwnKey(shape, predicate.field)) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` clause on field \"${predicate.field}\", which is not declared in the kind's schema.`,\n {\n kind,\n constraintName: constraint.name,\n field: predicate.field,\n declaredFields: Object.keys(shape),\n },\n {\n suggestion: `Name a declared field (${Object.keys(shape).join(\", \")}) or add \"${predicate.field}\" to the schema.`,\n },\n );\n }\n}\n\ntype PredicateContext = Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n>;\n\n/**\n * Builds the context a constraint's `where` callback names fields on.\n *\n * EVERY field name gets a member, because the builder type declares every\n * schema field as required (`-?` in `UniqueConstraintPredicateBuilder`) —\n * precisely so a partial constraint can ask whether an OPTIONAL field is\n * present. Populating the context from the props bag's own keys instead left a\n * declared-but-absent field with no member, and the callback's access then hit\n * whatever the context's prototype offered: `Object.prototype.toString` for a\n * field named `toString` (so naming it threw \"isNull is not a function\"), and\n * `undefined` for an ordinary field (so the everyday partial constraint over\n * `externalId` threw — \"Cannot read properties of undefined\", or \"Expected a\n * defined value\" through `requireDefined` — for every node written without it).\n *\n * Answering every name is safe because a name comes from the predicate author\n * (the code), never from data, and the field's VALUE is still read from the\n * props bag by own key when the predicate is evaluated — so an absent field\n * evaluates as null, which is what a partial constraint means by absent. Every\n * reader of a `where` clause goes through {@link captureWherePredicate}, which\n * builds this one context, so a persisted `where`, a validated `where`, and an\n * evaluated `where` cannot see different builders.\n *\n * The guard against a TYPO'D field name is NOT this Proxy — it must stay total\n * or a declared-but-absent field loses its member. It is\n * {@link assertWhereFieldDeclared}, which every constraint passes at\n * graph-definition time: an undeclared name is refused there with a typed\n * `ConfigurationError`, so no `where` clause naming one ever reaches\n * evaluation, from a typed or an untyped caller.\n */\nfunction buildPredicateContext(): PredicateContext {\n return new Proxy<PredicateContext>(\n {},\n {\n get(_target, property) {\n if (typeof property === \"symbol\") return;\n return {\n isNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNull\" as const,\n }),\n isNotNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNotNull\" as const,\n }),\n };\n },\n },\n );\n}\n\n/**\n * Evaluates a uniqueness predicate.\n *\n * Takes a CAPTURED predicate, not an `unknown`: the \"is this really a\n * predicate?\" question belongs to {@link captureWherePredicate}, which is its\n * single owner. The defensive `return true` arms this function used to carry\n * were a second, quieter answer to that question — and they answered it the\n * opposite way, widening a partial constraint into a total one where the owner\n * refuses.\n */\nfunction evaluatePredicate(\n pred: UniquePredicate,\n props: Record<string, unknown>,\n): boolean {\n // Own-key read: `pred.field` is a schema field name, and a props bag that\n // does not carry it must read as absent rather than as the inherited\n // `Object.prototype` member a field named after one would otherwise find\n // (which reads as present, inverting both `isNull` and `isNotNull`).\n const value = readOwnProperty(props, pred.field);\n if (pred.op === \"isNull\") {\n return value === null || value === undefined;\n }\n return isPresent(value);\n}\n\n/**\n * Gets all kinds that should be checked for a uniqueness constraint.\n *\n * For \"kindWithSubClasses\" scope, includes the entire subclass hierarchy:\n * - The kind itself\n * - All ancestors (parent classes)\n * - All descendants of those ancestors (sibling classes)\n *\n * For \"kind\" scope, only the specific kind.\n */\nexport function getKindsForUniquenessCheck(\n baseKind: string,\n scope: UniquenessScope,\n registry: KindRegistry,\n): readonly string[] {\n if (scope === \"kind\") {\n return [baseKind];\n }\n\n // Get the entire connected subclass hierarchy by finding the root ancestor\n const root = findRootAncestor(baseKind, registry);\n\n // Return the root and all its descendants (which includes baseKind and siblings)\n return registry.expandSubClasses(root);\n}\n\n/**\n * Finds the topmost ancestor of a kind, or the kind itself if it has no ancestors.\n */\nfunction findRootAncestor(kind: string, registry: KindRegistry): string {\n const ancestors = registry.getAncestors(kind);\n\n if (ancestors.size === 0) {\n return kind;\n }\n\n // Find an ancestor with no ancestors (the root)\n for (const ancestor of ancestors) {\n if (registry.getAncestors(ancestor).size === 0) {\n return ancestor;\n }\n }\n\n // If all ancestors have ancestors, recurse up\n const firstAncestor = [...ancestors][0];\n return firstAncestor ? findRootAncestor(firstAncestor, registry) : kind;\n}\n\n/**\n * Creates a uniqueness error.\n */\nexport function createUniquenessError(\n constraintName: string,\n kind: string,\n existingId: string,\n newId: string,\n fields: readonly string[],\n): UniquenessError {\n return new UniquenessError({\n constraintName,\n kind,\n existingId,\n newId,\n fields: [...fields],\n });\n}\n\n// ============================================================\n// Cardinality Validation\n// ============================================================\n\n/**\n * Checks if adding an edge would violate cardinality constraints.\n *\n * @param edgeKind - The edge kind being added\n * @param fromKind - The source node kind\n * @param fromId - The source node ID\n * @param cardinality - The cardinality constraint\n * @param existingEdgeCount - Number of existing edges of this kind from this source\n * @param hasActiveEdge - Whether there's an active (valid_to IS NULL) edge\n * @returns Error if violation, undefined if valid\n */\nexport function checkCardinality(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n cardinality: Cardinality,\n existingEdgeCount: number,\n hasActiveEdge: boolean,\n): CardinalityError | undefined {\n switch (cardinality) {\n case \"many\": {\n // No constraint\n return undefined;\n }\n case \"one\": {\n // At most one edge of this kind from any source node\n if (existingEdgeCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"one\",\n existingCount: existingEdgeCount,\n });\n }\n return undefined;\n }\n case \"unique\": {\n // unique is checked separately per (source, target) pair\n return undefined;\n }\n case \"oneActive\": {\n // At most one edge with valid_to IS NULL from any source\n if (hasActiveEdge) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"oneActive\",\n existingCount: 1,\n });\n }\n return undefined;\n }\n }\n}\n\n/**\n * Checks unique edge constraint (at most one edge between any source-target pair).\n */\nexport function checkUniqueEdge(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n _toKind: string,\n _toId: string,\n existingCount: number,\n): CardinalityError | undefined {\n if (existingCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"unique\",\n existingCount,\n });\n }\n return undefined;\n}\n\n// ============================================================\n// Endpoint Validation\n// ============================================================\n\n/**\n * Validates that an edge's endpoints are valid node kinds.\n */\nexport function validateEdgeEndpoints(\n edgeKind: string,\n fromKind: string,\n toKind: string,\n registration: EdgeRegistration,\n registry: KindRegistry,\n): EndpointError | undefined {\n // Check from kinds\n const validFromKinds = registration.from.map((node) => node.kind);\n if (!registry.isAssignableToAny(fromKind, validFromKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"from\",\n actualKind: fromKind,\n expectedKinds: validFromKinds,\n });\n }\n\n // Check to kinds\n const validToKinds = registration.to.map((node) => node.kind);\n if (!registry.isAssignableToAny(toKind, validToKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"to\",\n actualKind: toKind,\n expectedKinds: validToKinds,\n });\n }\n\n return undefined;\n}\n\n// ============================================================\n// Disjointness Validation\n// ============================================================\n\n/**\n * Checks if creating a node would violate disjointness constraints.\n *\n * @param nodeId - The node ID being created\n * @param nodeKind - The kind of the new node\n * @param existingKinds - Kinds of existing nodes with the same ID\n * @param registry - The kind registry for disjointness checks\n * @returns Error if disjoint violation, undefined if valid\n */\nexport function checkDisjointness(\n nodeId: string,\n nodeKind: string,\n existingKinds: readonly string[],\n registry: KindRegistry,\n): DisjointError | undefined {\n for (const existingKind of existingKinds) {\n if (registry.areDisjoint(nodeKind, existingKind)) {\n return new DisjointError({\n nodeId,\n attemptedKind: nodeKind,\n conflictingKind: existingKind,\n });\n }\n }\n return undefined;\n}\n\n/**\n * Gets all disjoint kinds for a given kind.\n */\nexport function getDisjointKinds(\n kind: string,\n registry: KindRegistry,\n): readonly string[] {\n return registry.getDisjointKinds(kind);\n}\n"]}
1
+ {"version":3,"sources":["../src/constraints/index.ts"],"names":[],"mappings":"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","file":"chunk-GLHXM7C4.js","sourcesContent":["/**\n * Constraint validation module.\n *\n * Provides validation functions for enforcing graph constraints:\n * - Uniqueness constraints on node properties\n * - Cardinality constraints on edges\n * - Endpoint type constraints on edges\n * - Disjointness constraints between node kinds\n */\n\n/**\n * Separator used between field values in composite unique keys.\n * Uses ASCII Record Separator (0x1E) — valid UTF-8 and safe for PostgreSQL\n * TEXT columns (unlike \\0 which PostgreSQL rejects).\n */\nconst UNIQUE_KEY_SEPARATOR = \"\\u001E\";\n\n/** Marker for undefined/null field values in unique keys. */\nconst UNIQUE_KEY_NULL_MARKER = \"\\u001F\"; // ASCII Unit Separator\nimport {\n type Cardinality,\n type Collation,\n type EdgeRegistration,\n type NullCheckOp,\n type UniqueConstraint,\n type UniquenessScope,\n} from \"../core/types\";\nimport {\n CardinalityError,\n ConfigurationError,\n DisjointError,\n EndpointError,\n UniquenessError,\n} from \"../errors\";\nimport { type KindRegistry } from \"../registry/kind-registry\";\nimport { hasOwnKey, readOwnProperty } from \"../utils/object\";\nimport { isPresent } from \"../utils/presence\";\n\n// ============================================================\n// Uniqueness Validation\n// ============================================================\n\n/**\n * Computes the unique key for a node's uniqueness constraint.\n *\n * The key is built by concatenating the specified field values,\n * optionally normalized for case-insensitive comparison.\n *\n * Field values are read by declared OWN key ({@link readOwnProperty}): a\n * constraint may name a field that a props bag does not carry (an absent\n * optional field), and a plain `props[field]` read would answer such a field\n * with the inherited `Object.prototype` member when the field is named after\n * one. A constraint over a field named `toString` then keyed on the inherited\n * function — `\"\"` under `binary` (the function stringified and dropped by\n * `JSON.stringify`) and a `TypeError` under `caseInsensitive` — instead of the\n * null marker every other absent value gets.\n */\nexport function computeUniqueKey(\n props: Record<string, unknown>,\n fields: readonly string[],\n collation: Collation,\n): string {\n const values = fields.map((field) => {\n const value = readOwnProperty(props, field);\n if (value === undefined || value === null) {\n return UNIQUE_KEY_NULL_MARKER;\n }\n // Convert to string, handling primitives safely\n const stringValue =\n typeof value === \"string\" ? value\n : typeof value === \"number\" || typeof value === \"boolean\" ?\n value.toString()\n : JSON.stringify(value);\n return collation === \"caseInsensitive\" ?\n stringValue.toLowerCase()\n : stringValue;\n });\n return values.join(UNIQUE_KEY_SEPARATOR);\n}\n\n/**\n * Checks if a uniqueness constraint's where predicate passes.\n *\n * A `where` callback that does not return a predicate is REFUSED here, not\n * treated as \"the constraint always applies\". The same malformed clause is a\n * hard `ConfigurationError` at definition time ({@link assertWhereFieldDeclared})\n * and at persistence time (`serializeWherePredicate`); a third reading that\n * silently widened a partial constraint to a total one would let the three\n * sites disagree about the same clause — the divergence\n * {@link captureWherePredicate} exists to prevent.\n *\n * The arm SHOULD be unreachable: `defineGraph` refuses a non-predicate callback\n * before any write can evaluate it, `validateGraphExtension` refuses the\n * document form, and a constraint reconstructed from a persisted schema carries\n * a callback this module built itself. It is reachable only by handing the\n * store a constraint object that never passed a definition gate — for which\n * failing loudly is the correct answer, since the alternative is enforcing\n * uniqueness over rows the author meant to exclude.\n */\nexport function checkWherePredicate(\n constraint: UniqueConstraint,\n props: Record<string, unknown>,\n): boolean {\n if (!constraint.where) {\n return true; // No where clause, always applies\n }\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" has a \\`where\\` callback that does not return a predicate.`,\n { constraintName: constraint.name, fields: [...constraint.fields] },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${constraint.fields[0] ?? \"someField\"}.isNotNull()\\`. A constraint built outside \\`defineGraph\\` bypasses the definition-time check that normally reports this.`,\n },\n );\n }\n\n return evaluatePredicate(predicate, props);\n}\n\ntype UniquePredicate = Readonly<{\n __type: \"unique_predicate\";\n field: string;\n op: NullCheckOp;\n}>;\n\n/**\n * The `where` callback as every caller of {@link captureWherePredicate} sees it:\n * a per-field builder in, whatever the author returned out.\n *\n * Deliberately looser than `UniqueConstraint[\"where\"]`, whose builder type is\n * generic in the kind's schema — the capture is the same operation whether the\n * callback came from a typed `defineGraph` registration, a compiled\n * graph-extension document, or an untyped JavaScript caller.\n */\ntype UniqueWhereCallback = (\n builder: Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n >,\n) => unknown;\n\n/**\n * Runs a `where` callback against the shared builder and returns the predicate\n * it named, or `undefined` when the callback returned something that is not a\n * predicate.\n *\n * The single owner of \"what does this `where` clause say\": constraint\n * EVALUATION ({@link checkWherePredicate}), definition-time VALIDATION\n * ({@link assertWhereFieldDeclared}), and persistence-time CAPTURE\n * (`serializeWherePredicate` in src/schema/serializer.ts) all read the clause\n * through this one function, so a persisted `where`, a validated `where`, and\n * an evaluated `where` cannot disagree about which field the author named.\n */\nexport function captureWherePredicate(\n where: UniqueWhereCallback,\n): UniquePredicate | undefined {\n const predicate = where(buildPredicateContext());\n if (\n typeof predicate !== \"object\" ||\n predicate === null ||\n !(\"__type\" in predicate)\n ) {\n return undefined;\n }\n\n const candidate = predicate as {\n __type: unknown;\n field: unknown;\n op: unknown;\n };\n if (\n candidate.__type !== \"unique_predicate\" ||\n typeof candidate.field !== \"string\" ||\n (candidate.op !== \"isNull\" && candidate.op !== \"isNotNull\")\n ) {\n return undefined;\n }\n\n return {\n __type: \"unique_predicate\",\n field: candidate.field,\n op: candidate.op,\n };\n}\n\n/**\n * Refuses a uniqueness constraint whose `where` clause names a field the kind\n * does not declare.\n *\n * The runtime half of the builder's guard. {@link buildPredicateContext} is\n * total by design — it must answer for a DECLARED-but-absent field, which is\n * the whole point of a partial constraint — so a typo'd name cannot be caught\n * there, and the type system catches it only for typed callers\n * (`UniqueConstraintPredicateBuilder` declares exactly the schema's fields and\n * has no index signature). An untyped caller naming an undeclared field\n * otherwise gets a predicate that quietly never applies.\n *\n * Called once per constraint at graph-definition time — the single point every\n * constraint passes through before any write can evaluate it — rather than at\n * each of the write paths' `checkWherePredicate` call sites, so the refusal\n * covers every path uniformly and costs nothing per write. Mirrors\n * `validateGraphExtension`'s `UNKNOWN_UNIQUE_WHERE_FIELD` refusal, which\n * already holds the same invariant for kinds declared as JSON documents.\n */\nexport function assertWhereFieldDeclared(\n kind: string,\n constraint: UniqueConstraint,\n shape: Readonly<Record<string, unknown>>,\n): void {\n if (!constraint.where) return;\n\n const predicate = captureWherePredicate(constraint.where);\n if (predicate === undefined) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` callback that does not return a predicate.`,\n { kind, constraintName: constraint.name },\n {\n suggestion: `Return a field predicate, e.g. \\`where: (fields) => fields.${Object.keys(shape)[0] ?? \"someField\"}.isNotNull()\\`.`,\n },\n );\n }\n\n if (!hasOwnKey(shape, predicate.field)) {\n throw new ConfigurationError(\n `Unique constraint \"${constraint.name}\" on node kind \"${kind}\" has a \\`where\\` clause on field \"${predicate.field}\", which is not declared in the kind's schema.`,\n {\n kind,\n constraintName: constraint.name,\n field: predicate.field,\n declaredFields: Object.keys(shape),\n },\n {\n suggestion: `Name a declared field (${Object.keys(shape).join(\", \")}) or add \"${predicate.field}\" to the schema.`,\n },\n );\n }\n}\n\ntype PredicateContext = Readonly<\n Record<\n string,\n Readonly<{\n isNull: () => UniquePredicate;\n isNotNull: () => UniquePredicate;\n }>\n >\n>;\n\n/**\n * Builds the context a constraint's `where` callback names fields on.\n *\n * EVERY field name gets a member, because the builder type declares every\n * schema field as required (`-?` in `UniqueConstraintPredicateBuilder`) —\n * precisely so a partial constraint can ask whether an OPTIONAL field is\n * present. Populating the context from the props bag's own keys instead left a\n * declared-but-absent field with no member, and the callback's access then hit\n * whatever the context's prototype offered: `Object.prototype.toString` for a\n * field named `toString` (so naming it threw \"isNull is not a function\"), and\n * `undefined` for an ordinary field (so the everyday partial constraint over\n * `externalId` threw — \"Cannot read properties of undefined\", or \"Expected a\n * defined value\" through `requireDefined` — for every node written without it).\n *\n * Answering every name is safe because a name comes from the predicate author\n * (the code), never from data, and the field's VALUE is still read from the\n * props bag by own key when the predicate is evaluated — so an absent field\n * evaluates as null, which is what a partial constraint means by absent. Every\n * reader of a `where` clause goes through {@link captureWherePredicate}, which\n * builds this one context, so a persisted `where`, a validated `where`, and an\n * evaluated `where` cannot see different builders.\n *\n * The guard against a TYPO'D field name is NOT this Proxy — it must stay total\n * or a declared-but-absent field loses its member. It is\n * {@link assertWhereFieldDeclared}, which every constraint passes at\n * graph-definition time: an undeclared name is refused there with a typed\n * `ConfigurationError`, so no `where` clause naming one ever reaches\n * evaluation, from a typed or an untyped caller.\n */\nfunction buildPredicateContext(): PredicateContext {\n return new Proxy<PredicateContext>(\n {},\n {\n get(_target, property) {\n if (typeof property === \"symbol\") return;\n return {\n isNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNull\" as const,\n }),\n isNotNull: () => ({\n __type: \"unique_predicate\" as const,\n field: property,\n op: \"isNotNull\" as const,\n }),\n };\n },\n },\n );\n}\n\n/**\n * Evaluates a uniqueness predicate.\n *\n * Takes a CAPTURED predicate, not an `unknown`: the \"is this really a\n * predicate?\" question belongs to {@link captureWherePredicate}, which is its\n * single owner. The defensive `return true` arms this function used to carry\n * were a second, quieter answer to that question — and they answered it the\n * opposite way, widening a partial constraint into a total one where the owner\n * refuses.\n */\nfunction evaluatePredicate(\n pred: UniquePredicate,\n props: Record<string, unknown>,\n): boolean {\n // Own-key read: `pred.field` is a schema field name, and a props bag that\n // does not carry it must read as absent rather than as the inherited\n // `Object.prototype` member a field named after one would otherwise find\n // (which reads as present, inverting both `isNull` and `isNotNull`).\n const value = readOwnProperty(props, pred.field);\n if (pred.op === \"isNull\") {\n return value === null || value === undefined;\n }\n return isPresent(value);\n}\n\n/**\n * Gets all kinds that should be checked for a uniqueness constraint.\n *\n * For \"kindWithSubClasses\" scope, includes the entire subclass hierarchy:\n * - The kind itself\n * - All ancestors (parent classes)\n * - All descendants of those ancestors (sibling classes)\n *\n * For \"kind\" scope, only the specific kind.\n */\nexport function getKindsForUniquenessCheck(\n baseKind: string,\n scope: UniquenessScope,\n registry: KindRegistry,\n): readonly string[] {\n if (scope === \"kind\") {\n return [baseKind];\n }\n\n // Get the entire connected subclass hierarchy by finding the root ancestor\n const root = findRootAncestor(baseKind, registry);\n\n // Return the root and all its descendants (which includes baseKind and siblings)\n return registry.expandSubClasses(root);\n}\n\n/**\n * Finds the topmost ancestor of a kind, or the kind itself if it has no ancestors.\n */\nfunction findRootAncestor(kind: string, registry: KindRegistry): string {\n const ancestors = registry.getAncestors(kind);\n\n if (ancestors.size === 0) {\n return kind;\n }\n\n // Find an ancestor with no ancestors (the root)\n for (const ancestor of ancestors) {\n if (registry.getAncestors(ancestor).size === 0) {\n return ancestor;\n }\n }\n\n // If all ancestors have ancestors, recurse up\n const firstAncestor = [...ancestors][0];\n return firstAncestor ? findRootAncestor(firstAncestor, registry) : kind;\n}\n\n/**\n * Creates a uniqueness error.\n */\nexport function createUniquenessError(\n constraintName: string,\n kind: string,\n existingId: string,\n newId: string,\n fields: readonly string[],\n): UniquenessError {\n return new UniquenessError({\n constraintName,\n kind,\n existingId,\n newId,\n fields: [...fields],\n });\n}\n\n// ============================================================\n// Cardinality Validation\n// ============================================================\n\n/**\n * Checks if adding an edge would violate cardinality constraints.\n *\n * @param edgeKind - The edge kind being added\n * @param fromKind - The source node kind\n * @param fromId - The source node ID\n * @param cardinality - The cardinality constraint\n * @param existingEdgeCount - Number of existing edges of this kind from this source\n * @param hasActiveEdge - Whether there's an active (valid_to IS NULL) edge\n * @returns Error if violation, undefined if valid\n */\nexport function checkCardinality(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n cardinality: Cardinality,\n existingEdgeCount: number,\n hasActiveEdge: boolean,\n): CardinalityError | undefined {\n switch (cardinality) {\n case \"many\": {\n // No constraint\n return undefined;\n }\n case \"one\": {\n // At most one edge of this kind from any source node\n if (existingEdgeCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"one\",\n existingCount: existingEdgeCount,\n });\n }\n return undefined;\n }\n case \"unique\": {\n // unique is checked separately per (source, target) pair\n return undefined;\n }\n case \"oneActive\": {\n // At most one edge with valid_to IS NULL from any source\n if (hasActiveEdge) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"oneActive\",\n existingCount: 1,\n });\n }\n return undefined;\n }\n }\n}\n\n/**\n * Checks unique edge constraint (at most one edge between any source-target pair).\n */\nexport function checkUniqueEdge(\n edgeKind: string,\n fromKind: string,\n fromId: string,\n _toKind: string,\n _toId: string,\n existingCount: number,\n): CardinalityError | undefined {\n if (existingCount > 0) {\n return new CardinalityError({\n edgeKind,\n fromKind,\n fromId,\n cardinality: \"unique\",\n existingCount,\n });\n }\n return undefined;\n}\n\n// ============================================================\n// Endpoint Validation\n// ============================================================\n\n/**\n * Validates that an edge's endpoints are valid node kinds.\n */\nexport function validateEdgeEndpoints(\n edgeKind: string,\n fromKind: string,\n toKind: string,\n registration: EdgeRegistration,\n registry: KindRegistry,\n): EndpointError | undefined {\n // Check from kinds\n const validFromKinds = registration.from.map((node) => node.kind);\n if (!registry.isAssignableToAny(fromKind, validFromKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"from\",\n actualKind: fromKind,\n expectedKinds: validFromKinds,\n });\n }\n\n // Check to kinds\n const validToKinds = registration.to.map((node) => node.kind);\n if (!registry.isAssignableToAny(toKind, validToKinds)) {\n return new EndpointError({\n edgeKind,\n endpoint: \"to\",\n actualKind: toKind,\n expectedKinds: validToKinds,\n });\n }\n\n return undefined;\n}\n\n// ============================================================\n// Disjointness Validation\n// ============================================================\n\n/**\n * Checks if creating a node would violate disjointness constraints.\n *\n * @param nodeId - The node ID being created\n * @param nodeKind - The kind of the new node\n * @param existingKinds - Kinds of existing nodes with the same ID\n * @param registry - The kind registry for disjointness checks\n * @returns Error if disjoint violation, undefined if valid\n */\nexport function checkDisjointness(\n nodeId: string,\n nodeKind: string,\n existingKinds: readonly string[],\n registry: KindRegistry,\n): DisjointError | undefined {\n for (const existingKind of existingKinds) {\n if (registry.areDisjoint(nodeKind, existingKind)) {\n return new DisjointError({\n nodeId,\n attemptedKind: nodeKind,\n conflictingKind: existingKind,\n });\n }\n }\n return undefined;\n}\n\n/**\n * Gets all disjoint kinds for a given kind.\n */\nexport function getDisjointKinds(\n kind: string,\n registry: KindRegistry,\n): readonly string[] {\n return registry.getDisjointKinds(kind);\n}\n"]}