@prisma-next/family-sql 0.5.0-dev.9 → 0.5.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 (76) hide show
  1. package/README.md +2 -3
  2. package/dist/{authoring-type-constructors-BAR65pSK.mjs → authoring-type-constructors-F4JpCJl7.mjs} +14 -15
  3. package/dist/authoring-type-constructors-F4JpCJl7.mjs.map +1 -0
  4. package/dist/control-adapter.d.mts +26 -2
  5. package/dist/control-adapter.d.mts.map +1 -1
  6. package/dist/control-adapter.mjs +1 -1
  7. package/dist/control.d.mts +125 -45
  8. package/dist/control.d.mts.map +1 -1
  9. package/dist/control.mjs +1174 -54
  10. package/dist/control.mjs.map +1 -1
  11. package/dist/migration.d.mts +22 -24
  12. package/dist/migration.d.mts.map +1 -1
  13. package/dist/migration.mjs +25 -24
  14. package/dist/migration.mjs.map +1 -1
  15. package/dist/pack.d.mts +35 -23
  16. package/dist/pack.d.mts.map +1 -1
  17. package/dist/pack.mjs +3 -5
  18. package/dist/pack.mjs.map +1 -1
  19. package/dist/runtime.d.mts +19 -2
  20. package/dist/runtime.d.mts.map +1 -1
  21. package/dist/runtime.mjs +26 -4
  22. package/dist/runtime.mjs.map +1 -1
  23. package/dist/schema-verify.d.mts +4 -15
  24. package/dist/schema-verify.d.mts.map +1 -1
  25. package/dist/schema-verify.mjs +2 -3
  26. package/dist/test-utils.d.mts +2 -2
  27. package/dist/test-utils.mjs +2 -3
  28. package/dist/timestamp-now-generator-BWp8S2sa.mjs +86 -0
  29. package/dist/timestamp-now-generator-BWp8S2sa.mjs.map +1 -0
  30. package/dist/types-mhjAPuMn.d.mts +470 -0
  31. package/dist/types-mhjAPuMn.d.mts.map +1 -0
  32. package/dist/verify-pRYxnpiG.mjs +81 -0
  33. package/dist/verify-pRYxnpiG.mjs.map +1 -0
  34. package/dist/{verify-sql-schema-Ovz7RXR5.mjs → verify-sql-schema-1tDh3x5x.mjs} +18 -72
  35. package/dist/verify-sql-schema-1tDh3x5x.mjs.map +1 -0
  36. package/dist/{verify-sql-schema-BBhkqEDo.d.mts → verify-sql-schema-CPHiuYHR.d.mts} +2 -3
  37. package/dist/verify-sql-schema-CPHiuYHR.d.mts.map +1 -0
  38. package/dist/verify.d.mts +16 -21
  39. package/dist/verify.d.mts.map +1 -1
  40. package/dist/verify.mjs +2 -3
  41. package/package.json +23 -21
  42. package/src/core/authoring-field-presets.ts +35 -23
  43. package/src/core/control-adapter.ts +32 -0
  44. package/src/core/control-descriptor.ts +2 -1
  45. package/src/core/control-instance.ts +117 -30
  46. package/src/core/migrations/contract-to-schema-ir.ts +4 -29
  47. package/src/core/migrations/field-event-planner.ts +194 -0
  48. package/src/core/migrations/plan-helpers.ts +4 -0
  49. package/src/core/migrations/types.ts +207 -59
  50. package/src/core/operation-preview.ts +62 -0
  51. package/src/core/psl-contract-infer/default-mapping.ts +56 -0
  52. package/src/core/psl-contract-infer/name-transforms.ts +178 -0
  53. package/src/core/psl-contract-infer/postgres-default-mapping.ts +16 -0
  54. package/src/core/psl-contract-infer/postgres-type-map.ts +165 -0
  55. package/src/core/psl-contract-infer/printer-config.ts +55 -0
  56. package/src/core/psl-contract-infer/raw-default-parser.ts +91 -0
  57. package/src/core/psl-contract-infer/relation-inference.ts +196 -0
  58. package/src/core/psl-contract-infer/sql-schema-ir-to-psl-ast.ts +832 -0
  59. package/src/core/schema-verify/verify-helpers.ts +47 -70
  60. package/src/core/schema-verify/verify-sql-schema.ts +1 -6
  61. package/src/core/sql-migration.ts +25 -23
  62. package/src/core/timestamp-now-generator.ts +74 -0
  63. package/src/core/timestamp-now-runtime-generator.ts +24 -0
  64. package/src/core/verify.ts +46 -108
  65. package/src/exports/control.ts +11 -4
  66. package/src/exports/runtime.ts +2 -0
  67. package/src/exports/schema-verify.ts +0 -1
  68. package/src/exports/test-utils.ts +0 -1
  69. package/src/exports/verify.ts +1 -1
  70. package/dist/authoring-type-constructors-BAR65pSK.mjs.map +0 -1
  71. package/dist/types-C6K4mxDM.d.mts +0 -301
  72. package/dist/types-C6K4mxDM.d.mts.map +0 -1
  73. package/dist/verify-4GshvY4p.mjs +0 -122
  74. package/dist/verify-4GshvY4p.mjs.map +0 -1
  75. package/dist/verify-sql-schema-BBhkqEDo.d.mts.map +0 -1
  76. package/dist/verify-sql-schema-Ovz7RXR5.mjs.map +0 -1
package/dist/control.mjs CHANGED
@@ -1,15 +1,1014 @@
1
- import { n as sqlFamilyAuthoringFieldPresets, t as sqlFamilyAuthoringTypes } from "./authoring-type-constructors-BAR65pSK.mjs";
2
- import { c as extractCodecControlHooks, o as collectInitDependencies, s as isDatabaseDependencyProvider, t as verifySqlSchema } from "./verify-sql-schema-Ovz7RXR5.mjs";
3
- import { r as readMarker, t as collectSupportedCodecTypeIds } from "./verify-4GshvY4p.mjs";
1
+ import { n as sqlFamilyAuthoringFieldPresets, t as sqlFamilyAuthoringTypes } from "./authoring-type-constructors-F4JpCJl7.mjs";
2
+ import { a as extractCodecControlHooks, t as verifySqlSchema } from "./verify-sql-schema-1tDh3x5x.mjs";
3
+ import { t as collectSupportedCodecTypeIds } from "./verify-pRYxnpiG.mjs";
4
+ import { n as temporalAuthoringPresets, r as timestampNowControlDescriptor } from "./timestamp-now-generator-BWp8S2sa.mjs";
4
5
  import { sqlEmission } from "@prisma-next/sql-contract-emitter";
5
6
  import { emptyCodecLookup } from "@prisma-next/framework-components/codec";
6
- import { SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH, assembleAuthoringContributions } from "@prisma-next/framework-components/control";
7
+ import { APP_SPACE_ID, SchemaTreeNode, VERIFY_CODE_HASH_MISMATCH, VERIFY_CODE_MARKER_MISSING, VERIFY_CODE_TARGET_MISMATCH, assembleAuthoringContributions } from "@prisma-next/framework-components/control";
8
+ import { assertDescriptorSelfConsistency } from "@prisma-next/migration-tools/spaces";
7
9
  import { validateContract } from "@prisma-next/sql-contract/validate";
8
10
  import { ensureSchemaStatement, ensureTableStatement, writeContractMarker } from "@prisma-next/sql-runtime";
9
11
  import { defaultIndexName } from "@prisma-next/sql-schema-ir/naming";
10
12
  import { ifDefined } from "@prisma-next/utils/defined";
11
13
  import { notOk, ok } from "@prisma-next/utils/result";
12
-
14
+ //#region src/core/operation-preview.ts
15
+ function isDdlStatement(sqlStatement) {
16
+ const trimmed = sqlStatement.trim().toLowerCase();
17
+ return trimmed.startsWith("create ") || trimmed.startsWith("alter ") || trimmed.startsWith("drop ");
18
+ }
19
+ function hasExecuteSteps(operation) {
20
+ const candidate = operation;
21
+ if (!("execute" in candidate) || !Array.isArray(candidate["execute"])) return false;
22
+ return candidate["execute"].every((step) => typeof step === "object" && step !== null && "sql" in step);
23
+ }
24
+ /**
25
+ * Extracts a best-effort SQL DDL preview for CLI plan output.
26
+ * Presentation-only: never used to decide migration correctness.
27
+ */
28
+ function extractSqlDdl(operations) {
29
+ const statements = [];
30
+ for (const operation of operations) {
31
+ if (!hasExecuteSteps(operation)) continue;
32
+ for (const step of operation.execute) if (typeof step.sql === "string" && isDdlStatement(step.sql)) statements.push(step.sql.trim());
33
+ }
34
+ return statements;
35
+ }
36
+ /**
37
+ * Wraps `extractSqlDdl` into the family-agnostic `OperationPreview` shape.
38
+ * Each statement carries `language: 'sql'`.
39
+ */
40
+ function sqlOperationsToPreview(operations) {
41
+ return { statements: extractSqlDdl(operations).map((text) => ({
42
+ text,
43
+ language: "sql"
44
+ })) };
45
+ }
46
+ //#endregion
47
+ //#region src/core/psl-contract-infer/default-mapping.ts
48
+ const DEFAULT_FUNCTION_ATTRIBUTES = {
49
+ "autoincrement()": "@default(autoincrement())",
50
+ "now()": "@default(now())"
51
+ };
52
+ function mapDefault(columnDefault, options) {
53
+ switch (columnDefault.kind) {
54
+ case "literal": return { attribute: `@default(${formatLiteralValue(columnDefault.value)})` };
55
+ case "function": {
56
+ const attribute = options?.functionAttributes?.[columnDefault.expression] ?? DEFAULT_FUNCTION_ATTRIBUTES[columnDefault.expression] ?? options?.fallbackFunctionAttribute?.(columnDefault.expression);
57
+ return attribute ? { attribute } : { comment: `// Raw default: ${columnDefault.expression.replace(/[\r\n]+/g, " ")}` };
58
+ }
59
+ }
60
+ }
61
+ function formatLiteralValue(value) {
62
+ if (value === null) return "null";
63
+ switch (typeof value) {
64
+ case "boolean":
65
+ case "number": return String(value);
66
+ case "string": return quoteString(value);
67
+ default: return quoteString(JSON.stringify(value));
68
+ }
69
+ }
70
+ function quoteString(str) {
71
+ return `"${escapeString(str)}"`;
72
+ }
73
+ function escapeString(str) {
74
+ return JSON.stringify(str).slice(1, -1);
75
+ }
76
+ //#endregion
77
+ //#region src/core/psl-contract-infer/name-transforms.ts
78
+ const PSL_RESERVED_WORDS = new Set([
79
+ "model",
80
+ "enum",
81
+ "types",
82
+ "type",
83
+ "generator",
84
+ "datasource"
85
+ ]);
86
+ const IDENTIFIER_PART_PATTERN = /[A-Za-z0-9]+/g;
87
+ function hasSeparators(input) {
88
+ return /[^A-Za-z0-9]/.test(input);
89
+ }
90
+ function extractIdentifierParts(input) {
91
+ return input.match(IDENTIFIER_PART_PATTERN) ?? [];
92
+ }
93
+ function createSyntheticIdentifier(input) {
94
+ let hash = 2166136261;
95
+ for (const char of input) {
96
+ hash ^= char.codePointAt(0) ?? 0;
97
+ hash = Math.imul(hash, 16777619);
98
+ }
99
+ return `x${(hash >>> 0).toString(16)}`;
100
+ }
101
+ function sanitizeIdentifierCharacters(input) {
102
+ const sanitized = input.replace(/[^\w]/g, "");
103
+ return sanitized.length > 0 ? sanitized : createSyntheticIdentifier(input);
104
+ }
105
+ function capitalize(word) {
106
+ return word.charAt(0).toUpperCase() + word.slice(1);
107
+ }
108
+ function snakeToPascalCase(input) {
109
+ const parts = extractIdentifierParts(input);
110
+ if (parts.length === 0) return capitalize(sanitizeIdentifierCharacters(input));
111
+ return parts.map(capitalize).join("");
112
+ }
113
+ function snakeToCamelCase(input) {
114
+ const parts = extractIdentifierParts(input);
115
+ if (parts.length === 0) return sanitizeIdentifierCharacters(input);
116
+ const [firstPart = input, ...rest] = parts;
117
+ return firstPart.charAt(0).toLowerCase() + firstPart.slice(1) + rest.map(capitalize).join("");
118
+ }
119
+ function needsEscaping(name) {
120
+ return PSL_RESERVED_WORDS.has(name.toLowerCase()) || /^\d/.test(name);
121
+ }
122
+ function escapeName(name) {
123
+ return `_${name}`;
124
+ }
125
+ function escapeIfNeeded(name) {
126
+ return needsEscaping(name) ? escapeName(name) : name;
127
+ }
128
+ function toModelName(tableName) {
129
+ let name;
130
+ if (hasSeparators(tableName)) name = snakeToPascalCase(tableName);
131
+ else name = tableName.charAt(0).toUpperCase() + tableName.slice(1);
132
+ if (needsEscaping(name)) return {
133
+ name: escapeName(name),
134
+ map: tableName
135
+ };
136
+ if (name !== tableName) return {
137
+ name,
138
+ map: tableName
139
+ };
140
+ return { name };
141
+ }
142
+ function toFieldName(columnName) {
143
+ let name;
144
+ if (hasSeparators(columnName)) name = snakeToCamelCase(columnName);
145
+ else name = columnName.charAt(0).toLowerCase() + columnName.slice(1);
146
+ if (needsEscaping(name)) return {
147
+ name: escapeName(name),
148
+ map: columnName
149
+ };
150
+ if (name !== columnName) return {
151
+ name,
152
+ map: columnName
153
+ };
154
+ return { name };
155
+ }
156
+ function toEnumName(pgTypeName) {
157
+ let name;
158
+ if (hasSeparators(pgTypeName)) name = snakeToPascalCase(pgTypeName);
159
+ else name = pgTypeName.charAt(0).toUpperCase() + pgTypeName.slice(1);
160
+ if (needsEscaping(name)) return {
161
+ name: escapeName(name),
162
+ map: pgTypeName
163
+ };
164
+ if (name !== pgTypeName) return {
165
+ name,
166
+ map: pgTypeName
167
+ };
168
+ return { name };
169
+ }
170
+ function pluralize(word) {
171
+ if (word.endsWith("s") || word.endsWith("x") || word.endsWith("z") || word.endsWith("ch") || word.endsWith("sh")) return `${word}es`;
172
+ if (word.endsWith("y") && !/[aeiou]y$/i.test(word)) return `${word.slice(0, -1)}ies`;
173
+ return `${word}s`;
174
+ }
175
+ function deriveRelationFieldName(fkColumns, referencedTableName) {
176
+ if (fkColumns.length === 1) {
177
+ const [col = referencedTableName] = fkColumns;
178
+ const stripped = col.replace(/_id$/i, "").replace(/Id$/, "");
179
+ if (stripped.length > 0 && stripped !== col) return escapeIfNeeded(snakeToCamelCase(stripped));
180
+ return escapeIfNeeded(snakeToCamelCase(referencedTableName));
181
+ }
182
+ return escapeIfNeeded(snakeToCamelCase(referencedTableName));
183
+ }
184
+ function deriveBackRelationFieldName(childModelName, isOneToOne) {
185
+ const base = childModelName.charAt(0).toLowerCase() + childModelName.slice(1);
186
+ return isOneToOne ? base : pluralize(base);
187
+ }
188
+ function toNamedTypeName(columnName) {
189
+ let name;
190
+ if (hasSeparators(columnName)) name = snakeToPascalCase(columnName);
191
+ else name = columnName.charAt(0).toUpperCase() + columnName.slice(1);
192
+ return escapeIfNeeded(name);
193
+ }
194
+ //#endregion
195
+ //#region src/core/psl-contract-infer/postgres-default-mapping.ts
196
+ const POSTGRES_FUNCTION_ATTRIBUTES = { "gen_random_uuid()": "@default(dbgenerated(\"gen_random_uuid()\"))" };
197
+ function formatDbGeneratedAttribute(expression) {
198
+ return `@default(dbgenerated(${JSON.stringify(expression)}))`;
199
+ }
200
+ function createPostgresDefaultMapping() {
201
+ return {
202
+ functionAttributes: POSTGRES_FUNCTION_ATTRIBUTES,
203
+ fallbackFunctionAttribute: formatDbGeneratedAttribute
204
+ };
205
+ }
206
+ //#endregion
207
+ //#region src/core/psl-contract-infer/postgres-type-map.ts
208
+ const POSTGRES_TO_PSL = {
209
+ text: "String",
210
+ bool: "Boolean",
211
+ boolean: "Boolean",
212
+ int4: "Int",
213
+ integer: "Int",
214
+ int8: "BigInt",
215
+ bigint: "BigInt",
216
+ float8: "Float",
217
+ "double precision": "Float",
218
+ numeric: "Decimal",
219
+ decimal: "Decimal",
220
+ timestamptz: "DateTime",
221
+ "timestamp with time zone": "DateTime",
222
+ jsonb: "Json",
223
+ bytea: "Bytes"
224
+ };
225
+ const PRESERVED_NATIVE_TYPES = {
226
+ "character varying": {
227
+ pslType: "String",
228
+ attributeName: "db.VarChar"
229
+ },
230
+ character: {
231
+ pslType: "String",
232
+ attributeName: "db.Char"
233
+ },
234
+ char: {
235
+ pslType: "String",
236
+ attributeName: "db.Char"
237
+ },
238
+ varchar: {
239
+ pslType: "String",
240
+ attributeName: "db.VarChar"
241
+ },
242
+ uuid: {
243
+ pslType: "String",
244
+ attributeName: "db.Uuid"
245
+ },
246
+ int2: {
247
+ pslType: "Int",
248
+ attributeName: "db.SmallInt"
249
+ },
250
+ smallint: {
251
+ pslType: "Int",
252
+ attributeName: "db.SmallInt"
253
+ },
254
+ float4: {
255
+ pslType: "Float",
256
+ attributeName: "db.Real"
257
+ },
258
+ real: {
259
+ pslType: "Float",
260
+ attributeName: "db.Real"
261
+ },
262
+ timestamp: {
263
+ pslType: "DateTime",
264
+ attributeName: "db.Timestamp"
265
+ },
266
+ "timestamp without time zone": {
267
+ pslType: "DateTime",
268
+ attributeName: "db.Timestamp"
269
+ },
270
+ date: {
271
+ pslType: "DateTime",
272
+ attributeName: "db.Date"
273
+ },
274
+ time: {
275
+ pslType: "DateTime",
276
+ attributeName: "db.Time"
277
+ },
278
+ "time without time zone": {
279
+ pslType: "DateTime",
280
+ attributeName: "db.Time"
281
+ },
282
+ timetz: {
283
+ pslType: "DateTime",
284
+ attributeName: "db.Timetz"
285
+ },
286
+ "time with time zone": {
287
+ pslType: "DateTime",
288
+ attributeName: "db.Timetz"
289
+ },
290
+ json: {
291
+ pslType: "Json",
292
+ attributeName: "db.Json"
293
+ }
294
+ };
295
+ const PARAMETERIZED_NATIVE_TYPES = {
296
+ "character varying": {
297
+ pslType: "String",
298
+ attributeName: "db.VarChar"
299
+ },
300
+ character: {
301
+ pslType: "String",
302
+ attributeName: "db.Char"
303
+ },
304
+ char: {
305
+ pslType: "String",
306
+ attributeName: "db.Char"
307
+ },
308
+ varchar: {
309
+ pslType: "String",
310
+ attributeName: "db.VarChar"
311
+ },
312
+ numeric: {
313
+ pslType: "Decimal",
314
+ attributeName: "db.Numeric"
315
+ },
316
+ timestamp: {
317
+ pslType: "DateTime",
318
+ attributeName: "db.Timestamp"
319
+ },
320
+ timestamptz: {
321
+ pslType: "DateTime",
322
+ attributeName: "db.Timestamptz"
323
+ },
324
+ time: {
325
+ pslType: "DateTime",
326
+ attributeName: "db.Time"
327
+ },
328
+ timetz: {
329
+ pslType: "DateTime",
330
+ attributeName: "db.Timetz"
331
+ }
332
+ };
333
+ const PARAMETERIZED_TYPE_PATTERN = /^(.+?)\((.+)\)$/;
334
+ const ENUM_CODEC_ID = "pg/enum@1";
335
+ function getOwnMappingValue(map, key) {
336
+ return Object.hasOwn(map, key) ? map[key] : void 0;
337
+ }
338
+ function getOwnRecordValue(map, key) {
339
+ return Object.hasOwn(map, key) ? map[key] : void 0;
340
+ }
341
+ function createNativeTypeAttribute(name, args) {
342
+ return args && args.length > 0 ? {
343
+ name,
344
+ args
345
+ } : { name };
346
+ }
347
+ function splitTypeParameterList(params) {
348
+ return params.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
349
+ }
350
+ function createPostgresTypeMap(enumTypeNames) {
351
+ return { resolve(nativeType) {
352
+ if (enumTypeNames?.has(nativeType)) return {
353
+ pslType: nativeType,
354
+ nativeType
355
+ };
356
+ const paramMatch = nativeType.match(PARAMETERIZED_TYPE_PATTERN);
357
+ if (paramMatch) {
358
+ const [, baseType = nativeType, params = ""] = paramMatch;
359
+ const template = getOwnRecordValue(PARAMETERIZED_NATIVE_TYPES, baseType);
360
+ if (template) return {
361
+ pslType: template.pslType,
362
+ nativeType,
363
+ typeParams: {
364
+ baseType,
365
+ params
366
+ },
367
+ nativeTypeAttribute: createNativeTypeAttribute(template.attributeName, splitTypeParameterList(params))
368
+ };
369
+ }
370
+ const preservedType = getOwnRecordValue(PRESERVED_NATIVE_TYPES, nativeType);
371
+ if (preservedType) return {
372
+ pslType: preservedType.pslType,
373
+ nativeType,
374
+ nativeTypeAttribute: createNativeTypeAttribute(preservedType.attributeName)
375
+ };
376
+ const pslType = getOwnMappingValue(POSTGRES_TO_PSL, nativeType);
377
+ if (pslType) return {
378
+ pslType,
379
+ nativeType
380
+ };
381
+ return {
382
+ unsupported: true,
383
+ nativeType
384
+ };
385
+ } };
386
+ }
387
+ function extractEnumInfo(annotations) {
388
+ const storageTypes = (annotations?.["pg"])?.["storageTypes"];
389
+ const typeNames = /* @__PURE__ */ new Set();
390
+ const definitions = /* @__PURE__ */ new Map();
391
+ if (storageTypes) {
392
+ for (const [key, typeInstance] of Object.entries(storageTypes)) if (typeInstance.codecId === ENUM_CODEC_ID) {
393
+ typeNames.add(key);
394
+ const values = typeInstance.typeParams?.["values"];
395
+ if (Array.isArray(values)) definitions.set(key, values);
396
+ }
397
+ }
398
+ return {
399
+ typeNames,
400
+ definitions
401
+ };
402
+ }
403
+ //#endregion
404
+ //#region src/core/psl-contract-infer/raw-default-parser.ts
405
+ const NEXTVAL_PATTERN = /^nextval\s*\(/i;
406
+ const NOW_FUNCTION_PATTERN = /^(now\s*\(\s*\)|CURRENT_TIMESTAMP)$/i;
407
+ const CLOCK_TIMESTAMP_PATTERN = /^clock_timestamp\s*\(\s*\)$/i;
408
+ const TIMESTAMP_CAST_SUFFIX = /::timestamp(?:tz|\s+(?:with|without)\s+time\s+zone)?$/i;
409
+ const TEXT_CAST_SUFFIX = /::text$/i;
410
+ const NOW_LITERAL_PATTERN = /^'now'$/i;
411
+ const UUID_PATTERN = /^gen_random_uuid\s*\(\s*\)$/i;
412
+ const UUID_OSSP_PATTERN = /^uuid_generate_v4\s*\(\s*\)$/i;
413
+ const NULL_PATTERN = /^NULL(?:::.+)?$/i;
414
+ const TRUE_PATTERN = /^true$/i;
415
+ const FALSE_PATTERN = /^false$/i;
416
+ const NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
417
+ const JSON_CAST_SUFFIX = /::jsonb?$/i;
418
+ const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:"[^"]+"|[\w\s]+)(?:\(\d+\))?)?$/;
419
+ function canonicalizeTimestampDefault(expr) {
420
+ if (NOW_FUNCTION_PATTERN.test(expr)) return "now()";
421
+ if (CLOCK_TIMESTAMP_PATTERN.test(expr)) return "clock_timestamp()";
422
+ if (!TIMESTAMP_CAST_SUFFIX.test(expr)) return void 0;
423
+ let inner = expr.replace(TIMESTAMP_CAST_SUFFIX, "").trim();
424
+ if (inner.startsWith("(") && inner.endsWith(")")) inner = inner.slice(1, -1).trim();
425
+ if (NOW_FUNCTION_PATTERN.test(inner)) return "now()";
426
+ if (CLOCK_TIMESTAMP_PATTERN.test(inner)) return "clock_timestamp()";
427
+ inner = inner.replace(TEXT_CAST_SUFFIX, "").trim();
428
+ if (NOW_LITERAL_PATTERN.test(inner)) return "now()";
429
+ }
430
+ function parseRawDefault(rawDefault, nativeType) {
431
+ const trimmed = rawDefault.trim();
432
+ const normalizedType = nativeType?.toLowerCase();
433
+ if (NEXTVAL_PATTERN.test(trimmed)) return {
434
+ kind: "function",
435
+ expression: "autoincrement()"
436
+ };
437
+ const canonicalTimestamp = canonicalizeTimestampDefault(trimmed);
438
+ if (canonicalTimestamp) return {
439
+ kind: "function",
440
+ expression: canonicalTimestamp
441
+ };
442
+ if (UUID_PATTERN.test(trimmed) || UUID_OSSP_PATTERN.test(trimmed)) return {
443
+ kind: "function",
444
+ expression: "gen_random_uuid()"
445
+ };
446
+ if (NULL_PATTERN.test(trimmed)) return {
447
+ kind: "literal",
448
+ value: null
449
+ };
450
+ if (TRUE_PATTERN.test(trimmed)) return {
451
+ kind: "literal",
452
+ value: true
453
+ };
454
+ if (FALSE_PATTERN.test(trimmed)) return {
455
+ kind: "literal",
456
+ value: false
457
+ };
458
+ if (NUMERIC_PATTERN.test(trimmed)) return {
459
+ kind: "literal",
460
+ value: Number(trimmed)
461
+ };
462
+ const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
463
+ if (stringMatch?.[1] !== void 0) {
464
+ const unescaped = stringMatch[1].replace(/''/g, "'");
465
+ if (normalizedType === "json" || normalizedType === "jsonb") {
466
+ if (JSON_CAST_SUFFIX.test(trimmed)) return {
467
+ kind: "function",
468
+ expression: trimmed
469
+ };
470
+ try {
471
+ return {
472
+ kind: "literal",
473
+ value: JSON.parse(unescaped)
474
+ };
475
+ } catch {}
476
+ }
477
+ return {
478
+ kind: "literal",
479
+ value: unescaped
480
+ };
481
+ }
482
+ return {
483
+ kind: "function",
484
+ expression: trimmed
485
+ };
486
+ }
487
+ //#endregion
488
+ //#region src/core/psl-contract-infer/relation-inference.ts
489
+ const DEFAULT_ON_DELETE = "noAction";
490
+ const DEFAULT_ON_UPDATE = "noAction";
491
+ const REFERENTIAL_ACTION_PSL = {
492
+ noAction: "NoAction",
493
+ restrict: "Restrict",
494
+ cascade: "Cascade",
495
+ setNull: "SetNull",
496
+ setDefault: "SetDefault"
497
+ };
498
+ function inferRelations(tables, modelNameMap) {
499
+ const relationsByTable = /* @__PURE__ */ new Map();
500
+ const fkCountByPair = /* @__PURE__ */ new Map();
501
+ for (const table of Object.values(tables)) for (const fk of table.foreignKeys) {
502
+ const pairKey = `${table.name}→${fk.referencedTable}`;
503
+ fkCountByPair.set(pairKey, (fkCountByPair.get(pairKey) ?? 0) + 1);
504
+ }
505
+ const usedFieldNames = /* @__PURE__ */ new Map();
506
+ for (const table of Object.values(tables)) {
507
+ const names = /* @__PURE__ */ new Set();
508
+ for (const col of Object.values(table.columns)) names.add(col.name);
509
+ usedFieldNames.set(table.name, names);
510
+ }
511
+ for (const table of Object.values(tables)) for (const fk of table.foreignKeys) {
512
+ const childTableName = table.name;
513
+ const parentTableName = fk.referencedTable;
514
+ const childUsed = usedFieldNames.get(childTableName);
515
+ const childModelName = modelNameMap.get(childTableName) ?? childTableName;
516
+ const parentModelName = modelNameMap.get(parentTableName) ?? parentTableName;
517
+ const pairKey = `${childTableName}→${parentTableName}`;
518
+ const isSelfRelation = childTableName === parentTableName;
519
+ const needsRelationName = fkCountByPair.get(pairKey) > 1 || isSelfRelation;
520
+ const isOneToOne = detectOneToOne(fk, table);
521
+ const childRelFieldName = resolveUniqueFieldName(deriveRelationFieldName(fk.columns, parentTableName), childUsed, parentModelName);
522
+ const relationName = needsRelationName ? deriveRelationName(fk, childRelFieldName, parentModelName, isSelfRelation) : void 0;
523
+ addRelationField(relationsByTable, childTableName, buildChildRelationField(childRelFieldName, parentModelName, fk, fk.columns.some((columnName) => table.columns[columnName]?.nullable ?? false), relationName));
524
+ childUsed.add(childRelFieldName);
525
+ const parentUsed = usedFieldNames.get(parentTableName) ?? /* @__PURE__ */ new Set();
526
+ usedFieldNames.set(parentTableName, parentUsed);
527
+ const backRelFieldName = resolveUniqueFieldName(deriveBackRelationFieldName(childModelName, isOneToOne), parentUsed, childModelName);
528
+ addRelationField(relationsByTable, parentTableName, {
529
+ fieldName: backRelFieldName,
530
+ typeName: childModelName,
531
+ optional: isOneToOne,
532
+ list: !isOneToOne,
533
+ relationName
534
+ });
535
+ parentUsed.add(backRelFieldName);
536
+ }
537
+ return { relationsByTable };
538
+ }
539
+ function detectOneToOne(fk, table) {
540
+ const fkCols = [...fk.columns].sort();
541
+ if (table.primaryKey) {
542
+ const pkCols = [...table.primaryKey.columns].sort();
543
+ if (pkCols.length === fkCols.length && pkCols.every((c, i) => c === fkCols[i])) return true;
544
+ }
545
+ for (const unique of table.uniques) {
546
+ const uniqueCols = [...unique.columns].sort();
547
+ if (uniqueCols.length === fkCols.length && uniqueCols.every((c, i) => c === fkCols[i])) return true;
548
+ }
549
+ return false;
550
+ }
551
+ function deriveRelationName(fk, childRelationFieldName, parentModelName, isSelfRelation) {
552
+ if (fk.name) return fk.name;
553
+ if (isSelfRelation) return `${childRelationFieldName.charAt(0).toUpperCase() + childRelationFieldName.slice(1)}${pluralize(parentModelName)}`;
554
+ return fk.columns.join("_");
555
+ }
556
+ function buildChildRelationField(fieldName, parentModelName, fk, optional, relationName) {
557
+ const onDelete = fk.onDelete && fk.onDelete !== DEFAULT_ON_DELETE ? fk.onDelete : void 0;
558
+ const onUpdate = fk.onUpdate && fk.onUpdate !== DEFAULT_ON_UPDATE ? fk.onUpdate : void 0;
559
+ return {
560
+ fieldName,
561
+ typeName: parentModelName,
562
+ referencedTableName: fk.referencedTable,
563
+ optional,
564
+ list: false,
565
+ relationName,
566
+ fkName: fk.name,
567
+ fields: fk.columns,
568
+ references: fk.referencedColumns,
569
+ onDelete: onDelete ? REFERENTIAL_ACTION_PSL[onDelete] : void 0,
570
+ onUpdate: onUpdate ? REFERENTIAL_ACTION_PSL[onUpdate] : void 0
571
+ };
572
+ }
573
+ function resolveUniqueFieldName(desired, usedNames, fallbackSuffix) {
574
+ if (!usedNames.has(desired)) return desired;
575
+ const withSuffix = `${desired}${fallbackSuffix}`;
576
+ if (!usedNames.has(withSuffix)) return withSuffix;
577
+ let counter = 2;
578
+ while (usedNames.has(`${desired}${counter}`)) counter++;
579
+ return `${desired}${counter}`;
580
+ }
581
+ function addRelationField(map, tableName, field) {
582
+ const existing = map.get(tableName);
583
+ if (existing) existing.push(field);
584
+ else map.set(tableName, [field]);
585
+ }
586
+ //#endregion
587
+ //#region src/core/psl-contract-infer/sql-schema-ir-to-psl-ast.ts
588
+ const SYNTHETIC_SPAN = {
589
+ start: {
590
+ offset: 0,
591
+ line: 1,
592
+ column: 1
593
+ },
594
+ end: {
595
+ offset: 0,
596
+ line: 1,
597
+ column: 1
598
+ }
599
+ };
600
+ const PSL_SCALAR_TYPE_NAMES = new Set([
601
+ "String",
602
+ "Boolean",
603
+ "Int",
604
+ "BigInt",
605
+ "Float",
606
+ "Decimal",
607
+ "DateTime",
608
+ "Json",
609
+ "Bytes"
610
+ ]);
611
+ /**
612
+ * Converts a SQL schema IR into a PSL AST suitable for `printPsl`.
613
+ *
614
+ * This function owns all SQL-specific concerns: native type mapping (Postgres),
615
+ * relation inference from foreign keys, enum extraction, and raw default parsing.
616
+ * The output is a fully-formed `PslDocumentAst` with synthetic spans.
617
+ */
618
+ function sqlSchemaIrToPslAst(schemaIR) {
619
+ const enumInfo = extractEnumInfo(schemaIR.annotations);
620
+ return buildPslDocumentAst(schemaIR, {
621
+ typeMap: createPostgresTypeMap(enumInfo.typeNames),
622
+ defaultMapping: createPostgresDefaultMapping(),
623
+ enumInfo,
624
+ parseRawDefault
625
+ });
626
+ }
627
+ function buildPslDocumentAst(schemaIR, options) {
628
+ const { typeMap, defaultMapping, enumInfo, parseRawDefault: rawDefaultParser } = options;
629
+ const { typeNames: enumTypeNames, definitions: enumDefinitions } = enumInfo ?? {
630
+ typeNames: /* @__PURE__ */ new Set(),
631
+ definitions: /* @__PURE__ */ new Map()
632
+ };
633
+ const modelNames = buildTopLevelNameMap(Object.keys(schemaIR.tables), toModelName, "model", "table");
634
+ const enumNames = buildTopLevelNameMap(enumTypeNames, toEnumName, "enum", "enum type");
635
+ assertNoCrossKindNameCollisions(modelNames, enumNames);
636
+ const modelNameMap = new Map([...modelNames].map(([tableName, result]) => [tableName, result.name]));
637
+ const enumNameMap = new Map([...enumNames].map(([pgTypeName, result]) => [pgTypeName, result.name]));
638
+ const reservedNamedTypeNames = createReservedNamedTypeNames(modelNames, enumNames);
639
+ const fieldNamesByTable = buildFieldNamesByTable(schemaIR.tables);
640
+ const { relationsByTable } = inferRelations(schemaIR.tables, modelNameMap);
641
+ const namedTypes = seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNamedTypeNames);
642
+ const models = [];
643
+ for (const table of Object.values(schemaIR.tables)) models.push(buildModel(table, typeMap, enumNameMap, fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, relationsByTable.get(table.name) ?? []));
644
+ const sortedModels = topologicalSort(models, schemaIR.tables, modelNameMap);
645
+ const enums = [];
646
+ for (const [pgTypeName, values] of enumDefinitions) {
647
+ const enumName = enumNames.get(pgTypeName);
648
+ enums.push(buildEnum(enumName, values));
649
+ }
650
+ enums.sort((a, b) => a.name.localeCompare(b.name));
651
+ const namedTypeEntries = [...namedTypes.entriesByKey.values()].sort((a, b) => a.name.localeCompare(b.name));
652
+ const types = namedTypeEntries.length > 0 ? {
653
+ kind: "types",
654
+ declarations: namedTypeEntries.map(buildNamedTypeDeclaration),
655
+ span: SYNTHETIC_SPAN
656
+ } : void 0;
657
+ return {
658
+ kind: "document",
659
+ sourceId: "<sql-schema-ir>",
660
+ models: sortedModels,
661
+ enums,
662
+ compositeTypes: [],
663
+ ...types ? { types } : {},
664
+ span: SYNTHETIC_SPAN
665
+ };
666
+ }
667
+ function buildModel(table, typeMap, enumNameMap, fieldNamesByTable, namedTypes, defaultMapping, rawDefaultParser, relationFields) {
668
+ const { name: modelName, map: mapName } = toModelName(table.name);
669
+ const fieldNameMap = fieldNamesByTable.get(table.name);
670
+ const pkColumns = new Set(table.primaryKey?.columns ?? []);
671
+ const isSinglePk = pkColumns.size === 1;
672
+ const singlePkConstraintName = isSinglePk ? table.primaryKey?.name : void 0;
673
+ const uniqueColumns = /* @__PURE__ */ new Map();
674
+ for (const unique of table.uniques) if (unique.columns.length === 1) {
675
+ const [columnName = ""] = unique.columns;
676
+ const existingConstraintName = uniqueColumns.get(columnName);
677
+ if (!uniqueColumns.has(columnName) || existingConstraintName === void 0 && unique.name) uniqueColumns.set(columnName, unique.name);
678
+ }
679
+ const fields = [];
680
+ for (const column of Object.values(table.columns)) fields.push(buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, namedTypes, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns));
681
+ const usedFieldNames = new Set(fields.map((field) => field.name));
682
+ for (const rel of relationFields) fields.push(buildRelationField(rel, table.name, fieldNamesByTable, usedFieldNames));
683
+ const modelAttributes = [];
684
+ if (table.primaryKey && table.primaryKey.columns.length > 1) {
685
+ const pkFieldNames = table.primaryKey.columns.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
686
+ modelAttributes.push(buildModelConstraintAttribute("id", pkFieldNames, table.primaryKey.name));
687
+ }
688
+ for (const unique of table.uniques) if (unique.columns.length > 1) {
689
+ const uniqueFieldNames = unique.columns.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
690
+ modelAttributes.push(buildModelConstraintAttribute("unique", uniqueFieldNames, unique.name));
691
+ }
692
+ for (const index of table.indexes) if (!index.unique) {
693
+ const indexFieldNames = index.columns.map((columnName) => resolveColumnFieldName(fieldNamesByTable, table.name, columnName));
694
+ modelAttributes.push(buildModelConstraintAttribute("index", indexFieldNames, index.name));
695
+ }
696
+ if (mapName) modelAttributes.push(buildMapAttribute("model", mapName));
697
+ const comment = table.primaryKey ? void 0 : "// WARNING: This table has no primary key in the database";
698
+ return {
699
+ kind: "model",
700
+ name: modelName,
701
+ fields,
702
+ attributes: modelAttributes,
703
+ span: SYNTHETIC_SPAN,
704
+ ...comment !== void 0 ? { comment } : {}
705
+ };
706
+ }
707
+ function buildScalarField(column, table, typeMap, enumNameMap, fieldNameMap, namedTypes, defaultMapping, rawDefaultParser, pkColumns, isSinglePk, singlePkConstraintName, uniqueColumns) {
708
+ const resolvedField = fieldNameMap?.get(column.name);
709
+ const fieldName = resolvedField?.fieldName ?? toFieldName(column.name).name;
710
+ const fieldMap = resolvedField?.fieldMap;
711
+ const resolution = typeMap.resolve(column.nativeType, table.annotations);
712
+ if ("unsupported" in resolution) {
713
+ const attrs = [];
714
+ if (fieldMap !== void 0) attrs.push(buildMapAttribute("field", fieldMap));
715
+ return {
716
+ kind: "field",
717
+ name: fieldName,
718
+ typeName: `Unsupported("${escapePslString(resolution.nativeType)}")`,
719
+ optional: column.nullable,
720
+ list: false,
721
+ attributes: attrs,
722
+ span: SYNTHETIC_SPAN
723
+ };
724
+ }
725
+ let typeName = resolution.pslType;
726
+ const enumPslName = enumNameMap.get(column.nativeType);
727
+ if (enumPslName) typeName = enumPslName;
728
+ if (resolution.nativeTypeAttribute && !enumPslName) typeName = resolveNamedTypeName(namedTypes, resolution);
729
+ const attributes = [];
730
+ const isId = isSinglePk && pkColumns.has(column.name);
731
+ if (isId) attributes.push(buildSimpleConstraintFieldAttribute("id", singlePkConstraintName));
732
+ if (column.default !== void 0) {
733
+ const parsed = parseColumnDefault(column.default, column.nativeType, rawDefaultParser);
734
+ if (parsed) {
735
+ const result = mapDefault(parsed, defaultMapping);
736
+ if ("attribute" in result) attributes.push(parseDefaultAttributeString(result.attribute));
737
+ }
738
+ }
739
+ if (uniqueColumns.has(column.name) && !isId) {
740
+ const uniqueConstraintName = uniqueColumns.get(column.name);
741
+ attributes.push(buildSimpleConstraintFieldAttribute("unique", uniqueConstraintName));
742
+ }
743
+ if (fieldMap !== void 0) attributes.push(buildMapAttribute("field", fieldMap));
744
+ return {
745
+ kind: "field",
746
+ name: fieldName,
747
+ typeName,
748
+ optional: column.nullable,
749
+ list: false,
750
+ attributes,
751
+ span: SYNTHETIC_SPAN
752
+ };
753
+ }
754
+ function buildRelationField(rel, hostTableName, fieldNamesByTable, usedFieldNames) {
755
+ const fieldName = createUniqueFieldName(rel.fieldName, usedFieldNames);
756
+ usedFieldNames.add(fieldName);
757
+ const args = [];
758
+ if (rel.fields && rel.references) {
759
+ if (rel.relationName) args.push(namedArg("name", `"${escapePslString(rel.relationName)}"`));
760
+ args.push(namedArg("fields", `[${rel.fields.map((columnName) => resolveColumnFieldName(fieldNamesByTable, hostTableName, columnName)).join(", ")}]`));
761
+ args.push(namedArg("references", `[${rel.references.map((columnName) => resolveColumnFieldName(fieldNamesByTable, rel.referencedTableName ?? "", columnName)).join(", ")}]`));
762
+ if (rel.onDelete) args.push(namedArg("onDelete", rel.onDelete));
763
+ if (rel.onUpdate) args.push(namedArg("onUpdate", rel.onUpdate));
764
+ if (rel.fkName) args.push(namedArg("map", `"${escapePslString(rel.fkName)}"`));
765
+ } else if (rel.relationName) args.push(namedArg("name", `"${escapePslString(rel.relationName)}"`));
766
+ const attrs = args.length > 0 ? [buildAttribute("field", "relation", args)] : [];
767
+ return {
768
+ kind: "field",
769
+ name: fieldName,
770
+ typeName: rel.typeName,
771
+ optional: rel.optional,
772
+ list: rel.list,
773
+ attributes: attrs,
774
+ span: SYNTHETIC_SPAN
775
+ };
776
+ }
777
+ function buildModelConstraintAttribute(name, fields, constraintName) {
778
+ const args = [positionalArg(`[${fields.join(", ")}]`)];
779
+ if (constraintName !== void 0) args.push(namedArg("map", `"${escapePslString(constraintName)}"`));
780
+ return buildAttribute("model", name, args);
781
+ }
782
+ function buildSimpleConstraintFieldAttribute(name, constraintName) {
783
+ if (constraintName === void 0) return buildAttribute("field", name, []);
784
+ return buildAttribute("field", name, [namedArg("map", `"${escapePslString(constraintName)}"`)]);
785
+ }
786
+ function parseDefaultAttributeString(attributeText) {
787
+ return buildAttribute("field", "default", [positionalArg(attributeText.replace(/^@default\(/, "").replace(/\)$/, ""))]);
788
+ }
789
+ function buildMapAttribute(target, mapName) {
790
+ return buildAttribute(target, "map", [positionalArg(`"${escapePslString(mapName)}"`)]);
791
+ }
792
+ function buildAttribute(target, name, args) {
793
+ return {
794
+ kind: "attribute",
795
+ target,
796
+ name,
797
+ args,
798
+ span: SYNTHETIC_SPAN
799
+ };
800
+ }
801
+ function positionalArg(value) {
802
+ return {
803
+ kind: "positional",
804
+ value,
805
+ span: SYNTHETIC_SPAN
806
+ };
807
+ }
808
+ function namedArg(name, value) {
809
+ return {
810
+ kind: "named",
811
+ name,
812
+ value,
813
+ span: SYNTHETIC_SPAN
814
+ };
815
+ }
816
+ function buildEnum(name, values) {
817
+ const attrs = [];
818
+ if (name.map) attrs.push(buildMapAttribute("enum", name.map));
819
+ return {
820
+ kind: "enum",
821
+ name: name.name,
822
+ values: values.map((value) => ({
823
+ kind: "enumValue",
824
+ name: value,
825
+ span: SYNTHETIC_SPAN
826
+ })),
827
+ attributes: attrs,
828
+ span: SYNTHETIC_SPAN
829
+ };
830
+ }
831
+ function buildNamedTypeDeclaration(entry) {
832
+ const attribute = buildAttribute("namedType", entry.nativeTypeAttribute.name, (entry.nativeTypeAttribute.args ?? []).map(positionalArg));
833
+ return {
834
+ kind: "namedType",
835
+ name: entry.name,
836
+ baseType: entry.baseType,
837
+ attributes: [attribute],
838
+ span: SYNTHETIC_SPAN
839
+ };
840
+ }
841
+ function escapePslString(value) {
842
+ return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
843
+ }
844
+ /**
845
+ * Resolves a `SqlColumnIR.default` value into a normalized {@link ColumnDefault}.
846
+ *
847
+ * `SqlSchemaIR` types the column default as `string` (a raw database default
848
+ * expression). Some legacy fixtures and tests still pass already-normalized
849
+ * `ColumnDefault` objects in the same slot, so we accept either shape
850
+ * defensively at runtime.
851
+ */
852
+ function parseColumnDefault(value, nativeType, rawDefaultParser) {
853
+ if (typeof value === "string") return rawDefaultParser ? rawDefaultParser(value, nativeType) : void 0;
854
+ if (value !== null && typeof value === "object" && "kind" in value) return value;
855
+ }
856
+ function buildFieldNamesByTable(tables) {
857
+ const fieldNamesByTable = /* @__PURE__ */ new Map();
858
+ for (const table of Object.values(tables)) {
859
+ const assignmentOrder = [...Object.values(table.columns).map((column, index) => {
860
+ const { name, map } = toFieldName(column.name);
861
+ return {
862
+ columnName: column.name,
863
+ desiredFieldName: name,
864
+ fieldMap: map,
865
+ index
866
+ };
867
+ })].sort((left, right) => {
868
+ const mapComparison = Number(left.fieldMap !== void 0) - Number(right.fieldMap !== void 0);
869
+ if (mapComparison !== 0) return mapComparison;
870
+ return left.index - right.index;
871
+ });
872
+ const usedFieldNames = /* @__PURE__ */ new Set();
873
+ const tableFieldNames = /* @__PURE__ */ new Map();
874
+ for (const column of assignmentOrder) {
875
+ const fieldName = createUniqueFieldName(column.desiredFieldName, usedFieldNames);
876
+ usedFieldNames.add(fieldName);
877
+ tableFieldNames.set(column.columnName, {
878
+ fieldName,
879
+ fieldMap: column.fieldMap
880
+ });
881
+ }
882
+ fieldNamesByTable.set(table.name, tableFieldNames);
883
+ }
884
+ return fieldNamesByTable;
885
+ }
886
+ function resolveColumnFieldName(fieldNamesByTable, tableName, columnName) {
887
+ return fieldNamesByTable.get(tableName)?.get(columnName)?.fieldName ?? toFieldName(columnName).name;
888
+ }
889
+ function createUniqueFieldName(desiredName, usedFieldNames) {
890
+ if (!usedFieldNames.has(desiredName)) return desiredName;
891
+ let counter = 2;
892
+ while (usedFieldNames.has(`${desiredName}${counter}`)) counter++;
893
+ return `${desiredName}${counter}`;
894
+ }
895
+ function buildTopLevelNameMap(sources, normalize, kind, sourceKind) {
896
+ const results = /* @__PURE__ */ new Map();
897
+ const normalizedToSources = /* @__PURE__ */ new Map();
898
+ for (const source of sources) {
899
+ const normalized = normalize(source);
900
+ results.set(source, normalized);
901
+ normalizedToSources.set(normalized.name, [...normalizedToSources.get(normalized.name) ?? [], source]);
902
+ }
903
+ const duplicates = [...normalizedToSources.entries()].filter(([, conflictingSources]) => conflictingSources.length > 1);
904
+ if (duplicates.length > 0) {
905
+ const details = duplicates.map(([normalizedName, conflictingSources]) => `- ${kind} "${normalizedName}" from ${sourceKind}s ${conflictingSources.map((source) => `"${source}"`).join(", ")}`);
906
+ throw new Error(`PSL ${kind} name collisions detected:\n${details.join("\n")}`);
907
+ }
908
+ return results;
909
+ }
910
+ function assertNoCrossKindNameCollisions(modelNames, enumNames) {
911
+ const enumSourceByName = new Map([...enumNames].map(([source, result]) => [result.name, source]));
912
+ const collisions = [...modelNames.entries()].map(([tableName, result]) => {
913
+ const enumSource = enumSourceByName.get(result.name);
914
+ return enumSource ? `- identifier "${result.name}" from table "${tableName}" collides with enum type "${enumSource}"` : void 0;
915
+ }).filter((detail) => detail !== void 0);
916
+ if (collisions.length > 0) throw new Error(`PSL top-level name collisions detected:\n${collisions.join("\n")}`);
917
+ }
918
+ function createReservedNamedTypeNames(modelNames, enumNames) {
919
+ const reservedNames = new Set(PSL_SCALAR_TYPE_NAMES);
920
+ for (const result of modelNames.values()) reservedNames.add(result.name);
921
+ for (const result of enumNames.values()) reservedNames.add(result.name);
922
+ return reservedNames;
923
+ }
924
+ function seedNamedTypeRegistry(schemaIR, typeMap, enumNameMap, reservedNames) {
925
+ const seeds = /* @__PURE__ */ new Map();
926
+ for (const tableName of Object.keys(schemaIR.tables).sort()) {
927
+ const table = schemaIR.tables[tableName];
928
+ if (!table) continue;
929
+ for (const columnName of Object.keys(table.columns).sort()) {
930
+ const column = table.columns[columnName];
931
+ if (!column) continue;
932
+ const resolution = typeMap.resolve(column.nativeType, table.annotations);
933
+ if ("unsupported" in resolution || enumNameMap.has(column.nativeType) || !resolution.nativeTypeAttribute) continue;
934
+ const signatureKey = createNamedTypeSignatureKey(resolution);
935
+ if (!seeds.has(signatureKey)) seeds.set(signatureKey, {
936
+ baseType: resolution.pslType,
937
+ desiredName: toNamedTypeName(column.name),
938
+ nativeTypeAttribute: resolution.nativeTypeAttribute
939
+ });
940
+ }
941
+ }
942
+ const registry = {
943
+ entriesByKey: /* @__PURE__ */ new Map(),
944
+ usedNames: new Set(reservedNames)
945
+ };
946
+ const sortedSeeds = [...seeds.entries()].sort((left, right) => {
947
+ const desiredNameComparison = left[1].desiredName.localeCompare(right[1].desiredName);
948
+ if (desiredNameComparison !== 0) return desiredNameComparison;
949
+ return left[0].localeCompare(right[0]);
950
+ });
951
+ for (const [signatureKey, seed] of sortedSeeds) {
952
+ const name = createUniqueFieldName(seed.desiredName, registry.usedNames);
953
+ registry.entriesByKey.set(signatureKey, {
954
+ name,
955
+ baseType: seed.baseType,
956
+ nativeTypeAttribute: seed.nativeTypeAttribute
957
+ });
958
+ registry.usedNames.add(name);
959
+ }
960
+ return registry;
961
+ }
962
+ function resolveNamedTypeName(registry, resolution) {
963
+ const key = createNamedTypeSignatureKey(resolution);
964
+ const existing = registry.entriesByKey.get(key);
965
+ if (existing) return existing.name;
966
+ throw new Error(`Named type registry was not seeded for native type "${resolution.nativeType}"`);
967
+ }
968
+ function createNamedTypeSignatureKey(resolution) {
969
+ return JSON.stringify({
970
+ baseType: resolution.pslType,
971
+ nativeTypeAttribute: resolution.nativeTypeAttribute ? {
972
+ name: resolution.nativeTypeAttribute.name,
973
+ args: resolution.nativeTypeAttribute.args ?? null
974
+ } : null
975
+ });
976
+ }
977
+ function topologicalSort(models, tables, modelNameMap) {
978
+ const modelByName = /* @__PURE__ */ new Map();
979
+ for (const model of models) modelByName.set(model.name, model);
980
+ const deps = /* @__PURE__ */ new Map();
981
+ const tableToModel = /* @__PURE__ */ new Map();
982
+ for (const tableName of Object.keys(tables)) {
983
+ const modelName = modelNameMap.get(tableName);
984
+ tableToModel.set(tableName, modelName);
985
+ deps.set(modelName, /* @__PURE__ */ new Set());
986
+ }
987
+ for (const [tableName, table] of Object.entries(tables)) {
988
+ const modelName = tableToModel.get(tableName);
989
+ for (const fk of table.foreignKeys) {
990
+ const refModelName = tableToModel.get(fk.referencedTable);
991
+ if (refModelName && refModelName !== modelName) deps.get(modelName).add(refModelName);
992
+ }
993
+ }
994
+ const result = [];
995
+ const visited = /* @__PURE__ */ new Set();
996
+ const visiting = /* @__PURE__ */ new Set();
997
+ const sortedNames = [...deps.keys()].sort();
998
+ function visit(name) {
999
+ if (visited.has(name)) return;
1000
+ if (visiting.has(name)) return;
1001
+ visiting.add(name);
1002
+ const sortedDeps = [...deps.get(name)].sort();
1003
+ for (const dep of sortedDeps) visit(dep);
1004
+ visiting.delete(name);
1005
+ visited.add(name);
1006
+ result.push(modelByName.get(name));
1007
+ }
1008
+ for (const name of sortedNames) visit(name);
1009
+ return result;
1010
+ }
1011
+ //#endregion
13
1012
  //#region src/core/control-instance.ts
14
1013
  function extractCodecTypeIdsFromContract(contract) {
15
1014
  const typeIds = /* @__PURE__ */ new Set();
@@ -49,7 +1048,7 @@ function createVerifyResult(options) {
49
1048
  return result;
50
1049
  }
51
1050
  function isSqlControlAdapter(value) {
52
- return typeof value === "object" && value !== null && "introspect" in value && typeof value.introspect === "function";
1051
+ return typeof value === "object" && value !== null && "introspect" in value && typeof value.introspect === "function" && "readMarker" in value && typeof value.readMarker === "function" && "readAllMarkers" in value && typeof value.readAllMarkers === "function";
53
1052
  }
54
1053
  function buildSqlTypeMetadataRegistry(options) {
55
1054
  const { target, adapter, extensionPacks: extensions } = options;
@@ -77,16 +1076,30 @@ function createSqlFamilyInstance(stack) {
77
1076
  const target = stack.target;
78
1077
  const adapter = stack.adapter;
79
1078
  const extensions = stack.extensionPacks;
80
- const { codecTypeImports, operationTypeImports, extensionIds } = stack;
1079
+ for (const extension of extensions) if (extension.contractSpace) {
1080
+ const { contractJson, headRef } = extension.contractSpace;
1081
+ assertDescriptorSelfConsistency({
1082
+ extensionId: extension.id,
1083
+ target: contractJson.target,
1084
+ targetFamily: contractJson.targetFamily,
1085
+ storage: contractJson.storage,
1086
+ headRefHash: headRef.hash
1087
+ });
1088
+ }
1089
+ const { codecTypeImports, extensionIds } = stack;
81
1090
  const typeMetadataRegistry = buildSqlTypeMetadataRegistry({
82
1091
  target,
83
1092
  adapter,
84
1093
  extensionPacks: extensions
85
1094
  });
1095
+ const getControlAdapter = () => {
1096
+ const controlAdapter = adapter.create(stack);
1097
+ if (!isSqlControlAdapter(controlAdapter)) throw new Error("Adapter does not implement SqlControlAdapter (missing introspect, readMarker, or readAllMarkers)");
1098
+ return controlAdapter;
1099
+ };
86
1100
  return {
87
1101
  familyId: "sql",
88
1102
  codecTypeImports,
89
- operationTypeImports,
90
1103
  extensionIds,
91
1104
  typeMetadataRegistry,
92
1105
  validateContract(contractJson) {
@@ -99,7 +1112,7 @@ function createSqlFamilyInstance(stack) {
99
1112
  const contractStorageHash = contract.storage.storageHash;
100
1113
  const contractProfileHash = contract.profileHash;
101
1114
  const contractTarget = contract.target;
102
- const marker = await readMarker(driver);
1115
+ const marker = await getControlAdapter().readMarker(driver, APP_SPACE_ID);
103
1116
  let missingCodecs;
104
1117
  let codecCoverageSkipped = false;
105
1118
  const supportedTypeIds = collectSupportedCodecTypeIds([
@@ -186,8 +1199,7 @@ function createSqlFamilyInstance(stack) {
186
1199
  async schemaVerify(options) {
187
1200
  const { driver, contract: contractInput, strict, context, frameworkComponents } = options;
188
1201
  const contract = validateContract(contractInput, emptyCodecLookup);
189
- const controlAdapter = adapter.create(stack);
190
- if (!isSqlControlAdapter(controlAdapter)) throw new Error("Adapter does not implement SqlControlAdapter.introspect()");
1202
+ const controlAdapter = getControlAdapter();
191
1203
  return verifySqlSchema({
192
1204
  contract,
193
1205
  schema: await controlAdapter.introspect(driver, contractInput),
@@ -199,6 +1211,19 @@ function createSqlFamilyInstance(stack) {
199
1211
  ...ifDefined("normalizeNativeType", controlAdapter.normalizeNativeType)
200
1212
  });
201
1213
  },
1214
+ schemaVerifyAgainstSchema(options) {
1215
+ const contract = validateContract(options.contract, emptyCodecLookup);
1216
+ const controlAdapter = getControlAdapter();
1217
+ return verifySqlSchema({
1218
+ contract,
1219
+ schema: options.schema,
1220
+ strict: options.strict,
1221
+ typeMetadataRegistry,
1222
+ frameworkComponents: options.frameworkComponents,
1223
+ ...ifDefined("normalizeDefault", controlAdapter.normalizeDefault),
1224
+ ...ifDefined("normalizeNativeType", controlAdapter.normalizeNativeType)
1225
+ });
1226
+ },
202
1227
  async sign(options) {
203
1228
  const { driver, contract: contractInput, contractPath, configPath } = options;
204
1229
  const startTime = Date.now();
@@ -208,12 +1233,13 @@ function createSqlFamilyInstance(stack) {
208
1233
  const contractTarget = contract.target;
209
1234
  await driver.query(ensureSchemaStatement.sql, ensureSchemaStatement.params);
210
1235
  await driver.query(ensureTableStatement.sql, ensureTableStatement.params);
211
- const existingMarker = await readMarker(driver);
1236
+ const existingMarker = await getControlAdapter().readMarker(driver, APP_SPACE_ID);
212
1237
  let markerCreated = false;
213
1238
  let markerUpdated = false;
214
1239
  let previousHashes;
215
1240
  if (!existingMarker) {
216
1241
  const write = writeContractMarker({
1242
+ space: APP_SPACE_ID,
217
1243
  storageHash: contractStorageHash,
218
1244
  profileHash: contractProfileHash,
219
1245
  contractJson: contractInput,
@@ -230,6 +1256,7 @@ function createSqlFamilyInstance(stack) {
230
1256
  profileHash: existingProfileHash
231
1257
  };
232
1258
  const write = writeContractMarker({
1259
+ space: APP_SPACE_ID,
233
1260
  storageHash: contractStorageHash,
234
1261
  profileHash: contractProfileHash,
235
1262
  contractJson: contractInput,
@@ -268,13 +1295,19 @@ function createSqlFamilyInstance(stack) {
268
1295
  };
269
1296
  },
270
1297
  async readMarker(options) {
271
- return readMarker(options.driver);
1298
+ return getControlAdapter().readMarker(options.driver, options.space);
1299
+ },
1300
+ async readAllMarkers(options) {
1301
+ return getControlAdapter().readAllMarkers(options.driver);
272
1302
  },
273
1303
  async introspect(options) {
274
- const { driver, contract } = options;
275
- const controlAdapter = adapter.create(stack);
276
- if (!isSqlControlAdapter(controlAdapter)) throw new Error("Adapter does not implement SqlControlAdapter.introspect()");
277
- return controlAdapter.introspect(driver, contract);
1304
+ return getControlAdapter().introspect(options.driver, options.contract);
1305
+ },
1306
+ inferPslContract(schemaIR) {
1307
+ return sqlSchemaIrToPslAst(schemaIR);
1308
+ },
1309
+ toOperationPreview(operations) {
1310
+ return sqlOperationsToPreview(operations);
278
1311
  },
279
1312
  toSchemaView(schema) {
280
1313
  const tableNodes = Object.entries(schema.tables).map(([tableName, table]) => {
@@ -356,25 +1389,15 @@ function createSqlFamilyInstance(stack) {
356
1389
  ...children.length > 0 ? { children } : {}
357
1390
  });
358
1391
  });
359
- const dependencyNodes = schema.dependencies.map((dep) => {
360
- const shortName = dep.id.split(".").pop() ?? dep.id;
361
- return new SchemaTreeNode({
362
- kind: "dependency",
363
- id: `dependency-${dep.id}`,
364
- label: `${shortName} dependency is installed`
365
- });
366
- });
367
- const rootChildren = [...tableNodes, ...dependencyNodes];
368
1392
  return { root: new SchemaTreeNode({
369
1393
  kind: "root",
370
1394
  id: "sql-schema",
371
1395
  label: "database",
372
- ...rootChildren.length > 0 ? { children: rootChildren } : {}
1396
+ ...tableNodes.length > 0 ? { children: tableNodes } : {}
373
1397
  }) };
374
1398
  }
375
1399
  };
376
1400
  }
377
-
378
1401
  //#endregion
379
1402
  //#region src/core/control-descriptor.ts
380
1403
  var SqlFamilyDescriptor = class {
@@ -391,7 +1414,6 @@ var SqlFamilyDescriptor = class {
391
1414
  return createSqlFamilyInstance(stack);
392
1415
  }
393
1416
  };
394
-
395
1417
  //#endregion
396
1418
  //#region src/core/migrations/contract-to-schema-ir.ts
397
1419
  function convertColumn(name, column, storageTypes, expandNativeType, renderDefault) {
@@ -501,10 +1523,9 @@ function detectDestructiveChanges(from, to) {
501
1523
  /**
502
1524
  * Converts a `Contract` to `SqlSchemaIR`.
503
1525
  *
504
- * Reads `contract.storage` for tables, `contract.storage.types` for type
505
- * annotations, and derives database dependencies from `frameworkComponents`
506
- * (each component's `databaseDependencies.init[].id`).
507
- * Storage-type annotations are written under `options.annotationNamespace`.
1526
+ * Reads `contract.storage` for tables and `contract.storage.types` for type
1527
+ * annotations. Storage-type annotations are written under
1528
+ * `options.annotationNamespace`.
508
1529
  *
509
1530
  * Drops codec metadata (`codecId`, `typeRef`) since the schema IR only represents
510
1531
  * structural information. When `expandNativeType` is provided, parameterized types
@@ -515,38 +1536,135 @@ function detectDestructiveChanges(from, to) {
515
1536
  */
516
1537
  function contractToSchemaIR(contract, options) {
517
1538
  if (options.annotationNamespace.length === 0) throw new Error("annotationNamespace must be a non-empty string");
518
- if (!contract) return {
519
- tables: {},
520
- dependencies: []
521
- };
1539
+ if (!contract) return { tables: {} };
522
1540
  const storage = contract.storage;
523
1541
  const storageTypes = storage.types ?? {};
524
1542
  const tables = {};
525
1543
  for (const [tableName, tableDef] of Object.entries(storage.tables)) tables[tableName] = convertTable(tableName, tableDef, storageTypes, options.expandNativeType, options.renderDefault);
526
1544
  return {
527
1545
  tables,
528
- dependencies: deduplicateDependencyIRs(collectInitDependencies(options.frameworkComponents ?? [])),
529
1546
  ...ifDefined("annotations", deriveAnnotations(storage, options.annotationNamespace))
530
1547
  };
531
1548
  }
532
- function deduplicateDependencyIRs(deps) {
533
- const seen = /* @__PURE__ */ new Set();
534
- const result = [];
535
- for (const dep of deps) {
536
- if (dep.id.trim().length === 0) throw new Error("Dependency id must be a non-empty string");
537
- if (seen.has(dep.id)) continue;
538
- seen.add(dep.id);
539
- result.push({ id: dep.id });
540
- }
541
- return result;
542
- }
543
1549
  function deriveAnnotations(storage, annotationNamespace) {
544
1550
  if (!storage.types || Object.keys(storage.types).length === 0) return void 0;
545
1551
  const byNativeType = {};
546
1552
  for (const typeInstance of Object.values(storage.types)) byNativeType[typeInstance.nativeType] = typeInstance;
547
1553
  return { [annotationNamespace]: { storageTypes: byNativeType } };
548
1554
  }
549
-
1555
+ //#endregion
1556
+ //#region src/core/migrations/field-event-planner.ts
1557
+ function planFieldEventOperations(options) {
1558
+ const priorTables = options.priorContract?.storage.tables ?? {};
1559
+ const newTables = options.newContract.storage.tables;
1560
+ const added = [];
1561
+ const dropped = [];
1562
+ const altered = [];
1563
+ const tableNames = unionSorted(Object.keys(priorTables), Object.keys(newTables));
1564
+ for (const tableName of tableNames) {
1565
+ const priorTable = priorTables[tableName];
1566
+ const newTable = newTables[tableName];
1567
+ const fieldNames = unionSorted(priorTable ? Object.keys(priorTable.columns) : [], newTable ? Object.keys(newTable.columns) : []);
1568
+ for (const fieldName of fieldNames) {
1569
+ const priorField = priorTable?.columns[fieldName];
1570
+ const newField = newTable?.columns[fieldName];
1571
+ const entry = {
1572
+ tableName,
1573
+ fieldName,
1574
+ priorTable,
1575
+ newTable,
1576
+ priorField,
1577
+ newField
1578
+ };
1579
+ if (priorField === void 0 && newField !== void 0) added.push(entry);
1580
+ else if (priorField !== void 0 && newField === void 0) dropped.push(entry);
1581
+ else if (priorField !== void 0 && newField !== void 0) {
1582
+ if (isAlteration(priorField, newField)) altered.push(entry);
1583
+ }
1584
+ }
1585
+ }
1586
+ const calls = [];
1587
+ appendCalls("added", added, options.codecHooks, calls, (e) => e.newField?.codecId);
1588
+ appendCalls("dropped", dropped, options.codecHooks, calls, (e) => e.priorField?.codecId);
1589
+ appendCalls("altered", altered, options.codecHooks, calls, (e) => e.newField?.codecId);
1590
+ return calls;
1591
+ }
1592
+ function appendCalls(event, entries, codecHooks, calls, pickCodecId) {
1593
+ for (const entry of entries) {
1594
+ const codecId = pickCodecId(entry);
1595
+ if (codecId === void 0) continue;
1596
+ const hook = codecHooks.get(codecId);
1597
+ if (!hook?.onFieldEvent) continue;
1598
+ const ctx = buildContext(event, entry);
1599
+ const emitted = hook.onFieldEvent(event, ctx);
1600
+ for (const call of emitted) calls.push(call);
1601
+ }
1602
+ }
1603
+ /**
1604
+ * The context's prior/new sides are scoped to the event:
1605
+ *
1606
+ * - `'added'` — only `newTable` / `newField` populated.
1607
+ * - `'dropped'` — only `priorTable` / `priorField` populated.
1608
+ * - `'altered'` — both sides populated.
1609
+ */
1610
+ function buildContext(event, entry) {
1611
+ const base = {
1612
+ tableName: entry.tableName,
1613
+ fieldName: entry.fieldName
1614
+ };
1615
+ if (event === "added") return {
1616
+ ...base,
1617
+ ...entry.newTable !== void 0 ? { newTable: entry.newTable } : {},
1618
+ ...entry.newField !== void 0 ? { newField: entry.newField } : {}
1619
+ };
1620
+ if (event === "dropped") return {
1621
+ ...base,
1622
+ ...entry.priorTable !== void 0 ? { priorTable: entry.priorTable } : {},
1623
+ ...entry.priorField !== void 0 ? { priorField: entry.priorField } : {}
1624
+ };
1625
+ return {
1626
+ ...base,
1627
+ ...entry.priorTable !== void 0 ? { priorTable: entry.priorTable } : {},
1628
+ ...entry.newTable !== void 0 ? { newTable: entry.newTable } : {},
1629
+ ...entry.priorField !== void 0 ? { priorField: entry.priorField } : {},
1630
+ ...entry.newField !== void 0 ? { newField: entry.newField } : {}
1631
+ };
1632
+ }
1633
+ /**
1634
+ * `'altered'` predicate. Returns `false` whenever `codecId` differs —
1635
+ * any codec change suppresses the `altered` event entirely, including
1636
+ * cases where another property also differs in the same diff. Codec
1637
+ * rotation is a v1 non-goal; avoiding the mixed event keeps the
1638
+ * migration semantics for codec changes explicit rather than smuggling
1639
+ * them through as `altered`.
1640
+ *
1641
+ * For non-`codecId` diffs, returns `true` iff any other column property
1642
+ * differs.
1643
+ */
1644
+ function isAlteration(prior, current) {
1645
+ if (prior.codecId !== current.codecId) return false;
1646
+ return !sameStorageColumn(prior, current);
1647
+ }
1648
+ function sameStorageColumn(a, b) {
1649
+ if (a === b) return true;
1650
+ if (a.nativeType !== b.nativeType) return false;
1651
+ if (a.nullable !== b.nullable) return false;
1652
+ if (a.typeRef !== b.typeRef) return false;
1653
+ if (!sameJson(a.typeParams, b.typeParams)) return false;
1654
+ if (!sameJson(a.default, b.default)) return false;
1655
+ return true;
1656
+ }
1657
+ function sameJson(a, b) {
1658
+ if (a === b) return true;
1659
+ if (a === void 0 || b === void 0) return false;
1660
+ return JSON.stringify(a) === JSON.stringify(b);
1661
+ }
1662
+ function unionSorted(a, b) {
1663
+ const set = /* @__PURE__ */ new Set();
1664
+ for (const name of a) set.add(name);
1665
+ for (const name of b) set.add(name);
1666
+ return [...set].sort((x, y) => x < y ? -1 : x > y ? 1 : 0);
1667
+ }
550
1668
  //#endregion
551
1669
  //#region src/core/migrations/plan-helpers.ts
552
1670
  const readOnlyEmptyObject = Object.freeze({});
@@ -559,6 +1677,7 @@ function freezeSteps(steps) {
559
1677
  return Object.freeze(steps.map((step) => Object.freeze({
560
1678
  description: step.description,
561
1679
  sql: step.sql,
1680
+ ...step.params ? { params: Object.freeze([...step.params]) } : {},
562
1681
  ...step.meta ? { meta: cloneRecord(step.meta) } : {}
563
1682
  })));
564
1683
  }
@@ -580,6 +1699,7 @@ function freezeOperation(operation) {
580
1699
  label: operation.label,
581
1700
  ...operation.summary ? { summary: operation.summary } : {},
582
1701
  operationClass: operation.operationClass,
1702
+ ...operation.invariantId ? { invariantId: operation.invariantId } : {},
583
1703
  target: freezeTargetDetails(operation.target),
584
1704
  precheck: freezeSteps(operation.precheck),
585
1705
  execute: freezeSteps(operation.execute),
@@ -594,9 +1714,11 @@ function freezeOperations(operations) {
594
1714
  function createMigrationPlan(options) {
595
1715
  return Object.freeze({
596
1716
  targetId: options.targetId,
1717
+ spaceId: options.spaceId,
597
1718
  ...options.origin !== void 0 ? { origin: options.origin ? Object.freeze({ ...options.origin }) : null } : {},
598
1719
  destination: Object.freeze({ ...options.destination }),
599
1720
  operations: freezeOperations(options.operations),
1721
+ providedInvariants: Object.freeze([...options.providedInvariants]),
600
1722
  ...options.meta ? { meta: cloneRecord(options.meta) } : {}
601
1723
  });
602
1724
  }
@@ -638,18 +1760,16 @@ function runnerFailure(code, summary, options) {
638
1760
  ...options?.meta ? { meta: cloneRecord(options.meta) } : {}
639
1761
  }));
640
1762
  }
641
-
642
1763
  //#endregion
643
1764
  //#region src/core/migrations/policies.ts
644
1765
  /**
645
1766
  * Policy used by `db init`: additive-only operations, no widening/destructive steps.
646
1767
  */
647
1768
  const INIT_ADDITIVE_POLICY = Object.freeze({ allowedOperationClasses: Object.freeze(["additive"]) });
648
-
649
1769
  //#endregion
650
1770
  //#region src/exports/control.ts
651
1771
  var control_default = new SqlFamilyDescriptor();
652
-
653
1772
  //#endregion
654
- export { INIT_ADDITIVE_POLICY, assembleAuthoringContributions, collectInitDependencies, contractToSchemaIR, createMigrationPlan, control_default as default, detectDestructiveChanges, extractCodecControlHooks, isDatabaseDependencyProvider, plannerFailure, plannerSuccess, runnerFailure, runnerSuccess };
1773
+ export { INIT_ADDITIVE_POLICY, assembleAuthoringContributions, contractToSchemaIR, createMigrationPlan, control_default as default, detectDestructiveChanges, extractCodecControlHooks, planFieldEventOperations, plannerFailure, plannerSuccess, runnerFailure, runnerSuccess, temporalAuthoringPresets, timestampNowControlDescriptor };
1774
+
655
1775
  //# sourceMappingURL=control.mjs.map