@vibeorm/migrate 2.4.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
@@ -6798,6 +6798,7 @@ function collectExtensionArtifacts(params) {
6798
6798
  const { schema, dialect, extensions } = params;
6799
6799
  const setup = [];
6800
6800
  const objects = [];
6801
+ const groups = [];
6801
6802
  for (const extension of extensions) {
6802
6803
  const artifactsHook = extension.migrate?.artifacts;
6803
6804
  if (artifactsHook === undefined)
@@ -6805,6 +6806,7 @@ function collectExtensionArtifacts(params) {
6805
6806
  const declarations = extensionDeclarations({ schema, name: extension.name });
6806
6807
  if (Object.keys(declarations).length === 0 && extension.schema?.configOnly !== true)
6807
6808
  continue;
6809
+ const contributed = [];
6808
6810
  for (const artifact of artifactsHook({
6809
6811
  schema,
6810
6812
  dialect,
@@ -6812,10 +6814,19 @@ function collectExtensionArtifacts(params) {
6812
6814
  options: extension.options,
6813
6815
  declarations
6814
6816
  })) {
6815
- (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
+ }
6816
6823
  }
6824
+ groups.push({ extension: extension.name, objects: contributed });
6817
6825
  }
6818
- 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;
6819
6830
  }
6820
6831
  function ownedTableNames(params) {
6821
6832
  const exact = new Set;
@@ -6917,6 +6928,36 @@ async function probeInstalledExtensionState(params) {
6917
6928
  function artifactCreateSql(params) {
6918
6929
  return params.artifacts.flatMap((artifact) => [...artifact.create]);
6919
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
+ }
6920
6961
  // packages/migrate/src/runner.ts
6921
6962
  function migrationRlsSecurityChanges(params) {
6922
6963
  const source = params.migration.rls;
@@ -7067,6 +7108,7 @@ function generateMigration(params) {
7067
7108
  extensions: params.extensions ?? []
7068
7109
  });
7069
7110
  const allArtifacts = [...artifacts.setup, ...artifacts.objects];
7111
+ const rebuilt = planChangedArtifacts({ previous: collectExtensionArtifacts({ schema: from, dialect, extensions: params.extensions ?? [] }), current: artifacts, missing: [] });
7070
7112
  assertRetainedMigrationObjects({ from: from.migrationObjects ?? [], to: to.migrationObjects ?? [] });
7071
7113
  const strippedFrom = preserveMigrationObjects({ from: stripExtensionArtifacts({ schema: from, artifacts: allArtifacts }), to, objects: [...from.migrationObjects ?? [], ...to.migrationObjects ?? []] });
7072
7114
  const steps = diffSchemas({ from: strippedFrom, to, dialect, ...params.renames === undefined ? {} : { renames: params.renames } });
@@ -7077,6 +7119,7 @@ function generateMigration(params) {
7077
7119
  artifacts: missing.filter((artifact) => artifact.owns.kind === "postgresExtension")
7078
7120
  }),
7079
7121
  ...coreSql,
7122
+ ...artifactDropSql({ artifacts: rebuilt }),
7080
7123
  ...artifactCreateSql({
7081
7124
  artifacts: missing.filter((artifact) => artifact.owns.kind !== "postgresExtension")
7082
7125
  }),
@@ -8434,14 +8477,47 @@ async function compareReplayMigrationObjects(params) {
8434
8477
  return { ...params.schema, migrationObjects: objects.map((object) => ({ ...object, expected: definitions.get(sqlObjectKey11({ identity: object.identity })) })) };
8435
8478
  }
8436
8479
  // packages/migrate/src/replay-plan.ts
8437
- import { VibeError as VibeError39, sqlObjectKey as sqlObjectKey13 } from "@vibeorm/schema";
8480
+ import { VibeError as VibeError40, sqlObjectKey as sqlObjectKey13 } from "@vibeorm/schema";
8438
8481
 
8439
8482
  // packages/migrate/src/planner.ts
8440
- import { VibeError as VibeError38, sqlObjectKey as sqlObjectKey12 } from "@vibeorm/schema";
8483
+ import { VibeError as VibeError39, sqlObjectKey as sqlObjectKey12 } from "@vibeorm/schema";
8441
8484
  import { renderSqliteRebuildObjects, sqliteDialect as sqliteDialect4 } from "@vibeorm/sql";
8442
8485
 
8443
- // packages/migrate/src/index-predicates.ts
8486
+ // packages/migrate/src/artifact-probe.ts
8444
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";
8445
8521
  import { defaultIndexName as defaultIndexName2 } from "@vibeorm/schema";
8446
8522
  function physicalIndexName(params) {
8447
8523
  return params.index.name ?? defaultIndexName2({ table: params.table, columns: params.columns, unique: params.index.kind === "unique", dialect: "postgres" });
@@ -8482,7 +8558,7 @@ async function deparseIndexPredicate(params) {
8482
8558
  const match = /^CHECK \((.*)\)$/s.exec(definition);
8483
8559
  return match === null ? undefined : match[1];
8484
8560
  } catch (error) {
8485
- if (error instanceof VibeError37 && error.code === "VIBE_MIGRATION")
8561
+ if (error instanceof VibeError38 && error.code === "VIBE_MIGRATION")
8486
8562
  throw error;
8487
8563
  return;
8488
8564
  }
@@ -8501,7 +8577,7 @@ async function planSchemaMigration(params) {
8501
8577
  assertRetainedMigrationObjects({ from: params.previous?.schema.migrationObjects ?? [], to: objects });
8502
8578
  for (const object of objects)
8503
8579
  if (object.dialect !== dialect)
8504
- throw new VibeError38({ 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 } });
8505
8581
  const physical = params.physical ?? (dialect === "postgres" ? await introspectPhysicalPostgres({ executor }) : dialect === "mysql" ? await introspectMysql({ executor }) : await introspectSqlite({ executor }));
8506
8582
  if (params.previous !== undefined)
8507
8583
  assertMigrationState({ report: await verifyMigrationState({ executor, expected: params.previous, dialect, ...params.probe === undefined ? {} : { probe: params.probe } }) });
@@ -8510,7 +8586,7 @@ async function planSchemaMigration(params) {
8510
8586
  const identity = object.identity;
8511
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))
8512
8588
  continue;
8513
- throw new VibeError38({ 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 } });
8514
8590
  }
8515
8591
  const states = resolved.unavailable.map((identity) => {
8516
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)));
@@ -8541,7 +8617,7 @@ async function planSchemaMigration(params) {
8541
8617
  }
8542
8618
  for (const object of legacyObjects) {
8543
8619
  if (objects.some((entry) => sqlObjectKey12({ identity: entry.identity }) === sqlObjectKey12({ identity: object.identity })))
8544
- throw new VibeError38({ 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 } });
8545
8621
  const expected = object.expected ?? params.previous?.definitions.find((entry) => sqlObjectKey12({ identity: entry.identity }) === sqlObjectKey12({ identity: object.identity }));
8546
8622
  if (expected === undefined)
8547
8623
  states.push({ identity: object.identity, ownership: "migration", state: "unavailable", reason: "legacy-definition-required", differences: [] });
@@ -8584,7 +8660,7 @@ async function planSchemaMigration(params) {
8584
8660
  if (object.inspectionUnavailable !== undefined)
8585
8661
  states.push({ identity: object.identity, ownership, state: "unavailable", reason: object.inspectionUnavailable, differences: [] });
8586
8662
  if (object.inspectionUnavailable !== undefined && invalid.rebuilt.has("table" in object.identity ? object.identity.table.name : object.identity.name.name))
8587
- throw new VibeError38({ 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 } });
8588
8664
  if (ownership === "unknown")
8589
8665
  states.push({ identity: object.identity, ownership, state: "unavailable", reason: "unmanaged", differences: [] });
8590
8666
  let collateral = "table" in object.identity && object.identity.table.namespace === namespace && droppedTables.has(object.identity.table.name);
@@ -8603,7 +8679,7 @@ async function planSchemaMigration(params) {
8603
8679
  for (const address of addresses) {
8604
8680
  const value = JSON.parse(String(address));
8605
8681
  if (!Array.isArray(value) || !Array.isArray(value[2]))
8606
- throw new VibeError38({ code: "VIBE_MIGRATION", message: "Malformed catalog dependency address" });
8682
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Malformed catalog dependency address" });
8607
8683
  const names = value[2];
8608
8684
  if (names[0] !== namespace || typeof names[1] !== "string")
8609
8685
  continue;
@@ -8613,10 +8689,10 @@ async function planSchemaMigration(params) {
8613
8689
  }
8614
8690
  }
8615
8691
  if (dialect === "sqlite" && ownership === "unknown" && object.identity.kind === "generatedColumn" && invalid.rebuilt.has(object.identity.table.name))
8616
- throw new VibeError38({ 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 } });
8617
8693
  const removed = collateral || removals.some((identity) => sqlObjectKey12({ identity }) === key);
8618
8694
  if (removed && ownership === "migration")
8619
- throw new VibeError38({ 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 } });
8620
8696
  if (removed && ownership === "unknown" && object.backingConstraint === undefined)
8621
8697
  unmanagedRemovals.push(object.identity);
8622
8698
  }
@@ -8627,6 +8703,19 @@ async function planSchemaMigration(params) {
8627
8703
  if (artifact.owns.kind === "trigger" && invalidated.has(artifact.owns.table))
8628
8704
  triggers?.delete(artifact.owns.name);
8629
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
+ });
8630
8719
  const restore = new Map;
8631
8720
  const preservedColumns = new Map;
8632
8721
  const preservedDefaults = new Map;
@@ -8650,11 +8739,11 @@ async function planSchemaMigration(params) {
8650
8739
  continue;
8651
8740
  const live = await inspectSqlObject({ executor, dialect, identity });
8652
8741
  if (live.state !== "present" || identity.kind !== "columnDefault" && typeof live.definition.facts.columnDefinition !== "string")
8653
- throw new VibeError38({ 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 } });
8654
8743
  if (identity.kind === "columnDefault") {
8655
8744
  const definition = live.definition.facts.definition;
8656
8745
  if (definition !== null && typeof definition !== "string")
8657
- throw new VibeError38({ code: "VIBE_MIGRATION", message: "Cannot preserve SQLite default", meta: { identity } });
8746
+ throw new VibeError39({ code: "VIBE_MIGRATION", message: "Cannot preserve SQLite default", meta: { identity } });
8658
8747
  const defaults = preservedDefaults.get(identity.table.name) ?? new Map;
8659
8748
  defaults.set(identity.column, definition);
8660
8749
  preservedDefaults.set(identity.table.name, defaults);
@@ -8676,10 +8765,12 @@ async function planSchemaMigration(params) {
8676
8765
  return { ...rest, ...typeof expression === "string" ? { default: { kind: "dbgenerated", sql: expression } } : {} };
8677
8766
  }) })) };
8678
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));
8679
8769
  const sql = [
8680
8770
  ...artifactCreateSql({ artifacts: missing.filter((artifact) => artifact.owns.kind === "postgresExtension") }),
8681
8771
  ...core,
8682
- ...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))) }),
8683
8774
  ...creates
8684
8775
  ];
8685
8776
  if (sql.length === 0) {
@@ -8691,7 +8782,7 @@ async function planSchemaMigration(params) {
8691
8782
  states.push(...report.objects);
8692
8783
  }
8693
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));
8694
- 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 };
8695
8786
  }
8696
8787
 
8697
8788
  // packages/migrate/src/replay-plan.ts
@@ -8718,7 +8809,8 @@ async function planReplayMigration(params) {
8718
8809
  const probe = reference.dialect === "postgres" ? "rollback" : reference.dialect === "mysql" ? "temporary" : "none";
8719
8810
  if (probe === "rollback")
8720
8811
  await executor({ text: "BEGIN" });
8721
- 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 () => {
8722
8814
  if (probe === "rollback")
8723
8815
  await executor({ text: "ROLLBACK" });
8724
8816
  });
@@ -8737,24 +8829,24 @@ async function planReplayMigration(params) {
8737
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);
8738
8830
  const removedRegistrations = [...historicalObjects].filter(([key]) => present.has(key) && !declared.has(key)).map(([, identity]) => identity);
8739
8831
  if (removedRegistrations.length > 0)
8740
- throw new VibeError39({ 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 } });
8741
8833
  return { ...plan, requiredRemovals: [...removals.values()], retainedObjects, securityChanges: securityChangesOf({ steps: plan.steps }), replayRemovals: params.migrations.flatMap((migration) => migration.desiredState?.unmanagedRemovals ?? []) };
8742
8834
  }
8743
8835
  function assertReplayRemovals(params) {
8744
8836
  const wanted = new Set([...params.plan.requiredRemovals, ...params.plan.replayRemovals].map((identity) => sqlObjectKey13({ identity })));
8745
8837
  const keys = params.approved.map((identity) => sqlObjectKey13({ identity }));
8746
8838
  if (new Set(keys).size !== keys.length)
8747
- throw new VibeError39({ 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 } });
8748
8840
  const unused = params.approved.filter((identity) => !wanted.has(sqlObjectKey13({ identity })));
8749
8841
  if (unused.length > 0)
8750
- throw new VibeError39({ 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 } });
8751
8843
  assertNamedRemovals({ removals: params.plan.requiredRemovals, approved: params.approved, acceptIntegrityLoss: params.acceptIntegrityLoss });
8752
8844
  }
8753
8845
  // packages/migrate/src/baseline.ts
8754
- import { VibeError as VibeError44, sqlObjectKey as sqlObjectKey16 } from "@vibeorm/schema";
8846
+ import { VibeError as VibeError45, sqlObjectKey as sqlObjectKey16 } from "@vibeorm/schema";
8755
8847
 
8756
8848
  // packages/migrate/src/reference-state.ts
8757
- import { VibeError as VibeError40, sqlObjectKey as sqlObjectKey14 } from "@vibeorm/schema";
8849
+ import { VibeError as VibeError41, sqlObjectKey as sqlObjectKey14 } from "@vibeorm/schema";
8758
8850
  async function captureMigrationReference(params) {
8759
8851
  const namespace = await migrationNamespace({ executor: params.referenceExecutor, dialect: params.dialect });
8760
8852
  const identities = [...schemaObjectIdentities({ schema: params.schema, dialect: params.dialect, namespace }), ...(params.schema.migrationObjects ?? []).map((object) => object.identity)];
@@ -8764,14 +8856,14 @@ async function captureMigrationReference(params) {
8764
8856
  continue;
8765
8857
  const result = await inspectSqlObject({ executor: params.referenceExecutor, dialect: params.dialect, identity });
8766
8858
  if (result.state !== "present")
8767
- throw new VibeError40({ 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 } });
8768
8860
  definitions.push(result.definition);
8769
8861
  }
8770
8862
  let schema = params.schema;
8771
8863
  if (params.dialect === "postgres" && schema.models.some((model) => model.fields.some((field) => field.isUnsupported === true))) {
8772
8864
  const resolved = await resolvePostgresTypeIdentities({ executor: params.referenceExecutor, schema, mode: "reference" });
8773
8865
  if (resolved.unavailable.length > 0)
8774
- throw new VibeError40({ 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 } });
8775
8867
  const physical = await introspectPhysicalPostgres({ executor: params.referenceExecutor });
8776
8868
  for (const model of resolved.schema.models)
8777
8869
  for (const field of model.fields) {
@@ -8779,7 +8871,7 @@ async function captureMigrationReference(params) {
8779
8871
  continue;
8780
8872
  const actual = physical.models.find((entry) => entry.name === (model.dbName ?? model.name))?.fields.find((entry) => entry.name === (field.dbName ?? field.name));
8781
8873
  if (actual === undefined || columnTypeKey({ field }) !== columnTypeKey({ field: actual }))
8782
- throw new VibeError40({ 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 } });
8783
8875
  }
8784
8876
  schema = resolved.schema;
8785
8877
  }
@@ -8787,13 +8879,13 @@ async function captureMigrationReference(params) {
8787
8879
  }
8788
8880
 
8789
8881
  // packages/migrate/src/compile-desired-state.ts
8790
- import { VibeError as VibeError41 } from "@vibeorm/schema";
8882
+ import { VibeError as VibeError42 } from "@vibeorm/schema";
8791
8883
  import { renderExclusionSetup as renderExclusionSetup2, getSqlDialect as getSqlDialect12, renderMigrationServerVersion as renderMigrationServerVersion2 } from "@vibeorm/sql";
8792
8884
  async function compileDesiredState(params) {
8793
8885
  if (params.dialect !== "postgres")
8794
- throw new VibeError41({ 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 } });
8795
8887
  if (params.steps.some((step) => step.kind === "alterColumn" || step.kind === "addColumn" || step.kind === "addEnumValue"))
8796
- throw new VibeError41({ 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" } });
8797
8889
  const definitions = (params.schema.migrationObjects ?? []).flatMap((object) => object.expected === undefined ? [] : [object.expected]);
8798
8890
  await params.executor({ text: "SAVEPOINT vibeorm_desired_state" });
8799
8891
  try {
@@ -8816,7 +8908,7 @@ async function compileDesiredState(params) {
8816
8908
  const query = renderMigrationServerVersion2({ dialect: getSqlDialect12({ dialect: params.dialect }) });
8817
8909
  const version = (await params.executor({ text: query.text, values: [] }))[0]?.version;
8818
8910
  if (typeof version !== "string")
8819
- throw new VibeError41({ code: "VIBE_MIGRATION", message: "Cannot determine definition normalization version" });
8911
+ throw new VibeError42({ code: "VIBE_MIGRATION", message: "Cannot determine definition normalization version" });
8820
8912
  return { ...createDesiredState({ schema: { ...params.schema, models }, dialect: params.dialect, definitions }), normalization: { format: "catalog-v1", dialect: params.dialect, serverVersion: version } };
8821
8913
  } finally {
8822
8914
  await params.executor({ text: "ROLLBACK TO SAVEPOINT vibeorm_desired_state" });
@@ -8825,7 +8917,7 @@ async function compileDesiredState(params) {
8825
8917
  }
8826
8918
 
8827
8919
  // packages/migrate/src/verify-history.ts
8828
- import { VibeError as VibeError43, sqlObjectKey as sqlObjectKey15 } from "@vibeorm/schema";
8920
+ import { VibeError as VibeError44, sqlObjectKey as sqlObjectKey15 } from "@vibeorm/schema";
8829
8921
  import { getSqlDialect as getSqlDialect13, renderReplayCoverageGaps as renderReplayCoverageGaps2 } from "@vibeorm/sql";
8830
8922
 
8831
8923
  // packages/migrate/src/compare-sqlite-primary-key.ts
@@ -8898,7 +8990,7 @@ function compareSqlitePrimaryKeyRepresentations(params) {
8898
8990
  }
8899
8991
 
8900
8992
  // packages/migrate/src/compare-reference-rls.ts
8901
- import { VibeError as VibeError42 } from "@vibeorm/schema";
8993
+ import { VibeError as VibeError43 } from "@vibeorm/schema";
8902
8994
  function securityFacts(params) {
8903
8995
  return new Map(params.tables.filter((table) => table.enabled || table.force || table.policies.length > 0).map((table) => [table.table, {
8904
8996
  table: table.table,
@@ -8909,7 +9001,7 @@ function securityFacts(params) {
8909
9001
  }
8910
9002
  async function comparePostgresReferenceRls(params) {
8911
9003
  if (params.schema.rls !== undefined && params.referenceExecutor === undefined)
8912
- throw new VibeError42({ 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" } });
8913
9005
  const expected = securityFacts({ tables: params.schema.rls === undefined ? [] : await readPostgresRls({ executor: params.referenceExecutor }) });
8914
9006
  const actual = securityFacts({ tables: await readPostgresRls({ executor: params.executor }) });
8915
9007
  const objects = [...new Set([...expected.keys(), ...actual.keys()])].sort().map((table) => {
@@ -8933,14 +9025,14 @@ function selectMigrationVerificationPrefix(params) {
8933
9025
  for (const [index, file] of params.migrations.entries()) {
8934
9026
  const previous = params.migrations[index - 1];
8935
9027
  if (seen.has(file.name) || previous !== undefined && previous.name.localeCompare(file.name) > 0) {
8936
- throw new VibeError43({ 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 } });
8937
9029
  }
8938
9030
  seen.add(file.name);
8939
9031
  }
8940
9032
  for (const [index, row] of params.recorded.entries()) {
8941
9033
  const file = params.migrations[index];
8942
9034
  if (row.state !== "applied" || row.statementIndex < 0 || row.checksum === "" || file?.name !== row.name || file.desiredStatePending === true || migrationChecksum(file) !== row.checksum) {
8943
- throw new VibeError43({ 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 } });
8944
9036
  }
8945
9037
  }
8946
9038
  return params.migrations.slice(0, params.recorded.length);
@@ -8957,7 +9049,7 @@ async function verifyMigrationReference(params) {
8957
9049
  const coverage = renderReplayCoverageGaps2({ dialect: getSqlDialect13({ dialect }), namespace });
8958
9050
  const gaps = await executor({ text: coverage.text, values: [...coverage.values] });
8959
9051
  if (gaps.length > 0)
8960
- throw new VibeError43({ 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 } });
8961
9053
  const security = dialect === "postgres" ? await comparePostgresReferenceRls({ executor, referenceExecutor: params.referenceExecutor, schema: reference.state.schema }) : { inSync: true, objects: [] };
8962
9054
  const inspected = await verifyMigrationState({ executor, dialect, expected: reference.state, probe: "none", batch: true });
8963
9055
  const structural = dialect === "sqlite" ? compareSqlitePrimaryKeyRepresentations({ report: inspected }) : inspected;
@@ -9104,7 +9196,7 @@ async function mysqlComparisonFacts(params) {
9104
9196
  return { ...facts, members };
9105
9197
  }
9106
9198
  function referenceContextError() {
9107
- return new VibeError43({ 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" } });
9108
9200
  }
9109
9201
 
9110
9202
  // packages/migrate/src/baseline.ts
@@ -9112,19 +9204,19 @@ function generateBaselineMigration(params) {
9112
9204
  const objects = orderedMigrationObjects({ objects: params.schema.migrationObjects ?? [] });
9113
9205
  for (const object of objects)
9114
9206
  if (object.dialect !== params.dialect)
9115
- throw new VibeError44({ 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 } });
9116
9208
  const prerequisites = objects.filter((object) => object.identity.kind === "postgresExtension" || object.identity.kind === "enum" || object.identity.kind === "sequence");
9117
9209
  const prerequisiteKeys = new Set(prerequisites.map((object) => sqlObjectKey16({ identity: object.identity })));
9118
9210
  for (const object of prerequisites) {
9119
9211
  const unresolved = object.dependsOn.filter((identity) => !prerequisiteKeys.has(sqlObjectKey16({ identity })));
9120
9212
  if (unresolved.length > 0)
9121
- throw new VibeError44({ 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 } });
9122
9214
  }
9123
9215
  const schema = { ...params.schema, migrationObjects: objects.filter((object) => !prerequisiteKeys.has(sqlObjectKey16({ identity: object.identity }))) };
9124
9216
  const generated = generateMigration({ from: { datasource: schema.datasource, models: [], enums: [], extensions: [] }, to: schema, name: params.name, dialect: params.dialect, extensions: params.extensions ?? [] });
9125
9217
  const sql = splitSqlStatements({ sql: joinSqlStatements({ sql: [...prerequisites.flatMap((object) => object.create), ...generated.sql] }), dialect: params.dialect });
9126
9218
  if (sql.length === 0)
9127
- throw new VibeError44({ 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" } });
9128
9220
  return {
9129
9221
  name: generated.name,
9130
9222
  sql,
@@ -9153,17 +9245,17 @@ async function verifyBaselineDeclarations(params) {
9153
9245
  async function verifyBaselineTarget(params) {
9154
9246
  const { reference } = params;
9155
9247
  if (reference.unavailable.length > 0 || reference.inventory.some((object) => object.inspectionUnavailable !== undefined))
9156
- throw new VibeError44({ 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) } });
9157
9249
  const comparison = await verifyMigrationReference({ executor: params.executor, dialect: reference.dialect, reference, referenceExecutor: params.referenceExecutor }).catch((cause) => {
9158
- if (cause instanceof VibeError44 && cause.meta.reason === "verification-rls-reference-required")
9159
- throw new VibeError44({ 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 });
9160
9252
  throw cause;
9161
9253
  });
9162
9254
  const security = comparison.objects.filter((object) => object.reason === "native-rls-mismatch");
9163
9255
  if (security.length > 0)
9164
- throw new VibeError44({ 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])) } });
9165
9257
  if (comparison.unavailable.length > 0)
9166
- throw new VibeError44({ 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 } });
9167
9259
  const report = { inSync: comparison.objects.every((object) => object.state === "matching"), objects: comparison.objects };
9168
9260
  assertMigrationState({ report });
9169
9261
  const unmanaged = comparison.unmanaged.map((object) => object.identity);
@@ -9171,14 +9263,14 @@ async function verifyBaselineTarget(params) {
9171
9263
  const exclusions = params.excludeUnmanaged ?? [];
9172
9264
  const excluded = new Set(exclusions.map((identity) => sqlObjectKey16({ identity })));
9173
9265
  if (excluded.size !== exclusions.length || exclusions.some((identity) => !extras.has(sqlObjectKey16({ identity }))))
9174
- throw new VibeError44({ 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 } });
9175
9267
  const unreviewed = unmanaged.filter((identity) => !excluded.has(sqlObjectKey16({ identity })));
9176
9268
  if (unreviewed.length > 0)
9177
- throw new VibeError44({ 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 } });
9178
9270
  return { ...report, unmanaged };
9179
9271
  }
9180
9272
  // packages/migrate/src/baseline-record.ts
9181
- import { VibeError as VibeError45 } from "@vibeorm/schema";
9273
+ import { VibeError as VibeError46 } from "@vibeorm/schema";
9182
9274
  import { getSqlDialect as getSqlDialect15, renderStatement } from "@vibeorm/sql";
9183
9275
 
9184
9276
  // packages/migrate/src/history.ts
@@ -9194,20 +9286,20 @@ async function readMigrationHistory(params) {
9194
9286
 
9195
9287
  // packages/migrate/src/baseline-record.ts
9196
9288
  function transactionFailure(params) {
9197
- if (params.cause instanceof VibeError45)
9289
+ if (params.cause instanceof VibeError46)
9198
9290
  return params.cause;
9199
- return new VibeError45({ 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 });
9200
9292
  }
9201
9293
  async function recordBaselineMigration(params) {
9202
9294
  if (params.migration.moduleOrigin !== undefined)
9203
- throw new VibeError45({ 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" } });
9204
9296
  validateMigrationReplay({ dialect: params.dialect, migrations: [params.migration], acceptSecurityChanges: params.acceptSecurityChanges });
9205
9297
  await withMigrationLock({ executor: params.executor, dialect: params.dialect, run: async (executor) => {
9206
9298
  const record = async () => {
9207
9299
  const assertEmpty = async () => {
9208
9300
  const history = await readMigrationHistory({ executor, migrations: [params.migration], dialect: params.dialect });
9209
9301
  if (history.recorded.length > 0)
9210
- throw new VibeError45({ 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 })) } });
9211
9303
  };
9212
9304
  await assertEmpty();
9213
9305
  await params.verify({ executor });
@@ -9232,14 +9324,14 @@ async function recordBaselineMigration(params) {
9232
9324
  await executor({ text: "COMMIT" });
9233
9325
  }).then(undefined, async (cause) => {
9234
9326
  await executor({ text: "ROLLBACK" }).then(undefined, (rollback) => {
9235
- throw new VibeError45({ 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") });
9236
9328
  });
9237
9329
  throw transactionFailure({ cause });
9238
9330
  });
9239
9331
  } });
9240
9332
  }
9241
9333
  // packages/migrate/src/down.ts
9242
- import { VibeError as VibeError46, sqlObjectKey as sqlObjectKey17 } from "@vibeorm/schema";
9334
+ import { VibeError as VibeError47, sqlObjectKey as sqlObjectKey17 } from "@vibeorm/schema";
9243
9335
  function buildRollbackTarget(params) {
9244
9336
  const { from, to, dialect } = params;
9245
9337
  const skipped = [];
@@ -9292,6 +9384,7 @@ function generateDownMigration(params) {
9292
9384
  extensions: params.extensions ?? []
9293
9385
  });
9294
9386
  const allArtifacts = [...artifacts.setup, ...artifacts.objects];
9387
+ const previous = collectExtensionArtifacts({ schema: params.previousDeclarations ?? from, dialect, extensions: params.extensions ?? [] });
9295
9388
  const owned = [...from.migrationObjects ?? [], ...to.migrationObjects ?? []];
9296
9389
  const strippedFrom = preserveMigrationObjects({ from: stripExtensionArtifacts({ schema: from, artifacts: allArtifacts }), to: from, objects: owned });
9297
9390
  const { target, skipped } = buildRollbackTarget({ from: strippedFrom, to, dialect });
@@ -9315,14 +9408,27 @@ function generateDownMigration(params) {
9315
9408
  return added?.kind === "addColumn" ? { ...field, isOptional: added.column.isOptional } : field;
9316
9409
  }) })) };
9317
9410
  const coreSql = renderSteps({ steps, dialect, from: to, to: dialect === "sqlite" ? sqlitePreservedSchema({ from, to: restored, objects: from.migrationObjects ?? [] }) : restored });
9318
- const created = planMissingArtifacts({ introspected: from, artifacts: allArtifacts });
9319
- 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 = [];
9320
9414
  for (const artifact of [...created].reverse()) {
9321
9415
  if (artifact.owns.kind === "postgresExtension") {
9322
9416
  skipped.push(`extension "${artifact.owns.name}" stays installed \u2014 other objects may depend on it (drop it manually if intended)`);
9323
9417
  continue;
9324
9418
  }
9325
- 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);
9326
9432
  }
9327
9433
  const previousKeys = new Set((from.migrationObjects ?? []).map((object) => sqlObjectKey17({ identity: object.identity })));
9328
9434
  const ownedDropSql = [];
@@ -9334,24 +9440,26 @@ function generateDownMigration(params) {
9334
9440
  continue;
9335
9441
  }
9336
9442
  if (object.drop.length === 0)
9337
- throw new VibeError46({ 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 } });
9338
9444
  ownedDropSql.push(...object.drop);
9339
9445
  }
9340
9446
  return {
9341
9447
  name,
9342
9448
  target: restored,
9343
- sql: [...ownedDropSql, ...artifactDropSql, ...coreSql],
9449
+ sql: [...ownedDropSql, ...createdDropSql, ...artifactDropSql({ artifacts: rebuilt.map((entry) => entry.artifact) }), ...coreSql, ...restoreSql],
9344
9450
  destructive: steps.some((step) => step.destructive),
9345
9451
  ...securityChangesOf({ steps }).length === 0 ? {} : { securityChanges: securityChangesOf({ steps }) },
9346
9452
  skipped
9347
9453
  };
9348
9454
  }
9349
9455
  // packages/migrate/src/push.ts
9350
- import { VibeError as VibeError47, 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";
9351
9457
  import { DIALECT_CAPABILITIES as DIALECT_CAPABILITIES4 } from "@vibeorm/sql";
9352
9458
  async function push(params) {
9353
9459
  assertValidSchemaIR4({ schema: params.schema });
9354
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" });
9355
9463
  if (dialect !== "postgres")
9356
9464
  return pushChanges({ ...params, dialect });
9357
9465
  await params.executor({ text: "BEGIN" });
@@ -9379,6 +9487,7 @@ async function pushChanges(params) {
9379
9487
  ...params.previousState === undefined ? {} : { previous: params.previousState },
9380
9488
  ...params.extensions === undefined ? {} : { extensions: params.extensions },
9381
9489
  ...params.probe === undefined ? {} : { probe: params.probe },
9490
+ ...params.rebuildArtifacts === undefined ? {} : { rebuildArtifacts: params.rebuildArtifacts },
9382
9491
  ...params.replaceChecks === undefined ? {} : { replaceChecks: params.replaceChecks }
9383
9492
  });
9384
9493
  const { steps, sql } = plan;
@@ -9386,11 +9495,11 @@ async function pushChanges(params) {
9386
9495
  if (params.dryRun === true)
9387
9496
  return { steps, applied: [], planned: sql, securityChanges, objects: plan.objects, blocked: plan.blocked, unmanagedRemovals: plan.unmanagedRemovals };
9388
9497
  if (plan.blocked)
9389
- throw new VibeError47({ 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 } });
9390
9499
  assertSecurityAcknowledgement({ securityChanges, ...params.acceptSecurityChanges === undefined ? {} : { acceptSecurityChanges: params.acceptSecurityChanges } });
9391
9500
  const destructive = steps.filter((step) => step.destructive);
9392
9501
  if (destructive.length > 0 && params.acceptDataLoss !== true)
9393
- throw new VibeError47({ 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 })) } });
9394
9503
  assertRemovalAuthorization({
9395
9504
  steps,
9396
9505
  dialect,
@@ -9402,7 +9511,7 @@ async function pushChanges(params) {
9402
9511
  const approved = new Set((params.removeUnmanaged ?? []).map((identity) => sqlObjectKey18({ identity })));
9403
9512
  const unapproved = plan.unmanagedRemovals.filter((identity) => !approved.has(sqlObjectKey18({ identity })));
9404
9513
  if (unapproved.length > 0)
9405
- throw new VibeError47({ 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 } });
9406
9515
  const wrap = dialect !== "postgres" && DIALECT_CAPABILITIES4[dialect].transactionalDdl && !usesSelfManagedTransactions({ sql });
9407
9516
  if (wrap)
9408
9517
  await executor({ text: "BEGIN" });
@@ -9420,7 +9529,7 @@ async function pushChanges(params) {
9420
9529
  } catch {}
9421
9530
  } else if (dialect === "sqlite")
9422
9531
  await cleanupSelfManagedFailure({ executor });
9423
- throw new VibeError47({ 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 });
9424
9533
  }
9425
9534
  return { steps, applied: sql, securityChanges, objects: plan.objects, desiredState: createDesiredState({ schema: plan.to, dialect }) };
9426
9535
  }
@@ -9435,23 +9544,23 @@ async function pull(params) {
9435
9544
  }
9436
9545
  }
9437
9546
  // packages/migrate/src/module-export.ts
9438
- import { VibeError as VibeError49 } from "@vibeorm/schema";
9547
+ import { VibeError as VibeError50 } from "@vibeorm/schema";
9439
9548
 
9440
9549
  // packages/migrate/src/module-bundle.ts
9441
- import { VibeError as VibeError48 } from "@vibeorm/schema";
9550
+ import { VibeError as VibeError49 } from "@vibeorm/schema";
9442
9551
  function defineModuleMigrations(params) {
9443
9552
  if (!Array.isArray(params.steps) || params.steps.length === 0)
9444
- throw new VibeError48({ 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 } });
9445
9554
  const migrations = [];
9446
9555
  const revisions = new Set;
9447
9556
  let previous = null;
9448
9557
  for (const step of params.steps) {
9449
9558
  if (step.previousRevision !== previous || revisions.has(step.revision))
9450
- throw new VibeError48({ 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 } });
9451
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 });
9452
9561
  const predecessor = migrations.at(-1)?.moduleOrigin;
9453
9562
  if (predecessor !== undefined && canonicalMigrationJson({ value: predecessor.source.desiredState.to }) !== canonicalMigrationJson({ value: origin.source.desiredState.from }))
9454
- throw new VibeError48({ 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 } });
9455
9564
  validateMigrationReplay({ migrations: [origin.source], dialect: params.dialect, acceptSecurityChanges: true, acceptIntegrityLoss: true, removeUnmanaged: origin.source.desiredState?.unmanagedRemovals ?? [] });
9456
9565
  migrations.push(Object.freeze({ ...origin.source, moduleOrigin: origin }));
9457
9566
  revisions.add(step.revision);
@@ -9461,13 +9570,13 @@ function defineModuleMigrations(params) {
9461
9570
  }
9462
9571
  function moduleMigrationFiles(params) {
9463
9572
  if (params.bundle === null || typeof params.bundle !== "object" || !Array.isArray(params.bundle.migrations))
9464
- throw new VibeError48({ 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" } });
9465
9574
  if (!/^[A-Za-z0-9_-]+$/.test(params.prefix))
9466
- throw new VibeError48({ 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" } });
9467
9576
  const bundle = defineModuleMigrations({ moduleId: params.bundle.moduleId, dialect: params.bundle.dialect, steps: params.bundle.migrations.map((migration) => {
9468
9577
  const origin = migration?.moduleOrigin;
9469
9578
  if (origin === undefined || origin.moduleId !== params.bundle.moduleId || origin.dialect !== params.bundle.dialect)
9470
- throw new VibeError48({ 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" } });
9471
9580
  assertModuleOrigin({ value: origin });
9472
9581
  restoreModuleMigration({ migration, origin });
9473
9582
  return { revision: origin.revision, previousRevision: origin.previousRevision, contracts: origin.contracts, owned: origin.owned, migration: origin.source };
@@ -9480,7 +9589,7 @@ function emitModuleMigrationExport(params) {
9480
9589
  moduleMigrationFiles({ bundle: params.bundle, prefix: "export" });
9481
9590
  const origin = params.bundle.migrations.at(-1).moduleOrigin;
9482
9591
  if (!origin.contracts.includes(params.contract))
9483
- throw new VibeError49({ 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 } });
9484
9593
  const expectation = { moduleId: origin.moduleId, revision: origin.revision, artifactChecksum: origin.artifactChecksum, contract: params.contract };
9485
9594
  return [
9486
9595
  { name: "migrations.js", content: `// Generated immutable migration data; no driver, filesystem or runner import.
@@ -9497,9 +9606,9 @@ export const moduleReadiness = Object.freeze(${JSON.stringify(expectation)});
9497
9606
  ];
9498
9607
  }
9499
9608
  // packages/migrate/src/module-pending.ts
9500
- import { VibeError as VibeError50, sqlObjectKey as sqlObjectKey19 } from "@vibeorm/schema";
9609
+ import { VibeError as VibeError51, sqlObjectKey as sqlObjectKey19 } from "@vibeorm/schema";
9501
9610
  function refusal3(params) {
9502
- return new VibeError50({ 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 });
9503
9612
  }
9504
9613
  function compose(params) {
9505
9614
  const { current, from, to } = params;
@@ -9607,16 +9716,16 @@ function pendingModuleMigrations(params) {
9607
9716
  return Object.freeze(result);
9608
9717
  }
9609
9718
  // packages/migrate/src/module-readiness.ts
9610
- import { VibeError as VibeError51 } from "@vibeorm/schema";
9719
+ import { VibeError as VibeError52 } from "@vibeorm/schema";
9611
9720
  async function inspectModuleReadiness(params) {
9612
9721
  const ids = new Set;
9613
9722
  for (const expected of params.modules) {
9614
9723
  if (ids.has(expected.moduleId) || !expected.moduleId || !expected.revision || !expected.contract || !/^[a-f0-9]{64}$/.test(expected.artifactChecksum))
9615
- throw new VibeError51({ 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 } });
9616
9725
  ids.add(expected.moduleId);
9617
9726
  }
9618
9727
  if (params.compatibility !== undefined && params.compatibility !== "exact" && params.compatibility !== "contract")
9619
- throw new VibeError51({ 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" } });
9620
9729
  const records = await readModuleJournal(params);
9621
9730
  const heads = moduleHistoryHeads({ records });
9622
9731
  const unresolved = [...records.values()].some(({ row, entry }) => row.error !== undefined || row.statementIndex < 0 || entry !== undefined && (!entry.complete || row.statementIndex !== entry.migration.sql.length));
@@ -9650,7 +9759,7 @@ async function inspectModuleReadiness(params) {
9650
9759
  return { ready: !unresolved && modules.every((module) => (module.revision === "matching" || module.revision === "compatible") && module.structural.status !== "drifted"), modules };
9651
9760
  }
9652
9761
  // packages/migrate/src/adoption.ts
9653
- import { VibeError as VibeError52 } from "@vibeorm/schema";
9762
+ import { VibeError as VibeError53 } from "@vibeorm/schema";
9654
9763
  async function adoptMigration(params) {
9655
9764
  const report = await verifyMigrationState({ executor: params.executor, expected: params.reference, dialect: params.dialect });
9656
9765
  assertMigrationState({ report });
@@ -9666,11 +9775,11 @@ function deployedDesiredState(params) {
9666
9775
  for (const [index, row] of params.recorded.entries()) {
9667
9776
  const file = params.migrations[index];
9668
9777
  if (row.state !== "applied" || row.checksum === "" || file?.name !== row.name || migrationChecksum(file) !== row.checksum)
9669
- throw new VibeError52({ 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 } });
9670
9779
  }
9671
9780
  const applied = new Set(params.recorded.map((row) => row.name));
9672
9781
  if (params.migrations.some((migration) => applied.has(migration.name) && migration.desiredStatePending === true))
9673
- throw new VibeError52({ 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" } });
9674
9783
  const last = [...params.migrations].reverse().find((migration) => applied.has(migration.name));
9675
9784
  return last?.desiredState?.to;
9676
9785
  }
@@ -9684,6 +9793,7 @@ export {
9684
9793
  adoptMigration,
9685
9794
  applyMigrations,
9686
9795
  artifactCreateSql,
9796
+ artifactDropSql,
9687
9797
  assertMigrationState,
9688
9798
  assertProbeMode,
9689
9799
  assertRemovalAuthorization,
@@ -9720,6 +9830,7 @@ export {
9720
9830
  introspectPostgres,
9721
9831
  introspectSqlite,
9722
9832
  isDefaultExecution,
9833
+ lastDeclaredSchema,
9723
9834
  legacyMigrationObjects,
9724
9835
  migrationChecksum,
9725
9836
  migrationNamespace,
@@ -9731,11 +9842,13 @@ export {
9731
9842
  parseExecutionSidecar,
9732
9843
  parseModuleOrigin,
9733
9844
  pendingModuleMigrations,
9845
+ planChangedArtifacts,
9734
9846
  planMissingArtifacts,
9735
9847
  planRenames,
9736
9848
  planReplayMigration,
9737
9849
  planSchemaMigration,
9738
9850
  prepareCheckDiff,
9851
+ probeChangedArtifacts,
9739
9852
  probeInstalledExtensionState,
9740
9853
  pull,
9741
9854
  push,
@@ -9762,4 +9875,4 @@ export {
9762
9875
  withMigrationReference
9763
9876
  };
9764
9877
 
9765
- //# debugId=AA96882D3F595BC864756E2164756E21
9878
+ //# debugId=9F525A8FE96388CC64756E2164756E21