callman-core 1.29.0 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/dist/ai/prompts/diagram.d.ts.map +1 -1
  2. package/dist/ai/prompts/diagram.js +24 -7
  3. package/dist/ai/prompts/diagram.js.map +1 -1
  4. package/dist/ai/types.d.ts +1 -1
  5. package/dist/ai/types.d.ts.map +1 -1
  6. package/dist/diagram/componentCatalog.d.ts +3 -0
  7. package/dist/diagram/componentCatalog.d.ts.map +1 -1
  8. package/dist/diagram/componentCatalog.js +5 -1
  9. package/dist/diagram/componentCatalog.js.map +1 -1
  10. package/dist/diagram/database/derive.d.ts +14 -0
  11. package/dist/diagram/database/derive.d.ts.map +1 -0
  12. package/dist/diagram/database/derive.js +114 -0
  13. package/dist/diagram/database/derive.js.map +1 -0
  14. package/dist/diagram/database/diff.d.ts +48 -0
  15. package/dist/diagram/database/diff.d.ts.map +1 -0
  16. package/dist/diagram/database/diff.js +109 -0
  17. package/dist/diagram/database/diff.js.map +1 -0
  18. package/dist/diagram/database/edit.d.ts +113 -0
  19. package/dist/diagram/database/edit.d.ts.map +1 -0
  20. package/dist/diagram/database/edit.js +359 -0
  21. package/dist/diagram/database/edit.js.map +1 -0
  22. package/dist/diagram/database/fromSchema.d.ts +12 -0
  23. package/dist/diagram/database/fromSchema.d.ts.map +1 -0
  24. package/dist/diagram/database/fromSchema.js +182 -0
  25. package/dist/diagram/database/fromSchema.js.map +1 -0
  26. package/dist/diagram/database/index.d.ts +9 -0
  27. package/dist/diagram/database/index.d.ts.map +1 -0
  28. package/dist/diagram/database/index.js +14 -0
  29. package/dist/diagram/database/index.js.map +1 -0
  30. package/dist/diagram/database/model.d.ts +93 -0
  31. package/dist/diagram/database/model.d.ts.map +1 -0
  32. package/dist/diagram/database/model.js +294 -0
  33. package/dist/diagram/database/model.js.map +1 -0
  34. package/dist/diagram/database/patch.d.ts +14 -0
  35. package/dist/diagram/database/patch.d.ts.map +1 -0
  36. package/dist/diagram/database/patch.js +186 -0
  37. package/dist/diagram/database/patch.js.map +1 -0
  38. package/dist/diagram/database/place.d.ts +4 -0
  39. package/dist/diagram/database/place.d.ts.map +1 -0
  40. package/dist/diagram/database/place.js +22 -0
  41. package/dist/diagram/database/place.js.map +1 -0
  42. package/dist/diagram/database/types.d.ts +50 -0
  43. package/dist/diagram/database/types.d.ts.map +1 -0
  44. package/dist/diagram/database/types.js +106 -0
  45. package/dist/diagram/database/types.js.map +1 -0
  46. package/dist/diagram/index.d.ts +1 -0
  47. package/dist/diagram/index.d.ts.map +1 -1
  48. package/dist/diagram/index.js +1 -0
  49. package/dist/diagram/index.js.map +1 -1
  50. package/dist/diagram/layout.d.ts +1 -0
  51. package/dist/diagram/layout.d.ts.map +1 -1
  52. package/dist/diagram/layout.js +2 -1
  53. package/dist/diagram/layout.js.map +1 -1
  54. package/dist/diagram/ops.d.ts +1 -1
  55. package/dist/diagram/ops.d.ts.map +1 -1
  56. package/dist/diagram/ops.js +42 -0
  57. package/dist/diagram/ops.js.map +1 -1
  58. package/dist/diagram/opsReference.d.ts +1 -1
  59. package/dist/diagram/opsReference.d.ts.map +1 -1
  60. package/dist/diagram/opsReference.js +9 -0
  61. package/dist/diagram/opsReference.js.map +1 -1
  62. package/dist/diagram/patchInput.d.ts +65 -1
  63. package/dist/diagram/patchInput.d.ts.map +1 -1
  64. package/dist/diagram/patchInput.js +414 -11
  65. package/dist/diagram/patchInput.js.map +1 -1
  66. package/dist/diagram/schema.d.ts +2 -2
  67. package/dist/diagram/schema.d.ts.map +1 -1
  68. package/dist/diagram/schema.js +3 -3
  69. package/dist/diagram/schema.js.map +1 -1
  70. package/dist/diagram/views.d.ts +13 -0
  71. package/dist/diagram/views.d.ts.map +1 -1
  72. package/dist/diagram/views.js +49 -0
  73. package/dist/diagram/views.js.map +1 -1
  74. package/dist/host/db/introspection/index.d.ts +9 -0
  75. package/dist/host/db/introspection/index.d.ts.map +1 -0
  76. package/dist/host/db/introspection/index.js +35 -0
  77. package/dist/host/db/introspection/index.js.map +1 -0
  78. package/dist/host/db/introspection/mongo.d.ts +7 -0
  79. package/dist/host/db/introspection/mongo.d.ts.map +1 -0
  80. package/dist/host/db/introspection/mongo.js +183 -0
  81. package/dist/host/db/introspection/mongo.js.map +1 -0
  82. package/dist/host/db/introspection/mssql.d.ts +6 -0
  83. package/dist/host/db/introspection/mssql.d.ts.map +1 -0
  84. package/dist/host/db/introspection/mssql.js +211 -0
  85. package/dist/host/db/introspection/mssql.js.map +1 -0
  86. package/dist/host/db/introspection/mysql.d.ts +5 -0
  87. package/dist/host/db/introspection/mysql.d.ts.map +1 -0
  88. package/dist/host/db/introspection/mysql.js +163 -0
  89. package/dist/host/db/introspection/mysql.js.map +1 -0
  90. package/dist/host/db/introspection/oracle.d.ts +12 -0
  91. package/dist/host/db/introspection/oracle.d.ts.map +1 -0
  92. package/dist/host/db/introspection/oracle.js +225 -0
  93. package/dist/host/db/introspection/oracle.js.map +1 -0
  94. package/dist/host/db/introspection/postgres.d.ts +5 -0
  95. package/dist/host/db/introspection/postgres.d.ts.map +1 -0
  96. package/dist/host/db/introspection/postgres.js +172 -0
  97. package/dist/host/db/introspection/postgres.js.map +1 -0
  98. package/dist/host/db/introspection/shared.d.ts +29 -0
  99. package/dist/host/db/introspection/shared.d.ts.map +1 -0
  100. package/dist/host/db/introspection/shared.js +119 -0
  101. package/dist/host/db/introspection/shared.js.map +1 -0
  102. package/dist/host/db/introspection/types.d.ts +58 -0
  103. package/dist/host/db/introspection/types.d.ts.map +1 -0
  104. package/dist/host/db/introspection/types.js +6 -0
  105. package/dist/host/db/introspection/types.js.map +1 -0
  106. package/dist/host/db/mongoAdapter.d.ts +1 -0
  107. package/dist/host/db/mongoAdapter.d.ts.map +1 -1
  108. package/dist/host/db/mongoAdapter.js +13 -0
  109. package/dist/host/db/mongoAdapter.js.map +1 -1
  110. package/dist/host/db/mssqlAdapter.d.ts +1 -0
  111. package/dist/host/db/mssqlAdapter.d.ts.map +1 -1
  112. package/dist/host/db/mssqlAdapter.js +3 -1
  113. package/dist/host/db/mssqlAdapter.js.map +1 -1
  114. package/dist/host/db/mysqlAdapter.d.ts +1 -0
  115. package/dist/host/db/mysqlAdapter.d.ts.map +1 -1
  116. package/dist/host/db/mysqlAdapter.js +11 -0
  117. package/dist/host/db/mysqlAdapter.js.map +1 -1
  118. package/dist/host/db/oracleAdapter.d.ts +1 -0
  119. package/dist/host/db/oracleAdapter.d.ts.map +1 -1
  120. package/dist/host/db/oracleAdapter.js +22 -0
  121. package/dist/host/db/oracleAdapter.js.map +1 -1
  122. package/dist/host/db/postgresAdapter.d.ts +1 -0
  123. package/dist/host/db/postgresAdapter.d.ts.map +1 -1
  124. package/dist/host/db/postgresAdapter.js +13 -0
  125. package/dist/host/db/postgresAdapter.js.map +1 -1
  126. package/dist/host/db/queryExecutor.d.ts +2 -1
  127. package/dist/host/db/queryExecutor.d.ts.map +1 -1
  128. package/dist/host/db/queryExecutor.js +1 -1
  129. package/dist/host/db/queryExecutor.js.map +1 -1
  130. package/dist/host/index.d.ts +7 -0
  131. package/dist/host/index.d.ts.map +1 -1
  132. package/dist/host/index.js +9 -0
  133. package/dist/host/index.js.map +1 -1
  134. package/dist-cjs/ai/prompts/diagram.js +23 -6
  135. package/dist-cjs/ai/prompts/diagram.js.map +1 -1
  136. package/dist-cjs/diagram/componentCatalog.js +5 -1
  137. package/dist-cjs/diagram/componentCatalog.js.map +1 -1
  138. package/dist-cjs/diagram/database/derive.js +119 -0
  139. package/dist-cjs/diagram/database/derive.js.map +1 -0
  140. package/dist-cjs/diagram/database/diff.js +115 -0
  141. package/dist-cjs/diagram/database/diff.js.map +1 -0
  142. package/dist-cjs/diagram/database/edit.js +366 -0
  143. package/dist-cjs/diagram/database/edit.js.map +1 -0
  144. package/dist-cjs/diagram/database/fromSchema.js +188 -0
  145. package/dist-cjs/diagram/database/fromSchema.js.map +1 -0
  146. package/dist-cjs/diagram/database/index.js +32 -0
  147. package/dist-cjs/diagram/database/index.js.map +1 -0
  148. package/dist-cjs/diagram/database/model.js +311 -0
  149. package/dist-cjs/diagram/database/model.js.map +1 -0
  150. package/dist-cjs/diagram/database/patch.js +190 -0
  151. package/dist-cjs/diagram/database/patch.js.map +1 -0
  152. package/dist-cjs/diagram/database/place.js +26 -0
  153. package/dist-cjs/diagram/database/place.js.map +1 -0
  154. package/dist-cjs/diagram/database/types.js +122 -0
  155. package/dist-cjs/diagram/database/types.js.map +1 -0
  156. package/dist-cjs/diagram/index.js +1 -0
  157. package/dist-cjs/diagram/index.js.map +1 -1
  158. package/dist-cjs/diagram/layout.js +3 -2
  159. package/dist-cjs/diagram/layout.js.map +1 -1
  160. package/dist-cjs/diagram/ops.js +42 -0
  161. package/dist-cjs/diagram/ops.js.map +1 -1
  162. package/dist-cjs/diagram/opsReference.js +9 -0
  163. package/dist-cjs/diagram/opsReference.js.map +1 -1
  164. package/dist-cjs/diagram/patchInput.js +414 -11
  165. package/dist-cjs/diagram/patchInput.js.map +1 -1
  166. package/dist-cjs/diagram/schema.js +3 -3
  167. package/dist-cjs/diagram/schema.js.map +1 -1
  168. package/dist-cjs/diagram/views.js +51 -1
  169. package/dist-cjs/diagram/views.js.map +1 -1
  170. package/dist-cjs/host/db/introspection/index.js +59 -0
  171. package/dist-cjs/host/db/introspection/index.js.map +1 -0
  172. package/dist-cjs/host/db/introspection/mongo.js +189 -0
  173. package/dist-cjs/host/db/introspection/mongo.js.map +1 -0
  174. package/dist-cjs/host/db/introspection/mssql.js +216 -0
  175. package/dist-cjs/host/db/introspection/mssql.js.map +1 -0
  176. package/dist-cjs/host/db/introspection/mysql.js +167 -0
  177. package/dist-cjs/host/db/introspection/mysql.js.map +1 -0
  178. package/dist-cjs/host/db/introspection/oracle.js +230 -0
  179. package/dist-cjs/host/db/introspection/oracle.js.map +1 -0
  180. package/dist-cjs/host/db/introspection/postgres.js +176 -0
  181. package/dist-cjs/host/db/introspection/postgres.js.map +1 -0
  182. package/dist-cjs/host/db/introspection/shared.js +133 -0
  183. package/dist-cjs/host/db/introspection/shared.js.map +1 -0
  184. package/dist-cjs/host/db/introspection/types.js +7 -0
  185. package/dist-cjs/host/db/introspection/types.js.map +1 -0
  186. package/dist-cjs/host/db/mongoAdapter.js +15 -1
  187. package/dist-cjs/host/db/mongoAdapter.js.map +1 -1
  188. package/dist-cjs/host/db/mssqlAdapter.js +5 -2
  189. package/dist-cjs/host/db/mssqlAdapter.js.map +1 -1
  190. package/dist-cjs/host/db/mysqlAdapter.js +13 -1
  191. package/dist-cjs/host/db/mysqlAdapter.js.map +1 -1
  192. package/dist-cjs/host/db/oracleAdapter.js +24 -1
  193. package/dist-cjs/host/db/oracleAdapter.js.map +1 -1
  194. package/dist-cjs/host/db/postgresAdapter.js +15 -1
  195. package/dist-cjs/host/db/postgresAdapter.js.map +1 -1
  196. package/dist-cjs/host/db/queryExecutor.js +5 -4
  197. package/dist-cjs/host/db/queryExecutor.js.map +1 -1
  198. package/dist-cjs/host/index.js +24 -1
  199. package/dist-cjs/host/index.js.map +1 -1
  200. package/package.json +1 -1
@@ -0,0 +1,182 @@
1
+ // Introspection → model (import, refresh) and typed nodes → model (an AI
2
+ // CREATE or an MCP create_diagram that wrote db.* nodes with columns).
3
+ import { columnFromInput } from "./edit.js";
4
+ import { emptyDatabaseModel, findColumn, findEntity, newColumnId, newEntityId, newRelationshipId, } from "./model.js";
5
+ import { dbEdgeData, dbNodeData, isDatabaseType, kindForDatabaseType } from "./types.js";
6
+ export const dialectForConnectionType = (type) => {
7
+ switch (type) {
8
+ case "postgres":
9
+ case "postgresql":
10
+ return "postgres";
11
+ case "mysql":
12
+ return "mysql";
13
+ case "mssql":
14
+ return "mssql";
15
+ case "oracle":
16
+ return "oracle";
17
+ case "mongo":
18
+ case "mongodb":
19
+ return "mongo";
20
+ default:
21
+ return "generic";
22
+ }
23
+ };
24
+ const lower = (value) => (value ?? "").toLowerCase();
25
+ const sameTable = (entity, table) => lower(entity.name) === lower(table.name) && (lower(entity.schema) === lower(table.schema) || !entity.schema || !table.schema);
26
+ // Same column set (order-insensitive)?
27
+ const sameSet = (a, b) => a.length === b.length && [...a].sort().join("\u0000") === [...b].sort().join("\u0000");
28
+ const cardinalityForForeignKey = (table, fkColumns) => {
29
+ if (fkColumns.length > 0 && sameSet(fkColumns, table.primaryKey))
30
+ return "1:1";
31
+ if (table.indexes.some((index) => index.unique && sameSet(index.columns, fkColumns)))
32
+ return "1:1";
33
+ if (fkColumns.length === 1 && table.columns.find((column) => column.name === fkColumns[0])?.unique)
34
+ return "1:1";
35
+ return "N:1";
36
+ };
37
+ export const databaseModelFromSchema = (schema, options = {}) => {
38
+ const model = emptyDatabaseModel(dialectForConnectionType(schema.dialect));
39
+ const previous = options.previous;
40
+ if (options.connection) {
41
+ model.connection = {
42
+ ...options.connection,
43
+ ...(schema.database ? { database: schema.database } : {}),
44
+ ...(schema.schemas.length > 0 ? { schemas: schema.schemas } : {}),
45
+ capturedAt: schema.capturedAt,
46
+ };
47
+ }
48
+ for (const table of schema.tables) {
49
+ const kept = previous?.entities.find((entity) => sameTable(entity, table));
50
+ const id = kept && !model.entities.some((entity) => entity.id === kept.id) ? kept.id : newEntityId(model, table.name, table.schema);
51
+ const entity = { id, name: table.name, ...(table.schema ? { schema: table.schema } : {}), kind: table.kind, columns: [] };
52
+ const taken = new Set();
53
+ for (const column of table.columns) {
54
+ const keptColumn = kept?.columns.find((candidate) => lower(candidate.name) === lower(column.name));
55
+ const columnId = keptColumn && !taken.has(keptColumn.id) ? keptColumn.id : newColumnId({ columns: [...entity.columns, ...[...taken].map((t) => ({ id: t }))] }, column.name);
56
+ taken.add(columnId);
57
+ entity.columns.push({
58
+ id: columnId,
59
+ name: column.name,
60
+ dataType: column.dataType,
61
+ ...(column.nullable ? { nullable: true } : {}),
62
+ ...(column.primaryKey ? { primaryKey: true } : {}),
63
+ ...(column.unique ? { unique: true } : {}),
64
+ ...(column.defaultValue !== undefined ? { defaultValue: column.defaultValue } : {}),
65
+ ...(column.autoIncrement ? { autoIncrement: true } : {}),
66
+ ...(column.comment ? { comment: column.comment } : {}),
67
+ ...(column.metadata ? { metadata: column.metadata } : {}),
68
+ });
69
+ }
70
+ const indexes = table.indexes
71
+ .filter((index) => !index.primary)
72
+ .map((index) => ({ name: index.name, columns: index.columns.map((name) => findColumn(entity, name)?.id).filter((v) => Boolean(v)), ...(index.unique ? { unique: true } : {}) }))
73
+ .filter((index) => index.columns.length > 0);
74
+ if (indexes.length > 0)
75
+ entity.indexes = indexes;
76
+ if (table.comment)
77
+ entity.comment = table.comment;
78
+ if (table.rowCountEstimate !== undefined)
79
+ entity.metadata = { rowCountEstimate: table.rowCountEstimate };
80
+ model.entities.push(entity);
81
+ }
82
+ // Relationships from the foreign keys whose both ends were imported.
83
+ for (const table of schema.tables) {
84
+ const source = model.entities.find((entity) => sameTable(entity, table));
85
+ if (!source)
86
+ continue;
87
+ for (const fk of table.foreignKeys) {
88
+ const target = model.entities.find((entity) => lower(entity.name) === lower(fk.refTable) && (!fk.refSchema || !entity.schema || lower(entity.schema) === lower(fk.refSchema)));
89
+ if (!target)
90
+ continue;
91
+ const sourceColumns = fk.columns.map((name) => findColumn(source, name)?.id).filter((v) => Boolean(v));
92
+ const targetColumns = fk.refColumns.map((name) => findColumn(target, name)?.id).filter((v) => Boolean(v));
93
+ const keptRelationship = previous?.relationships.find((relationship) => relationship.kind === "foreignKey" && relationship.source.entityId === source.id && relationship.target.entityId === target.id && sameSet(relationship.source.columnIds, sourceColumns));
94
+ const id = keptRelationship && !model.relationships.some((relationship) => relationship.id === keptRelationship.id) ? keptRelationship.id : newRelationshipId(model, source.id, target.id, fk.name);
95
+ const relationship = {
96
+ id,
97
+ source: { entityId: source.id, columnIds: sourceColumns },
98
+ target: { entityId: target.id, columnIds: targetColumns },
99
+ cardinality: cardinalityForForeignKey(table, fk.columns),
100
+ kind: "foreignKey",
101
+ ...(fk.name ? { name: fk.name } : {}),
102
+ ...(keptRelationship?.label ? { label: keptRelationship.label } : {}),
103
+ ...(fk.onDelete ? { onDelete: fk.onDelete } : {}),
104
+ ...(fk.onUpdate ? { onUpdate: fk.onUpdate } : {}),
105
+ };
106
+ model.relationships.push(relationship);
107
+ }
108
+ }
109
+ // Manual relationships of the previous model survive a refresh when both
110
+ // ends still exist.
111
+ for (const manual of previous?.relationships.filter((relationship) => relationship.kind === "manual") ?? []) {
112
+ const source = findEntity(model, manual.source.entityId);
113
+ const target = findEntity(model, manual.target.entityId);
114
+ if (!source || !target || model.relationships.some((relationship) => relationship.id === manual.id))
115
+ continue;
116
+ model.relationships.push({
117
+ ...manual,
118
+ source: { entityId: source.id, columnIds: manual.source.columnIds.filter((id) => source.columns.some((column) => column.id === id)) },
119
+ target: { entityId: target.id, columnIds: manual.target.columnIds.filter((id) => target.columns.some((column) => column.id === id)) },
120
+ });
121
+ }
122
+ return model;
123
+ };
124
+ // Typed nodes (db.* with `data.db.columns` as column inputs, edges with
125
+ // `data.db` naming columns) → model. The authoring path for AI CREATE and
126
+ // MCP create_diagram: the caller then stores the model as the source.
127
+ export const databaseModelFromDocument = (doc, dialect) => {
128
+ const model = emptyDatabaseModel(dialect);
129
+ const entityByNode = new Map();
130
+ for (const node of doc.nodes) {
131
+ if (!isDatabaseType(node.type))
132
+ continue;
133
+ const data = dbNodeData(node.data);
134
+ const raw = (node.data?.db ?? {});
135
+ const name = (data?.name ?? node.label ?? node.id).trim() || node.id;
136
+ const schema = typeof raw.schema === "string" && raw.schema.trim() ? raw.schema.trim() : undefined;
137
+ const id = model.entities.some((entity) => entity.id === node.id) ? newEntityId(model, name, schema) : node.id;
138
+ const entity = { id, name, ...(schema ? { schema } : {}), kind: kindForDatabaseType(node.type), columns: [] };
139
+ const inputs = Array.isArray(raw.columns) ? raw.columns : Array.isArray(raw.columnInputs) ? raw.columnInputs : [];
140
+ const taken = new Set();
141
+ for (const input of inputs) {
142
+ if (!input || typeof input !== "object")
143
+ continue;
144
+ const columnInput = input;
145
+ if (typeof columnInput.name !== "string" || !columnInput.name.trim())
146
+ continue;
147
+ try {
148
+ entity.columns.push(columnFromInput(entity, { ...columnInput, dataType: columnInput.dataType ?? columnInput.type ?? "" }, taken));
149
+ }
150
+ catch {
151
+ // A duplicate column in the input: keep the first.
152
+ }
153
+ }
154
+ if (typeof raw.comment === "string" && raw.comment.trim())
155
+ entity.comment = raw.comment.trim();
156
+ model.entities.push(entity);
157
+ entityByNode.set(node.id, entity);
158
+ }
159
+ for (const edge of doc.edges) {
160
+ if (!edge.source || !edge.target)
161
+ continue;
162
+ const source = entityByNode.get(edge.source);
163
+ const target = entityByNode.get(edge.target);
164
+ if (!source || !target)
165
+ continue;
166
+ const data = dbEdgeData(edge.data);
167
+ const raw = (edge.data?.db ?? {});
168
+ const columnIds = (entity, refs) => (Array.isArray(refs) ? refs : []).map((ref) => (typeof ref === "string" ? findColumn(entity, ref)?.id : undefined)).filter((v) => Boolean(v));
169
+ const cardinality = data?.cardinality && ["1:1", "1:N", "N:1", "N:M"].includes(data.cardinality) ? data.cardinality : "N:1";
170
+ model.relationships.push({
171
+ id: model.relationships.some((relationship) => relationship.id === edge.id) ? newRelationshipId(model, source.id, target.id) : edge.id,
172
+ source: { entityId: source.id, columnIds: columnIds(source, raw.sourceColumns) },
173
+ target: { entityId: target.id, columnIds: columnIds(target, raw.targetColumns) },
174
+ cardinality,
175
+ kind: raw.kind === "foreignKey" ? "foreignKey" : "manual",
176
+ ...(typeof raw.name === "string" && raw.name ? { name: raw.name } : {}),
177
+ ...(edge.label ? { label: edge.label } : {}),
178
+ });
179
+ }
180
+ return model;
181
+ };
182
+ //# sourceMappingURL=fromSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fromSchema.js","sourceRoot":"","sources":["../../../src/diagram/database/fromSchema.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,uEAAuE;AAKvE,OAAO,EAAE,eAAe,EAA4B,MAAM,WAAW,CAAC;AACtE,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,iBAAiB,GAOlB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEzF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,IAA2C,EAAmB,EAAE;IACvG,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,UAAU,CAAC;QAChB,KAAK,YAAY;YACf,OAAO,UAAU,CAAC;QACpB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,QAAQ,CAAC;QAClB,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,OAAO,CAAC;QACjB;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC,CAAC;AASF,MAAM,KAAK,GAAG,CAAC,KAAyB,EAAU,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAEjF,MAAM,SAAS,GAAG,CAAC,MAA+C,EAAE,KAA6C,EAAW,EAAE,CAC5H,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAEhI,uCAAuC;AACvC,MAAM,OAAO,GAAG,CAAC,CAAW,EAAE,CAAW,EAAW,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAE9I,MAAM,wBAAwB,GAAG,CAAC,KAAoB,EAAE,SAAmB,EAAuB,EAAE;IAClG,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/E,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACnG,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM;QAAE,OAAO,KAAK,CAAC;IACjH,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAgB,EAAE,UAAkC,EAAE,EAAiB,EAAE;IAC/G,MAAM,KAAK,GAAG,kBAAkB,CAAC,wBAAwB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,KAAK,CAAC,UAAU,GAAG;YACjB,GAAG,OAAO,CAAC,UAAU;YACrB,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3E,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACpI,MAAM,MAAM,GAAmB,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAC1I,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,UAAU,GAAG,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACnG,MAAM,QAAQ,GAAG,UAAU,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAU,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACtL,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClB,EAAE,EAAE,QAAQ;gBACZ,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9C,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClD,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnF,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1D,CAAC,CAAC;QACL,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO;aAC1B,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;aACjC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;aAC5L,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QACjD,IAAI,KAAK,CAAC,OAAO;YAAE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAClD,IAAI,KAAK,CAAC,gBAAgB,KAAK,SAAS;YAAE,MAAM,CAAC,QAAQ,GAAG,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACzG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IACD,qEAAqE;IACrE,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,KAAK,MAAM,EAAE,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC/K,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YACpH,MAAM,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YACvH,MAAM,gBAAgB,GAAG,QAAQ,EAAE,aAAa,CAAC,IAAI,CACnD,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,KAAK,YAAY,IAAI,YAAY,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAC1M,CAAC;YACF,MAAM,EAAE,GAAG,gBAAgB,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;YACpM,MAAM,YAAY,GAAyB;gBACzC,EAAE;gBACF,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE;gBACzD,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE;gBACzD,WAAW,EAAE,wBAAwB,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC;gBACxD,IAAI,EAAE,YAAY;gBAClB,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrC,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrE,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjD,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClD,CAAC;YACF,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,yEAAyE;IACzE,oBAAoB;IACpB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5G,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;YAAE,SAAS;QAC9G,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC;YACvB,GAAG,MAAM;YACT,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE;YACrI,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE;SACtI,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,wEAAwE;AACxE,0EAA0E;AAC1E,sEAAsE;AACtE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,GAAoB,EAAE,OAAyB,EAAiB,EAAE;IAC1G,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,YAAY,GAAG,IAAI,GAAG,EAA0B,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACzC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAA4B,CAAC;QAC7D,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACnG,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/G,MAAM,MAAM,GAAmB,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAC9H,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,OAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,YAA0B,CAAC,CAAC,CAAC,EAAE,CAAC;QAChJ,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,SAAS;YAClD,MAAM,WAAW,GAAG,KAAgD,CAAC;YACrE,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC/E,IAAI,CAAC;gBACH,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,GAAG,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,IAAI,WAAW,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;YACpI,CAAC;YAAC,MAAM,CAAC;gBACP,mDAAmD;YACrD,CAAC;QACH,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE;YAAE,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/F,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,SAAS;QAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM;YAAE,SAAS;QACjC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAA4B,CAAC;QAC7D,MAAM,SAAS,GAAG,CAAC,MAAsB,EAAE,IAAa,EAAY,EAAE,CACpE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7J,MAAM,WAAW,GAAwB,IAAI,EAAE,WAAW,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;QACjJ,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC;YACvB,EAAE,EAAE,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;YACtI,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE;YAChF,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE;YAChF,WAAW;YACX,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ;YACzD,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7C,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export * from "./model.js";
2
+ export * from "./types.js";
3
+ export * from "./edit.js";
4
+ export * from "./fromSchema.js";
5
+ export * from "./derive.js";
6
+ export * from "./diff.js";
7
+ export * from "./place.js";
8
+ export { patchDatabaseSource, type DatabasePatchContext, type DatabasePatchResult } from "./patch.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/diagram/database/index.ts"],"names":[],"mappings":"AAKA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,14 @@
1
+ // Database Diagram (ERD) as a diagram SOURCE format: the JSON database model
2
+ // (entities, columns, keys, relationships) is the structure truth; the
3
+ // nodes/edges hold layout and visibility. Introspection (host/db) builds the
4
+ // model from a real database, the desktop edits it on an ERD canvas, the AI
5
+ // and MCP edit it through semantic ops — all on this one model.
6
+ export * from "./model.js";
7
+ export * from "./types.js";
8
+ export * from "./edit.js";
9
+ export * from "./fromSchema.js";
10
+ export * from "./derive.js";
11
+ export * from "./diff.js";
12
+ export * from "./place.js";
13
+ export { patchDatabaseSource } from "./patch.js";
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/diagram/database/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,uEAAuE;AACvE,6EAA6E;AAC7E,4EAA4E;AAC5E,gEAAgE;AAChE,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAuD,MAAM,YAAY,CAAC"}
@@ -0,0 +1,93 @@
1
+ export declare const DATABASE_MODEL_FORMAT = "callman-database";
2
+ export declare const DATABASE_GRAMMAR_VERSION = "1";
3
+ export type DatabaseDialect = "postgres" | "mysql" | "mssql" | "oracle" | "mongo" | "generic";
4
+ export declare const DATABASE_DIALECTS: readonly DatabaseDialect[];
5
+ export type DatabaseEntityKind = "table" | "view" | "collection";
6
+ export declare const DATABASE_ENTITY_KINDS: readonly DatabaseEntityKind[];
7
+ export type DatabaseCardinality = "1:1" | "1:N" | "N:1" | "N:M";
8
+ export declare const DATABASE_CARDINALITIES: readonly DatabaseCardinality[];
9
+ export type DatabaseRelationshipKind = "foreignKey" | "manual";
10
+ export interface DatabaseColumn {
11
+ id: string;
12
+ name: string;
13
+ dataType: string;
14
+ nullable?: boolean;
15
+ primaryKey?: boolean;
16
+ unique?: boolean;
17
+ defaultValue?: string;
18
+ autoIncrement?: boolean;
19
+ comment?: string;
20
+ metadata?: Record<string, unknown>;
21
+ }
22
+ export interface DatabaseIndex {
23
+ name: string;
24
+ columns: string[];
25
+ unique?: boolean;
26
+ primary?: boolean;
27
+ }
28
+ export interface DatabaseEntity {
29
+ id: string;
30
+ name: string;
31
+ schema?: string;
32
+ kind: DatabaseEntityKind;
33
+ columns: DatabaseColumn[];
34
+ indexes?: DatabaseIndex[];
35
+ comment?: string;
36
+ metadata?: Record<string, unknown>;
37
+ }
38
+ export interface DatabaseRelationshipEnd {
39
+ entityId: string;
40
+ columnIds: string[];
41
+ }
42
+ export interface DatabaseRelationship {
43
+ id: string;
44
+ source: DatabaseRelationshipEnd;
45
+ target: DatabaseRelationshipEnd;
46
+ cardinality: DatabaseCardinality;
47
+ kind: DatabaseRelationshipKind;
48
+ name?: string;
49
+ label?: string;
50
+ onDelete?: string;
51
+ onUpdate?: string;
52
+ }
53
+ export interface DatabaseConnectionRef {
54
+ connectionId: string;
55
+ name?: string;
56
+ provider?: string;
57
+ database?: string;
58
+ schemas?: string[];
59
+ capturedAt?: string;
60
+ selection?: string[];
61
+ }
62
+ export interface DatabaseModel {
63
+ format: typeof DATABASE_MODEL_FORMAT;
64
+ version: 1;
65
+ dialect?: DatabaseDialect;
66
+ connection?: DatabaseConnectionRef;
67
+ entities: DatabaseEntity[];
68
+ relationships: DatabaseRelationship[];
69
+ }
70
+ export declare const emptyDatabaseModel: (dialect?: DatabaseDialect) => DatabaseModel;
71
+ export declare const entityQualifiedName: (entity: Pick<DatabaseEntity, "name" | "schema">) => string;
72
+ export declare const findEntity: (model: DatabaseModel, ref: string) => DatabaseEntity | undefined;
73
+ export declare const findColumn: (entity: DatabaseEntity, ref: string) => DatabaseColumn | undefined;
74
+ export declare const findRelationship: (model: DatabaseModel, ref: string) => DatabaseRelationship | undefined;
75
+ export declare const parseColumnRef: (ref: string) => {
76
+ table: string;
77
+ column?: string;
78
+ };
79
+ export declare const newEntityId: (model: DatabaseModel, name: string, schema?: string) => string;
80
+ export declare const newColumnId: (entity: Pick<DatabaseEntity, "columns">, name: string) => string;
81
+ export declare const newRelationshipId: (model: DatabaseModel, sourceEntityId: string, targetEntityId: string, name?: string) => string;
82
+ export declare const compactDatabaseModel: (model: DatabaseModel) => DatabaseModel;
83
+ export declare const serializeDatabaseModel: (model: DatabaseModel) => string;
84
+ export interface ParsedDatabaseModel {
85
+ ok: boolean;
86
+ model: DatabaseModel;
87
+ errors: string[];
88
+ warnings: string[];
89
+ }
90
+ export declare const looksLikeDatabaseModel: (text: string) => boolean;
91
+ export declare const parseDatabaseModel: (text: string) => ParsedDatabaseModel;
92
+ export declare const cloneDatabaseModel: (model: DatabaseModel) => DatabaseModel;
93
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/diagram/database/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,294 @@
1
+ // The canonical Database Diagram model: what an ERD KNOWS about a database —
2
+ // entities (tables, views, collections), their columns, keys and indexes, and
3
+ // the relationships between them. It is the STRUCTURE truth of a database
4
+ // diagram and lives as JSON text in `document.source` (format "database");
5
+ // positions, sizes, colors, hidden/collapsed states live on the nodes and
6
+ // edges, never here — a schema refresh replaces this model and leaves the
7
+ // layout alone.
8
+ //
9
+ // Ids are stable slugs (entity "users", column "user_id", relationship
10
+ // "fk-orders-users"); a rename keeps the id, so relationships, node positions
11
+ // and MCP references survive it.
12
+ import { slugify } from "../ids.js";
13
+ export const DATABASE_MODEL_FORMAT = "callman-database";
14
+ export const DATABASE_GRAMMAR_VERSION = "1";
15
+ export const DATABASE_DIALECTS = ["postgres", "mysql", "mssql", "oracle", "mongo", "generic"];
16
+ export const DATABASE_ENTITY_KINDS = ["table", "view", "collection"];
17
+ export const DATABASE_CARDINALITIES = ["1:1", "1:N", "N:1", "N:M"];
18
+ export const emptyDatabaseModel = (dialect) => ({
19
+ format: DATABASE_MODEL_FORMAT,
20
+ version: 1,
21
+ ...(dialect ? { dialect } : {}),
22
+ entities: [],
23
+ relationships: [],
24
+ });
25
+ // --- names and lookups ------------------------------------------------------------
26
+ export const entityQualifiedName = (entity) => entity.schema ? `${entity.schema}.${entity.name}` : entity.name;
27
+ const lower = (value) => (value ?? "").toLowerCase();
28
+ // An entity by id, then by qualified name, then by bare name (case-insensitive).
29
+ export const findEntity = (model, ref) => {
30
+ const wanted = ref.trim();
31
+ if (!wanted)
32
+ return undefined;
33
+ const byId = model.entities.find((entity) => entity.id === wanted);
34
+ if (byId)
35
+ return byId;
36
+ const lowered = wanted.toLowerCase();
37
+ return (model.entities.find((entity) => lower(entityQualifiedName(entity)) === lowered) ??
38
+ model.entities.find((entity) => lower(entity.name) === lowered) ??
39
+ model.entities.find((entity) => entity.id.toLowerCase() === lowered));
40
+ };
41
+ export const findColumn = (entity, ref) => {
42
+ const wanted = ref.trim();
43
+ if (!wanted)
44
+ return undefined;
45
+ return entity.columns.find((column) => column.id === wanted) ?? entity.columns.find((column) => lower(column.name) === wanted.toLowerCase()) ?? entity.columns.find((column) => column.id.toLowerCase() === wanted.toLowerCase());
46
+ };
47
+ export const findRelationship = (model, ref) => {
48
+ const wanted = ref.trim();
49
+ return model.relationships.find((relationship) => relationship.id === wanted) ?? model.relationships.find((relationship) => relationship.name === wanted);
50
+ };
51
+ // "users.id" → { table: "users", column: "id" }; "public.users.id" → table
52
+ // "public.users". A bare "users" names the table only.
53
+ export const parseColumnRef = (ref) => {
54
+ const trimmed = ref.trim();
55
+ const dot = trimmed.lastIndexOf(".");
56
+ if (dot <= 0 || dot === trimmed.length - 1)
57
+ return { table: trimmed };
58
+ return { table: trimmed.slice(0, dot), column: trimmed.slice(dot + 1) };
59
+ };
60
+ // --- ids ------------------------------------------------------------------------
61
+ const uniqueId = (base, taken, fallback) => {
62
+ const root = base || fallback;
63
+ let candidate = root;
64
+ let suffix = 2;
65
+ while (taken.has(candidate)) {
66
+ candidate = `${root}-${suffix}`;
67
+ suffix += 1;
68
+ }
69
+ return candidate;
70
+ };
71
+ export const newEntityId = (model, name, schema) => {
72
+ const taken = new Set(model.entities.map((entity) => entity.id));
73
+ const bare = slugify(name);
74
+ if (bare && !taken.has(bare))
75
+ return bare;
76
+ const qualified = schema ? slugify(`${schema}-${name}`) : "";
77
+ if (qualified && !taken.has(qualified))
78
+ return qualified;
79
+ return uniqueId(bare || qualified, taken, "table");
80
+ };
81
+ export const newColumnId = (entity, name) => uniqueId(slugify(name), new Set(entity.columns.map((column) => column.id)), "column");
82
+ export const newRelationshipId = (model, sourceEntityId, targetEntityId, name) => {
83
+ const taken = new Set(model.relationships.map((relationship) => relationship.id));
84
+ const preferred = name ? slugify(name) : "";
85
+ if (preferred && !taken.has(preferred))
86
+ return preferred;
87
+ return uniqueId(slugify(`fk-${sourceEntityId}-${targetEntityId}`), taken, "rel");
88
+ };
89
+ // --- serialize / parse -------------------------------------------------------------
90
+ const compactColumn = (column) => ({
91
+ id: column.id,
92
+ name: column.name,
93
+ dataType: column.dataType,
94
+ ...(column.nullable ? { nullable: true } : {}),
95
+ ...(column.primaryKey ? { primaryKey: true } : {}),
96
+ ...(column.unique ? { unique: true } : {}),
97
+ ...(column.defaultValue !== undefined ? { defaultValue: column.defaultValue } : {}),
98
+ ...(column.autoIncrement ? { autoIncrement: true } : {}),
99
+ ...(column.comment ? { comment: column.comment } : {}),
100
+ ...(column.metadata && Object.keys(column.metadata).length > 0 ? { metadata: column.metadata } : {}),
101
+ });
102
+ const compactEntity = (entity) => ({
103
+ id: entity.id,
104
+ name: entity.name,
105
+ ...(entity.schema ? { schema: entity.schema } : {}),
106
+ kind: entity.kind,
107
+ columns: entity.columns.map(compactColumn),
108
+ ...(entity.indexes && entity.indexes.length > 0
109
+ ? { indexes: entity.indexes.map((index) => ({ name: index.name, columns: [...index.columns], ...(index.unique ? { unique: true } : {}), ...(index.primary ? { primary: true } : {}) })) }
110
+ : {}),
111
+ ...(entity.comment ? { comment: entity.comment } : {}),
112
+ ...(entity.metadata && Object.keys(entity.metadata).length > 0 ? { metadata: entity.metadata } : {}),
113
+ });
114
+ const compactRelationship = (relationship) => ({
115
+ id: relationship.id,
116
+ source: { entityId: relationship.source.entityId, columnIds: [...relationship.source.columnIds] },
117
+ target: { entityId: relationship.target.entityId, columnIds: [...relationship.target.columnIds] },
118
+ cardinality: relationship.cardinality,
119
+ kind: relationship.kind,
120
+ ...(relationship.name ? { name: relationship.name } : {}),
121
+ ...(relationship.label ? { label: relationship.label } : {}),
122
+ ...(relationship.onDelete ? { onDelete: relationship.onDelete } : {}),
123
+ ...(relationship.onUpdate ? { onUpdate: relationship.onUpdate } : {}),
124
+ });
125
+ // A model with a fixed key order and no empty optionals — the same model
126
+ // always serializes to the same bytes (hashes, diffs and undo rely on it).
127
+ export const compactDatabaseModel = (model) => ({
128
+ format: DATABASE_MODEL_FORMAT,
129
+ version: 1,
130
+ ...(model.dialect ? { dialect: model.dialect } : {}),
131
+ ...(model.connection
132
+ ? {
133
+ connection: {
134
+ connectionId: model.connection.connectionId,
135
+ ...(model.connection.name ? { name: model.connection.name } : {}),
136
+ ...(model.connection.provider ? { provider: model.connection.provider } : {}),
137
+ ...(model.connection.database ? { database: model.connection.database } : {}),
138
+ ...(model.connection.schemas && model.connection.schemas.length > 0 ? { schemas: [...model.connection.schemas] } : {}),
139
+ ...(model.connection.capturedAt ? { capturedAt: model.connection.capturedAt } : {}),
140
+ ...(model.connection.selection && model.connection.selection.length > 0 ? { selection: [...model.connection.selection] } : {}),
141
+ },
142
+ }
143
+ : {}),
144
+ entities: model.entities.map(compactEntity),
145
+ relationships: model.relationships.map(compactRelationship),
146
+ });
147
+ export const serializeDatabaseModel = (model) => `${JSON.stringify(compactDatabaseModel(model), null, 2)}\n`;
148
+ const isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
149
+ const isStr = (value) => typeof value === "string";
150
+ const optStr = (value) => (isStr(value) && value.length > 0 ? value : undefined);
151
+ const optBool = (value) => (typeof value === "boolean" ? value : undefined);
152
+ const strList = (value) => (Array.isArray(value) ? value.filter(isStr) : []);
153
+ // Cheap sniff for file import: JSON whose root names our format.
154
+ export const looksLikeDatabaseModel = (text) => {
155
+ const trimmed = text.trim();
156
+ if (!trimmed.startsWith("{"))
157
+ return false;
158
+ return trimmed.includes(`"${DATABASE_MODEL_FORMAT}"`) || (trimmed.includes('"entities"') && trimmed.includes('"relationships"'));
159
+ };
160
+ // Tolerant reader: structural problems are errors (the model is then empty),
161
+ // dangling references are dropped with a warning (the model is still usable).
162
+ export const parseDatabaseModel = (text) => {
163
+ const errors = [];
164
+ const warnings = [];
165
+ let raw;
166
+ try {
167
+ raw = JSON.parse(text);
168
+ }
169
+ catch (error) {
170
+ return { ok: false, model: emptyDatabaseModel(), errors: [`Not valid JSON: ${error instanceof Error ? error.message : String(error)}`], warnings };
171
+ }
172
+ if (!isObject(raw))
173
+ return { ok: false, model: emptyDatabaseModel(), errors: ["The database model must be a JSON object."], warnings };
174
+ if (raw.format !== undefined && raw.format !== DATABASE_MODEL_FORMAT)
175
+ errors.push(`format must be "${DATABASE_MODEL_FORMAT}".`);
176
+ if (!Array.isArray(raw.entities))
177
+ errors.push("entities must be an array.");
178
+ if (raw.relationships !== undefined && !Array.isArray(raw.relationships))
179
+ errors.push("relationships must be an array.");
180
+ if (errors.length > 0)
181
+ return { ok: false, model: emptyDatabaseModel(), errors, warnings };
182
+ const dialect = isStr(raw.dialect) && DATABASE_DIALECTS.includes(raw.dialect) ? raw.dialect : undefined;
183
+ const model = emptyDatabaseModel(dialect);
184
+ if (isObject(raw.connection) && isStr(raw.connection.connectionId)) {
185
+ model.connection = {
186
+ connectionId: raw.connection.connectionId,
187
+ ...(optStr(raw.connection.name) ? { name: String(raw.connection.name) } : {}),
188
+ ...(optStr(raw.connection.provider) ? { provider: String(raw.connection.provider) } : {}),
189
+ ...(optStr(raw.connection.database) ? { database: String(raw.connection.database) } : {}),
190
+ ...(strList(raw.connection.schemas).length > 0 ? { schemas: strList(raw.connection.schemas) } : {}),
191
+ ...(optStr(raw.connection.capturedAt) ? { capturedAt: String(raw.connection.capturedAt) } : {}),
192
+ ...(strList(raw.connection.selection).length > 0 ? { selection: strList(raw.connection.selection) } : {}),
193
+ };
194
+ }
195
+ const entityIds = new Set();
196
+ raw.entities.forEach((item, index) => {
197
+ if (!isObject(item) || !isStr(item.name)) {
198
+ errors.push(`entities[${index}] needs a name.`);
199
+ return;
200
+ }
201
+ const name = item.name;
202
+ const schema = optStr(item.schema);
203
+ const kind = isStr(item.kind) && DATABASE_ENTITY_KINDS.includes(item.kind) ? item.kind : "table";
204
+ const entity = { id: "", name, ...(schema ? { schema } : {}), kind, columns: [] };
205
+ entity.id = isStr(item.id) && item.id.trim() && !entityIds.has(item.id.trim()) ? item.id.trim() : newEntityId(model, name, schema);
206
+ if (isStr(item.id) && item.id.trim() && entityIds.has(item.id.trim()))
207
+ warnings.push(`Duplicate entity id "${item.id}" — renamed to "${entity.id}".`);
208
+ entityIds.add(entity.id);
209
+ const columnIds = new Set();
210
+ if (Array.isArray(item.columns)) {
211
+ item.columns.forEach((columnRaw, columnIndex) => {
212
+ if (!isObject(columnRaw) || !isStr(columnRaw.name)) {
213
+ warnings.push(`${entityQualifiedName(entity)}: columns[${columnIndex}] has no name — dropped.`);
214
+ return;
215
+ }
216
+ const requested = isStr(columnRaw.id) && columnRaw.id.trim() ? columnRaw.id.trim() : "";
217
+ const id = requested && !columnIds.has(requested) ? requested : newColumnId(entity, columnRaw.name);
218
+ columnIds.add(id);
219
+ entity.columns.push({
220
+ id,
221
+ name: columnRaw.name,
222
+ dataType: optStr(columnRaw.dataType) ?? optStr(columnRaw.type) ?? "",
223
+ ...(optBool(columnRaw.nullable) ? { nullable: true } : {}),
224
+ ...(optBool(columnRaw.primaryKey) ? { primaryKey: true } : {}),
225
+ ...(optBool(columnRaw.unique) ? { unique: true } : {}),
226
+ ...(columnRaw.defaultValue !== undefined && columnRaw.defaultValue !== null ? { defaultValue: String(columnRaw.defaultValue) } : {}),
227
+ ...(optBool(columnRaw.autoIncrement) ? { autoIncrement: true } : {}),
228
+ ...(optStr(columnRaw.comment) ? { comment: String(columnRaw.comment) } : {}),
229
+ ...(isObject(columnRaw.metadata) ? { metadata: columnRaw.metadata } : {}),
230
+ });
231
+ });
232
+ }
233
+ if (Array.isArray(item.indexes)) {
234
+ const indexes = [];
235
+ for (const indexRaw of item.indexes) {
236
+ if (!isObject(indexRaw) || !isStr(indexRaw.name))
237
+ continue;
238
+ const columns = strList(indexRaw.columns).map((ref) => findColumn(entity, ref)?.id).filter((id) => Boolean(id));
239
+ indexes.push({ name: indexRaw.name, columns, ...(optBool(indexRaw.unique) ? { unique: true } : {}), ...(optBool(indexRaw.primary) ? { primary: true } : {}) });
240
+ }
241
+ if (indexes.length > 0)
242
+ entity.indexes = indexes;
243
+ }
244
+ if (optStr(item.comment))
245
+ entity.comment = String(item.comment);
246
+ if (isObject(item.metadata))
247
+ entity.metadata = item.metadata;
248
+ model.entities.push(entity);
249
+ });
250
+ const relationshipIds = new Set();
251
+ const readEnd = (value, relationshipLabel) => {
252
+ if (!isObject(value) || !isStr(value.entityId)) {
253
+ warnings.push(`${relationshipLabel}: an end has no entityId — dropped.`);
254
+ return null;
255
+ }
256
+ const entity = findEntity(model, value.entityId);
257
+ if (!entity) {
258
+ warnings.push(`${relationshipLabel}: entity "${value.entityId}" does not exist — dropped.`);
259
+ return null;
260
+ }
261
+ const columnIds = strList(value.columnIds).map((ref) => findColumn(entity, ref)?.id).filter((id) => Boolean(id));
262
+ return { entityId: entity.id, columnIds };
263
+ };
264
+ for (const item of Array.isArray(raw.relationships) ? raw.relationships : []) {
265
+ if (!isObject(item))
266
+ continue;
267
+ const label = `relationship ${isStr(item.id) ? item.id : "(no id)"}`;
268
+ const source = readEnd(item.source, label);
269
+ const target = readEnd(item.target, label);
270
+ if (!source || !target)
271
+ continue;
272
+ const cardinality = isStr(item.cardinality) && DATABASE_CARDINALITIES.includes(item.cardinality) ? item.cardinality : "N:1";
273
+ const kind = item.kind === "manual" ? "manual" : "foreignKey";
274
+ const requested = isStr(item.id) && item.id.trim() ? item.id.trim() : "";
275
+ const id = requested && !relationshipIds.has(requested) ? requested : newRelationshipId(model, source.entityId, target.entityId, optStr(item.name));
276
+ relationshipIds.add(id);
277
+ model.relationships.push({
278
+ id,
279
+ source,
280
+ target,
281
+ cardinality,
282
+ kind,
283
+ ...(optStr(item.name) ? { name: String(item.name) } : {}),
284
+ ...(optStr(item.label) ? { label: String(item.label) } : {}),
285
+ ...(optStr(item.onDelete) ? { onDelete: String(item.onDelete) } : {}),
286
+ ...(optStr(item.onUpdate) ? { onUpdate: String(item.onUpdate) } : {}),
287
+ });
288
+ }
289
+ return { ok: errors.length === 0, model, errors, warnings };
290
+ };
291
+ // Deep copy through the compact form (models are small JSON; edits clone
292
+ // before they mutate so callers keep their previous model intact).
293
+ export const cloneDatabaseModel = (model) => JSON.parse(JSON.stringify(compactDatabaseModel(model)));
294
+ //# sourceMappingURL=model.js.map