@nicia-ai/typegraph 0.24.1 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/backend/postgres/index.cjs +226 -55
  2. package/dist/backend/postgres/index.cjs.map +1 -1
  3. package/dist/backend/postgres/index.d.cts +6 -7
  4. package/dist/backend/postgres/index.d.ts +6 -7
  5. package/dist/backend/postgres/index.js +195 -28
  6. package/dist/backend/postgres/index.js.map +1 -1
  7. package/dist/backend/sqlite/index.cjs +19 -17
  8. package/dist/backend/sqlite/index.d.cts +6 -7
  9. package/dist/backend/sqlite/index.d.ts +6 -7
  10. package/dist/backend/sqlite/index.js +9 -7
  11. package/dist/backend/sqlite/libsql.cjs +12 -10
  12. package/dist/backend/sqlite/libsql.cjs.map +1 -1
  13. package/dist/backend/sqlite/libsql.d.cts +4 -5
  14. package/dist/backend/sqlite/libsql.d.ts +4 -5
  15. package/dist/backend/sqlite/libsql.js +9 -7
  16. package/dist/backend/sqlite/libsql.js.map +1 -1
  17. package/dist/backend/sqlite/local.cjs +14 -12
  18. package/dist/backend/sqlite/local.cjs.map +1 -1
  19. package/dist/backend/sqlite/local.d.cts +4 -5
  20. package/dist/backend/sqlite/local.d.ts +4 -5
  21. package/dist/backend/sqlite/local.js +9 -7
  22. package/dist/backend/sqlite/local.js.map +1 -1
  23. package/dist/chunk-4BOWVUGQ.js +2029 -0
  24. package/dist/chunk-4BOWVUGQ.js.map +1 -0
  25. package/dist/chunk-7V335GHG.cjs +112 -0
  26. package/dist/chunk-7V335GHG.cjs.map +1 -0
  27. package/dist/chunk-AAA2CR3P.js +2628 -0
  28. package/dist/chunk-AAA2CR3P.js.map +1 -0
  29. package/dist/{chunk-QOLTW7OZ.js → chunk-CLEUFN2K.js} +195 -13
  30. package/dist/chunk-CLEUFN2K.js.map +1 -0
  31. package/dist/{chunk-OVJ2BE5Q.cjs → chunk-CLGC7AQ2.cjs} +215 -33
  32. package/dist/chunk-CLGC7AQ2.cjs.map +1 -0
  33. package/dist/{chunk-GUTQTMOV.js → chunk-CPFR3O7L.js} +2 -2
  34. package/dist/chunk-CPFR3O7L.js.map +1 -0
  35. package/dist/{chunk-5HVDOPZU.cjs → chunk-CQVNGKU7.cjs} +452 -104
  36. package/dist/chunk-CQVNGKU7.cjs.map +1 -0
  37. package/dist/chunk-CTHNVU6K.cjs +551 -0
  38. package/dist/chunk-CTHNVU6K.cjs.map +1 -0
  39. package/dist/chunk-D2GO3RBL.cjs +12 -0
  40. package/dist/chunk-D2GO3RBL.cjs.map +1 -0
  41. package/dist/{chunk-WFMTAEEN.js → chunk-DOTEN2FG.js} +81 -7
  42. package/dist/chunk-DOTEN2FG.js.map +1 -0
  43. package/dist/chunk-E5JZSEGJ.cjs +301 -0
  44. package/dist/chunk-E5JZSEGJ.cjs.map +1 -0
  45. package/dist/chunk-EG6TJ3I5.js +286 -0
  46. package/dist/chunk-EG6TJ3I5.js.map +1 -0
  47. package/dist/chunk-EJCDOA37.js +537 -0
  48. package/dist/chunk-EJCDOA37.js.map +1 -0
  49. package/dist/{chunk-UVZHTBZ5.cjs → chunk-EK6RJ373.cjs} +7 -150
  50. package/dist/chunk-EK6RJ373.cjs.map +1 -0
  51. package/dist/{chunk-3JK66E3I.cjs → chunk-JTI5WT4P.cjs} +630 -59
  52. package/dist/chunk-JTI5WT4P.cjs.map +1 -0
  53. package/dist/chunk-NHQWXSTS.js +10 -0
  54. package/dist/chunk-NHQWXSTS.js.map +1 -0
  55. package/dist/chunk-NZ5PMBTG.js +105 -0
  56. package/dist/chunk-NZ5PMBTG.js.map +1 -0
  57. package/dist/{chunk-SUHW2UYL.cjs → chunk-OECDVACY.cjs} +2 -2
  58. package/dist/chunk-OECDVACY.cjs.map +1 -0
  59. package/dist/{chunk-EYELZHKY.js → chunk-OOS2RKRH.js} +5 -140
  60. package/dist/chunk-OOS2RKRH.js.map +1 -0
  61. package/dist/{chunk-EY4LBX3F.js → chunk-PSKUWVCB.js} +373 -38
  62. package/dist/chunk-PSKUWVCB.js.map +1 -0
  63. package/dist/chunk-QMQYK3IF.cjs +2680 -0
  64. package/dist/chunk-QMQYK3IF.cjs.map +1 -0
  65. package/dist/chunk-RCAJZG67.cjs +2069 -0
  66. package/dist/chunk-RCAJZG67.cjs.map +1 -0
  67. package/dist/{chunk-O5PST6TB.cjs → chunk-W5MTHMTE.cjs} +83 -6
  68. package/dist/chunk-W5MTHMTE.cjs.map +1 -0
  69. package/dist/chunk-WVQXAFP3.js +79 -0
  70. package/dist/chunk-WVQXAFP3.js.map +1 -0
  71. package/dist/chunk-X3244EKP.cjs +84 -0
  72. package/dist/chunk-X3244EKP.cjs.map +1 -0
  73. package/dist/{chunk-753F33CV.js → chunk-YZZBDCLV.js} +617 -44
  74. package/dist/chunk-YZZBDCLV.js.map +1 -0
  75. package/dist/{ddl-B_H8JM-E.d.cts → ddl-BqMmpNor.d.ts} +1328 -283
  76. package/dist/{ddl-1tFIvt9V.d.ts → ddl-Bwjh8Hff.d.cts} +1328 -283
  77. package/dist/extension-types-D07e_NTw.d.cts +543 -0
  78. package/dist/extension-types-D07e_NTw.d.ts +543 -0
  79. package/dist/graph-extension/index.cjs +71 -0
  80. package/dist/graph-extension/index.cjs.map +1 -0
  81. package/dist/graph-extension/index.d.cts +278 -0
  82. package/dist/graph-extension/index.d.ts +278 -0
  83. package/dist/graph-extension/index.js +6 -0
  84. package/dist/graph-extension/index.js.map +1 -0
  85. package/dist/{index-DXkEXpNz.d.ts → index-CT6nvtxL.d.cts} +114 -5
  86. package/dist/{index-DXkEXpNz.d.cts → index-DQheiVQV.d.ts} +114 -5
  87. package/dist/index.cjs +2672 -901
  88. package/dist/index.cjs.map +1 -1
  89. package/dist/index.d.cts +29 -10
  90. package/dist/index.d.ts +29 -10
  91. package/dist/index.js +2248 -598
  92. package/dist/index.js.map +1 -1
  93. package/dist/indexes/index.cjs +25 -23
  94. package/dist/indexes/index.d.cts +40 -22
  95. package/dist/indexes/index.d.ts +40 -22
  96. package/dist/indexes/index.js +5 -3
  97. package/dist/interchange/index.cjs +8 -7
  98. package/dist/interchange/index.cjs.map +1 -1
  99. package/dist/interchange/index.d.cts +5 -4
  100. package/dist/interchange/index.d.ts +5 -4
  101. package/dist/interchange/index.js +3 -2
  102. package/dist/interchange/index.js.map +1 -1
  103. package/dist/{manager-Vkz28eAC.d.cts → manager-Cy3dhwYO.d.cts} +194 -6
  104. package/dist/{manager-nIhmttD-.d.ts → manager-sZkU2VPC.d.ts} +194 -6
  105. package/dist/materialize-indexes-BB9N5uQl.d.cts +68 -0
  106. package/dist/materialize-indexes-BYpU2RKh.d.ts +68 -0
  107. package/dist/profiler/index.cjs +10 -8
  108. package/dist/profiler/index.cjs.map +1 -1
  109. package/dist/profiler/index.d.cts +8 -7
  110. package/dist/profiler/index.d.ts +8 -7
  111. package/dist/profiler/index.js +3 -1
  112. package/dist/profiler/index.js.map +1 -1
  113. package/dist/schema/index.cjs +43 -22
  114. package/dist/schema/index.cjs.map +1 -1
  115. package/dist/schema/index.d.cts +17 -8
  116. package/dist/schema/index.d.ts +17 -8
  117. package/dist/schema/index.js +9 -4
  118. package/dist/schema/index.js.map +1 -1
  119. package/dist/{sqlite-D0aceIe0.d.cts → sqlite-BhFswiAR.d.cts} +837 -120
  120. package/dist/{sqlite-SUxbZqfy.d.ts → sqlite-h6dta1IJ.d.ts} +837 -120
  121. package/dist/{store-CpvwTMxV.d.cts → store-BS_hehiz.d.ts} +659 -23
  122. package/dist/{store-U3i2tUch.d.ts → store-CkCvqRUf.d.cts} +659 -23
  123. package/dist/{types-yH4_p0XB.d.cts → types-BpgACExN.d.cts} +3 -2
  124. package/dist/{types-qYFZ9SqD.d.ts → types-Bz-Pi681.d.ts} +3 -2
  125. package/dist/types-DptZHe-l.d.ts +2132 -0
  126. package/dist/types-WF5ItKQu.d.cts +2132 -0
  127. package/dist/where-C40InMIp.d.ts +11 -0
  128. package/dist/where-DZYMiXVq.d.cts +11 -0
  129. package/package.json +33 -73
  130. package/dist/ast-C8S37w1A.d.ts +0 -497
  131. package/dist/ast-dgLhLOg0.d.cts +0 -497
  132. package/dist/chunk-3JK66E3I.cjs.map +0 -1
  133. package/dist/chunk-3PPEHLGK.js +0 -1116
  134. package/dist/chunk-3PPEHLGK.js.map +0 -1
  135. package/dist/chunk-5HVDOPZU.cjs.map +0 -1
  136. package/dist/chunk-753F33CV.js.map +0 -1
  137. package/dist/chunk-EY4LBX3F.js.map +0 -1
  138. package/dist/chunk-EYELZHKY.js.map +0 -1
  139. package/dist/chunk-GFGVREHH.js +0 -1381
  140. package/dist/chunk-GFGVREHH.js.map +0 -1
  141. package/dist/chunk-GUTQTMOV.js.map +0 -1
  142. package/dist/chunk-LBORRUNJ.js +0 -135
  143. package/dist/chunk-LBORRUNJ.js.map +0 -1
  144. package/dist/chunk-O5PST6TB.cjs.map +0 -1
  145. package/dist/chunk-OLROXS2S.cjs +0 -147
  146. package/dist/chunk-OLROXS2S.cjs.map +0 -1
  147. package/dist/chunk-OVJ2BE5Q.cjs.map +0 -1
  148. package/dist/chunk-PAUN562Y.cjs +0 -1417
  149. package/dist/chunk-PAUN562Y.cjs.map +0 -1
  150. package/dist/chunk-PEE4EWXZ.cjs +0 -1131
  151. package/dist/chunk-PEE4EWXZ.cjs.map +0 -1
  152. package/dist/chunk-QOLTW7OZ.js.map +0 -1
  153. package/dist/chunk-SUHW2UYL.cjs.map +0 -1
  154. package/dist/chunk-UVZHTBZ5.cjs.map +0 -1
  155. package/dist/chunk-WFMTAEEN.js.map +0 -1
  156. package/dist/types-C-zfYDJB.d.ts +0 -159
  157. package/dist/types-CQx4iW5Y.d.cts +0 -159
  158. package/dist/types-Qk2l3IkQ.d.cts +0 -1254
  159. package/dist/types-Qk2l3IkQ.d.ts +0 -1254
@@ -0,0 +1,2628 @@
1
+ import { NODE_TYPE_BRAND, EDGE_TYPE_BRAND, nowIso, getNodeKinds, getEdgeKinds, autoDeriveVectorIndexes, mergeVectorIndexes } from './chunk-EG6TJ3I5.js';
2
+ import { ALL_META_EDGE_NAMES, META_EDGE_IMPLIES, META_EDGE_INVERSE_OF, META_EDGE_PART_OF, META_EDGE_HAS_PART, META_EDGE_DISJOINT_WITH, META_EDGE_DIFFERENT_FROM, META_EDGE_SAME_AS, META_EDGE_EQUIVALENT_TO, META_EDGE_RELATED_TO, META_EDGE_BROADER, META_EDGE_NARROWER, META_EDGE_SUB_CLASS_OF, assertJsonValue, isReachable, computeTransitiveClosure, invertClosure, LEGACY_GRAPH_EXTENSION_VERSION, unwrap, validateGraphExtension, compactUndefined, KindCollisionError, GraphExtensionUnresolvedEndpointError, freezeDeep, assertSchemaKeysAreFree, RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS } from './chunk-4BOWVUGQ.js';
3
+ import { sha256Hex, defineNodeIndex, defineEdgeIndex } from './chunk-EJCDOA37.js';
4
+ import { searchable } from './chunk-OOS2RKRH.js';
5
+ import { embedding } from './chunk-WVQXAFP3.js';
6
+ import { ConfigurationError, KindNotFoundError, DatabaseOperationError, MigrationError, ValidationError } from './chunk-DOTEN2FG.js';
7
+ import { z } from 'zod';
8
+
9
+ // src/core/node.ts
10
+ function validateSchemaKeys(schema, name) {
11
+ assertSchemaKeysAreFree(
12
+ "Node",
13
+ name,
14
+ Object.keys(schema.shape),
15
+ RESERVED_NODE_KEYS
16
+ );
17
+ }
18
+ function defineNode(name, options) {
19
+ validateSchemaKeys(options.schema, name);
20
+ if (options.annotations !== void 0) {
21
+ assertJsonValue(options.annotations, "annotations", `Node "${name}"`);
22
+ }
23
+ return Object.freeze({
24
+ [NODE_TYPE_BRAND]: true,
25
+ kind: name,
26
+ schema: options.schema,
27
+ description: options.description,
28
+ annotations: options.annotations
29
+ });
30
+ }
31
+ var EMPTY_SCHEMA = z.object({});
32
+ function validateSchemaKeys2(schema, name) {
33
+ assertSchemaKeysAreFree(
34
+ "Edge",
35
+ name,
36
+ Object.keys(schema.shape),
37
+ RESERVED_EDGE_KEYS
38
+ );
39
+ }
40
+ function defineEdge(name, options) {
41
+ const schema = options?.schema ?? EMPTY_SCHEMA;
42
+ validateSchemaKeys2(schema, name);
43
+ if (options?.annotations !== void 0) {
44
+ assertJsonValue(options.annotations, "annotations", `Edge "${name}"`);
45
+ }
46
+ return Object.freeze({
47
+ [EDGE_TYPE_BRAND]: true,
48
+ kind: name,
49
+ schema,
50
+ description: options?.description,
51
+ annotations: options?.annotations,
52
+ from: options?.from,
53
+ to: options?.to
54
+ });
55
+ }
56
+
57
+ // src/ontology/types.ts
58
+ var META_EDGE_BRAND = "__metaEdge";
59
+ function isMetaEdge(value) {
60
+ return typeof value === "object" && value !== null && META_EDGE_BRAND in value && value[META_EDGE_BRAND] === true;
61
+ }
62
+ function getTypeName(typeOrIri) {
63
+ if (typeof typeOrIri === "string") {
64
+ return typeOrIri;
65
+ }
66
+ return typeOrIri.kind;
67
+ }
68
+
69
+ // src/ontology/core-meta-edges.ts
70
+ function createMetaEdge(name, properties) {
71
+ return Object.freeze({
72
+ [META_EDGE_BRAND]: true,
73
+ name,
74
+ properties: {
75
+ transitive: properties.transitive ?? false,
76
+ symmetric: properties.symmetric ?? false,
77
+ reflexive: properties.reflexive ?? false,
78
+ inverse: properties.inverse,
79
+ inference: properties.inference,
80
+ description: properties.description
81
+ }
82
+ });
83
+ }
84
+ var subClassOfMetaEdge = createMetaEdge(META_EDGE_SUB_CLASS_OF, {
85
+ transitive: true,
86
+ inference: "subsumption",
87
+ description: "Type inheritance (Podcast subClassOf Media)"
88
+ });
89
+ function subClassOf(child, parent) {
90
+ return {
91
+ metaEdge: subClassOfMetaEdge,
92
+ from: child,
93
+ to: parent
94
+ };
95
+ }
96
+ var broaderMetaEdge = createMetaEdge(META_EDGE_BROADER, {
97
+ transitive: true,
98
+ inverse: META_EDGE_NARROWER,
99
+ inference: "hierarchy",
100
+ description: "Broader concept (ML broader AI)"
101
+ });
102
+ function broader(narrowerConcept, broaderConcept) {
103
+ return {
104
+ metaEdge: broaderMetaEdge,
105
+ from: narrowerConcept,
106
+ to: broaderConcept
107
+ };
108
+ }
109
+ var narrowerMetaEdge = createMetaEdge(META_EDGE_NARROWER, {
110
+ transitive: true,
111
+ inverse: META_EDGE_BROADER,
112
+ inference: "hierarchy",
113
+ description: "Narrower concept (AI narrower ML)"
114
+ });
115
+ function narrower(broaderConcept, narrowerConcept) {
116
+ return {
117
+ metaEdge: narrowerMetaEdge,
118
+ from: broaderConcept,
119
+ to: narrowerConcept
120
+ };
121
+ }
122
+ var relatedToMetaEdge = createMetaEdge(META_EDGE_RELATED_TO, {
123
+ symmetric: true,
124
+ inference: "association",
125
+ description: "Non-hierarchical association"
126
+ });
127
+ function relatedTo(conceptA, conceptB) {
128
+ return {
129
+ metaEdge: relatedToMetaEdge,
130
+ from: conceptA,
131
+ to: conceptB
132
+ };
133
+ }
134
+ var equivalentToMetaEdge = createMetaEdge(META_EDGE_EQUIVALENT_TO, {
135
+ symmetric: true,
136
+ transitive: true,
137
+ inference: "substitution",
138
+ description: "Same class, different representation"
139
+ });
140
+ function equivalentTo(kindA, kindBOrIri) {
141
+ return {
142
+ metaEdge: equivalentToMetaEdge,
143
+ from: kindA,
144
+ to: kindBOrIri
145
+ };
146
+ }
147
+ var sameAsMetaEdge = createMetaEdge(META_EDGE_SAME_AS, {
148
+ symmetric: true,
149
+ transitive: true,
150
+ inference: "substitution",
151
+ description: "Same individual (for deduplication)"
152
+ });
153
+ function sameAs(kindA, kindBOrIri) {
154
+ return {
155
+ metaEdge: sameAsMetaEdge,
156
+ from: kindA,
157
+ to: kindBOrIri
158
+ };
159
+ }
160
+ var differentFromMetaEdge = createMetaEdge(META_EDGE_DIFFERENT_FROM, {
161
+ symmetric: true,
162
+ inference: "constraint",
163
+ description: "Explicitly different individuals"
164
+ });
165
+ function differentFrom(kindA, kindB) {
166
+ return {
167
+ metaEdge: differentFromMetaEdge,
168
+ from: kindA,
169
+ to: kindB
170
+ };
171
+ }
172
+ var disjointWithMetaEdge = createMetaEdge(META_EDGE_DISJOINT_WITH, {
173
+ symmetric: true,
174
+ inference: "constraint",
175
+ description: "Mutually exclusive types"
176
+ });
177
+ function disjointWith(kindA, kindB) {
178
+ return {
179
+ metaEdge: disjointWithMetaEdge,
180
+ from: kindA,
181
+ to: kindB
182
+ };
183
+ }
184
+ var partOfMetaEdge = createMetaEdge(META_EDGE_PART_OF, {
185
+ transitive: true,
186
+ inverse: META_EDGE_HAS_PART,
187
+ inference: "composition",
188
+ description: "X is part of Y"
189
+ });
190
+ function partOf(part, whole) {
191
+ return {
192
+ metaEdge: partOfMetaEdge,
193
+ from: part,
194
+ to: whole
195
+ };
196
+ }
197
+ var hasPartMetaEdge = createMetaEdge(META_EDGE_HAS_PART, {
198
+ transitive: true,
199
+ inverse: META_EDGE_PART_OF,
200
+ inference: "composition",
201
+ description: "Y has part X"
202
+ });
203
+ function hasPart(whole, part) {
204
+ return {
205
+ metaEdge: hasPartMetaEdge,
206
+ from: whole,
207
+ to: part
208
+ };
209
+ }
210
+ var inverseOfMetaEdge = createMetaEdge(META_EDGE_INVERSE_OF, {
211
+ symmetric: true,
212
+ inference: "none",
213
+ description: "Edge A is inverse of edge B"
214
+ });
215
+ var impliesMetaEdge = createMetaEdge(META_EDGE_IMPLIES, {
216
+ transitive: true,
217
+ inference: "none",
218
+ description: "Edge A implies edge B exists"
219
+ });
220
+ function inverseOf(edgeA, edgeB) {
221
+ return {
222
+ metaEdge: inverseOfMetaEdge,
223
+ from: edgeA,
224
+ to: edgeB
225
+ };
226
+ }
227
+ function implies(edgeA, edgeB) {
228
+ return {
229
+ metaEdge: impliesMetaEdge,
230
+ from: edgeA,
231
+ to: edgeB
232
+ };
233
+ }
234
+ var core = {
235
+ // Meta-edges
236
+ subClassOfMetaEdge,
237
+ broaderMetaEdge,
238
+ narrowerMetaEdge,
239
+ relatedToMetaEdge,
240
+ equivalentToMetaEdge,
241
+ sameAsMetaEdge,
242
+ differentFromMetaEdge,
243
+ disjointWithMetaEdge,
244
+ partOfMetaEdge,
245
+ hasPartMetaEdge,
246
+ inverseOfMetaEdge,
247
+ impliesMetaEdge,
248
+ // Relation factories
249
+ subClassOf,
250
+ broader,
251
+ narrower,
252
+ relatedTo,
253
+ equivalentTo,
254
+ sameAs,
255
+ differentFrom,
256
+ disjointWith,
257
+ partOf,
258
+ hasPart,
259
+ inverseOf,
260
+ implies
261
+ };
262
+
263
+ // src/schema/canonical.ts
264
+ function sortedReplacer(_key, value) {
265
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
266
+ const sorted = {};
267
+ for (const key of Object.keys(value).toSorted()) {
268
+ sorted[key] = value[key];
269
+ }
270
+ return sorted;
271
+ }
272
+ return value;
273
+ }
274
+ function canonicalEqual(a, b) {
275
+ return JSON.stringify(a, sortedReplacer) === JSON.stringify(b, sortedReplacer);
276
+ }
277
+
278
+ // src/schema/migration.ts
279
+ function computeSchemaDiff(before, after) {
280
+ const nodeChanges = diffNodes(before.nodes, after.nodes);
281
+ const edgeChanges = diffEdges(before.edges, after.edges);
282
+ const ontologyChanges = diffOntology(before.ontology, after.ontology);
283
+ const indexChanges = diffIndexes(before.indexes, after.indexes);
284
+ const extensionChange = diffExtension(before.extension, after.extension);
285
+ const deprecatedKindsChange = diffDeprecatedKinds(
286
+ before.deprecatedKinds,
287
+ after.deprecatedKinds
288
+ );
289
+ const allChanges = [
290
+ ...nodeChanges,
291
+ ...edgeChanges,
292
+ ...ontologyChanges,
293
+ ...indexChanges
294
+ ];
295
+ const hasBreakingChanges = allChanges.some(
296
+ (change) => change.severity === "breaking"
297
+ );
298
+ const hasChanges = allChanges.length > 0 || extensionChange !== void 0 || deprecatedKindsChange !== void 0;
299
+ const summary = generateSummary(
300
+ nodeChanges,
301
+ edgeChanges,
302
+ ontologyChanges,
303
+ indexChanges,
304
+ extensionChange,
305
+ deprecatedKindsChange
306
+ );
307
+ return {
308
+ fromVersion: before.version,
309
+ toVersion: after.version,
310
+ nodes: nodeChanges,
311
+ edges: edgeChanges,
312
+ ontology: ontologyChanges,
313
+ indexes: indexChanges,
314
+ ...extensionChange === void 0 ? {} : { extension: extensionChange },
315
+ ...deprecatedKindsChange === void 0 ? {} : { deprecatedKinds: deprecatedKindsChange },
316
+ hasBreakingChanges,
317
+ isBackwardsCompatible: !hasBreakingChanges,
318
+ hasChanges,
319
+ summary
320
+ };
321
+ }
322
+ function diffNodes(before, after) {
323
+ const changes = [];
324
+ const beforeNames = new Set(Object.keys(before));
325
+ const afterNames = new Set(Object.keys(after));
326
+ for (const name of beforeNames) {
327
+ if (!afterNames.has(name)) {
328
+ changes.push({
329
+ type: "removed",
330
+ kind: name,
331
+ severity: "breaking",
332
+ details: `Node kind "${name}" was removed`,
333
+ before: before[name]
334
+ });
335
+ }
336
+ }
337
+ for (const name of afterNames) {
338
+ if (!beforeNames.has(name)) {
339
+ changes.push({
340
+ type: "added",
341
+ kind: name,
342
+ severity: "safe",
343
+ details: `Node kind "${name}" was added`,
344
+ after: after[name]
345
+ });
346
+ }
347
+ }
348
+ for (const name of beforeNames) {
349
+ if (afterNames.has(name)) {
350
+ const nodeBefore = before[name];
351
+ const nodeAfter = after[name];
352
+ const nodeChanges = diffNodeDef(name, nodeBefore, nodeAfter);
353
+ changes.push(...nodeChanges);
354
+ }
355
+ }
356
+ return changes;
357
+ }
358
+ function diffNodeDef(name, before, after) {
359
+ const changes = [];
360
+ if (!canonicalEqual(before.properties, after.properties)) {
361
+ const beforeProps = before.properties.properties ?? {};
362
+ const afterProps = after.properties.properties ?? {};
363
+ const beforeRequired = new Set(before.properties.required);
364
+ const afterRequired = new Set(after.properties.required);
365
+ const addedProps = Object.keys(afterProps).filter(
366
+ (p) => !(p in beforeProps)
367
+ );
368
+ const removedProps = Object.keys(beforeProps).filter(
369
+ (p) => !(p in afterProps)
370
+ );
371
+ const newRequired = [...afterRequired].filter(
372
+ (p) => !beforeRequired.has(p)
373
+ );
374
+ const { severity, details } = computePropertyChangeSeverity(
375
+ name,
376
+ removedProps,
377
+ addedProps,
378
+ newRequired
379
+ );
380
+ changes.push({
381
+ type: "modified",
382
+ kind: name,
383
+ severity,
384
+ details,
385
+ before,
386
+ after
387
+ });
388
+ }
389
+ if (before.onDelete !== after.onDelete) {
390
+ changes.push({
391
+ type: "modified",
392
+ kind: name,
393
+ severity: "warning",
394
+ details: `onDelete changed from "${before.onDelete}" to "${after.onDelete}" for "${name}"`,
395
+ before,
396
+ after
397
+ });
398
+ }
399
+ if (!canonicalEqual(before.uniqueConstraints, after.uniqueConstraints)) {
400
+ changes.push({
401
+ type: "modified",
402
+ kind: name,
403
+ severity: "warning",
404
+ details: `Unique constraints changed for "${name}"`,
405
+ before,
406
+ after
407
+ });
408
+ }
409
+ if (annotationsChanged(before.annotations, after.annotations)) {
410
+ changes.push({
411
+ type: "modified",
412
+ kind: name,
413
+ severity: "safe",
414
+ details: `Annotations changed for "${name}"`,
415
+ before,
416
+ after
417
+ });
418
+ }
419
+ return changes;
420
+ }
421
+ function computePropertyChangeSeverity(name, removedProps, addedProps, newRequired) {
422
+ if (removedProps.length > 0) {
423
+ return {
424
+ severity: "breaking",
425
+ details: `Properties removed from "${name}": ${removedProps.join(", ")}`
426
+ };
427
+ }
428
+ if (newRequired.length > 0) {
429
+ return {
430
+ severity: "breaking",
431
+ details: `New required properties in "${name}": ${newRequired.join(", ")}`
432
+ };
433
+ }
434
+ if (addedProps.length > 0) {
435
+ return {
436
+ severity: "safe",
437
+ details: `Properties added to "${name}": ${addedProps.join(", ")}`
438
+ };
439
+ }
440
+ return {
441
+ severity: "safe",
442
+ details: `Properties changed in "${name}"`
443
+ };
444
+ }
445
+ function diffEdges(before, after) {
446
+ const changes = [];
447
+ const beforeNames = new Set(Object.keys(before));
448
+ const afterNames = new Set(Object.keys(after));
449
+ for (const name of beforeNames) {
450
+ if (!afterNames.has(name)) {
451
+ changes.push({
452
+ type: "removed",
453
+ kind: name,
454
+ severity: "breaking",
455
+ details: `Edge kind "${name}" was removed`,
456
+ before: before[name]
457
+ });
458
+ }
459
+ }
460
+ for (const name of afterNames) {
461
+ if (!beforeNames.has(name)) {
462
+ changes.push({
463
+ type: "added",
464
+ kind: name,
465
+ severity: "safe",
466
+ details: `Edge kind "${name}" was added`,
467
+ after: after[name]
468
+ });
469
+ }
470
+ }
471
+ for (const name of beforeNames) {
472
+ if (afterNames.has(name)) {
473
+ const edgeBefore = before[name];
474
+ const edgeAfter = after[name];
475
+ const edgeChanges = diffEdgeDef(name, edgeBefore, edgeAfter);
476
+ changes.push(...edgeChanges);
477
+ }
478
+ }
479
+ return changes;
480
+ }
481
+ function diffEdgeDef(name, before, after) {
482
+ const changes = [];
483
+ if (!canonicalEqual(before.fromKinds, after.fromKinds)) {
484
+ changes.push({
485
+ type: "modified",
486
+ kind: name,
487
+ severity: "warning",
488
+ details: `fromKinds changed for "${name}"`,
489
+ before,
490
+ after
491
+ });
492
+ }
493
+ if (!canonicalEqual(before.toKinds, after.toKinds)) {
494
+ changes.push({
495
+ type: "modified",
496
+ kind: name,
497
+ severity: "warning",
498
+ details: `toKinds changed for "${name}"`,
499
+ before,
500
+ after
501
+ });
502
+ }
503
+ if (before.cardinality !== after.cardinality) {
504
+ changes.push({
505
+ type: "modified",
506
+ kind: name,
507
+ severity: "warning",
508
+ details: `Cardinality changed from "${before.cardinality}" to "${after.cardinality}" for "${name}"`,
509
+ before,
510
+ after
511
+ });
512
+ }
513
+ if (!canonicalEqual(before.properties, after.properties)) {
514
+ changes.push({
515
+ type: "modified",
516
+ kind: name,
517
+ severity: "safe",
518
+ details: `Properties changed for "${name}"`,
519
+ before,
520
+ after
521
+ });
522
+ }
523
+ if (annotationsChanged(before.annotations, after.annotations)) {
524
+ changes.push({
525
+ type: "modified",
526
+ kind: name,
527
+ severity: "safe",
528
+ details: `Annotations changed for "${name}"`,
529
+ before,
530
+ after
531
+ });
532
+ }
533
+ return changes;
534
+ }
535
+ function annotationsChanged(before, after) {
536
+ if (before === void 0 && after === void 0) return false;
537
+ if (before === void 0 || after === void 0) return true;
538
+ return !canonicalEqual(before, after);
539
+ }
540
+ function diffOntology(before, after) {
541
+ const changes = [];
542
+ const metaEdgesBefore = new Set(Object.keys(before.metaEdges));
543
+ const metaEdgesAfter = new Set(Object.keys(after.metaEdges));
544
+ for (const name of metaEdgesBefore) {
545
+ if (!metaEdgesAfter.has(name)) {
546
+ changes.push({
547
+ type: "removed",
548
+ entity: "metaEdge",
549
+ name,
550
+ severity: "breaking",
551
+ details: `Meta-edge "${name}" was removed`
552
+ });
553
+ }
554
+ }
555
+ for (const name of metaEdgesAfter) {
556
+ if (!metaEdgesBefore.has(name)) {
557
+ changes.push({
558
+ type: "added",
559
+ entity: "metaEdge",
560
+ name,
561
+ severity: "safe",
562
+ details: `Meta-edge "${name}" was added`
563
+ });
564
+ }
565
+ }
566
+ const relationsBefore = new Set(
567
+ before.relations.map((r) => `${r.metaEdge}:${r.from}:${r.to}`)
568
+ );
569
+ const relationsAfter = new Set(
570
+ after.relations.map((r) => `${r.metaEdge}:${r.from}:${r.to}`)
571
+ );
572
+ for (const relationKey of relationsBefore) {
573
+ if (!relationsAfter.has(relationKey)) {
574
+ const [metaEdge, from, to] = relationKey.split(":");
575
+ changes.push({
576
+ type: "removed",
577
+ entity: "relation",
578
+ name: relationKey,
579
+ severity: "warning",
580
+ details: `Relation ${metaEdge}(${from}, ${to}) was removed`
581
+ });
582
+ }
583
+ }
584
+ for (const relationKey of relationsAfter) {
585
+ if (!relationsBefore.has(relationKey)) {
586
+ const [metaEdge, from, to] = relationKey.split(":");
587
+ changes.push({
588
+ type: "added",
589
+ entity: "relation",
590
+ name: relationKey,
591
+ severity: "safe",
592
+ details: `Relation ${metaEdge}(${from}, ${to}) was added`
593
+ });
594
+ }
595
+ }
596
+ return changes;
597
+ }
598
+ function diffIndexes(before, after) {
599
+ const beforeIndexes = before ?? [];
600
+ const afterIndexes = after ?? [];
601
+ const beforeByName = /* @__PURE__ */ new Map();
602
+ for (const index of beforeIndexes) {
603
+ beforeByName.set(index.name, index);
604
+ }
605
+ const afterByName = /* @__PURE__ */ new Map();
606
+ for (const index of afterIndexes) {
607
+ afterByName.set(index.name, index);
608
+ }
609
+ const changes = [];
610
+ for (const [name, index] of beforeByName) {
611
+ if (!afterByName.has(name)) {
612
+ changes.push({
613
+ type: "removed",
614
+ name,
615
+ entity: index.entity,
616
+ severity: "safe",
617
+ details: `Index "${name}" was removed`,
618
+ before: index
619
+ });
620
+ }
621
+ }
622
+ for (const [name, index] of afterByName) {
623
+ if (!beforeByName.has(name)) {
624
+ changes.push({
625
+ type: "added",
626
+ name,
627
+ entity: index.entity,
628
+ severity: "safe",
629
+ details: `Index "${name}" was added`,
630
+ after: index
631
+ });
632
+ }
633
+ }
634
+ for (const [name, beforeIndex] of beforeByName) {
635
+ const afterIndex = afterByName.get(name);
636
+ if (!afterIndex) continue;
637
+ if (!canonicalEqual(beforeIndex, afterIndex)) {
638
+ changes.push({
639
+ type: "modified",
640
+ name,
641
+ entity: beforeIndex.entity,
642
+ severity: "safe",
643
+ details: `Index "${name}" was modified`,
644
+ before: beforeIndex,
645
+ after: afterIndex
646
+ });
647
+ }
648
+ }
649
+ return changes;
650
+ }
651
+ function diffExtension(before, after) {
652
+ if (before === after) return void 0;
653
+ if (before === void 0) {
654
+ return {
655
+ type: "added",
656
+ severity: "safe",
657
+ details: "Graph extension document was added"
658
+ };
659
+ }
660
+ if (after === void 0) {
661
+ return {
662
+ type: "removed",
663
+ severity: "safe",
664
+ details: "Graph extension document was removed"
665
+ };
666
+ }
667
+ if (canonicalEqual(before, after)) return void 0;
668
+ return {
669
+ type: "modified",
670
+ severity: "safe",
671
+ details: "Graph extension document was modified"
672
+ };
673
+ }
674
+ function diffDeprecatedKinds(before, after) {
675
+ const beforeSet = new Set(before);
676
+ const afterSet = new Set(after);
677
+ const added = [];
678
+ const removed = [];
679
+ for (const name of afterSet) {
680
+ if (!beforeSet.has(name)) added.push(name);
681
+ }
682
+ for (const name of beforeSet) {
683
+ if (!afterSet.has(name)) removed.push(name);
684
+ }
685
+ if (added.length === 0 && removed.length === 0) return void 0;
686
+ added.sort();
687
+ removed.sort();
688
+ const parts = [];
689
+ if (added.length > 0) parts.push(`added ${added.join(", ")}`);
690
+ if (removed.length > 0) parts.push(`removed ${removed.join(", ")}`);
691
+ return {
692
+ added,
693
+ removed,
694
+ severity: "safe",
695
+ details: `Deprecated kinds: ${parts.join("; ")}`
696
+ };
697
+ }
698
+ function generateSummary(nodeChanges, edgeChanges, ontologyChanges, indexChanges, extensionChange, deprecatedKindsChange) {
699
+ const parts = [];
700
+ const nodeAdded = nodeChanges.filter((c) => c.type === "added").length;
701
+ const nodeRemoved = nodeChanges.filter((c) => c.type === "removed").length;
702
+ const nodeModified = nodeChanges.filter((c) => c.type === "modified").length;
703
+ if (nodeAdded > 0 || nodeRemoved > 0 || nodeModified > 0) {
704
+ parts.push(
705
+ `Nodes: ${nodeAdded} added, ${nodeRemoved} removed, ${nodeModified} modified`
706
+ );
707
+ }
708
+ const edgeAdded = edgeChanges.filter((c) => c.type === "added").length;
709
+ const edgeRemoved = edgeChanges.filter((c) => c.type === "removed").length;
710
+ const edgeModified = edgeChanges.filter((c) => c.type === "modified").length;
711
+ if (edgeAdded > 0 || edgeRemoved > 0 || edgeModified > 0) {
712
+ parts.push(
713
+ `Edges: ${edgeAdded} added, ${edgeRemoved} removed, ${edgeModified} modified`
714
+ );
715
+ }
716
+ const ontologyAdded = ontologyChanges.filter(
717
+ (c) => c.type === "added"
718
+ ).length;
719
+ const ontologyRemoved = ontologyChanges.filter(
720
+ (c) => c.type === "removed"
721
+ ).length;
722
+ if (ontologyAdded > 0 || ontologyRemoved > 0) {
723
+ parts.push(`Ontology: ${ontologyAdded} added, ${ontologyRemoved} removed`);
724
+ }
725
+ const indexAdded = indexChanges.filter((c) => c.type === "added").length;
726
+ const indexRemoved = indexChanges.filter((c) => c.type === "removed").length;
727
+ const indexModified = indexChanges.filter(
728
+ (c) => c.type === "modified"
729
+ ).length;
730
+ if (indexAdded > 0 || indexRemoved > 0 || indexModified > 0) {
731
+ parts.push(
732
+ `Indexes: ${indexAdded} added, ${indexRemoved} removed, ${indexModified} modified`
733
+ );
734
+ }
735
+ if (extensionChange !== void 0) {
736
+ parts.push(`Graph extension document: ${extensionChange.type}`);
737
+ }
738
+ if (deprecatedKindsChange !== void 0) {
739
+ const { added, removed } = deprecatedKindsChange;
740
+ parts.push(
741
+ `Deprecated kinds: ${added.length} added, ${removed.length} removed`
742
+ );
743
+ }
744
+ if (parts.length === 0) {
745
+ return "No changes";
746
+ }
747
+ return parts.join("; ");
748
+ }
749
+ function isBackwardsCompatible(diff) {
750
+ return !diff.hasBreakingChanges;
751
+ }
752
+ function getMigrationActions(diff) {
753
+ const actions = [];
754
+ for (const change of diff.nodes) {
755
+ if (change.type === "removed") {
756
+ actions.push(`DELETE data for removed node kind "${change.kind}"`);
757
+ }
758
+ if (change.severity === "breaking" && change.type === "modified") {
759
+ actions.push(
760
+ `MIGRATE data for node kind "${change.kind}": ${change.details}`
761
+ );
762
+ }
763
+ }
764
+ for (const change of diff.edges) {
765
+ if (change.type === "removed") {
766
+ actions.push(`DELETE data for removed edge kind "${change.kind}"`);
767
+ }
768
+ }
769
+ return actions;
770
+ }
771
+
772
+ // src/registry/kind-registry.ts
773
+ var KindRegistry = class {
774
+ // === Node & Edge Kinds ===
775
+ nodeKinds;
776
+ edgeKinds;
777
+ // === Subsumption (subClassOf) ===
778
+ // Transitive closure for inheritance
779
+ subClassAncestors;
780
+ subClassDescendants;
781
+ // === Hierarchy (broader/narrower) ===
782
+ // Transitive closure for concept hierarchy (separate from subClassOf!)
783
+ broaderClosure;
784
+ narrowerClosure;
785
+ // === Equivalence ===
786
+ equivalenceSets;
787
+ iriToKind;
788
+ // === Constraints ===
789
+ disjointPairs;
790
+ // Normalized pairs: "Organization|Person"
791
+ // === Composition ===
792
+ partOfClosure;
793
+ hasPartClosure;
794
+ // === Edge Relationships ===
795
+ edgeInverses;
796
+ edgeImplicationsClosure;
797
+ edgeImplyingClosure;
798
+ constructor(nodeKinds, edgeKinds, closures) {
799
+ this.nodeKinds = nodeKinds;
800
+ this.edgeKinds = edgeKinds;
801
+ this.subClassAncestors = closures.subClassAncestors;
802
+ this.subClassDescendants = closures.subClassDescendants;
803
+ this.broaderClosure = closures.broaderClosure;
804
+ this.narrowerClosure = closures.narrowerClosure;
805
+ this.equivalenceSets = closures.equivalenceSets;
806
+ this.iriToKind = closures.iriToKind;
807
+ this.disjointPairs = closures.disjointPairs;
808
+ this.partOfClosure = closures.partOfClosure;
809
+ this.hasPartClosure = closures.hasPartClosure;
810
+ this.edgeInverses = closures.edgeInverses;
811
+ this.edgeImplicationsClosure = closures.edgeImplicationsClosure;
812
+ this.edgeImplyingClosure = closures.edgeImplyingClosure;
813
+ }
814
+ // === Subsumption Methods ===
815
+ /**
816
+ * Checks if child is a subclass of parent (directly or transitively).
817
+ */
818
+ isSubClassOf(child, parent) {
819
+ return isReachable(this.subClassAncestors, child, parent);
820
+ }
821
+ /**
822
+ * Expands a kind to include all its subclasses.
823
+ * Returns [kind, ...subclasses].
824
+ */
825
+ expandSubClasses(kind) {
826
+ const descendants = this.subClassDescendants.get(kind) ?? /* @__PURE__ */ new Set();
827
+ return [kind, ...descendants];
828
+ }
829
+ /**
830
+ * Gets all ancestors of a kind (via subClassOf).
831
+ */
832
+ getAncestors(kind) {
833
+ return this.subClassAncestors.get(kind) ?? /* @__PURE__ */ new Set();
834
+ }
835
+ /**
836
+ * Gets all descendants of a kind (via subClassOf).
837
+ */
838
+ getDescendants(kind) {
839
+ return this.subClassDescendants.get(kind) ?? /* @__PURE__ */ new Set();
840
+ }
841
+ // === Hierarchy Methods ===
842
+ /**
843
+ * Checks if narrowerConcept is narrower than broaderConcept.
844
+ */
845
+ isNarrowerThan(narrowerConcept, broaderConcept) {
846
+ return isReachable(this.broaderClosure, narrowerConcept, broaderConcept);
847
+ }
848
+ /**
849
+ * Checks if broaderConcept is broader than narrowerConcept.
850
+ */
851
+ isBroaderThan(broaderConcept, narrowerConcept) {
852
+ return isReachable(this.narrowerClosure, broaderConcept, narrowerConcept);
853
+ }
854
+ /**
855
+ * Expands to include all narrower concepts.
856
+ */
857
+ expandNarrower(kind) {
858
+ const narrower2 = this.narrowerClosure.get(kind) ?? /* @__PURE__ */ new Set();
859
+ return [kind, ...narrower2];
860
+ }
861
+ /**
862
+ * Expands to include all broader concepts.
863
+ */
864
+ expandBroader(kind) {
865
+ const broader2 = this.broaderClosure.get(kind) ?? /* @__PURE__ */ new Set();
866
+ return [kind, ...broader2];
867
+ }
868
+ // === Equivalence Methods ===
869
+ /**
870
+ * Checks if two kinds are equivalent.
871
+ */
872
+ areEquivalent(a, b) {
873
+ const equivalents = this.equivalenceSets.get(a);
874
+ return equivalents?.has(b) ?? false;
875
+ }
876
+ /**
877
+ * Gets all equivalents of a kind (including external IRIs).
878
+ */
879
+ getEquivalents(kind) {
880
+ const equivalents = this.equivalenceSets.get(kind);
881
+ return equivalents ? [...equivalents] : [];
882
+ }
883
+ /**
884
+ * Resolves an external IRI to an internal kind name.
885
+ */
886
+ resolveIri(iri) {
887
+ return this.iriToKind.get(iri);
888
+ }
889
+ // === Constraint Methods ===
890
+ /**
891
+ * Checks if two kinds are disjoint.
892
+ */
893
+ areDisjoint(a, b) {
894
+ const normalizedPair = a < b ? `${a}|${b}` : `${b}|${a}`;
895
+ return this.disjointPairs.has(normalizedPair);
896
+ }
897
+ /**
898
+ * Gets all kinds that are disjoint with the given kind.
899
+ */
900
+ getDisjointKinds(kind) {
901
+ const result = [];
902
+ for (const pair of this.disjointPairs) {
903
+ const parts = pair.split("|");
904
+ const firstKind = parts[0];
905
+ const secondKind = parts[1];
906
+ if (firstKind === kind) result.push(secondKind);
907
+ else if (secondKind === kind) result.push(firstKind);
908
+ }
909
+ return result;
910
+ }
911
+ // === Composition Methods ===
912
+ /**
913
+ * Checks if part is part of whole (directly or transitively).
914
+ */
915
+ isPartOf(part, whole) {
916
+ return isReachable(this.partOfClosure, part, whole);
917
+ }
918
+ /**
919
+ * Gets all wholes that contain this part.
920
+ */
921
+ getWholes(part) {
922
+ const wholes = this.partOfClosure.get(part);
923
+ return wholes ? [...wholes] : [];
924
+ }
925
+ /**
926
+ * Gets all parts of this whole.
927
+ */
928
+ getParts(whole) {
929
+ const parts = this.hasPartClosure.get(whole);
930
+ return parts ? [...parts] : [];
931
+ }
932
+ // === Edge Relationship Methods ===
933
+ /**
934
+ * Gets the inverse edge kind for a given edge kind.
935
+ * If edgeA inverseOf edgeB, then getInverseEdge("edgeA") returns "edgeB".
936
+ */
937
+ getInverseEdge(edgeKind) {
938
+ return this.edgeInverses.get(edgeKind);
939
+ }
940
+ /**
941
+ * Gets all edges implied by a given edge (transitively).
942
+ * If A implies B and B implies C, then getImpliedEdges("A") returns ["B", "C"].
943
+ */
944
+ getImpliedEdges(edgeKind) {
945
+ const implied = this.edgeImplicationsClosure.get(edgeKind);
946
+ return implied ? [...implied] : [];
947
+ }
948
+ /**
949
+ * Gets all edges that imply a given edge (transitively).
950
+ * If A implies B and B implies C, then getImplyingEdges("C") returns ["A", "B"].
951
+ * Used for query-time expansion: when querying for C, also include A and B edges.
952
+ */
953
+ getImplyingEdges(edgeKind) {
954
+ const implying = this.edgeImplyingClosure.get(edgeKind);
955
+ return implying ? [...implying] : [];
956
+ }
957
+ /**
958
+ * Expands an edge kind to include all edges that imply it.
959
+ * Returns [edgeKind, ...implyingEdges].
960
+ */
961
+ expandImplyingEdges(edgeKind) {
962
+ const implying = this.edgeImplyingClosure.get(edgeKind) ?? /* @__PURE__ */ new Set();
963
+ return [edgeKind, ...implying];
964
+ }
965
+ // === Edge Endpoint Validation ===
966
+ /**
967
+ * Checks if a concrete kind is assignable to a target kind.
968
+ * Uses subsumption: Company is assignable to Organization if Company subClassOf Organization.
969
+ */
970
+ isAssignableTo(concreteKind, targetKind) {
971
+ if (concreteKind === targetKind) return true;
972
+ return this.isSubClassOf(concreteKind, targetKind);
973
+ }
974
+ /**
975
+ * Validates that a kind exists in the registry.
976
+ */
977
+ hasNodeType(name) {
978
+ return this.nodeKinds.has(name);
979
+ }
980
+ /**
981
+ * Validates that an edge kind exists in the registry.
982
+ */
983
+ hasEdgeType(name) {
984
+ return this.edgeKinds.has(name);
985
+ }
986
+ /**
987
+ * Gets a node kind by name.
988
+ */
989
+ getNodeType(name) {
990
+ return this.nodeKinds.get(name);
991
+ }
992
+ /**
993
+ * Gets an edge kind by name.
994
+ */
995
+ getEdgeType(name) {
996
+ return this.edgeKinds.get(name);
997
+ }
998
+ };
999
+ function createEmptyClosures() {
1000
+ return {
1001
+ subClassAncestors: /* @__PURE__ */ new Map(),
1002
+ subClassDescendants: /* @__PURE__ */ new Map(),
1003
+ broaderClosure: /* @__PURE__ */ new Map(),
1004
+ narrowerClosure: /* @__PURE__ */ new Map(),
1005
+ equivalenceSets: /* @__PURE__ */ new Map(),
1006
+ iriToKind: /* @__PURE__ */ new Map(),
1007
+ disjointPairs: /* @__PURE__ */ new Set(),
1008
+ partOfClosure: /* @__PURE__ */ new Map(),
1009
+ hasPartClosure: /* @__PURE__ */ new Map(),
1010
+ edgeInverses: /* @__PURE__ */ new Map(),
1011
+ edgeImplicationsClosure: /* @__PURE__ */ new Map(),
1012
+ edgeImplyingClosure: /* @__PURE__ */ new Map()
1013
+ };
1014
+ }
1015
+ function computeClosuresFromOntology(ontology) {
1016
+ const subClassRelations = [];
1017
+ const broaderRelations = [];
1018
+ const equivalentRelations = [];
1019
+ const disjointRelations = [];
1020
+ const partOfRelations = [];
1021
+ const inverseOfRelations = [];
1022
+ const impliesRelations = [];
1023
+ for (const relation of ontology) {
1024
+ const fromName = getKindName(relation.from);
1025
+ const toName = getKindName(relation.to);
1026
+ switch (relation.metaEdge.name) {
1027
+ case META_EDGE_SUB_CLASS_OF: {
1028
+ subClassRelations.push([fromName, toName]);
1029
+ break;
1030
+ }
1031
+ case META_EDGE_BROADER: {
1032
+ broaderRelations.push([fromName, toName]);
1033
+ break;
1034
+ }
1035
+ case META_EDGE_NARROWER: {
1036
+ broaderRelations.push([toName, fromName]);
1037
+ break;
1038
+ }
1039
+ case META_EDGE_EQUIVALENT_TO:
1040
+ case META_EDGE_SAME_AS: {
1041
+ equivalentRelations.push([fromName, toName]);
1042
+ break;
1043
+ }
1044
+ case META_EDGE_DISJOINT_WITH: {
1045
+ disjointRelations.push([fromName, toName]);
1046
+ break;
1047
+ }
1048
+ case META_EDGE_PART_OF: {
1049
+ partOfRelations.push([fromName, toName]);
1050
+ break;
1051
+ }
1052
+ case META_EDGE_HAS_PART: {
1053
+ partOfRelations.push([toName, fromName]);
1054
+ break;
1055
+ }
1056
+ case META_EDGE_INVERSE_OF: {
1057
+ inverseOfRelations.push([fromName, toName]);
1058
+ break;
1059
+ }
1060
+ case META_EDGE_IMPLIES: {
1061
+ impliesRelations.push([fromName, toName]);
1062
+ break;
1063
+ }
1064
+ }
1065
+ }
1066
+ const subClassAncestors = computeTransitiveClosure(subClassRelations);
1067
+ const subClassDescendants = invertClosure(subClassAncestors);
1068
+ const broaderClosure = computeTransitiveClosure(broaderRelations);
1069
+ const narrowerClosure = invertClosure(broaderClosure);
1070
+ const equivalenceSets = computeEquivalenceSets(equivalentRelations);
1071
+ const iriToKind = computeIriMapping(equivalentRelations);
1072
+ const disjointPairs = computeDisjointPairs(disjointRelations);
1073
+ const partOfClosure = computeTransitiveClosure(partOfRelations);
1074
+ const hasPartClosure = invertClosure(partOfClosure);
1075
+ const edgeInverses = computeEdgeInverses(inverseOfRelations);
1076
+ const edgeImplicationsClosure = computeTransitiveClosure(impliesRelations);
1077
+ const edgeImplyingClosure = invertClosure(edgeImplicationsClosure);
1078
+ return {
1079
+ subClassAncestors,
1080
+ subClassDescendants,
1081
+ broaderClosure,
1082
+ narrowerClosure,
1083
+ equivalenceSets,
1084
+ iriToKind,
1085
+ disjointPairs,
1086
+ partOfClosure,
1087
+ hasPartClosure,
1088
+ edgeInverses,
1089
+ edgeImplicationsClosure,
1090
+ edgeImplyingClosure
1091
+ };
1092
+ }
1093
+ function getKindName(kindOrIri) {
1094
+ if (typeof kindOrIri === "string") {
1095
+ return kindOrIri;
1096
+ }
1097
+ return kindOrIri.kind;
1098
+ }
1099
+ function isExternalIri(value) {
1100
+ return value.startsWith("http://") || value.startsWith("https://");
1101
+ }
1102
+ function computeEquivalenceSets(relations) {
1103
+ const parent = /* @__PURE__ */ new Map();
1104
+ function find(x) {
1105
+ if (!parent.has(x)) {
1106
+ parent.set(x, x);
1107
+ return x;
1108
+ }
1109
+ const parentNode = parent.get(x);
1110
+ if (parentNode === x) return x;
1111
+ const root = find(parentNode);
1112
+ parent.set(x, root);
1113
+ return root;
1114
+ }
1115
+ function union(a, b) {
1116
+ const rootA = find(a);
1117
+ const rootB = find(b);
1118
+ if (rootA !== rootB) {
1119
+ parent.set(rootA, rootB);
1120
+ }
1121
+ }
1122
+ for (const [a, b] of relations) {
1123
+ union(a, b);
1124
+ }
1125
+ const classes = /* @__PURE__ */ new Map();
1126
+ for (const key of parent.keys()) {
1127
+ const root = find(key);
1128
+ const existing = classes.get(root) ?? /* @__PURE__ */ new Set();
1129
+ existing.add(key);
1130
+ classes.set(root, existing);
1131
+ }
1132
+ const result = /* @__PURE__ */ new Map();
1133
+ for (const members of classes.values()) {
1134
+ for (const member of members) {
1135
+ const others = new Set(members);
1136
+ others.delete(member);
1137
+ result.set(member, others);
1138
+ }
1139
+ }
1140
+ return result;
1141
+ }
1142
+ function computeIriMapping(relations) {
1143
+ const result = /* @__PURE__ */ new Map();
1144
+ for (const [a, b] of relations) {
1145
+ if (isExternalIri(a) && !isExternalIri(b)) {
1146
+ result.set(a, b);
1147
+ } else if (isExternalIri(b) && !isExternalIri(a)) {
1148
+ result.set(b, a);
1149
+ }
1150
+ }
1151
+ return result;
1152
+ }
1153
+ function computeDisjointPairs(relations) {
1154
+ const result = /* @__PURE__ */ new Set();
1155
+ for (const [a, b] of relations) {
1156
+ const normalized = a < b ? `${a}|${b}` : `${b}|${a}`;
1157
+ result.add(normalized);
1158
+ }
1159
+ return result;
1160
+ }
1161
+ function computeEdgeInverses(relations) {
1162
+ const result = /* @__PURE__ */ new Map();
1163
+ for (const [a, b] of relations) {
1164
+ result.set(a, b);
1165
+ result.set(b, a);
1166
+ }
1167
+ return result;
1168
+ }
1169
+
1170
+ // src/schema/serializer.ts
1171
+ function serializeSchema(graph, version) {
1172
+ const nodes = serializeNodes(graph);
1173
+ const edges = serializeEdges(graph);
1174
+ const ontology = serializeOntology(graph.ontology);
1175
+ const indexes = serializeIndexes(graph.indexes);
1176
+ const extension = canonicalExtension(graph.extension);
1177
+ const deprecatedKinds = serializeDeprecatedKinds(graph.deprecatedKinds);
1178
+ return {
1179
+ graphId: graph.id,
1180
+ version,
1181
+ generatedAt: nowIso(),
1182
+ nodes,
1183
+ edges,
1184
+ ontology,
1185
+ defaults: {
1186
+ onNodeDelete: graph.defaults.onNodeDelete,
1187
+ temporalMode: graph.defaults.temporalMode
1188
+ },
1189
+ // `serializeIndexes` collapses both absent and empty inputs to
1190
+ // `undefined` (see the helper's docstring); omit the field entirely
1191
+ // in that case so legacy graphs hash byte-identically to the
1192
+ // pre-`indexes` form.
1193
+ ...indexes === void 0 ? {} : { indexes },
1194
+ // The graph extension is the durable source the loader uses to
1195
+ // rebuild extension-kind Zod validators on restart. Omitted on
1196
+ // graphs that have never been extended so legacy schemas hash
1197
+ // byte-identically.
1198
+ ...extension === void 0 ? {} : { extension },
1199
+ // Soft-deprecated kind names. Omitted when empty so legacy
1200
+ // schemas hash byte-identically; sorted for canonical-form
1201
+ // stability across insertion-order differences.
1202
+ ...deprecatedKinds === void 0 ? {} : { deprecatedKinds }
1203
+ };
1204
+ }
1205
+ function serializeDeprecatedKinds(set) {
1206
+ if (set === void 0 || set.size === 0) return void 0;
1207
+ return [...set].toSorted();
1208
+ }
1209
+ function canonicalExtension(document) {
1210
+ if (document === void 0) return void 0;
1211
+ if (document.version === void 0) return document;
1212
+ if (document.version !== LEGACY_GRAPH_EXTENSION_VERSION) return document;
1213
+ const { version: _omit, ...rest } = document;
1214
+ return rest;
1215
+ }
1216
+ function canonicalAnnotations(annotations) {
1217
+ if (annotations === void 0) return void 0;
1218
+ if (Object.keys(annotations).length === 0) return void 0;
1219
+ return annotations;
1220
+ }
1221
+ function serializeIndexes(indexes) {
1222
+ if (indexes === void 0 || indexes.length === 0) return void 0;
1223
+ return indexes.toSorted(
1224
+ (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
1225
+ ).map((index) => serializeIndexDeclaration(index));
1226
+ }
1227
+ function serializeIndexDeclaration(declaration) {
1228
+ if (declaration.entity === "node") {
1229
+ return serializeNodeIndexDeclaration(declaration);
1230
+ }
1231
+ if (declaration.entity === "edge") {
1232
+ return serializeEdgeIndexDeclaration(declaration);
1233
+ }
1234
+ return serializeVectorIndexDeclaration(declaration);
1235
+ }
1236
+ function serializeVectorIndexDeclaration(declaration) {
1237
+ return {
1238
+ entity: "vector",
1239
+ kind: declaration.kind,
1240
+ name: declaration.name,
1241
+ fieldPath: declaration.fieldPath,
1242
+ dimensions: declaration.dimensions,
1243
+ metric: declaration.metric,
1244
+ indexType: declaration.indexType,
1245
+ indexParams: declaration.indexParams,
1246
+ ...declaration.origin === "runtime" ? { origin: "runtime" } : {}
1247
+ };
1248
+ }
1249
+ function serializeNodeIndexDeclaration(declaration) {
1250
+ return {
1251
+ entity: "node",
1252
+ kind: declaration.kind,
1253
+ name: declaration.name,
1254
+ fields: declaration.fields,
1255
+ fieldValueTypes: declaration.fieldValueTypes,
1256
+ coveringFields: declaration.coveringFields,
1257
+ coveringFieldValueTypes: declaration.coveringFieldValueTypes,
1258
+ unique: declaration.unique,
1259
+ scope: declaration.scope,
1260
+ where: declaration.where,
1261
+ // `origin: "compile-time"` is the default and is omitted from the
1262
+ // canonical form (absence == compile-time). Only `runtime` is
1263
+ // emitted explicitly so the restart loader can route the declaration
1264
+ // through the runtime compiler.
1265
+ ...declaration.origin === "runtime" ? { origin: "runtime" } : {}
1266
+ };
1267
+ }
1268
+ function serializeEdgeIndexDeclaration(declaration) {
1269
+ return {
1270
+ entity: "edge",
1271
+ kind: declaration.kind,
1272
+ name: declaration.name,
1273
+ direction: declaration.direction,
1274
+ fields: declaration.fields,
1275
+ fieldValueTypes: declaration.fieldValueTypes,
1276
+ coveringFields: declaration.coveringFields,
1277
+ coveringFieldValueTypes: declaration.coveringFieldValueTypes,
1278
+ unique: declaration.unique,
1279
+ scope: declaration.scope,
1280
+ where: declaration.where,
1281
+ ...declaration.origin === "runtime" ? { origin: "runtime" } : {}
1282
+ };
1283
+ }
1284
+ function serializeNodes(graph) {
1285
+ const result = {};
1286
+ for (const kindName of getNodeKinds(graph)) {
1287
+ const registration = graph.nodes[kindName];
1288
+ if (registration === void 0) continue;
1289
+ result[kindName] = serializeNodeDef(registration);
1290
+ }
1291
+ return result;
1292
+ }
1293
+ function serializeNodeDef(registration) {
1294
+ const node = registration.type;
1295
+ const annotations = canonicalAnnotations(node.annotations);
1296
+ return {
1297
+ kind: node.kind,
1298
+ properties: serializeZodSchema(node.schema),
1299
+ uniqueConstraints: serializeUniqueConstraints(registration.unique ?? []),
1300
+ onDelete: registration.onDelete ?? "restrict",
1301
+ description: node.description,
1302
+ ...annotations === void 0 ? {} : { annotations }
1303
+ };
1304
+ }
1305
+ function serializeUniqueConstraints(constraints) {
1306
+ return constraints.map((constraint) => ({
1307
+ name: constraint.name,
1308
+ fields: [...constraint.fields],
1309
+ where: constraint.where ? serializeWherePredicate(constraint.where) : void 0,
1310
+ scope: constraint.scope,
1311
+ collation: constraint.collation
1312
+ }));
1313
+ }
1314
+ function serializeWherePredicate(whereFunction) {
1315
+ const builder = new Proxy(
1316
+ {},
1317
+ {
1318
+ get(_target, field) {
1319
+ return {
1320
+ isNull: () => ({
1321
+ __type: "unique_predicate",
1322
+ field,
1323
+ op: "isNull"
1324
+ }),
1325
+ isNotNull: () => ({
1326
+ __type: "unique_predicate",
1327
+ field,
1328
+ op: "isNotNull"
1329
+ })
1330
+ };
1331
+ }
1332
+ }
1333
+ );
1334
+ const predicate = whereFunction(builder);
1335
+ return JSON.stringify({ field: predicate.field, op: predicate.op });
1336
+ }
1337
+ function deserializeWherePredicate(serialized) {
1338
+ const parsed = JSON.parse(serialized);
1339
+ return (builder) => {
1340
+ const fieldBuilder = builder[parsed.field];
1341
+ if (!fieldBuilder) {
1342
+ throw new Error(`Unknown field in where predicate: ${parsed.field}`);
1343
+ }
1344
+ const result = parsed.op === "isNull" ? fieldBuilder.isNull() : fieldBuilder.isNotNull();
1345
+ return {
1346
+ __type: "unique_predicate",
1347
+ field: result.field,
1348
+ op: result.op
1349
+ };
1350
+ };
1351
+ }
1352
+ function serializeEdges(graph) {
1353
+ const result = {};
1354
+ for (const kindName of getEdgeKinds(graph)) {
1355
+ const registration = graph.edges[kindName];
1356
+ if (registration === void 0) continue;
1357
+ result[kindName] = serializeEdgeDef(registration);
1358
+ }
1359
+ return result;
1360
+ }
1361
+ function serializeEdgeDef(registration) {
1362
+ const edge = registration.type;
1363
+ const annotations = canonicalAnnotations(edge.annotations);
1364
+ return {
1365
+ kind: edge.kind,
1366
+ fromKinds: registration.from.map((node) => node.kind),
1367
+ toKinds: registration.to.map((node) => node.kind),
1368
+ properties: serializeZodSchema(edge.schema),
1369
+ cardinality: registration.cardinality ?? "many",
1370
+ endpointExistence: registration.endpointExistence ?? "notDeleted",
1371
+ description: edge.description,
1372
+ ...annotations === void 0 ? {} : { annotations }
1373
+ };
1374
+ }
1375
+ function serializeOntology(relations) {
1376
+ const metaEdgeMap = /* @__PURE__ */ new Map();
1377
+ for (const relation of relations) {
1378
+ const metaEdge = relation.metaEdge;
1379
+ if (!metaEdgeMap.has(metaEdge.name)) {
1380
+ metaEdgeMap.set(metaEdge.name, metaEdge);
1381
+ }
1382
+ }
1383
+ const metaEdges = {};
1384
+ for (const [name, metaEdge] of metaEdgeMap) {
1385
+ metaEdges[name] = serializeMetaEdge(metaEdge);
1386
+ }
1387
+ const serializedRelations = relations.map(
1388
+ (relation) => serializeOntologyRelation(relation)
1389
+ );
1390
+ const closures = serializeClosures(relations);
1391
+ return {
1392
+ metaEdges,
1393
+ relations: serializedRelations,
1394
+ closures
1395
+ };
1396
+ }
1397
+ function serializeMetaEdge(metaEdge) {
1398
+ return {
1399
+ name: metaEdge.name,
1400
+ transitive: metaEdge.properties.transitive,
1401
+ symmetric: metaEdge.properties.symmetric,
1402
+ reflexive: metaEdge.properties.reflexive,
1403
+ inverse: metaEdge.properties.inverse,
1404
+ inference: metaEdge.properties.inference,
1405
+ description: metaEdge.properties.description
1406
+ };
1407
+ }
1408
+ function serializeOntologyRelation(relation) {
1409
+ return {
1410
+ metaEdge: relation.metaEdge.name,
1411
+ from: getTypeName(relation.from),
1412
+ to: getTypeName(relation.to)
1413
+ };
1414
+ }
1415
+ function serializeClosures(relations) {
1416
+ if (relations.length === 0) {
1417
+ return {
1418
+ subClassAncestors: {},
1419
+ subClassDescendants: {},
1420
+ broaderClosure: {},
1421
+ narrowerClosure: {},
1422
+ equivalenceSets: {},
1423
+ disjointPairs: [],
1424
+ partOfClosure: {},
1425
+ hasPartClosure: {},
1426
+ iriToKind: {},
1427
+ edgeInverses: {},
1428
+ edgeImplicationsClosure: {},
1429
+ edgeImplyingClosure: {}
1430
+ };
1431
+ }
1432
+ const computed = computeClosuresFromOntology(relations);
1433
+ return {
1434
+ subClassAncestors: mapToRecord(computed.subClassAncestors),
1435
+ subClassDescendants: mapToRecord(computed.subClassDescendants),
1436
+ broaderClosure: mapToRecord(computed.broaderClosure),
1437
+ narrowerClosure: mapToRecord(computed.narrowerClosure),
1438
+ equivalenceSets: mapToRecord(computed.equivalenceSets),
1439
+ disjointPairs: [...computed.disjointPairs],
1440
+ partOfClosure: mapToRecord(computed.partOfClosure),
1441
+ hasPartClosure: mapToRecord(computed.hasPartClosure),
1442
+ iriToKind: mapToSimpleRecord(computed.iriToKind),
1443
+ edgeInverses: mapToSimpleRecord(computed.edgeInverses),
1444
+ edgeImplicationsClosure: mapToRecord(computed.edgeImplicationsClosure),
1445
+ edgeImplyingClosure: mapToRecord(computed.edgeImplyingClosure)
1446
+ };
1447
+ }
1448
+ function mapToRecord(map) {
1449
+ const result = {};
1450
+ for (const [key, values] of map) {
1451
+ result[key] = [...values];
1452
+ }
1453
+ return result;
1454
+ }
1455
+ function mapToSimpleRecord(map) {
1456
+ const result = {};
1457
+ for (const [key, value] of map) {
1458
+ result[key] = value;
1459
+ }
1460
+ return result;
1461
+ }
1462
+ var SCHEMA_PROPERTIES_CACHE = /* @__PURE__ */ new WeakMap();
1463
+ function serializeSchemaProperties(schema) {
1464
+ const cached = SCHEMA_PROPERTIES_CACHE.get(schema);
1465
+ if (cached !== void 0) return cached;
1466
+ const computed = serializeZodSchema(schema);
1467
+ SCHEMA_PROPERTIES_CACHE.set(schema, computed);
1468
+ return computed;
1469
+ }
1470
+ function serializeZodSchema(schema) {
1471
+ try {
1472
+ const jsonSchema = z.toJSONSchema(schema);
1473
+ return jsonSchema;
1474
+ } catch {
1475
+ return { type: "object" };
1476
+ }
1477
+ }
1478
+ var SCHEMA_HASH_CACHE = /* @__PURE__ */ new WeakMap();
1479
+ async function getSchemaHash(graph, version) {
1480
+ const perGraph = SCHEMA_HASH_CACHE.get(graph);
1481
+ const cached = perGraph?.get(version);
1482
+ if (cached !== void 0) return cached;
1483
+ const hash = await computeSchemaHash(serializeSchema(graph, version));
1484
+ if (perGraph === void 0) {
1485
+ SCHEMA_HASH_CACHE.set(graph, /* @__PURE__ */ new Map([[version, hash]]));
1486
+ } else {
1487
+ perGraph.set(version, hash);
1488
+ }
1489
+ return hash;
1490
+ }
1491
+ async function computeSchemaHash(schema) {
1492
+ const hashable = {
1493
+ graphId: schema.graphId,
1494
+ nodes: schema.nodes,
1495
+ edges: schema.edges,
1496
+ ontology: schema.ontology,
1497
+ defaults: schema.defaults,
1498
+ ...schema.indexes === void 0 ? {} : { indexes: schema.indexes },
1499
+ ...schema.extension === void 0 ? {} : { extension: schema.extension },
1500
+ ...schema.deprecatedKinds === void 0 ? {} : { deprecatedKinds: schema.deprecatedKinds }
1501
+ };
1502
+ const json = JSON.stringify(hashable, sortedReplacer);
1503
+ return sha256Hex(json);
1504
+ }
1505
+ var COMPILE_NODE_CACHE = /* @__PURE__ */ new Map();
1506
+ var COMPILE_EDGE_SCHEMA_CACHE = /* @__PURE__ */ new WeakMap();
1507
+ function compileGraphExtension(document) {
1508
+ const nodes = [];
1509
+ const nodeTypeByName = /* @__PURE__ */ new Map();
1510
+ for (const [kindName, nodeDocument] of Object.entries(document.nodes ?? {})) {
1511
+ const compiled = compileNodeCached(kindName, nodeDocument);
1512
+ nodes.push(compiled);
1513
+ nodeTypeByName.set(kindName, compiled.type);
1514
+ }
1515
+ const edges = [];
1516
+ for (const [kindName, edgeDocument] of Object.entries(document.edges ?? {})) {
1517
+ const compiled = compileEdge(kindName, edgeDocument, nodeTypeByName);
1518
+ edges.push(compiled);
1519
+ }
1520
+ const ontology = [];
1521
+ for (const relation of document.ontology ?? []) {
1522
+ ontology.push(compileOntologyRelation(relation, nodeTypeByName));
1523
+ }
1524
+ return Object.freeze({
1525
+ nodes: Object.freeze(nodes),
1526
+ edges: Object.freeze(edges),
1527
+ ontology: Object.freeze(ontology),
1528
+ // Indexes pass through — the merge step resolves the kind name
1529
+ // against graph-extension-or-compile-time NodeType / EdgeType and builds
1530
+ // the final `IndexDeclaration` via `defineNodeIndex` /
1531
+ // `defineEdgeIndex`.
1532
+ indexes: Object.freeze([...document.indexes ?? []])
1533
+ });
1534
+ }
1535
+ function compileNodeCached(kindName, document) {
1536
+ const perName = COMPILE_NODE_CACHE.get(kindName);
1537
+ const cached = perName?.get(document);
1538
+ if (cached !== void 0) return cached;
1539
+ const computed = compileNode(kindName, document);
1540
+ if (perName === void 0) {
1541
+ COMPILE_NODE_CACHE.set(kindName, new WeakMap([[document, computed]]));
1542
+ } else {
1543
+ perName.set(document, computed);
1544
+ }
1545
+ return computed;
1546
+ }
1547
+ function compileNode(kindName, document) {
1548
+ const schema = buildObjectSchema(document.properties);
1549
+ const type = defineNode(
1550
+ kindName,
1551
+ compactUndefined({
1552
+ schema,
1553
+ description: document.description,
1554
+ annotations: document.annotations
1555
+ })
1556
+ );
1557
+ const unique = (document.unique ?? []).map(
1558
+ (constraint) => compileUniqueConstraint(constraint)
1559
+ );
1560
+ return Object.freeze({ type, unique: Object.freeze(unique) });
1561
+ }
1562
+ function compileEdge(kindName, document, nodeTypeByName) {
1563
+ let schema = COMPILE_EDGE_SCHEMA_CACHE.get(document);
1564
+ if (schema === void 0) {
1565
+ schema = buildObjectSchema(document.properties ?? {});
1566
+ COMPILE_EDGE_SCHEMA_CACHE.set(document, schema);
1567
+ }
1568
+ const from = document.from.map(
1569
+ (name) => nodeTypeByName.get(name) ?? name
1570
+ );
1571
+ const to = document.to.map(
1572
+ (name) => nodeTypeByName.get(name) ?? name
1573
+ );
1574
+ return Object.freeze(
1575
+ compactUndefined({
1576
+ kindName,
1577
+ schema,
1578
+ description: document.description,
1579
+ annotations: document.annotations,
1580
+ from: Object.freeze(from),
1581
+ to: Object.freeze(to)
1582
+ })
1583
+ );
1584
+ }
1585
+ function buildObjectSchema(properties) {
1586
+ const shape = {};
1587
+ for (const [propertyName, propertyType] of Object.entries(properties)) {
1588
+ shape[propertyName] = applyOptional(
1589
+ compileProperty(propertyType),
1590
+ propertyType
1591
+ );
1592
+ }
1593
+ return z.object(shape);
1594
+ }
1595
+ function compileProperty(property) {
1596
+ switch (property.type) {
1597
+ case "string": {
1598
+ return compileStringProperty(property);
1599
+ }
1600
+ case "number": {
1601
+ return compileNumberProperty(property);
1602
+ }
1603
+ case "boolean": {
1604
+ return z.boolean();
1605
+ }
1606
+ case "enum": {
1607
+ return compileEnumProperty(property);
1608
+ }
1609
+ case "array": {
1610
+ return compileArrayProperty(property);
1611
+ }
1612
+ case "object": {
1613
+ return compileObjectProperty(property);
1614
+ }
1615
+ }
1616
+ }
1617
+ function compileStringProperty(property) {
1618
+ if (property.searchable !== void 0) {
1619
+ return applyStringRefinements(searchable(property.searchable), property);
1620
+ }
1621
+ if (property.format === void 0) {
1622
+ return applyStringRefinements(z.string(), property);
1623
+ }
1624
+ switch (property.format) {
1625
+ case "datetime": {
1626
+ return z.iso.datetime();
1627
+ }
1628
+ case "date": {
1629
+ return z.iso.date();
1630
+ }
1631
+ case "uri": {
1632
+ return z.url();
1633
+ }
1634
+ case "email": {
1635
+ return z.email();
1636
+ }
1637
+ case "uuid": {
1638
+ return z.uuid();
1639
+ }
1640
+ }
1641
+ }
1642
+ function applyStringRefinements(base, property) {
1643
+ let schema = base;
1644
+ if (property.minLength !== void 0) schema = schema.min(property.minLength);
1645
+ if (property.maxLength !== void 0) schema = schema.max(property.maxLength);
1646
+ if (property.pattern !== void 0) {
1647
+ schema = schema.regex(new RegExp(property.pattern));
1648
+ }
1649
+ return schema;
1650
+ }
1651
+ function compileNumberProperty(property) {
1652
+ let schema = z.number();
1653
+ if (property.int === true) {
1654
+ schema = schema.int();
1655
+ }
1656
+ if (property.min !== void 0) {
1657
+ schema = schema.min(property.min);
1658
+ }
1659
+ if (property.max !== void 0) {
1660
+ schema = schema.max(property.max);
1661
+ }
1662
+ return schema;
1663
+ }
1664
+ function compileEnumProperty(property) {
1665
+ return z.enum(property.values);
1666
+ }
1667
+ function compileArrayProperty(property) {
1668
+ if (property.embedding !== void 0) {
1669
+ return embedding(property.embedding.dimensions);
1670
+ }
1671
+ const inner = compilePropertyForArrayItem(property.items);
1672
+ return z.array(inner);
1673
+ }
1674
+ function compilePropertyForArrayItem(item) {
1675
+ return applyOptional(compileProperty(item), item);
1676
+ }
1677
+ function compileObjectProperty(property) {
1678
+ return buildObjectSchema(property.properties);
1679
+ }
1680
+ function applyOptional(schema, property) {
1681
+ return property.optional === true ? schema.optional() : schema;
1682
+ }
1683
+ function compileUniqueConstraint(document) {
1684
+ const base = {
1685
+ name: document.name,
1686
+ fields: document.fields,
1687
+ scope: document.scope ?? "kind",
1688
+ collation: document.collation ?? "binary"
1689
+ };
1690
+ if (document.where === void 0) {
1691
+ return base;
1692
+ }
1693
+ return {
1694
+ ...base,
1695
+ where: makeWherePredicate(document.where.field, document.where.op)
1696
+ };
1697
+ }
1698
+ function makeWherePredicate(field, op) {
1699
+ return (props) => {
1700
+ const builder = props[field];
1701
+ if (builder === void 0) {
1702
+ return { __type: "unique_predicate", field, op };
1703
+ }
1704
+ const result = op === "isNull" ? builder.isNull() : builder.isNotNull();
1705
+ return result;
1706
+ };
1707
+ }
1708
+ var META_EDGE_BY_NAME = Object.fromEntries(
1709
+ ALL_META_EDGE_NAMES.map((name) => [name, core[`${name}MetaEdge`]])
1710
+ );
1711
+ function compileOntologyRelation(relation, nodeTypeByName) {
1712
+ const metaEdge = META_EDGE_BY_NAME[relation.metaEdge];
1713
+ const fromNode = nodeTypeByName.get(relation.from);
1714
+ const toNode = nodeTypeByName.get(relation.to);
1715
+ return {
1716
+ metaEdge,
1717
+ from: fromNode ?? relation.from,
1718
+ to: toNode ?? relation.to
1719
+ };
1720
+ }
1721
+
1722
+ // src/graph-extension/ontology-keys.ts
1723
+ function graphExtensionOntologyKey(entry) {
1724
+ return `${entry.metaEdge}|${entry.from}|${entry.to}`;
1725
+ }
1726
+ function compileTimeOntologyKey(relation) {
1727
+ return `${relation.metaEdge.name}|${getTypeName(relation.from)}|${getTypeName(relation.to)}`;
1728
+ }
1729
+ function buildGraphExtensionOntologyKeySet(document) {
1730
+ return new Set(
1731
+ (document?.ontology ?? []).map((entry) => graphExtensionOntologyKey(entry))
1732
+ );
1733
+ }
1734
+ function extensionKindNames(document) {
1735
+ return {
1736
+ nodes: new Set(Object.keys(document?.nodes ?? {})),
1737
+ edges: new Set(Object.keys(document?.edges ?? {}))
1738
+ };
1739
+ }
1740
+
1741
+ // src/graph-extension/merge.ts
1742
+ function mergeGraphExtension(graph, document) {
1743
+ const existingDocument = graph.extension ?? Object.freeze({});
1744
+ const unionDocument = unionDocuments(existingDocument, document);
1745
+ if (graph.extension !== void 0 && canonicalEqual(unionDocument, existingDocument)) {
1746
+ return graph;
1747
+ }
1748
+ const validatedUnion = unwrap(validateGraphExtension(unionDocument));
1749
+ const compiled = compileGraphExtension(validatedUnion);
1750
+ const { nodes: runtimeNodeNames, edges: runtimeEdgeNames } = extensionKindNames(existingDocument);
1751
+ const nodeKinds = /* @__PURE__ */ new Map();
1752
+ for (const registration of Object.values(graph.nodes)) {
1753
+ if (runtimeNodeNames.has(registration.type.kind)) continue;
1754
+ nodeKinds.set(registration.type.kind, registration.type);
1755
+ }
1756
+ for (const node of compiled.nodes) {
1757
+ assertNoCollision(
1758
+ node.type.kind,
1759
+ "node",
1760
+ nodeKinds.has(node.type.kind),
1761
+ graph.id
1762
+ );
1763
+ nodeKinds.set(node.type.kind, node.type);
1764
+ }
1765
+ const mergedNodes = {};
1766
+ for (const [name, registration] of Object.entries(graph.nodes)) {
1767
+ if (runtimeNodeNames.has(name)) continue;
1768
+ mergedNodes[name] = registration;
1769
+ }
1770
+ for (const node of compiled.nodes) {
1771
+ mergedNodes[node.type.kind] = {
1772
+ type: node.type,
1773
+ ...node.unique.length === 0 ? {} : { unique: [...node.unique] }
1774
+ };
1775
+ }
1776
+ const mergedEdges = {};
1777
+ for (const [name, registration] of Object.entries(graph.edges)) {
1778
+ if (runtimeEdgeNames.has(name)) continue;
1779
+ mergedEdges[name] = registration;
1780
+ }
1781
+ for (const edge of compiled.edges) {
1782
+ assertNoCollision(
1783
+ edge.kindName,
1784
+ "edge",
1785
+ mergedEdges[edge.kindName] !== void 0,
1786
+ graph.id
1787
+ );
1788
+ const from = resolveEndpoints(edge.from, nodeKinds, {
1789
+ graphId: graph.id,
1790
+ edgeKind: edge.kindName,
1791
+ side: "from"
1792
+ });
1793
+ const to = resolveEndpoints(edge.to, nodeKinds, {
1794
+ graphId: graph.id,
1795
+ edgeKind: edge.kindName,
1796
+ side: "to"
1797
+ });
1798
+ const type = defineEdge(
1799
+ edge.kindName,
1800
+ compactUndefined({
1801
+ schema: edge.schema,
1802
+ description: edge.description,
1803
+ annotations: edge.annotations,
1804
+ from,
1805
+ to
1806
+ })
1807
+ );
1808
+ mergedEdges[edge.kindName] = { type, from, to };
1809
+ }
1810
+ const runtimeOntologyKeys = buildGraphExtensionOntologyKeySet(existingDocument);
1811
+ const compileTimeOntology = graph.ontology.filter(
1812
+ (relation) => !runtimeOntologyKeys.has(compileTimeOntologyKey(relation))
1813
+ );
1814
+ const mergedOntology = [
1815
+ ...compileTimeOntology,
1816
+ ...compiled.ontology.map(
1817
+ (relation) => resolveOntologyEndpoints(relation, nodeKinds)
1818
+ )
1819
+ ];
1820
+ const runtimeVectorIndexes = deriveGraphExtensionVectorIndexes(compiled.nodes);
1821
+ const runtimeRelationalIndexes = compileGraphExtensionRelationalIndexes(
1822
+ compiled.indexes,
1823
+ nodeKinds,
1824
+ mergedEdges,
1825
+ graph.id
1826
+ );
1827
+ const mergedIndexes = mergeIndexesWithGraphExtension(
1828
+ graph.indexes,
1829
+ [...runtimeVectorIndexes, ...runtimeRelationalIndexes],
1830
+ graph.id
1831
+ );
1832
+ return Object.freeze({
1833
+ ...graph,
1834
+ nodes: mergedNodes,
1835
+ edges: mergedEdges,
1836
+ ontology: mergedOntology,
1837
+ indexes: mergedIndexes,
1838
+ extension: validatedUnion
1839
+ });
1840
+ }
1841
+ function deriveGraphExtensionVectorIndexes(compiledNodes) {
1842
+ if (compiledNodes.length === 0) return [];
1843
+ const registrations = {};
1844
+ for (const compiled of compiledNodes) {
1845
+ registrations[compiled.type.kind] = {
1846
+ type: compiled.type,
1847
+ ...compiled.unique.length === 0 ? {} : { unique: [...compiled.unique] }
1848
+ };
1849
+ }
1850
+ return autoDeriveVectorIndexes(registrations).map(
1851
+ (index) => Object.freeze({ ...index, origin: "runtime" })
1852
+ );
1853
+ }
1854
+ function mergeIndexesWithGraphExtension(existing, runtimeIndexes, graphId) {
1855
+ if (existing === void 0 && runtimeIndexes.length === 0) {
1856
+ return void 0;
1857
+ }
1858
+ const compileTimeIndexes = (existing ?? []).filter(
1859
+ (index) => index.origin !== "runtime"
1860
+ );
1861
+ if (runtimeIndexes.length === 0) return compileTimeIndexes;
1862
+ const runtimeVectors = runtimeIndexes.filter(
1863
+ (index) => index.entity === "vector"
1864
+ );
1865
+ const runtimeRelational = runtimeIndexes.filter(
1866
+ (index) => index.entity !== "vector"
1867
+ );
1868
+ const vectorMerged = mergeVectorIndexes(compileTimeIndexes, runtimeVectors);
1869
+ const merged = [...vectorMerged, ...runtimeRelational];
1870
+ assertUniqueIndexNames(merged, graphId);
1871
+ return merged;
1872
+ }
1873
+ function assertUniqueIndexNames(indexes, graphId) {
1874
+ const seen = /* @__PURE__ */ new Set();
1875
+ for (const index of indexes) {
1876
+ if (!seen.has(index.name)) {
1877
+ seen.add(index.name);
1878
+ continue;
1879
+ }
1880
+ throw new ConfigurationError(
1881
+ `Duplicate index name "${index.name}" after merging graph extension into graph "${graphId}". Index names must be unique within a graph.`,
1882
+ { graphId, indexName: index.name, code: "DUPLICATE_INDEX_NAME" },
1883
+ {
1884
+ suggestion: "Give the graph-extension index a unique `name`, or remove the duplicate declaration."
1885
+ }
1886
+ );
1887
+ }
1888
+ }
1889
+ function compileGraphExtensionRelationalIndexes(documents, nodeKinds, mergedEdges, graphId) {
1890
+ if (documents.length === 0) return [];
1891
+ const result = [];
1892
+ for (const document of documents) {
1893
+ if (document.entity === "node") {
1894
+ const node = nodeKinds.get(document.kind);
1895
+ if (node === void 0) {
1896
+ throw new KindNotFoundError(document.kind, "node", {
1897
+ graphId,
1898
+ suggestion: "Declare the kind under `nodes` in this graph extension, or remove the index from `indexes`."
1899
+ });
1900
+ }
1901
+ const declaration2 = defineNodeIndex(
1902
+ node,
1903
+ toNodeIndexConfig(document)
1904
+ );
1905
+ result.push(Object.freeze({ ...declaration2, origin: "runtime" }));
1906
+ continue;
1907
+ }
1908
+ const edgeRegistration = mergedEdges[document.kind];
1909
+ if (edgeRegistration === void 0) {
1910
+ throw new KindNotFoundError(document.kind, "edge", {
1911
+ graphId,
1912
+ suggestion: "Declare the edge under `edges` in this graph extension, or remove the index from `indexes`."
1913
+ });
1914
+ }
1915
+ const declaration = defineEdgeIndex(
1916
+ edgeRegistration.type,
1917
+ toEdgeIndexConfig(document)
1918
+ );
1919
+ result.push(Object.freeze({ ...declaration, origin: "runtime" }));
1920
+ }
1921
+ return result;
1922
+ }
1923
+ function buildWhereCallback(where) {
1924
+ return (props) => {
1925
+ const builder = props[where.field];
1926
+ if (builder === void 0) {
1927
+ throw new ConfigurationError(
1928
+ `Graph-extension index \`where\` references unknown field "${where.field}".`,
1929
+ { field: where.field, code: "EXTENSION_INDEX_WHERE_UNKNOWN_FIELD" }
1930
+ );
1931
+ }
1932
+ return where.op === "isNull" ? builder.isNull() : builder.isNotNull();
1933
+ };
1934
+ }
1935
+ function toNodeIndexConfig(document) {
1936
+ return compactUndefined({
1937
+ fields: document.fields,
1938
+ coveringFields: document.coveringFields,
1939
+ unique: document.unique,
1940
+ name: document.name,
1941
+ scope: document.scope,
1942
+ where: document.where === void 0 ? void 0 : buildWhereCallback(document.where)
1943
+ });
1944
+ }
1945
+ function toEdgeIndexConfig(document) {
1946
+ return compactUndefined({
1947
+ fields: document.fields,
1948
+ coveringFields: document.coveringFields,
1949
+ unique: document.unique,
1950
+ name: document.name,
1951
+ scope: document.scope,
1952
+ direction: document.direction,
1953
+ where: document.where === void 0 ? void 0 : buildWhereCallback(document.where)
1954
+ });
1955
+ }
1956
+ function unionDocuments(existing, next) {
1957
+ if (isEmptyExtension(existing)) {
1958
+ return next;
1959
+ }
1960
+ const nodes = existing.nodes === void 0 && next.nodes === void 0 ? void 0 : { ...existing.nodes, ...next.nodes };
1961
+ const edges = existing.edges === void 0 && next.edges === void 0 ? void 0 : { ...existing.edges, ...next.edges };
1962
+ const ontology = existing.ontology === void 0 && next.ontology === void 0 ? void 0 : dedupBy(
1963
+ [...existing.ontology ?? [], ...next.ontology ?? []],
1964
+ graphExtensionOntologyKey
1965
+ );
1966
+ const indexes = existing.indexes === void 0 && next.indexes === void 0 ? void 0 : dedupBy(
1967
+ [...existing.indexes ?? [], ...next.indexes ?? []],
1968
+ indexCompositeKey,
1969
+ "last"
1970
+ );
1971
+ const version = next.version ?? existing.version;
1972
+ return Object.freeze({
1973
+ ...version === void 0 ? {} : { version },
1974
+ ...nodes === void 0 ? {} : { nodes },
1975
+ ...edges === void 0 ? {} : { edges },
1976
+ ...ontology === void 0 ? {} : { ontology },
1977
+ ...indexes === void 0 ? {} : { indexes }
1978
+ });
1979
+ }
1980
+ function dedupBy(items, keyFunction, strategy = "first") {
1981
+ const seen = /* @__PURE__ */ new Map();
1982
+ const order = [];
1983
+ for (const item of items) {
1984
+ const key = keyFunction(item);
1985
+ if (!seen.has(key)) {
1986
+ order.push(key);
1987
+ seen.set(key, item);
1988
+ } else if (strategy === "last") {
1989
+ seen.set(key, item);
1990
+ }
1991
+ }
1992
+ return order.map((key) => seen.get(key));
1993
+ }
1994
+ function indexCompositeKey(entry) {
1995
+ return `${entry.entity}|${entry.kind}|${entry.name ?? ""}|${entry.fields.join(",")}`;
1996
+ }
1997
+ function isEmptyExtension(extension) {
1998
+ return extension.nodes === void 0 && extension.edges === void 0 && extension.ontology === void 0 && extension.indexes === void 0;
1999
+ }
2000
+ function assertNoCollision(kindName, entity, collides, graphId) {
2001
+ if (!collides) return;
2002
+ throw new KindCollisionError(kindName, entity, graphId);
2003
+ }
2004
+ function resolveEndpoints(entries, nodeKinds, context) {
2005
+ return entries.map((entry) => {
2006
+ if (typeof entry !== "string") return entry;
2007
+ const resolved = nodeKinds.get(entry);
2008
+ if (resolved === void 0) {
2009
+ throw new GraphExtensionUnresolvedEndpointError(
2010
+ context.edgeKind,
2011
+ context.side,
2012
+ entry,
2013
+ context.graphId
2014
+ );
2015
+ }
2016
+ return resolved;
2017
+ });
2018
+ }
2019
+ function resolveOntologyEndpoints(relation, nodeKinds) {
2020
+ const from = typeof relation.from === "string" ? nodeKinds.get(relation.from) ?? relation.from : relation.from;
2021
+ const to = typeof relation.to === "string" ? nodeKinds.get(relation.to) ?? relation.to : relation.to;
2022
+ return { ...relation, from, to };
2023
+ }
2024
+ var deleteBehaviorZod = z.enum(["restrict", "cascade", "disconnect"]);
2025
+ var cardinalityZod = z.enum(["many", "one", "unique", "oneActive"]);
2026
+ var endpointExistenceZod = z.enum(["notDeleted", "currentlyValid", "ever"]);
2027
+ var temporalModeZod = z.enum([
2028
+ "current",
2029
+ "asOf",
2030
+ "includeEnded",
2031
+ "includeTombstones"
2032
+ ]);
2033
+ var uniquenessScopeZod = z.enum(["kind", "kindWithSubClasses"]);
2034
+ var collationZod = z.enum(["binary", "caseInsensitive"]);
2035
+ var inferenceTypeZod = z.enum([
2036
+ "subsumption",
2037
+ "hierarchy",
2038
+ "substitution",
2039
+ "constraint",
2040
+ "composition",
2041
+ "association",
2042
+ "none"
2043
+ ]);
2044
+ var indexScopeZod = z.enum(["graphAndKind", "graph", "none"]);
2045
+ var indexOriginZod = z.enum(["compile-time", "runtime"]);
2046
+ var edgeIndexDirectionZod = z.enum(["out", "in", "none"]);
2047
+ var valueTypeZod = z.enum([
2048
+ "string",
2049
+ "number",
2050
+ "boolean",
2051
+ "date",
2052
+ "array",
2053
+ "object",
2054
+ "embedding",
2055
+ "unknown"
2056
+ ]);
2057
+ var valueTypeOrUndefinedZod = valueTypeZod.optional();
2058
+ var systemColumnNameZod = z.enum([
2059
+ "graph_id",
2060
+ "kind",
2061
+ "id",
2062
+ "from_kind",
2063
+ "from_id",
2064
+ "to_kind",
2065
+ "to_id",
2066
+ "deleted_at",
2067
+ "valid_from",
2068
+ "valid_to",
2069
+ "created_at",
2070
+ "updated_at",
2071
+ "version"
2072
+ ]);
2073
+ var indexWhereOperandZod = z.discriminatedUnion("__type", [
2074
+ z.object({
2075
+ __type: z.literal("index_operand_system"),
2076
+ column: systemColumnNameZod,
2077
+ valueType: valueTypeOrUndefinedZod
2078
+ }),
2079
+ z.object({
2080
+ __type: z.literal("index_operand_prop"),
2081
+ field: z.string(),
2082
+ valueType: valueTypeOrUndefinedZod
2083
+ })
2084
+ ]);
2085
+ var indexWhereLiteralZod = z.object({
2086
+ __type: z.literal("index_where_literal"),
2087
+ value: z.union([z.string(), z.number(), z.boolean()]),
2088
+ valueType: valueTypeZod
2089
+ });
2090
+ var indexWhereOpZod = z.enum([
2091
+ "eq",
2092
+ "neq",
2093
+ "gt",
2094
+ "gte",
2095
+ "lt",
2096
+ "lte",
2097
+ "in",
2098
+ "notIn"
2099
+ ]);
2100
+ var indexWhereExpressionZod = z.lazy(
2101
+ () => z.discriminatedUnion("__type", [
2102
+ z.object({
2103
+ __type: z.literal("index_where_and"),
2104
+ predicates: z.array(indexWhereExpressionZod)
2105
+ }),
2106
+ z.object({
2107
+ __type: z.literal("index_where_or"),
2108
+ predicates: z.array(indexWhereExpressionZod)
2109
+ }),
2110
+ z.object({
2111
+ __type: z.literal("index_where_not"),
2112
+ predicate: indexWhereExpressionZod
2113
+ }),
2114
+ z.object({
2115
+ __type: z.literal("index_where_comparison"),
2116
+ left: indexWhereOperandZod,
2117
+ op: indexWhereOpZod,
2118
+ right: z.union([indexWhereLiteralZod, z.array(indexWhereLiteralZod)])
2119
+ }),
2120
+ z.object({
2121
+ __type: z.literal("index_where_null_check"),
2122
+ operand: indexWhereOperandZod,
2123
+ op: z.enum(["isNull", "isNotNull"])
2124
+ })
2125
+ ])
2126
+ );
2127
+ var jsonPointerZod = z.custom(
2128
+ (value) => typeof value === "string",
2129
+ { message: "Expected a JSON pointer string" }
2130
+ );
2131
+ var indexDeclarationCommonShape = {
2132
+ name: z.string(),
2133
+ // `origin` is optional. `"compile-time"` is the default and is omitted
2134
+ // from canonical form so legacy graphs without indexes hash
2135
+ // byte-identically. Consumers that need a concrete value should
2136
+ // coalesce `index.origin ?? "compile-time"`.
2137
+ origin: indexOriginZod.optional(),
2138
+ fields: z.array(jsonPointerZod),
2139
+ fieldValueTypes: z.array(valueTypeOrUndefinedZod),
2140
+ coveringFields: z.array(jsonPointerZod),
2141
+ coveringFieldValueTypes: z.array(valueTypeOrUndefinedZod),
2142
+ unique: z.boolean(),
2143
+ scope: indexScopeZod,
2144
+ where: indexWhereExpressionZod.optional()
2145
+ };
2146
+ var nodeIndexDeclarationZod = z.object({
2147
+ entity: z.literal("node"),
2148
+ kind: z.string(),
2149
+ ...indexDeclarationCommonShape
2150
+ }).loose();
2151
+ var edgeIndexDeclarationZod = z.object({
2152
+ entity: z.literal("edge"),
2153
+ kind: z.string(),
2154
+ direction: edgeIndexDirectionZod,
2155
+ ...indexDeclarationCommonShape
2156
+ }).loose();
2157
+ var vectorIndexMetricZod = z.enum(["cosine", "l2", "inner_product"]);
2158
+ var vectorIndexImplementationZod = z.enum(["hnsw", "ivfflat", "none"]);
2159
+ var vectorIndexParamsZod = z.object({
2160
+ m: z.number(),
2161
+ efConstruction: z.number(),
2162
+ lists: z.number().optional()
2163
+ }).loose();
2164
+ var vectorIndexDeclarationZod = z.object({
2165
+ entity: z.literal("vector"),
2166
+ name: z.string(),
2167
+ origin: indexOriginZod.optional(),
2168
+ kind: z.string(),
2169
+ fieldPath: z.string(),
2170
+ dimensions: z.number(),
2171
+ metric: vectorIndexMetricZod,
2172
+ indexType: vectorIndexImplementationZod,
2173
+ indexParams: vectorIndexParamsZod
2174
+ }).loose();
2175
+ var indexDeclarationZod = z.discriminatedUnion("entity", [
2176
+ nodeIndexDeclarationZod,
2177
+ edgeIndexDeclarationZod,
2178
+ vectorIndexDeclarationZod
2179
+ ]);
2180
+ var runtimePropertyZod = z.record(z.string(), z.unknown());
2181
+ var runtimeNodeDocumentZod = z.object({
2182
+ description: z.string().optional(),
2183
+ annotations: z.record(z.string(), z.json()).optional(),
2184
+ properties: z.record(z.string(), runtimePropertyZod),
2185
+ unique: z.array(z.object({}).loose()).optional()
2186
+ }).loose();
2187
+ var runtimeEdgeDocumentZod = z.object({
2188
+ description: z.string().optional(),
2189
+ annotations: z.record(z.string(), z.json()).optional(),
2190
+ from: z.array(z.string()),
2191
+ to: z.array(z.string()),
2192
+ properties: z.record(z.string(), runtimePropertyZod).optional()
2193
+ }).loose();
2194
+ var runtimeOntologyRelationZod = z.object({
2195
+ metaEdge: z.string(),
2196
+ from: z.string(),
2197
+ to: z.string()
2198
+ }).loose();
2199
+ var runtimeIndexDocumentZod = z.object({
2200
+ entity: z.string(),
2201
+ kind: z.string(),
2202
+ name: z.string().optional(),
2203
+ fields: z.array(z.string()).optional(),
2204
+ coveringFields: z.array(z.string()).optional(),
2205
+ unique: z.boolean().optional(),
2206
+ scope: z.string().optional(),
2207
+ direction: z.string().optional(),
2208
+ where: z.object({ field: z.string(), op: z.string() }).loose().optional()
2209
+ }).loose();
2210
+ var graphExtensionZod = z.object({
2211
+ // Version is parsed loosely here so the persistence boundary
2212
+ // never rejects a stored document — the runtime validator owns
2213
+ // the version check and produces actionable errors. Documents
2214
+ // that pre-date the field round-trip as `version: undefined`.
2215
+ version: z.number().optional(),
2216
+ nodes: z.record(z.string(), runtimeNodeDocumentZod).optional(),
2217
+ edges: z.record(z.string(), runtimeEdgeDocumentZod).optional(),
2218
+ ontology: z.array(runtimeOntologyRelationZod).optional(),
2219
+ indexes: z.array(runtimeIndexDocumentZod).optional()
2220
+ }).loose();
2221
+ function checkRecordKeyMatchesField(field, section) {
2222
+ return (record, ctx) => {
2223
+ for (const [key, value] of Object.entries(record)) {
2224
+ const embedded = value[field];
2225
+ if (typeof embedded === "string" && embedded !== key) {
2226
+ ctx.addIssue({
2227
+ code: "custom",
2228
+ path: [key, field],
2229
+ message: `Record key "${key}" does not match ${field} "${embedded}" in ${section}`
2230
+ });
2231
+ }
2232
+ }
2233
+ };
2234
+ }
2235
+ var serializedSchemaZod = z.object({
2236
+ graphId: z.string(),
2237
+ version: z.number(),
2238
+ generatedAt: z.string(),
2239
+ nodes: z.record(
2240
+ z.string(),
2241
+ z.object({
2242
+ kind: z.string(),
2243
+ properties: z.record(z.string(), z.unknown()),
2244
+ uniqueConstraints: z.array(
2245
+ z.object({
2246
+ name: z.string(),
2247
+ fields: z.array(z.string()),
2248
+ where: z.string().optional(),
2249
+ scope: uniquenessScopeZod,
2250
+ collation: collationZod
2251
+ }).loose()
2252
+ ),
2253
+ onDelete: deleteBehaviorZod,
2254
+ description: z.string().optional(),
2255
+ annotations: z.record(z.string(), z.json()).optional()
2256
+ }).loose()
2257
+ ).superRefine(checkRecordKeyMatchesField("kind", "nodes")),
2258
+ edges: z.record(
2259
+ z.string(),
2260
+ z.object({
2261
+ kind: z.string(),
2262
+ fromKinds: z.array(z.string()),
2263
+ toKinds: z.array(z.string()),
2264
+ properties: z.record(z.string(), z.unknown()),
2265
+ cardinality: cardinalityZod,
2266
+ endpointExistence: endpointExistenceZod,
2267
+ description: z.string().optional(),
2268
+ annotations: z.record(z.string(), z.json()).optional()
2269
+ }).loose()
2270
+ ).superRefine(checkRecordKeyMatchesField("kind", "edges")),
2271
+ ontology: z.object({
2272
+ metaEdges: z.record(
2273
+ z.string(),
2274
+ z.object({
2275
+ name: z.string(),
2276
+ transitive: z.boolean(),
2277
+ symmetric: z.boolean(),
2278
+ reflexive: z.boolean(),
2279
+ inference: inferenceTypeZod,
2280
+ inverse: z.string().optional(),
2281
+ description: z.string().optional()
2282
+ }).loose()
2283
+ ).superRefine(checkRecordKeyMatchesField("name", "ontology.metaEdges")),
2284
+ relations: z.array(
2285
+ z.object({
2286
+ metaEdge: z.string(),
2287
+ from: z.string(),
2288
+ to: z.string()
2289
+ }).loose()
2290
+ ),
2291
+ closures: z.object({
2292
+ subClassAncestors: z.record(z.string(), z.array(z.string())),
2293
+ subClassDescendants: z.record(z.string(), z.array(z.string())),
2294
+ broaderClosure: z.record(z.string(), z.array(z.string())),
2295
+ narrowerClosure: z.record(z.string(), z.array(z.string())),
2296
+ equivalenceSets: z.record(z.string(), z.array(z.string())),
2297
+ disjointPairs: z.array(z.string()),
2298
+ partOfClosure: z.record(z.string(), z.array(z.string())),
2299
+ hasPartClosure: z.record(z.string(), z.array(z.string())),
2300
+ iriToKind: z.record(z.string(), z.string()),
2301
+ edgeInverses: z.record(z.string(), z.string()),
2302
+ edgeImplicationsClosure: z.record(z.string(), z.array(z.string())),
2303
+ edgeImplyingClosure: z.record(z.string(), z.array(z.string()))
2304
+ }).loose()
2305
+ }).loose(),
2306
+ defaults: z.object({
2307
+ onNodeDelete: deleteBehaviorZod,
2308
+ temporalMode: temporalModeZod
2309
+ }).loose(),
2310
+ /**
2311
+ * Index declarations attached to the graph.
2312
+ *
2313
+ * Optional: graphs that never declared the slice omit the field
2314
+ * entirely so their canonical-form hash is byte-identical to graphs
2315
+ * authored before `indexes` existed.
2316
+ */
2317
+ indexes: z.array(indexDeclarationZod).optional(),
2318
+ /**
2319
+ * Graph extension persisted alongside the compiled `nodes` / `edges`
2320
+ * / `ontology` slices. The loader rebuilds extension-kind Zod
2321
+ * validators from this value (the only durable source); legacy
2322
+ * graphs omit the field and hash byte-identically to before
2323
+ * extensions existed.
2324
+ *
2325
+ * `.loose()` on the inner shape accepts forward-compatible additions
2326
+ * without breaking older readers.
2327
+ */
2328
+ extension: graphExtensionZod.optional(),
2329
+ /**
2330
+ * Names of node and edge kinds the operator has soft-deprecated via
2331
+ * `store.deprecateKinds(...)`. Surfaces in introspection so consumers
2332
+ * (codegen, UI tooling, lints) can route around them. Does not affect
2333
+ * reads, writes, or queries.
2334
+ *
2335
+ * Omitted when empty so legacy schemas hash byte-identically.
2336
+ */
2337
+ deprecatedKinds: z.array(z.string()).optional()
2338
+ });
2339
+
2340
+ // src/schema/manager.ts
2341
+ var PARSE_CACHE_LIMIT = 100;
2342
+ var PARSE_CACHE = /* @__PURE__ */ new Map();
2343
+ function parseSerializedSchema(json) {
2344
+ const cached = PARSE_CACHE.get(json);
2345
+ if (cached !== void 0) {
2346
+ PARSE_CACHE.delete(json);
2347
+ PARSE_CACHE.set(json, cached);
2348
+ return cached;
2349
+ }
2350
+ let parsed;
2351
+ try {
2352
+ parsed = JSON.parse(json);
2353
+ } catch {
2354
+ throw new DatabaseOperationError(
2355
+ "Stored schema document is not valid JSON",
2356
+ { operation: "select", entity: "schema" }
2357
+ );
2358
+ }
2359
+ const result = serializedSchemaZod.safeParse(parsed);
2360
+ if (!result.success) {
2361
+ const issues = result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
2362
+ throw new DatabaseOperationError(
2363
+ `Stored schema document is malformed: ${issues}`,
2364
+ { operation: "select", entity: "schema" }
2365
+ );
2366
+ }
2367
+ const validated = freezeDeep(result.data);
2368
+ if (PARSE_CACHE.size >= PARSE_CACHE_LIMIT) {
2369
+ const oldest = PARSE_CACHE.keys().next().value;
2370
+ if (oldest !== void 0) PARSE_CACHE.delete(oldest);
2371
+ }
2372
+ PARSE_CACHE.set(json, validated);
2373
+ return validated;
2374
+ }
2375
+ var MISSING_TABLE_PATTERNS = [
2376
+ "no such table",
2377
+ // SQLite
2378
+ "does not exist",
2379
+ // PostgreSQL ("relation ... does not exist")
2380
+ "SQLITE_ERROR"
2381
+ // D1 / Durable Objects error code
2382
+ ];
2383
+ function isMissingTableError(error) {
2384
+ const message = error instanceof Error ? error.message : String(error);
2385
+ return MISSING_TABLE_PATTERNS.some((pattern) => message.includes(pattern));
2386
+ }
2387
+ async function loadActiveSchemaWithBootstrap(backend, graphId) {
2388
+ try {
2389
+ const row = await backend.getActiveSchema(graphId);
2390
+ await backend.ensureFulltextTable?.();
2391
+ return row;
2392
+ } catch (error) {
2393
+ if (backend.bootstrapTables && isMissingTableError(error)) {
2394
+ await backend.bootstrapTables();
2395
+ return await backend.getActiveSchema(graphId);
2396
+ }
2397
+ throw error;
2398
+ }
2399
+ }
2400
+ async function loadAndMergeGraphExtensionDocument(backend, graph) {
2401
+ const activeRow = await loadActiveSchemaWithBootstrap(backend, graph.id);
2402
+ if (activeRow === void 0) {
2403
+ return { graph, activeRow: void 0, storedSchema: void 0 };
2404
+ }
2405
+ const storedSchema = parseSerializedSchema(activeRow.schema_doc);
2406
+ const merged = storedSchema.extension === void 0 ? graph : mergeGraphExtension(graph, storedSchema.extension);
2407
+ return {
2408
+ graph: applyDeprecatedKinds(merged, storedSchema.deprecatedKinds),
2409
+ activeRow,
2410
+ storedSchema
2411
+ };
2412
+ }
2413
+ function applyDeprecatedKinds(graph, names) {
2414
+ const current = graph.deprecatedKinds;
2415
+ if (names === current) return graph;
2416
+ const nextSet = names === void 0 ? /* @__PURE__ */ new Set() : names instanceof Set ? names : new Set(names);
2417
+ if (nextSet.size === 0 && current.size === 0) return graph;
2418
+ if (nextSet.size === current.size && [...nextSet].every((name) => current.has(name))) {
2419
+ return graph;
2420
+ }
2421
+ return Object.freeze({
2422
+ ...graph,
2423
+ deprecatedKinds: Object.freeze(new Set(nextSet))
2424
+ });
2425
+ }
2426
+ async function ensureSchema(backend, graph, options) {
2427
+ const autoMigrate = options?.autoMigrate ?? true;
2428
+ const throwOnBreaking = options?.throwOnBreaking ?? true;
2429
+ const preloaded = options?.preloaded;
2430
+ const activeSchema = preloaded === void 0 ? await loadActiveSchemaWithBootstrap(backend, graph.id) : preloaded.activeRow;
2431
+ if (activeSchema === void 0) {
2432
+ const result = await initializeSchema(backend, graph);
2433
+ return {
2434
+ status: "initialized",
2435
+ version: result.version,
2436
+ committedRow: result
2437
+ };
2438
+ }
2439
+ const storedHash = activeSchema.schema_hash;
2440
+ const currentHash = await getSchemaHash(graph, activeSchema.version + 1);
2441
+ if (storedHash === currentHash) {
2442
+ return { status: "unchanged", version: activeSchema.version };
2443
+ }
2444
+ const storedSchema = preloaded?.storedSchema ?? parseSerializedSchema(activeSchema.schema_doc);
2445
+ const currentSchema = serializeSchema(graph, activeSchema.version + 1);
2446
+ const diff = computeSchemaDiff(storedSchema, currentSchema);
2447
+ if (!diff.hasChanges) {
2448
+ return { status: "unchanged", version: activeSchema.version };
2449
+ }
2450
+ if (isBackwardsCompatible(diff)) {
2451
+ if (autoMigrate) {
2452
+ const hookContext = {
2453
+ graphId: graph.id,
2454
+ fromVersion: activeSchema.version,
2455
+ toVersion: activeSchema.version + 1,
2456
+ diff
2457
+ };
2458
+ await options?.onBeforeMigrate?.(hookContext);
2459
+ const committedRow = await commitNewSchemaVersion(
2460
+ backend,
2461
+ graph,
2462
+ activeSchema.version
2463
+ );
2464
+ await options?.onAfterMigrate?.(hookContext);
2465
+ return {
2466
+ status: "migrated",
2467
+ fromVersion: activeSchema.version,
2468
+ toVersion: committedRow.version,
2469
+ diff,
2470
+ committedRow
2471
+ };
2472
+ }
2473
+ return {
2474
+ status: "pending",
2475
+ version: activeSchema.version,
2476
+ diff
2477
+ };
2478
+ }
2479
+ const actions = getMigrationActions(diff);
2480
+ if (throwOnBreaking) {
2481
+ throw new MigrationError(
2482
+ `Schema migration required: ${diff.summary}. ${actions.length} migration action(s) needed. Use getSchemaChanges() to review, then migrateSchema() to apply.`,
2483
+ {
2484
+ graphId: graph.id,
2485
+ fromVersion: activeSchema.version,
2486
+ toVersion: activeSchema.version + 1
2487
+ }
2488
+ );
2489
+ }
2490
+ return { status: "breaking", diff, actions };
2491
+ }
2492
+ async function initializeSchema(backend, graph) {
2493
+ const schema = serializeSchema(graph, 1);
2494
+ const hash = await computeSchemaHash(schema);
2495
+ return backend.commitSchemaVersion({
2496
+ graphId: graph.id,
2497
+ expected: { kind: "initial" },
2498
+ version: 1,
2499
+ schemaHash: hash,
2500
+ schemaDoc: schema
2501
+ });
2502
+ }
2503
+ async function migrateSchema(backend, graph, currentVersion) {
2504
+ const committed = await commitNewSchemaVersion(
2505
+ backend,
2506
+ graph,
2507
+ currentVersion
2508
+ );
2509
+ return committed.version;
2510
+ }
2511
+ async function commitNewSchemaVersion(backend, graph, currentVersion) {
2512
+ const newVersion = currentVersion + 1;
2513
+ const schema = serializeSchema(graph, newVersion);
2514
+ const hash = await computeSchemaHash(schema);
2515
+ return backend.commitSchemaVersion({
2516
+ graphId: graph.id,
2517
+ expected: { kind: "active", version: currentVersion },
2518
+ version: newVersion,
2519
+ schemaHash: hash,
2520
+ schemaDoc: schema
2521
+ });
2522
+ }
2523
+ async function rollbackSchema(backend, graphId, targetVersion) {
2524
+ const activeRow = await backend.getActiveSchema(graphId);
2525
+ if (activeRow === void 0) {
2526
+ throw new MigrationError(
2527
+ `Cannot rollback graph "${graphId}": no active schema version exists.`,
2528
+ { graphId, fromVersion: 0, toVersion: targetVersion }
2529
+ );
2530
+ }
2531
+ await backend.setActiveVersion({
2532
+ graphId,
2533
+ expected: { kind: "active", version: activeRow.version },
2534
+ version: targetVersion
2535
+ });
2536
+ }
2537
+ async function getActiveSchema(backend, graphId) {
2538
+ const row = await backend.getActiveSchema(graphId);
2539
+ if (row === void 0) return void 0;
2540
+ return parseSerializedSchema(row.schema_doc);
2541
+ }
2542
+ async function isSchemaInitialized(backend, graphId) {
2543
+ const row = await backend.getActiveSchema(graphId);
2544
+ return row !== void 0;
2545
+ }
2546
+ async function getSchemaChanges(backend, graph) {
2547
+ const activeSchema = await backend.getActiveSchema(graph.id);
2548
+ if (activeSchema === void 0) return void 0;
2549
+ const storedSchema = parseSerializedSchema(activeSchema.schema_doc);
2550
+ const currentSchema = serializeSchema(graph, activeSchema.version + 1);
2551
+ return computeSchemaDiff(storedSchema, currentSchema);
2552
+ }
2553
+
2554
+ // src/errors/validation.ts
2555
+ function zodIssuesToValidationIssues(error) {
2556
+ return error.issues.map((issue) => ({
2557
+ path: issue.path.join("."),
2558
+ message: issue.message,
2559
+ code: issue.code
2560
+ }));
2561
+ }
2562
+ function buildLocationString(context) {
2563
+ if (context.id) {
2564
+ return `${context.kind}/${context.id}`;
2565
+ }
2566
+ return `new ${context.kind}`;
2567
+ }
2568
+ function validateProps(schema, props, context) {
2569
+ const result = schema.safeParse(props);
2570
+ if (result.success) {
2571
+ return result.data;
2572
+ }
2573
+ const issues = zodIssuesToValidationIssues(result.error);
2574
+ const location = buildLocationString(context);
2575
+ throw new ValidationError(
2576
+ `Invalid ${context.entityType} props for ${location}: ${result.error.message}`,
2577
+ {
2578
+ entityType: context.entityType,
2579
+ kind: context.kind,
2580
+ operation: context.operation,
2581
+ ...context.id !== void 0 && { id: context.id },
2582
+ issues
2583
+ },
2584
+ { cause: result.error }
2585
+ );
2586
+ }
2587
+ function validateNodeProps(schema, props, context) {
2588
+ return validateProps(schema, props, {
2589
+ entityType: "node",
2590
+ ...context
2591
+ });
2592
+ }
2593
+ function validateEdgeProps(schema, props, context) {
2594
+ return validateProps(schema, props, {
2595
+ entityType: "edge",
2596
+ ...context
2597
+ });
2598
+ }
2599
+ function wrapZodError(error, context) {
2600
+ const issues = zodIssuesToValidationIssues(error);
2601
+ const location = buildLocationString(context);
2602
+ return new ValidationError(
2603
+ `Validation failed for ${context.entityType} ${location}: ${error.message}`,
2604
+ {
2605
+ entityType: context.entityType,
2606
+ kind: context.kind,
2607
+ operation: context.operation,
2608
+ ...context.id !== void 0 && { id: context.id },
2609
+ issues
2610
+ },
2611
+ { cause: error }
2612
+ );
2613
+ }
2614
+ function createValidationError(message, issues, context) {
2615
+ return new ValidationError(message, {
2616
+ ...context?.entityType !== void 0 && {
2617
+ entityType: context.entityType
2618
+ },
2619
+ ...context?.kind !== void 0 && { kind: context.kind },
2620
+ ...context?.operation !== void 0 && { operation: context.operation },
2621
+ ...context?.id !== void 0 && { id: context.id },
2622
+ issues
2623
+ });
2624
+ }
2625
+
2626
+ export { KindRegistry, META_EDGE_BRAND, applyDeprecatedKinds, broader, buildGraphExtensionOntologyKeySet, canonicalEqual, commitNewSchemaVersion, compileTimeOntologyKey, computeClosuresFromOntology, computeSchemaDiff, computeSchemaHash, core, createEmptyClosures, createValidationError, defineEdge, defineNode, deserializeWherePredicate, differentFrom, disjointWith, ensureSchema, equivalentTo, extensionKindNames, getActiveSchema, getMigrationActions, getSchemaChanges, getTypeName, hasPart, implies, initializeSchema, inverseOf, isBackwardsCompatible, isMetaEdge, isSchemaInitialized, loadActiveSchemaWithBootstrap, loadAndMergeGraphExtensionDocument, mergeGraphExtension, migrateSchema, narrower, parseSerializedSchema, partOf, relatedTo, rollbackSchema, sameAs, serializeSchema, serializeSchemaProperties, sortedReplacer, subClassOf, validateEdgeProps, validateNodeProps, validateProps, wrapZodError };
2627
+ //# sourceMappingURL=chunk-AAA2CR3P.js.map
2628
+ //# sourceMappingURL=chunk-AAA2CR3P.js.map