@vibeorm/migrate 2.3.0 → 2.5.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.
package/dist/index.js CHANGED
@@ -307,10 +307,10 @@ import { VibeError as VibeError18, sqlObjectKey as sqlObjectKey6 } from "@vibeor
307
307
  import { getSqlDialect as getSqlDialect3, renderModuleDependencyQuery } from "@vibeorm/sql";
308
308
 
309
309
  // packages/migrate/src/object-ownership.ts
310
- import { VibeError as VibeError7, sqlObjectKey as sqlObjectKey2, enumStorageOf as enumStorageOf2 } from "@vibeorm/schema";
310
+ import { VibeError as VibeError7, defaultPrimaryKeyName, enumStorageOf as enumStorageOf2, implicitJoinTableObjectNames, postgresGeneratedObjectName, sqlObjectKey as sqlObjectKey2 } from "@vibeorm/schema";
311
311
 
312
312
  // packages/migrate/src/normalize.ts
313
- import { VibeError as VibeError6, enumStorageOf, isEnumType as isEnumType5, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
313
+ import { VibeError as VibeError6, defaultForeignKeyName, defaultIndexName, enumStorageOf, isEnumType as isEnumType5, unsupportedCapability as unsupportedCapability4 } from "@vibeorm/schema";
314
314
 
315
315
  // packages/migrate/src/relations.ts
316
316
  import { implicitJoinTable, isImplicitManyToManyRelation } from "@vibeorm/schema";
@@ -360,6 +360,49 @@ var SCALAR_TO_PG = {
360
360
  var CANONICAL_EQUIVALENTS = {
361
361
  DateTime: ["timestamptz(3)", "timestamptz(6)"]
362
362
  };
363
+ var CANONICAL_UDT = {
364
+ text: "String",
365
+ bool: "Boolean",
366
+ int4: "Int",
367
+ int8: "BigInt",
368
+ float8: "Float",
369
+ numeric: "Decimal",
370
+ timestamptz: "DateTime",
371
+ jsonb: "Json",
372
+ bytea: "Bytes"
373
+ };
374
+ var NON_CANONICAL_UDT = {
375
+ varchar: "String",
376
+ bpchar: "String",
377
+ uuid: "String",
378
+ bit: "String",
379
+ varbit: "String",
380
+ xml: "String",
381
+ inet: "String",
382
+ citext: "String",
383
+ int2: "Int",
384
+ oid: "Int",
385
+ float4: "Float",
386
+ money: "Decimal",
387
+ timestamp: "DateTime",
388
+ date: "DateTime",
389
+ time: "DateTime",
390
+ timetz: "DateTime",
391
+ json: "Json"
392
+ };
393
+ var SPELLING_TO_UDT = {
394
+ integer: "int4",
395
+ bigint: "int8",
396
+ smallint: "int2",
397
+ boolean: "bool",
398
+ doubleprecision: "float8",
399
+ real: "float4",
400
+ char: "bpchar"
401
+ };
402
+ function scalarForBuiltinType(params) {
403
+ const udt = SPELLING_TO_UDT[params.name] ?? params.name;
404
+ return CANONICAL_UDT[udt] ?? NON_CANONICAL_UDT[udt];
405
+ }
363
406
  var NATIVE_ALIASES = {
364
407
  charactervarying: "varchar",
365
408
  character: "char",
@@ -379,7 +422,11 @@ var NATIVE_ALIASES = {
379
422
  timestampwithtimezone: "timestamptz",
380
423
  timestampwithouttimezone: "timestamp",
381
424
  timewithtimezone: "timetz",
382
- timewithouttimezone: "time"
425
+ timewithouttimezone: "time",
426
+ bitvarying: "varbit"
427
+ };
428
+ var IMPLICIT_MODIFIERS = {
429
+ bit: "(1)"
383
430
  };
384
431
  function normalizeNativeType(params) {
385
432
  const compact = params.raw.toLowerCase().replace(/\s+/g, "");
@@ -387,7 +434,7 @@ function normalizeNativeType(params) {
387
434
  if (match === null)
388
435
  return compact;
389
436
  const base = NATIVE_ALIASES[match[1]] ?? match[1];
390
- return `${base}${match[2] ?? ""}${match[3] ?? ""}`;
437
+ return `${base}${match[2] ?? IMPLICIT_MODIFIERS[base] ?? ""}${match[3] ?? ""}`;
391
438
  }
392
439
  function parseUnsupportedPostgresType(params) {
393
440
  const temporal = /^\s*(time(?:stamp)?)\s*(\(\s*\d+\s*\))?\s+(with|without)\s+time\s+zone\s*((?:\[\s*\]\s*)*)$/i.exec(params.raw);
@@ -408,6 +455,11 @@ function columnTypeKey(params) {
408
455
  return `u:${field.nativeType ?? ""}`;
409
456
  const evidence = field.nativeTypeIdentity;
410
457
  const namespace = evidence !== undefined && evidence.source === field.nativeType ? evidence.namespace : parsed.namespace;
458
+ const scalar = namespace === undefined || namespace === "pg_catalog" ? scalarForBuiltinType({ name: parsed.name }) : undefined;
459
+ if (scalar !== undefined) {
460
+ const { isUnsupported: _unsupported, nativeTypeIdentity: _identity, ...rest } = field;
461
+ return columnTypeKey({ field: { ...rest, type: scalar, nativeType: `${parsed.name}${parsed.modifier ?? ""}`, isList: parsed.array || field.isList } });
462
+ }
411
463
  return `u:${JSON.stringify([namespace ?? null, parsed.name, parsed.modifier, parsed.array || field.isList])}`;
412
464
  }
413
465
  if (isEnumType(field.type)) {
@@ -496,8 +548,12 @@ function defaultFingerprint(params) {
496
548
  }
497
549
  case "enumValue":
498
550
  return `enum:${def.value}`;
499
- case "dbgenerated":
500
- return `db:${def.sql.trim()}`;
551
+ case "dbgenerated": {
552
+ const sql = def.sql.trim();
553
+ if (/^now\(\)$/i.test(sql) || /^current_timestamp(\(\d\))?$/i.test(sql))
554
+ return "now";
555
+ return `db:${sql}`;
556
+ }
501
557
  }
502
558
  }
503
559
  function defaultSql(params) {
@@ -988,8 +1044,8 @@ function normalizeModel(params) {
988
1044
  });
989
1045
  }
990
1046
  const pk = normalizePk({ model });
991
- const indexes = normalizeIndexes({ model, table });
992
- const fks = normalizeFks({ model, table, schema });
1047
+ const indexes = normalizeIndexes({ model, table, dialect });
1048
+ const fks = normalizeFks({ model, table, schema, dialect });
993
1049
  const checks = new Map;
994
1050
  for (const check of model.checks ?? [])
995
1051
  checks.set(check.name, check.expression);
@@ -1003,7 +1059,7 @@ function normalizePk(params) {
1003
1059
  return model.fields.filter((field) => field.isId).map((field) => field.dbName ?? field.name);
1004
1060
  }
1005
1061
  function normalizeIndexes(params) {
1006
- const { model, table } = params;
1062
+ const { model, table, dialect } = params;
1007
1063
  const result = new Map;
1008
1064
  const add = (index) => {
1009
1065
  const unique = index.kind === "unique";
@@ -1022,7 +1078,7 @@ function normalizeIndexes(params) {
1022
1078
  const key = indexComparisonKey({ unique, kind, columns, where, nullsNotDistinct });
1023
1079
  if (result.has(key))
1024
1080
  return;
1025
- const name = index.name ?? `${table}_${columns.map((column) => column.name).join("_")}_${unique ? "key" : "idx"}`;
1081
+ const name = index.name ?? defaultIndexName({ table, columns: columns.map((column) => column.name), unique, dialect });
1026
1082
  result.set(key, {
1027
1083
  key,
1028
1084
  name,
@@ -1228,7 +1284,7 @@ function normalizeFks(params) {
1228
1284
  continue;
1229
1285
  result.set(key, {
1230
1286
  key,
1231
- constraintName: relation.constraintName ?? `${table}_${columns.join("_")}_fkey`,
1287
+ constraintName: relation.constraintName ?? defaultForeignKeyName({ table, columns, dialect: params.dialect }),
1232
1288
  columns,
1233
1289
  refTable,
1234
1290
  refColumns,
@@ -1371,7 +1427,7 @@ function removalIdentity(params) {
1371
1427
  case "dropForeignKey":
1372
1428
  return { kind: "constraint", constraintType: "foreignKey", table, name: step.constraintName };
1373
1429
  case "dropPrimaryKey":
1374
- return { kind: "constraint", constraintType: "primaryKey", table, name: step.constraintName ?? `${step.table}_pkey` };
1430
+ return { kind: "constraint", constraintType: "primaryKey", table, name: step.constraintName ?? defaultPrimaryKeyName({ table: step.table, dialect: "postgres" }) };
1375
1431
  default:
1376
1432
  return;
1377
1433
  }
@@ -1390,7 +1446,7 @@ function schemaObjectIdentities(params) {
1390
1446
  if (definition.defaultKey !== null)
1391
1447
  result.push({ kind: "columnDefault", table, column });
1392
1448
  if (params.dialect === "postgres" && definition.field.default?.kind === "autoincrement")
1393
- result.push({ kind: "sequence", name: { namespace: params.namespace, name: `${name}_${column}_seq` } });
1449
+ result.push({ kind: "sequence", name: { namespace: params.namespace, name: postgresGeneratedObjectName({ name1: name, name2: column, label: "seq" }) } });
1394
1450
  }
1395
1451
  for (const exclusion of model.model.exclusions ?? [])
1396
1452
  result.push({ kind: "constraint", constraintType: "exclusion", table, name: exclusion.name });
@@ -1404,15 +1460,15 @@ function schemaObjectIdentities(params) {
1404
1460
  for (const fk of model.fks.values())
1405
1461
  result.push({ kind: "constraint", constraintType: "foreignKey", table, name: fk.constraintName });
1406
1462
  if (model.pk.length > 0)
1407
- result.push({ kind: "constraint", constraintType: "primaryKey", table, name: model.model.primaryKeyConstraintName ?? (params.dialect === "mysql" ? "PRIMARY" : `${name}_pkey`) });
1463
+ result.push({ kind: "constraint", constraintType: "primaryKey", table, name: model.model.primaryKeyConstraintName ?? (params.dialect === "mysql" ? "PRIMARY" : defaultPrimaryKeyName({ table: name, dialect: params.dialect })) });
1408
1464
  }
1409
1465
  for (const name of normalized.joinTables.keys()) {
1410
1466
  const table = { namespace: params.namespace, name };
1411
1467
  result.push({ kind: "table", name: table });
1412
- for (const column of ["A", "B"])
1413
- result.push({ kind: "column", table, column }, { kind: "constraint", constraintType: "foreignKey", table, name: `${name}_${column}_fkey` });
1414
- for (const suffix of ["AB_unique", "B_index"])
1415
- result.push({ kind: "index", table, name: `${name}_${suffix}` });
1468
+ const derived = implicitJoinTableObjectNames({ table: name });
1469
+ result.push({ kind: "column", table, column: "A" }, { kind: "constraint", constraintType: "foreignKey", table, name: derived.foreignKeyA });
1470
+ result.push({ kind: "column", table, column: "B" }, { kind: "constraint", constraintType: "foreignKey", table, name: derived.foreignKeyB });
1471
+ result.push({ kind: "index", table, name: derived.uniqueIndex }, { kind: "index", table, name: derived.indexB });
1416
1472
  }
1417
1473
  for (const name of normalized.views.keys())
1418
1474
  result.push({ kind: "view", name: { namespace: params.namespace, name } });
@@ -1487,7 +1543,7 @@ function assertRemovalAuthorization(params) {
1487
1543
  }
1488
1544
 
1489
1545
  // packages/migrate/src/inventory.ts
1490
- import { VibeError as VibeError17, isSqlObjectIdentity as isSqlObjectIdentity2, sqlObjectKey as sqlObjectKey5 } from "@vibeorm/schema";
1546
+ import { VibeError as VibeError17, defaultForeignKeyName as defaultForeignKeyName2, defaultPrimaryKeyName as defaultPrimaryKeyName2, isSqlObjectIdentity as isSqlObjectIdentity2, sqlObjectKey as sqlObjectKey5 } from "@vibeorm/schema";
1491
1547
  import { getSqlDialect as getSqlDialect2, renderMigrationInventory, renderSqliteColumnInventory as renderSqliteColumnInventory2, renderMysqlObjectMembers as renderMysqlObjectMembers2, sqliteTableConstraints as sqliteTableConstraints3, renderSqliteForeignKeyInventory } from "@vibeorm/sql";
1492
1548
 
1493
1549
  // packages/migrate/src/exclusions.ts
@@ -2233,18 +2289,17 @@ async function introspectPostgres(params) {
2233
2289
  if (params.inTransaction !== true)
2234
2290
  await executor({ text: "BEGIN" });
2235
2291
  try {
2236
- const savedPath = params.inTransaction === true ? await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "readSearchPath" })) : undefined;
2237
- const searchPath = savedPath?.[0]?.searchPath;
2238
- if (params.inTransaction === true && typeof searchPath !== "string")
2292
+ const savedPath = await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "readSearchPath" }));
2293
+ const searchPath = savedPath[0]?.searchPath;
2294
+ if (typeof searchPath !== "string")
2239
2295
  throw new VibeError13({ code: "VIBE_MIGRATION", message: "Cannot read the migration search_path" });
2240
2296
  const matched = await verifyPostgresRls({ executor, ...params.rlsSchema === undefined ? {} : { schema: params.rlsSchema }, ...params.requireInstalledRls === undefined ? {} : { requireInstalled: params.requireInstalledRls } }).then((verified) => verified, (error) => {
2241
2297
  if (error instanceof VibeError13)
2242
2298
  throw error;
2243
2299
  throw new VibeError13({ 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 });
2244
2300
  });
2301
+ await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "setSearchPath", searchPath }));
2245
2302
  const physical = await introspectPhysicalPostgres({ executor });
2246
- if (typeof searchPath === "string")
2247
- await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "setSearchPath", searchPath }));
2248
2303
  return projectPostgresRls({ physical, ...params.rlsSchema === undefined ? {} : { declared: params.rlsSchema }, matched });
2249
2304
  } finally {
2250
2305
  if (params.inTransaction !== true)
@@ -2521,27 +2576,6 @@ function buildField(params) {
2521
2576
  ...mapped.isUnsupported === true ? { isUnsupported: true } : {}
2522
2577
  };
2523
2578
  }
2524
- var CANONICAL_UDT = {
2525
- text: "String",
2526
- bool: "Boolean",
2527
- int4: "Int",
2528
- int8: "BigInt",
2529
- float8: "Float",
2530
- numeric: "Decimal",
2531
- timestamptz: "DateTime",
2532
- jsonb: "Json",
2533
- bytea: "Bytes"
2534
- };
2535
- var NON_CANONICAL_UDT = {
2536
- varchar: "String",
2537
- bpchar: "String",
2538
- uuid: "String",
2539
- int2: "Int",
2540
- float4: "Float",
2541
- timestamp: "DateTime",
2542
- date: "DateTime",
2543
- json: "Json"
2544
- };
2545
2579
  function reverseMapType(params) {
2546
2580
  const { column, enumNames } = params;
2547
2581
  const isList = column.dataType === "ARRAY";
@@ -2597,8 +2631,10 @@ function withModifier(params) {
2597
2631
  }
2598
2632
  if (udt === "bpchar")
2599
2633
  return "char";
2600
- if (udt === "timestamp" && column.datetimePrecision !== null && column.datetimePrecision !== 6) {
2601
- return `timestamp(${column.datetimePrecision})`;
2634
+ if ((udt === "bit" || udt === "varbit") && column.charMaxLength !== null)
2635
+ return `${udt}(${column.charMaxLength})`;
2636
+ if ((udt === "timestamp" || udt === "time" || udt === "timetz") && column.datetimePrecision !== null && column.datetimePrecision !== 6) {
2637
+ return `${udt}(${column.datetimePrecision})`;
2602
2638
  }
2603
2639
  return udt;
2604
2640
  }
@@ -4348,7 +4384,7 @@ async function inspectMigrationInventory(params) {
4348
4384
  for (const constraint of clauses) {
4349
4385
  if (constraint.type === "check")
4350
4386
  continue;
4351
- const name = constraint.named ? constraint.name : constraint.type === "primaryKey" ? `${qualified.name}_pkey` : constraint.type === "foreignKey" ? `${qualified.name}_${constraint.columns.join("_")}_fkey` : constraint.name;
4387
+ 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;
4352
4388
  objects.push({ identity: { kind: "constraint", constraintType: constraint.type, table: qualified, name }, ...constraint.type === "unique" && !constraint.named ? { inspectionUnavailable: "sqlite-anonymous-unique-constraint" } : {} });
4353
4389
  }
4354
4390
  const checks = parseSqliteNamedChecks({ tableSql: row.definition });
@@ -4359,7 +4395,7 @@ async function inspectMigrationInventory(params) {
4359
4395
  const query = renderSqliteColumnInventory2({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4360
4396
  const columns = await params.executor({ text: query.text, values: [...query.values] });
4361
4397
  if (columns.some((column) => Number(column.pk) > 0) && !clauses.some((clause) => clause.type === "primaryKey"))
4362
- objects.push({ identity: { kind: "constraint", constraintType: "primaryKey", table: qualified, name: `${qualified.name}_pkey` } });
4398
+ objects.push({ identity: { kind: "constraint", constraintType: "primaryKey", table: qualified, name: defaultPrimaryKeyName2({ table: qualified.name, dialect: "sqlite" }) } });
4363
4399
  const fkQuery = renderSqliteForeignKeyInventory({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4364
4400
  const foreignKeys = await params.executor({ text: fkQuery.text, values: [...fkQuery.values] });
4365
4401
  const groups = new Map;
@@ -4368,7 +4404,7 @@ async function inspectMigrationInventory(params) {
4368
4404
  for (const fields of groups.values()) {
4369
4405
  if (clauses.some((clause) => clause.type === "foreignKey" && JSON.stringify(clause.columns) === JSON.stringify(fields)))
4370
4406
  continue;
4371
- objects.push({ identity: { kind: "constraint", constraintType: "foreignKey", table: qualified, name: `${qualified.name}_${fields.join("_")}_fkey` }, inspectionUnavailable: "sqlite-inline-foreign-key-definition-unavailable" });
4407
+ 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" });
4372
4408
  }
4373
4409
  for (const column of columns) {
4374
4410
  objects.push({ identity: { kind: "column", table: qualified, column: String(column.name) } });
@@ -5641,7 +5677,7 @@ import { VibeError as VibeError31, sqlObjectKey as sqlObjectKey9 } from "@vibeor
5641
5677
 
5642
5678
  // packages/migrate/src/ddl/postgres.ts
5643
5679
  import { renderExclusionSetup } from "@vibeorm/sql";
5644
- import { VibeError as VibeError28, isEnumType as isEnumType7 } from "@vibeorm/schema";
5680
+ import { VibeError as VibeError28, defaultPrimaryKeyName as defaultPrimaryKeyName3, implicitJoinTableObjectNames as implicitJoinTableObjectNames2, isEnumType as isEnumType7 } from "@vibeorm/schema";
5645
5681
  import { postgresDialect as postgresDialect8, renderRlsPolicyPath } from "@vibeorm/sql";
5646
5682
  function renderPostgresSteps(params) {
5647
5683
  refuseSameTransactionEnumUse({ steps: params.steps });
@@ -5713,7 +5749,7 @@ function renderStep(params) {
5713
5749
  const lines = step.columns.map((column) => ` ${columnDefSql({ field: column })}`);
5714
5750
  if (step.primaryKey.length > 0) {
5715
5751
  const pkCols = step.primaryKey.map((column) => q2(column)).join(", ");
5716
- lines.push(` CONSTRAINT ${q2(step.primaryKeyConstraintName ?? `${step.table}_pkey`)} PRIMARY KEY (${pkCols})`);
5752
+ lines.push(` CONSTRAINT ${q2(step.primaryKeyConstraintName ?? defaultPrimaryKeyName3({ table: step.table, dialect: "postgres" }))} PRIMARY KEY (${pkCols})`);
5717
5753
  }
5718
5754
  for (const check of step.checks ?? []) {
5719
5755
  lines.push(` CONSTRAINT ${q2(check.name)} CHECK (${check.expression})`);
@@ -5786,25 +5822,26 @@ ${lines.join(`,
5786
5822
  case "createJoinTable": {
5787
5823
  const aType = columnTypeSql({ field: { ...step.a.field, isList: false } });
5788
5824
  const bType = columnTypeSql({ field: { ...step.b.field, isList: false } });
5825
+ const names = implicitJoinTableObjectNames2({ table: step.table });
5789
5826
  return [
5790
5827
  `CREATE TABLE ${publicName(step.table)} (
5791
5828
  "A" ${aType} NOT NULL,
5792
5829
  "B" ${bType} NOT NULL
5793
5830
  );`,
5794
- `CREATE UNIQUE INDEX ${q2(`${step.table}_AB_unique`)} ON ${publicName(step.table)} ("A", "B");`,
5795
- `CREATE INDEX ${q2(`${step.table}_B_index`)} ON ${publicName(step.table)} ("B");`,
5796
- `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;`,
5797
- `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;`
5831
+ `CREATE UNIQUE INDEX ${q2(names.uniqueIndex)} ON ${publicName(step.table)} ("A", "B");`,
5832
+ `CREATE INDEX ${q2(names.indexB)} ON ${publicName(step.table)} ("B");`,
5833
+ `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;`,
5834
+ `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;`
5798
5835
  ];
5799
5836
  }
5800
5837
  case "addPrimaryKey": {
5801
5838
  const cols = step.columns.map((column) => q2(column)).join(", ");
5802
5839
  return [
5803
- `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.constraintName ?? `${step.table}_pkey`)} PRIMARY KEY (${cols});`
5840
+ `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.constraintName ?? defaultPrimaryKeyName3({ table: step.table, dialect: "postgres" }))} PRIMARY KEY (${cols});`
5804
5841
  ];
5805
5842
  }
5806
5843
  case "dropPrimaryKey":
5807
- return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.constraintName ?? `${step.table}_pkey`)};`];
5844
+ return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.constraintName ?? defaultPrimaryKeyName3({ table: step.table, dialect: "postgres" }))};`];
5808
5845
  }
5809
5846
  }
5810
5847
  function columnDefSql(params) {
@@ -5866,7 +5903,7 @@ function q2(name) {
5866
5903
  }
5867
5904
 
5868
5905
  // packages/migrate/src/ddl/sqlite.ts
5869
- import { VibeError as VibeError29, isEnumType as isEnumType8, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
5906
+ import { VibeError as VibeError29, implicitJoinTableObjectNames as implicitJoinTableObjectNames3, isEnumType as isEnumType8, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
5870
5907
  import { sqliteDialect as sqliteDialect3 } from "@vibeorm/sql";
5871
5908
 
5872
5909
  // packages/migrate/src/ddl/drop-order.ts
@@ -6064,12 +6101,13 @@ function renderSqliteSteps(params) {
6064
6101
  case "createJoinTable": {
6065
6102
  const aType = sqliteStorageType({ field: { ...step.a.field, isList: false } });
6066
6103
  const bType = sqliteStorageType({ field: { ...step.b.field, isList: false } });
6104
+ const names = implicitJoinTableObjectNames3({ table: step.table });
6067
6105
  statements.push(`CREATE TABLE ${q3(step.table)} (
6068
6106
  "A" ${aType} NOT NULL,
6069
6107
  "B" ${bType} NOT NULL,
6070
- CONSTRAINT ${q3(`${step.table}_A_fkey`)} FOREIGN KEY ("A") REFERENCES ${q3(step.a.table)} (${q3(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE,
6071
- CONSTRAINT ${q3(`${step.table}_B_fkey`)} FOREIGN KEY ("B") REFERENCES ${q3(step.b.table)} (${q3(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE
6072
- );`, `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");`);
6108
+ CONSTRAINT ${q3(names.foreignKeyA)} FOREIGN KEY ("A") REFERENCES ${q3(step.a.table)} (${q3(step.a.column)}) ON DELETE CASCADE ON UPDATE CASCADE,
6109
+ CONSTRAINT ${q3(names.foreignKeyB)} FOREIGN KEY ("B") REFERENCES ${q3(step.b.table)} (${q3(step.b.column)}) ON DELETE CASCADE ON UPDATE CASCADE
6110
+ );`, `CREATE UNIQUE INDEX ${q3(names.uniqueIndex)} ON ${q3(step.table)} ("A", "B");`, `CREATE INDEX ${q3(names.indexB)} ON ${q3(step.table)} ("B");`);
6073
6111
  break;
6074
6112
  }
6075
6113
  case "addColumn":
@@ -6435,7 +6473,7 @@ function q3(name) {
6435
6473
  }
6436
6474
 
6437
6475
  // packages/migrate/src/ddl/mysql.ts
6438
- import { VibeError as VibeError30, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
6476
+ import { VibeError as VibeError30, implicitJoinTableObjectNames as implicitJoinTableObjectNames4, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
6439
6477
  import { mysqlDialect as mysqlDialect3 } from "@vibeorm/sql";
6440
6478
  function renderMysqlSteps(params) {
6441
6479
  for (const step of params.steps) {
@@ -6614,15 +6652,16 @@ ${lines.join(`,
6614
6652
  case "createJoinTable": {
6615
6653
  const aType = mysqlColumnTypeSql({ field: { ...step.a.field, isList: false }, enums });
6616
6654
  const bType = mysqlColumnTypeSql({ field: { ...step.b.field, isList: false }, enums });
6655
+ const names = implicitJoinTableObjectNames4({ table: step.table });
6617
6656
  return [
6618
6657
  `CREATE TABLE ${q4(step.table)} (
6619
6658
  \`A\` ${aType} NOT NULL,
6620
6659
  \`B\` ${bType} NOT NULL
6621
6660
  );`,
6622
- `CREATE UNIQUE INDEX ${q4(`${step.table}_AB_unique`)} ON ${q4(step.table)} (\`A\`, \`B\`);`,
6623
- `CREATE INDEX ${q4(`${step.table}_B_index`)} ON ${q4(step.table)} (\`B\`);`,
6624
- `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;`,
6625
- `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;`
6661
+ `CREATE UNIQUE INDEX ${q4(names.uniqueIndex)} ON ${q4(step.table)} (\`A\`, \`B\`);`,
6662
+ `CREATE INDEX ${q4(names.indexB)} ON ${q4(step.table)} (\`B\`);`,
6663
+ `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;`,
6664
+ `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;`
6626
6665
  ];
6627
6666
  }
6628
6667
  case "addPrimaryKey":
@@ -6759,6 +6798,7 @@ function collectExtensionArtifacts(params) {
6759
6798
  const { schema, dialect, extensions } = params;
6760
6799
  const setup = [];
6761
6800
  const objects = [];
6801
+ const groups = [];
6762
6802
  for (const extension of extensions) {
6763
6803
  const artifactsHook = extension.migrate?.artifacts;
6764
6804
  if (artifactsHook === undefined)
@@ -6766,6 +6806,7 @@ function collectExtensionArtifacts(params) {
6766
6806
  const declarations = extensionDeclarations({ schema, name: extension.name });
6767
6807
  if (Object.keys(declarations).length === 0 && extension.schema?.configOnly !== true)
6768
6808
  continue;
6809
+ const contributed = [];
6769
6810
  for (const artifact of artifactsHook({
6770
6811
  schema,
6771
6812
  dialect,
@@ -6773,10 +6814,19 @@ function collectExtensionArtifacts(params) {
6773
6814
  options: extension.options,
6774
6815
  declarations
6775
6816
  })) {
6776
- (artifact.owns.kind === "postgresExtension" ? setup : objects).push(artifact);
6817
+ if (artifact.owns.kind === "postgresExtension")
6818
+ setup.push(artifact);
6819
+ else {
6820
+ objects.push(artifact);
6821
+ contributed.push(artifact);
6822
+ }
6777
6823
  }
6824
+ groups.push({ extension: extension.name, objects: contributed });
6778
6825
  }
6779
- return { setup, objects };
6826
+ return { setup, objects, groups };
6827
+ }
6828
+ function lastDeclaredSchema(params) {
6829
+ return [...params.migrations].reverse().find((migration) => migration.desiredState !== undefined)?.desiredState?.to.schema;
6780
6830
  }
6781
6831
  function ownedTableNames(params) {
6782
6832
  const exact = new Set;
@@ -6878,6 +6928,36 @@ async function probeInstalledExtensionState(params) {
6878
6928
  function artifactCreateSql(params) {
6879
6929
  return params.artifacts.flatMap((artifact) => [...artifact.create]);
6880
6930
  }
6931
+ function planChangedArtifacts(params) {
6932
+ const previousById = new Map((params.previous?.objects ?? []).map((artifact) => [artifact.id, artifact]));
6933
+ const probedIds = new Set((params.probed ?? []).map((artifact) => artifact.id));
6934
+ const missingIds = new Set(params.missing.map((artifact) => artifact.id));
6935
+ const rebuilt = new Set;
6936
+ for (const group of params.current.groups) {
6937
+ const changed = group.objects.filter((artifact) => {
6938
+ if (missingIds.has(artifact.id))
6939
+ return false;
6940
+ if (probedIds.has(artifact.id))
6941
+ return true;
6942
+ const before = previousById.get(artifact.id);
6943
+ return before !== undefined && JSON.stringify(before.owns) === JSON.stringify(artifact.owns) && JSON.stringify(before.create) !== JSON.stringify(artifact.create);
6944
+ });
6945
+ if (changed.length === 0)
6946
+ continue;
6947
+ const rebuiltColumnTables = new Set(changed.flatMap((artifact) => artifact.owns.kind === "column" ? [artifact.owns.table] : []));
6948
+ for (const artifact of group.objects) {
6949
+ if (missingIds.has(artifact.id))
6950
+ continue;
6951
+ const dependent = (artifact.owns.kind === "index" || artifact.owns.kind === "trigger") && rebuiltColumnTables.has(artifact.owns.table);
6952
+ if (changed.includes(artifact) || dependent)
6953
+ rebuilt.add(artifact.id);
6954
+ }
6955
+ }
6956
+ return params.current.objects.filter((artifact) => rebuilt.has(artifact.id));
6957
+ }
6958
+ function artifactDropSql(params) {
6959
+ return [...params.artifacts].reverse().flatMap((artifact) => [...artifact.drop]);
6960
+ }
6881
6961
  // packages/migrate/src/runner.ts
6882
6962
  function migrationRlsSecurityChanges(params) {
6883
6963
  const source = params.migration.rls;
@@ -7028,6 +7108,7 @@ function generateMigration(params) {
7028
7108
  extensions: params.extensions ?? []
7029
7109
  });
7030
7110
  const allArtifacts = [...artifacts.setup, ...artifacts.objects];
7111
+ const rebuilt = planChangedArtifacts({ previous: collectExtensionArtifacts({ schema: from, dialect, extensions: params.extensions ?? [] }), current: artifacts, missing: [] });
7031
7112
  assertRetainedMigrationObjects({ from: from.migrationObjects ?? [], to: to.migrationObjects ?? [] });
7032
7113
  const strippedFrom = preserveMigrationObjects({ from: stripExtensionArtifacts({ schema: from, artifacts: allArtifacts }), to, objects: [...from.migrationObjects ?? [], ...to.migrationObjects ?? []] });
7033
7114
  const steps = diffSchemas({ from: strippedFrom, to, dialect, ...params.renames === undefined ? {} : { renames: params.renames } });
@@ -7038,6 +7119,7 @@ function generateMigration(params) {
7038
7119
  artifacts: missing.filter((artifact) => artifact.owns.kind === "postgresExtension")
7039
7120
  }),
7040
7121
  ...coreSql,
7122
+ ...artifactDropSql({ artifacts: rebuilt }),
7041
7123
  ...artifactCreateSql({
7042
7124
  artifacts: missing.filter((artifact) => artifact.owns.kind !== "postgresExtension")
7043
7125
  }),
@@ -8395,11 +8477,94 @@ async function compareReplayMigrationObjects(params) {
8395
8477
  return { ...params.schema, migrationObjects: objects.map((object) => ({ ...object, expected: definitions.get(sqlObjectKey11({ identity: object.identity })) })) };
8396
8478
  }
8397
8479
  // packages/migrate/src/replay-plan.ts
8398
- import { VibeError as VibeError38, sqlObjectKey as sqlObjectKey13 } from "@vibeorm/schema";
8480
+ import { VibeError as VibeError40, sqlObjectKey as sqlObjectKey13 } from "@vibeorm/schema";
8399
8481
 
8400
8482
  // packages/migrate/src/planner.ts
8401
- import { VibeError as VibeError37, sqlObjectKey as sqlObjectKey12 } from "@vibeorm/schema";
8483
+ import { VibeError as VibeError39, sqlObjectKey as sqlObjectKey12 } from "@vibeorm/schema";
8402
8484
  import { renderSqliteRebuildObjects, sqliteDialect as sqliteDialect4 } from "@vibeorm/sql";
8485
+
8486
+ // packages/migrate/src/artifact-probe.ts
8487
+ import { VibeError as VibeError37 } from "@vibeorm/schema";
8488
+ var SAVEPOINT = "vibeorm_artifact_probe";
8489
+ async function probeChangedArtifacts(params) {
8490
+ const { executor, namespace } = params;
8491
+ const changed = [];
8492
+ for (const artifact of params.artifacts) {
8493
+ if (artifact.owns.kind === "postgresExtension" || artifact.drop.length === 0)
8494
+ continue;
8495
+ const identity = legacyMigrationObjects({ artifacts: [artifact], dialect: "postgres", namespace })[0].identity;
8496
+ const before = await inspectSqlObject({ executor, dialect: "postgres", identity });
8497
+ if (before.state !== "present")
8498
+ continue;
8499
+ await executor({ text: `SAVEPOINT ${SAVEPOINT}` });
8500
+ let after;
8501
+ try {
8502
+ for (const statement of [...artifact.drop, ...artifact.create])
8503
+ await executor({ text: statement });
8504
+ after = await inspectSqlObject({ executor, dialect: "postgres", identity });
8505
+ } finally {
8506
+ await executor({ text: `ROLLBACK TO SAVEPOINT ${SAVEPOINT}` });
8507
+ await executor({ text: `RELEASE SAVEPOINT ${SAVEPOINT}` });
8508
+ }
8509
+ if (after.state !== "present")
8510
+ throw new VibeError37({ code: "VIBE_MIGRATION", message: `Extension artifact ${artifact.id} did not produce its object when probed; its create SQL cannot be verified against the replayed history`, meta: { reason: "artifact-probe-unavailable", id: artifact.id, identity } });
8511
+ if (canonicalMigrationJson({ value: before.definition.facts }) === canonicalMigrationJson({ value: after.definition.facts }))
8512
+ continue;
8513
+ const definition = before.definition.facts.definition;
8514
+ changed.push({ artifact, ...identity.kind === "index" && typeof definition === "string" ? { restore: [`${definition};`] } : {} });
8515
+ }
8516
+ return changed;
8517
+ }
8518
+
8519
+ // packages/migrate/src/index-predicates.ts
8520
+ import { VibeError as VibeError38 } from "@vibeorm/schema";
8521
+ import { defaultIndexName as defaultIndexName2 } from "@vibeorm/schema";
8522
+ function physicalIndexName(params) {
8523
+ return params.index.name ?? defaultIndexName2({ table: params.table, columns: params.columns, unique: params.index.kind === "unique", dialect: "postgres" });
8524
+ }
8525
+ async function prepareIndexPredicateDiff(params) {
8526
+ if (params.probe !== "rollback")
8527
+ return params.from;
8528
+ const models = [];
8529
+ for (const live of params.from.models) {
8530
+ const table = live.dbName ?? live.name;
8531
+ const authored = params.to.models.find((entry) => (entry.dbName ?? entry.name) === table);
8532
+ if (authored === undefined || !live.indexes.some((index) => index.where !== undefined)) {
8533
+ models.push(live);
8534
+ continue;
8535
+ }
8536
+ const authoredByName = new Map;
8537
+ for (const index of authored.indexes) {
8538
+ const columns = index.fields.map((entry) => authored.fields.find((candidate) => candidate.name === entry.name)?.dbName ?? entry.name);
8539
+ authoredByName.set(physicalIndexName({ index, table, columns }), index);
8540
+ }
8541
+ const indexes = [];
8542
+ for (const index of live.indexes) {
8543
+ const next = index.name === undefined ? undefined : authoredByName.get(index.name);
8544
+ if (index.where === undefined || next?.where === undefined || next.where === index.where) {
8545
+ indexes.push(index);
8546
+ continue;
8547
+ }
8548
+ const deparsed = await deparseIndexPredicate({ executor: params.executor, table: { namespace: params.namespace, name: table }, where: next.where });
8549
+ indexes.push(deparsed === index.where ? { ...index, where: next.where } : index);
8550
+ }
8551
+ models.push({ ...live, indexes });
8552
+ }
8553
+ return { ...params.from, models };
8554
+ }
8555
+ async function deparseIndexPredicate(params) {
8556
+ try {
8557
+ const definition = await deparsePostgresCheck({ executor: params.executor, table: params.table, expression: params.where, probe: "rollback" });
8558
+ const match = /^CHECK \((.*)\)$/s.exec(definition);
8559
+ return match === null ? undefined : match[1];
8560
+ } catch (error) {
8561
+ if (error instanceof VibeError38 && error.code === "VIBE_MIGRATION")
8562
+ throw error;
8563
+ return;
8564
+ }
8565
+ }
8566
+
8567
+ // packages/migrate/src/planner.ts
8403
8568
  async function planSchemaMigration(params) {
8404
8569
  const { executor, dialect } = params;
8405
8570
  const resolved = dialect === "postgres" ? await resolvePostgresTypeIdentities({ executor, schema: params.schema, ...params.previous === undefined ? {} : { previous: params.previous.schema }, mode: "verify" }) : { schema: params.schema, unavailable: [] };
@@ -8412,7 +8577,7 @@ async function planSchemaMigration(params) {
8412
8577
  assertRetainedMigrationObjects({ from: params.previous?.schema.migrationObjects ?? [], to: objects });
8413
8578
  for (const object of objects)
8414
8579
  if (object.dialect !== dialect)
8415
- throw new VibeError37({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Migration object ${object.id} requires ${object.dialect}`, meta: { feature: "migrationObject", dialect } });
8580
+ throw new VibeError39({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Migration object ${object.id} requires ${object.dialect}`, meta: { feature: "migrationObject", dialect } });
8416
8581
  const physical = params.physical ?? (dialect === "postgres" ? await introspectPhysicalPostgres({ executor }) : dialect === "mysql" ? await introspectMysql({ executor }) : await introspectSqlite({ executor }));
8417
8582
  if (params.previous !== undefined)
8418
8583
  assertMigrationState({ report: await verifyMigrationState({ executor, expected: params.previous, dialect, ...params.probe === undefined ? {} : { probe: params.probe } }) });
@@ -8421,7 +8586,7 @@ async function planSchemaMigration(params) {
8421
8586
  const identity = object.identity;
8422
8587
  if (identity.kind !== "table" || physical.models.some((model) => (model.dbName ?? model.name) === identity.name.name) || normalizeSchema({ schema: physical, dialect }).joinTables.has(identity.name.name))
8423
8588
  continue;
8424
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "Catalog table is not visible to schema introspection; automatic planning cannot prove the complete physical state", meta: { reason: "inventory-unavailable", identity: object.identity } });
8589
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Catalog table is not visible to schema introspection; automatic planning cannot prove the complete physical state", meta: { reason: "inventory-unavailable", identity: object.identity } });
8425
8590
  }
8426
8591
  const states = resolved.unavailable.map((identity) => {
8427
8592
  const exists = identity.kind === "column" && [physical, params.previous?.schema].some((source) => source?.models.some((model) => (model.dbName ?? model.name) === identity.table.name && model.fields.some((field) => (field.dbName ?? field.name) === identity.column)));
@@ -8452,7 +8617,7 @@ async function planSchemaMigration(params) {
8452
8617
  }
8453
8618
  for (const object of legacyObjects) {
8454
8619
  if (objects.some((entry) => sqlObjectKey12({ identity: entry.identity }) === sqlObjectKey12({ identity: object.identity })))
8455
- throw new VibeError37({ code: "VIBE_SCHEMA_INVALID", message: "Duplicate combined and migration-only ownership", meta: { identity: object.identity } });
8620
+ throw new VibeError39({ code: "VIBE_SCHEMA_INVALID", message: "Duplicate combined and migration-only ownership", meta: { identity: object.identity } });
8456
8621
  const expected = object.expected ?? params.previous?.definitions.find((entry) => sqlObjectKey12({ identity: entry.identity }) === sqlObjectKey12({ identity: object.identity }));
8457
8622
  if (expected === undefined)
8458
8623
  states.push({ identity: object.identity, ownership: "migration", state: "unavailable", reason: "legacy-definition-required", differences: [] });
@@ -8467,7 +8632,8 @@ async function planSchemaMigration(params) {
8467
8632
  const protectedObjects = [...legacyObjects, ...objects, ...params.previous?.schema.migrationObjects ?? []];
8468
8633
  const stripped = preserveMigrationObjects({ from: stripExtensionArtifacts({ schema: physical, artifacts }), to: schema, objects: protectedObjects, namespace });
8469
8634
  const checked = await prepareCheckDiff({ executor, from: stripped, to: schema, dialect, ...params.probe === undefined ? {} : { probe: params.probe }, ...params.previous === undefined ? {} : { previous: params.previous }, ...params.replaceChecks === undefined ? {} : { replaceChecks: params.replaceChecks } });
8470
- const from = await prepareExclusionDiff({ ...params, from: checked, to: schema });
8635
+ const exclusionsPrepared = await prepareExclusionDiff({ ...params, from: checked, to: schema });
8636
+ const from = dialect === "postgres" ? await prepareIndexPredicateDiff({ executor, from: exclusionsPrepared, to: schema, namespace, ...params.probe === undefined ? {} : { probe: params.probe } }) : exclusionsPrepared;
8471
8637
  const steps = diffSchemas({ from, to: schema, dialect });
8472
8638
  const known = new Set(schemaObjectIdentities({ schema: params.previous?.schema ?? schema, dialect, namespace }).map((identity) => sqlObjectKey12({ identity })));
8473
8639
  const declaredIndexes = normalizeSchema({ schema: params.previous?.schema ?? schema, dialect });
@@ -8494,7 +8660,7 @@ async function planSchemaMigration(params) {
8494
8660
  if (object.inspectionUnavailable !== undefined)
8495
8661
  states.push({ identity: object.identity, ownership, state: "unavailable", reason: object.inspectionUnavailable, differences: [] });
8496
8662
  if (object.inspectionUnavailable !== undefined && invalid.rebuilt.has("table" in object.identity ? object.identity.table.name : object.identity.name.name))
8497
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "SQLite rebuild cannot discard an unrepresented constraint; declare its independent definition or use a reviewed migration", meta: { reason: "sqlite-preservation-unavailable", identity: object.identity } });
8663
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "SQLite rebuild cannot discard an unrepresented constraint; declare its independent definition or use a reviewed migration", meta: { reason: "sqlite-preservation-unavailable", identity: object.identity } });
8498
8664
  if (ownership === "unknown")
8499
8665
  states.push({ identity: object.identity, ownership, state: "unavailable", reason: "unmanaged", differences: [] });
8500
8666
  let collateral = "table" in object.identity && object.identity.table.namespace === namespace && droppedTables.has(object.identity.table.name);
@@ -8513,7 +8679,7 @@ async function planSchemaMigration(params) {
8513
8679
  for (const address of addresses) {
8514
8680
  const value = JSON.parse(String(address));
8515
8681
  if (!Array.isArray(value) || !Array.isArray(value[2]))
8516
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "Malformed catalog dependency address" });
8682
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Malformed catalog dependency address" });
8517
8683
  const names = value[2];
8518
8684
  if (names[0] !== namespace || typeof names[1] !== "string")
8519
8685
  continue;
@@ -8523,10 +8689,10 @@ async function planSchemaMigration(params) {
8523
8689
  }
8524
8690
  }
8525
8691
  if (dialect === "sqlite" && ownership === "unknown" && object.identity.kind === "generatedColumn" && invalid.rebuilt.has(object.identity.table.name))
8526
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "SQLite generated-column preservation requires an independent ownership declaration", meta: { reason: "sqlite-preservation-unavailable", identity: object.identity } });
8692
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "SQLite generated-column preservation requires an independent ownership declaration", meta: { reason: "sqlite-preservation-unavailable", identity: object.identity } });
8527
8693
  const removed = collateral || removals.some((identity) => sqlObjectKey12({ identity }) === key);
8528
8694
  if (removed && ownership === "migration")
8529
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "Automatic DDL would remove a migration-owned object", meta: { reason: "migration-owned-removal", identity: object.identity } });
8695
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Automatic DDL would remove a migration-owned object", meta: { reason: "migration-owned-removal", identity: object.identity } });
8530
8696
  if (removed && ownership === "unknown" && object.backingConstraint === undefined)
8531
8697
  unmanagedRemovals.push(object.identity);
8532
8698
  }
@@ -8537,6 +8703,19 @@ async function planSchemaMigration(params) {
8537
8703
  if (artifact.owns.kind === "trigger" && invalidated.has(artifact.owns.table))
8538
8704
  triggers?.delete(artifact.owns.name);
8539
8705
  const missing = planMissingArtifacts({ introspected: physical, artifacts, installed: { ...installed, ...triggers === undefined ? {} : { triggers } } });
8706
+ const previousDeclarations = params.previousDeclarations ?? params.previous?.schema;
8707
+ const previousArtifacts = previousDeclarations === undefined ? undefined : collectExtensionArtifacts({ schema: previousDeclarations, dialect, extensions: params.extensions ?? [] });
8708
+ const missingIds = new Set(missing.map((artifact) => artifact.id));
8709
+ const probed = dialect === "postgres" && params.probe === "rollback" && params.probeArtifacts === true ? await probeChangedArtifacts({ executor, namespace, artifacts: collected.objects.filter((artifact) => !missingIds.has(artifact.id)) }) : [];
8710
+ const rebuilt = params.rebuildArtifacts === true ? collected.objects.filter((artifact) => !missingIds.has(artifact.id)) : planChangedArtifacts({ ...previousArtifacts === undefined ? {} : { previous: previousArtifacts }, current: collected, missing, probed: probed.map((entry) => entry.artifact) });
8711
+ const probedById = new Map(probed.map((entry) => [entry.artifact.id, entry]));
8712
+ const rebuiltArtifacts = rebuilt.map((artifact) => {
8713
+ const probe = probedById.get(artifact.id);
8714
+ if (probe !== undefined)
8715
+ return probe;
8716
+ const declared = previousArtifacts?.objects.find((entry) => entry.id === artifact.id);
8717
+ return { artifact, restore: [...(declared ?? artifact).create] };
8718
+ });
8540
8719
  const restore = new Map;
8541
8720
  const preservedColumns = new Map;
8542
8721
  const preservedDefaults = new Map;
@@ -8560,11 +8739,11 @@ async function planSchemaMigration(params) {
8560
8739
  continue;
8561
8740
  const live = await inspectSqlObject({ executor, dialect, identity });
8562
8741
  if (live.state !== "present" || identity.kind !== "columnDefault" && typeof live.definition.facts.columnDefinition !== "string")
8563
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "Cannot read the verified SQLite column definition for preservation", meta: { reason: "sqlite-preservation-unavailable", identity } });
8742
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Cannot read the verified SQLite column definition for preservation", meta: { reason: "sqlite-preservation-unavailable", identity } });
8564
8743
  if (identity.kind === "columnDefault") {
8565
8744
  const definition = live.definition.facts.definition;
8566
8745
  if (definition !== null && typeof definition !== "string")
8567
- throw new VibeError37({ code: "VIBE_MIGRATION", message: "Cannot preserve SQLite default", meta: { identity } });
8746
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Cannot preserve SQLite default", meta: { identity } });
8568
8747
  const defaults = preservedDefaults.get(identity.table.name) ?? new Map;
8569
8748
  defaults.set(identity.column, definition);
8570
8749
  preservedDefaults.set(identity.table.name, defaults);
@@ -8586,10 +8765,12 @@ async function planSchemaMigration(params) {
8586
8765
  return { ...rest, ...typeof expression === "string" ? { default: { kind: "dbgenerated", sql: expression } } : {} };
8587
8766
  }) })) };
8588
8767
  const core = renderSteps({ steps, dialect, from: dialect === "sqlite" ? physical : from, to: dialect === "mysql" ? { ...target, migrationObjects: protectedObjects } : target, sqliteRestore: restore, sqliteColumns: preservedColumns });
8768
+ const planned = new Set([...missing, ...rebuilt].map((artifact) => artifact.id));
8589
8769
  const sql = [
8590
8770
  ...artifactCreateSql({ artifacts: missing.filter((artifact) => artifact.owns.kind === "postgresExtension") }),
8591
8771
  ...core,
8592
- ...artifactCreateSql({ artifacts: missing.filter((artifact) => artifact.owns.kind !== "postgresExtension" && !(artifact.owns.kind === "trigger" && invalid.rebuilt.has(artifact.owns.table))) }),
8772
+ ...artifactDropSql({ artifacts: rebuilt }),
8773
+ ...artifactCreateSql({ artifacts: collected.objects.filter((artifact) => planned.has(artifact.id) && !(artifact.owns.kind === "trigger" && invalid.rebuilt.has(artifact.owns.table))) }),
8593
8774
  ...creates
8594
8775
  ];
8595
8776
  if (sql.length === 0) {
@@ -8601,7 +8782,7 @@ async function planSchemaMigration(params) {
8601
8782
  states.push(...report.objects);
8602
8783
  }
8603
8784
  const blocked = states.some((state) => state.reason === "dependency-inspection-unavailable" || state.ownership !== "unknown" && state.reason !== "legacy-definition-required" && (state.state === "unavailable" || state.state === "changed" || state.state === "missing" && sql.length === 0));
8604
- return { physical, from, to: schema, namespace, steps, objects: states, unmanagedRemovals, blocked, sql: blocked ? [] : sql };
8785
+ return { physical, from, to: schema, namespace, steps, objects: states, unmanagedRemovals, blocked, sql: blocked ? [] : sql, rebuiltArtifacts };
8605
8786
  }
8606
8787
 
8607
8788
  // packages/migrate/src/replay-plan.ts
@@ -8628,7 +8809,8 @@ async function planReplayMigration(params) {
8628
8809
  const probe = reference.dialect === "postgres" ? "rollback" : reference.dialect === "mysql" ? "temporary" : "none";
8629
8810
  if (probe === "rollback")
8630
8811
  await executor({ text: "BEGIN" });
8631
- const plan = await Promise.resolve().then(() => planSchemaMigration({ executor, schema, physical: reference.state.schema, physicalInventory: reference.inventory, dialect: reference.dialect, namespace: reference.namespace, extensions: params.extensions, replaceChecks: params.replaceChecks, probe })).finally(async () => {
8812
+ const previousDeclarations = lastDeclaredSchema({ migrations: params.migrations });
8813
+ const plan = await Promise.resolve().then(() => planSchemaMigration({ executor, schema, physical: reference.state.schema, physicalInventory: reference.inventory, dialect: reference.dialect, namespace: reference.namespace, extensions: params.extensions, replaceChecks: params.replaceChecks, probe, probeArtifacts: probe === "rollback", ...previousDeclarations === undefined ? {} : { previousDeclarations } })).finally(async () => {
8632
8814
  if (probe === "rollback")
8633
8815
  await executor({ text: "ROLLBACK" });
8634
8816
  });
@@ -8647,24 +8829,24 @@ async function planReplayMigration(params) {
8647
8829
  const retainedObjects = reference.inventory.filter((object) => !declared.has(sqlObjectKey13({ identity: object.identity })) && !removals.has(sqlObjectKey13({ identity: object.identity })) && (object.identity.kind === "function" || object.identity.kind === "trigger" || historicalObjects.has(sqlObjectKey13({ identity: object.identity })))).map((object) => object.identity);
8648
8830
  const removedRegistrations = [...historicalObjects].filter(([key]) => present.has(key) && !declared.has(key)).map(([, identity]) => identity);
8649
8831
  if (removedRegistrations.length > 0)
8650
- throw new VibeError38({ code: "VIBE_MIGRATION", message: "Custom registrations removed from declarations still exist in replayed history. Restore the registration or supply reviewed SQL removing the exact named objects before generating again.", meta: { reason: "migration-object-removal-review-required", shadowReusable: true, objects: removedRegistrations } });
8832
+ throw new VibeError40({ code: "VIBE_MIGRATION", message: "Custom registrations removed from declarations still exist in replayed history. Restore the registration or supply reviewed SQL removing the exact named objects before generating again.", meta: { reason: "migration-object-removal-review-required", shadowReusable: true, objects: removedRegistrations } });
8651
8833
  return { ...plan, requiredRemovals: [...removals.values()], retainedObjects, securityChanges: securityChangesOf({ steps: plan.steps }), replayRemovals: params.migrations.flatMap((migration) => migration.desiredState?.unmanagedRemovals ?? []) };
8652
8834
  }
8653
8835
  function assertReplayRemovals(params) {
8654
8836
  const wanted = new Set([...params.plan.requiredRemovals, ...params.plan.replayRemovals].map((identity) => sqlObjectKey13({ identity })));
8655
8837
  const keys = params.approved.map((identity) => sqlObjectKey13({ identity }));
8656
8838
  if (new Set(keys).size !== keys.length)
8657
- throw new VibeError38({ code: "VIBE_MIGRATION", message: "Removal decisions contain duplicate identities", meta: { reason: "removal-decision-invalid", shadowReusable: true } });
8839
+ throw new VibeError40({ code: "VIBE_MIGRATION", message: "Removal decisions contain duplicate identities", meta: { reason: "removal-decision-invalid", shadowReusable: true } });
8658
8840
  const unused = params.approved.filter((identity) => !wanted.has(sqlObjectKey13({ identity })));
8659
8841
  if (unused.length > 0)
8660
- throw new VibeError38({ code: "VIBE_MIGRATION", message: "Removal decisions do not identify proposed removals. Custom objects without a generated removal require a reviewed hand-authored SQL migration.", meta: { reason: "removal-decision-unused", shadowReusable: true, objects: unused } });
8842
+ throw new VibeError40({ code: "VIBE_MIGRATION", message: "Removal decisions do not identify proposed removals. Custom objects without a generated removal require a reviewed hand-authored SQL migration.", meta: { reason: "removal-decision-unused", shadowReusable: true, objects: unused } });
8661
8843
  assertNamedRemovals({ removals: params.plan.requiredRemovals, approved: params.approved, acceptIntegrityLoss: params.acceptIntegrityLoss });
8662
8844
  }
8663
8845
  // packages/migrate/src/baseline.ts
8664
- import { VibeError as VibeError43, sqlObjectKey as sqlObjectKey16 } from "@vibeorm/schema";
8846
+ import { VibeError as VibeError45, sqlObjectKey as sqlObjectKey16 } from "@vibeorm/schema";
8665
8847
 
8666
8848
  // packages/migrate/src/reference-state.ts
8667
- import { VibeError as VibeError39, sqlObjectKey as sqlObjectKey14 } from "@vibeorm/schema";
8849
+ import { VibeError as VibeError41, sqlObjectKey as sqlObjectKey14 } from "@vibeorm/schema";
8668
8850
  async function captureMigrationReference(params) {
8669
8851
  const namespace = await migrationNamespace({ executor: params.referenceExecutor, dialect: params.dialect });
8670
8852
  const identities = [...schemaObjectIdentities({ schema: params.schema, dialect: params.dialect, namespace }), ...(params.schema.migrationObjects ?? []).map((object) => object.identity)];
@@ -8674,14 +8856,14 @@ async function captureMigrationReference(params) {
8674
8856
  continue;
8675
8857
  const result = await inspectSqlObject({ executor: params.referenceExecutor, dialect: params.dialect, identity });
8676
8858
  if (result.state !== "present")
8677
- throw new VibeError39({ code: "VIBE_MIGRATION", message: "Independent reference object is missing or unavailable", meta: { reason: "reference-unavailable", identity, state: result.state } });
8859
+ throw new VibeError41({ code: "VIBE_MIGRATION", message: "Independent reference object is missing or unavailable", meta: { reason: "reference-unavailable", identity, state: result.state } });
8678
8860
  definitions.push(result.definition);
8679
8861
  }
8680
8862
  let schema = params.schema;
8681
8863
  if (params.dialect === "postgres" && schema.models.some((model) => model.fields.some((field) => field.isUnsupported === true))) {
8682
8864
  const resolved = await resolvePostgresTypeIdentities({ executor: params.referenceExecutor, schema, mode: "reference" });
8683
8865
  if (resolved.unavailable.length > 0)
8684
- throw new VibeError39({ code: "VIBE_MIGRATION", message: "Resolve unsupported types in the independent reference before capture", meta: { reason: "type-reference-required", columns: resolved.unavailable } });
8866
+ throw new VibeError41({ code: "VIBE_MIGRATION", message: "Resolve unsupported types in the independent reference before capture", meta: { reason: "type-reference-required", columns: resolved.unavailable } });
8685
8867
  const physical = await introspectPhysicalPostgres({ executor: params.referenceExecutor });
8686
8868
  for (const model of resolved.schema.models)
8687
8869
  for (const field of model.fields) {
@@ -8689,7 +8871,7 @@ async function captureMigrationReference(params) {
8689
8871
  continue;
8690
8872
  const actual = physical.models.find((entry) => entry.name === (model.dbName ?? model.name))?.fields.find((entry) => entry.name === (field.dbName ?? field.name));
8691
8873
  if (actual === undefined || columnTypeKey({ field }) !== columnTypeKey({ field: actual }))
8692
- throw new VibeError39({ code: "VIBE_MIGRATION", message: "Independent reference column does not match its declared PostgreSQL type", meta: { reason: "reference-type-mismatch", table: model.dbName ?? model.name, column: field.dbName ?? field.name } });
8874
+ throw new VibeError41({ code: "VIBE_MIGRATION", message: "Independent reference column does not match its declared PostgreSQL type", meta: { reason: "reference-type-mismatch", table: model.dbName ?? model.name, column: field.dbName ?? field.name } });
8693
8875
  }
8694
8876
  schema = resolved.schema;
8695
8877
  }
@@ -8697,13 +8879,13 @@ async function captureMigrationReference(params) {
8697
8879
  }
8698
8880
 
8699
8881
  // packages/migrate/src/compile-desired-state.ts
8700
- import { VibeError as VibeError40 } from "@vibeorm/schema";
8882
+ import { VibeError as VibeError42 } from "@vibeorm/schema";
8701
8883
  import { renderExclusionSetup as renderExclusionSetup2, getSqlDialect as getSqlDialect12, renderMigrationServerVersion as renderMigrationServerVersion2 } from "@vibeorm/sql";
8702
8884
  async function compileDesiredState(params) {
8703
8885
  if (params.dialect !== "postgres")
8704
- throw new VibeError40({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Rollback declaration compilation requires PostgreSQL", meta: { feature: "desiredStateCompilation", dialect: params.dialect } });
8886
+ throw new VibeError42({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Rollback declaration compilation requires PostgreSQL", meta: { feature: "desiredStateCompilation", dialect: params.dialect } });
8705
8887
  if (params.steps.some((step) => step.kind === "alterColumn" || step.kind === "addColumn" || step.kind === "addEnumValue"))
8706
- throw new VibeError40({ code: "VIBE_MIGRATION", message: "CHECK compilation after column or enum changes requires an independently built reference with the new type context", meta: { reason: "reference-required" } });
8888
+ throw new VibeError42({ code: "VIBE_MIGRATION", message: "CHECK compilation after column or enum changes requires an independently built reference with the new type context", meta: { reason: "reference-required" } });
8707
8889
  const definitions = (params.schema.migrationObjects ?? []).flatMap((object) => object.expected === undefined ? [] : [object.expected]);
8708
8890
  await params.executor({ text: "SAVEPOINT vibeorm_desired_state" });
8709
8891
  try {
@@ -8726,7 +8908,7 @@ async function compileDesiredState(params) {
8726
8908
  const query = renderMigrationServerVersion2({ dialect: getSqlDialect12({ dialect: params.dialect }) });
8727
8909
  const version = (await params.executor({ text: query.text, values: [] }))[0]?.version;
8728
8910
  if (typeof version !== "string")
8729
- throw new VibeError40({ code: "VIBE_MIGRATION", message: "Cannot determine definition normalization version" });
8911
+ throw new VibeError42({ code: "VIBE_MIGRATION", message: "Cannot determine definition normalization version" });
8730
8912
  return { ...createDesiredState({ schema: { ...params.schema, models }, dialect: params.dialect, definitions }), normalization: { format: "catalog-v1", dialect: params.dialect, serverVersion: version } };
8731
8913
  } finally {
8732
8914
  await params.executor({ text: "ROLLBACK TO SAVEPOINT vibeorm_desired_state" });
@@ -8735,7 +8917,7 @@ async function compileDesiredState(params) {
8735
8917
  }
8736
8918
 
8737
8919
  // packages/migrate/src/verify-history.ts
8738
- import { VibeError as VibeError42, sqlObjectKey as sqlObjectKey15 } from "@vibeorm/schema";
8920
+ import { VibeError as VibeError44, sqlObjectKey as sqlObjectKey15 } from "@vibeorm/schema";
8739
8921
  import { getSqlDialect as getSqlDialect13, renderReplayCoverageGaps as renderReplayCoverageGaps2 } from "@vibeorm/sql";
8740
8922
 
8741
8923
  // packages/migrate/src/compare-sqlite-primary-key.ts
@@ -8808,7 +8990,7 @@ function compareSqlitePrimaryKeyRepresentations(params) {
8808
8990
  }
8809
8991
 
8810
8992
  // packages/migrate/src/compare-reference-rls.ts
8811
- import { VibeError as VibeError41 } from "@vibeorm/schema";
8993
+ import { VibeError as VibeError43 } from "@vibeorm/schema";
8812
8994
  function securityFacts(params) {
8813
8995
  return new Map(params.tables.filter((table) => table.enabled || table.force || table.policies.length > 0).map((table) => [table.table, {
8814
8996
  table: table.table,
@@ -8819,7 +9001,7 @@ function securityFacts(params) {
8819
9001
  }
8820
9002
  async function comparePostgresReferenceRls(params) {
8821
9003
  if (params.schema.rls !== undefined && params.referenceExecutor === undefined)
8822
- throw new VibeError41({ code: "VIBE_MIGRATION", message: "Native RLS verification requires the independently replayed reference connection; target policy probes are not permitted.", meta: { reason: "verification-rls-reference-required" } });
9004
+ throw new VibeError43({ code: "VIBE_MIGRATION", message: "Native RLS verification requires the independently replayed reference connection; target policy probes are not permitted.", meta: { reason: "verification-rls-reference-required" } });
8823
9005
  const expected = securityFacts({ tables: params.schema.rls === undefined ? [] : await readPostgresRls({ executor: params.referenceExecutor }) });
8824
9006
  const actual = securityFacts({ tables: await readPostgresRls({ executor: params.executor }) });
8825
9007
  const objects = [...new Set([...expected.keys(), ...actual.keys()])].sort().map((table) => {
@@ -8843,14 +9025,14 @@ function selectMigrationVerificationPrefix(params) {
8843
9025
  for (const [index, file] of params.migrations.entries()) {
8844
9026
  const previous = params.migrations[index - 1];
8845
9027
  if (seen.has(file.name) || previous !== undefined && previous.name.localeCompare(file.name) > 0) {
8846
- throw new VibeError42({ code: "VIBE_MIGRATION", message: "Verification requires a complete local migration chain in unique name order", meta: { reason: "verification-history-order", migration: file.name } });
9028
+ throw new VibeError44({ code: "VIBE_MIGRATION", message: "Verification requires a complete local migration chain in unique name order", meta: { reason: "verification-history-order", migration: file.name } });
8847
9029
  }
8848
9030
  seen.add(file.name);
8849
9031
  }
8850
9032
  for (const [index, row] of params.recorded.entries()) {
8851
9033
  const file = params.migrations[index];
8852
9034
  if (row.state !== "applied" || row.statementIndex < 0 || row.checksum === "" || file?.name !== row.name || file.desiredStatePending === true || migrationChecksum(file) !== row.checksum) {
8853
- throw new VibeError42({ code: "VIBE_MIGRATION", message: "Verification requires an exact, complete, checksum-verified applied prefix; inspect migrate status and resolve the history discrepancy first", meta: { reason: "verification-history-unverified", migration: row.name, state: row.state } });
9035
+ throw new VibeError44({ code: "VIBE_MIGRATION", message: "Verification requires an exact, complete, checksum-verified applied prefix; inspect migrate status and resolve the history discrepancy first", meta: { reason: "verification-history-unverified", migration: row.name, state: row.state } });
8854
9036
  }
8855
9037
  }
8856
9038
  return params.migrations.slice(0, params.recorded.length);
@@ -8867,7 +9049,7 @@ async function verifyMigrationReference(params) {
8867
9049
  const coverage = renderReplayCoverageGaps2({ dialect: getSqlDialect13({ dialect }), namespace });
8868
9050
  const gaps = await executor({ text: coverage.text, values: [...coverage.values] });
8869
9051
  if (gaps.length > 0)
8870
- throw new VibeError42({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Target contains objects whose full definitions are outside migration inspection coverage; verification is unavailable. No target changes were made.", meta: { feature: "targetInventoryCoverage", dialect, namespace, objects: gaps } });
9052
+ throw new VibeError44({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Target contains objects whose full definitions are outside migration inspection coverage; verification is unavailable. No target changes were made.", meta: { feature: "targetInventoryCoverage", dialect, namespace, objects: gaps } });
8871
9053
  const security = dialect === "postgres" ? await comparePostgresReferenceRls({ executor, referenceExecutor: params.referenceExecutor, schema: reference.state.schema }) : { inSync: true, objects: [] };
8872
9054
  const inspected = await verifyMigrationState({ executor, dialect, expected: reference.state, probe: "none", batch: true });
8873
9055
  const structural = dialect === "sqlite" ? compareSqlitePrimaryKeyRepresentations({ report: inspected }) : inspected;
@@ -9014,7 +9196,7 @@ async function mysqlComparisonFacts(params) {
9014
9196
  return { ...facts, members };
9015
9197
  }
9016
9198
  function referenceContextError() {
9017
- return new VibeError42({ code: "VIBE_MIGRATION", message: "Replay and target dialect/namespace differ; safe reference translation is unavailable. Use a supported same-namespace reference setup", meta: { reason: "verification-reference-context" } });
9199
+ return new VibeError44({ code: "VIBE_MIGRATION", message: "Replay and target dialect/namespace differ; safe reference translation is unavailable. Use a supported same-namespace reference setup", meta: { reason: "verification-reference-context" } });
9018
9200
  }
9019
9201
 
9020
9202
  // packages/migrate/src/baseline.ts
@@ -9022,19 +9204,19 @@ function generateBaselineMigration(params) {
9022
9204
  const objects = orderedMigrationObjects({ objects: params.schema.migrationObjects ?? [] });
9023
9205
  for (const object of objects)
9024
9206
  if (object.dialect !== params.dialect)
9025
- throw new VibeError43({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Baseline object ${object.id} requires ${object.dialect}`, meta: { identity: object.identity, dialect: params.dialect } });
9207
+ throw new VibeError45({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Baseline object ${object.id} requires ${object.dialect}`, meta: { identity: object.identity, dialect: params.dialect } });
9026
9208
  const prerequisites = objects.filter((object) => object.identity.kind === "postgresExtension" || object.identity.kind === "enum" || object.identity.kind === "sequence");
9027
9209
  const prerequisiteKeys = new Set(prerequisites.map((object) => sqlObjectKey16({ identity: object.identity })));
9028
9210
  for (const object of prerequisites) {
9029
9211
  const unresolved = object.dependsOn.filter((identity) => !prerequisiteKeys.has(sqlObjectKey16({ identity })));
9030
9212
  if (unresolved.length > 0)
9031
- throw new VibeError43({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Baseline prerequisite depends on objects created later. Supply reviewed initial SQL with an explicit dependency order.", meta: { reason: "baseline-prerequisite-order", identity: object.identity, dependencies: unresolved } });
9213
+ throw new VibeError45({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Baseline prerequisite depends on objects created later. Supply reviewed initial SQL with an explicit dependency order.", meta: { reason: "baseline-prerequisite-order", identity: object.identity, dependencies: unresolved } });
9032
9214
  }
9033
9215
  const schema = { ...params.schema, migrationObjects: objects.filter((object) => !prerequisiteKeys.has(sqlObjectKey16({ identity: object.identity }))) };
9034
9216
  const generated = generateMigration({ from: { datasource: schema.datasource, models: [], enums: [], extensions: [] }, to: schema, name: params.name, dialect: params.dialect, extensions: params.extensions ?? [] });
9035
9217
  const sql = splitSqlStatements({ sql: joinSqlStatements({ sql: [...prerequisites.flatMap((object) => object.create), ...generated.sql] }), dialect: params.dialect });
9036
9218
  if (sql.length === 0)
9037
- throw new VibeError43({ code: "VIBE_MIGRATION", message: "A baseline must create declared database objects", meta: { reason: "baseline-empty" } });
9219
+ throw new VibeError45({ code: "VIBE_MIGRATION", message: "A baseline must create declared database objects", meta: { reason: "baseline-empty" } });
9038
9220
  return {
9039
9221
  name: generated.name,
9040
9222
  sql,
@@ -9063,17 +9245,17 @@ async function verifyBaselineDeclarations(params) {
9063
9245
  async function verifyBaselineTarget(params) {
9064
9246
  const { reference } = params;
9065
9247
  if (reference.unavailable.length > 0 || reference.inventory.some((object) => object.inspectionUnavailable !== undefined))
9066
- throw new VibeError43({ code: "VIBE_MIGRATION", message: "Baseline reference contains objects that cannot be inspected. Supply supported reviewed declarations before adoption.", meta: { reason: "baseline-reference-unavailable", objects: reference.unavailable, inventory: reference.inventory.filter((object) => object.inspectionUnavailable !== undefined) } });
9248
+ throw new VibeError45({ code: "VIBE_MIGRATION", message: "Baseline reference contains objects that cannot be inspected. Supply supported reviewed declarations before adoption.", meta: { reason: "baseline-reference-unavailable", objects: reference.unavailable, inventory: reference.inventory.filter((object) => object.inspectionUnavailable !== undefined) } });
9067
9249
  const comparison = await verifyMigrationReference({ executor: params.executor, dialect: reference.dialect, reference, referenceExecutor: params.referenceExecutor }).catch((cause) => {
9068
- if (cause instanceof VibeError43 && cause.meta.reason === "verification-rls-reference-required")
9069
- throw new VibeError43({ code: cause.code, message: cause.message, meta: { reason: "baseline-rls-reference-required" }, cause });
9250
+ if (cause instanceof VibeError45 && cause.meta.reason === "verification-rls-reference-required")
9251
+ throw new VibeError45({ code: cause.code, message: cause.message, meta: { reason: "baseline-rls-reference-required" }, cause });
9070
9252
  throw cause;
9071
9253
  });
9072
9254
  const security = comparison.objects.filter((object) => object.reason === "native-rls-mismatch");
9073
9255
  if (security.length > 0)
9074
- throw new VibeError43({ code: "VIBE_MIGRATION", message: "Target native RLS policies or flags differ from the independent baseline. Restore the reviewed security declarations before recording; no target policies were changed.", meta: { reason: "baseline-rls-mismatch", shadowReusable: true, expected: security.flatMap((object) => object.differences.flatMap((difference) => difference.expected === undefined ? [] : [difference.expected])), actual: security.flatMap((object) => object.differences.flatMap((difference) => difference.actual === undefined ? [] : [difference.actual])) } });
9256
+ throw new VibeError45({ code: "VIBE_MIGRATION", message: "Target native RLS policies or flags differ from the independent baseline. Restore the reviewed security declarations before recording; no target policies were changed.", meta: { reason: "baseline-rls-mismatch", shadowReusable: true, expected: security.flatMap((object) => object.differences.flatMap((difference) => difference.expected === undefined ? [] : [difference.expected])), actual: security.flatMap((object) => object.differences.flatMap((difference) => difference.actual === undefined ? [] : [difference.actual])) } });
9075
9257
  if (comparison.unavailable.length > 0)
9076
- throw new VibeError43({ code: "VIBE_MIGRATION", message: "Baseline comparison contains objects whose definitions cannot be verified in the target context; use a supported reference before adoption.", meta: { reason: "baseline-target-unavailable", shadowReusable: true, objects: comparison.unavailable } });
9258
+ throw new VibeError45({ code: "VIBE_MIGRATION", message: "Baseline comparison contains objects whose definitions cannot be verified in the target context; use a supported reference before adoption.", meta: { reason: "baseline-target-unavailable", shadowReusable: true, objects: comparison.unavailable } });
9077
9259
  const report = { inSync: comparison.objects.every((object) => object.state === "matching"), objects: comparison.objects };
9078
9260
  assertMigrationState({ report });
9079
9261
  const unmanaged = comparison.unmanaged.map((object) => object.identity);
@@ -9081,14 +9263,14 @@ async function verifyBaselineTarget(params) {
9081
9263
  const exclusions = params.excludeUnmanaged ?? [];
9082
9264
  const excluded = new Set(exclusions.map((identity) => sqlObjectKey16({ identity })));
9083
9265
  if (excluded.size !== exclusions.length || exclusions.some((identity) => !extras.has(sqlObjectKey16({ identity }))))
9084
- throw new VibeError43({ code: "VIBE_CONFIG", message: "Baseline exclusions must uniquely name actual unmanaged target objects, never declared objects", meta: { reason: "baseline-exclusion-invalid", shadowReusable: true, exclusions } });
9266
+ throw new VibeError45({ code: "VIBE_CONFIG", message: "Baseline exclusions must uniquely name actual unmanaged target objects, never declared objects", meta: { reason: "baseline-exclusion-invalid", shadowReusable: true, exclusions } });
9085
9267
  const unreviewed = unmanaged.filter((identity) => !excluded.has(sqlObjectKey16({ identity })));
9086
9268
  if (unreviewed.length > 0)
9087
- throw new VibeError43({ code: "VIBE_MIGRATION", message: "Target has unmanaged objects. Register their SQL or explicitly exclude each identity with --exclude-unmanaged; no target objects were removed.", meta: { reason: "baseline-unmanaged-objects", shadowReusable: true, objects: unreviewed } });
9269
+ throw new VibeError45({ code: "VIBE_MIGRATION", message: "Target has unmanaged objects. Register their SQL or explicitly exclude each identity with --exclude-unmanaged; no target objects were removed.", meta: { reason: "baseline-unmanaged-objects", shadowReusable: true, objects: unreviewed } });
9088
9270
  return { ...report, unmanaged };
9089
9271
  }
9090
9272
  // packages/migrate/src/baseline-record.ts
9091
- import { VibeError as VibeError44 } from "@vibeorm/schema";
9273
+ import { VibeError as VibeError46 } from "@vibeorm/schema";
9092
9274
  import { getSqlDialect as getSqlDialect15, renderStatement } from "@vibeorm/sql";
9093
9275
 
9094
9276
  // packages/migrate/src/history.ts
@@ -9104,20 +9286,20 @@ async function readMigrationHistory(params) {
9104
9286
 
9105
9287
  // packages/migrate/src/baseline-record.ts
9106
9288
  function transactionFailure(params) {
9107
- if (params.cause instanceof VibeError44)
9289
+ if (params.cause instanceof VibeError46)
9108
9290
  return params.cause;
9109
- return new VibeError44({ code: "VIBE_MIGRATION", message: "SQLite baseline recording failed; inspect the journal and transaction outcome before retrying.", meta: { reason: "baseline-record-transaction-failed" }, cause: params.cause });
9291
+ return new VibeError46({ code: "VIBE_MIGRATION", message: "SQLite baseline recording failed; inspect the journal and transaction outcome before retrying.", meta: { reason: "baseline-record-transaction-failed" }, cause: params.cause });
9110
9292
  }
9111
9293
  async function recordBaselineMigration(params) {
9112
9294
  if (params.migration.moduleOrigin !== undefined)
9113
- throw new VibeError44({ code: "VIBE_MIGRATION", message: "Package module migrations must use the immutable module installation workflow, not baseline adoption", meta: { reason: "baseline-module-unsupported" } });
9295
+ throw new VibeError46({ code: "VIBE_MIGRATION", message: "Package module migrations must use the immutable module installation workflow, not baseline adoption", meta: { reason: "baseline-module-unsupported" } });
9114
9296
  validateMigrationReplay({ dialect: params.dialect, migrations: [params.migration], acceptSecurityChanges: params.acceptSecurityChanges });
9115
9297
  await withMigrationLock({ executor: params.executor, dialect: params.dialect, run: async (executor) => {
9116
9298
  const record = async () => {
9117
9299
  const assertEmpty = async () => {
9118
9300
  const history = await readMigrationHistory({ executor, migrations: [params.migration], dialect: params.dialect });
9119
9301
  if (history.recorded.length > 0)
9120
- throw new VibeError44({ code: "VIBE_MIGRATION", message: "Baseline recording requires an absent or empty migration journal. Use normal apply or explicit recovery for existing history.", meta: { reason: "baseline-journal-not-empty", shadowReusable: true, recorded: history.recorded.map((row) => ({ name: row.name, state: row.state })) } });
9302
+ throw new VibeError46({ code: "VIBE_MIGRATION", message: "Baseline recording requires an absent or empty migration journal. Use normal apply or explicit recovery for existing history.", meta: { reason: "baseline-journal-not-empty", shadowReusable: true, recorded: history.recorded.map((row) => ({ name: row.name, state: row.state })) } });
9121
9303
  };
9122
9304
  await assertEmpty();
9123
9305
  await params.verify({ executor });
@@ -9142,14 +9324,14 @@ async function recordBaselineMigration(params) {
9142
9324
  await executor({ text: "COMMIT" });
9143
9325
  }).then(undefined, async (cause) => {
9144
9326
  await executor({ text: "ROLLBACK" }).then(undefined, (rollback) => {
9145
- throw new VibeError44({ code: "VIBE_MIGRATION", message: "Baseline recording failed and its SQLite transaction could not be rolled back. Inspect the journal and connection state before retrying; the outcome is uncertain.", meta: { reason: "baseline-record-rollback-failed" }, cause: new AggregateError([cause, rollback], "Baseline recording and rollback failed") });
9327
+ throw new VibeError46({ code: "VIBE_MIGRATION", message: "Baseline recording failed and its SQLite transaction could not be rolled back. Inspect the journal and connection state before retrying; the outcome is uncertain.", meta: { reason: "baseline-record-rollback-failed" }, cause: new AggregateError([cause, rollback], "Baseline recording and rollback failed") });
9146
9328
  });
9147
9329
  throw transactionFailure({ cause });
9148
9330
  });
9149
9331
  } });
9150
9332
  }
9151
9333
  // packages/migrate/src/down.ts
9152
- import { VibeError as VibeError45, sqlObjectKey as sqlObjectKey17 } from "@vibeorm/schema";
9334
+ import { VibeError as VibeError47, sqlObjectKey as sqlObjectKey17 } from "@vibeorm/schema";
9153
9335
  function buildRollbackTarget(params) {
9154
9336
  const { from, to, dialect } = params;
9155
9337
  const skipped = [];
@@ -9202,6 +9384,7 @@ function generateDownMigration(params) {
9202
9384
  extensions: params.extensions ?? []
9203
9385
  });
9204
9386
  const allArtifacts = [...artifacts.setup, ...artifacts.objects];
9387
+ const previous = collectExtensionArtifacts({ schema: params.previousDeclarations ?? from, dialect, extensions: params.extensions ?? [] });
9205
9388
  const owned = [...from.migrationObjects ?? [], ...to.migrationObjects ?? []];
9206
9389
  const strippedFrom = preserveMigrationObjects({ from: stripExtensionArtifacts({ schema: from, artifacts: allArtifacts }), to: from, objects: owned });
9207
9390
  const { target, skipped } = buildRollbackTarget({ from: strippedFrom, to, dialect });
@@ -9225,14 +9408,27 @@ function generateDownMigration(params) {
9225
9408
  return added?.kind === "addColumn" ? { ...field, isOptional: added.column.isOptional } : field;
9226
9409
  }) })) };
9227
9410
  const coreSql = renderSteps({ steps, dialect, from: to, to: dialect === "sqlite" ? sqlitePreservedSchema({ from, to: restored, objects: from.migrationObjects ?? [] }) : restored });
9228
- const created = planMissingArtifacts({ introspected: from, artifacts: allArtifacts });
9229
- const artifactDropSql = [];
9411
+ const declaredBefore = new Set([...previous.setup, ...previous.objects].map((artifact) => JSON.stringify([artifact.id, artifact.owns])));
9412
+ const created = params.physical === undefined ? allArtifacts.filter((artifact) => !declaredBefore.has(JSON.stringify([artifact.id, artifact.owns]))) : planMissingArtifacts({ introspected: params.physical, artifacts: allArtifacts, ...params.installed === undefined ? {} : { installed: params.installed } });
9413
+ const createdDropSql = [];
9230
9414
  for (const artifact of [...created].reverse()) {
9231
9415
  if (artifact.owns.kind === "postgresExtension") {
9232
9416
  skipped.push(`extension "${artifact.owns.name}" stays installed \u2014 other objects may depend on it (drop it manually if intended)`);
9233
9417
  continue;
9234
9418
  }
9235
- artifactDropSql.push(...artifact.drop);
9419
+ createdDropSql.push(...artifact.drop);
9420
+ }
9421
+ const rebuilt = params.rebuilt ?? planChangedArtifacts({ previous, current: artifacts, missing: created }).map((artifact) => {
9422
+ const declared = previous.objects.find((entry) => entry.id === artifact.id);
9423
+ return { artifact, ...declared === undefined ? {} : { restore: artifactCreateSql({ artifacts: [declared] }) } };
9424
+ });
9425
+ const restoreSql = [];
9426
+ for (const entry of rebuilt) {
9427
+ if (entry.restore === undefined) {
9428
+ skipped.push(`rebuilt ${entry.artifact.id} cannot be restored automatically \u2014 its previous definition is not spelled by the catalog; write it into a reviewed down migration`);
9429
+ continue;
9430
+ }
9431
+ restoreSql.push(...entry.restore);
9236
9432
  }
9237
9433
  const previousKeys = new Set((from.migrationObjects ?? []).map((object) => sqlObjectKey17({ identity: object.identity })));
9238
9434
  const ownedDropSql = [];
@@ -9244,30 +9440,32 @@ function generateDownMigration(params) {
9244
9440
  continue;
9245
9441
  }
9246
9442
  if (object.drop.length === 0)
9247
- throw new VibeError45({ code: "VIBE_MIGRATION", message: `Migration object ${object.id} needs reviewed reverse SQL`, meta: { reason: "migration-object-reverse-required", id: object.id } });
9443
+ throw new VibeError47({ code: "VIBE_MIGRATION", message: `Migration object ${object.id} needs reviewed reverse SQL`, meta: { reason: "migration-object-reverse-required", id: object.id } });
9248
9444
  ownedDropSql.push(...object.drop);
9249
9445
  }
9250
9446
  return {
9251
9447
  name,
9252
9448
  target: restored,
9253
- sql: [...ownedDropSql, ...artifactDropSql, ...coreSql],
9449
+ sql: [...ownedDropSql, ...createdDropSql, ...artifactDropSql({ artifacts: rebuilt.map((entry) => entry.artifact) }), ...coreSql, ...restoreSql],
9254
9450
  destructive: steps.some((step) => step.destructive),
9255
9451
  ...securityChangesOf({ steps }).length === 0 ? {} : { securityChanges: securityChangesOf({ steps }) },
9256
9452
  skipped
9257
9453
  };
9258
9454
  }
9259
9455
  // packages/migrate/src/push.ts
9260
- import { VibeError as VibeError46, assertValidSchemaIR as assertValidSchemaIR4, providerToDialect as providerToDialect4, sqlObjectKey as sqlObjectKey18 } from "@vibeorm/schema";
9456
+ import { VibeError as VibeError48, assertValidSchemaIR as assertValidSchemaIR4, providerToDialect as providerToDialect4, sqlObjectKey as sqlObjectKey18, unsupportedCapability as unsupportedCapability9 } from "@vibeorm/schema";
9261
9457
  import { DIALECT_CAPABILITIES as DIALECT_CAPABILITIES4 } from "@vibeorm/sql";
9262
9458
  async function push(params) {
9263
9459
  assertValidSchemaIR4({ schema: params.schema });
9264
9460
  const dialect = providerToDialect4({ provider: params.schema.datasource.provider });
9461
+ if (params.rebuildArtifacts === true && dialect !== "postgres")
9462
+ throw unsupportedCapability9({ dialect, feature: "rebuilding extension artifacts on push (rebuildArtifacts)", hint: "drop the extension's objects by hand and push again; the transactional rebuild exists on PostgreSQL only" });
9265
9463
  if (dialect !== "postgres")
9266
9464
  return pushChanges({ ...params, dialect });
9267
9465
  await params.executor({ text: "BEGIN" });
9268
9466
  let committed = false;
9269
9467
  try {
9270
- const result = await pushChanges({ ...params, dialect });
9468
+ const result = await pushChanges({ ...params, dialect, probe: params.probe ?? "rollback" });
9271
9469
  if (params.dryRun !== true) {
9272
9470
  await params.executor({ text: "COMMIT" });
9273
9471
  committed = true;
@@ -9289,6 +9487,7 @@ async function pushChanges(params) {
9289
9487
  ...params.previousState === undefined ? {} : { previous: params.previousState },
9290
9488
  ...params.extensions === undefined ? {} : { extensions: params.extensions },
9291
9489
  ...params.probe === undefined ? {} : { probe: params.probe },
9490
+ ...params.rebuildArtifacts === undefined ? {} : { rebuildArtifacts: params.rebuildArtifacts },
9292
9491
  ...params.replaceChecks === undefined ? {} : { replaceChecks: params.replaceChecks }
9293
9492
  });
9294
9493
  const { steps, sql } = plan;
@@ -9296,11 +9495,11 @@ async function pushChanges(params) {
9296
9495
  if (params.dryRun === true)
9297
9496
  return { steps, applied: [], planned: sql, securityChanges, objects: plan.objects, blocked: plan.blocked, unmanagedRemovals: plan.unmanagedRemovals };
9298
9497
  if (plan.blocked)
9299
- throw new VibeError46({ code: "VIBE_MIGRATION", message: "Schema push is blocked by unverified object definitions", meta: { reason: "migration-state-unverified", objects: plan.objects } });
9498
+ throw new VibeError48({ code: "VIBE_MIGRATION", message: "Schema push is blocked by unverified object definitions", meta: { reason: "migration-state-unverified", objects: plan.objects } });
9300
9499
  assertSecurityAcknowledgement({ securityChanges, ...params.acceptSecurityChanges === undefined ? {} : { acceptSecurityChanges: params.acceptSecurityChanges } });
9301
9500
  const destructive = steps.filter((step) => step.destructive);
9302
9501
  if (destructive.length > 0 && params.acceptDataLoss !== true)
9303
- throw new VibeError46({ code: "VIBE_MIGRATION", message: `push refused: ${destructive.length} destructive step(s) would lose data; pass acceptDataLoss: true: ${destructive.map((step) => describeStep({ step })).join("; ")}`, meta: { destructive: destructive.map((step) => describeStep({ step })) } });
9502
+ throw new VibeError48({ code: "VIBE_MIGRATION", message: `push refused: ${destructive.length} destructive step(s) would lose data; pass acceptDataLoss: true: ${destructive.map((step) => describeStep({ step })).join("; ")}`, meta: { destructive: destructive.map((step) => describeStep({ step })) } });
9304
9503
  assertRemovalAuthorization({
9305
9504
  steps,
9306
9505
  dialect,
@@ -9312,7 +9511,7 @@ async function pushChanges(params) {
9312
9511
  const approved = new Set((params.removeUnmanaged ?? []).map((identity) => sqlObjectKey18({ identity })));
9313
9512
  const unapproved = plan.unmanagedRemovals.filter((identity) => !approved.has(sqlObjectKey18({ identity })));
9314
9513
  if (unapproved.length > 0)
9315
- throw new VibeError46({ code: "VIBE_MIGRATION", message: "DDL would remove unmanaged dependent objects; approve their exact identities", meta: { reason: "unmanaged-removal-required", objects: unapproved } });
9514
+ throw new VibeError48({ code: "VIBE_MIGRATION", message: "DDL would remove unmanaged dependent objects; approve their exact identities", meta: { reason: "unmanaged-removal-required", objects: unapproved } });
9316
9515
  const wrap = dialect !== "postgres" && DIALECT_CAPABILITIES4[dialect].transactionalDdl && !usesSelfManagedTransactions({ sql });
9317
9516
  if (wrap)
9318
9517
  await executor({ text: "BEGIN" });
@@ -9330,7 +9529,7 @@ async function pushChanges(params) {
9330
9529
  } catch {}
9331
9530
  } else if (dialect === "sqlite")
9332
9531
  await cleanupSelfManagedFailure({ executor });
9333
- throw new VibeError46({ code: "VIBE_MIGRATION", message: `push failed while applying schema changes: ${error instanceof Error ? error.message : String(error)}`, meta: { statements: sql }, cause: error });
9532
+ throw new VibeError48({ code: "VIBE_MIGRATION", message: `push failed while applying schema changes: ${error instanceof Error ? error.message : String(error)}`, meta: { statements: sql }, cause: error });
9334
9533
  }
9335
9534
  return { steps, applied: sql, securityChanges, objects: plan.objects, desiredState: createDesiredState({ schema: plan.to, dialect }) };
9336
9535
  }
@@ -9345,23 +9544,23 @@ async function pull(params) {
9345
9544
  }
9346
9545
  }
9347
9546
  // packages/migrate/src/module-export.ts
9348
- import { VibeError as VibeError48 } from "@vibeorm/schema";
9547
+ import { VibeError as VibeError50 } from "@vibeorm/schema";
9349
9548
 
9350
9549
  // packages/migrate/src/module-bundle.ts
9351
- import { VibeError as VibeError47 } from "@vibeorm/schema";
9550
+ import { VibeError as VibeError49 } from "@vibeorm/schema";
9352
9551
  function defineModuleMigrations(params) {
9353
9552
  if (!Array.isArray(params.steps) || params.steps.length === 0)
9354
- throw new VibeError47({ code: "VIBE_MIGRATION", message: "A module upgrade bundle must contain its initial revision", meta: { reason: "module-chain-invalid", moduleId: params.moduleId } });
9553
+ throw new VibeError49({ code: "VIBE_MIGRATION", message: "A module upgrade bundle must contain its initial revision", meta: { reason: "module-chain-invalid", moduleId: params.moduleId } });
9355
9554
  const migrations = [];
9356
9555
  const revisions = new Set;
9357
9556
  let previous = null;
9358
9557
  for (const step of params.steps) {
9359
9558
  if (step.previousRevision !== previous || revisions.has(step.revision))
9360
- throw new VibeError47({ code: "VIBE_MIGRATION", message: `Module ${params.moduleId} has a duplicate revision or broken predecessor chain`, meta: { reason: "module-chain-invalid", moduleId: params.moduleId, revision: step.revision } });
9559
+ throw new VibeError49({ code: "VIBE_MIGRATION", message: `Module ${params.moduleId} has a duplicate revision or broken predecessor chain`, meta: { reason: "module-chain-invalid", moduleId: params.moduleId, revision: step.revision } });
9361
9560
  const origin = createModuleOrigin({ moduleId: params.moduleId, dialect: params.dialect, revision: step.revision, previousRevision: step.previousRevision, contracts: step.contracts, owned: step.owned, source: step.migration });
9362
9561
  const predecessor = migrations.at(-1)?.moduleOrigin;
9363
9562
  if (predecessor !== undefined && canonicalMigrationJson({ value: predecessor.source.desiredState.to }) !== canonicalMigrationJson({ value: origin.source.desiredState.from }))
9364
- throw new VibeError47({ code: "VIBE_MIGRATION", message: "Module source state differs from its predecessor", meta: { reason: "module-predecessor-state", moduleId: params.moduleId } });
9563
+ throw new VibeError49({ code: "VIBE_MIGRATION", message: "Module source state differs from its predecessor", meta: { reason: "module-predecessor-state", moduleId: params.moduleId } });
9365
9564
  validateMigrationReplay({ migrations: [origin.source], dialect: params.dialect, acceptSecurityChanges: true, acceptIntegrityLoss: true, removeUnmanaged: origin.source.desiredState?.unmanagedRemovals ?? [] });
9366
9565
  migrations.push(Object.freeze({ ...origin.source, moduleOrigin: origin }));
9367
9566
  revisions.add(step.revision);
@@ -9371,13 +9570,13 @@ function defineModuleMigrations(params) {
9371
9570
  }
9372
9571
  function moduleMigrationFiles(params) {
9373
9572
  if (params.bundle === null || typeof params.bundle !== "object" || !Array.isArray(params.bundle.migrations))
9374
- throw new VibeError47({ code: "VIBE_MIGRATION", message: "Module bundle must contain an immutable migration chain", meta: { reason: "module-chain-invalid" } });
9573
+ throw new VibeError49({ code: "VIBE_MIGRATION", message: "Module bundle must contain an immutable migration chain", meta: { reason: "module-chain-invalid" } });
9375
9574
  if (!/^[A-Za-z0-9_-]+$/.test(params.prefix))
9376
- throw new VibeError47({ code: "VIBE_MIGRATION", message: "Module migration prefix must be a safe local directory name", meta: { reason: "module-prefix-invalid" } });
9575
+ throw new VibeError49({ code: "VIBE_MIGRATION", message: "Module migration prefix must be a safe local directory name", meta: { reason: "module-prefix-invalid" } });
9377
9576
  const bundle = defineModuleMigrations({ moduleId: params.bundle.moduleId, dialect: params.bundle.dialect, steps: params.bundle.migrations.map((migration) => {
9378
9577
  const origin = migration?.moduleOrigin;
9379
9578
  if (origin === undefined || origin.moduleId !== params.bundle.moduleId || origin.dialect !== params.bundle.dialect)
9380
- throw new VibeError47({ code: "VIBE_MIGRATION", message: "Module bundle lacks matching immutable origin metadata", meta: { reason: "module-origin-invalid" } });
9579
+ throw new VibeError49({ code: "VIBE_MIGRATION", message: "Module bundle lacks matching immutable origin metadata", meta: { reason: "module-origin-invalid" } });
9381
9580
  assertModuleOrigin({ value: origin });
9382
9581
  restoreModuleMigration({ migration, origin });
9383
9582
  return { revision: origin.revision, previousRevision: origin.previousRevision, contracts: origin.contracts, owned: origin.owned, migration: origin.source };
@@ -9390,7 +9589,7 @@ function emitModuleMigrationExport(params) {
9390
9589
  moduleMigrationFiles({ bundle: params.bundle, prefix: "export" });
9391
9590
  const origin = params.bundle.migrations.at(-1).moduleOrigin;
9392
9591
  if (!origin.contracts.includes(params.contract))
9393
- throw new VibeError48({ code: "VIBE_CONFIG", message: "The package runtime contract is not supported by its migration head", meta: { reason: "module-contract-mismatch", moduleId: origin.moduleId } });
9592
+ throw new VibeError50({ code: "VIBE_CONFIG", message: "The package runtime contract is not supported by its migration head", meta: { reason: "module-contract-mismatch", moduleId: origin.moduleId } });
9394
9593
  const expectation = { moduleId: origin.moduleId, revision: origin.revision, artifactChecksum: origin.artifactChecksum, contract: params.contract };
9395
9594
  return [
9396
9595
  { name: "migrations.js", content: `// Generated immutable migration data; no driver, filesystem or runner import.
@@ -9407,9 +9606,9 @@ export const moduleReadiness = Object.freeze(${JSON.stringify(expectation)});
9407
9606
  ];
9408
9607
  }
9409
9608
  // packages/migrate/src/module-pending.ts
9410
- import { VibeError as VibeError49, sqlObjectKey as sqlObjectKey19 } from "@vibeorm/schema";
9609
+ import { VibeError as VibeError51, sqlObjectKey as sqlObjectKey19 } from "@vibeorm/schema";
9411
9610
  function refusal3(params) {
9412
- return new VibeError49({ code: "VIBE_MIGRATION", message: "Module registration or immutable upgrade history conflicts with the application's declarations; review the registration and deployment sequence", meta: params });
9611
+ return new VibeError51({ code: "VIBE_MIGRATION", message: "Module registration or immutable upgrade history conflicts with the application's declarations; review the registration and deployment sequence", meta: params });
9413
9612
  }
9414
9613
  function compose(params) {
9415
9614
  const { current, from, to } = params;
@@ -9517,16 +9716,16 @@ function pendingModuleMigrations(params) {
9517
9716
  return Object.freeze(result);
9518
9717
  }
9519
9718
  // packages/migrate/src/module-readiness.ts
9520
- import { VibeError as VibeError50 } from "@vibeorm/schema";
9719
+ import { VibeError as VibeError52 } from "@vibeorm/schema";
9521
9720
  async function inspectModuleReadiness(params) {
9522
9721
  const ids = new Set;
9523
9722
  for (const expected of params.modules) {
9524
9723
  if (ids.has(expected.moduleId) || !expected.moduleId || !expected.revision || !expected.contract || !/^[a-f0-9]{64}$/.test(expected.artifactChecksum))
9525
- throw new VibeError50({ code: "VIBE_CONFIG", message: "Module readiness needs a unique module id, revision, contract and immutable artifact checksum", meta: { reason: "module-readiness-expectation", moduleId: expected.moduleId } });
9724
+ throw new VibeError52({ code: "VIBE_CONFIG", message: "Module readiness needs a unique module id, revision, contract and immutable artifact checksum", meta: { reason: "module-readiness-expectation", moduleId: expected.moduleId } });
9526
9725
  ids.add(expected.moduleId);
9527
9726
  }
9528
9727
  if (params.compatibility !== undefined && params.compatibility !== "exact" && params.compatibility !== "contract")
9529
- throw new VibeError50({ code: "VIBE_CONFIG", message: "Unknown module compatibility mode", meta: { reason: "module-readiness-expectation" } });
9728
+ throw new VibeError52({ code: "VIBE_CONFIG", message: "Unknown module compatibility mode", meta: { reason: "module-readiness-expectation" } });
9530
9729
  const records = await readModuleJournal(params);
9531
9730
  const heads = moduleHistoryHeads({ records });
9532
9731
  const unresolved = [...records.values()].some(({ row, entry }) => row.error !== undefined || row.statementIndex < 0 || entry !== undefined && (!entry.complete || row.statementIndex !== entry.migration.sql.length));
@@ -9560,7 +9759,7 @@ async function inspectModuleReadiness(params) {
9560
9759
  return { ready: !unresolved && modules.every((module) => (module.revision === "matching" || module.revision === "compatible") && module.structural.status !== "drifted"), modules };
9561
9760
  }
9562
9761
  // packages/migrate/src/adoption.ts
9563
- import { VibeError as VibeError51 } from "@vibeorm/schema";
9762
+ import { VibeError as VibeError53 } from "@vibeorm/schema";
9564
9763
  async function adoptMigration(params) {
9565
9764
  const report = await verifyMigrationState({ executor: params.executor, expected: params.reference, dialect: params.dialect });
9566
9765
  assertMigrationState({ report });
@@ -9576,11 +9775,11 @@ function deployedDesiredState(params) {
9576
9775
  for (const [index, row] of params.recorded.entries()) {
9577
9776
  const file = params.migrations[index];
9578
9777
  if (row.state !== "applied" || row.checksum === "" || file?.name !== row.name || migrationChecksum(file) !== row.checksum)
9579
- throw new VibeError51({ code: "VIBE_MIGRATION", message: "Desired state requires complete, checksum-verified migration history", meta: { reason: "desired-state-history-unverified", migration: row.name, state: row.state } });
9778
+ throw new VibeError53({ code: "VIBE_MIGRATION", message: "Desired state requires complete, checksum-verified migration history", meta: { reason: "desired-state-history-unverified", migration: row.name, state: row.state } });
9580
9779
  }
9581
9780
  const applied = new Set(params.recorded.map((row) => row.name));
9582
9781
  if (params.migrations.some((migration) => applied.has(migration.name) && migration.desiredStatePending === true))
9583
- throw new VibeError51({ code: "VIBE_MIGRATION", message: "Applied unfinalized metadata cannot establish desired state", meta: { reason: "desired-state-history-unverified" } });
9782
+ throw new VibeError53({ code: "VIBE_MIGRATION", message: "Applied unfinalized metadata cannot establish desired state", meta: { reason: "desired-state-history-unverified" } });
9584
9783
  const last = [...params.migrations].reverse().find((migration) => applied.has(migration.name));
9585
9784
  return last?.desiredState?.to;
9586
9785
  }
@@ -9594,6 +9793,7 @@ export {
9594
9793
  adoptMigration,
9595
9794
  applyMigrations,
9596
9795
  artifactCreateSql,
9796
+ artifactDropSql,
9597
9797
  assertMigrationState,
9598
9798
  assertProbeMode,
9599
9799
  assertRemovalAuthorization,
@@ -9630,6 +9830,7 @@ export {
9630
9830
  introspectPostgres,
9631
9831
  introspectSqlite,
9632
9832
  isDefaultExecution,
9833
+ lastDeclaredSchema,
9633
9834
  legacyMigrationObjects,
9634
9835
  migrationChecksum,
9635
9836
  migrationNamespace,
@@ -9641,11 +9842,13 @@ export {
9641
9842
  parseExecutionSidecar,
9642
9843
  parseModuleOrigin,
9643
9844
  pendingModuleMigrations,
9845
+ planChangedArtifacts,
9644
9846
  planMissingArtifacts,
9645
9847
  planRenames,
9646
9848
  planReplayMigration,
9647
9849
  planSchemaMigration,
9648
9850
  prepareCheckDiff,
9851
+ probeChangedArtifacts,
9649
9852
  probeInstalledExtensionState,
9650
9853
  pull,
9651
9854
  push,
@@ -9672,4 +9875,4 @@ export {
9672
9875
  withMigrationReference
9673
9876
  };
9674
9877
 
9675
- //# debugId=077A2093537C73C664756E2164756E21
9878
+ //# debugId=9F525A8FE96388CC64756E2164756E21