@vibeorm/migrate 2.2.0 → 2.4.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 (59) hide show
  1. package/dist/adoption.d.ts.map +1 -1
  2. package/dist/baseline-record.d.ts +14 -0
  3. package/dist/baseline-record.d.ts.map +1 -0
  4. package/dist/baseline.d.ts +31 -0
  5. package/dist/baseline.d.ts.map +1 -0
  6. package/dist/compare-reference-rls.d.ts +10 -0
  7. package/dist/compare-reference-rls.d.ts.map +1 -0
  8. package/dist/compare-sqlite-primary-key.d.ts +6 -0
  9. package/dist/compare-sqlite-primary-key.d.ts.map +1 -0
  10. package/dist/ddl/sqlite.d.ts.map +1 -1
  11. package/dist/desired-state.d.ts.map +1 -1
  12. package/dist/fs.js +735 -452
  13. package/dist/fs.js.map +19 -16
  14. package/dist/index-predicates.d.ts +35 -0
  15. package/dist/index-predicates.d.ts.map +1 -0
  16. package/dist/index.d.ts +12 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +6430 -5110
  19. package/dist/index.js.map +48 -34
  20. package/dist/inspect-objects.d.ts +8 -1
  21. package/dist/inspect-objects.d.ts.map +1 -1
  22. package/dist/introspect/postgres.d.ts.map +1 -1
  23. package/dist/module-history.d.ts +6 -0
  24. package/dist/module-history.d.ts.map +1 -1
  25. package/dist/module-ownership.d.ts +8 -0
  26. package/dist/module-ownership.d.ts.map +1 -1
  27. package/dist/module-pending.d.ts +2 -0
  28. package/dist/module-pending.d.ts.map +1 -1
  29. package/dist/mysql-catalog-visibility.d.ts +5 -0
  30. package/dist/mysql-catalog-visibility.d.ts.map +1 -0
  31. package/dist/normalize.d.ts.map +1 -1
  32. package/dist/object-ownership.d.ts.map +1 -1
  33. package/dist/planner.d.ts +5 -0
  34. package/dist/planner.d.ts.map +1 -1
  35. package/dist/postgres-type-identity.d.ts +15 -0
  36. package/dist/postgres-type-identity.d.ts.map +1 -0
  37. package/dist/postgres-types.d.ts +21 -0
  38. package/dist/postgres-types.d.ts.map +1 -1
  39. package/dist/push.d.ts.map +1 -1
  40. package/dist/reference-state.d.ts.map +1 -1
  41. package/dist/replay-objects.d.ts +10 -0
  42. package/dist/replay-objects.d.ts.map +1 -0
  43. package/dist/replay-plan.d.ts +28 -0
  44. package/dist/replay-plan.d.ts.map +1 -0
  45. package/dist/replay-reference.d.ts +18 -0
  46. package/dist/replay-reference.d.ts.map +1 -0
  47. package/dist/runner.d.ts +6 -0
  48. package/dist/runner.d.ts.map +1 -1
  49. package/dist/shadow-dedicated.d.ts +12 -0
  50. package/dist/shadow-dedicated.d.ts.map +1 -0
  51. package/dist/shadow-guard.d.ts +13 -0
  52. package/dist/shadow-guard.d.ts.map +1 -0
  53. package/dist/shadow-types.d.ts +52 -0
  54. package/dist/shadow-types.d.ts.map +1 -0
  55. package/dist/shadow.d.ts +17 -0
  56. package/dist/shadow.d.ts.map +1 -0
  57. package/dist/verify-history.d.ts +35 -0
  58. package/dist/verify-history.d.ts.map +1 -0
  59. package/package.json +3 -3
package/dist/fs.js CHANGED
@@ -1,6 +1,22 @@
1
1
  // @bun
2
+ // packages/migrate/src/mysql-catalog-visibility.ts
3
+ function hasMysqlGlobalCatalogVisibility(params) {
4
+ let visible = false;
5
+ for (const row of params.rows) {
6
+ const values = Object.values(row);
7
+ if (values.length !== 1 || typeof values[0] !== "string" || !values[0].startsWith("GRANT "))
8
+ return false;
9
+ const grant = /^GRANT ([A-Z_ ,]+) ON \*\.\* TO /.exec(values[0]);
10
+ const privileges = grant?.[1]?.split(", ") ?? [];
11
+ if (privileges.some((privilege) => privilege === "SHOW VIEW" || privilege === "SELECT" || privilege === "ALL PRIVILEGES"))
12
+ visible = true;
13
+ }
14
+ return visible;
15
+ }
16
+
2
17
  // packages/migrate/src/module-ownership.ts
3
- import { VibeError as VibeError16, sqlObjectKey as sqlObjectKey6 } from "@vibeorm/schema";
18
+ import { VibeError as VibeError17, sqlObjectKey as sqlObjectKey6 } from "@vibeorm/schema";
19
+ import { getSqlDialect as getSqlDialect3, renderModuleDependencyQuery } from "@vibeorm/sql";
4
20
 
5
21
  // packages/migrate/src/desired-state.ts
6
22
  import { VibeError, assertValidSchemaIR, isSqlObjectDefinition, isSqlObjectIdentity, providerToDialect, sqlObjectKey } from "@vibeorm/schema";
@@ -38,7 +54,7 @@ function keysOnly(value, allowed) {
38
54
  function modelShape(value) {
39
55
  if (!record(value) || typeof value.name !== "string" || !Array.isArray(value.fields) || !Array.isArray(value.relations) || !Array.isArray(value.indexes))
40
56
  return false;
41
- return value.fields.every((field) => record(field) && typeof field.name === "string" && (typeof field.type === "string" || record(field.type) && typeof field.type.enum === "string") && ["isId", "isUnique", "isOptional", "isList"].every((key) => typeof field[key] === "boolean")) && value.relations.every(record) && value.indexes.every((index) => record(index) && Array.isArray(index.fields) && index.fields.every(record)) && (value.checks === undefined || Array.isArray(value.checks) && value.checks.every((check) => record(check) && typeof check.name === "string" && typeof check.expression === "string"));
57
+ return value.fields.every((field) => record(field) && typeof field.name === "string" && (field.nativeTypeIdentity === undefined || record(field.nativeTypeIdentity) && keysOnly(field.nativeTypeIdentity, ["source", "namespace"]) && field.isUnsupported === true && typeof field.nativeTypeIdentity.source === "string" && field.nativeTypeIdentity.source === field.nativeType && typeof field.nativeTypeIdentity.namespace === "string" && field.nativeTypeIdentity.namespace.length > 0) && (typeof field.type === "string" || record(field.type) && typeof field.type.enum === "string") && ["isId", "isUnique", "isOptional", "isList"].every((key) => typeof field[key] === "boolean")) && value.relations.every(record) && value.indexes.every((index) => record(index) && Array.isArray(index.fields) && index.fields.every(record)) && (value.checks === undefined || Array.isArray(value.checks) && value.checks.every((check) => record(check) && typeof check.name === "string" && typeof check.expression === "string"));
42
58
  }
43
59
  function state(value) {
44
60
  if (!record(value) || !keysOnly(value, ["schema", "definitions", "normalization"]) || !record(value.schema) || !Array.isArray(value.definitions) || !value.definitions.every(isSqlObjectDefinition))
@@ -100,10 +116,10 @@ function parseMigrationMetadata(params) {
100
116
  }
101
117
 
102
118
  // packages/migrate/src/object-ownership.ts
103
- import { VibeError as VibeError6, sqlObjectKey as sqlObjectKey2, enumStorageOf as enumStorageOf2 } from "@vibeorm/schema";
119
+ import { VibeError as VibeError6, defaultPrimaryKeyName, enumStorageOf as enumStorageOf2, implicitJoinTableObjectNames, postgresGeneratedObjectName, sqlObjectKey as sqlObjectKey2 } from "@vibeorm/schema";
104
120
 
105
121
  // packages/migrate/src/normalize.ts
106
- import { VibeError as VibeError5, enumStorageOf, isEnumType as isEnumType5, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
122
+ import { VibeError as VibeError5, defaultForeignKeyName, defaultIndexName, enumStorageOf, isEnumType as isEnumType5, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
107
123
 
108
124
  // packages/migrate/src/relations.ts
109
125
  import { implicitJoinTable, isImplicitManyToManyRelation } from "@vibeorm/schema";
@@ -138,7 +154,7 @@ function detectImplicitM2MPairs(params) {
138
154
 
139
155
  // packages/migrate/src/postgres-types.ts
140
156
  import { VibeError as VibeError2, isEnumType, scalarListDefault, serializeJsonDefault } from "@vibeorm/schema";
141
- import { POSTGRES_CODECS, postgresDialect, toPgArrayLiteral } from "@vibeorm/sql";
157
+ import { POSTGRES_CODECS, postgresDialect, toPgArrayLiteral, parsePostgresTypeName, renderPostgresTypeName } from "@vibeorm/sql";
142
158
  var SCALAR_TO_PG = {
143
159
  String: "text",
144
160
  Boolean: "boolean",
@@ -153,6 +169,49 @@ var SCALAR_TO_PG = {
153
169
  var CANONICAL_EQUIVALENTS = {
154
170
  DateTime: ["timestamptz(3)", "timestamptz(6)"]
155
171
  };
172
+ var CANONICAL_UDT = {
173
+ text: "String",
174
+ bool: "Boolean",
175
+ int4: "Int",
176
+ int8: "BigInt",
177
+ float8: "Float",
178
+ numeric: "Decimal",
179
+ timestamptz: "DateTime",
180
+ jsonb: "Json",
181
+ bytea: "Bytes"
182
+ };
183
+ var NON_CANONICAL_UDT = {
184
+ varchar: "String",
185
+ bpchar: "String",
186
+ uuid: "String",
187
+ bit: "String",
188
+ varbit: "String",
189
+ xml: "String",
190
+ inet: "String",
191
+ citext: "String",
192
+ int2: "Int",
193
+ oid: "Int",
194
+ float4: "Float",
195
+ money: "Decimal",
196
+ timestamp: "DateTime",
197
+ date: "DateTime",
198
+ time: "DateTime",
199
+ timetz: "DateTime",
200
+ json: "Json"
201
+ };
202
+ var SPELLING_TO_UDT = {
203
+ integer: "int4",
204
+ bigint: "int8",
205
+ smallint: "int2",
206
+ boolean: "bool",
207
+ doubleprecision: "float8",
208
+ real: "float4",
209
+ char: "bpchar"
210
+ };
211
+ function scalarForBuiltinType(params) {
212
+ const udt = SPELLING_TO_UDT[params.name] ?? params.name;
213
+ return CANONICAL_UDT[udt] ?? NON_CANONICAL_UDT[udt];
214
+ }
156
215
  var NATIVE_ALIASES = {
157
216
  charactervarying: "varchar",
158
217
  character: "char",
@@ -172,7 +231,11 @@ var NATIVE_ALIASES = {
172
231
  timestampwithtimezone: "timestamptz",
173
232
  timestampwithouttimezone: "timestamp",
174
233
  timewithtimezone: "timetz",
175
- timewithouttimezone: "time"
234
+ timewithouttimezone: "time",
235
+ bitvarying: "varbit"
236
+ };
237
+ var IMPLICIT_MODIFIERS = {
238
+ bit: "(1)"
176
239
  };
177
240
  function normalizeNativeType(params) {
178
241
  const compact = params.raw.toLowerCase().replace(/\s+/g, "");
@@ -180,13 +243,33 @@ function normalizeNativeType(params) {
180
243
  if (match === null)
181
244
  return compact;
182
245
  const base = NATIVE_ALIASES[match[1]] ?? match[1];
183
- return `${base}${match[2] ?? ""}${match[3] ?? ""}`;
246
+ return `${base}${match[2] ?? IMPLICIT_MODIFIERS[base] ?? ""}${match[3] ?? ""}`;
247
+ }
248
+ function parseUnsupportedPostgresType(params) {
249
+ const temporal = /^\s*(time(?:stamp)?)\s*(\(\s*\d+\s*\))?\s+(with|without)\s+time\s+zone\s*((?:\[\s*\]\s*)*)$/i.exec(params.raw);
250
+ if (temporal !== null)
251
+ return parsePostgresTypeName({ raw: `${temporal[1].toLowerCase()}${temporal[3].toLowerCase() === "with" ? "tz" : ""}${temporal[2] ?? ""}${temporal[4] ?? ""}` });
252
+ const parsed = parsePostgresTypeName(params);
253
+ if (parsed !== undefined || /["']/.test(params.raw))
254
+ return parsed;
255
+ const base = params.raw.toLowerCase().replace(/\s+/g, "").replace(/\(.*\)|\[\]/g, "");
256
+ return NATIVE_ALIASES[base] === undefined ? undefined : parsePostgresTypeName({ raw: normalizeNativeType(params) });
184
257
  }
185
258
  function columnTypeKey(params) {
186
259
  const { field } = params;
187
260
  const listSuffix = field.isList ? "[]" : "";
188
261
  if (field.isUnsupported === true) {
189
- return `u:${normalizeNativeType({ raw: field.nativeType ?? "" })}`;
262
+ const parsed = parseUnsupportedPostgresType({ raw: field.nativeType ?? "" });
263
+ if (parsed === undefined)
264
+ return `u:${field.nativeType ?? ""}`;
265
+ const evidence = field.nativeTypeIdentity;
266
+ const namespace = evidence !== undefined && evidence.source === field.nativeType ? evidence.namespace : parsed.namespace;
267
+ const scalar = namespace === undefined || namespace === "pg_catalog" ? scalarForBuiltinType({ name: parsed.name }) : undefined;
268
+ if (scalar !== undefined) {
269
+ const { isUnsupported: _unsupported, nativeTypeIdentity: _identity, ...rest } = field;
270
+ return columnTypeKey({ field: { ...rest, type: scalar, nativeType: `${parsed.name}${parsed.modifier ?? ""}`, isList: parsed.array || field.isList } });
271
+ }
272
+ return `u:${JSON.stringify([namespace ?? null, parsed.name, parsed.modifier, parsed.array || field.isList])}`;
190
273
  }
191
274
  if (isEnumType(field.type)) {
192
275
  return `e:${field.type.enum}${listSuffix}`;
@@ -218,6 +301,10 @@ function columnTypeSql(params) {
218
301
  meta: { field: field.name }
219
302
  });
220
303
  }
304
+ const parsed = parseUnsupportedPostgresType({ raw: field.nativeType });
305
+ const evidence = field.nativeTypeIdentity;
306
+ if (parsed !== undefined && evidence?.source === field.nativeType)
307
+ return renderPostgresTypeName({ dialect: postgresDialect, type: { ...parsed, namespace: evidence.namespace, array: parsed.array || field.isList } });
221
308
  return field.nativeType;
222
309
  }
223
310
  const listSuffix = field.isList ? "[]" : "";
@@ -270,8 +357,12 @@ function defaultFingerprint(params) {
270
357
  }
271
358
  case "enumValue":
272
359
  return `enum:${def.value}`;
273
- case "dbgenerated":
274
- return `db:${def.sql.trim()}`;
360
+ case "dbgenerated": {
361
+ const sql = def.sql.trim();
362
+ if (/^now\(\)$/i.test(sql) || /^current_timestamp(\(\d\))?$/i.test(sql))
363
+ return "now";
364
+ return `db:${sql}`;
365
+ }
275
366
  }
276
367
  }
277
368
  function defaultSql(params) {
@@ -762,8 +853,8 @@ function normalizeModel(params) {
762
853
  });
763
854
  }
764
855
  const pk = normalizePk({ model });
765
- const indexes = normalizeIndexes({ model, table });
766
- const fks = normalizeFks({ model, table, schema });
856
+ const indexes = normalizeIndexes({ model, table, dialect });
857
+ const fks = normalizeFks({ model, table, schema, dialect });
767
858
  const checks = new Map;
768
859
  for (const check of model.checks ?? [])
769
860
  checks.set(check.name, check.expression);
@@ -777,7 +868,7 @@ function normalizePk(params) {
777
868
  return model.fields.filter((field) => field.isId).map((field) => field.dbName ?? field.name);
778
869
  }
779
870
  function normalizeIndexes(params) {
780
- const { model, table } = params;
871
+ const { model, table, dialect } = params;
781
872
  const result = new Map;
782
873
  const add = (index) => {
783
874
  const unique = index.kind === "unique";
@@ -796,7 +887,7 @@ function normalizeIndexes(params) {
796
887
  const key = indexComparisonKey({ unique, kind, columns, where, nullsNotDistinct });
797
888
  if (result.has(key))
798
889
  return;
799
- const name = index.name ?? `${table}_${columns.map((column) => column.name).join("_")}_${unique ? "key" : "idx"}`;
890
+ const name = index.name ?? defaultIndexName({ table, columns: columns.map((column) => column.name), unique, dialect });
800
891
  result.set(key, {
801
892
  key,
802
893
  name,
@@ -1002,7 +1093,7 @@ function normalizeFks(params) {
1002
1093
  continue;
1003
1094
  result.set(key, {
1004
1095
  key,
1005
- constraintName: relation.constraintName ?? `${table}_${columns.join("_")}_fkey`,
1096
+ constraintName: relation.constraintName ?? defaultForeignKeyName({ table, columns, dialect: params.dialect }),
1006
1097
  columns,
1007
1098
  refTable,
1008
1099
  refColumns,
@@ -1145,7 +1236,7 @@ function removalIdentity(params) {
1145
1236
  case "dropForeignKey":
1146
1237
  return { kind: "constraint", constraintType: "foreignKey", table, name: step.constraintName };
1147
1238
  case "dropPrimaryKey":
1148
- return { kind: "constraint", constraintType: "primaryKey", table, name: step.constraintName ?? `${step.table}_pkey` };
1239
+ return { kind: "constraint", constraintType: "primaryKey", table, name: step.constraintName ?? defaultPrimaryKeyName({ table: step.table, dialect: "postgres" }) };
1149
1240
  default:
1150
1241
  return;
1151
1242
  }
@@ -1164,7 +1255,7 @@ function schemaObjectIdentities(params) {
1164
1255
  if (definition.defaultKey !== null)
1165
1256
  result.push({ kind: "columnDefault", table, column });
1166
1257
  if (params.dialect === "postgres" && definition.field.default?.kind === "autoincrement")
1167
- result.push({ kind: "sequence", name: { namespace: params.namespace, name: `${name}_${column}_seq` } });
1258
+ result.push({ kind: "sequence", name: { namespace: params.namespace, name: postgresGeneratedObjectName({ name1: name, name2: column, label: "seq" }) } });
1168
1259
  }
1169
1260
  for (const exclusion of model.model.exclusions ?? [])
1170
1261
  result.push({ kind: "constraint", constraintType: "exclusion", table, name: exclusion.name });
@@ -1178,15 +1269,15 @@ function schemaObjectIdentities(params) {
1178
1269
  for (const fk of model.fks.values())
1179
1270
  result.push({ kind: "constraint", constraintType: "foreignKey", table, name: fk.constraintName });
1180
1271
  if (model.pk.length > 0)
1181
- result.push({ kind: "constraint", constraintType: "primaryKey", table, name: model.model.primaryKeyConstraintName ?? (params.dialect === "mysql" ? "PRIMARY" : `${name}_pkey`) });
1272
+ result.push({ kind: "constraint", constraintType: "primaryKey", table, name: model.model.primaryKeyConstraintName ?? (params.dialect === "mysql" ? "PRIMARY" : defaultPrimaryKeyName({ table: name, dialect: params.dialect })) });
1182
1273
  }
1183
1274
  for (const name of normalized.joinTables.keys()) {
1184
1275
  const table = { namespace: params.namespace, name };
1185
1276
  result.push({ kind: "table", name: table });
1186
- for (const column of ["A", "B"])
1187
- result.push({ kind: "column", table, column }, { kind: "constraint", constraintType: "foreignKey", table, name: `${name}_${column}_fkey` });
1188
- for (const suffix of ["AB_unique", "B_index"])
1189
- result.push({ kind: "index", table, name: `${name}_${suffix}` });
1277
+ const derived = implicitJoinTableObjectNames({ table: name });
1278
+ result.push({ kind: "column", table, column: "A" }, { kind: "constraint", constraintType: "foreignKey", table, name: derived.foreignKeyA });
1279
+ result.push({ kind: "column", table, column: "B" }, { kind: "constraint", constraintType: "foreignKey", table, name: derived.foreignKeyB });
1280
+ result.push({ kind: "index", table, name: derived.uniqueIndex }, { kind: "index", table, name: derived.indexB });
1190
1281
  }
1191
1282
  for (const name of normalized.views.keys())
1192
1283
  result.push({ kind: "view", name: { namespace: params.namespace, name } });
@@ -1196,7 +1287,7 @@ function assertRetainedMigrationObjects(params) {
1196
1287
  const keys = new Set(params.to.map((object) => sqlObjectKey2({ identity: object.identity })));
1197
1288
  const removed = params.from.filter((object) => !keys.has(sqlObjectKey2({ identity: object.identity })));
1198
1289
  if (removed.length > 0)
1199
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Removing migration ownership requires a reviewed hand-authored migration and new desired state", meta: { reason: "migration-object-removal-review-required", objects: removed.map((object) => object.identity) } });
1290
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Removing migration ownership requires a reviewed hand-authored migration and new desired state", meta: { reason: "migration-object-removal-review-required", shadowReusable: true, objects: removed.map((object) => object.identity) } });
1200
1291
  }
1201
1292
  function orderedMigrationObjects(params) {
1202
1293
  const byKey = new Map(params.objects.map((object) => [sqlObjectKey2({ identity: object.identity }), object]));
@@ -1227,10 +1318,10 @@ function assertNamedRemovals(params) {
1227
1318
  const approved = new Set((params.approved ?? []).map((identity) => sqlObjectKey2({ identity })));
1228
1319
  const missing = params.removals.filter((identity) => !approved.has(sqlObjectKey2({ identity })));
1229
1320
  if (missing.length > 0)
1230
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unmanaged removals require individually named approvals", meta: { reason: "unmanaged-removal-required", objects: missing } });
1321
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unmanaged removals require individually named approvals", meta: { reason: "unmanaged-removal-required", shadowReusable: true, objects: missing } });
1231
1322
  const integrity = params.removals.filter((identity) => identity.kind === "constraint" || identity.kind === "index");
1232
1323
  if (integrity.length > 0 && params.acceptIntegrityLoss !== true)
1233
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Named constraint or index removals also require acceptIntegrityLoss", meta: { reason: "integrity-acknowledgement-required", objects: integrity } });
1324
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Named constraint or index removals also require acceptIntegrityLoss", meta: { reason: "integrity-acknowledgement-required", shadowReusable: true, objects: integrity } });
1234
1325
  }
1235
1326
  function assertRemovalAuthorization(params) {
1236
1327
  const declared = params.previous === undefined ? [] : schemaObjectIdentities({ schema: params.previous.schema, dialect: params.dialect, namespace: params.namespace });
@@ -1255,14 +1346,14 @@ function assertRemovalAuthorization(params) {
1255
1346
  }
1256
1347
  }
1257
1348
  if (unknown.length > 0)
1258
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unknown object removals require individually named removeUnmanaged decisions", meta: { reason: "unmanaged-removal-required", objects: unknown } });
1349
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unknown object removals require individually named removeUnmanaged decisions", meta: { reason: "unmanaged-removal-required", shadowReusable: true, objects: unknown } });
1259
1350
  if (integrity.length > 0 && params.acceptIntegrityLoss !== true)
1260
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Constraint or index removal requires acceptIntegrityLoss; data-loss acknowledgement does not authorize it", meta: { reason: "integrity-acknowledgement-required", objects: integrity } });
1351
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Constraint or index removal requires acceptIntegrityLoss; data-loss acknowledgement does not authorize it", meta: { reason: "integrity-acknowledgement-required", shadowReusable: true, objects: integrity } });
1261
1352
  }
1262
1353
 
1263
1354
  // packages/migrate/src/inventory.ts
1264
- import { VibeError as VibeError15, isSqlObjectIdentity as isSqlObjectIdentity2, sqlObjectKey as sqlObjectKey5 } from "@vibeorm/schema";
1265
- import { getSqlDialect as getSqlDialect2, renderMigrationInventory, renderSqliteColumnInventory, renderMysqlObjectMembers as renderMysqlObjectMembers2, sqliteTableConstraints as sqliteTableConstraints3, renderSqliteForeignKeyInventory } from "@vibeorm/sql";
1355
+ import { VibeError as VibeError16, defaultForeignKeyName as defaultForeignKeyName2, defaultPrimaryKeyName as defaultPrimaryKeyName2, isSqlObjectIdentity as isSqlObjectIdentity2, sqlObjectKey as sqlObjectKey5 } from "@vibeorm/schema";
1356
+ import { getSqlDialect as getSqlDialect2, renderMigrationInventory, renderSqliteColumnInventory as renderSqliteColumnInventory2, renderMysqlObjectMembers as renderMysqlObjectMembers2, sqliteTableConstraints as sqliteTableConstraints3, renderSqliteForeignKeyInventory } from "@vibeorm/sql";
1266
1357
 
1267
1358
  // packages/migrate/src/exclusions.ts
1268
1359
  import { randomUUID } from "crypto";
@@ -1342,16 +1433,16 @@ async function verifyExclusions(params) {
1342
1433
 
1343
1434
  // packages/migrate/src/inspect-objects.ts
1344
1435
  import { randomUUID as randomUUID2 } from "crypto";
1345
- import { VibeError as VibeError14, sqlObjectKey as sqlObjectKey4, DIALECT_CAPABILITIES as DIALECT_CAPABILITIES2 } from "@vibeorm/schema";
1346
- import { getSqlDialect, renderMigrationObjectQuery, renderCheckProbe, renderMigrationNamespace, renderMigrationDependencies, renderMysqlObjectMembers, renderMysqlCheckProbe, sqliteColumnClauses as sqliteColumnClauses2, renderMigrationVisibility, sqliteTableConstraints as sqliteTableConstraints2 } from "@vibeorm/sql";
1436
+ import { VibeError as VibeError15, sqlObjectKey as sqlObjectKey4, DIALECT_CAPABILITIES as DIALECT_CAPABILITIES2 } from "@vibeorm/schema";
1437
+ import { getSqlDialect, renderMigrationObjectBatch, renderMigrationObjectQuery, renderCheckProbe, renderMigrationNamespace, renderMigrationDependencies, renderMysqlObjectMembers, renderMysqlCheckProbe, sqliteColumnClauses as sqliteColumnClauses2, renderMigrationVisibility, sqliteTableConstraints as sqliteTableConstraints2, renderSqliteColumnInventory } from "@vibeorm/sql";
1347
1438
 
1348
1439
  // packages/migrate/src/introspect/postgres.ts
1349
1440
  import { renderExclusionCatalog as renderExclusionCatalog2 } from "@vibeorm/sql";
1350
1441
  import { parsePgArrayLiteral } from "@vibeorm/sql";
1351
1442
  import { scalarListDefault as scalarListDefault2 } from "@vibeorm/schema";
1352
1443
  import { exactIntegerLiteral } from "@vibeorm/schema";
1353
- import { postgresDialect as postgresDialect5, renderRlsReadinessQuery } from "@vibeorm/sql";
1354
- import { VibeError as VibeError11 } from "@vibeorm/schema";
1444
+ import { postgresDialect as postgresDialect6, renderRlsReadinessQuery } from "@vibeorm/sql";
1445
+ import { VibeError as VibeError12 } from "@vibeorm/schema";
1355
1446
 
1356
1447
  // packages/migrate/src/journal-table.ts
1357
1448
  var MIGRATIONS_TABLE_NAME = "_vibe_migrations";
@@ -1543,12 +1634,58 @@ function lowerFirst(value) {
1543
1634
  return value.charAt(0).toLowerCase() + value.slice(1);
1544
1635
  }
1545
1636
 
1637
+ // packages/migrate/src/postgres-type-identity.ts
1638
+ import { VibeError as VibeError9 } from "@vibeorm/schema";
1639
+ import { postgresDialect as postgresDialect3, renderPostgresTypeIdentity } from "@vibeorm/sql";
1640
+ async function resolvePostgresTypeIdentities(params) {
1641
+ const unavailable = [];
1642
+ const models = [];
1643
+ for (const model of params.schema.models) {
1644
+ const table = { namespace: "public", name: model.dbName ?? model.name };
1645
+ const previous = params.previous?.models.find((entry) => (entry.dbName ?? entry.name) === table.name);
1646
+ const fields = [];
1647
+ for (const field of model.fields) {
1648
+ if (field.isUnsupported !== true) {
1649
+ fields.push(field);
1650
+ continue;
1651
+ }
1652
+ const column = field.dbName ?? field.name;
1653
+ const parsed = parseUnsupportedPostgresType({ raw: field.nativeType ?? "" });
1654
+ const evidence = field.nativeTypeIdentity;
1655
+ if (evidence !== undefined && (evidence.source !== field.nativeType || parsed?.namespace !== undefined && parsed.namespace !== evidence.namespace)) {
1656
+ throw new VibeError9({ code: "VIBE_MIGRATION", message: "PostgreSQL type evidence no longer matches its declaration; recapture the independent reference", meta: { reason: "type-reference-invalid", shadowReusable: true, table: table.name, column } });
1657
+ }
1658
+ const prior = previous?.fields.find((entry) => (entry.dbName ?? entry.name) === column && entry.isUnsupported === true);
1659
+ const priorType = parseUnsupportedPostgresType({ raw: prior?.nativeType ?? "" });
1660
+ const priorNamespace = prior?.nativeTypeIdentity?.source === prior?.nativeType ? prior?.nativeTypeIdentity?.namespace : priorType?.namespace;
1661
+ let namespace = parsed?.namespace ?? evidence?.namespace ?? (priorType?.name === parsed?.name ? priorNamespace : undefined);
1662
+ if (params.mode === "catalog" || params.mode === "reference" || namespace === undefined) {
1663
+ const source = params.mode === "catalog" ? { table, column } : { type: { name: parsed?.name ?? "", ...namespace === undefined && params.mode === "reference" ? {} : { namespace: namespace ?? "pg_catalog" } } };
1664
+ const query = renderPostgresTypeIdentity({ dialect: postgresDialect3, source });
1665
+ const rows = parsed === undefined && params.mode !== "catalog" ? [] : await params.executor({ text: query.text, values: [...query.values] }).then((rows) => rows, (cause) => {
1666
+ throw new VibeError9({ code: "VIBE_MIGRATION", message: "PostgreSQL type identity inspection failed", meta: { reason: "type-inspection-unavailable", table: table.name, column }, cause });
1667
+ });
1668
+ const resolved = rows.length === 1 ? rows[0] : undefined;
1669
+ namespace = typeof resolved?.namespace === "string" && (resolved.name === parsed?.name || parsed === undefined && params.mode === "catalog") ? resolved.namespace : undefined;
1670
+ }
1671
+ if (parsed === undefined && params.mode !== "catalog" || namespace === undefined || field.nativeType === undefined) {
1672
+ unavailable.push({ kind: "column", table, column });
1673
+ fields.push(field);
1674
+ } else {
1675
+ fields.push({ ...field, nativeTypeIdentity: { source: field.nativeType, namespace } });
1676
+ }
1677
+ }
1678
+ models.push({ ...model, fields });
1679
+ }
1680
+ return { schema: { ...params.schema, models }, unavailable };
1681
+ }
1682
+
1546
1683
  // packages/migrate/src/introspect/postgres-rls.ts
1547
- import { VibeError as VibeError10, assertValidSchemaIR as assertValidSchemaIR3 } from "@vibeorm/schema";
1548
- import { NATIVE_RLS, postgresDialect as postgresDialect4, renderRlsPolicy as renderRlsPolicy2 } from "@vibeorm/sql";
1684
+ import { VibeError as VibeError11, assertValidSchemaIR as assertValidSchemaIR3 } from "@vibeorm/schema";
1685
+ import { NATIVE_RLS, postgresDialect as postgresDialect5, renderRlsPolicy as renderRlsPolicy2 } from "@vibeorm/sql";
1549
1686
 
1550
1687
  // packages/migrate/src/ddl/rls.ts
1551
- import { VibeError as VibeError9, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
1688
+ import { VibeError as VibeError10, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
1552
1689
  import * as sql from "@vibeorm/sql";
1553
1690
  function isRlsProtected(params) {
1554
1691
  return params.model.rls !== undefined && params.model.rls !== "unprotected";
@@ -1664,7 +1801,7 @@ function renderRlsStep(params) {
1664
1801
  return [renderer(common).text];
1665
1802
  }
1666
1803
  default:
1667
- throw new VibeError9({ code: "VIBE_MIGRATION", message: "Expected a native RLS migration step" });
1804
+ throw new VibeError10({ code: "VIBE_MIGRATION", message: "Expected a native RLS migration step" });
1668
1805
  }
1669
1806
  }
1670
1807
  function securityChangesOf(params) {
@@ -1673,7 +1810,7 @@ function securityChangesOf(params) {
1673
1810
  function assertSecurityAcknowledgement(params) {
1674
1811
  if (params.securityChanges.length === 0 || params.acceptSecurityChanges === true)
1675
1812
  return;
1676
- throw new VibeError9({
1813
+ throw new VibeError10({
1677
1814
  code: "VIBE_MIGRATION",
1678
1815
  message: `Security changes require acceptSecurityChanges: true; acceptDataLoss does not authorize them:
1679
1816
  ${params.securityChanges.join(`
@@ -1700,19 +1837,19 @@ async function readPostgresRls(params) {
1700
1837
  const tables = new Map;
1701
1838
  for (const row of rows) {
1702
1839
  const table = String(row.table_name);
1703
- let state2 = tables.get(table);
1704
- if (state2 === undefined) {
1705
- state2 = { table, enabled: row.enabled === true, force: row.force === true, policies: [] };
1706
- tables.set(table, state2);
1840
+ let state = tables.get(table);
1841
+ if (state === undefined) {
1842
+ state = { table, enabled: row.enabled === true, force: row.force === true, policies: [] };
1843
+ tables.set(table, state);
1707
1844
  }
1708
1845
  if (row.policy_name !== null && row.policy_name !== undefined) {
1709
- state2.policies.push({ name: String(row.policy_name), command: String(row.command), permissive: row.permissive === true, roles: String(row.roles), using: row.using_expression === null ? null : String(row.using_expression), withCheck: row.check_expression === null ? null : String(row.check_expression), comment: row.comment === null ? null : String(row.comment) });
1846
+ state.policies.push({ name: String(row.policy_name), command: String(row.command), permissive: row.permissive === true, roles: String(row.roles), using: row.using_expression === null ? null : String(row.using_expression), withCheck: row.check_expression === null ? null : String(row.check_expression), comment: row.comment === null ? null : String(row.comment) });
1710
1847
  }
1711
1848
  }
1712
1849
  return [...tables.values()];
1713
1850
  }
1714
1851
  function conflict(params) {
1715
- throw new VibeError10({
1852
+ throw new VibeError11({
1716
1853
  code: "VIBE_MIGRATION",
1717
1854
  message: `Native RLS on public.${params.table} cannot be managed safely (${params.attributes.join(", ")}). Review the live policies and restore the deployed declaration, or remove conflicting policies explicitly with administrator credentials. Supply rlsSchema/previousSchema for the deployed policy; no policy is deleted or adopted automatically.`,
1718
1855
  meta: params
@@ -1725,32 +1862,32 @@ async function verifyPostgresRls(params) {
1725
1862
  await executor({ text: "SET LOCAL search_path = ''" });
1726
1863
  const declared = new Map((schema?.models ?? []).map((model) => [model.dbName ?? model.name, model]));
1727
1864
  let tables = await readPostgresRls({ executor });
1728
- for (const state2 of tables) {
1729
- const model = declared.get(state2.table);
1730
- if (!state2.enabled && !state2.force && state2.policies.length === 0 && (model === undefined || !isRlsProtected({ model })))
1865
+ for (const state of tables) {
1866
+ const model = declared.get(state.table);
1867
+ if (!state.enabled && !state.force && state.policies.length === 0 && (model === undefined || !isRlsProtected({ model })))
1731
1868
  continue;
1732
- await executor({ text: `LOCK TABLE "public".${postgresDialect4.quoteIdent({ name: state2.table })} IN ACCESS EXCLUSIVE MODE` });
1869
+ await executor({ text: `LOCK TABLE "public".${postgresDialect5.quoteIdent({ name: state.table })} IN ACCESS EXCLUSIVE MODE` });
1733
1870
  }
1734
1871
  tables = await readPostgresRls({ executor });
1735
1872
  const matched = new Set;
1736
- for (const state2 of tables) {
1737
- const model = declared.get(state2.table);
1738
- const active = state2.enabled || state2.force || state2.policies.length > 0;
1873
+ for (const state of tables) {
1874
+ const model = declared.get(state.table);
1875
+ const active = state.enabled || state.force || state.policies.length > 0;
1739
1876
  if (schema === undefined && active)
1740
- conflict({ table: state2.table, reason: "rls-unmanaged", attributes: ["security metadata cannot be exported losslessly without a trusted declaration"] });
1877
+ conflict({ table: state.table, reason: "rls-unmanaged", attributes: ["security metadata cannot be exported losslessly without a trusted declaration"] });
1741
1878
  if (model === undefined || !isRlsProtected({ model })) {
1742
1879
  if (active)
1743
- conflict({ table: state2.table, reason: "rls-conflict", attributes: ["unexpected native policies or RLS flags"] });
1880
+ conflict({ table: state.table, reason: "rls-conflict", attributes: ["unexpected native policies or RLS flags"] });
1744
1881
  continue;
1745
1882
  }
1746
1883
  if (!active && params.requireInstalled !== true)
1747
1884
  continue;
1748
- const unknown = state2.policies.filter((policy2) => policy2.name !== NATIVE_RLS.policyName);
1885
+ const unknown = state.policies.filter((policy) => policy.name !== NATIVE_RLS.policyName);
1749
1886
  if (unknown.length > 0)
1750
- conflict({ table: state2.table, reason: "rls-conflict", attributes: unknown.map((policy2) => `unexpected policy ${policy2.name}`) });
1751
- const policy = state2.policies.find((entry) => entry.name === NATIVE_RLS.policyName);
1887
+ conflict({ table: state.table, reason: "rls-conflict", attributes: unknown.map((policy) => `unexpected policy ${policy.name}`) });
1888
+ const policy = state.policies.find((entry) => entry.name === NATIVE_RLS.policyName);
1752
1889
  if (policy === undefined)
1753
- conflict({ table: state2.table, reason: "rls-drift", attributes: ["missing policy"] });
1890
+ conflict({ table: state.table, reason: "rls-drift", attributes: ["missing policy"] });
1754
1891
  const structure = [
1755
1892
  ...policy.command !== "*" ? ["command"] : [],
1756
1893
  ...!policy.permissive ? ["permissiveness"] : [],
@@ -1758,27 +1895,27 @@ async function verifyPostgresRls(params) {
1758
1895
  ...policy.withCheck === null ? ["missing WITH CHECK"] : []
1759
1896
  ];
1760
1897
  if (structure.length > 0)
1761
- conflict({ table: state2.table, reason: "rls-conflict", attributes: structure });
1762
- const attributes = [...!state2.enabled ? ["enabled"] : [], ...!state2.force ? ["force"] : []];
1898
+ conflict({ table: state.table, reason: "rls-conflict", attributes: structure });
1899
+ const attributes = [...!state.enabled ? ["enabled"] : [], ...!state.force ? ["force"] : []];
1763
1900
  await executor({ text: "SAVEPOINT vibeorm_rls_probe" });
1764
1901
  let probe;
1765
1902
  try {
1766
- const rendered = renderRlsPolicy2({ dialect: postgresDialect4, schema, model: model.name, policyName: PROBE });
1903
+ const rendered = renderRlsPolicy2({ dialect: postgresDialect5, schema, model: model.name, policyName: PROBE });
1767
1904
  await executor({ text: rendered.text });
1768
- probe = (await readPostgresRls({ executor })).find((entry) => entry.table === state2.table)?.policies.find((entry) => entry.name === PROBE);
1905
+ probe = (await readPostgresRls({ executor })).find((entry) => entry.table === state.table)?.policies.find((entry) => entry.name === PROBE);
1769
1906
  } finally {
1770
1907
  await executor({ text: "ROLLBACK TO SAVEPOINT vibeorm_rls_probe" });
1771
1908
  await executor({ text: "RELEASE SAVEPOINT vibeorm_rls_probe" });
1772
1909
  }
1773
1910
  if (probe === undefined)
1774
- conflict({ table: state2.table, reason: "rls-drift", attributes: ["probe unavailable"] });
1911
+ conflict({ table: state.table, reason: "rls-drift", attributes: ["probe unavailable"] });
1775
1912
  if (policy.using !== probe.using)
1776
1913
  attributes.push("using");
1777
1914
  if (policy.withCheck !== probe.withCheck)
1778
1915
  attributes.push("withCheck");
1779
1916
  if (attributes.length > 0)
1780
- conflict({ table: state2.table, reason: "rls-drift", attributes });
1781
- matched.add(state2.table);
1917
+ conflict({ table: state.table, reason: "rls-drift", attributes });
1918
+ matched.add(state.table);
1782
1919
  }
1783
1920
  if (params.requireInstalled === true) {
1784
1921
  for (const [table, model] of declared) {
@@ -1961,18 +2098,17 @@ async function introspectPostgres(params) {
1961
2098
  if (params.inTransaction !== true)
1962
2099
  await executor({ text: "BEGIN" });
1963
2100
  try {
1964
- const savedPath = params.inTransaction === true ? await executor(renderRlsReadinessQuery({ dialect: postgresDialect5, query: "readSearchPath" })) : undefined;
1965
- const searchPath = savedPath?.[0]?.searchPath;
1966
- if (params.inTransaction === true && typeof searchPath !== "string")
1967
- throw new VibeError11({ code: "VIBE_MIGRATION", message: "Cannot read the migration search_path" });
2101
+ const savedPath = await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "readSearchPath" }));
2102
+ const searchPath = savedPath[0]?.searchPath;
2103
+ if (typeof searchPath !== "string")
2104
+ throw new VibeError12({ code: "VIBE_MIGRATION", message: "Cannot read the migration search_path" });
1968
2105
  const matched = await verifyPostgresRls({ executor, ...params.rlsSchema === undefined ? {} : { schema: params.rlsSchema }, ...params.requireInstalledRls === undefined ? {} : { requireInstalled: params.requireInstalledRls } }).then((verified) => verified, (error) => {
1969
- if (error instanceof VibeError11)
2106
+ if (error instanceof VibeError12)
1970
2107
  throw error;
1971
- throw new VibeError11({ code: "VIBE_MIGRATION", message: "Native RLS verification could not complete. Check migration privileges and supply the deployed schema as previousSchema/rlsSchema before changing referenced columns.", meta: { reason: "rls-verification-unavailable" }, cause: error });
2108
+ throw new VibeError12({ code: "VIBE_MIGRATION", message: "Native RLS verification could not complete. Check migration privileges and supply the deployed schema as previousSchema/rlsSchema before changing referenced columns.", meta: { reason: "rls-verification-unavailable" }, cause: error });
1972
2109
  });
2110
+ await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "setSearchPath", searchPath }));
1973
2111
  const physical = await introspectPhysicalPostgres({ executor });
1974
- if (typeof searchPath === "string")
1975
- await executor(renderRlsReadinessQuery({ dialect: postgresDialect5, query: "setSearchPath", searchPath }));
1976
2112
  return projectPostgresRls({ physical, ...params.rlsSchema === undefined ? {} : { declared: params.rlsSchema }, matched });
1977
2113
  } finally {
1978
2114
  if (params.inTransaction !== true)
@@ -1990,7 +2126,7 @@ async function introspectPhysicalPostgres(params) {
1990
2126
  executor({ text: ENUMS_QUERY }),
1991
2127
  executor({ text: INDEXES_QUERY }),
1992
2128
  executor({ text: CHECKS_QUERY }),
1993
- executor({ text: renderExclusionCatalog2({ dialect: postgresDialect5 }) })
2129
+ executor({ text: renderExclusionCatalog2({ dialect: postgresDialect6 }) })
1994
2130
  ]);
1995
2131
  const tables = tableRows.map((row) => row.table_name);
1996
2132
  const views = viewRows.map((row) => row.table_name);
@@ -2158,12 +2294,15 @@ async function introspectPhysicalPostgres(params) {
2158
2294
  }
2159
2295
  addFkRelations({ models, fkGroups, joinTables });
2160
2296
  addJoinTableRelations({ models, joinTables });
2161
- return {
2297
+ const resolved = await resolvePostgresTypeIdentities({ executor, mode: "catalog", schema: {
2162
2298
  datasource: { provider: "postgresql" },
2163
2299
  models,
2164
2300
  enums,
2165
2301
  extensions: []
2166
- };
2302
+ } });
2303
+ if (resolved.unavailable.length > 0)
2304
+ throw new VibeError12({ code: "VIBE_MIGRATION", message: "PostgreSQL column type identity could not be read", meta: { reason: "type-inspection-unavailable", columns: resolved.unavailable } });
2305
+ return resolved.schema;
2167
2306
  }
2168
2307
  function buildModel(params) {
2169
2308
  const { table, isView, columns, pkByTable, uniquesByConstraint, constraintNames, indexes, enumNames } = params;
@@ -2246,27 +2385,6 @@ function buildField(params) {
2246
2385
  ...mapped.isUnsupported === true ? { isUnsupported: true } : {}
2247
2386
  };
2248
2387
  }
2249
- var CANONICAL_UDT = {
2250
- text: "String",
2251
- bool: "Boolean",
2252
- int4: "Int",
2253
- int8: "BigInt",
2254
- float8: "Float",
2255
- numeric: "Decimal",
2256
- timestamptz: "DateTime",
2257
- jsonb: "Json",
2258
- bytea: "Bytes"
2259
- };
2260
- var NON_CANONICAL_UDT = {
2261
- varchar: "String",
2262
- bpchar: "String",
2263
- uuid: "String",
2264
- int2: "Int",
2265
- float4: "Float",
2266
- timestamp: "DateTime",
2267
- date: "DateTime",
2268
- json: "Json"
2269
- };
2270
2388
  function reverseMapType(params) {
2271
2389
  const { column, enumNames } = params;
2272
2390
  const isList = column.dataType === "ARRAY";
@@ -2322,8 +2440,10 @@ function withModifier(params) {
2322
2440
  }
2323
2441
  if (udt === "bpchar")
2324
2442
  return "char";
2325
- if (udt === "timestamp" && column.datetimePrecision !== null && column.datetimePrecision !== 6) {
2326
- return `timestamp(${column.datetimePrecision})`;
2443
+ if ((udt === "bit" || udt === "varbit") && column.charMaxLength !== null)
2444
+ return `${udt}(${column.charMaxLength})`;
2445
+ if ((udt === "timestamp" || udt === "time" || udt === "timetz") && column.datetimePrecision !== null && column.datetimePrecision !== 6) {
2446
+ return `${udt}(${column.datetimePrecision})`;
2327
2447
  }
2328
2448
  return udt;
2329
2449
  }
@@ -3132,8 +3252,8 @@ async function readIndexes(params) {
3132
3252
  }
3133
3253
  let where;
3134
3254
  if (partial) {
3135
- const sql2 = indexSqlByName.get(name);
3136
- const match = sql2?.match(/\sWHERE\s+(.*)$/is);
3255
+ const sql = indexSqlByName.get(name);
3256
+ const match = sql?.match(/\sWHERE\s+(.*)$/is);
3137
3257
  where = match?.[1]?.trim();
3138
3258
  }
3139
3259
  tableIndexes.push({
@@ -3164,17 +3284,17 @@ async function readIndexes(params) {
3164
3284
  var PLAIN_INDEX_COLUMN = /^"((?:[^"]|"")+)"(?:\s+(ASC|DESC))?$/i;
3165
3285
  var CAST_REAL_INDEX_COLUMN = /^CAST\s*\(\s*"((?:[^"]|"")+)"\s+AS\s+REAL\s*\)(?:\s+(ASC|DESC))?$/i;
3166
3286
  function parseIndexColumnsFromSql(params) {
3167
- const { sql: sql2 } = params;
3168
- if (sql2 === null)
3287
+ const { sql } = params;
3288
+ if (sql === null)
3169
3289
  return null;
3170
- const onMatch = /\sON\s+"(?:[^"]|"")+"\s*\(/i.exec(sql2);
3290
+ const onMatch = /\sON\s+"(?:[^"]|"")+"\s*\(/i.exec(sql);
3171
3291
  if (onMatch === null)
3172
3292
  return null;
3173
3293
  const open = onMatch.index + onMatch[0].length - 1;
3174
3294
  let listDepth = 0;
3175
3295
  let close = -1;
3176
- for (let index = open;index < sql2.length; index++) {
3177
- const char = sql2[index];
3296
+ for (let index = open;index < sql.length; index++) {
3297
+ const char = sql[index];
3178
3298
  if (char === "(")
3179
3299
  listDepth += 1;
3180
3300
  else if (char === ")") {
@@ -3187,7 +3307,7 @@ function parseIndexColumnsFromSql(params) {
3187
3307
  }
3188
3308
  if (close === -1)
3189
3309
  return null;
3190
- const list = sql2.slice(open + 1, close);
3310
+ const list = sql.slice(open + 1, close);
3191
3311
  const terms = [];
3192
3312
  let depth = 0;
3193
3313
  let start = 0;
@@ -3328,7 +3448,7 @@ function q(name) {
3328
3448
  }
3329
3449
 
3330
3450
  // packages/migrate/src/execute.ts
3331
- import { VibeError as VibeError12 } from "@vibeorm/schema";
3451
+ import { VibeError as VibeError13 } from "@vibeorm/schema";
3332
3452
  var SELF_MANAGED_MARKER = "PRAGMA foreign_keys=OFF";
3333
3453
  var FK_CHECK_PREFIX = "PRAGMA foreign_key_check";
3334
3454
  function usesSelfManagedTransactions(params) {
@@ -3349,9 +3469,9 @@ function classifySelfManagedStatement(params) {
3349
3469
  return "plain";
3350
3470
  }
3351
3471
  function selfManagedResumeStart(params) {
3352
- const { sql: sql2, start } = params;
3472
+ const { sql, start } = params;
3353
3473
  for (let index = start - 1;index >= 0; index -= 1) {
3354
- const control = classifySelfManagedStatement({ statement: sql2[index] });
3474
+ const control = classifySelfManagedStatement({ statement: sql[index] });
3355
3475
  if (control === "endTransaction" || control === "abandon" || control === "fkOn")
3356
3476
  return start;
3357
3477
  if (control === "fkOff")
@@ -3369,7 +3489,7 @@ function assertSelfManagedResumeSafe(params) {
3369
3489
  const completedIndex = params.direction === "up" ? params.start + 1 : -(params.start + 2);
3370
3490
  const rewind = selfManagedResumeStart({ sql: params.sql, start: params.start });
3371
3491
  const retryIndex = params.direction === "up" ? rewind : -(rewind + 1);
3372
- throw new VibeError12({
3492
+ throw new VibeError13({
3373
3493
  code: "VIBE_MIGRATION",
3374
3494
  message: `migration "${params.migration}" has a legacy sqlite checkpoint at ${params.direction} COMMIT (statement ${params.start + 1}). The block may already have committed; replay is refused. Inspect the block's effects. If it committed, set its journal statement_index to ${completedIndex} and error to NULL to resume the remaining statements. Only if the entire block did not commit, set statement_index to ${retryIndex} and error to NULL to retry the block. Do not mark the whole migration applied unless all remaining statements also ran.`,
3375
3495
  meta: { reason: "uncertain-statement", migration: params.migration, statementIndex: params.start, direction: params.direction, dialect: "sqlite" }
@@ -3398,37 +3518,37 @@ function unsupportedScript(params) {
3398
3518
  const { migration, direction, index, problem, found } = params;
3399
3519
  const subject = direction === "down" ? `the down script of migration "${migration}"` : `migration "${migration}"`;
3400
3520
  const position = `${direction === "down" ? "down statement" : "statement"} ${index + 1} of ${params.statements}`;
3401
- return new VibeError12({
3521
+ return new VibeError13({
3402
3522
  code: "VIBE_MIGRATION",
3403
3523
  message: `${subject} manages its own sqlite transactions, and ${position} breaks the shape recovery depends on: ${found}. ` + `A table-rebuild block must be written exactly as \`${SUPPORTED_BLOCK_SHAPE}\`. ` + "Inside that block a crash rolls everything back, so a resume can replay it safely. " + "A statement that sits in a foreign-keys-off region with no transaction around it commits on its own, " + "and the resume would run it a second time with no error raised either time. " + "Nothing has been executed. Move the statement after `PRAGMA foreign_keys=ON`, where it commits together " + "with its own journal checkpoint, or give it its own `BEGIN;` and `COMMIT;`. " + 'See "Self-managed sqlite scripts" in docs/migrations.md.',
3404
3524
  meta: { reason: "unsupported-self-managed-script", problem, migration, statementIndex: index, direction }
3405
3525
  });
3406
3526
  }
3407
3527
  function assertSupportedSelfManagedScript(params) {
3408
- const { sql: sql2, migration, direction } = params;
3409
- const statements = sql2.length;
3528
+ const { sql, migration, direction } = params;
3529
+ const statements = sql.length;
3410
3530
  const refuse = (index, problem, found) => unsupportedScript({ migration, direction, index, statements, problem, found });
3411
- let state2 = "outside";
3531
+ let state = "outside";
3412
3532
  let openedAt = -1;
3413
3533
  for (let index = 0;index < statements; index += 1) {
3414
- const control = classifySelfManagedStatement({ statement: sql2[index] });
3415
- if (state2 === "fkOff") {
3534
+ const control = classifySelfManagedStatement({ statement: sql[index] });
3535
+ if (state === "fkOff") {
3416
3536
  if (control !== "begin") {
3417
3537
  throw refuse(index, "fk-off-without-transaction", "`PRAGMA foreign_keys=OFF` is not followed by `BEGIN;`");
3418
3538
  }
3419
- state2 = "inBlock";
3539
+ state = "inBlock";
3420
3540
  continue;
3421
3541
  }
3422
- if (state2 === "committed") {
3542
+ if (state === "committed") {
3423
3543
  if (control !== "fkOn") {
3424
3544
  throw refuse(index, "commit-without-restore", "`COMMIT;` is not followed by `PRAGMA foreign_keys=ON;`");
3425
3545
  }
3426
- state2 = "outside";
3546
+ state = "outside";
3427
3547
  continue;
3428
3548
  }
3429
- if (state2 === "inBlock") {
3549
+ if (state === "inBlock") {
3430
3550
  if (control === "endTransaction") {
3431
- state2 = "committed";
3551
+ state = "committed";
3432
3552
  continue;
3433
3553
  }
3434
3554
  if (control === "plain")
@@ -3436,7 +3556,7 @@ function assertSupportedSelfManagedScript(params) {
3436
3556
  throw refuse(index, "unsupported-control-in-block", "transaction or pragma control appears inside an open rebuild block");
3437
3557
  }
3438
3558
  if (control === "fkOff") {
3439
- state2 = "fkOff";
3559
+ state = "fkOff";
3440
3560
  openedAt = index;
3441
3561
  continue;
3442
3562
  }
@@ -3444,8 +3564,8 @@ function assertSupportedSelfManagedScript(params) {
3444
3564
  throw refuse(index, "transaction-control-outside-block", "transaction control appears outside any rebuild block");
3445
3565
  }
3446
3566
  }
3447
- if (state2 !== "outside") {
3448
- throw refuse(openedAt, state2 === "committed" ? "commit-without-restore" : "unclosed-block", state2 === "committed" ? "the block commits but never restores foreign keys with `PRAGMA foreign_keys=ON;`" : "`PRAGMA foreign_keys=OFF` is never closed by `COMMIT;` and `PRAGMA foreign_keys=ON;`");
3567
+ if (state !== "outside") {
3568
+ throw refuse(openedAt, state === "committed" ? "commit-without-restore" : "unclosed-block", state === "committed" ? "the block commits but never restores foreign keys with `PRAGMA foreign_keys=ON;`" : "`PRAGMA foreign_keys=OFF` is never closed by `COMMIT;` and `PRAGMA foreign_keys=ON;`");
3449
3569
  }
3450
3570
  }
3451
3571
  async function executeStatement(params) {
@@ -3454,7 +3574,7 @@ async function executeStatement(params) {
3454
3574
  const rows = await executor({ text: statement, values: [] });
3455
3575
  if (rows.length > 0) {
3456
3576
  const sample = rows.slice(0, 5).map((row) => `${String(row.table)} rowid ${String(row.rowid)} \u2192 ${String(row.parent)}`).join("; ");
3457
- throw new VibeError12({
3577
+ throw new VibeError13({
3458
3578
  code: "VIBE_MIGRATION",
3459
3579
  message: `foreign key check failed after table rebuild: ${rows.length} violation(s) \u2014 ${sample}`,
3460
3580
  meta: { violations: rows }
@@ -3474,8 +3594,8 @@ async function cleanupSelfManagedFailure(params) {
3474
3594
  }
3475
3595
 
3476
3596
  // packages/migrate/src/postgres-default-equivalence.ts
3477
- import { VibeError as VibeError13 } from "@vibeorm/schema";
3478
- import { postgresDialect as postgresDialect6, renderPostgresDefaultFunctionIdentity } from "@vibeorm/sql";
3597
+ import { VibeError as VibeError14 } from "@vibeorm/schema";
3598
+ import { postgresDialect as postgresDialect7, renderPostgresDefaultFunctionIdentity } from "@vibeorm/sql";
3479
3599
  var IDENTIFIER = '(?:"(?:[^"\\u0000]|"")+"|[A-Za-z_][A-Za-z_0-9$]*)';
3480
3600
  var CALL = new RegExp(`^\\s*(${IDENTIFIER})(?:\\s*\\.\\s*(${IDENTIFIER}))?\\s*\\(\\s*\\)\\s*$`);
3481
3601
  function parseCall(params) {
@@ -3491,9 +3611,9 @@ async function equivalentPostgresDefaultFunction(params) {
3491
3611
  const observed = parseCall({ expression: params.actual });
3492
3612
  if (expected?.namespace === undefined || observed === undefined)
3493
3613
  return false;
3494
- const query = renderPostgresDefaultFunctionIdentity({ dialect: postgresDialect6, table: params.table, column: params.column });
3614
+ const query = renderPostgresDefaultFunctionIdentity({ dialect: postgresDialect7, table: params.table, column: params.column });
3495
3615
  const rows = await params.executor({ text: query.text, values: [...query.values] }).catch((cause) => {
3496
- throw new VibeError13({ code: "VIBE_MIGRATION", message: "Cannot inspect the stored default function identity", meta: { reason: "default-inspection-unavailable", table: params.table, column: params.column }, cause });
3616
+ throw new VibeError14({ code: "VIBE_MIGRATION", message: "Cannot inspect the stored default function identity", meta: { reason: "default-inspection-unavailable", table: params.table, column: params.column }, cause });
3497
3617
  });
3498
3618
  if (rows.length !== 1)
3499
3619
  return false;
@@ -3545,9 +3665,17 @@ async function inspectSqlObject(params) {
3545
3665
  } else {
3546
3666
  const constraintType = params.identity.constraintType;
3547
3667
  const constraint = sqliteTableConstraints2({ sql: String(facts.definition ?? "") }).find((entry) => entry.name === name && entry.type === constraintType);
3548
- if (constraint === undefined)
3549
- return { state: "unavailable", reason: "constraint-definition-inspection-unavailable" };
3550
- facts = { type: constraint.type, definition: constraint.sql };
3668
+ if (constraint === undefined && constraintType === "primaryKey" && name === `${params.identity.table.name}_pkey`) {
3669
+ const query = renderSqliteColumnInventory({ dialect: getSqlDialect({ dialect: "sqlite" }), namespace: params.identity.table.namespace, table: params.identity.table.name });
3670
+ const columns = (await params.executor({ text: query.text, values: [...query.values] })).filter((column) => Number(column.pk) > 0).sort((a, b) => Number(a.pk) - Number(b.pk));
3671
+ if (columns.length === 0)
3672
+ return { state: "missing" };
3673
+ facts = { type: "primaryKey", columns: columns.map((column) => String(column.name)) };
3674
+ } else {
3675
+ if (constraint === undefined)
3676
+ return { state: "unavailable", reason: "constraint-definition-inspection-unavailable" };
3677
+ facts = { type: constraint.type, definition: constraint.sql };
3678
+ }
3551
3679
  }
3552
3680
  }
3553
3681
  if (params.dialect === "sqlite" && (params.identity.kind === "column" || params.identity.kind === "columnDefault" || params.identity.kind === "generatedColumn")) {
@@ -3561,34 +3689,84 @@ async function inspectSqlObject(params) {
3561
3689
  if (params.identity.kind === "columnDefault")
3562
3690
  facts = { definition: facts.definition ?? null };
3563
3691
  if (params.dialect === "postgres") {
3564
- const query2 = renderMigrationDependencies({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3565
- const rows2 = await params.executor({ text: query2.text, values: [...query2.values] });
3566
- if (rows2.some((row) => typeof row.address !== "string"))
3567
- return { state: "unavailable", reason: "dependency-inspection-unavailable" };
3568
- facts = { ...facts, dependencyAddresses: rows2.map((row) => String(row.address)).sort() };
3692
+ const query = renderMigrationDependencies({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3693
+ const rows = await params.executor({ text: query.text, values: [...query.values] });
3694
+ return postgresInspection({ identity: params.identity, facts, addresses: rows.map((row) => row.address) });
3569
3695
  }
3570
3696
  if (params.dialect === "mysql") {
3571
- const query2 = renderMysqlObjectMembers({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3572
- if (query2 !== undefined) {
3573
- const rows2 = await params.executor({ text: query2.text, values: [...query2.values] });
3574
- if (params.identity.kind === "function" && rows2.length === 0)
3697
+ const query = renderMysqlObjectMembers({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3698
+ if (query !== undefined) {
3699
+ const rows = await params.executor({ text: query.text, values: [...query.values] });
3700
+ if (params.identity.kind === "function" && rows.length === 0)
3575
3701
  return { state: "unavailable", reason: "function-signature-unavailable" };
3576
3702
  if (params.identity.kind === "function") {
3577
- const signature = rows2.filter((row) => row.mode !== null).map((row) => ({ namespace: "mysql", name: String(row.type) }));
3703
+ const signature = rows.filter((row) => row.mode !== null).map((row) => ({ namespace: "mysql", name: String(row.type) }));
3578
3704
  if (canonicalMigrationJson({ value: signature }) !== canonicalMigrationJson({ value: params.identity.argumentTypes }))
3579
3705
  return { state: "missing" };
3580
3706
  }
3581
- facts = { ...facts, members: rows2.map((row) => canonicalMigrationJson({ value: row })) };
3707
+ facts = { ...facts, members: rows.map((row) => canonicalMigrationJson({ value: row })) };
3582
3708
  }
3583
3709
  }
3584
- const dependencies = [];
3585
- if (params.identity.kind === "trigger" && params.dialect === "postgres") {
3586
- if (facts.functionArguments !== "")
3587
- return { state: "unavailable", reason: "trigger-function-signature-unavailable" };
3588
- dependencies.push({ kind: "function", name: { namespace: String(facts.functionNamespace), name: String(facts.functionName) }, argumentTypes: [] });
3710
+ return { state: "present", definition: { identity: params.identity, facts, dependencies: [], format: "catalog-v2" } };
3711
+ }).catch((error) => ({ state: "unavailable", reason: error instanceof VibeError15 ? String(error.meta.feature ?? error.code) : "catalog-query-failed" }));
3712
+ }
3713
+ function postgresInspection(params) {
3714
+ if (!params.addresses.every((address) => typeof address === "string"))
3715
+ return { state: "unavailable", reason: "dependency-inspection-unavailable" };
3716
+ const facts = { ...params.identity.kind === "columnDefault" ? { definition: params.facts.definition ?? null } : params.facts, dependencyAddresses: [...params.addresses].sort() };
3717
+ const dependencies = [];
3718
+ if (params.identity.kind === "trigger") {
3719
+ if (params.facts.functionArguments !== "")
3720
+ return { state: "unavailable", reason: "trigger-function-signature-unavailable" };
3721
+ dependencies.push({ kind: "function", name: { namespace: String(params.facts.functionNamespace), name: String(params.facts.functionName) }, argumentTypes: [] });
3722
+ }
3723
+ return { state: "present", definition: { identity: params.identity, facts, dependencies, format: "catalog-v2" } };
3724
+ }
3725
+ function unavailableReason(params) {
3726
+ return params.error instanceof VibeError15 ? String(params.error.meta.feature ?? params.error.meta.reason ?? params.error.code) : "catalog-query-failed";
3727
+ }
3728
+ async function readBatch(params) {
3729
+ const positions = new Set(params.batch.positions);
3730
+ return Promise.resolve().then(async () => {
3731
+ const rows = new Map;
3732
+ for (const row of await params.executor({ text: params.batch.text, values: [...params.batch.values] })) {
3733
+ if (typeof row.position !== "number" || !Number.isInteger(row.position) || !positions.has(row.position))
3734
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Invalid batched catalog identity", meta: { reason: "catalog-query-failed" } });
3735
+ const matches = rows.get(row.position) ?? [];
3736
+ matches.push(row);
3737
+ rows.set(row.position, matches);
3738
+ }
3739
+ return { ok: true, rows };
3740
+ }).then((outcome) => outcome, (error) => ({ ok: false, reason: unavailableReason({ error }) }));
3741
+ }
3742
+ function batchedInspection(params) {
3743
+ if (params.matches.length === 0)
3744
+ return { state: "missing" };
3745
+ if (params.matches.length !== 1)
3746
+ return { state: "unavailable", reason: "ambiguous-catalog-identity" };
3747
+ const row = params.matches[0];
3748
+ const facts = row.facts !== null && typeof row.facts === "object" && !Array.isArray(row.facts) ? factsOf({ row: row.facts }) : undefined;
3749
+ if (facts === undefined || !Array.isArray(row.dependencyAddresses))
3750
+ return { state: "unavailable", reason: "unsupported-catalog-value" };
3751
+ return postgresInspection({ identity: params.identity, facts, addresses: row.dependencyAddresses });
3752
+ }
3753
+ async function inspectSqlObjects(params) {
3754
+ if (params.dialect !== "postgres") {
3755
+ const results = [];
3756
+ for (const identity of params.identities)
3757
+ results.push(await inspectSqlObject({ ...params, identity }));
3758
+ return results;
3759
+ }
3760
+ return Promise.resolve().then(async () => {
3761
+ const results = params.identities.map(() => ({ state: "unavailable", reason: "catalog-query-failed" }));
3762
+ for (const batch of renderMigrationObjectBatch({ dialect: getSqlDialect({ dialect: params.dialect }), identities: params.identities })) {
3763
+ const outcome = await readBatch({ executor: params.executor, batch });
3764
+ for (const position of batch.positions) {
3765
+ results[position] = outcome.ok ? batchedInspection({ identity: params.identities[position], matches: outcome.rows.get(position) ?? [] }) : { state: "unavailable", reason: outcome.reason };
3766
+ }
3589
3767
  }
3590
- return { state: "present", definition: { identity: params.identity, facts, dependencies, format: "catalog-v1" } };
3591
- }).catch((error) => ({ state: "unavailable", reason: error instanceof VibeError14 ? String(error.meta.feature ?? error.code) : "catalog-query-failed" }));
3768
+ return results;
3769
+ }).then((result) => result, (error) => params.identities.map(() => ({ state: "unavailable", reason: unavailableReason({ error }) })));
3592
3770
  }
3593
3771
  async function assertCatalogVisibility(params) {
3594
3772
  if (params.dialect !== "mysql")
@@ -3598,15 +3776,23 @@ async function assertCatalogVisibility(params) {
3598
3776
  const grants = new Set(rows.map((row) => row.privilege));
3599
3777
  const missing = ["SELECT", "TRIGGER", "SHOW VIEW", "EXECUTE"].filter((privilege) => !grants.has(privilege));
3600
3778
  if (missing.length > 0)
3601
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "MySQL catalog visibility requires direct database-wide grants; role-only or partial grants cannot prove object absence", meta: { reason: "inventory-unavailable", missing } });
3779
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "MySQL catalog visibility requires direct database-wide grants; role-only or partial grants cannot prove object absence", meta: { reason: "inventory-unavailable", missing } });
3602
3780
  }
3781
+ var CATALOG_V1_OMITTED_FACTS = Object.freeze({
3782
+ function: ["definerOwner"],
3783
+ column: ["collationNamespace", "collationName"],
3784
+ generatedColumn: ["collationNamespace", "collationName"]
3785
+ });
3603
3786
  function compare(params) {
3604
3787
  const differences = [];
3788
+ const omitted = params.expected.format === "catalog-v1" ? CATALOG_V1_OMITTED_FACTS[params.expected.identity.kind] ?? [] : [];
3605
3789
  for (const key of new Set([...Object.keys(params.expected.facts), ...Object.keys(params.live.facts)])) {
3606
- const expected2 = params.expected.facts[key];
3607
- const actual2 = params.live.facts[key];
3608
- if (expected2 === undefined !== (actual2 === undefined) || canonicalMigrationJson({ value: expected2 }) !== canonicalMigrationJson({ value: actual2 }))
3609
- differences.push({ attribute: key, expected: expected2, actual: actual2 });
3790
+ if (omitted.includes(key) && !Object.hasOwn(params.expected.facts, key))
3791
+ continue;
3792
+ const expected = params.expected.facts[key];
3793
+ const actual = params.live.facts[key];
3794
+ if (expected === undefined !== (actual === undefined) || canonicalMigrationJson({ value: expected }) !== canonicalMigrationJson({ value: actual }))
3795
+ differences.push({ attribute: key, expected, actual });
3610
3796
  }
3611
3797
  const expected = params.expected.dependencies.map((identity) => sqlObjectKey4({ identity })).sort();
3612
3798
  const actual = params.live.dependencies.map((identity) => sqlObjectKey4({ identity })).sort();
@@ -3616,7 +3802,7 @@ function compare(params) {
3616
3802
  }
3617
3803
  function assertProbeMode(params) {
3618
3804
  if (params.probe !== undefined && params.probe !== "none" && DIALECT_CAPABILITIES2[params.dialect].checkNormalization !== params.probe)
3619
- throw new VibeError14({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `${params.probe} CHECK probes are unavailable on ${params.dialect}`, meta: { feature: "checkProbe", dialect: params.dialect } });
3805
+ throw new VibeError15({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `${params.probe} CHECK probes are unavailable on ${params.dialect}`, meta: { feature: "checkProbe", dialect: params.dialect } });
3620
3806
  }
3621
3807
  async function verifyMigrationState(params) {
3622
3808
  return verifyState(params);
@@ -3630,10 +3816,13 @@ async function verifyState(params) {
3630
3816
  for (const object of declarations)
3631
3817
  identities.set(sqlObjectKey4({ identity: object.identity }), object.identity);
3632
3818
  const objects = [];
3819
+ const inspections = params.batch === true ? await inspectSqlObjects({ ...params, identities: [...identities.values()] }) : undefined;
3820
+ let position = 0;
3633
3821
  for (const [key, identity] of identities) {
3634
3822
  const ownership = owned.has(key) ? "migration" : "schema";
3635
3823
  const expected = definitions.get(key);
3636
- const live = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3824
+ const live = inspections === undefined ? await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity }) : inspections[position];
3825
+ position++;
3637
3826
  if (live.state !== "present") {
3638
3827
  objects.push({ identity, ownership, state: live.state, differences: [], ...live.state === "unavailable" ? { reason: live.reason } : {} });
3639
3828
  } else if (expected === undefined) {
@@ -3653,9 +3842,10 @@ async function verifyState(params) {
3653
3842
  }
3654
3843
  async function verifySchemaObjects(params) {
3655
3844
  const physical = params.dialect === "postgres" ? await introspectPhysicalPostgres({ executor: params.executor }) : params.dialect === "mysql" ? await introspectMysql({ executor: params.executor }) : params.sqliteRestorePending === true ? await introspectSqliteBeforeForeignKeyRestore({ executor: params.executor }) : await introspectSqlite({ executor: params.executor });
3656
- const expected = normalizeSchema({ schema: params.expected.schema, dialect: params.dialect });
3845
+ const resolved = params.dialect === "postgres" ? await resolvePostgresTypeIdentities({ executor: params.executor, schema: params.expected.schema, mode: "verify" }) : { schema: params.expected.schema, unavailable: [] };
3846
+ const expected = normalizeSchema({ schema: resolved.schema, dialect: params.dialect });
3657
3847
  const actual = normalizeSchema({ schema: physical, dialect: params.dialect });
3658
- const objects = [];
3848
+ const objects = resolved.unavailable.map((identity) => ({ identity, ownership: "schema", state: "unavailable", reason: "type-reference-required", differences: [] }));
3659
3849
  const namespace = await migrationNamespace({ executor: params.executor, dialect: params.dialect });
3660
3850
  const sqliteTableOptions = params.dialect === "sqlite" && expected.tables.size > 0 ? await params.executor({ text: "PRAGMA main.table_list;", values: [] }) : undefined;
3661
3851
  if (params.dialect === "postgres")
@@ -3690,9 +3880,9 @@ async function verifySchemaObjects(params) {
3690
3880
  }
3691
3881
  }
3692
3882
  const differences = [];
3693
- const pin = (attribute, expected2, actual2) => {
3694
- if (canonicalMigrationJson({ value: expected2 }) !== canonicalMigrationJson({ value: actual2 }))
3695
- differences.push({ attribute, expected: expected2, actual: actual2 });
3883
+ const pin = (attribute, expected, actual) => {
3884
+ if (canonicalMigrationJson({ value: expected }) !== canonicalMigrationJson({ value: actual }))
3885
+ differences.push({ attribute, expected, actual });
3696
3886
  };
3697
3887
  pin("primaryKey", desired.pk, live.pk);
3698
3888
  for (const [column, field] of desired.columns) {
@@ -3722,8 +3912,8 @@ async function verifySchemaObjects(params) {
3722
3912
  if (inspection.state !== "present") {
3723
3913
  objects.push({ identity, ownership: "schema", state: inspection.state, differences: [], ...inspection.state === "unavailable" ? { reason: inspection.reason } : {} });
3724
3914
  } else {
3725
- const differences2 = ["validated", "triggersEnabled"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3726
- objects.push({ identity, ownership: "schema", state: differences2.length === 0 ? "matching" : "changed", differences: differences2 });
3915
+ const differences = ["validated", "triggersEnabled"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3916
+ objects.push({ identity, ownership: "schema", state: differences.length === 0 ? "matching" : "changed", differences });
3727
3917
  }
3728
3918
  }
3729
3919
  }
@@ -3738,8 +3928,8 @@ async function verifySchemaObjects(params) {
3738
3928
  if (inspection.state !== "present") {
3739
3929
  objects.push({ identity, ownership: "schema", state: inspection.state, differences: [], ...inspection.state === "unavailable" ? { reason: inspection.reason } : {} });
3740
3930
  } else {
3741
- const differences2 = ["valid", "ready"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3742
- objects.push({ identity, ownership: "schema", state: differences2.length === 0 ? "matching" : "changed", differences: differences2 });
3931
+ const differences = ["valid", "ready"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3932
+ objects.push({ identity, ownership: "schema", state: differences.length === 0 ? "matching" : "changed", differences });
3743
3933
  }
3744
3934
  }
3745
3935
  objects.push({ identity: { kind: "table", name: table }, ownership: "schema", state: differences.length === 0 ? "matching" : "changed", differences });
@@ -3771,14 +3961,14 @@ async function verifySchemaObjects(params) {
3771
3961
  if (params.dialect === "postgres" && params.probe === "rollback") {
3772
3962
  const normalized = await deparsePostgresCheck({ executor: params.executor, table, expression, probe: "rollback" });
3773
3963
  const read = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3774
- const actual2 = read.state === "present" ? read.definition.facts.definition : undefined;
3775
- objects.push({ identity, ownership: "schema", state: normalized === actual2 ? "matching" : "changed", differences: normalized === actual2 ? [] : [{ attribute: "definition", expected: normalized, actual: actual2 }] });
3964
+ const actual = read.state === "present" ? read.definition.facts.definition : undefined;
3965
+ objects.push({ identity, ownership: "schema", state: normalized === actual ? "matching" : "changed", differences: normalized === actual ? [] : [{ attribute: "definition", expected: normalized, actual }] });
3776
3966
  } else if (params.dialect === "mysql" && params.probe === "temporary") {
3777
3967
  const normalized = await deparseMysqlCheck({ executor: params.executor, table, expression, probe: "temporary" });
3778
3968
  const inspection = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3779
- const actual2 = inspection.state === "present" ? inspection.definition.facts.definition : undefined;
3780
- const match = normalized === actual2;
3781
- objects.push({ identity, ownership: "schema", state: inspection.state === "unavailable" ? "unavailable" : match ? "matching" : "changed", differences: match ? [] : [{ attribute: "definition", expected: normalized, actual: actual2 }] });
3969
+ const actual = inspection.state === "present" ? inspection.definition.facts.definition : undefined;
3970
+ const match = normalized === actual;
3971
+ objects.push({ identity, ownership: "schema", state: inspection.state === "unavailable" ? "unavailable" : match ? "matching" : "changed", differences: match ? [] : [{ attribute: "definition", expected: normalized, actual }] });
3782
3972
  } else
3783
3973
  objects.push({ identity, ownership: "schema", state: "unavailable", reason: "explicit-replacement-required", differences: [{ attribute: "definition", expected: expression, actual: stored }] });
3784
3974
  }
@@ -3800,14 +3990,14 @@ async function verifyMigrationTransition(params) {
3800
3990
  }
3801
3991
  async function verifySqliteTransitionBeforeRestore(params) {
3802
3992
  if (params.dialect !== "sqlite")
3803
- throw new VibeError14({ code: "VIBE_INTERNAL", message: "SQLite rebuild verification requires the SQLite dialect" });
3993
+ throw new VibeError15({ code: "VIBE_INTERNAL", message: "SQLite rebuild verification requires the SQLite dialect" });
3804
3994
  await executeStatement({ executor: params.executor, dialect: "sqlite", statement: "PRAGMA foreign_key_check;" });
3805
3995
  return verifyTransition({ ...params, sqliteRestorePending: true });
3806
3996
  }
3807
3997
  async function verifyTransition(params) {
3808
3998
  const report = await verifyState({ executor: params.executor, dialect: params.dialect, expected: params.to, ...params.sqliteRestorePending === true ? { sqliteRestorePending: true } : {}, ...params.probe === undefined ? {} : { probe: params.probe } });
3809
3999
  const namespace = await migrationNamespace(params);
3810
- const identities = (state2) => [...schemaObjectIdentities({ schema: state2.schema, dialect: params.dialect, namespace }), ...(state2.schema.migrationObjects ?? []).map((object) => object.identity), ...state2.definitions.map((definition) => definition.identity)];
4000
+ const identities = (state) => [...schemaObjectIdentities({ schema: state.schema, dialect: params.dialect, namespace }), ...(state.schema.migrationObjects ?? []).map((object) => object.identity), ...state.definitions.map((definition) => definition.identity)];
3811
4001
  const retained = new Set(identities(params.to).map((identity) => sqlObjectKey4({ identity })));
3812
4002
  const removed = new Map([...identities(params.from).filter((identity) => !retained.has(sqlObjectKey4({ identity }))), ...params.removals ?? []].map((identity) => [sqlObjectKey4({ identity }), identity]));
3813
4003
  const objects = [...report.objects];
@@ -3826,12 +4016,12 @@ async function migrationNamespace(params) {
3826
4016
  const rows = await params.executor({ text: query.text, values: [] });
3827
4017
  const namespace = rows[0]?.namespace;
3828
4018
  if (typeof namespace !== "string" || namespace.length === 0)
3829
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Cannot determine the migration namespace", meta: { reason: "inspection-unavailable" } });
4019
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Cannot determine the migration namespace", meta: { reason: "inspection-unavailable" } });
3830
4020
  return namespace;
3831
4021
  }
3832
4022
  function assertMigrationState(params) {
3833
4023
  if (!params.report.inSync)
3834
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Migration state could not be verified", meta: { reason: "migration-state-unverified", objects: params.report.objects.filter((object) => object.state !== "matching") } });
4024
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Migration state could not be verified", meta: { reason: "migration-state-unverified", shadowReusable: true, objects: params.report.objects.filter((object) => object.state !== "matching") } });
3835
4025
  }
3836
4026
  async function deparsePostgresCheck(params) {
3837
4027
  const definition = await deparsePostgresCheckDefinition({ ...params, constraint: "vibeorm_check_probe" });
@@ -3845,7 +4035,7 @@ async function deparsePostgresCheckDefinition(params) {
3845
4035
  await params.executor({ text: query.text });
3846
4036
  const result = await inspectSqlObject({ executor: params.executor, dialect: "postgres", identity: { kind: "constraint", constraintType: "check", table: params.table, name } });
3847
4037
  if (result.state !== "present" || typeof result.definition.facts.definition !== "string")
3848
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "CHECK normalization probe unavailable", meta: { reason: "check-inspection-unavailable" } });
4038
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "CHECK normalization probe unavailable", meta: { reason: "check-inspection-unavailable" } });
3849
4039
  return { ...result.definition, identity: { kind: "constraint", constraintType: "check", table: params.table, name: params.constraint }, facts: { ...result.definition.facts, definition: result.definition.facts.definition.replace(/ NOT VALID$/, ""), validated: true } };
3850
4040
  } finally {
3851
4041
  await params.executor({ text: "ROLLBACK TO SAVEPOINT vibeorm_check_probe" });
@@ -3863,7 +4053,7 @@ async function deparseMysqlCheck(params) {
3863
4053
  const source = await params.executor({ text: read.text, values: [] });
3864
4054
  const definition = source[0]?.["Create Table"];
3865
4055
  if (typeof definition !== "string")
3866
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Cannot read temporary clone definition" });
4056
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Cannot read temporary clone definition" });
3867
4057
  const drop = renderMysqlCheckProbe({ dialect, probe, operation: "drop" });
3868
4058
  await params.executor({ text: drop.text });
3869
4059
  created = false;
@@ -3874,7 +4064,7 @@ async function deparseMysqlCheck(params) {
3874
4064
  const normalizedDefinition = rows[0]?.["Create Table"];
3875
4065
  const check = typeof normalizedDefinition === "string" ? parseSqliteNamedChecks({ tableSql: normalizedDefinition }).find((entry) => entry.name === probe) : undefined;
3876
4066
  if (check === undefined)
3877
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "MySQL temporary CHECK deparse unavailable", meta: { reason: "check-inspection-unavailable" } });
4067
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "MySQL temporary CHECK deparse unavailable", meta: { reason: "check-inspection-unavailable" } });
3878
4068
  return check.expression;
3879
4069
  } finally {
3880
4070
  if (created) {
@@ -3901,7 +4091,7 @@ async function prepareCheckDiff(params) {
3901
4091
  const desired = await deparsePostgresCheck({ executor: params.executor, table: identity.table, expression: next.expression, probe: "rollback" });
3902
4092
  const live = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3903
4093
  if (live.state !== "present")
3904
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
4094
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
3905
4095
  if (live.definition.facts.definition === desired) {
3906
4096
  checks.push(next);
3907
4097
  continue;
@@ -3913,7 +4103,7 @@ async function prepareCheckDiff(params) {
3913
4103
  const desired = await deparseMysqlCheck({ executor: params.executor, table: identity.table, expression: next.expression, probe: "temporary" });
3914
4104
  const live = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3915
4105
  if (live.state !== "present")
3916
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
4106
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
3917
4107
  checks.push(desired === live.definition.facts.definition ? next : { name: check.name, expression: check.expression });
3918
4108
  continue;
3919
4109
  }
@@ -3926,7 +4116,7 @@ async function prepareCheckDiff(params) {
3926
4116
  checks.push({ name: check.name, expression: check.expression });
3927
4117
  continue;
3928
4118
  }
3929
- throw new VibeError14({ code: "VIBE_MIGRATION", message: `Cannot establish CHECK equivalence for ${table}.${check.name}; request a rollback probe or an explicit replacement`, meta: { reason: "explicit-replacement-required", identity } });
4119
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: `Cannot establish CHECK equivalence for ${table}.${check.name}; request a rollback probe or an explicit replacement`, meta: { reason: "explicit-replacement-required", identity } });
3930
4120
  }
3931
4121
  models.push({ ...model, checks });
3932
4122
  }
@@ -3953,7 +4143,7 @@ async function inspectMigrationInventory(params) {
3953
4143
  for (const row of rows) {
3954
4144
  const name = row.name;
3955
4145
  if (typeof name !== "string" || typeof row.kind !== "string")
3956
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "Malformed catalog identity", meta: { reason: "inventory-unavailable" } });
4146
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "Malformed catalog identity", meta: { reason: "inventory-unavailable" } });
3957
4147
  const qualified = { namespace: params.namespace, name };
3958
4148
  const table = { namespace: params.namespace, name: String(row.parent ?? "") };
3959
4149
  let identity;
@@ -3975,27 +4165,27 @@ async function inspectMigrationInventory(params) {
3975
4165
  case "constraint": {
3976
4166
  const constraintType = kinds[String(row.subtype)];
3977
4167
  if (constraintType === undefined)
3978
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "Unknown constraint catalog kind", meta: { reason: "inventory-unavailable" } });
4168
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "Unknown constraint catalog kind", meta: { reason: "inventory-unavailable" } });
3979
4169
  identity = { kind: "constraint", table, name, constraintType };
3980
4170
  break;
3981
4171
  }
3982
4172
  case "function": {
3983
4173
  let argumentTypes = JSON.parse(String(row.signature));
3984
4174
  if (params.dialect === "mysql") {
3985
- const query2 = renderMysqlObjectMembers2({ dialect: getSqlDialect2({ dialect: params.dialect }), identity: { kind: "function", name: qualified, argumentTypes: [] } });
3986
- const members = await params.executor({ text: query2.text, values: [...query2.values] });
4175
+ const query = renderMysqlObjectMembers2({ dialect: getSqlDialect2({ dialect: params.dialect }), identity: { kind: "function", name: qualified, argumentTypes: [] } });
4176
+ const members = await params.executor({ text: query.text, values: [...query.values] });
3987
4177
  if (members.length === 0)
3988
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "MySQL function signature unavailable", meta: { reason: "inventory-unavailable", name } });
4178
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "MySQL function signature unavailable", meta: { reason: "inventory-unavailable", name } });
3989
4179
  argumentTypes = members.filter((member) => member.mode !== null).map((member) => ({ namespace: "mysql", name: String(member.type) }));
3990
4180
  }
3991
4181
  const candidate = { kind: "function", name: qualified, argumentTypes };
3992
4182
  if (!isSqlObjectIdentity2(candidate))
3993
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "Invalid function signature in catalog", meta: { reason: "inventory-unavailable" } });
4183
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "Invalid function signature in catalog", meta: { reason: "inventory-unavailable" } });
3994
4184
  identity = candidate;
3995
4185
  break;
3996
4186
  }
3997
4187
  default:
3998
- throw new VibeError15({ code: "VIBE_MIGRATION", message: `Unknown catalog object kind ${row.kind}`, meta: { reason: "inventory-unavailable" } });
4188
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: `Unknown catalog object kind ${row.kind}`, meta: { reason: "inventory-unavailable" } });
3999
4189
  }
4000
4190
  objects.push({ identity, ...typeof row.backing === "string" ? { backingConstraint: row.backing } : {} });
4001
4191
  if (params.dialect === "sqlite" && row.kind === "table" && typeof row.definition === "string" && !/^\s*CREATE\s+VIRTUAL\s+TABLE\b/i.test(row.definition)) {
@@ -4003,18 +4193,18 @@ async function inspectMigrationInventory(params) {
4003
4193
  for (const constraint of clauses) {
4004
4194
  if (constraint.type === "check")
4005
4195
  continue;
4006
- const name2 = constraint.named ? constraint.name : constraint.type === "primaryKey" ? `${qualified.name}_pkey` : constraint.type === "foreignKey" ? `${qualified.name}_${constraint.columns.join("_")}_fkey` : constraint.name;
4007
- objects.push({ identity: { kind: "constraint", constraintType: constraint.type, table: qualified, name: name2 }, ...constraint.type === "unique" && !constraint.named ? { inspectionUnavailable: "sqlite-anonymous-unique-constraint" } : {} });
4196
+ const name = constraint.named ? constraint.name : constraint.type === "primaryKey" ? defaultPrimaryKeyName2({ table: qualified.name, dialect: "sqlite" }) : constraint.type === "foreignKey" ? defaultForeignKeyName2({ table: qualified.name, columns: constraint.columns, dialect: "sqlite" }) : constraint.name;
4197
+ objects.push({ identity: { kind: "constraint", constraintType: constraint.type, table: qualified, name }, ...constraint.type === "unique" && !constraint.named ? { inspectionUnavailable: "sqlite-anonymous-unique-constraint" } : {} });
4008
4198
  }
4009
4199
  const checks = parseSqliteNamedChecks({ tableSql: row.definition });
4010
4200
  for (const check of checks)
4011
4201
  objects.push({ identity: { kind: "constraint", constraintType: "check", table: qualified, name: check.name } });
4012
4202
  if ([...row.definition.matchAll(/\bCHECK\s*\(/gi)].length > checks.length)
4013
4203
  objects.push({ identity: { kind: "table", name: qualified }, inspectionUnavailable: "sqlite-unnamed-check-definition-unavailable" });
4014
- const query2 = renderSqliteColumnInventory({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4015
- const columns = await params.executor({ text: query2.text, values: [...query2.values] });
4204
+ const query = renderSqliteColumnInventory2({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4205
+ const columns = await params.executor({ text: query.text, values: [...query.values] });
4016
4206
  if (columns.some((column) => Number(column.pk) > 0) && !clauses.some((clause) => clause.type === "primaryKey"))
4017
- objects.push({ identity: { kind: "constraint", constraintType: "primaryKey", table: qualified, name: `${qualified.name}_pkey` } });
4207
+ objects.push({ identity: { kind: "constraint", constraintType: "primaryKey", table: qualified, name: defaultPrimaryKeyName2({ table: qualified.name, dialect: "sqlite" }) } });
4018
4208
  const fkQuery = renderSqliteForeignKeyInventory({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4019
4209
  const foreignKeys = await params.executor({ text: fkQuery.text, values: [...fkQuery.values] });
4020
4210
  const groups = new Map;
@@ -4023,7 +4213,7 @@ async function inspectMigrationInventory(params) {
4023
4213
  for (const fields of groups.values()) {
4024
4214
  if (clauses.some((clause) => clause.type === "foreignKey" && JSON.stringify(clause.columns) === JSON.stringify(fields)))
4025
4215
  continue;
4026
- objects.push({ identity: { kind: "constraint", constraintType: "foreignKey", table: qualified, name: `${qualified.name}_${fields.join("_")}_fkey` }, inspectionUnavailable: "sqlite-inline-foreign-key-definition-unavailable" });
4216
+ objects.push({ identity: { kind: "constraint", constraintType: "foreignKey", table: qualified, name: defaultForeignKeyName2({ table: qualified.name, columns: fields, dialect: "sqlite" }) }, inspectionUnavailable: "sqlite-inline-foreign-key-definition-unavailable" });
4027
4217
  }
4028
4218
  for (const column of columns) {
4029
4219
  objects.push({ identity: { kind: "column", table: qualified, column: String(column.name) } });
@@ -4039,7 +4229,7 @@ async function inspectMigrationInventory(params) {
4039
4229
 
4040
4230
  // packages/migrate/src/module-ownership.ts
4041
4231
  function refusal(params) {
4042
- return new VibeError16({ code: "VIBE_MIGRATION", message: "Module ownership or dependencies cannot be reconciled with the declared and live schema; no package SQL was authorized", meta: params });
4232
+ return new VibeError17({ code: "VIBE_MIGRATION", message: "Module ownership or dependencies cannot be reconciled with the declared and live schema; no package SQL was authorized", meta: params });
4043
4233
  }
4044
4234
  function identities(params) {
4045
4235
  return [...schemaObjectIdentities({ schema: params.state.schema, dialect: params.dialect, namespace: params.namespace }), ...(params.state.schema.migrationObjects ?? []).map((object) => object.identity), ...params.state.definitions.map((definition) => definition.identity)];
@@ -4055,14 +4245,14 @@ function moduleNamespace(params) {
4055
4245
  function moduleOwnedObjects(params) {
4056
4246
  const { desiredState } = params;
4057
4247
  const namespace = params.namespace ?? (desiredState.dialect === "sqlite" ? "main" : "public");
4058
- const all = [desiredState.from, desiredState.to, ...desiredState.down === undefined ? [] : [desiredState.down]].flatMap((state2) => identities({ state: state2, dialect: desiredState.dialect, namespace }));
4248
+ const all = [desiredState.from, desiredState.to, ...desiredState.down === undefined ? [] : [desiredState.down]].flatMap((state) => identities({ state, dialect: desiredState.dialect, namespace }));
4059
4249
  return [...new Map(all.map((identity) => [sqlObjectKey6({ identity }), identity])).values()].sort((a, b) => sqlObjectKey6({ identity: a }).localeCompare(sqlObjectKey6({ identity: b })));
4060
4250
  }
4061
4251
  function assertModuleOwnership(params) {
4062
4252
  const { origin } = params;
4063
- const state2 = origin.source.desiredState;
4253
+ const state = origin.source.desiredState;
4064
4254
  const namespace = moduleNamespace({ origin });
4065
- const expected = moduleOwnedObjects({ desiredState: state2, namespace });
4255
+ const expected = moduleOwnedObjects({ desiredState: state, namespace });
4066
4256
  const owned = new Set(origin.owned.map((identity) => sqlObjectKey6({ identity })));
4067
4257
  if (expected.length !== owned.size || expected.some((identity) => !owned.has(sqlObjectKey6({ identity }))))
4068
4258
  throw refusal({ reason: "module-ownership-invalid", moduleId: origin.moduleId });
@@ -4071,10 +4261,10 @@ function assertModuleOwnership(params) {
4071
4261
  if (name?.namespace !== namespace || name.name === "_vibe_migrations")
4072
4262
  throw refusal({ reason: "module-ownership-invalid", moduleId: origin.moduleId, identity });
4073
4263
  }
4074
- for (const target of [state2.from, state2.to, ...state2.down === undefined ? [] : [state2.down]]) {
4264
+ for (const target of [state.from, state.to, ...state.down === undefined ? [] : [state.down]]) {
4075
4265
  if (target.schema.rls !== undefined || target.schema.extensions.length > 0)
4076
4266
  throw refusal({ reason: "module-schema-unsupported", moduleId: origin.moduleId });
4077
- for (const dependency of [...target.definitions.flatMap((definition) => definition.dependencies), ...(target.schema.migrationObjects ?? []).flatMap((object) => object.dependsOn), ...state2.unmanagedRemovals ?? []]) {
4267
+ for (const dependency of [...target.definitions.flatMap((definition) => definition.dependencies), ...(target.schema.migrationObjects ?? []).flatMap((object) => object.dependsOn), ...state.unmanagedRemovals ?? []]) {
4078
4268
  if (!owned.has(sqlObjectKey6({ identity: dependency })))
4079
4269
  throw refusal({ reason: "module-external-dependency", moduleId: origin.moduleId, identity: dependency });
4080
4270
  }
@@ -4095,10 +4285,39 @@ function assertModuleOwnership(params) {
4095
4285
  throw refusal({ reason: "module-source-state-mismatch", moduleId: origin.moduleId });
4096
4286
  return { ...actual, schema: { ...actual.schema, models: actual.schema.models.filter((model) => !tables.has(model.dbName ?? model.name)), enums: actual.schema.enums.filter((entry) => !enums.has(entry.dbName ?? entry.name)), migrationObjects: (actual.schema.migrationObjects ?? []).filter((object) => !owned.has(sqlObjectKey6({ identity: object.identity }))) }, definitions: actual.definitions.filter((definition) => !owned.has(sqlObjectKey6({ identity: definition.identity }))) };
4097
4287
  };
4098
- const before = canonicalMigrationJson({ value: rest(local.from, state2.from) });
4099
- if (before !== canonicalMigrationJson({ value: rest(local.to, state2.to) }) || before !== canonicalMigrationJson({ value: rest(local.down ?? local.from, state2.down ?? state2.from) }))
4288
+ const before = canonicalMigrationJson({ value: rest(local.from, state.from) });
4289
+ if (before !== canonicalMigrationJson({ value: rest(local.to, state.to) }) || before !== canonicalMigrationJson({ value: rest(local.down ?? local.from, state.down ?? state.from) }))
4100
4290
  throw refusal({ reason: "module-mutates-application-state", moduleId: origin.moduleId });
4101
4291
  }
4292
+ function dependencyUnavailable(params) {
4293
+ return new VibeError17({ code: "VIBE_MIGRATION", message: "Cannot establish module foreign-key dependencies across namespaces. MySQL requires direct global SHOW VIEW (or SELECT) without partial revokes; SHOW VIEW exposes metadata without granting external row reads. Restore catalog visibility before retrying", meta: { reason: "module-dependency-unavailable", moduleId: params.origin.moduleId }, ...params.cause === undefined ? {} : { cause: params.cause } });
4294
+ }
4295
+ async function assertCrossNamespaceModuleDependencies(params) {
4296
+ const { executor, origin } = params;
4297
+ const dialect = getSqlDialect3({ dialect: origin.dialect });
4298
+ const query = renderModuleDependencyQuery({ dialect, operation: { kind: "foreignKeys", namespace: params.namespace, tables: [...params.tables] } });
4299
+ if (query === undefined)
4300
+ return;
4301
+ const visibility = renderModuleDependencyQuery({ dialect, operation: { kind: "visibility" } });
4302
+ if (visibility !== undefined) {
4303
+ const rows = await executor({ text: visibility.text, values: [...visibility.values] }).then(undefined, (cause) => {
4304
+ throw dependencyUnavailable({ origin, cause });
4305
+ });
4306
+ if (!hasMysqlGlobalCatalogVisibility({ rows }))
4307
+ throw dependencyUnavailable({ origin });
4308
+ }
4309
+ const rows = await executor({ text: query.text, values: [...query.values] }).then(undefined, (cause) => {
4310
+ throw dependencyUnavailable({ origin, cause });
4311
+ });
4312
+ const flags = [true, false, 0, 1, "0", "1"];
4313
+ for (const row of rows) {
4314
+ const { constraint_name: name, source_namespace: namespace, source_table: table, target_namespace: targetNamespace, target_table: targetTable, source_owned: source, target_owned: target } = row;
4315
+ if (typeof name !== "string" || name.length === 0 || typeof namespace !== "string" || namespace.length === 0 || typeof table !== "string" || table.length === 0 || typeof targetNamespace !== "string" || targetNamespace.length === 0 || typeof targetTable !== "string" || targetTable.length === 0 || !flags.includes(source) || !flags.includes(target) || Number(source) + Number(target) === 0)
4316
+ throw dependencyUnavailable({ origin });
4317
+ if (Number(source) !== Number(target))
4318
+ throw refusal({ reason: "module-external-dependency", moduleId: origin.moduleId, identity: { kind: "constraint", constraintType: "foreignKey", table: { namespace, name: table }, name } });
4319
+ }
4320
+ }
4102
4321
  async function assertLiveModuleOwnership(params) {
4103
4322
  const { executor, origin } = params;
4104
4323
  const namespace = moduleNamespace({ origin });
@@ -4108,6 +4327,7 @@ async function assertLiveModuleOwnership(params) {
4108
4327
  const before = new Set(identities({ state: origin.source.desiredState.from, dialect: origin.dialect, namespace }).map((identity) => sqlObjectKey6({ identity })));
4109
4328
  const owned = new Set(origin.owned.map((identity) => sqlObjectKey6({ identity })));
4110
4329
  const tables = new Set(origin.owned.flatMap((identity) => identity.kind === "table" ? [identity.name.name] : []));
4330
+ await assertCrossNamespaceModuleDependencies({ executor, origin, namespace, tables });
4111
4331
  for (const object of inventory) {
4112
4332
  const key = sqlObjectKey6({ identity: object.identity });
4113
4333
  if (params.resume !== true && owned.has(key) && !before.has(key))
@@ -4117,7 +4337,7 @@ async function assertLiveModuleOwnership(params) {
4117
4337
  if (object.inspectionUnavailable !== undefined && (owned.has(key) || ("table" in object.identity) && tables.has(object.identity.table.name)))
4118
4338
  throw refusal({ reason: "module-dependency-unavailable", moduleId: origin.moduleId, identity: object.identity });
4119
4339
  }
4120
- const physical = origin.dialect === "postgres" ? await introspectPhysicalPostgres({ executor }) : origin.dialect === "mysql" ? await introspectMysql({ executor }) : await introspectSqlite({ executor });
4340
+ const physical = origin.dialect === "postgres" ? await introspectPhysicalPostgres({ executor }) : origin.dialect === "mysql" ? await introspectMysql({ executor }) : params.sqliteRestorePending === true ? await introspectSqliteBeforeForeignKeyRestore({ executor }) : await introspectSqlite({ executor });
4121
4341
  for (const model of physical.models)
4122
4342
  for (const relation of model.relations) {
4123
4343
  const target = physical.models.find((candidate) => candidate.name === relation.targetModel);
@@ -4125,13 +4345,23 @@ async function assertLiveModuleOwnership(params) {
4125
4345
  throw refusal({ reason: "module-external-dependency", moduleId: origin.moduleId });
4126
4346
  }
4127
4347
  }
4348
+ async function assertApplicationModuleState(params) {
4349
+ for (const origin of params.origins) {
4350
+ await assertLiveModuleOwnership({ executor: params.executor, origin, resume: true, ...params.sqliteRestorePending === true ? { sqliteRestorePending: true } : {} });
4351
+ const state = origin.source.desiredState;
4352
+ const options = { executor: params.executor, dialect: origin.dialect, from: state.from, to: state.to, removals: state.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } };
4353
+ const report = params.sqliteRestorePending === true ? await verifySqliteTransitionBeforeRestore(options) : await verifyMigrationTransition(options);
4354
+ if (!report.inSync)
4355
+ throw new VibeError17({ code: "VIBE_MIGRATION", message: `Application SQL cannot change objects owned by module ${origin.moduleId}; use its reviewed module upgrade`, meta: { reason: "module-application-mutation", moduleId: origin.moduleId, report } });
4356
+ }
4357
+ }
4128
4358
 
4129
4359
  // packages/migrate/src/sql-statements.ts
4130
- import { VibeError as VibeError17 } from "@vibeorm/schema";
4360
+ import { VibeError as VibeError18 } from "@vibeorm/schema";
4131
4361
  var COMPOUND_BODY_HEADER = /^(?:\s|--[^\n]*\n|\/\*[\s\S]*?\*\/)*CREATE\s+(?:OR\s+REPLACE\s+)?(?:(?:TEMP|TEMPORARY)\s+)?(?:DEFINER\s*=\s*\S+\s+)?(?:TRIGGER|PROCEDURE|FUNCTION|EVENT)\b/i;
4132
4362
  var BLOCK_OPENERS = new Set(["BEGIN", "CASE", "IF", "LOOP", "WHILE", "REPEAT"]);
4133
4363
  function splitSqlStatements(params) {
4134
- const { sql: sql2, dialect } = params;
4364
+ const { sql, dialect } = params;
4135
4365
  const statements = [];
4136
4366
  let current = "";
4137
4367
  let hasContent = false;
@@ -4149,65 +4379,65 @@ function splitSqlStatements(params) {
4149
4379
  compound = false;
4150
4380
  afterEnd = false;
4151
4381
  };
4152
- while (i < sql2.length) {
4153
- const ch = sql2[i];
4154
- const next = sql2[i + 1];
4155
- if (ch === "-" && next === "-" && (dialect !== "mysql" || /\s/.test(sql2[i + 2] ?? `
4382
+ while (i < sql.length) {
4383
+ const ch = sql[i];
4384
+ const next = sql[i + 1];
4385
+ if (ch === "-" && next === "-" && (dialect !== "mysql" || /\s/.test(sql[i + 2] ?? `
4156
4386
  `)) || ch === "#" && dialect === "mysql") {
4157
- while (i < sql2.length && sql2[i] !== `
4387
+ while (i < sql.length && sql[i] !== `
4158
4388
  `) {
4159
- current += sql2[i];
4389
+ current += sql[i];
4160
4390
  i++;
4161
4391
  }
4162
4392
  continue;
4163
4393
  }
4164
4394
  if (ch === "/" && next === "*") {
4165
- current += sql2.slice(i, i + 2);
4395
+ current += sql.slice(i, i + 2);
4166
4396
  i += 2;
4167
4397
  let depth = 1;
4168
- while (i < sql2.length && depth > 0) {
4169
- if (sql2[i] === "/" && sql2[i + 1] === "*" && (dialect === undefined || dialect === "postgres")) {
4398
+ while (i < sql.length && depth > 0) {
4399
+ if (sql[i] === "/" && sql[i + 1] === "*" && (dialect === undefined || dialect === "postgres")) {
4170
4400
  depth++;
4171
4401
  current += "/*";
4172
4402
  i += 2;
4173
- } else if (sql2[i] === "*" && sql2[i + 1] === "/") {
4403
+ } else if (sql[i] === "*" && sql[i + 1] === "/") {
4174
4404
  depth--;
4175
4405
  current += "*/";
4176
4406
  i += 2;
4177
4407
  } else {
4178
- current += sql2[i];
4408
+ current += sql[i];
4179
4409
  i++;
4180
4410
  }
4181
4411
  }
4182
4412
  continue;
4183
4413
  }
4184
- const escapeString = (dialect === undefined || dialect === "postgres") && (ch === "e" || ch === "E") && next === "'" && !/[A-Za-z0-9_$]/.test(sql2[i - 1] ?? "");
4414
+ const escapeString = (dialect === undefined || dialect === "postgres") && (ch === "e" || ch === "E") && next === "'" && !/[A-Za-z0-9_$]/.test(sql[i - 1] ?? "");
4185
4415
  if (escapeString) {
4186
4416
  current += ch;
4187
4417
  i++;
4188
4418
  }
4189
- const quote = sql2[i];
4419
+ const quote = sql[i];
4190
4420
  if (escapeString || quote === "'" || quote === '"' || quote === "`" && dialect !== "postgres" || quote === "[" && (dialect === undefined || dialect === "sqlite")) {
4191
4421
  hasContent = true;
4192
4422
  const endQuote = quote === "[" ? "]" : quote;
4193
4423
  current += quote;
4194
4424
  i++;
4195
- while (i < sql2.length) {
4196
- const value = sql2[i];
4425
+ while (i < sql.length) {
4426
+ const value = sql[i];
4197
4427
  current += value;
4198
4428
  if (value === "\\" && (quote === "'" || quote === '"')) {
4199
4429
  if (escapeString) {
4200
- if (sql2[i + 1] !== undefined)
4201
- current += sql2[i + 1];
4430
+ if (sql[i + 1] !== undefined)
4431
+ current += sql[i + 1];
4202
4432
  i += 2;
4203
4433
  continue;
4204
4434
  }
4205
4435
  if (dialect === "mysql" || dialect === undefined) {
4206
- throw new VibeError17({ code: "VIBE_MIGRATION", message: "SQL string backslash escaping depends on the session SQL mode; use mode-independent quoting and pass the migration dialect", meta: { reason: "sql-mode-ambiguous", dialect } });
4436
+ throw new VibeError18({ code: "VIBE_MIGRATION", message: "SQL string backslash escaping depends on the session SQL mode; use mode-independent quoting and pass the migration dialect", meta: { reason: "sql-mode-ambiguous", dialect } });
4207
4437
  }
4208
4438
  }
4209
4439
  if (value === endQuote) {
4210
- if (quote !== "[" && sql2[i + 1] === endQuote) {
4440
+ if (quote !== "[" && sql[i + 1] === endQuote) {
4211
4441
  current += endQuote;
4212
4442
  i += 2;
4213
4443
  continue;
@@ -4219,14 +4449,14 @@ function splitSqlStatements(params) {
4219
4449
  }
4220
4450
  continue;
4221
4451
  }
4222
- if (ch === "$" && (dialect === undefined || dialect === "postgres") && !/[A-Za-z0-9_$]/.test(sql2[i - 1] ?? "")) {
4223
- const tagMatch = /^\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$/.exec(sql2.slice(i));
4452
+ if (ch === "$" && (dialect === undefined || dialect === "postgres") && !/[A-Za-z0-9_$]/.test(sql[i - 1] ?? "")) {
4453
+ const tagMatch = /^\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$/.exec(sql.slice(i));
4224
4454
  if (tagMatch !== null) {
4225
4455
  hasContent = true;
4226
4456
  const tag = tagMatch[0];
4227
- const end = sql2.indexOf(tag, i + tag.length);
4228
- const stop = end === -1 ? sql2.length : end + tag.length;
4229
- current += sql2.slice(i, stop);
4457
+ const end = sql.indexOf(tag, i + tag.length);
4458
+ const stop = end === -1 ? sql.length : end + tag.length;
4459
+ current += sql.slice(i, stop);
4230
4460
  i = stop;
4231
4461
  continue;
4232
4462
  }
@@ -4241,14 +4471,14 @@ function splitSqlStatements(params) {
4241
4471
  i++;
4242
4472
  continue;
4243
4473
  }
4244
- const word = /^[A-Za-z_][A-Za-z_0-9]*/.exec(sql2.slice(i))?.[0];
4474
+ const word = /^[A-Za-z_][A-Za-z_0-9]*/.exec(sql.slice(i))?.[0];
4245
4475
  if (word !== undefined) {
4246
4476
  hasContent = true;
4247
4477
  if (!compound && COMPOUND_BODY_HEADER.test(current + word))
4248
4478
  compound = true;
4249
4479
  if (compound) {
4250
4480
  const upper = word.toUpperCase();
4251
- const rest = sql2.slice(i + word.length);
4481
+ const rest = sql.slice(i + word.length);
4252
4482
  const opens = !afterEnd && (upper === "BEGIN" || blockDepth > 0 && BLOCK_OPENERS.has(upper) && !/^\s*\(/.test(rest) && !(upper === "IF" && /^\s+(?:NOT\s+)?EXISTS\b/i.test(rest)));
4253
4483
  afterEnd = upper === "END";
4254
4484
  if (opens)
@@ -4277,10 +4507,10 @@ function joinSqlStatements(params) {
4277
4507
 
4278
4508
  // packages/migrate/src/module-origin.ts
4279
4509
  import { createHash } from "crypto";
4280
- import { VibeError as VibeError18, isSqlObjectIdentity as isSqlObjectIdentity3, sqlObjectKey as sqlObjectKey7 } from "@vibeorm/schema";
4510
+ import { VibeError as VibeError19, isSqlObjectIdentity as isSqlObjectIdentity3, sqlObjectKey as sqlObjectKey7 } from "@vibeorm/schema";
4281
4511
  var MODULE_ORIGIN_METADATA = Object.freeze({ filename: "module-origin.json", version: 1 });
4282
4512
  function invalid2() {
4283
- return new VibeError18({ code: "VIBE_MIGRATION", message: "Module migration origin is malformed or differs from its immutable package artifact; restore the reviewed artifact", meta: { reason: "module-origin-invalid" } });
4513
+ return new VibeError19({ code: "VIBE_MIGRATION", message: "Module migration origin is malformed or differs from its immutable package artifact; restore the reviewed artifact", meta: { reason: "module-origin-invalid" } });
4284
4514
  }
4285
4515
  function record2(value) {
4286
4516
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -4344,7 +4574,7 @@ function assertMaterializedModuleMigration(params) {
4344
4574
  return;
4345
4575
  const restored = restoreModuleMigration({ migration, origin: migration.moduleOrigin });
4346
4576
  if (migration.desiredState === undefined || canonicalMigrationJson({ value: restored }) !== canonicalMigrationJson({ value: migration }))
4347
- throw new VibeError18({ code: "VIBE_MIGRATION", message: "Materialized module metadata differs from its immutable source", meta: { reason: "module-source-state-mismatch", moduleId: migration.moduleOrigin.moduleId } });
4577
+ throw new VibeError19({ code: "VIBE_MIGRATION", message: "Materialized module metadata differs from its immutable source", meta: { reason: "module-source-state-mismatch", moduleId: migration.moduleOrigin.moduleId } });
4348
4578
  }
4349
4579
  function restoreModuleMigration(params) {
4350
4580
  const { migration, origin } = params;
@@ -4353,7 +4583,7 @@ function restoreModuleMigration(params) {
4353
4583
  const actual = migration[key];
4354
4584
  if (actual === undefined)
4355
4585
  continue;
4356
- const normalized = (sql2) => sql2.flatMap((text) => splitSqlStatements({ sql: text, dialect: origin.dialect }));
4586
+ const normalized = (sql) => sql.flatMap((text) => splitSqlStatements({ sql: text, dialect: origin.dialect }));
4357
4587
  if (canonicalMigrationJson({ value: normalized(actual) }) !== canonicalMigrationJson({ value: normalized(origin.source[key] ?? []) }))
4358
4588
  throw invalid2();
4359
4589
  }
@@ -4367,13 +4597,13 @@ function restoreModuleMigration(params) {
4367
4597
  // packages/migrate/src/fs.ts
4368
4598
  import { readFile, readdir } from "fs/promises";
4369
4599
  import { join } from "path";
4370
- import { VibeError as VibeError31, assertValidSchemaIR as assertValidSchemaIR4 } from "@vibeorm/schema";
4600
+ import { VibeError as VibeError33, assertValidSchemaIR as assertValidSchemaIR4 } from "@vibeorm/schema";
4371
4601
 
4372
4602
  // packages/migrate/src/migration-checksum.ts
4373
4603
  import { createHash as createHash2 } from "crypto";
4374
4604
 
4375
4605
  // packages/migrate/src/execution.ts
4376
- import { VibeError as VibeError19 } from "@vibeorm/schema";
4606
+ import { VibeError as VibeError20 } from "@vibeorm/schema";
4377
4607
  var EXECUTION_SIDECAR_FILENAME = "execution.json";
4378
4608
  var EXECUTION_SIDECAR_VERSION = 1;
4379
4609
  function isDefaultExecution(params) {
@@ -4412,7 +4642,7 @@ ${lines.join(`
4412
4642
  `)}`;
4413
4643
  }
4414
4644
  function invalid3(params) {
4415
- return new VibeError19({
4645
+ return new VibeError20({
4416
4646
  code: "VIBE_MIGRATION",
4417
4647
  message: `invalid execution metadata for migration "${params.migration}": ${params.detail}`,
4418
4648
  meta: { reason: "execution-metadata-invalid", migration: params.migration }
@@ -4463,7 +4693,7 @@ function parseExecutionSidecar(params) {
4463
4693
  try {
4464
4694
  parsed = JSON.parse(params.text);
4465
4695
  } catch (error) {
4466
- throw new VibeError19({
4696
+ throw new VibeError20({
4467
4697
  code: "VIBE_MIGRATION",
4468
4698
  message: `invalid execution metadata for migration "${migration}": not valid JSON`,
4469
4699
  meta: { reason: "execution-metadata-invalid", migration },
@@ -4561,16 +4791,35 @@ function migrationChecksum(params) {
4561
4791
  -- vibeorm:down ${JSON.stringify(params.downSql ?? null)}${executionChecksumSuffix({ ...params.downExecution === undefined ? {} : { execution: params.downExecution } })}`)).digest("hex");
4562
4792
  }
4563
4793
 
4794
+ // packages/migrate/src/shadow-guard.ts
4795
+ import { VibeError as VibeError21 } from "@vibeorm/schema";
4796
+ import { getSqlDialect as getSqlDialect4, renderShadowOperation } from "@vibeorm/sql";
4797
+ var replayExecutors = new WeakSet;
4798
+ async function assertDatabaseNotShadow(params) {
4799
+ if (params.dialect === "sqlite" || replayExecutors.has(params.executor))
4800
+ return;
4801
+ const [query] = renderShadowOperation({ dialect: getSqlDialect4({ dialect: params.dialect }), operation: { kind: "markerExists" } });
4802
+ const rows = await params.executor({ text: query.text, values: [...query.values] });
4803
+ if (rows.length !== 0)
4804
+ throw new VibeError21({ code: "VIBE_MIGRATION", message: "This database is claimed as a disposable migration shadow. Application migrations must use the deployment target.", meta: { reason: "shadow-database-is-not-target" } });
4805
+ }
4806
+ function runShadowReplay(params) {
4807
+ replayExecutors.add(params.executor);
4808
+ return Promise.resolve().then(params.run).finally(() => {
4809
+ replayExecutors.delete(params.executor);
4810
+ });
4811
+ }
4812
+
4564
4813
  // packages/migrate/src/module-history.ts
4565
- import { VibeError as VibeError20, sqlObjectKey as sqlObjectKey8 } from "@vibeorm/schema";
4814
+ import { VibeError as VibeError22, sqlObjectKey as sqlObjectKey8 } from "@vibeorm/schema";
4566
4815
  function refusal2(params) {
4567
- return new VibeError20({ code: "VIBE_MIGRATION", message: `Module ${params.moduleId} history, ownership or predecessor state is inconsistent; restore or complete the reviewed upgrade first`, meta: params });
4816
+ return new VibeError22({ code: "VIBE_MIGRATION", message: `Module ${params.moduleId} history, ownership or predecessor state is inconsistent; restore or complete the reviewed upgrade first`, meta: params });
4568
4817
  }
4569
4818
  function moduleHistoryHeads(params) {
4570
4819
  const heads = new Map;
4571
4820
  const revisions = new Map;
4572
- for (const record3 of params.records.values()) {
4573
- const origin = record3.entry?.migration.moduleOrigin;
4821
+ for (const record of params.records.values()) {
4822
+ const origin = record.entry?.migration.moduleOrigin;
4574
4823
  if (origin === undefined)
4575
4824
  continue;
4576
4825
  const previous = heads.get(origin.moduleId);
@@ -4583,10 +4832,21 @@ function moduleHistoryHeads(params) {
4583
4832
  throw refusal2({ reason: "module-predecessor-state", moduleId: origin.moduleId });
4584
4833
  seen.add(origin.revision);
4585
4834
  revisions.set(origin.moduleId, seen);
4586
- heads.set(origin.moduleId, record3);
4835
+ heads.set(origin.moduleId, record);
4587
4836
  }
4588
4837
  return heads;
4589
4838
  }
4839
+ function applicationModuleOrigins(params) {
4840
+ if (params.migration.moduleOrigin !== undefined || params.migration.desiredState !== undefined)
4841
+ return [];
4842
+ const origins = [];
4843
+ for (const [moduleId, head] of moduleHistoryHeads(params)) {
4844
+ if (!head.entry.complete || head.row.error !== undefined || head.row.statementIndex !== head.entry.migration.sql.length)
4845
+ throw refusal2({ reason: "module-chain-incomplete", moduleId });
4846
+ origins.push(head.entry.migration.moduleOrigin);
4847
+ }
4848
+ return origins;
4849
+ }
4590
4850
  function preserves(params) {
4591
4851
  const tables = new Set(params.expected.schema.models.map((model) => model.dbName ?? model.name));
4592
4852
  const enums = new Set(params.expected.schema.enums.map((entry) => entry.dbName ?? entry.name));
@@ -4617,9 +4877,9 @@ function assertModuleUpgradeHistory(params) {
4617
4877
  owners.set(key, origin.moduleId);
4618
4878
  }
4619
4879
  };
4620
- for (const record3 of params.records.values())
4621
- if (record3.entry !== undefined)
4622
- register(record3.entry.migration);
4880
+ for (const record of params.records.values())
4881
+ if (record.entry !== undefined)
4882
+ register(record.entry.migration);
4623
4883
  for (const migration of params.migrations) {
4624
4884
  const stored = params.records.get(migration.name);
4625
4885
  const origin = migration.moduleOrigin;
@@ -4631,7 +4891,7 @@ function assertModuleUpgradeHistory(params) {
4631
4891
  if (origin === undefined) {
4632
4892
  for (const [moduleId, head] of heads) {
4633
4893
  if (migration.desiredState === undefined)
4634
- throw refusal2({ reason: "module-application-state-required", moduleId });
4894
+ continue;
4635
4895
  const expected = head.entry.migration.moduleOrigin.source.desiredState.to;
4636
4896
  for (const actual of [migration.desiredState.from, migration.desiredState.to, migration.desiredState.down ?? migration.desiredState.from])
4637
4897
  preserves({ actual, expected, moduleId });
@@ -4658,22 +4918,22 @@ function assertModuleUpgradeHistory(params) {
4658
4918
  }
4659
4919
 
4660
4920
  // packages/migrate/src/module-journal.ts
4661
- import { VibeError as VibeError22 } from "@vibeorm/schema";
4662
- import { getSqlDialect as getSqlDialect3, MODULE_JOURNAL_COLUMN, renderModuleJournal } from "@vibeorm/sql";
4921
+ import { VibeError as VibeError24 } from "@vibeorm/schema";
4922
+ import { getSqlDialect as getSqlDialect5, MODULE_JOURNAL_COLUMN, renderModuleJournal } from "@vibeorm/sql";
4663
4923
 
4664
4924
  // packages/migrate/src/journal-read.ts
4665
- import { VibeError as VibeError21 } from "@vibeorm/schema";
4925
+ import { VibeError as VibeError23 } from "@vibeorm/schema";
4666
4926
  var MISSING_TABLE_IDENTIFIERS = new Set(["42P01", "42S02", "ER_NO_SUCH_TABLE"]);
4667
4927
  function isMissingTable(params) {
4668
4928
  let current = params.cause;
4669
4929
  for (let depth = 0;depth < 6 && current !== null && typeof current === "object"; depth++) {
4670
- const record3 = current;
4930
+ const record = current;
4671
4931
  for (const key of ["code", "errno", "sqlState"]) {
4672
- const value = record3[key];
4932
+ const value = record[key];
4673
4933
  if (typeof value === "string" && MISSING_TABLE_IDENTIFIERS.has(value))
4674
4934
  return true;
4675
4935
  }
4676
- current = record3.cause;
4936
+ current = record.cause;
4677
4937
  }
4678
4938
  return false;
4679
4939
  }
@@ -4686,7 +4946,7 @@ async function readJournalRows(params) {
4686
4946
  if (presence.state === "missing")
4687
4947
  return;
4688
4948
  }
4689
- throw new VibeError21({ code: "VIBE_MIGRATION", message: "Cannot inspect migration history; check SELECT privileges", meta: { reason: "history-unavailable" }, cause });
4949
+ throw new VibeError23({ code: "VIBE_MIGRATION", message: "Cannot inspect migration history; check SELECT privileges", meta: { reason: "history-unavailable" }, cause });
4690
4950
  });
4691
4951
  if (rows === undefined)
4692
4952
  return;
@@ -4694,7 +4954,7 @@ async function readJournalRows(params) {
4694
4954
  for (const row of rows) {
4695
4955
  const index = row.statement_index;
4696
4956
  if (typeof row.name !== "string" || typeof row.checksum !== "string" || typeof index !== "number" && typeof index !== "string" || typeof index === "string" && !/^-?\d+$/.test(index) || !Number.isSafeInteger(Number(index)) || row.module_origin !== null && row.module_origin !== undefined && typeof row.module_origin !== "string" || row.error !== null && row.error !== undefined && typeof row.error !== "string" || result.has(row.name)) {
4697
- throw new VibeError21({ code: "VIBE_MIGRATION", message: "Malformed migration journal row", meta: { reason: "history-unavailable" } });
4957
+ throw new VibeError23({ code: "VIBE_MIGRATION", message: "Malformed migration journal row", meta: { reason: "history-unavailable" } });
4698
4958
  }
4699
4959
  result.set(row.name, { checksum: row.checksum, statementIndex: Number(index), ...typeof row.error === "string" ? { error: row.error } : {}, ...typeof row.module_origin === "string" ? { moduleEntry: row.module_origin } : {} });
4700
4960
  }
@@ -4703,7 +4963,7 @@ async function readJournalRows(params) {
4703
4963
 
4704
4964
  // packages/migrate/src/module-journal.ts
4705
4965
  function invalid4() {
4706
- return new VibeError22({ code: "VIBE_MIGRATION", message: "Module migration history is missing, altered or inconsistent; restore the reviewed history before using this module", meta: { reason: "module-history-invalid" } });
4966
+ return new VibeError24({ code: "VIBE_MIGRATION", message: "Module migration history is missing, altered or inconsistent; restore the reviewed history before using this module", meta: { reason: "module-history-invalid" } });
4707
4967
  }
4708
4968
  function parseModuleJournalEntry(params) {
4709
4969
  return parseMigrationMetadata({ text: params.text, failure: invalid4, parse: (value) => {
@@ -4719,7 +4979,7 @@ function parseModuleJournalEntry(params) {
4719
4979
  } });
4720
4980
  }
4721
4981
  async function readModuleJournal(params) {
4722
- const query = renderModuleJournal({ dialect: getSqlDialect3({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: { kind: "read" } });
4982
+ const query = renderModuleJournal({ dialect: getSqlDialect5({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: { kind: "read" } });
4723
4983
  const rows = await readJournalRows({ ...params, query });
4724
4984
  return new Map([...rows ?? []].map(([name, row]) => {
4725
4985
  const entry = row.moduleEntry === undefined ? undefined : parseModuleJournalEntry({ text: row.moduleEntry, name, checksum: row.checksum });
@@ -4729,14 +4989,14 @@ async function readModuleJournal(params) {
4729
4989
  }));
4730
4990
  }
4731
4991
  async function ensureModuleJournal(params) {
4732
- const dialect = getSqlDialect3({ dialect: params.dialect });
4992
+ const dialect = getSqlDialect5({ dialect: params.dialect });
4733
4993
  const columns = await params.executor(renderModuleJournal({ dialect, table: MIGRATIONS_TABLE_NAME, operation: { kind: "columns" } }));
4734
4994
  if (columns.some((row) => row.name === MODULE_JOURNAL_COLUMN))
4735
4995
  return;
4736
4996
  await params.executor(renderModuleJournal({ dialect, table: MIGRATIONS_TABLE_NAME, operation: { kind: "addColumn" } }));
4737
4997
  }
4738
4998
  async function insertModuleJournal(params) {
4739
- await params.executor(renderModuleJournal({ dialect: getSqlDialect3({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4999
+ await params.executor(renderModuleJournal({ dialect: getSqlDialect5({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4740
5000
  kind: "insert",
4741
5001
  name: params.migration.name,
4742
5002
  checksum: migrationChecksum(params.migration),
@@ -4745,7 +5005,7 @@ async function insertModuleJournal(params) {
4745
5005
  } }));
4746
5006
  }
4747
5007
  async function completeModuleJournal(params) {
4748
- await params.executor(renderModuleJournal({ dialect: getSqlDialect3({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
5008
+ await params.executor(renderModuleJournal({ dialect: getSqlDialect5({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4749
5009
  kind: "complete",
4750
5010
  name: params.migration.name,
4751
5011
  entry: canonicalMigrationJson({ value: { version: 1, migration: params.migration, complete: true } })
@@ -4762,19 +5022,19 @@ function moduleRecordComplete(params) {
4762
5022
  }
4763
5023
 
4764
5024
  // packages/migrate/src/runner.ts
4765
- import { VibeError as VibeError30 } from "@vibeorm/schema";
5025
+ import { VibeError as VibeError32 } from "@vibeorm/schema";
4766
5026
  import {
4767
5027
  DIALECT_CAPABILITIES as DIALECT_CAPABILITIES3,
4768
- getSqlDialect as getSqlDialect5,
5028
+ getSqlDialect as getSqlDialect7,
4769
5029
  renderMigrationSessionRead,
4770
5030
  renderMigrationSessionRestore,
4771
5031
  renderMigrationSessionSet
4772
5032
  } from "@vibeorm/sql";
4773
5033
 
4774
5034
  // packages/migrate/src/recovery.ts
4775
- import { VibeError as VibeError23 } from "@vibeorm/schema";
5035
+ import { VibeError as VibeError25 } from "@vibeorm/schema";
4776
5036
  import {
4777
- getSqlDialect as getSqlDialect4,
5037
+ getSqlDialect as getSqlDialect6,
4778
5038
  renderColumnStateQuery,
4779
5039
  renderConstraintStateQuery,
4780
5040
  renderIndexStateQuery,
@@ -4788,7 +5048,7 @@ function constraintUnverifiable(params) {
4788
5048
  });
4789
5049
  }
4790
5050
  function conflict2(params) {
4791
- return new VibeError23({
5051
+ return new VibeError25({
4792
5052
  code: "VIBE_MIGRATION",
4793
5053
  message: params.message,
4794
5054
  meta: { reason: params.reason, ...params.meta }
@@ -4813,7 +5073,7 @@ function sameShape(params) {
4813
5073
  }
4814
5074
  async function establishOperationState(params) {
4815
5075
  const { executor, operation } = params;
4816
- const dialect = getSqlDialect4({ dialect: params.dialect });
5076
+ const dialect = getSqlDialect6({ dialect: params.dialect });
4817
5077
  const run = async (query) => executor({ text: query.text, values: [...query.values] });
4818
5078
  switch (operation.kind) {
4819
5079
  case "createIndexConcurrently": {
@@ -4893,10 +5153,10 @@ async function establishOperationState(params) {
4893
5153
 
4894
5154
  // packages/migrate/src/differ.ts
4895
5155
  import { isEnumType as isEnumType6, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
4896
- import { VibeError as VibeError25 } from "@vibeorm/schema";
5156
+ import { VibeError as VibeError27 } from "@vibeorm/schema";
4897
5157
 
4898
5158
  // packages/migrate/src/renames.ts
4899
- import { VibeError as VibeError24 } from "@vibeorm/schema";
5159
+ import { VibeError as VibeError26 } from "@vibeorm/schema";
4900
5160
  function tableOf(model) {
4901
5161
  return model.dbName ?? model.name;
4902
5162
  }
@@ -4907,7 +5167,7 @@ function hasColumn(params) {
4907
5167
  return params.model.fields.some((field) => (field.dbName ?? field.name) === params.column);
4908
5168
  }
4909
5169
  function ambiguous(params) {
4910
- return new VibeError24({
5170
+ return new VibeError26({
4911
5171
  code: "VIBE_MIGRATION",
4912
5172
  message: `rename refused: ${params.detail}`,
4913
5173
  meta: { reason: "rename-ambiguous", ...params.meta }
@@ -5055,7 +5315,7 @@ function diffSchemas(params) {
5055
5315
  if (before?.definition === exclusion.definition)
5056
5316
  continue;
5057
5317
  if (before?.catalogDefinition)
5058
- throw new VibeError25({ code: "VIBE_MIGRATION", message: "Exclusion comparison requires normalized evidence", meta: { reason: "exclusion-inspection-unavailable", table, name: exclusion.name } });
5318
+ throw new VibeError27({ code: "VIBE_MIGRATION", message: "Exclusion comparison requires normalized evidence", meta: { reason: "exclusion-inspection-unavailable", table, name: exclusion.name } });
5059
5319
  if (before !== undefined)
5060
5320
  buckets.dropExclusion.push({ kind: "dropExclusion", table, exclusion: before, destructive: false });
5061
5321
  buckets.addExclusion.push({ kind: "addExclusion", table, exclusion, destructive: false });
@@ -5267,7 +5527,7 @@ function diffOneTable(params) {
5267
5527
  changes.push("collation");
5268
5528
  if (changes.length === 0)
5269
5529
  continue;
5270
- if (changes.includes("type") && [...previous.checks].some(([name2, expression]) => current.checks.get(name2) === expression)) {
5530
+ if (changes.includes("type") && [...previous.checks].some(([name, expression]) => current.checks.get(name) === expression)) {
5271
5531
  throw unsupportedCapability6({ dialect, feature: "alterColumnWithRetainedCheck", hint: "CHECK dependencies and type compatibility are not proven; use a reviewed migration that replaces and revalidates the affected constraints" });
5272
5532
  }
5273
5533
  const storageChange = isEnumStringTransition({ from: before.field, to: column.field });
@@ -5331,7 +5591,7 @@ function diffOneTable(params) {
5331
5591
  if (before === expression)
5332
5592
  continue;
5333
5593
  if (before !== undefined && previous.model.checks?.some((check) => check.name === name && check.catalogExpression === true))
5334
- throw new VibeError25({ code: "VIBE_MIGRATION", message: "Unequal catalog CHECK text requires normalized evidence or explicit replacement through the live planner", meta: { reason: "check-inspection-unavailable", table, name } });
5594
+ throw new VibeError27({ code: "VIBE_MIGRATION", message: "Unequal catalog CHECK text requires normalized evidence or explicit replacement through the live planner", meta: { reason: "check-inspection-unavailable", table, name } });
5335
5595
  if (before !== undefined)
5336
5596
  buckets.dropCheck.push({ kind: "dropCheck", table, name, destructive: false });
5337
5597
  buckets.addCheck.push({ kind: "addCheck", table, name, expression, destructive: false });
@@ -5410,12 +5670,12 @@ function diffOneTable(params) {
5410
5670
  }
5411
5671
 
5412
5672
  // packages/migrate/src/ddl/render.ts
5413
- import { VibeError as VibeError29, sqlObjectKey as sqlObjectKey9 } from "@vibeorm/schema";
5673
+ import { VibeError as VibeError31, sqlObjectKey as sqlObjectKey9 } from "@vibeorm/schema";
5414
5674
 
5415
5675
  // packages/migrate/src/ddl/postgres.ts
5416
5676
  import { renderExclusionSetup } from "@vibeorm/sql";
5417
- import { VibeError as VibeError26, isEnumType as isEnumType7 } from "@vibeorm/schema";
5418
- import { postgresDialect as postgresDialect7, renderRlsPolicyPath } from "@vibeorm/sql";
5677
+ import { VibeError as VibeError28, defaultPrimaryKeyName as defaultPrimaryKeyName3, implicitJoinTableObjectNames as implicitJoinTableObjectNames2, isEnumType as isEnumType7 } from "@vibeorm/schema";
5678
+ import { postgresDialect as postgresDialect8, renderRlsPolicyPath } from "@vibeorm/sql";
5419
5679
  function renderPostgresSteps(params) {
5420
5680
  refuseSameTransactionEnumUse({ steps: params.steps });
5421
5681
  return params.steps.flatMap((step) => renderStep({ step }));
@@ -5449,7 +5709,7 @@ function refuseSameTransactionEnumUse(params) {
5449
5709
  const found = use(field);
5450
5710
  if (found === undefined)
5451
5711
  continue;
5452
- throw new VibeError26({
5712
+ throw new VibeError28({
5453
5713
  code: "VIBE_MIGRATION",
5454
5714
  message: `enum value "${found.value}" is added to "${found.enumName}" and used as a default on "${step.table}"."${field.dbName ?? field.name}" in the same migration \u2014 PostgreSQL cannot use an enum member before the transaction that added it commits. Split this into two migrations: the first containing only the ALTER TYPE ... ADD VALUE, the second the column change`,
5455
5715
  meta: { enum: found.enumName, value: found.value, table: step.table, column: field.dbName ?? field.name, rule: "enum-value-used-in-adding-transaction" }
@@ -5461,7 +5721,7 @@ function renderStep(params) {
5461
5721
  const { step } = params;
5462
5722
  switch (step.kind) {
5463
5723
  case "addExclusion":
5464
- return [...renderExclusionSetup({ dialect: postgresDialect7, exclusion: step.exclusion }), `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.exclusion.name)} ${step.exclusion.definition};`];
5724
+ return [...renderExclusionSetup({ dialect: postgresDialect8, exclusion: step.exclusion }), `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.exclusion.name)} ${step.exclusion.definition};`];
5465
5725
  case "dropExclusion":
5466
5726
  return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.exclusion.name)};`];
5467
5727
  case "enableRls":
@@ -5470,7 +5730,7 @@ function renderStep(params) {
5470
5730
  case "noForceRls":
5471
5731
  case "createPolicy":
5472
5732
  case "dropPolicy":
5473
- return step.kind === "createPolicy" ? [renderRlsPolicyPath({ dialect: postgresDialect7, stage: "save" }).text, renderRlsPolicyPath({ dialect: postgresDialect7, stage: "empty" }).text, ...renderRlsStep({ step, dialect: "postgres" }), renderRlsPolicyPath({ dialect: postgresDialect7, stage: "restore" }).text] : renderRlsStep({ step, dialect: "postgres" });
5733
+ return step.kind === "createPolicy" ? [renderRlsPolicyPath({ dialect: postgresDialect8, stage: "save" }).text, renderRlsPolicyPath({ dialect: postgresDialect8, stage: "empty" }).text, ...renderRlsStep({ step, dialect: "postgres" }), renderRlsPolicyPath({ dialect: postgresDialect8, stage: "restore" }).text] : renderRlsStep({ step, dialect: "postgres" });
5474
5734
  case "createEnum": {
5475
5735
  const name = step.enumDef.dbName ?? step.enumDef.name;
5476
5736
  const values = step.enumDef.values.map((value) => quotePgString({ value })).join(", ");
@@ -5486,7 +5746,7 @@ function renderStep(params) {
5486
5746
  const lines = step.columns.map((column) => ` ${columnDefSql({ field: column })}`);
5487
5747
  if (step.primaryKey.length > 0) {
5488
5748
  const pkCols = step.primaryKey.map((column) => q2(column)).join(", ");
5489
- lines.push(` CONSTRAINT ${q2(step.primaryKeyConstraintName ?? `${step.table}_pkey`)} PRIMARY KEY (${pkCols})`);
5749
+ lines.push(` CONSTRAINT ${q2(step.primaryKeyConstraintName ?? defaultPrimaryKeyName3({ table: step.table, dialect: "postgres" }))} PRIMARY KEY (${pkCols})`);
5490
5750
  }
5491
5751
  for (const check of step.checks ?? []) {
5492
5752
  lines.push(` CONSTRAINT ${q2(check.name)} CHECK (${check.expression})`);
@@ -5520,7 +5780,7 @@ ${lines.join(`,
5520
5780
  case "dropIndex":
5521
5781
  if (step.constraintName !== undefined) {
5522
5782
  if (step.table === undefined)
5523
- throw new VibeError26({ code: "VIBE_MIGRATION", message: "Constraint-backed index removal requires its owning table" });
5783
+ throw new VibeError28({ code: "VIBE_MIGRATION", message: "Constraint-backed index removal requires its owning table" });
5524
5784
  return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.constraintName)};`];
5525
5785
  }
5526
5786
  return [`DROP INDEX ${publicName(step.name)};`];
@@ -5559,32 +5819,33 @@ ${lines.join(`,
5559
5819
  case "createJoinTable": {
5560
5820
  const aType = columnTypeSql({ field: { ...step.a.field, isList: false } });
5561
5821
  const bType = columnTypeSql({ field: { ...step.b.field, isList: false } });
5822
+ const names = implicitJoinTableObjectNames2({ table: step.table });
5562
5823
  return [
5563
5824
  `CREATE TABLE ${publicName(step.table)} (
5564
5825
  "A" ${aType} NOT NULL,
5565
5826
  "B" ${bType} NOT NULL
5566
5827
  );`,
5567
- `CREATE UNIQUE INDEX ${q2(`${step.table}_AB_unique`)} ON ${publicName(step.table)} ("A", "B");`,
5568
- `CREATE INDEX ${q2(`${step.table}_B_index`)} ON ${publicName(step.table)} ("B");`,
5569
- `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(`${step.table}_A_fkey`)} FOREIGN KEY ("A") REFERENCES ${publicName(step.a.table)} (${q2(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`,
5570
- `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(`${step.table}_B_fkey`)} FOREIGN KEY ("B") REFERENCES ${publicName(step.b.table)} (${q2(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`
5828
+ `CREATE UNIQUE INDEX ${q2(names.uniqueIndex)} ON ${publicName(step.table)} ("A", "B");`,
5829
+ `CREATE INDEX ${q2(names.indexB)} ON ${publicName(step.table)} ("B");`,
5830
+ `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(names.foreignKeyA)} FOREIGN KEY ("A") REFERENCES ${publicName(step.a.table)} (${q2(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`,
5831
+ `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(names.foreignKeyB)} FOREIGN KEY ("B") REFERENCES ${publicName(step.b.table)} (${q2(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`
5571
5832
  ];
5572
5833
  }
5573
5834
  case "addPrimaryKey": {
5574
5835
  const cols = step.columns.map((column) => q2(column)).join(", ");
5575
5836
  return [
5576
- `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.constraintName ?? `${step.table}_pkey`)} PRIMARY KEY (${cols});`
5837
+ `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.constraintName ?? defaultPrimaryKeyName3({ table: step.table, dialect: "postgres" }))} PRIMARY KEY (${cols});`
5577
5838
  ];
5578
5839
  }
5579
5840
  case "dropPrimaryKey":
5580
- return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.constraintName ?? `${step.table}_pkey`)};`];
5841
+ return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.constraintName ?? defaultPrimaryKeyName3({ table: step.table, dialect: "postgres" }))};`];
5581
5842
  }
5582
5843
  }
5583
5844
  function columnDefSql(params) {
5584
5845
  const { field } = params;
5585
5846
  const name = q2(field.dbName ?? field.name);
5586
5847
  if (field.default?.kind === "autoincrement" && !isIdentityColumn({ field })) {
5587
- throw new VibeError26({
5848
+ throw new VibeError28({
5588
5849
  code: "VIBE_MIGRATION",
5589
5850
  message: `autoincrement default on "${field.name}" requires a non-list Int or BigInt column`,
5590
5851
  meta: { field: field.name }
@@ -5620,7 +5881,7 @@ function renderAlterColumn(params) {
5620
5881
  }
5621
5882
  if (step.changes.includes("default") || droppedDefault) {
5622
5883
  if (step.to.default?.kind === "autoincrement") {
5623
- throw new VibeError26({
5884
+ throw new VibeError28({
5624
5885
  code: "VIBE_MIGRATION",
5625
5886
  message: `cannot add autoincrement to existing column "${step.table}"."${step.column}" \u2014 drop and recreate the column instead`,
5626
5887
  meta: { table: step.table, column: step.column }
@@ -5635,11 +5896,11 @@ function publicName(name) {
5635
5896
  return `${q2("public")}.${q2(name)}`;
5636
5897
  }
5637
5898
  function q2(name) {
5638
- return postgresDialect7.quoteIdent({ name });
5899
+ return postgresDialect8.quoteIdent({ name });
5639
5900
  }
5640
5901
 
5641
5902
  // packages/migrate/src/ddl/sqlite.ts
5642
- import { VibeError as VibeError27, isEnumType as isEnumType8, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
5903
+ import { VibeError as VibeError29, implicitJoinTableObjectNames as implicitJoinTableObjectNames3, isEnumType as isEnumType8, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
5643
5904
  import { sqliteDialect as sqliteDialect3 } from "@vibeorm/sql";
5644
5905
 
5645
5906
  // packages/migrate/src/ddl/drop-order.ts
@@ -5779,7 +6040,7 @@ function renderSqliteSteps(params) {
5779
6040
  continue;
5780
6041
  const awaitsNewParent = [...toNorm?.tables.get(table)?.fks.values() ?? []].some((fk) => createdTables.has(fk.refTable));
5781
6042
  if (awaitsNewParent) {
5782
- throw new VibeError27({
6043
+ throw new VibeError29({
5783
6044
  code: "VIBE_MIGRATION",
5784
6045
  message: `cannot order this sqlite migration safely: rebuilding "${table}" must happen BEFORE the dropped table(s) it references (${[
5785
6046
  ...droppedTables
@@ -5808,7 +6069,7 @@ function renderSqliteSteps(params) {
5808
6069
  switch (step.kind) {
5809
6070
  case "addExclusion":
5810
6071
  case "dropExclusion":
5811
- throw new VibeError27({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
6072
+ throw new VibeError29({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
5812
6073
  case "createEnum":
5813
6074
  case "dropEnum":
5814
6075
  case "addEnumValue":
@@ -5837,12 +6098,13 @@ function renderSqliteSteps(params) {
5837
6098
  case "createJoinTable": {
5838
6099
  const aType = sqliteStorageType({ field: { ...step.a.field, isList: false } });
5839
6100
  const bType = sqliteStorageType({ field: { ...step.b.field, isList: false } });
6101
+ const names = implicitJoinTableObjectNames3({ table: step.table });
5840
6102
  statements.push(`CREATE TABLE ${q3(step.table)} (
5841
6103
  "A" ${aType} NOT NULL,
5842
6104
  "B" ${bType} NOT NULL,
5843
- CONSTRAINT ${q3(`${step.table}_A_fkey`)} FOREIGN KEY ("A") REFERENCES ${q3(step.a.table)} (${q3(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE,
5844
- CONSTRAINT ${q3(`${step.table}_B_fkey`)} FOREIGN KEY ("B") REFERENCES ${q3(step.b.table)} (${q3(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE
5845
- );`, `CREATE UNIQUE INDEX ${q3(`${step.table}_AB_unique`)} ON ${q3(step.table)} ("A", "B");`, `CREATE INDEX ${q3(`${step.table}_B_index`)} ON ${q3(step.table)} ("B");`);
6105
+ CONSTRAINT ${q3(names.foreignKeyA)} FOREIGN KEY ("A") REFERENCES ${q3(step.a.table)} (${q3(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE,
6106
+ CONSTRAINT ${q3(names.foreignKeyB)} FOREIGN KEY ("B") REFERENCES ${q3(step.b.table)} (${q3(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE
6107
+ );`, `CREATE UNIQUE INDEX ${q3(names.uniqueIndex)} ON ${q3(step.table)} ("A", "B");`, `CREATE INDEX ${q3(names.indexB)} ON ${q3(step.table)} ("B");`);
5846
6108
  break;
5847
6109
  }
5848
6110
  case "addColumn":
@@ -5893,7 +6155,7 @@ function renderSqliteSteps(params) {
5893
6155
  case "renameColumn": {
5894
6156
  const renamed = step.kind === "renameTable" ? step.from : step.table;
5895
6157
  if (rebuildSet.has(renamed) || step.kind === "renameTable" && rebuildSet.has(step.to)) {
5896
- throw new VibeError27({
6158
+ throw new VibeError29({
5897
6159
  code: "VIBE_MIGRATION",
5898
6160
  message: `sqlite cannot rename "${renamed}" in the same migration that rebuilds it \u2014 the table-rebuild recipe is written against a single table name. Split the rename and the column/constraint change into two migrations`,
5899
6161
  meta: { reason: "rename-ambiguous", table: renamed, dialect: "sqlite" }
@@ -5947,7 +6209,7 @@ function classifyRebuilds(params) {
5947
6209
  switch (step.kind) {
5948
6210
  case "addExclusion":
5949
6211
  case "dropExclusion":
5950
- throw new VibeError27({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
6212
+ throw new VibeError29({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
5951
6213
  case "alterColumn":
5952
6214
  case "dropForeignKey":
5953
6215
  case "addPrimaryKey":
@@ -6008,7 +6270,7 @@ function renderTableRebuild(params) {
6008
6270
  const source = from.tables.get(table);
6009
6271
  const target = to.tables.get(table);
6010
6272
  if (source === undefined || target === undefined) {
6011
- throw new VibeError27({
6273
+ throw new VibeError29({
6012
6274
  code: "VIBE_MIGRATION",
6013
6275
  message: `cannot rebuild "${table}" \u2014 the table is missing from the ${source === undefined ? "from" : "to"} schema`,
6014
6276
  meta: { table }
@@ -6143,7 +6405,7 @@ function columnDefSql2(params) {
6143
6405
  const { field, constraintTable, enums, inlinePkAutoincrement } = params;
6144
6406
  const name = field.dbName ?? field.name;
6145
6407
  if (field.default?.kind === "autoincrement" && !inlinePkAutoincrement) {
6146
- throw new VibeError27({
6408
+ throw new VibeError29({
6147
6409
  code: "VIBE_MIGRATION",
6148
6410
  message: `autoincrement on sqlite requires "${field.name}" to be the single-column Int or BigInt primary key`,
6149
6411
  meta: { field: field.name }
@@ -6162,7 +6424,7 @@ function columnDefSql2(params) {
6162
6424
  const enumName = field.type.enum;
6163
6425
  const values = resolveEnumValues({ name: enumName, enums });
6164
6426
  if (values === undefined) {
6165
- throw new VibeError27({
6427
+ throw new VibeError29({
6166
6428
  code: "VIBE_MIGRATION",
6167
6429
  message: `enum "${enumName}" on column "${field.name}" is not declared in the schema \u2014 sqlite rendering needs the target schema's enums for the CHECK constraint`,
6168
6430
  meta: { field: field.name, enum: enumName }
@@ -6197,7 +6459,7 @@ function requireSchemas(params) {
6197
6459
  const { step, fromNorm, toNorm } = params;
6198
6460
  if (fromNorm !== undefined && toNorm !== undefined)
6199
6461
  return;
6200
- throw new VibeError27({
6462
+ throw new VibeError29({
6201
6463
  code: "VIBE_MIGRATION",
6202
6464
  message: `sqlite step "${describeStep({ step })}" requires a table rebuild \u2014 renderSteps needs the { from, to } schemas to construct it`,
6203
6465
  meta: { step: step.kind }
@@ -6208,7 +6470,7 @@ function q3(name) {
6208
6470
  }
6209
6471
 
6210
6472
  // packages/migrate/src/ddl/mysql.ts
6211
- import { VibeError as VibeError28, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
6473
+ import { VibeError as VibeError30, implicitJoinTableObjectNames as implicitJoinTableObjectNames4, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
6212
6474
  import { mysqlDialect as mysqlDialect3 } from "@vibeorm/sql";
6213
6475
  function renderMysqlSteps(params) {
6214
6476
  for (const step of params.steps) {
@@ -6350,12 +6612,12 @@ ${lines.join(`,
6350
6612
  ];
6351
6613
  case "addExclusion":
6352
6614
  case "dropExclusion":
6353
- throw new VibeError28({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "mysql", feature: "exclusionConstraints" } });
6615
+ throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "mysql", feature: "exclusionConstraints" } });
6354
6616
  case "dropCheck":
6355
6617
  return [`ALTER TABLE ${q4(step.table)} DROP CHECK ${q4(step.name)};`];
6356
6618
  case "dropIndex": {
6357
6619
  if (step.table === undefined) {
6358
- throw new VibeError28({
6620
+ throw new VibeError30({
6359
6621
  code: "VIBE_MIGRATION",
6360
6622
  message: `dropIndex "${step.name}" carries no table \u2014 mysql's DROP INDEX requires one`,
6361
6623
  meta: { index: step.name }
@@ -6387,15 +6649,16 @@ ${lines.join(`,
6387
6649
  case "createJoinTable": {
6388
6650
  const aType = mysqlColumnTypeSql({ field: { ...step.a.field, isList: false }, enums });
6389
6651
  const bType = mysqlColumnTypeSql({ field: { ...step.b.field, isList: false }, enums });
6652
+ const names = implicitJoinTableObjectNames4({ table: step.table });
6390
6653
  return [
6391
6654
  `CREATE TABLE ${q4(step.table)} (
6392
6655
  \`A\` ${aType} NOT NULL,
6393
6656
  \`B\` ${bType} NOT NULL
6394
6657
  );`,
6395
- `CREATE UNIQUE INDEX ${q4(`${step.table}_AB_unique`)} ON ${q4(step.table)} (\`A\`, \`B\`);`,
6396
- `CREATE INDEX ${q4(`${step.table}_B_index`)} ON ${q4(step.table)} (\`B\`);`,
6397
- `ALTER TABLE ${q4(step.table)} ADD CONSTRAINT ${q4(`${step.table}_A_fkey`)} FOREIGN KEY (\`A\`) REFERENCES ${q4(step.a.table)} (${q4(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`,
6398
- `ALTER TABLE ${q4(step.table)} ADD CONSTRAINT ${q4(`${step.table}_B_fkey`)} FOREIGN KEY (\`B\`) REFERENCES ${q4(step.b.table)} (${q4(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`
6658
+ `CREATE UNIQUE INDEX ${q4(names.uniqueIndex)} ON ${q4(step.table)} (\`A\`, \`B\`);`,
6659
+ `CREATE INDEX ${q4(names.indexB)} ON ${q4(step.table)} (\`B\`);`,
6660
+ `ALTER TABLE ${q4(step.table)} ADD CONSTRAINT ${q4(names.foreignKeyA)} FOREIGN KEY (\`A\`) REFERENCES ${q4(step.a.table)} (${q4(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`,
6661
+ `ALTER TABLE ${q4(step.table)} ADD CONSTRAINT ${q4(names.foreignKeyB)} FOREIGN KEY (\`B\`) REFERENCES ${q4(step.b.table)} (${q4(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE;`
6399
6662
  ];
6400
6663
  }
6401
6664
  case "addPrimaryKey":
@@ -6411,7 +6674,7 @@ function columnDefSql3(params) {
6411
6674
  const name = q4(field.dbName ?? field.name);
6412
6675
  const autoincrement = field.default?.kind === "autoincrement";
6413
6676
  if (autoincrement && field.type !== "Int" && field.type !== "BigInt") {
6414
- throw new VibeError28({
6677
+ throw new VibeError30({
6415
6678
  code: "VIBE_MIGRATION",
6416
6679
  message: `autoincrement default on "${field.name}" requires a non-list Int or BigInt column`,
6417
6680
  meta: { field: field.name }
@@ -6433,7 +6696,7 @@ function renderAlterColumn2(params) {
6433
6696
  const { step, enums } = params;
6434
6697
  assertEnumStringTransition({ from: step.from, to: step.to, dialect: "mysql", table: step.table, column: step.column });
6435
6698
  if (step.to.default?.kind === "autoincrement" && step.from.default?.kind !== "autoincrement") {
6436
- throw new VibeError28({
6699
+ throw new VibeError30({
6437
6700
  code: "VIBE_MIGRATION",
6438
6701
  message: `cannot add autoincrement to existing column "${step.table}"."${step.column}" \u2014 drop and recreate the column instead`,
6439
6702
  meta: { table: step.table, column: step.column }
@@ -6465,32 +6728,32 @@ function declaredSqlitePreservation(params) {
6465
6728
  let to = params.to;
6466
6729
  if (params.from === undefined || to === undefined || (params.from.migrationObjects?.length ?? 0) === 0)
6467
6730
  return { to, restore, columns };
6468
- const invalid5 = sqliteInvalidatedTables({ steps: params.steps, from: params.from });
6731
+ const invalid = sqliteInvalidatedTables({ steps: params.steps, from: params.from });
6469
6732
  const retained = new Set((to.migrationObjects ?? []).map((object) => sqlObjectKey9({ identity: object.identity })));
6470
6733
  for (const object of params.from.migrationObjects ?? []) {
6471
6734
  const identity = object.identity;
6472
- if (!("table" in identity) || identity.table.namespace !== "main" || !invalid5.rebuilt.has(identity.table.name) || !retained.has(sqlObjectKey9({ identity })))
6735
+ if (!("table" in identity) || identity.table.namespace !== "main" || !invalid.rebuilt.has(identity.table.name) || !retained.has(sqlObjectKey9({ identity })))
6473
6736
  continue;
6474
6737
  const facts = object.expected?.facts;
6475
6738
  if (facts === undefined)
6476
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "SQLite rebuild requires independently declared preservation definitions", meta: { reason: "sqlite-preservation-unavailable", identity } });
6739
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "SQLite rebuild requires independently declared preservation definitions", meta: { reason: "sqlite-preservation-unavailable", identity } });
6477
6740
  if (identity.kind === "trigger" || identity.kind === "index") {
6478
6741
  if (identity.kind === "index" && to.models.some((model) => (model.dbName ?? model.name) === identity.table.name && model.indexes.some((index) => index.name === identity.name)))
6479
6742
  continue;
6480
6743
  if (typeof facts.definition !== "string")
6481
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "Missing SQLite restoration SQL", meta: { reason: "sqlite-preservation-unavailable", identity } });
6744
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "Missing SQLite restoration SQL", meta: { reason: "sqlite-preservation-unavailable", identity } });
6482
6745
  const statements = restore.get(identity.table.name) ?? [];
6483
6746
  statements.push(facts.definition);
6484
6747
  restore.set(identity.table.name, statements);
6485
6748
  } else if (identity.kind === "column" || identity.kind === "generatedColumn") {
6486
6749
  if (typeof facts.columnDefinition !== "string")
6487
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "Missing SQLite column clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6750
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "Missing SQLite column clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6488
6751
  const fields = columns.get(identity.table.name) ?? new Map;
6489
6752
  fields.set(identity.column, { sql: facts.columnDefinition, generated: Number(facts.generated) > 1 });
6490
6753
  columns.set(identity.table.name, fields);
6491
6754
  } else if (identity.kind === "columnDefault") {
6492
6755
  if (facts.definition !== null && typeof facts.definition !== "string")
6493
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "Missing SQLite default clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6756
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "Missing SQLite default clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6494
6757
  const expression = facts.definition;
6495
6758
  to = { ...to, models: to.models.map((model) => (model.dbName ?? model.name) !== identity.table.name ? model : { ...model, fields: model.fields.map((field) => {
6496
6759
  if ((field.dbName ?? field.name) !== identity.column)
@@ -6634,19 +6897,19 @@ function planMissingArtifacts(params) {
6634
6897
  }
6635
6898
  async function probeInstalledExtensionState(params) {
6636
6899
  const { executor, dialect, artifacts } = params;
6637
- const state2 = {};
6900
+ const state = {};
6638
6901
  if (dialect === "postgres" && artifacts.some((artifact) => artifact.owns.kind === "postgresExtension")) {
6639
6902
  const rows = await executor({ text: "SELECT extname FROM pg_extension" });
6640
- state2.pgExtensions = new Set(rows.map((row) => String(row["extname"])));
6903
+ state.pgExtensions = new Set(rows.map((row) => String(row["extname"])));
6641
6904
  }
6642
6905
  if (dialect === "sqlite" && artifacts.some((artifact) => artifact.owns.kind === "trigger")) {
6643
6906
  const rows = await executor({
6644
6907
  text: "SELECT name FROM sqlite_master WHERE type = 'trigger'",
6645
6908
  values: []
6646
6909
  });
6647
- state2.triggers = new Set(rows.map((row) => String(row["name"])));
6910
+ state.triggers = new Set(rows.map((row) => String(row["name"])));
6648
6911
  }
6649
- return state2;
6912
+ return state;
6650
6913
  }
6651
6914
  function artifactCreateSql(params) {
6652
6915
  return params.artifacts.flatMap((artifact) => [...artifact.create]);
@@ -6659,29 +6922,29 @@ function migrationRlsSecurityChanges(params) {
6659
6922
  return securityChangesOf({ steps: withRlsSteps({ from: params.down ? source.to : source.from, to: params.down ? source.from : source.to, steps: [] }) });
6660
6923
  }
6661
6924
  function containsNativeRlsSql(params) {
6662
- const { sql: sql2, dialect } = params;
6925
+ const { sql, dialect } = params;
6663
6926
  const tokens = [];
6664
6927
  let i = 0;
6665
- while (i < sql2.length) {
6666
- const ch = sql2[i];
6928
+ while (i < sql.length) {
6929
+ const ch = sql[i];
6667
6930
  if (/\s/.test(ch)) {
6668
6931
  i++;
6669
6932
  continue;
6670
6933
  }
6671
- if (sql2.startsWith("--", i) || dialect === "mysql" && ch === "#") {
6672
- const end = sql2.indexOf(`
6934
+ if (sql.startsWith("--", i) || dialect === "mysql" && ch === "#") {
6935
+ const end = sql.indexOf(`
6673
6936
  `, i);
6674
- i = end === -1 ? sql2.length : end + 1;
6937
+ i = end === -1 ? sql.length : end + 1;
6675
6938
  continue;
6676
6939
  }
6677
- if (sql2.startsWith("/*", i)) {
6940
+ if (sql.startsWith("/*", i)) {
6678
6941
  let depth = 1;
6679
6942
  i += 2;
6680
- while (i < sql2.length && depth > 0) {
6681
- if (sql2.startsWith("/*", i)) {
6943
+ while (i < sql.length && depth > 0) {
6944
+ if (sql.startsWith("/*", i)) {
6682
6945
  depth++;
6683
6946
  i += 2;
6684
- } else if (sql2.startsWith("*/", i)) {
6947
+ } else if (sql.startsWith("*/", i)) {
6685
6948
  depth--;
6686
6949
  i += 2;
6687
6950
  } else
@@ -6691,15 +6954,15 @@ function containsNativeRlsSql(params) {
6691
6954
  }
6692
6955
  if (ch === "'" || ch === '"' || ch === "`" || dialect === "sqlite" && ch === "[") {
6693
6956
  const endQuote = ch === "[" ? "]" : ch;
6694
- const backslash = dialect === "mysql" || ch === "'" && /(?:^|[^\w$])[eE]$/.test(sql2.slice(0, i));
6957
+ const backslash = dialect === "mysql" || ch === "'" && /(?:^|[^\w$])[eE]$/.test(sql.slice(0, i));
6695
6958
  i++;
6696
- while (i < sql2.length) {
6697
- if (backslash && sql2[i] === "\\") {
6959
+ while (i < sql.length) {
6960
+ if (backslash && sql[i] === "\\") {
6698
6961
  i += 2;
6699
6962
  continue;
6700
6963
  }
6701
- if (sql2[i] === endQuote) {
6702
- if (sql2[i + 1] === endQuote) {
6964
+ if (sql[i] === endQuote) {
6965
+ if (sql[i + 1] === endQuote) {
6703
6966
  i += 2;
6704
6967
  continue;
6705
6968
  }
@@ -6712,15 +6975,15 @@ function containsNativeRlsSql(params) {
6712
6975
  continue;
6713
6976
  }
6714
6977
  if (ch === "$") {
6715
- const tag = /^(?:\$\$|\$[A-Za-z_][A-Za-z_0-9]*\$)/.exec(sql2.slice(i))?.[0];
6978
+ const tag = /^(?:\$\$|\$[A-Za-z_][A-Za-z_0-9]*\$)/.exec(sql.slice(i))?.[0];
6716
6979
  if (tag !== undefined) {
6717
- const end = sql2.indexOf(tag, i + tag.length);
6718
- i = end === -1 ? sql2.length : end + tag.length;
6980
+ const end = sql.indexOf(tag, i + tag.length);
6981
+ i = end === -1 ? sql.length : end + tag.length;
6719
6982
  tokens.push("@");
6720
6983
  continue;
6721
6984
  }
6722
6985
  }
6723
- const word = /^[A-Za-z_][A-Za-z_0-9$]*/.exec(sql2.slice(i))?.[0];
6986
+ const word = /^[A-Za-z_][A-Za-z_0-9$]*/.exec(sql.slice(i))?.[0];
6724
6987
  tokens.push(word === undefined ? ch : word.toUpperCase());
6725
6988
  i += word?.length ?? 1;
6726
6989
  }
@@ -6730,14 +6993,14 @@ function containsNativeRlsSql(params) {
6730
6993
  });
6731
6994
  }
6732
6995
  function assertNativeMigrationMetadata(params) {
6733
- const native = params.migration.rls !== undefined || params.sql.some((sql2) => containsNativeRlsSql({ sql: sql2, dialect: params.dialect }));
6996
+ const native = params.migration.rls !== undefined || params.sql.some((sql) => containsNativeRlsSql({ sql, dialect: params.dialect }));
6734
6997
  if (!native)
6735
6998
  return;
6736
6999
  if (!DIALECT_CAPABILITIES3[params.dialect].nativeRowLevelSecurity) {
6737
- throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Native RLS migrations are unsupported on ${params.dialect}`, meta: { feature: "nativeRowLevelSecurity", dialect: params.dialect } });
7000
+ throw new VibeError32({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Native RLS migrations are unsupported on ${params.dialect}`, meta: { feature: "nativeRowLevelSecurity", dialect: params.dialect } });
6738
7001
  }
6739
7002
  if (params.migration.rls === undefined) {
6740
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Native RLS migration files require trusted rls.from/rls.to schema metadata. SQL alone cannot prove policy ownership or drift; regenerate with preserved security metadata.", meta: { reason: "rls-migration-metadata-required", migration: params.migration.name } });
7003
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Native RLS migration files require trusted rls.from/rls.to schema metadata. SQL alone cannot prove policy ownership or drift; regenerate with preserved security metadata.", meta: { reason: "rls-migration-metadata-required", migration: params.migration.name } });
6741
7004
  }
6742
7005
  }
6743
7006
  var PG_ADVISORY_LOCK_KEY = 1447645253;
@@ -6779,14 +7042,14 @@ function checksumOf(params) {
6779
7042
  return migrationChecksum(migration);
6780
7043
  }
6781
7044
  async function assertForwardStart(params) {
6782
- const state2 = params.migration.desiredState;
6783
- if (state2 === undefined)
7045
+ const state = params.migration.desiredState;
7046
+ if (state === undefined)
6784
7047
  return;
6785
- const report = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state2.from, ...params.probe === undefined ? {} : { probe: params.probe } });
7048
+ const report = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state.from, ...params.probe === undefined ? {} : { probe: params.probe } });
6786
7049
  if (report.inSync)
6787
7050
  return;
6788
- if (state2.down !== undefined) {
6789
- const restored = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state2.down, ...params.probe === undefined ? {} : { probe: params.probe } });
7051
+ if (state.down !== undefined) {
7052
+ const restored = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state.down, ...params.probe === undefined ? {} : { probe: params.probe } });
6790
7053
  if (restored.inSync)
6791
7054
  return;
6792
7055
  }
@@ -6806,7 +7069,7 @@ function generateMigration(params) {
6806
7069
  const steps = diffSchemas({ from: strippedFrom, to, dialect, ...params.renames === undefined ? {} : { renames: params.renames } });
6807
7070
  const coreSql = renderSteps({ steps, dialect, from: dialect === "sqlite" ? from : strippedFrom, to: dialect === "sqlite" ? sqlitePreservedSchema({ from, to, objects: [...from.migrationObjects ?? [], ...to.migrationObjects ?? []] }) : to });
6808
7071
  const missing = planMissingArtifacts({ introspected: from, artifacts: allArtifacts });
6809
- const sql2 = [
7072
+ const sql = [
6810
7073
  ...artifactCreateSql({
6811
7074
  artifacts: missing.filter((artifact) => artifact.owns.kind === "postgresExtension")
6812
7075
  }),
@@ -6816,18 +7079,18 @@ function generateMigration(params) {
6816
7079
  }),
6817
7080
  ...orderedMigrationObjects({ objects: to.migrationObjects ?? [] }).flatMap((object) => {
6818
7081
  if (object.dialect !== dialect)
6819
- throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Migration object ${object.id} requires ${object.dialect}` });
7082
+ throw new VibeError32({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Migration object ${object.id} requires ${object.dialect}` });
6820
7083
  const previous = (params.desiredState?.from.schema.migrationObjects ?? from.migrationObjects)?.find((entry) => entry.id === object.id);
6821
7084
  if (previous === undefined)
6822
7085
  return [...object.create];
6823
7086
  if (JSON.stringify(previous) !== JSON.stringify(object))
6824
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration-owned object ${object.id} changed; supply a reviewed forward SQL migration`, meta: { reason: "migration-object-replacement-required", id: object.id } });
7087
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration-owned object ${object.id} changed; supply a reviewed forward SQL migration`, meta: { reason: "migration-object-replacement-required", shadowReusable: true, id: object.id } });
6825
7088
  return [];
6826
7089
  })
6827
7090
  ];
6828
7091
  return {
6829
7092
  name,
6830
- sql: sql2,
7093
+ sql,
6831
7094
  destructive: steps.some((step) => step.destructive),
6832
7095
  ...securityChangesOf({ steps }).length === 0 ? {} : { securityChanges: securityChangesOf({ steps }) },
6833
7096
  ...from.rls === undefined && to.rls === undefined ? {} : { rls: { from, to } },
@@ -6835,6 +7098,25 @@ function generateMigration(params) {
6835
7098
  desiredState: params.desiredState ?? { version: 1, dialect, from: createDesiredState({ schema: from, dialect }), to: createDesiredState({ schema: to, dialect }) }
6836
7099
  };
6837
7100
  }
7101
+ async function withMigrationLock(params) {
7102
+ const runLocked = async (executor) => {
7103
+ await acquireLock({ executor, dialect: params.dialect });
7104
+ return Promise.resolve().then(async () => {
7105
+ await assertDatabaseNotShadow({ executor, dialect: params.dialect });
7106
+ return params.run(executor);
7107
+ }).then(async (value) => {
7108
+ await releaseLock({ executor, dialect: params.dialect });
7109
+ return value;
7110
+ }, (cause) => releaseLock({ executor, dialect: params.dialect }).then(() => {
7111
+ throw cause;
7112
+ }, (cleanupCause) => {
7113
+ if (cause instanceof VibeError32)
7114
+ throw new VibeError32({ code: cause.code, message: cause.message, meta: { ...cause.meta, cleanupCause }, cause });
7115
+ throw cause;
7116
+ }));
7117
+ };
7118
+ return params.executor.withSession === undefined ? runLocked(params.executor) : params.executor.withSession({ run: runLocked });
7119
+ }
6838
7120
  function validateMigrationReplay(params) {
6839
7121
  const dialect = params.dialect ?? "postgres";
6840
7122
  assertProbeMode({ dialect, probe: params.probe });
@@ -6845,8 +7127,8 @@ function validateMigrationReplay(params) {
6845
7127
  assertSupportedSelfManagedScript({ sql: migration.sql, migration: migration.name, direction: "up" });
6846
7128
  assertNamedRemovals({ removals: migration.desiredState?.unmanagedRemovals ?? [], approved: params.removeUnmanaged, acceptIntegrityLoss: params.acceptIntegrityLoss });
6847
7129
  if (migration.desiredState !== undefined) {
6848
- const state2 = migration.desiredState;
6849
- assertRemovalAuthorization({ steps: diffSchemas({ from: state2.from.schema, to: state2.to.schema, dialect }), previous: state2.from, dialect, namespace: dialect === "sqlite" ? "main" : "public", ...params.acceptIntegrityLoss === undefined ? {} : { acceptIntegrityLoss: params.acceptIntegrityLoss } });
7130
+ const state = migration.desiredState;
7131
+ assertRemovalAuthorization({ steps: diffSchemas({ from: state.from.schema, to: state.to.schema, dialect }), previous: state.from, dialect, namespace: dialect === "sqlite" ? "main" : "public", ...params.acceptIntegrityLoss === undefined ? {} : { acceptIntegrityLoss: params.acceptIntegrityLoss } });
6850
7132
  }
6851
7133
  assertSecurityAcknowledgement({ securityChanges: [...migration.securityChanges ?? [], ...migrationRlsSecurityChanges({ migration, down: false })], ...params.acceptSecurityChanges === undefined ? {} : { acceptSecurityChanges: params.acceptSecurityChanges } });
6852
7134
  }
@@ -6858,11 +7140,11 @@ function assertMigrationMetadata(params) {
6858
7140
  assertModuleOwnership({ origin: migration.moduleOrigin, desiredState: migration.desiredState });
6859
7141
  }
6860
7142
  if (migration.desiredStatePending === true)
6861
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration ${migration.name} has unfinalized desired state; finalize its reviewed before/after declarations before applying`, meta: { reason: "desired-state-unfinalized", migration: migration.name } });
7143
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration ${migration.name} has unfinalized desired state; finalize its reviewed before/after declarations before applying`, meta: { reason: "desired-state-unfinalized", migration: migration.name } });
6862
7144
  if (migration.desiredState !== undefined) {
6863
7145
  assertDesiredState({ value: migration.desiredState, migration: migration.name });
6864
7146
  if (migration.desiredState.dialect !== dialect)
6865
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch", migration: migration.name } });
7147
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch", migration: migration.name } });
6866
7148
  }
6867
7149
  assertNativeMigrationMetadata({ migration, sql: migration.sql, dialect });
6868
7150
  assertExecutable({ migration, execution: migration.execution, sql: migration.sql, dialect });
@@ -6871,23 +7153,19 @@ async function applyMigrations(params) {
6871
7153
  const { executor, migrations } = params;
6872
7154
  const dialect = params.dialect ?? "postgres";
6873
7155
  if (params.history !== undefined && params.history !== "complete" && params.history !== "subset")
6874
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Unknown migration history validation mode", meta: { reason: "history-mode-invalid" } });
7156
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Unknown migration history validation mode", meta: { reason: "history-mode-invalid" } });
6875
7157
  if (params.history === "complete")
6876
7158
  assertDistinctMigrationNames({ migrations });
6877
7159
  for (const migration of migrations)
6878
7160
  assertMigrationMetadata({ migration, dialect });
6879
- if (executor.withSession !== undefined) {
6880
- return executor.withSession({ run: (session) => applyMigrations({ ...params, executor: session }) });
6881
- }
6882
- await acquireLock({ executor, dialect });
6883
- try {
6884
- const moduleRecords = migrations.some((migration) => migration.moduleOrigin !== undefined) ? await readModuleJournal({ executor, dialect }) : undefined;
6885
- const recorded = moduleRecords === undefined ? await recordedRows({ executor, dialect }) : new Map([...moduleRecords].map(([name, record3]) => [name, record3.row]));
6886
- if (moduleRecords !== undefined) {
7161
+ return withMigrationLock({ executor, dialect, run: async (executor) => {
7162
+ let moduleRecords = await readModuleJournal({ executor, dialect });
7163
+ const recorded = new Map([...moduleRecords].map(([name, record]) => [name, record.row]));
7164
+ if (migrations.some((migration) => migration.moduleOrigin !== undefined) || [...moduleRecords.values()].some((record) => record.entry !== undefined)) {
6887
7165
  assertModuleUpgradeHistory({ migrations, records: moduleRecords });
6888
7166
  const namespace = await migrationNamespace({ executor, dialect });
6889
7167
  if (migrations.some((migration) => migration.moduleOrigin !== undefined && moduleNamespace({ origin: migration.moduleOrigin }) !== namespace))
6890
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Module placement differs from the active database namespace", meta: { reason: "module-placement-mismatch" } });
7168
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Module placement differs from the active database namespace", meta: { reason: "module-placement-mismatch" } });
6891
7169
  }
6892
7170
  if (params.history === "complete")
6893
7171
  assertCompleteHistory({ migrations, recorded, dialect });
@@ -6898,7 +7176,7 @@ async function applyMigrations(params) {
6898
7176
  });
6899
7177
  validateMigrationReplay({ ...params, migrations: pending, dialect });
6900
7178
  await ensureMigrationsTable({ executor, dialect });
6901
- if (moduleRecords !== undefined)
7179
+ if (migrations.some((migration) => migration.moduleOrigin !== undefined))
6902
7180
  await ensureModuleJournal({ executor, dialect });
6903
7181
  const applied = [];
6904
7182
  const skipped = [];
@@ -6908,7 +7186,7 @@ async function applyMigrations(params) {
6908
7186
  await assertLiveModuleOwnership({ executor, origin: migration.moduleOrigin, resume: stored !== undefined });
6909
7187
  if (stored !== undefined) {
6910
7188
  if (stored.statementIndex < 0) {
6911
- throw new VibeError30({
7189
+ throw new VibeError32({
6912
7190
  code: "VIBE_MIGRATION",
6913
7191
  message: `migration "${migration.name}" is mid-rollback (${-stored.statementIndex - 1} down statement(s) done) \u2014 finish it with \`migrate down\` or repair with resolveMigration before applying`,
6914
7192
  meta: { migration: migration.name, statementIndex: stored.statementIndex }
@@ -6929,11 +7207,14 @@ async function applyMigrations(params) {
6929
7207
  dialect,
6930
7208
  migration,
6931
7209
  start: stored.statementIndex,
7210
+ moduleOrigins: applicationModuleOrigins({ migration, records: moduleRecords }),
6932
7211
  ...params.probe === undefined ? {} : { probe: params.probe },
6933
7212
  insertRecord: false,
6934
7213
  ...stored.error === undefined ? {} : { storedError: stored.error }
6935
7214
  })
6936
7215
  });
7216
+ if (migration.moduleOrigin !== undefined)
7217
+ moduleRecords = await readModuleJournal({ executor, dialect });
6937
7218
  applied.push(migration.name);
6938
7219
  continue;
6939
7220
  }
@@ -6942,11 +7223,13 @@ async function applyMigrations(params) {
6942
7223
  executor,
6943
7224
  dialect,
6944
7225
  ...migration.execution === undefined ? {} : { execution: migration.execution },
6945
- run: () => runNonTransactional({ executor, dialect, migration, start: 0, insertRecord: true, ...params.probe === undefined ? {} : { probe: params.probe } })
7226
+ run: () => runNonTransactional({ executor, dialect, migration, moduleOrigins: applicationModuleOrigins({ migration, records: moduleRecords }), start: 0, insertRecord: true, ...params.probe === undefined ? {} : { probe: params.probe } })
6946
7227
  });
6947
7228
  } else {
6948
- await runTransactional({ executor, dialect, migration, ...params.probe === undefined ? {} : { probe: params.probe } });
7229
+ await runTransactional({ executor, dialect, migration, moduleOrigins: applicationModuleOrigins({ migration, records: moduleRecords }), ...params.probe === undefined ? {} : { probe: params.probe } });
6949
7230
  }
7231
+ if (migration.moduleOrigin !== undefined)
7232
+ moduleRecords = await readModuleJournal({ executor, dialect });
6950
7233
  applied.push(migration.name);
6951
7234
  }
6952
7235
  const final = migrations.at(-1);
@@ -6961,9 +7244,7 @@ async function applyMigrations(params) {
6961
7244
  }
6962
7245
  }
6963
7246
  return { applied, skipped };
6964
- } finally {
6965
- await releaseLock({ executor, dialect });
6966
- }
7247
+ } });
6967
7248
  }
6968
7249
  async function migrationStatus(params) {
6969
7250
  const { executor, migrations } = params;
@@ -7033,19 +7314,14 @@ function classifyJournal(params) {
7033
7314
  return journal;
7034
7315
  }
7035
7316
  async function resolveMigration(params) {
7036
- if (params.executor.withSession !== undefined) {
7037
- return params.executor.withSession({ run: (executor2) => resolveMigration({ ...params, executor: executor2 }) });
7038
- }
7039
- const { executor } = params;
7040
7317
  const dialect = params.dialect ?? "postgres";
7041
- await acquireLock({ executor, dialect });
7042
- await repairMigration({ ...params, executor, dialect }).finally(() => releaseLock({ executor, dialect }));
7318
+ await withMigrationLock({ executor: params.executor, dialect, run: (executor) => repairMigration({ ...params, executor, dialect }) });
7043
7319
  }
7044
7320
  async function repairMigration(params) {
7045
7321
  const { executor, name, dialect } = params;
7046
7322
  const moduleRecord = (await readModuleJournal({ executor, dialect })).get(name);
7047
7323
  if (moduleRecord?.entry !== undefined)
7048
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Module history cannot be marked applied or deleted without verified module recovery", meta: { reason: "module-resolution-required", moduleId: moduleRecord.entry.migration.moduleOrigin.moduleId } });
7324
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Module history cannot be marked applied or deleted without verified module recovery", meta: { reason: "module-resolution-required", moduleId: moduleRecord.entry.migration.moduleOrigin.moduleId } });
7049
7325
  await ensureMigrationsTable({ executor, dialect });
7050
7326
  if (params.as === "applied") {
7051
7327
  const insert = `INSERT INTO ${q5(dialect, MIGRATIONS_TABLE_NAME)} (${q5(dialect, "name")}, ${q5(dialect, "checksum")}, ${q5(dialect, "statement_index")}) VALUES (${ph(dialect, 1)}, ${ph(dialect, 2)}, ${RESOLVED_STATEMENT_INDEX})`;
@@ -7062,38 +7338,30 @@ async function rollbackMigration(params) {
7062
7338
  const { executor, migration } = params;
7063
7339
  const dialect = params.dialect ?? "postgres";
7064
7340
  const downSql = validateRollbackFile({ ...params, dialect });
7065
- if (executor.withSession !== undefined) {
7066
- return executor.withSession({ run: (session) => rollbackMigration({ ...params, executor: session }) });
7067
- }
7068
- await acquireLock({ executor, dialect });
7069
- await Promise.resolve().then(async () => {
7070
- const recorded = await recordedRows({ executor, dialect, modules: migration.moduleOrigin !== undefined });
7341
+ await withMigrationLock({ executor, dialect, run: async (executor) => {
7342
+ const recorded = await recordedRows({ executor, dialect, modules: true });
7071
7343
  const stored = assertRollbackRecord({ migration, stored: recorded.get(migration.name), dialect });
7072
7344
  const newest = [...recorded.keys()].at(-1);
7073
7345
  if (newest !== migration.name)
7074
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${migration.name}" is not the newest recorded migration; select rollback again`, meta: { reason: "rollback-not-latest", migration: migration.name, newest } });
7346
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${migration.name}" is not the newest recorded migration; select rollback again`, meta: { reason: "rollback-not-latest", migration: migration.name, newest } });
7075
7347
  await validateRollbackRecovery({ executor, migration, downSql, stored, dialect });
7076
- await executeRollback({ ...params, dialect, downSql, stored });
7077
- }).finally(() => releaseLock({ executor, dialect }));
7348
+ await executeRollback({ ...params, executor, dialect, downSql, stored });
7349
+ } });
7078
7350
  }
7079
7351
  async function rollbackMigrations(params) {
7080
7352
  const { executor, migrations } = params;
7081
7353
  const dialect = params.dialect ?? "postgres";
7082
7354
  assertDistinctMigrationNames({ migrations });
7083
- if (executor.withSession !== undefined) {
7084
- return executor.withSession({ run: (session) => rollbackMigrations({ ...params, executor: session }) });
7085
- }
7086
- await acquireLock({ executor, dialect });
7087
- return Promise.resolve().then(async () => {
7088
- const recorded = await recordedRows({ executor, dialect, modules: migrations.some((migration) => migration.moduleOrigin !== undefined) });
7355
+ return withMigrationLock({ executor, dialect, run: async (executor) => {
7356
+ const recorded = await recordedRows({ executor, dialect, modules: true });
7089
7357
  const journal = classifyJournal({ migrations, recorded, dialect });
7090
7358
  const byName = new Map(migrations.map((migration) => [migration.name, migration]));
7091
7359
  let start = Math.max(0, journal.length - 1);
7092
7360
  if (params.to !== undefined) {
7093
- const target = journal.findIndex((row2) => row2.name === params.to);
7361
+ const target = journal.findIndex((row) => row.name === params.to);
7094
7362
  const row = journal[target];
7095
7363
  if (row?.state !== "applied")
7096
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Rollback target "${params.to}" is not a known applied migration`, meta: { reason: "rollback-target-invalid", to: params.to, state: row?.state } });
7364
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Rollback target "${params.to}" is not a known applied migration`, meta: { reason: "rollback-target-invalid", to: params.to, state: row?.state } });
7097
7365
  assertMigrationMetadata({ migration: byName.get(row.name), dialect });
7098
7366
  start = target + 1;
7099
7367
  }
@@ -7101,7 +7369,7 @@ async function rollbackMigrations(params) {
7101
7369
  for (const row of journal.slice(start).reverse()) {
7102
7370
  const migration = byName.get(row.name);
7103
7371
  if (migration === undefined)
7104
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Cannot roll back "${row.name}" without its migration file`, meta: { reason: "rollback-file-missing", migration: row.name } });
7372
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Cannot roll back "${row.name}" without its migration file`, meta: { reason: "rollback-file-missing", migration: row.name } });
7105
7373
  const stored = assertRollbackRecord({ migration, stored: recorded.get(row.name), dialect });
7106
7374
  const downSql = validateRollbackFile({ ...params, migration, dialect });
7107
7375
  plan.push({ migration, downSql, stored });
@@ -7110,28 +7378,28 @@ async function rollbackMigrations(params) {
7110
7378
  await validateRollbackRecovery({ executor, dialect, ...entry });
7111
7379
  const rolledBack = [];
7112
7380
  for (const entry of plan) {
7113
- await executeRollback({ ...params, dialect, ...entry });
7381
+ await executeRollback({ ...params, executor, dialect, ...entry });
7114
7382
  rolledBack.push(entry.migration.name);
7115
7383
  }
7116
7384
  return { rolledBack };
7117
- }).finally(() => releaseLock({ executor, dialect }));
7385
+ } });
7118
7386
  }
7119
7387
  function validateRollbackFile(params) {
7120
7388
  const { migration, dialect } = params;
7121
7389
  if (migration.desiredStatePending === true)
7122
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Unfinalized desired state cannot be rolled back", meta: { reason: "desired-state-unfinalized", migration: migration.name } });
7390
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Unfinalized desired state cannot be rolled back", meta: { reason: "desired-state-unfinalized", migration: migration.name } });
7123
7391
  if (migration.moduleOrigin !== undefined) {
7124
7392
  assertMaterializedModuleMigration({ migration });
7125
7393
  assertModuleOwnership({ origin: migration.moduleOrigin, desiredState: migration.desiredState });
7126
7394
  }
7127
7395
  const downSql = migration.downSql;
7128
7396
  if (downSql === undefined)
7129
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" has no down.sql; roll it back manually, then repair with resolveMigration (as: "rolled-back")`, meta: { reason: "rollback-down-missing", migration: migration.name } });
7397
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" has no down.sql; roll it back manually, then repair with resolveMigration (as: "rolled-back")`, meta: { reason: "rollback-down-missing", migration: migration.name } });
7130
7398
  assertProbeMode({ dialect, probe: params.probe });
7131
7399
  if (migration.desiredState !== undefined) {
7132
7400
  assertDesiredState({ value: migration.desiredState, migration: migration.name });
7133
7401
  if (migration.desiredState.dialect !== dialect)
7134
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch" } });
7402
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch" } });
7135
7403
  assertRemovalAuthorization({ steps: diffSchemas({ from: migration.desiredState.to.schema, to: (migration.desiredState.down ?? migration.desiredState.from).schema, dialect }), previous: migration.desiredState.to, dialect, namespace: dialect === "sqlite" ? "main" : "public", ...params.acceptIntegrityLoss === undefined ? {} : { acceptIntegrityLoss: params.acceptIntegrityLoss } });
7136
7404
  }
7137
7405
  assertNativeMigrationMetadata({ migration, sql: downSql, dialect });
@@ -7144,10 +7412,10 @@ function validateRollbackFile(params) {
7144
7412
  function assertRollbackRecord(params) {
7145
7413
  const { migration, stored, dialect } = params;
7146
7414
  if (stored === undefined)
7147
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is not recorded as applied; nothing to roll back`, meta: { migration: migration.name } });
7415
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is not recorded as applied; nothing to roll back`, meta: { migration: migration.name } });
7148
7416
  assertChecksumMatches({ migration, stored: stored.checksum });
7149
7417
  if (stored.statementIndex >= 0 && (!isCompleteRecord({ dialect, migration, stored }) || stored.error !== undefined))
7150
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is only partially applied or has an unresolved error; its down mirrors the FULL up. Finish or repair with resolveMigration`, meta: { reason: "rollback-partial-up", migration: migration.name, statementIndex: stored.statementIndex } });
7418
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is only partially applied or has an unresolved error; its down mirrors the FULL up. Finish or repair with resolveMigration`, meta: { reason: "rollback-partial-up", migration: migration.name, statementIndex: stored.statementIndex } });
7151
7419
  return stored;
7152
7420
  }
7153
7421
  async function validateRollbackRecovery(params) {
@@ -7156,7 +7424,7 @@ async function validateRollbackRecovery(params) {
7156
7424
  return;
7157
7425
  const start = -stored.statementIndex - 1;
7158
7426
  if (start > downSql.length)
7159
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Rollback progress exceeds its statement count", meta: { reason: "rollback-progress-invalid", migration: migration.name } });
7427
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Rollback progress exceeds its statement count", meta: { reason: "rollback-progress-invalid", migration: migration.name } });
7160
7428
  if (dialect === "sqlite" && usesSelfManagedTransactions({ sql: downSql }))
7161
7429
  assertSelfManagedResumeSafe({ sql: downSql, start, migration: migration.name, direction: "down" });
7162
7430
  if (!marksInflight({ dialect, execution: migration.downExecution }) || start >= downSql.length)
@@ -7169,16 +7437,17 @@ async function validateRollbackRecovery(params) {
7169
7437
  }
7170
7438
  async function executeRollback(params) {
7171
7439
  const { executor, dialect, migration, downSql, stored } = params;
7440
+ const moduleOrigins = applicationModuleOrigins({ migration, records: await readModuleJournal({ executor, dialect }) });
7172
7441
  if (usesStatementBookkeeping({ dialect, sql: downSql, ...migration.downExecution === undefined ? {} : { execution: migration.downExecution } })) {
7173
7442
  const start = stored.statementIndex < 0 ? -stored.statementIndex - 1 : 0;
7174
7443
  await withSessionLimits({
7175
7444
  executor,
7176
7445
  dialect,
7177
7446
  execution: migration.downExecution,
7178
- run: () => runNonTransactionalDown({ executor, dialect, migration, downSql, start, probe: params.probe, storedError: stored.error })
7447
+ run: () => runNonTransactionalDown({ executor, dialect, migration, moduleOrigins, downSql, start, probe: params.probe, storedError: stored.error })
7179
7448
  });
7180
7449
  } else
7181
- await runTransactionalDown({ executor, dialect, migration, downSql, probe: params.probe });
7450
+ await runTransactionalDown({ executor, dialect, migration, moduleOrigins, downSql, probe: params.probe });
7182
7451
  }
7183
7452
  async function runTransactionalDown(params) {
7184
7453
  const { executor, dialect, migration, downSql } = params;
@@ -7190,14 +7459,15 @@ async function runTransactionalDown(params) {
7190
7459
  const limits = migration.downExecution;
7191
7460
  if (wrap && dialect === "postgres" && limits !== undefined) {
7192
7461
  if ((limits.lockTimeoutMs ?? 0) > 0)
7193
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7462
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7194
7463
  if ((limits.statementTimeoutMs ?? 0) > 0)
7195
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7464
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7196
7465
  }
7197
7466
  if (migration.desiredState !== undefined)
7198
7467
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7199
7468
  if (migration.rls !== undefined)
7200
7469
  await introspectPostgres({ executor, rlsSchema: migration.rls.to, inTransaction: true, requireInstalledRls: true });
7470
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7201
7471
  for (const statement of downSql) {
7202
7472
  await executeStatement({ executor, statement, dialect });
7203
7473
  }
@@ -7205,6 +7475,7 @@ async function runTransactionalDown(params) {
7205
7475
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7206
7476
  if (migration.rls !== undefined)
7207
7477
  await introspectPostgres({ executor, rlsSchema: migration.rls.from, inTransaction: true, requireInstalledRls: true });
7478
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7208
7479
  await executor({
7209
7480
  text: `DELETE FROM ${q5(dialect, MIGRATIONS_TABLE_NAME)} WHERE ${q5(dialect, "name")} = ${ph(dialect, 1)}`,
7210
7481
  values: [migration.name]
@@ -7219,7 +7490,7 @@ async function runTransactionalDown(params) {
7219
7490
  } else {
7220
7491
  await cleanupSelfManagedFailure({ executor });
7221
7492
  }
7222
- throw new VibeError30({
7493
+ throw new VibeError32({
7223
7494
  code: "VIBE_MIGRATION",
7224
7495
  message: `rollback of "${migration.name}" failed: ${error instanceof Error ? error.message : String(error)}`,
7225
7496
  meta: { migration: migration.name, ...timeoutDiagnostic({ error }) },
@@ -7251,6 +7522,7 @@ async function runNonTransactionalDown(params) {
7251
7522
  throw uncertainStatement({ migration: migration.name, statements: downSql, index: start, dialect, direction: "down" });
7252
7523
  }
7253
7524
  const resumeState = resumeOperation === undefined ? undefined : await establishOperationState({ executor, dialect, operation: resumeOperation });
7525
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7254
7526
  if (start === 0) {
7255
7527
  if (migration.desiredState !== undefined)
7256
7528
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
@@ -7260,6 +7532,8 @@ async function runNonTransactionalDown(params) {
7260
7532
  if (resumeOperation !== undefined && resumeState === "satisfied") {
7261
7533
  if (start + 1 === downSql.length && migration.desiredState !== undefined)
7262
7534
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7535
+ if (start + 1 === downSql.length)
7536
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7263
7537
  await recordProgress(start + 1);
7264
7538
  cursor = start + 1;
7265
7539
  }
@@ -7278,11 +7552,14 @@ async function runNonTransactionalDown(params) {
7278
7552
  if (commitsBlock) {
7279
7553
  if (migration.desiredState !== undefined && downSql.slice(index + 1).every((statement) => /^\s*PRAGMA\s+foreign_keys\s*=\s*ON\s*;?\s*$/i.test(statement)))
7280
7554
  assertMigrationState({ report: await verifySqliteTransitionBeforeRestore({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7555
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe, sqliteRestorePending: true });
7281
7556
  await recordProgress(index + 1);
7282
7557
  }
7283
7558
  await executeStatement({ executor, statement: downSql[index], dialect });
7284
7559
  if (index === downSql.length - 1 && migration.desiredState !== undefined)
7285
7560
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7561
+ if (index === downSql.length - 1)
7562
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7286
7563
  if (atomic) {
7287
7564
  await recordProgress(index + 1);
7288
7565
  await executor({ text: "COMMIT" });
@@ -7296,7 +7573,7 @@ async function runNonTransactionalDown(params) {
7296
7573
  values: [marks ? `${INFLIGHT_PREFIX}${index}` : error instanceof Error ? error.message : String(error), migration.name]
7297
7574
  });
7298
7575
  } catch {}
7299
- throw new VibeError30({
7576
+ throw new VibeError32({
7300
7577
  code: "VIBE_MIGRATION",
7301
7578
  message: `rollback of "${migration.name}" failed at down statement ${index + 1} of ${downSql.length}: ${error instanceof Error ? error.message : String(error)}. ${marks ? "The statement outcome is unknown; inspect its effects before resolving or retrying." : "Progress is recorded; re-running the rollback resumes from this statement."}`,
7302
7579
  meta: { migration: migration.name, statementIndex: index, ...marks ? { outcome: "unknown" } : {}, ...timeoutDiagnostic({ error }) },
@@ -7323,11 +7600,12 @@ async function runTransactional(params) {
7323
7600
  const limits = migration.execution;
7324
7601
  if (wrap && dialect === "postgres" && limits !== undefined) {
7325
7602
  if ((limits.lockTimeoutMs ?? 0) > 0)
7326
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7603
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7327
7604
  if ((limits.statementTimeoutMs ?? 0) > 0)
7328
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7605
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7329
7606
  }
7330
7607
  await assertForwardStart({ executor, dialect, migration, ...params.probe === undefined ? {} : { probe: params.probe } });
7608
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7331
7609
  if (migration.rls !== undefined)
7332
7610
  await introspectPostgres({ executor, rlsSchema: migration.rls.from, inTransaction: true, requireInstalledRls: true });
7333
7611
  let statementIndex = 0;
@@ -7339,6 +7617,7 @@ async function runTransactional(params) {
7339
7617
  assertMigrationState({ report: await verifyMigrationTransition({ executor, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, dialect, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7340
7618
  if (migration.rls !== undefined)
7341
7619
  await introspectPostgres({ executor, rlsSchema: migration.rls.to, inTransaction: true, requireInstalledRls: true });
7620
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7342
7621
  if (migration.moduleOrigin !== undefined)
7343
7622
  await insertModuleJournal({ executor, dialect, migration, index: statementIndex, complete: true });
7344
7623
  else
@@ -7356,7 +7635,7 @@ async function runTransactional(params) {
7356
7635
  } else {
7357
7636
  await cleanupSelfManagedFailure({ executor });
7358
7637
  }
7359
- throw new VibeError30({
7638
+ throw new VibeError32({
7360
7639
  code: "VIBE_MIGRATION",
7361
7640
  message: `migration "${migration.name}" failed: ${error instanceof Error ? error.message : String(error)}`,
7362
7641
  meta: { migration: migration.name },
@@ -7376,6 +7655,7 @@ async function runNonTransactional(params) {
7376
7655
  const declared = execution?.transaction === "none";
7377
7656
  const marks = marksInflight({ dialect, ...execution === undefined ? {} : { execution } });
7378
7657
  const start = selfManaged ? selfManagedResumeStart({ sql: migration.sql, start: params.start }) : params.start;
7658
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7379
7659
  if (insertRecord) {
7380
7660
  if (migration.desiredState !== undefined) {
7381
7661
  await assertForwardStart({ executor, dialect, migration, ...params.probe === undefined ? {} : { probe: params.probe } });
@@ -7400,10 +7680,12 @@ async function runNonTransactional(params) {
7400
7680
  if (marks && !insertRecord && start < migration.sql.length) {
7401
7681
  const operation = declared ? operationFor({ ...execution === undefined ? {} : { execution }, statement: start }) : undefined;
7402
7682
  if (operation !== undefined) {
7403
- const state2 = await establishOperationState({ executor, dialect, operation });
7404
- if (state2 === "satisfied") {
7683
+ const state = await establishOperationState({ executor, dialect, operation });
7684
+ if (state === "satisfied") {
7405
7685
  if (start + 1 === migration.sql.length && migration.desiredState !== undefined)
7406
7686
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7687
+ if (start + 1 === migration.sql.length)
7688
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7407
7689
  await checkpoint(start + 1);
7408
7690
  cursor = start + 1;
7409
7691
  }
@@ -7426,11 +7708,14 @@ async function runNonTransactional(params) {
7426
7708
  if (commitsBlock) {
7427
7709
  if (migration.desiredState !== undefined && migration.sql.slice(index + 1).every((statement) => /^\s*PRAGMA\s+foreign_keys\s*=\s*ON\s*;?\s*$/i.test(statement)))
7428
7710
  assertMigrationState({ report: await verifySqliteTransitionBeforeRestore({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7711
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe, sqliteRestorePending: true });
7429
7712
  await checkpoint(index + 1);
7430
7713
  }
7431
7714
  await executeStatement({ executor, statement: migration.sql[index], dialect });
7432
7715
  if (index === migration.sql.length - 1 && migration.desiredState !== undefined)
7433
7716
  assertMigrationState({ report: await verifyMigrationTransition({ executor, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, dialect, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7717
+ if (index === migration.sql.length - 1)
7718
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7434
7719
  if (atomic) {
7435
7720
  await checkpoint(index + 1);
7436
7721
  await executor({ text: "COMMIT" });
@@ -7446,7 +7731,7 @@ async function runNonTransactional(params) {
7446
7731
  } catch {}
7447
7732
  const sqlState = sqlStateOf(error);
7448
7733
  const timeout = sqlState === "55P03" ? "lock-timeout" : sqlState === "57014" ? "statement-timeout" : undefined;
7449
- throw new VibeError30({
7734
+ throw new VibeError32({
7450
7735
  code: "VIBE_MIGRATION",
7451
7736
  message: timeout === "lock-timeout" ? `migration "${migration.name}" gave up waiting for a lock at statement ${index + 1} of ${migration.sql.length} (lock_timeout ${String(execution?.lockTimeoutMs ?? 0)}ms, SQLSTATE 55P03). Another session holds a conflicting lock; inspect the declared operation before retrying.` : timeout === "statement-timeout" ? `migration "${migration.name}" exceeded its statement_timeout at statement ${index + 1} of ${migration.sql.length} (${String(execution?.statementTimeoutMs ?? 0)}ms, SQLSTATE 57014). Inspect the declared operation before retrying.` : `migration "${migration.name}" failed at statement ${index + 1} of ${migration.sql.length}: ${error instanceof Error ? error.message : String(error)}. ${marks ? "The statement outcome is unknown; inspect its effects before resolving or retrying." : "Progress is recorded; re-running applyMigrations resumes from this statement."}`,
7452
7737
  meta: { migration: migration.name, statementIndex: index, ...marks ? { outcome: "unknown" } : {}, ...timeout === undefined ? {} : { reason: timeout, sqlState } },
@@ -7474,7 +7759,7 @@ async function acquireLock(params) {
7474
7759
  });
7475
7760
  const acquired = Number(rows[0]?.vibe_lock) === 1;
7476
7761
  if (!acquired) {
7477
- throw new VibeError30({
7762
+ throw new VibeError32({
7478
7763
  code: "VIBE_MIGRATION",
7479
7764
  message: `could not acquire the migration lock ('${MYSQL_LOCK_NAME}') within ${MYSQL_LOCK_TIMEOUT_SECONDS}s \u2014 another migration run is in progress`,
7480
7765
  meta: { lock: MYSQL_LOCK_NAME }
@@ -7484,13 +7769,11 @@ async function acquireLock(params) {
7484
7769
  }
7485
7770
  async function releaseLock(params) {
7486
7771
  const { executor, dialect } = params;
7487
- try {
7488
- if (dialect === "postgres") {
7489
- await executor({ text: `SELECT pg_advisory_unlock(${PG_ADVISORY_LOCK_KEY})` });
7490
- } else if (dialect === "mysql") {
7491
- await executor({ text: `SELECT RELEASE_LOCK('${MYSQL_LOCK_NAME}')` });
7492
- }
7493
- } catch {}
7772
+ if (dialect === "postgres") {
7773
+ await executor({ text: `SELECT pg_advisory_unlock(${PG_ADVISORY_LOCK_KEY})` });
7774
+ } else if (dialect === "mysql") {
7775
+ await executor({ text: `SELECT RELEASE_LOCK('${MYSQL_LOCK_NAME}')` });
7776
+ }
7494
7777
  }
7495
7778
  var INFLIGHT_PREFIX = "VIBE_INFLIGHT:";
7496
7779
  function inflightStatement(params) {
@@ -7511,7 +7794,7 @@ function uncertainStatement(params) {
7511
7794
  const subject = direction === "down" ? `rollback of "${migration}"` : `migration "${migration}"`;
7512
7795
  const position = `${direction === "down" ? "down statement" : "statement"} ${index + 1} of ${statements.length}`;
7513
7796
  const why = dialect === "mysql" ? "MySQL commits every statement on its own, so nothing outside the statement records whether it finished." : "That statement declares no operation whose effect recovery can read back from the catalog.";
7514
- return new VibeError30({
7797
+ return new VibeError32({
7515
7798
  code: "VIBE_MIGRATION",
7516
7799
  message: `${subject} was interrupted while ${position} was running. ${why} ` + "It may or may not have committed, and replaying it could apply it twice, so VibeORM stops here instead of guessing. " + 'Inspect what that statement did to the database, then follow "Recovering from a stopped migration" in docs/migrations.md: ' + `clear the \`error\` column of this migration's journal row if the statement did NOT land, set \`statement_index\` to ${direction === "down" ? -(index + 2) : index + 1} if it DID, ` + "or finish the whole migration by hand and record that with `vibeorm migrate resolve --applied`. " + `The statement was: ${statements[index].slice(0, 200)}`,
7517
7800
  meta: {
@@ -7529,7 +7812,7 @@ function assertExecutable(params) {
7529
7812
  if (execution === undefined || isDefaultExecution({ execution }))
7530
7813
  return;
7531
7814
  if (dialect !== "postgres") {
7532
- throw new VibeError30({
7815
+ throw new VibeError32({
7533
7816
  code: "VIBE_UNSUPPORTED_CAPABILITY",
7534
7817
  message: `migration "${migration.name}" declares explicit execution semantics (transaction: "${execution.transaction}"), which only the postgres runner implements \u2014 ${dialect} has no separate nontransactional regime to opt into`,
7535
7818
  meta: { reason: "nontransactional-unsupported", dialect, migration: migration.name, feature: "nontransactionalMigrations" }
@@ -7552,7 +7835,7 @@ async function withSessionLimits(params) {
7552
7835
  const statement = execution?.statementTimeoutMs ?? 0;
7553
7836
  if (dialect !== "postgres" || lock === 0 && statement === 0)
7554
7837
  return params.run();
7555
- const sqlDialect = getSqlDialect5({ dialect });
7838
+ const sqlDialect = getSqlDialect7({ dialect });
7556
7839
  const previous = (await executor({ text: renderMigrationSessionRead({ dialect: sqlDialect }).text, values: [] }))[0];
7557
7840
  if (lock > 0)
7558
7841
  await executor({ text: renderMigrationSessionSet({ dialect: sqlDialect, setting: "lock_timeout", milliseconds: lock }).text });
@@ -7571,12 +7854,12 @@ async function withSessionLimits(params) {
7571
7854
  }
7572
7855
  }
7573
7856
  function usesStatementBookkeeping(params) {
7574
- const { dialect, sql: sql2 } = params;
7857
+ const { dialect, sql } = params;
7575
7858
  if (params.execution?.transaction === "none")
7576
7859
  return true;
7577
7860
  if (!DIALECT_CAPABILITIES3[dialect].transactionalDdl)
7578
7861
  return true;
7579
- return dialect === "sqlite" && usesSelfManagedTransactions({ sql: sql2 });
7862
+ return dialect === "sqlite" && usesSelfManagedTransactions({ sql });
7580
7863
  }
7581
7864
  function isCompleteRecord(params) {
7582
7865
  const { dialect, migration, stored } = params;
@@ -7591,7 +7874,7 @@ function isCompleteRecord(params) {
7591
7874
  async function recordedRows(params) {
7592
7875
  const { executor, dialect } = params;
7593
7876
  if (params.modules === true)
7594
- return new Map([...await readModuleJournal({ executor, dialect })].map(([name, record3]) => [name, record3.row]));
7877
+ return new Map([...await readModuleJournal({ executor, dialect })].map(([name, record]) => [name, record.row]));
7595
7878
  const rows = await readJournalRows({ executor, dialect, query: {
7596
7879
  text: `SELECT ${q5(dialect, "name")}, ${q5(dialect, "checksum")}, ${q5(dialect, "statement_index")}, ${q5(dialect, "error")} FROM ${q5(dialect, MIGRATIONS_TABLE_NAME)} ORDER BY ${q5(dialect, "id")}`,
7597
7880
  values: []
@@ -7605,7 +7888,7 @@ function assertChecksumMatches(params) {
7605
7888
  const actual = checksumOf({ migration });
7606
7889
  if (stored === actual)
7607
7890
  return;
7608
- throw new VibeError30({
7891
+ throw new VibeError32({
7609
7892
  code: "VIBE_MIGRATION",
7610
7893
  message: `checksum mismatch for migration "${migration.name}" \u2014 its SQL changed after it was applied (recorded ${stored.slice(0, 12)}\u2026, current ${actual.slice(0, 12)}\u2026)`,
7611
7894
  meta: { migration: migration.name, recorded: stored, current: actual }
@@ -7616,7 +7899,7 @@ function assertResumable(params) {
7616
7899
  const actual = checksumOf({ migration });
7617
7900
  if (stored.checksum === actual)
7618
7901
  return;
7619
- throw new VibeError30({
7902
+ throw new VibeError32({
7620
7903
  code: "VIBE_MIGRATION",
7621
7904
  message: `migration "${migration.name}" is partially applied (${stored.statementIndex} statement(s) done) and its SQL has CHANGED since \u2014 refusing to resume; restore the original SQL or repair with resolveMigration`,
7622
7905
  meta: {
@@ -7636,7 +7919,7 @@ function assertDistinctMigrationNames(params) {
7636
7919
  const names = new Set;
7637
7920
  for (const migration of params.migrations) {
7638
7921
  if (names.has(migration.name))
7639
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Duplicate migration file identity "${migration.name}"`, meta: { reason: "history-duplicate-file", migration: migration.name } });
7922
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Duplicate migration file identity "${migration.name}"`, meta: { reason: "history-duplicate-file", migration: migration.name } });
7640
7923
  names.add(migration.name);
7641
7924
  }
7642
7925
  }
@@ -7644,15 +7927,15 @@ function assertCompleteHistory(params) {
7644
7927
  const byName = new Map(params.migrations.map((migration) => [migration.name, migration]));
7645
7928
  for (const name of params.recorded.keys()) {
7646
7929
  if (!byName.has(name))
7647
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Recorded migration "${name}" has no file in the complete chain`, meta: { reason: "history-unknown-file", migration: name } });
7930
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Recorded migration "${name}" has no file in the complete chain`, meta: { reason: "history-unknown-file", migration: name } });
7648
7931
  }
7649
7932
  let index = 0;
7650
7933
  for (const [name, stored] of params.recorded) {
7651
7934
  const migration = params.migrations[index];
7652
7935
  if (migration?.name !== name)
7653
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Recorded migration order is not a prefix of the supplied complete chain", meta: { reason: "history-order-conflict", migration: name, expected: migration?.name, position: index } });
7936
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Recorded migration order is not a prefix of the supplied complete chain", meta: { reason: "history-order-conflict", migration: name, expected: migration?.name, position: index } });
7654
7937
  if (stored.statementIndex >= 0 && !isCompleteRecord({ dialect: params.dialect, migration, stored }) && index !== params.recorded.size - 1)
7655
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Partial migration "${name}" precedes later recorded work`, meta: { reason: "history-partial-not-last", migration: name } });
7938
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Partial migration "${name}" precedes later recorded work`, meta: { reason: "history-partial-not-last", migration: name } });
7656
7939
  index++;
7657
7940
  }
7658
7941
  }
@@ -7661,16 +7944,16 @@ async function assertApplyHistory(params) {
7661
7944
  const byName = new Map(migrations.map((migration) => [migration.name, migration]));
7662
7945
  for (const [name, stored] of recorded) {
7663
7946
  if (stored.statementIndex < 0) {
7664
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${name}" is mid-rollback; finish or resolve it before applying`, meta: { reason: "history-rolling-back", migration: name, statementIndex: stored.statementIndex } });
7947
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${name}" is mid-rollback; finish or resolve it before applying`, meta: { reason: "history-rolling-back", migration: name, statementIndex: stored.statementIndex } });
7665
7948
  }
7666
7949
  const migration = byName.get(name);
7667
7950
  if (migration === undefined) {
7668
7951
  if (stored.error !== undefined)
7669
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error but no supplied file`, meta: { reason: "history-unknown-dirty", migration: name } });
7952
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error but no supplied file`, meta: { reason: "history-unknown-dirty", migration: name } });
7670
7953
  continue;
7671
7954
  }
7672
7955
  if (isCompleteRecord({ dialect, migration, stored }) && stored.error !== undefined)
7673
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error`, meta: { reason: "history-dirty", migration: name } });
7956
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error`, meta: { reason: "history-dirty", migration: name } });
7674
7957
  if (isCompleteRecord({ dialect, migration, stored }))
7675
7958
  assertChecksumMatches({ migration, stored: stored.checksum });
7676
7959
  else
@@ -7695,10 +7978,10 @@ async function assertApplyHistory(params) {
7695
7978
  }
7696
7979
  }
7697
7980
  function q5(dialect, name) {
7698
- return getSqlDialect5({ dialect }).quoteIdent({ name });
7981
+ return getSqlDialect7({ dialect }).quoteIdent({ name });
7699
7982
  }
7700
7983
  function ph(dialect, index) {
7701
- return getSqlDialect5({ dialect }).placeholder({ index });
7984
+ return getSqlDialect7({ dialect }).placeholder({ index });
7702
7985
  }
7703
7986
 
7704
7987
  // packages/migrate/src/fs.ts
@@ -7706,7 +7989,7 @@ function absent(error) {
7706
7989
  return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
7707
7990
  }
7708
7991
  function failure(params) {
7709
- return new VibeError31({ code: "VIBE_MIGRATION", message: `Cannot read migration file ${params.path}`, meta: { reason: "migration-file-unreadable", path: params.path }, cause: params.cause });
7992
+ return new VibeError33({ code: "VIBE_MIGRATION", message: `Cannot read migration file ${params.path}`, meta: { reason: "migration-file-unreadable", path: params.path }, cause: params.cause });
7710
7993
  }
7711
7994
  async function optionalFile(params) {
7712
7995
  return readFile(params.path, "utf-8").catch((cause) => {
@@ -7718,15 +8001,15 @@ async function optionalFile(params) {
7718
8001
  function rlsMetadata(params) {
7719
8002
  return Promise.resolve().then(() => {
7720
8003
  const metadata = JSON.parse(params.text);
7721
- const strings2 = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
7722
- if (metadata?.version !== 1 || typeof metadata.destructive !== "boolean" || metadata.rls === undefined || !strings2(metadata.securityChanges) || !strings2(metadata.downSecurityChanges) || metadata.sqlChecksum !== migrationChecksum({ sql: params.migration.sql }) || metadata.downChecksum !== migrationChecksum({ sql: params.migration.downSql ?? [] })) {
7723
- throw new VibeError31({ code: "VIBE_MIGRATION", message: "Invalid native RLS metadata" });
8004
+ const strings = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
8005
+ if (metadata?.version !== 1 || typeof metadata.destructive !== "boolean" || metadata.rls === undefined || !strings(metadata.securityChanges) || !strings(metadata.downSecurityChanges) || metadata.sqlChecksum !== migrationChecksum({ sql: params.migration.sql }) || metadata.downChecksum !== migrationChecksum({ sql: params.migration.downSql ?? [] })) {
8006
+ throw new VibeError33({ code: "VIBE_MIGRATION", message: "Invalid native RLS metadata" });
7724
8007
  }
7725
8008
  assertValidSchemaIR4({ schema: metadata.rls.from });
7726
8009
  assertValidSchemaIR4({ schema: metadata.rls.to });
7727
8010
  return { ...params.migration, rls: metadata.rls, destructive: metadata.destructive, securityChanges: metadata.securityChanges, downSecurityChanges: metadata.downSecurityChanges };
7728
8011
  }).catch((cause) => {
7729
- throw new VibeError31({ code: "VIBE_MIGRATION", message: `Invalid native RLS metadata for migration "${params.migration.name}"`, meta: { reason: "rls-migration-metadata-invalid", migration: params.migration.name }, cause });
8012
+ throw new VibeError33({ code: "VIBE_MIGRATION", message: `Invalid native RLS metadata for migration "${params.migration.name}"`, meta: { reason: "rls-migration-metadata-invalid", migration: params.migration.name }, cause });
7730
8013
  });
7731
8014
  }
7732
8015
  async function loadMigrationFiles(params) {
@@ -7759,7 +8042,7 @@ async function loadMigrationFiles(params) {
7759
8042
  const desired = await optionalFile({ path: join(directory, DESIRED_STATE_METADATA.filename) });
7760
8043
  if (desired !== undefined) {
7761
8044
  const pending = await Promise.resolve().then(() => isUnfinalizedDesiredState({ text: desired })).catch((cause) => {
7762
- throw new VibeError31({ code: "VIBE_MIGRATION", message: `Malformed desired state for ${name}`, meta: { reason: "desired-state-invalid", migration: name }, cause });
8045
+ throw new VibeError33({ code: "VIBE_MIGRATION", message: `Malformed desired state for ${name}`, meta: { reason: "desired-state-invalid", migration: name }, cause });
7763
8046
  });
7764
8047
  migration = pending ? { ...migration, desiredStatePending: true } : { ...migration, desiredState: parseDesiredStateSidecar({ text: desired, migration: name }) };
7765
8048
  }
@@ -7771,9 +8054,9 @@ async function loadMigrationFiles(params) {
7771
8054
  return migrations;
7772
8055
  }
7773
8056
  export {
7774
- splitSqlStatements,
8057
+ joinSqlStatements,
7775
8058
  loadMigrationFiles,
7776
- joinSqlStatements
8059
+ splitSqlStatements
7777
8060
  };
7778
8061
 
7779
- //# debugId=8DB0E0F7582B731664756E2164756E21
8062
+ //# debugId=BB17658EE109D81A64756E2164756E21