@vibeorm/migrate 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/adoption.d.ts.map +1 -1
  2. package/dist/baseline-record.d.ts +14 -0
  3. package/dist/baseline-record.d.ts.map +1 -0
  4. package/dist/baseline.d.ts +31 -0
  5. package/dist/baseline.d.ts.map +1 -0
  6. package/dist/compare-reference-rls.d.ts +10 -0
  7. package/dist/compare-reference-rls.d.ts.map +1 -0
  8. package/dist/compare-sqlite-primary-key.d.ts +6 -0
  9. package/dist/compare-sqlite-primary-key.d.ts.map +1 -0
  10. package/dist/desired-state.d.ts.map +1 -1
  11. package/dist/fs.js +636 -392
  12. package/dist/fs.js.map +14 -11
  13. package/dist/index.d.ts +12 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +6322 -5092
  16. package/dist/index.js.map +46 -33
  17. package/dist/inspect-objects.d.ts +8 -1
  18. package/dist/inspect-objects.d.ts.map +1 -1
  19. package/dist/introspect/postgres.d.ts.map +1 -1
  20. package/dist/module-history.d.ts +6 -0
  21. package/dist/module-history.d.ts.map +1 -1
  22. package/dist/module-ownership.d.ts +8 -0
  23. package/dist/module-ownership.d.ts.map +1 -1
  24. package/dist/module-pending.d.ts +2 -0
  25. package/dist/module-pending.d.ts.map +1 -1
  26. package/dist/mysql-catalog-visibility.d.ts +5 -0
  27. package/dist/mysql-catalog-visibility.d.ts.map +1 -0
  28. package/dist/planner.d.ts +5 -0
  29. package/dist/planner.d.ts.map +1 -1
  30. package/dist/postgres-type-identity.d.ts +15 -0
  31. package/dist/postgres-type-identity.d.ts.map +1 -0
  32. package/dist/postgres-types.d.ts +5 -0
  33. package/dist/postgres-types.d.ts.map +1 -1
  34. package/dist/reference-state.d.ts.map +1 -1
  35. package/dist/replay-objects.d.ts +10 -0
  36. package/dist/replay-objects.d.ts.map +1 -0
  37. package/dist/replay-plan.d.ts +28 -0
  38. package/dist/replay-plan.d.ts.map +1 -0
  39. package/dist/replay-reference.d.ts +18 -0
  40. package/dist/replay-reference.d.ts.map +1 -0
  41. package/dist/runner.d.ts +6 -0
  42. package/dist/runner.d.ts.map +1 -1
  43. package/dist/shadow-dedicated.d.ts +12 -0
  44. package/dist/shadow-dedicated.d.ts.map +1 -0
  45. package/dist/shadow-guard.d.ts +13 -0
  46. package/dist/shadow-guard.d.ts.map +1 -0
  47. package/dist/shadow-types.d.ts +52 -0
  48. package/dist/shadow-types.d.ts.map +1 -0
  49. package/dist/shadow.d.ts +17 -0
  50. package/dist/shadow.d.ts.map +1 -0
  51. package/dist/verify-history.d.ts +35 -0
  52. package/dist/verify-history.d.ts.map +1 -0
  53. package/package.json +3 -3
package/dist/fs.js CHANGED
@@ -1,6 +1,22 @@
1
1
  // @bun
2
+ // packages/migrate/src/mysql-catalog-visibility.ts
3
+ function hasMysqlGlobalCatalogVisibility(params) {
4
+ let visible = false;
5
+ for (const row of params.rows) {
6
+ const values = Object.values(row);
7
+ if (values.length !== 1 || typeof values[0] !== "string" || !values[0].startsWith("GRANT "))
8
+ return false;
9
+ const grant = /^GRANT ([A-Z_ ,]+) ON \*\.\* TO /.exec(values[0]);
10
+ const privileges = grant?.[1]?.split(", ") ?? [];
11
+ if (privileges.some((privilege) => privilege === "SHOW VIEW" || privilege === "SELECT" || privilege === "ALL PRIVILEGES"))
12
+ visible = true;
13
+ }
14
+ return visible;
15
+ }
16
+
2
17
  // packages/migrate/src/module-ownership.ts
3
- import { VibeError as VibeError16, sqlObjectKey as sqlObjectKey6 } from "@vibeorm/schema";
18
+ import { VibeError as VibeError17, sqlObjectKey as sqlObjectKey6 } from "@vibeorm/schema";
19
+ import { getSqlDialect as getSqlDialect3, renderModuleDependencyQuery } from "@vibeorm/sql";
4
20
 
5
21
  // packages/migrate/src/desired-state.ts
6
22
  import { VibeError, assertValidSchemaIR, isSqlObjectDefinition, isSqlObjectIdentity, providerToDialect, sqlObjectKey } from "@vibeorm/schema";
@@ -38,7 +54,7 @@ function keysOnly(value, allowed) {
38
54
  function modelShape(value) {
39
55
  if (!record(value) || typeof value.name !== "string" || !Array.isArray(value.fields) || !Array.isArray(value.relations) || !Array.isArray(value.indexes))
40
56
  return false;
41
- return value.fields.every((field) => record(field) && typeof field.name === "string" && (typeof field.type === "string" || record(field.type) && typeof field.type.enum === "string") && ["isId", "isUnique", "isOptional", "isList"].every((key) => typeof field[key] === "boolean")) && value.relations.every(record) && value.indexes.every((index) => record(index) && Array.isArray(index.fields) && index.fields.every(record)) && (value.checks === undefined || Array.isArray(value.checks) && value.checks.every((check) => record(check) && typeof check.name === "string" && typeof check.expression === "string"));
57
+ return value.fields.every((field) => record(field) && typeof field.name === "string" && (field.nativeTypeIdentity === undefined || record(field.nativeTypeIdentity) && keysOnly(field.nativeTypeIdentity, ["source", "namespace"]) && field.isUnsupported === true && typeof field.nativeTypeIdentity.source === "string" && field.nativeTypeIdentity.source === field.nativeType && typeof field.nativeTypeIdentity.namespace === "string" && field.nativeTypeIdentity.namespace.length > 0) && (typeof field.type === "string" || record(field.type) && typeof field.type.enum === "string") && ["isId", "isUnique", "isOptional", "isList"].every((key) => typeof field[key] === "boolean")) && value.relations.every(record) && value.indexes.every((index) => record(index) && Array.isArray(index.fields) && index.fields.every(record)) && (value.checks === undefined || Array.isArray(value.checks) && value.checks.every((check) => record(check) && typeof check.name === "string" && typeof check.expression === "string"));
42
58
  }
43
59
  function state(value) {
44
60
  if (!record(value) || !keysOnly(value, ["schema", "definitions", "normalization"]) || !record(value.schema) || !Array.isArray(value.definitions) || !value.definitions.every(isSqlObjectDefinition))
@@ -138,7 +154,7 @@ function detectImplicitM2MPairs(params) {
138
154
 
139
155
  // packages/migrate/src/postgres-types.ts
140
156
  import { VibeError as VibeError2, isEnumType, scalarListDefault, serializeJsonDefault } from "@vibeorm/schema";
141
- import { POSTGRES_CODECS, postgresDialect, toPgArrayLiteral } from "@vibeorm/sql";
157
+ import { POSTGRES_CODECS, postgresDialect, toPgArrayLiteral, parsePostgresTypeName, renderPostgresTypeName } from "@vibeorm/sql";
142
158
  var SCALAR_TO_PG = {
143
159
  String: "text",
144
160
  Boolean: "boolean",
@@ -182,11 +198,26 @@ function normalizeNativeType(params) {
182
198
  const base = NATIVE_ALIASES[match[1]] ?? match[1];
183
199
  return `${base}${match[2] ?? ""}${match[3] ?? ""}`;
184
200
  }
201
+ function parseUnsupportedPostgresType(params) {
202
+ const temporal = /^\s*(time(?:stamp)?)\s*(\(\s*\d+\s*\))?\s+(with|without)\s+time\s+zone\s*((?:\[\s*\]\s*)*)$/i.exec(params.raw);
203
+ if (temporal !== null)
204
+ return parsePostgresTypeName({ raw: `${temporal[1].toLowerCase()}${temporal[3].toLowerCase() === "with" ? "tz" : ""}${temporal[2] ?? ""}${temporal[4] ?? ""}` });
205
+ const parsed = parsePostgresTypeName(params);
206
+ if (parsed !== undefined || /["']/.test(params.raw))
207
+ return parsed;
208
+ const base = params.raw.toLowerCase().replace(/\s+/g, "").replace(/\(.*\)|\[\]/g, "");
209
+ return NATIVE_ALIASES[base] === undefined ? undefined : parsePostgresTypeName({ raw: normalizeNativeType(params) });
210
+ }
185
211
  function columnTypeKey(params) {
186
212
  const { field } = params;
187
213
  const listSuffix = field.isList ? "[]" : "";
188
214
  if (field.isUnsupported === true) {
189
- return `u:${normalizeNativeType({ raw: field.nativeType ?? "" })}`;
215
+ const parsed = parseUnsupportedPostgresType({ raw: field.nativeType ?? "" });
216
+ if (parsed === undefined)
217
+ return `u:${field.nativeType ?? ""}`;
218
+ const evidence = field.nativeTypeIdentity;
219
+ const namespace = evidence !== undefined && evidence.source === field.nativeType ? evidence.namespace : parsed.namespace;
220
+ return `u:${JSON.stringify([namespace ?? null, parsed.name, parsed.modifier, parsed.array || field.isList])}`;
190
221
  }
191
222
  if (isEnumType(field.type)) {
192
223
  return `e:${field.type.enum}${listSuffix}`;
@@ -218,6 +249,10 @@ function columnTypeSql(params) {
218
249
  meta: { field: field.name }
219
250
  });
220
251
  }
252
+ const parsed = parseUnsupportedPostgresType({ raw: field.nativeType });
253
+ const evidence = field.nativeTypeIdentity;
254
+ if (parsed !== undefined && evidence?.source === field.nativeType)
255
+ return renderPostgresTypeName({ dialect: postgresDialect, type: { ...parsed, namespace: evidence.namespace, array: parsed.array || field.isList } });
221
256
  return field.nativeType;
222
257
  }
223
258
  const listSuffix = field.isList ? "[]" : "";
@@ -1196,7 +1231,7 @@ function assertRetainedMigrationObjects(params) {
1196
1231
  const keys = new Set(params.to.map((object) => sqlObjectKey2({ identity: object.identity })));
1197
1232
  const removed = params.from.filter((object) => !keys.has(sqlObjectKey2({ identity: object.identity })));
1198
1233
  if (removed.length > 0)
1199
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Removing migration ownership requires a reviewed hand-authored migration and new desired state", meta: { reason: "migration-object-removal-review-required", objects: removed.map((object) => object.identity) } });
1234
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Removing migration ownership requires a reviewed hand-authored migration and new desired state", meta: { reason: "migration-object-removal-review-required", shadowReusable: true, objects: removed.map((object) => object.identity) } });
1200
1235
  }
1201
1236
  function orderedMigrationObjects(params) {
1202
1237
  const byKey = new Map(params.objects.map((object) => [sqlObjectKey2({ identity: object.identity }), object]));
@@ -1227,10 +1262,10 @@ function assertNamedRemovals(params) {
1227
1262
  const approved = new Set((params.approved ?? []).map((identity) => sqlObjectKey2({ identity })));
1228
1263
  const missing = params.removals.filter((identity) => !approved.has(sqlObjectKey2({ identity })));
1229
1264
  if (missing.length > 0)
1230
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unmanaged removals require individually named approvals", meta: { reason: "unmanaged-removal-required", objects: missing } });
1265
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unmanaged removals require individually named approvals", meta: { reason: "unmanaged-removal-required", shadowReusable: true, objects: missing } });
1231
1266
  const integrity = params.removals.filter((identity) => identity.kind === "constraint" || identity.kind === "index");
1232
1267
  if (integrity.length > 0 && params.acceptIntegrityLoss !== true)
1233
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Named constraint or index removals also require acceptIntegrityLoss", meta: { reason: "integrity-acknowledgement-required", objects: integrity } });
1268
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Named constraint or index removals also require acceptIntegrityLoss", meta: { reason: "integrity-acknowledgement-required", shadowReusable: true, objects: integrity } });
1234
1269
  }
1235
1270
  function assertRemovalAuthorization(params) {
1236
1271
  const declared = params.previous === undefined ? [] : schemaObjectIdentities({ schema: params.previous.schema, dialect: params.dialect, namespace: params.namespace });
@@ -1255,14 +1290,14 @@ function assertRemovalAuthorization(params) {
1255
1290
  }
1256
1291
  }
1257
1292
  if (unknown.length > 0)
1258
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unknown object removals require individually named removeUnmanaged decisions", meta: { reason: "unmanaged-removal-required", objects: unknown } });
1293
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Unknown object removals require individually named removeUnmanaged decisions", meta: { reason: "unmanaged-removal-required", shadowReusable: true, objects: unknown } });
1259
1294
  if (integrity.length > 0 && params.acceptIntegrityLoss !== true)
1260
- throw new VibeError6({ code: "VIBE_MIGRATION", message: "Constraint or index removal requires acceptIntegrityLoss; data-loss acknowledgement does not authorize it", meta: { reason: "integrity-acknowledgement-required", objects: integrity } });
1295
+ throw new VibeError6({ code: "VIBE_MIGRATION", message: "Constraint or index removal requires acceptIntegrityLoss; data-loss acknowledgement does not authorize it", meta: { reason: "integrity-acknowledgement-required", shadowReusable: true, objects: integrity } });
1261
1296
  }
1262
1297
 
1263
1298
  // packages/migrate/src/inventory.ts
1264
- import { VibeError as VibeError15, isSqlObjectIdentity as isSqlObjectIdentity2, sqlObjectKey as sqlObjectKey5 } from "@vibeorm/schema";
1265
- import { getSqlDialect as getSqlDialect2, renderMigrationInventory, renderSqliteColumnInventory, renderMysqlObjectMembers as renderMysqlObjectMembers2, sqliteTableConstraints as sqliteTableConstraints3, renderSqliteForeignKeyInventory } from "@vibeorm/sql";
1299
+ import { VibeError as VibeError16, isSqlObjectIdentity as isSqlObjectIdentity2, sqlObjectKey as sqlObjectKey5 } from "@vibeorm/schema";
1300
+ import { getSqlDialect as getSqlDialect2, renderMigrationInventory, renderSqliteColumnInventory as renderSqliteColumnInventory2, renderMysqlObjectMembers as renderMysqlObjectMembers2, sqliteTableConstraints as sqliteTableConstraints3, renderSqliteForeignKeyInventory } from "@vibeorm/sql";
1266
1301
 
1267
1302
  // packages/migrate/src/exclusions.ts
1268
1303
  import { randomUUID } from "crypto";
@@ -1342,16 +1377,16 @@ async function verifyExclusions(params) {
1342
1377
 
1343
1378
  // packages/migrate/src/inspect-objects.ts
1344
1379
  import { randomUUID as randomUUID2 } from "crypto";
1345
- import { VibeError as VibeError14, sqlObjectKey as sqlObjectKey4, DIALECT_CAPABILITIES as DIALECT_CAPABILITIES2 } from "@vibeorm/schema";
1346
- import { getSqlDialect, renderMigrationObjectQuery, renderCheckProbe, renderMigrationNamespace, renderMigrationDependencies, renderMysqlObjectMembers, renderMysqlCheckProbe, sqliteColumnClauses as sqliteColumnClauses2, renderMigrationVisibility, sqliteTableConstraints as sqliteTableConstraints2 } from "@vibeorm/sql";
1380
+ import { VibeError as VibeError15, sqlObjectKey as sqlObjectKey4, DIALECT_CAPABILITIES as DIALECT_CAPABILITIES2 } from "@vibeorm/schema";
1381
+ import { getSqlDialect, renderMigrationObjectBatch, renderMigrationObjectQuery, renderCheckProbe, renderMigrationNamespace, renderMigrationDependencies, renderMysqlObjectMembers, renderMysqlCheckProbe, sqliteColumnClauses as sqliteColumnClauses2, renderMigrationVisibility, sqliteTableConstraints as sqliteTableConstraints2, renderSqliteColumnInventory } from "@vibeorm/sql";
1347
1382
 
1348
1383
  // packages/migrate/src/introspect/postgres.ts
1349
1384
  import { renderExclusionCatalog as renderExclusionCatalog2 } from "@vibeorm/sql";
1350
1385
  import { parsePgArrayLiteral } from "@vibeorm/sql";
1351
1386
  import { scalarListDefault as scalarListDefault2 } from "@vibeorm/schema";
1352
1387
  import { exactIntegerLiteral } from "@vibeorm/schema";
1353
- import { postgresDialect as postgresDialect5, renderRlsReadinessQuery } from "@vibeorm/sql";
1354
- import { VibeError as VibeError11 } from "@vibeorm/schema";
1388
+ import { postgresDialect as postgresDialect6, renderRlsReadinessQuery } from "@vibeorm/sql";
1389
+ import { VibeError as VibeError12 } from "@vibeorm/schema";
1355
1390
 
1356
1391
  // packages/migrate/src/journal-table.ts
1357
1392
  var MIGRATIONS_TABLE_NAME = "_vibe_migrations";
@@ -1543,12 +1578,58 @@ function lowerFirst(value) {
1543
1578
  return value.charAt(0).toLowerCase() + value.slice(1);
1544
1579
  }
1545
1580
 
1581
+ // packages/migrate/src/postgres-type-identity.ts
1582
+ import { VibeError as VibeError9 } from "@vibeorm/schema";
1583
+ import { postgresDialect as postgresDialect3, renderPostgresTypeIdentity } from "@vibeorm/sql";
1584
+ async function resolvePostgresTypeIdentities(params) {
1585
+ const unavailable = [];
1586
+ const models = [];
1587
+ for (const model of params.schema.models) {
1588
+ const table = { namespace: "public", name: model.dbName ?? model.name };
1589
+ const previous = params.previous?.models.find((entry) => (entry.dbName ?? entry.name) === table.name);
1590
+ const fields = [];
1591
+ for (const field of model.fields) {
1592
+ if (field.isUnsupported !== true) {
1593
+ fields.push(field);
1594
+ continue;
1595
+ }
1596
+ const column = field.dbName ?? field.name;
1597
+ const parsed = parseUnsupportedPostgresType({ raw: field.nativeType ?? "" });
1598
+ const evidence = field.nativeTypeIdentity;
1599
+ if (evidence !== undefined && (evidence.source !== field.nativeType || parsed?.namespace !== undefined && parsed.namespace !== evidence.namespace)) {
1600
+ throw new VibeError9({ code: "VIBE_MIGRATION", message: "PostgreSQL type evidence no longer matches its declaration; recapture the independent reference", meta: { reason: "type-reference-invalid", shadowReusable: true, table: table.name, column } });
1601
+ }
1602
+ const prior = previous?.fields.find((entry) => (entry.dbName ?? entry.name) === column && entry.isUnsupported === true);
1603
+ const priorType = parseUnsupportedPostgresType({ raw: prior?.nativeType ?? "" });
1604
+ const priorNamespace = prior?.nativeTypeIdentity?.source === prior?.nativeType ? prior?.nativeTypeIdentity?.namespace : priorType?.namespace;
1605
+ let namespace = parsed?.namespace ?? evidence?.namespace ?? (priorType?.name === parsed?.name ? priorNamespace : undefined);
1606
+ if (params.mode === "catalog" || params.mode === "reference" || namespace === undefined) {
1607
+ const source = params.mode === "catalog" ? { table, column } : { type: { name: parsed?.name ?? "", ...namespace === undefined && params.mode === "reference" ? {} : { namespace: namespace ?? "pg_catalog" } } };
1608
+ const query = renderPostgresTypeIdentity({ dialect: postgresDialect3, source });
1609
+ const rows = parsed === undefined && params.mode !== "catalog" ? [] : await params.executor({ text: query.text, values: [...query.values] }).then((rows) => rows, (cause) => {
1610
+ throw new VibeError9({ code: "VIBE_MIGRATION", message: "PostgreSQL type identity inspection failed", meta: { reason: "type-inspection-unavailable", table: table.name, column }, cause });
1611
+ });
1612
+ const resolved = rows.length === 1 ? rows[0] : undefined;
1613
+ namespace = typeof resolved?.namespace === "string" && (resolved.name === parsed?.name || parsed === undefined && params.mode === "catalog") ? resolved.namespace : undefined;
1614
+ }
1615
+ if (parsed === undefined && params.mode !== "catalog" || namespace === undefined || field.nativeType === undefined) {
1616
+ unavailable.push({ kind: "column", table, column });
1617
+ fields.push(field);
1618
+ } else {
1619
+ fields.push({ ...field, nativeTypeIdentity: { source: field.nativeType, namespace } });
1620
+ }
1621
+ }
1622
+ models.push({ ...model, fields });
1623
+ }
1624
+ return { schema: { ...params.schema, models }, unavailable };
1625
+ }
1626
+
1546
1627
  // packages/migrate/src/introspect/postgres-rls.ts
1547
- import { VibeError as VibeError10, assertValidSchemaIR as assertValidSchemaIR3 } from "@vibeorm/schema";
1548
- import { NATIVE_RLS, postgresDialect as postgresDialect4, renderRlsPolicy as renderRlsPolicy2 } from "@vibeorm/sql";
1628
+ import { VibeError as VibeError11, assertValidSchemaIR as assertValidSchemaIR3 } from "@vibeorm/schema";
1629
+ import { NATIVE_RLS, postgresDialect as postgresDialect5, renderRlsPolicy as renderRlsPolicy2 } from "@vibeorm/sql";
1549
1630
 
1550
1631
  // packages/migrate/src/ddl/rls.ts
1551
- import { VibeError as VibeError9, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
1632
+ import { VibeError as VibeError10, assertValidSchemaIR as assertValidSchemaIR2, unsupportedCapability as unsupportedCapability5 } from "@vibeorm/schema";
1552
1633
  import * as sql from "@vibeorm/sql";
1553
1634
  function isRlsProtected(params) {
1554
1635
  return params.model.rls !== undefined && params.model.rls !== "unprotected";
@@ -1664,7 +1745,7 @@ function renderRlsStep(params) {
1664
1745
  return [renderer(common).text];
1665
1746
  }
1666
1747
  default:
1667
- throw new VibeError9({ code: "VIBE_MIGRATION", message: "Expected a native RLS migration step" });
1748
+ throw new VibeError10({ code: "VIBE_MIGRATION", message: "Expected a native RLS migration step" });
1668
1749
  }
1669
1750
  }
1670
1751
  function securityChangesOf(params) {
@@ -1673,7 +1754,7 @@ function securityChangesOf(params) {
1673
1754
  function assertSecurityAcknowledgement(params) {
1674
1755
  if (params.securityChanges.length === 0 || params.acceptSecurityChanges === true)
1675
1756
  return;
1676
- throw new VibeError9({
1757
+ throw new VibeError10({
1677
1758
  code: "VIBE_MIGRATION",
1678
1759
  message: `Security changes require acceptSecurityChanges: true; acceptDataLoss does not authorize them:
1679
1760
  ${params.securityChanges.join(`
@@ -1700,19 +1781,19 @@ async function readPostgresRls(params) {
1700
1781
  const tables = new Map;
1701
1782
  for (const row of rows) {
1702
1783
  const table = String(row.table_name);
1703
- let state2 = tables.get(table);
1704
- if (state2 === undefined) {
1705
- state2 = { table, enabled: row.enabled === true, force: row.force === true, policies: [] };
1706
- tables.set(table, state2);
1784
+ let state = tables.get(table);
1785
+ if (state === undefined) {
1786
+ state = { table, enabled: row.enabled === true, force: row.force === true, policies: [] };
1787
+ tables.set(table, state);
1707
1788
  }
1708
1789
  if (row.policy_name !== null && row.policy_name !== undefined) {
1709
- state2.policies.push({ name: String(row.policy_name), command: String(row.command), permissive: row.permissive === true, roles: String(row.roles), using: row.using_expression === null ? null : String(row.using_expression), withCheck: row.check_expression === null ? null : String(row.check_expression), comment: row.comment === null ? null : String(row.comment) });
1790
+ state.policies.push({ name: String(row.policy_name), command: String(row.command), permissive: row.permissive === true, roles: String(row.roles), using: row.using_expression === null ? null : String(row.using_expression), withCheck: row.check_expression === null ? null : String(row.check_expression), comment: row.comment === null ? null : String(row.comment) });
1710
1791
  }
1711
1792
  }
1712
1793
  return [...tables.values()];
1713
1794
  }
1714
1795
  function conflict(params) {
1715
- throw new VibeError10({
1796
+ throw new VibeError11({
1716
1797
  code: "VIBE_MIGRATION",
1717
1798
  message: `Native RLS on public.${params.table} cannot be managed safely (${params.attributes.join(", ")}). Review the live policies and restore the deployed declaration, or remove conflicting policies explicitly with administrator credentials. Supply rlsSchema/previousSchema for the deployed policy; no policy is deleted or adopted automatically.`,
1718
1799
  meta: params
@@ -1725,32 +1806,32 @@ async function verifyPostgresRls(params) {
1725
1806
  await executor({ text: "SET LOCAL search_path = ''" });
1726
1807
  const declared = new Map((schema?.models ?? []).map((model) => [model.dbName ?? model.name, model]));
1727
1808
  let tables = await readPostgresRls({ executor });
1728
- for (const state2 of tables) {
1729
- const model = declared.get(state2.table);
1730
- if (!state2.enabled && !state2.force && state2.policies.length === 0 && (model === undefined || !isRlsProtected({ model })))
1809
+ for (const state of tables) {
1810
+ const model = declared.get(state.table);
1811
+ if (!state.enabled && !state.force && state.policies.length === 0 && (model === undefined || !isRlsProtected({ model })))
1731
1812
  continue;
1732
- await executor({ text: `LOCK TABLE "public".${postgresDialect4.quoteIdent({ name: state2.table })} IN ACCESS EXCLUSIVE MODE` });
1813
+ await executor({ text: `LOCK TABLE "public".${postgresDialect5.quoteIdent({ name: state.table })} IN ACCESS EXCLUSIVE MODE` });
1733
1814
  }
1734
1815
  tables = await readPostgresRls({ executor });
1735
1816
  const matched = new Set;
1736
- for (const state2 of tables) {
1737
- const model = declared.get(state2.table);
1738
- const active = state2.enabled || state2.force || state2.policies.length > 0;
1817
+ for (const state of tables) {
1818
+ const model = declared.get(state.table);
1819
+ const active = state.enabled || state.force || state.policies.length > 0;
1739
1820
  if (schema === undefined && active)
1740
- conflict({ table: state2.table, reason: "rls-unmanaged", attributes: ["security metadata cannot be exported losslessly without a trusted declaration"] });
1821
+ conflict({ table: state.table, reason: "rls-unmanaged", attributes: ["security metadata cannot be exported losslessly without a trusted declaration"] });
1741
1822
  if (model === undefined || !isRlsProtected({ model })) {
1742
1823
  if (active)
1743
- conflict({ table: state2.table, reason: "rls-conflict", attributes: ["unexpected native policies or RLS flags"] });
1824
+ conflict({ table: state.table, reason: "rls-conflict", attributes: ["unexpected native policies or RLS flags"] });
1744
1825
  continue;
1745
1826
  }
1746
1827
  if (!active && params.requireInstalled !== true)
1747
1828
  continue;
1748
- const unknown = state2.policies.filter((policy2) => policy2.name !== NATIVE_RLS.policyName);
1829
+ const unknown = state.policies.filter((policy) => policy.name !== NATIVE_RLS.policyName);
1749
1830
  if (unknown.length > 0)
1750
- conflict({ table: state2.table, reason: "rls-conflict", attributes: unknown.map((policy2) => `unexpected policy ${policy2.name}`) });
1751
- const policy = state2.policies.find((entry) => entry.name === NATIVE_RLS.policyName);
1831
+ conflict({ table: state.table, reason: "rls-conflict", attributes: unknown.map((policy) => `unexpected policy ${policy.name}`) });
1832
+ const policy = state.policies.find((entry) => entry.name === NATIVE_RLS.policyName);
1752
1833
  if (policy === undefined)
1753
- conflict({ table: state2.table, reason: "rls-drift", attributes: ["missing policy"] });
1834
+ conflict({ table: state.table, reason: "rls-drift", attributes: ["missing policy"] });
1754
1835
  const structure = [
1755
1836
  ...policy.command !== "*" ? ["command"] : [],
1756
1837
  ...!policy.permissive ? ["permissiveness"] : [],
@@ -1758,27 +1839,27 @@ async function verifyPostgresRls(params) {
1758
1839
  ...policy.withCheck === null ? ["missing WITH CHECK"] : []
1759
1840
  ];
1760
1841
  if (structure.length > 0)
1761
- conflict({ table: state2.table, reason: "rls-conflict", attributes: structure });
1762
- const attributes = [...!state2.enabled ? ["enabled"] : [], ...!state2.force ? ["force"] : []];
1842
+ conflict({ table: state.table, reason: "rls-conflict", attributes: structure });
1843
+ const attributes = [...!state.enabled ? ["enabled"] : [], ...!state.force ? ["force"] : []];
1763
1844
  await executor({ text: "SAVEPOINT vibeorm_rls_probe" });
1764
1845
  let probe;
1765
1846
  try {
1766
- const rendered = renderRlsPolicy2({ dialect: postgresDialect4, schema, model: model.name, policyName: PROBE });
1847
+ const rendered = renderRlsPolicy2({ dialect: postgresDialect5, schema, model: model.name, policyName: PROBE });
1767
1848
  await executor({ text: rendered.text });
1768
- probe = (await readPostgresRls({ executor })).find((entry) => entry.table === state2.table)?.policies.find((entry) => entry.name === PROBE);
1849
+ probe = (await readPostgresRls({ executor })).find((entry) => entry.table === state.table)?.policies.find((entry) => entry.name === PROBE);
1769
1850
  } finally {
1770
1851
  await executor({ text: "ROLLBACK TO SAVEPOINT vibeorm_rls_probe" });
1771
1852
  await executor({ text: "RELEASE SAVEPOINT vibeorm_rls_probe" });
1772
1853
  }
1773
1854
  if (probe === undefined)
1774
- conflict({ table: state2.table, reason: "rls-drift", attributes: ["probe unavailable"] });
1855
+ conflict({ table: state.table, reason: "rls-drift", attributes: ["probe unavailable"] });
1775
1856
  if (policy.using !== probe.using)
1776
1857
  attributes.push("using");
1777
1858
  if (policy.withCheck !== probe.withCheck)
1778
1859
  attributes.push("withCheck");
1779
1860
  if (attributes.length > 0)
1780
- conflict({ table: state2.table, reason: "rls-drift", attributes });
1781
- matched.add(state2.table);
1861
+ conflict({ table: state.table, reason: "rls-drift", attributes });
1862
+ matched.add(state.table);
1782
1863
  }
1783
1864
  if (params.requireInstalled === true) {
1784
1865
  for (const [table, model] of declared) {
@@ -1961,18 +2042,18 @@ async function introspectPostgres(params) {
1961
2042
  if (params.inTransaction !== true)
1962
2043
  await executor({ text: "BEGIN" });
1963
2044
  try {
1964
- const savedPath = params.inTransaction === true ? await executor(renderRlsReadinessQuery({ dialect: postgresDialect5, query: "readSearchPath" })) : undefined;
2045
+ const savedPath = params.inTransaction === true ? await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "readSearchPath" })) : undefined;
1965
2046
  const searchPath = savedPath?.[0]?.searchPath;
1966
2047
  if (params.inTransaction === true && typeof searchPath !== "string")
1967
- throw new VibeError11({ code: "VIBE_MIGRATION", message: "Cannot read the migration search_path" });
2048
+ throw new VibeError12({ code: "VIBE_MIGRATION", message: "Cannot read the migration search_path" });
1968
2049
  const matched = await verifyPostgresRls({ executor, ...params.rlsSchema === undefined ? {} : { schema: params.rlsSchema }, ...params.requireInstalledRls === undefined ? {} : { requireInstalled: params.requireInstalledRls } }).then((verified) => verified, (error) => {
1969
- if (error instanceof VibeError11)
2050
+ if (error instanceof VibeError12)
1970
2051
  throw error;
1971
- throw new VibeError11({ code: "VIBE_MIGRATION", message: "Native RLS verification could not complete. Check migration privileges and supply the deployed schema as previousSchema/rlsSchema before changing referenced columns.", meta: { reason: "rls-verification-unavailable" }, cause: error });
2052
+ throw new VibeError12({ code: "VIBE_MIGRATION", message: "Native RLS verification could not complete. Check migration privileges and supply the deployed schema as previousSchema/rlsSchema before changing referenced columns.", meta: { reason: "rls-verification-unavailable" }, cause: error });
1972
2053
  });
1973
2054
  const physical = await introspectPhysicalPostgres({ executor });
1974
2055
  if (typeof searchPath === "string")
1975
- await executor(renderRlsReadinessQuery({ dialect: postgresDialect5, query: "setSearchPath", searchPath }));
2056
+ await executor(renderRlsReadinessQuery({ dialect: postgresDialect6, query: "setSearchPath", searchPath }));
1976
2057
  return projectPostgresRls({ physical, ...params.rlsSchema === undefined ? {} : { declared: params.rlsSchema }, matched });
1977
2058
  } finally {
1978
2059
  if (params.inTransaction !== true)
@@ -1990,7 +2071,7 @@ async function introspectPhysicalPostgres(params) {
1990
2071
  executor({ text: ENUMS_QUERY }),
1991
2072
  executor({ text: INDEXES_QUERY }),
1992
2073
  executor({ text: CHECKS_QUERY }),
1993
- executor({ text: renderExclusionCatalog2({ dialect: postgresDialect5 }) })
2074
+ executor({ text: renderExclusionCatalog2({ dialect: postgresDialect6 }) })
1994
2075
  ]);
1995
2076
  const tables = tableRows.map((row) => row.table_name);
1996
2077
  const views = viewRows.map((row) => row.table_name);
@@ -2158,12 +2239,15 @@ async function introspectPhysicalPostgres(params) {
2158
2239
  }
2159
2240
  addFkRelations({ models, fkGroups, joinTables });
2160
2241
  addJoinTableRelations({ models, joinTables });
2161
- return {
2242
+ const resolved = await resolvePostgresTypeIdentities({ executor, mode: "catalog", schema: {
2162
2243
  datasource: { provider: "postgresql" },
2163
2244
  models,
2164
2245
  enums,
2165
2246
  extensions: []
2166
- };
2247
+ } });
2248
+ if (resolved.unavailable.length > 0)
2249
+ throw new VibeError12({ code: "VIBE_MIGRATION", message: "PostgreSQL column type identity could not be read", meta: { reason: "type-inspection-unavailable", columns: resolved.unavailable } });
2250
+ return resolved.schema;
2167
2251
  }
2168
2252
  function buildModel(params) {
2169
2253
  const { table, isView, columns, pkByTable, uniquesByConstraint, constraintNames, indexes, enumNames } = params;
@@ -3132,8 +3216,8 @@ async function readIndexes(params) {
3132
3216
  }
3133
3217
  let where;
3134
3218
  if (partial) {
3135
- const sql2 = indexSqlByName.get(name);
3136
- const match = sql2?.match(/\sWHERE\s+(.*)$/is);
3219
+ const sql = indexSqlByName.get(name);
3220
+ const match = sql?.match(/\sWHERE\s+(.*)$/is);
3137
3221
  where = match?.[1]?.trim();
3138
3222
  }
3139
3223
  tableIndexes.push({
@@ -3164,17 +3248,17 @@ async function readIndexes(params) {
3164
3248
  var PLAIN_INDEX_COLUMN = /^"((?:[^"]|"")+)"(?:\s+(ASC|DESC))?$/i;
3165
3249
  var CAST_REAL_INDEX_COLUMN = /^CAST\s*\(\s*"((?:[^"]|"")+)"\s+AS\s+REAL\s*\)(?:\s+(ASC|DESC))?$/i;
3166
3250
  function parseIndexColumnsFromSql(params) {
3167
- const { sql: sql2 } = params;
3168
- if (sql2 === null)
3251
+ const { sql } = params;
3252
+ if (sql === null)
3169
3253
  return null;
3170
- const onMatch = /\sON\s+"(?:[^"]|"")+"\s*\(/i.exec(sql2);
3254
+ const onMatch = /\sON\s+"(?:[^"]|"")+"\s*\(/i.exec(sql);
3171
3255
  if (onMatch === null)
3172
3256
  return null;
3173
3257
  const open = onMatch.index + onMatch[0].length - 1;
3174
3258
  let listDepth = 0;
3175
3259
  let close = -1;
3176
- for (let index = open;index < sql2.length; index++) {
3177
- const char = sql2[index];
3260
+ for (let index = open;index < sql.length; index++) {
3261
+ const char = sql[index];
3178
3262
  if (char === "(")
3179
3263
  listDepth += 1;
3180
3264
  else if (char === ")") {
@@ -3187,7 +3271,7 @@ function parseIndexColumnsFromSql(params) {
3187
3271
  }
3188
3272
  if (close === -1)
3189
3273
  return null;
3190
- const list = sql2.slice(open + 1, close);
3274
+ const list = sql.slice(open + 1, close);
3191
3275
  const terms = [];
3192
3276
  let depth = 0;
3193
3277
  let start = 0;
@@ -3328,7 +3412,7 @@ function q(name) {
3328
3412
  }
3329
3413
 
3330
3414
  // packages/migrate/src/execute.ts
3331
- import { VibeError as VibeError12 } from "@vibeorm/schema";
3415
+ import { VibeError as VibeError13 } from "@vibeorm/schema";
3332
3416
  var SELF_MANAGED_MARKER = "PRAGMA foreign_keys=OFF";
3333
3417
  var FK_CHECK_PREFIX = "PRAGMA foreign_key_check";
3334
3418
  function usesSelfManagedTransactions(params) {
@@ -3349,9 +3433,9 @@ function classifySelfManagedStatement(params) {
3349
3433
  return "plain";
3350
3434
  }
3351
3435
  function selfManagedResumeStart(params) {
3352
- const { sql: sql2, start } = params;
3436
+ const { sql, start } = params;
3353
3437
  for (let index = start - 1;index >= 0; index -= 1) {
3354
- const control = classifySelfManagedStatement({ statement: sql2[index] });
3438
+ const control = classifySelfManagedStatement({ statement: sql[index] });
3355
3439
  if (control === "endTransaction" || control === "abandon" || control === "fkOn")
3356
3440
  return start;
3357
3441
  if (control === "fkOff")
@@ -3369,7 +3453,7 @@ function assertSelfManagedResumeSafe(params) {
3369
3453
  const completedIndex = params.direction === "up" ? params.start + 1 : -(params.start + 2);
3370
3454
  const rewind = selfManagedResumeStart({ sql: params.sql, start: params.start });
3371
3455
  const retryIndex = params.direction === "up" ? rewind : -(rewind + 1);
3372
- throw new VibeError12({
3456
+ throw new VibeError13({
3373
3457
  code: "VIBE_MIGRATION",
3374
3458
  message: `migration "${params.migration}" has a legacy sqlite checkpoint at ${params.direction} COMMIT (statement ${params.start + 1}). The block may already have committed; replay is refused. Inspect the block's effects. If it committed, set its journal statement_index to ${completedIndex} and error to NULL to resume the remaining statements. Only if the entire block did not commit, set statement_index to ${retryIndex} and error to NULL to retry the block. Do not mark the whole migration applied unless all remaining statements also ran.`,
3375
3459
  meta: { reason: "uncertain-statement", migration: params.migration, statementIndex: params.start, direction: params.direction, dialect: "sqlite" }
@@ -3398,37 +3482,37 @@ function unsupportedScript(params) {
3398
3482
  const { migration, direction, index, problem, found } = params;
3399
3483
  const subject = direction === "down" ? `the down script of migration "${migration}"` : `migration "${migration}"`;
3400
3484
  const position = `${direction === "down" ? "down statement" : "statement"} ${index + 1} of ${params.statements}`;
3401
- return new VibeError12({
3485
+ return new VibeError13({
3402
3486
  code: "VIBE_MIGRATION",
3403
3487
  message: `${subject} manages its own sqlite transactions, and ${position} breaks the shape recovery depends on: ${found}. ` + `A table-rebuild block must be written exactly as \`${SUPPORTED_BLOCK_SHAPE}\`. ` + "Inside that block a crash rolls everything back, so a resume can replay it safely. " + "A statement that sits in a foreign-keys-off region with no transaction around it commits on its own, " + "and the resume would run it a second time with no error raised either time. " + "Nothing has been executed. Move the statement after `PRAGMA foreign_keys=ON`, where it commits together " + "with its own journal checkpoint, or give it its own `BEGIN;` and `COMMIT;`. " + 'See "Self-managed sqlite scripts" in docs/migrations.md.',
3404
3488
  meta: { reason: "unsupported-self-managed-script", problem, migration, statementIndex: index, direction }
3405
3489
  });
3406
3490
  }
3407
3491
  function assertSupportedSelfManagedScript(params) {
3408
- const { sql: sql2, migration, direction } = params;
3409
- const statements = sql2.length;
3492
+ const { sql, migration, direction } = params;
3493
+ const statements = sql.length;
3410
3494
  const refuse = (index, problem, found) => unsupportedScript({ migration, direction, index, statements, problem, found });
3411
- let state2 = "outside";
3495
+ let state = "outside";
3412
3496
  let openedAt = -1;
3413
3497
  for (let index = 0;index < statements; index += 1) {
3414
- const control = classifySelfManagedStatement({ statement: sql2[index] });
3415
- if (state2 === "fkOff") {
3498
+ const control = classifySelfManagedStatement({ statement: sql[index] });
3499
+ if (state === "fkOff") {
3416
3500
  if (control !== "begin") {
3417
3501
  throw refuse(index, "fk-off-without-transaction", "`PRAGMA foreign_keys=OFF` is not followed by `BEGIN;`");
3418
3502
  }
3419
- state2 = "inBlock";
3503
+ state = "inBlock";
3420
3504
  continue;
3421
3505
  }
3422
- if (state2 === "committed") {
3506
+ if (state === "committed") {
3423
3507
  if (control !== "fkOn") {
3424
3508
  throw refuse(index, "commit-without-restore", "`COMMIT;` is not followed by `PRAGMA foreign_keys=ON;`");
3425
3509
  }
3426
- state2 = "outside";
3510
+ state = "outside";
3427
3511
  continue;
3428
3512
  }
3429
- if (state2 === "inBlock") {
3513
+ if (state === "inBlock") {
3430
3514
  if (control === "endTransaction") {
3431
- state2 = "committed";
3515
+ state = "committed";
3432
3516
  continue;
3433
3517
  }
3434
3518
  if (control === "plain")
@@ -3436,7 +3520,7 @@ function assertSupportedSelfManagedScript(params) {
3436
3520
  throw refuse(index, "unsupported-control-in-block", "transaction or pragma control appears inside an open rebuild block");
3437
3521
  }
3438
3522
  if (control === "fkOff") {
3439
- state2 = "fkOff";
3523
+ state = "fkOff";
3440
3524
  openedAt = index;
3441
3525
  continue;
3442
3526
  }
@@ -3444,8 +3528,8 @@ function assertSupportedSelfManagedScript(params) {
3444
3528
  throw refuse(index, "transaction-control-outside-block", "transaction control appears outside any rebuild block");
3445
3529
  }
3446
3530
  }
3447
- if (state2 !== "outside") {
3448
- throw refuse(openedAt, state2 === "committed" ? "commit-without-restore" : "unclosed-block", state2 === "committed" ? "the block commits but never restores foreign keys with `PRAGMA foreign_keys=ON;`" : "`PRAGMA foreign_keys=OFF` is never closed by `COMMIT;` and `PRAGMA foreign_keys=ON;`");
3531
+ if (state !== "outside") {
3532
+ throw refuse(openedAt, state === "committed" ? "commit-without-restore" : "unclosed-block", state === "committed" ? "the block commits but never restores foreign keys with `PRAGMA foreign_keys=ON;`" : "`PRAGMA foreign_keys=OFF` is never closed by `COMMIT;` and `PRAGMA foreign_keys=ON;`");
3449
3533
  }
3450
3534
  }
3451
3535
  async function executeStatement(params) {
@@ -3454,7 +3538,7 @@ async function executeStatement(params) {
3454
3538
  const rows = await executor({ text: statement, values: [] });
3455
3539
  if (rows.length > 0) {
3456
3540
  const sample = rows.slice(0, 5).map((row) => `${String(row.table)} rowid ${String(row.rowid)} \u2192 ${String(row.parent)}`).join("; ");
3457
- throw new VibeError12({
3541
+ throw new VibeError13({
3458
3542
  code: "VIBE_MIGRATION",
3459
3543
  message: `foreign key check failed after table rebuild: ${rows.length} violation(s) \u2014 ${sample}`,
3460
3544
  meta: { violations: rows }
@@ -3474,8 +3558,8 @@ async function cleanupSelfManagedFailure(params) {
3474
3558
  }
3475
3559
 
3476
3560
  // packages/migrate/src/postgres-default-equivalence.ts
3477
- import { VibeError as VibeError13 } from "@vibeorm/schema";
3478
- import { postgresDialect as postgresDialect6, renderPostgresDefaultFunctionIdentity } from "@vibeorm/sql";
3561
+ import { VibeError as VibeError14 } from "@vibeorm/schema";
3562
+ import { postgresDialect as postgresDialect7, renderPostgresDefaultFunctionIdentity } from "@vibeorm/sql";
3479
3563
  var IDENTIFIER = '(?:"(?:[^"\\u0000]|"")+"|[A-Za-z_][A-Za-z_0-9$]*)';
3480
3564
  var CALL = new RegExp(`^\\s*(${IDENTIFIER})(?:\\s*\\.\\s*(${IDENTIFIER}))?\\s*\\(\\s*\\)\\s*$`);
3481
3565
  function parseCall(params) {
@@ -3491,9 +3575,9 @@ async function equivalentPostgresDefaultFunction(params) {
3491
3575
  const observed = parseCall({ expression: params.actual });
3492
3576
  if (expected?.namespace === undefined || observed === undefined)
3493
3577
  return false;
3494
- const query = renderPostgresDefaultFunctionIdentity({ dialect: postgresDialect6, table: params.table, column: params.column });
3578
+ const query = renderPostgresDefaultFunctionIdentity({ dialect: postgresDialect7, table: params.table, column: params.column });
3495
3579
  const rows = await params.executor({ text: query.text, values: [...query.values] }).catch((cause) => {
3496
- throw new VibeError13({ code: "VIBE_MIGRATION", message: "Cannot inspect the stored default function identity", meta: { reason: "default-inspection-unavailable", table: params.table, column: params.column }, cause });
3580
+ throw new VibeError14({ code: "VIBE_MIGRATION", message: "Cannot inspect the stored default function identity", meta: { reason: "default-inspection-unavailable", table: params.table, column: params.column }, cause });
3497
3581
  });
3498
3582
  if (rows.length !== 1)
3499
3583
  return false;
@@ -3545,9 +3629,17 @@ async function inspectSqlObject(params) {
3545
3629
  } else {
3546
3630
  const constraintType = params.identity.constraintType;
3547
3631
  const constraint = sqliteTableConstraints2({ sql: String(facts.definition ?? "") }).find((entry) => entry.name === name && entry.type === constraintType);
3548
- if (constraint === undefined)
3549
- return { state: "unavailable", reason: "constraint-definition-inspection-unavailable" };
3550
- facts = { type: constraint.type, definition: constraint.sql };
3632
+ if (constraint === undefined && constraintType === "primaryKey" && name === `${params.identity.table.name}_pkey`) {
3633
+ const query = renderSqliteColumnInventory({ dialect: getSqlDialect({ dialect: "sqlite" }), namespace: params.identity.table.namespace, table: params.identity.table.name });
3634
+ const columns = (await params.executor({ text: query.text, values: [...query.values] })).filter((column) => Number(column.pk) > 0).sort((a, b) => Number(a.pk) - Number(b.pk));
3635
+ if (columns.length === 0)
3636
+ return { state: "missing" };
3637
+ facts = { type: "primaryKey", columns: columns.map((column) => String(column.name)) };
3638
+ } else {
3639
+ if (constraint === undefined)
3640
+ return { state: "unavailable", reason: "constraint-definition-inspection-unavailable" };
3641
+ facts = { type: constraint.type, definition: constraint.sql };
3642
+ }
3551
3643
  }
3552
3644
  }
3553
3645
  if (params.dialect === "sqlite" && (params.identity.kind === "column" || params.identity.kind === "columnDefault" || params.identity.kind === "generatedColumn")) {
@@ -3561,34 +3653,84 @@ async function inspectSqlObject(params) {
3561
3653
  if (params.identity.kind === "columnDefault")
3562
3654
  facts = { definition: facts.definition ?? null };
3563
3655
  if (params.dialect === "postgres") {
3564
- const query2 = renderMigrationDependencies({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3565
- const rows2 = await params.executor({ text: query2.text, values: [...query2.values] });
3566
- if (rows2.some((row) => typeof row.address !== "string"))
3567
- return { state: "unavailable", reason: "dependency-inspection-unavailable" };
3568
- facts = { ...facts, dependencyAddresses: rows2.map((row) => String(row.address)).sort() };
3656
+ const query = renderMigrationDependencies({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3657
+ const rows = await params.executor({ text: query.text, values: [...query.values] });
3658
+ return postgresInspection({ identity: params.identity, facts, addresses: rows.map((row) => row.address) });
3569
3659
  }
3570
3660
  if (params.dialect === "mysql") {
3571
- const query2 = renderMysqlObjectMembers({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3572
- if (query2 !== undefined) {
3573
- const rows2 = await params.executor({ text: query2.text, values: [...query2.values] });
3574
- if (params.identity.kind === "function" && rows2.length === 0)
3661
+ const query = renderMysqlObjectMembers({ dialect: getSqlDialect({ dialect: params.dialect }), identity: params.identity });
3662
+ if (query !== undefined) {
3663
+ const rows = await params.executor({ text: query.text, values: [...query.values] });
3664
+ if (params.identity.kind === "function" && rows.length === 0)
3575
3665
  return { state: "unavailable", reason: "function-signature-unavailable" };
3576
3666
  if (params.identity.kind === "function") {
3577
- const signature = rows2.filter((row) => row.mode !== null).map((row) => ({ namespace: "mysql", name: String(row.type) }));
3667
+ const signature = rows.filter((row) => row.mode !== null).map((row) => ({ namespace: "mysql", name: String(row.type) }));
3578
3668
  if (canonicalMigrationJson({ value: signature }) !== canonicalMigrationJson({ value: params.identity.argumentTypes }))
3579
3669
  return { state: "missing" };
3580
3670
  }
3581
- facts = { ...facts, members: rows2.map((row) => canonicalMigrationJson({ value: row })) };
3671
+ facts = { ...facts, members: rows.map((row) => canonicalMigrationJson({ value: row })) };
3582
3672
  }
3583
3673
  }
3584
- const dependencies = [];
3585
- if (params.identity.kind === "trigger" && params.dialect === "postgres") {
3586
- if (facts.functionArguments !== "")
3587
- return { state: "unavailable", reason: "trigger-function-signature-unavailable" };
3588
- dependencies.push({ kind: "function", name: { namespace: String(facts.functionNamespace), name: String(facts.functionName) }, argumentTypes: [] });
3674
+ return { state: "present", definition: { identity: params.identity, facts, dependencies: [], format: "catalog-v2" } };
3675
+ }).catch((error) => ({ state: "unavailable", reason: error instanceof VibeError15 ? String(error.meta.feature ?? error.code) : "catalog-query-failed" }));
3676
+ }
3677
+ function postgresInspection(params) {
3678
+ if (!params.addresses.every((address) => typeof address === "string"))
3679
+ return { state: "unavailable", reason: "dependency-inspection-unavailable" };
3680
+ const facts = { ...params.identity.kind === "columnDefault" ? { definition: params.facts.definition ?? null } : params.facts, dependencyAddresses: [...params.addresses].sort() };
3681
+ const dependencies = [];
3682
+ if (params.identity.kind === "trigger") {
3683
+ if (params.facts.functionArguments !== "")
3684
+ return { state: "unavailable", reason: "trigger-function-signature-unavailable" };
3685
+ dependencies.push({ kind: "function", name: { namespace: String(params.facts.functionNamespace), name: String(params.facts.functionName) }, argumentTypes: [] });
3686
+ }
3687
+ return { state: "present", definition: { identity: params.identity, facts, dependencies, format: "catalog-v2" } };
3688
+ }
3689
+ function unavailableReason(params) {
3690
+ return params.error instanceof VibeError15 ? String(params.error.meta.feature ?? params.error.meta.reason ?? params.error.code) : "catalog-query-failed";
3691
+ }
3692
+ async function readBatch(params) {
3693
+ const positions = new Set(params.batch.positions);
3694
+ return Promise.resolve().then(async () => {
3695
+ const rows = new Map;
3696
+ for (const row of await params.executor({ text: params.batch.text, values: [...params.batch.values] })) {
3697
+ if (typeof row.position !== "number" || !Number.isInteger(row.position) || !positions.has(row.position))
3698
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Invalid batched catalog identity", meta: { reason: "catalog-query-failed" } });
3699
+ const matches = rows.get(row.position) ?? [];
3700
+ matches.push(row);
3701
+ rows.set(row.position, matches);
3702
+ }
3703
+ return { ok: true, rows };
3704
+ }).then((outcome) => outcome, (error) => ({ ok: false, reason: unavailableReason({ error }) }));
3705
+ }
3706
+ function batchedInspection(params) {
3707
+ if (params.matches.length === 0)
3708
+ return { state: "missing" };
3709
+ if (params.matches.length !== 1)
3710
+ return { state: "unavailable", reason: "ambiguous-catalog-identity" };
3711
+ const row = params.matches[0];
3712
+ const facts = row.facts !== null && typeof row.facts === "object" && !Array.isArray(row.facts) ? factsOf({ row: row.facts }) : undefined;
3713
+ if (facts === undefined || !Array.isArray(row.dependencyAddresses))
3714
+ return { state: "unavailable", reason: "unsupported-catalog-value" };
3715
+ return postgresInspection({ identity: params.identity, facts, addresses: row.dependencyAddresses });
3716
+ }
3717
+ async function inspectSqlObjects(params) {
3718
+ if (params.dialect !== "postgres") {
3719
+ const results = [];
3720
+ for (const identity of params.identities)
3721
+ results.push(await inspectSqlObject({ ...params, identity }));
3722
+ return results;
3723
+ }
3724
+ return Promise.resolve().then(async () => {
3725
+ const results = params.identities.map(() => ({ state: "unavailable", reason: "catalog-query-failed" }));
3726
+ for (const batch of renderMigrationObjectBatch({ dialect: getSqlDialect({ dialect: params.dialect }), identities: params.identities })) {
3727
+ const outcome = await readBatch({ executor: params.executor, batch });
3728
+ for (const position of batch.positions) {
3729
+ results[position] = outcome.ok ? batchedInspection({ identity: params.identities[position], matches: outcome.rows.get(position) ?? [] }) : { state: "unavailable", reason: outcome.reason };
3730
+ }
3589
3731
  }
3590
- return { state: "present", definition: { identity: params.identity, facts, dependencies, format: "catalog-v1" } };
3591
- }).catch((error) => ({ state: "unavailable", reason: error instanceof VibeError14 ? String(error.meta.feature ?? error.code) : "catalog-query-failed" }));
3732
+ return results;
3733
+ }).then((result) => result, (error) => params.identities.map(() => ({ state: "unavailable", reason: unavailableReason({ error }) })));
3592
3734
  }
3593
3735
  async function assertCatalogVisibility(params) {
3594
3736
  if (params.dialect !== "mysql")
@@ -3598,15 +3740,23 @@ async function assertCatalogVisibility(params) {
3598
3740
  const grants = new Set(rows.map((row) => row.privilege));
3599
3741
  const missing = ["SELECT", "TRIGGER", "SHOW VIEW", "EXECUTE"].filter((privilege) => !grants.has(privilege));
3600
3742
  if (missing.length > 0)
3601
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "MySQL catalog visibility requires direct database-wide grants; role-only or partial grants cannot prove object absence", meta: { reason: "inventory-unavailable", missing } });
3743
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "MySQL catalog visibility requires direct database-wide grants; role-only or partial grants cannot prove object absence", meta: { reason: "inventory-unavailable", missing } });
3602
3744
  }
3745
+ var CATALOG_V1_OMITTED_FACTS = Object.freeze({
3746
+ function: ["definerOwner"],
3747
+ column: ["collationNamespace", "collationName"],
3748
+ generatedColumn: ["collationNamespace", "collationName"]
3749
+ });
3603
3750
  function compare(params) {
3604
3751
  const differences = [];
3752
+ const omitted = params.expected.format === "catalog-v1" ? CATALOG_V1_OMITTED_FACTS[params.expected.identity.kind] ?? [] : [];
3605
3753
  for (const key of new Set([...Object.keys(params.expected.facts), ...Object.keys(params.live.facts)])) {
3606
- const expected2 = params.expected.facts[key];
3607
- const actual2 = params.live.facts[key];
3608
- if (expected2 === undefined !== (actual2 === undefined) || canonicalMigrationJson({ value: expected2 }) !== canonicalMigrationJson({ value: actual2 }))
3609
- differences.push({ attribute: key, expected: expected2, actual: actual2 });
3754
+ if (omitted.includes(key) && !Object.hasOwn(params.expected.facts, key))
3755
+ continue;
3756
+ const expected = params.expected.facts[key];
3757
+ const actual = params.live.facts[key];
3758
+ if (expected === undefined !== (actual === undefined) || canonicalMigrationJson({ value: expected }) !== canonicalMigrationJson({ value: actual }))
3759
+ differences.push({ attribute: key, expected, actual });
3610
3760
  }
3611
3761
  const expected = params.expected.dependencies.map((identity) => sqlObjectKey4({ identity })).sort();
3612
3762
  const actual = params.live.dependencies.map((identity) => sqlObjectKey4({ identity })).sort();
@@ -3616,7 +3766,7 @@ function compare(params) {
3616
3766
  }
3617
3767
  function assertProbeMode(params) {
3618
3768
  if (params.probe !== undefined && params.probe !== "none" && DIALECT_CAPABILITIES2[params.dialect].checkNormalization !== params.probe)
3619
- throw new VibeError14({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `${params.probe} CHECK probes are unavailable on ${params.dialect}`, meta: { feature: "checkProbe", dialect: params.dialect } });
3769
+ throw new VibeError15({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `${params.probe} CHECK probes are unavailable on ${params.dialect}`, meta: { feature: "checkProbe", dialect: params.dialect } });
3620
3770
  }
3621
3771
  async function verifyMigrationState(params) {
3622
3772
  return verifyState(params);
@@ -3630,10 +3780,13 @@ async function verifyState(params) {
3630
3780
  for (const object of declarations)
3631
3781
  identities.set(sqlObjectKey4({ identity: object.identity }), object.identity);
3632
3782
  const objects = [];
3783
+ const inspections = params.batch === true ? await inspectSqlObjects({ ...params, identities: [...identities.values()] }) : undefined;
3784
+ let position = 0;
3633
3785
  for (const [key, identity] of identities) {
3634
3786
  const ownership = owned.has(key) ? "migration" : "schema";
3635
3787
  const expected = definitions.get(key);
3636
- const live = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3788
+ const live = inspections === undefined ? await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity }) : inspections[position];
3789
+ position++;
3637
3790
  if (live.state !== "present") {
3638
3791
  objects.push({ identity, ownership, state: live.state, differences: [], ...live.state === "unavailable" ? { reason: live.reason } : {} });
3639
3792
  } else if (expected === undefined) {
@@ -3653,9 +3806,10 @@ async function verifyState(params) {
3653
3806
  }
3654
3807
  async function verifySchemaObjects(params) {
3655
3808
  const physical = params.dialect === "postgres" ? await introspectPhysicalPostgres({ executor: params.executor }) : params.dialect === "mysql" ? await introspectMysql({ executor: params.executor }) : params.sqliteRestorePending === true ? await introspectSqliteBeforeForeignKeyRestore({ executor: params.executor }) : await introspectSqlite({ executor: params.executor });
3656
- const expected = normalizeSchema({ schema: params.expected.schema, dialect: params.dialect });
3809
+ const resolved = params.dialect === "postgres" ? await resolvePostgresTypeIdentities({ executor: params.executor, schema: params.expected.schema, mode: "verify" }) : { schema: params.expected.schema, unavailable: [] };
3810
+ const expected = normalizeSchema({ schema: resolved.schema, dialect: params.dialect });
3657
3811
  const actual = normalizeSchema({ schema: physical, dialect: params.dialect });
3658
- const objects = [];
3812
+ const objects = resolved.unavailable.map((identity) => ({ identity, ownership: "schema", state: "unavailable", reason: "type-reference-required", differences: [] }));
3659
3813
  const namespace = await migrationNamespace({ executor: params.executor, dialect: params.dialect });
3660
3814
  const sqliteTableOptions = params.dialect === "sqlite" && expected.tables.size > 0 ? await params.executor({ text: "PRAGMA main.table_list;", values: [] }) : undefined;
3661
3815
  if (params.dialect === "postgres")
@@ -3690,9 +3844,9 @@ async function verifySchemaObjects(params) {
3690
3844
  }
3691
3845
  }
3692
3846
  const differences = [];
3693
- const pin = (attribute, expected2, actual2) => {
3694
- if (canonicalMigrationJson({ value: expected2 }) !== canonicalMigrationJson({ value: actual2 }))
3695
- differences.push({ attribute, expected: expected2, actual: actual2 });
3847
+ const pin = (attribute, expected, actual) => {
3848
+ if (canonicalMigrationJson({ value: expected }) !== canonicalMigrationJson({ value: actual }))
3849
+ differences.push({ attribute, expected, actual });
3696
3850
  };
3697
3851
  pin("primaryKey", desired.pk, live.pk);
3698
3852
  for (const [column, field] of desired.columns) {
@@ -3722,8 +3876,8 @@ async function verifySchemaObjects(params) {
3722
3876
  if (inspection.state !== "present") {
3723
3877
  objects.push({ identity, ownership: "schema", state: inspection.state, differences: [], ...inspection.state === "unavailable" ? { reason: inspection.reason } : {} });
3724
3878
  } else {
3725
- const differences2 = ["validated", "triggersEnabled"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3726
- objects.push({ identity, ownership: "schema", state: differences2.length === 0 ? "matching" : "changed", differences: differences2 });
3879
+ const differences = ["validated", "triggersEnabled"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3880
+ objects.push({ identity, ownership: "schema", state: differences.length === 0 ? "matching" : "changed", differences });
3727
3881
  }
3728
3882
  }
3729
3883
  }
@@ -3738,8 +3892,8 @@ async function verifySchemaObjects(params) {
3738
3892
  if (inspection.state !== "present") {
3739
3893
  objects.push({ identity, ownership: "schema", state: inspection.state, differences: [], ...inspection.state === "unavailable" ? { reason: inspection.reason } : {} });
3740
3894
  } else {
3741
- const differences2 = ["valid", "ready"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3742
- objects.push({ identity, ownership: "schema", state: differences2.length === 0 ? "matching" : "changed", differences: differences2 });
3895
+ const differences = ["valid", "ready"].flatMap((attribute) => inspection.definition.facts[attribute] === true ? [] : [{ attribute, expected: true, actual: inspection.definition.facts[attribute] }]);
3896
+ objects.push({ identity, ownership: "schema", state: differences.length === 0 ? "matching" : "changed", differences });
3743
3897
  }
3744
3898
  }
3745
3899
  objects.push({ identity: { kind: "table", name: table }, ownership: "schema", state: differences.length === 0 ? "matching" : "changed", differences });
@@ -3771,14 +3925,14 @@ async function verifySchemaObjects(params) {
3771
3925
  if (params.dialect === "postgres" && params.probe === "rollback") {
3772
3926
  const normalized = await deparsePostgresCheck({ executor: params.executor, table, expression, probe: "rollback" });
3773
3927
  const read = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3774
- const actual2 = read.state === "present" ? read.definition.facts.definition : undefined;
3775
- objects.push({ identity, ownership: "schema", state: normalized === actual2 ? "matching" : "changed", differences: normalized === actual2 ? [] : [{ attribute: "definition", expected: normalized, actual: actual2 }] });
3928
+ const actual = read.state === "present" ? read.definition.facts.definition : undefined;
3929
+ objects.push({ identity, ownership: "schema", state: normalized === actual ? "matching" : "changed", differences: normalized === actual ? [] : [{ attribute: "definition", expected: normalized, actual }] });
3776
3930
  } else if (params.dialect === "mysql" && params.probe === "temporary") {
3777
3931
  const normalized = await deparseMysqlCheck({ executor: params.executor, table, expression, probe: "temporary" });
3778
3932
  const inspection = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3779
- const actual2 = inspection.state === "present" ? inspection.definition.facts.definition : undefined;
3780
- const match = normalized === actual2;
3781
- objects.push({ identity, ownership: "schema", state: inspection.state === "unavailable" ? "unavailable" : match ? "matching" : "changed", differences: match ? [] : [{ attribute: "definition", expected: normalized, actual: actual2 }] });
3933
+ const actual = inspection.state === "present" ? inspection.definition.facts.definition : undefined;
3934
+ const match = normalized === actual;
3935
+ objects.push({ identity, ownership: "schema", state: inspection.state === "unavailable" ? "unavailable" : match ? "matching" : "changed", differences: match ? [] : [{ attribute: "definition", expected: normalized, actual }] });
3782
3936
  } else
3783
3937
  objects.push({ identity, ownership: "schema", state: "unavailable", reason: "explicit-replacement-required", differences: [{ attribute: "definition", expected: expression, actual: stored }] });
3784
3938
  }
@@ -3800,14 +3954,14 @@ async function verifyMigrationTransition(params) {
3800
3954
  }
3801
3955
  async function verifySqliteTransitionBeforeRestore(params) {
3802
3956
  if (params.dialect !== "sqlite")
3803
- throw new VibeError14({ code: "VIBE_INTERNAL", message: "SQLite rebuild verification requires the SQLite dialect" });
3957
+ throw new VibeError15({ code: "VIBE_INTERNAL", message: "SQLite rebuild verification requires the SQLite dialect" });
3804
3958
  await executeStatement({ executor: params.executor, dialect: "sqlite", statement: "PRAGMA foreign_key_check;" });
3805
3959
  return verifyTransition({ ...params, sqliteRestorePending: true });
3806
3960
  }
3807
3961
  async function verifyTransition(params) {
3808
3962
  const report = await verifyState({ executor: params.executor, dialect: params.dialect, expected: params.to, ...params.sqliteRestorePending === true ? { sqliteRestorePending: true } : {}, ...params.probe === undefined ? {} : { probe: params.probe } });
3809
3963
  const namespace = await migrationNamespace(params);
3810
- const identities = (state2) => [...schemaObjectIdentities({ schema: state2.schema, dialect: params.dialect, namespace }), ...(state2.schema.migrationObjects ?? []).map((object) => object.identity), ...state2.definitions.map((definition) => definition.identity)];
3964
+ const identities = (state) => [...schemaObjectIdentities({ schema: state.schema, dialect: params.dialect, namespace }), ...(state.schema.migrationObjects ?? []).map((object) => object.identity), ...state.definitions.map((definition) => definition.identity)];
3811
3965
  const retained = new Set(identities(params.to).map((identity) => sqlObjectKey4({ identity })));
3812
3966
  const removed = new Map([...identities(params.from).filter((identity) => !retained.has(sqlObjectKey4({ identity }))), ...params.removals ?? []].map((identity) => [sqlObjectKey4({ identity }), identity]));
3813
3967
  const objects = [...report.objects];
@@ -3826,12 +3980,12 @@ async function migrationNamespace(params) {
3826
3980
  const rows = await params.executor({ text: query.text, values: [] });
3827
3981
  const namespace = rows[0]?.namespace;
3828
3982
  if (typeof namespace !== "string" || namespace.length === 0)
3829
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Cannot determine the migration namespace", meta: { reason: "inspection-unavailable" } });
3983
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Cannot determine the migration namespace", meta: { reason: "inspection-unavailable" } });
3830
3984
  return namespace;
3831
3985
  }
3832
3986
  function assertMigrationState(params) {
3833
3987
  if (!params.report.inSync)
3834
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Migration state could not be verified", meta: { reason: "migration-state-unverified", objects: params.report.objects.filter((object) => object.state !== "matching") } });
3988
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Migration state could not be verified", meta: { reason: "migration-state-unverified", shadowReusable: true, objects: params.report.objects.filter((object) => object.state !== "matching") } });
3835
3989
  }
3836
3990
  async function deparsePostgresCheck(params) {
3837
3991
  const definition = await deparsePostgresCheckDefinition({ ...params, constraint: "vibeorm_check_probe" });
@@ -3845,7 +3999,7 @@ async function deparsePostgresCheckDefinition(params) {
3845
3999
  await params.executor({ text: query.text });
3846
4000
  const result = await inspectSqlObject({ executor: params.executor, dialect: "postgres", identity: { kind: "constraint", constraintType: "check", table: params.table, name } });
3847
4001
  if (result.state !== "present" || typeof result.definition.facts.definition !== "string")
3848
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "CHECK normalization probe unavailable", meta: { reason: "check-inspection-unavailable" } });
4002
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "CHECK normalization probe unavailable", meta: { reason: "check-inspection-unavailable" } });
3849
4003
  return { ...result.definition, identity: { kind: "constraint", constraintType: "check", table: params.table, name: params.constraint }, facts: { ...result.definition.facts, definition: result.definition.facts.definition.replace(/ NOT VALID$/, ""), validated: true } };
3850
4004
  } finally {
3851
4005
  await params.executor({ text: "ROLLBACK TO SAVEPOINT vibeorm_check_probe" });
@@ -3863,7 +4017,7 @@ async function deparseMysqlCheck(params) {
3863
4017
  const source = await params.executor({ text: read.text, values: [] });
3864
4018
  const definition = source[0]?.["Create Table"];
3865
4019
  if (typeof definition !== "string")
3866
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Cannot read temporary clone definition" });
4020
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Cannot read temporary clone definition" });
3867
4021
  const drop = renderMysqlCheckProbe({ dialect, probe, operation: "drop" });
3868
4022
  await params.executor({ text: drop.text });
3869
4023
  created = false;
@@ -3874,7 +4028,7 @@ async function deparseMysqlCheck(params) {
3874
4028
  const normalizedDefinition = rows[0]?.["Create Table"];
3875
4029
  const check = typeof normalizedDefinition === "string" ? parseSqliteNamedChecks({ tableSql: normalizedDefinition }).find((entry) => entry.name === probe) : undefined;
3876
4030
  if (check === undefined)
3877
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "MySQL temporary CHECK deparse unavailable", meta: { reason: "check-inspection-unavailable" } });
4031
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "MySQL temporary CHECK deparse unavailable", meta: { reason: "check-inspection-unavailable" } });
3878
4032
  return check.expression;
3879
4033
  } finally {
3880
4034
  if (created) {
@@ -3901,7 +4055,7 @@ async function prepareCheckDiff(params) {
3901
4055
  const desired = await deparsePostgresCheck({ executor: params.executor, table: identity.table, expression: next.expression, probe: "rollback" });
3902
4056
  const live = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3903
4057
  if (live.state !== "present")
3904
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
4058
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
3905
4059
  if (live.definition.facts.definition === desired) {
3906
4060
  checks.push(next);
3907
4061
  continue;
@@ -3913,7 +4067,7 @@ async function prepareCheckDiff(params) {
3913
4067
  const desired = await deparseMysqlCheck({ executor: params.executor, table: identity.table, expression: next.expression, probe: "temporary" });
3914
4068
  const live = await inspectSqlObject({ executor: params.executor, dialect: params.dialect, identity });
3915
4069
  if (live.state !== "present")
3916
- throw new VibeError14({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
4070
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: "Live CHECK inspection unavailable", meta: { reason: "check-inspection-unavailable", identity } });
3917
4071
  checks.push(desired === live.definition.facts.definition ? next : { name: check.name, expression: check.expression });
3918
4072
  continue;
3919
4073
  }
@@ -3926,7 +4080,7 @@ async function prepareCheckDiff(params) {
3926
4080
  checks.push({ name: check.name, expression: check.expression });
3927
4081
  continue;
3928
4082
  }
3929
- throw new VibeError14({ code: "VIBE_MIGRATION", message: `Cannot establish CHECK equivalence for ${table}.${check.name}; request a rollback probe or an explicit replacement`, meta: { reason: "explicit-replacement-required", identity } });
4083
+ throw new VibeError15({ code: "VIBE_MIGRATION", message: `Cannot establish CHECK equivalence for ${table}.${check.name}; request a rollback probe or an explicit replacement`, meta: { reason: "explicit-replacement-required", identity } });
3930
4084
  }
3931
4085
  models.push({ ...model, checks });
3932
4086
  }
@@ -3953,7 +4107,7 @@ async function inspectMigrationInventory(params) {
3953
4107
  for (const row of rows) {
3954
4108
  const name = row.name;
3955
4109
  if (typeof name !== "string" || typeof row.kind !== "string")
3956
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "Malformed catalog identity", meta: { reason: "inventory-unavailable" } });
4110
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "Malformed catalog identity", meta: { reason: "inventory-unavailable" } });
3957
4111
  const qualified = { namespace: params.namespace, name };
3958
4112
  const table = { namespace: params.namespace, name: String(row.parent ?? "") };
3959
4113
  let identity;
@@ -3975,27 +4129,27 @@ async function inspectMigrationInventory(params) {
3975
4129
  case "constraint": {
3976
4130
  const constraintType = kinds[String(row.subtype)];
3977
4131
  if (constraintType === undefined)
3978
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "Unknown constraint catalog kind", meta: { reason: "inventory-unavailable" } });
4132
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "Unknown constraint catalog kind", meta: { reason: "inventory-unavailable" } });
3979
4133
  identity = { kind: "constraint", table, name, constraintType };
3980
4134
  break;
3981
4135
  }
3982
4136
  case "function": {
3983
4137
  let argumentTypes = JSON.parse(String(row.signature));
3984
4138
  if (params.dialect === "mysql") {
3985
- const query2 = renderMysqlObjectMembers2({ dialect: getSqlDialect2({ dialect: params.dialect }), identity: { kind: "function", name: qualified, argumentTypes: [] } });
3986
- const members = await params.executor({ text: query2.text, values: [...query2.values] });
4139
+ const query = renderMysqlObjectMembers2({ dialect: getSqlDialect2({ dialect: params.dialect }), identity: { kind: "function", name: qualified, argumentTypes: [] } });
4140
+ const members = await params.executor({ text: query.text, values: [...query.values] });
3987
4141
  if (members.length === 0)
3988
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "MySQL function signature unavailable", meta: { reason: "inventory-unavailable", name } });
4142
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "MySQL function signature unavailable", meta: { reason: "inventory-unavailable", name } });
3989
4143
  argumentTypes = members.filter((member) => member.mode !== null).map((member) => ({ namespace: "mysql", name: String(member.type) }));
3990
4144
  }
3991
4145
  const candidate = { kind: "function", name: qualified, argumentTypes };
3992
4146
  if (!isSqlObjectIdentity2(candidate))
3993
- throw new VibeError15({ code: "VIBE_MIGRATION", message: "Invalid function signature in catalog", meta: { reason: "inventory-unavailable" } });
4147
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: "Invalid function signature in catalog", meta: { reason: "inventory-unavailable" } });
3994
4148
  identity = candidate;
3995
4149
  break;
3996
4150
  }
3997
4151
  default:
3998
- throw new VibeError15({ code: "VIBE_MIGRATION", message: `Unknown catalog object kind ${row.kind}`, meta: { reason: "inventory-unavailable" } });
4152
+ throw new VibeError16({ code: "VIBE_MIGRATION", message: `Unknown catalog object kind ${row.kind}`, meta: { reason: "inventory-unavailable" } });
3999
4153
  }
4000
4154
  objects.push({ identity, ...typeof row.backing === "string" ? { backingConstraint: row.backing } : {} });
4001
4155
  if (params.dialect === "sqlite" && row.kind === "table" && typeof row.definition === "string" && !/^\s*CREATE\s+VIRTUAL\s+TABLE\b/i.test(row.definition)) {
@@ -4003,16 +4157,16 @@ async function inspectMigrationInventory(params) {
4003
4157
  for (const constraint of clauses) {
4004
4158
  if (constraint.type === "check")
4005
4159
  continue;
4006
- const name2 = constraint.named ? constraint.name : constraint.type === "primaryKey" ? `${qualified.name}_pkey` : constraint.type === "foreignKey" ? `${qualified.name}_${constraint.columns.join("_")}_fkey` : constraint.name;
4007
- objects.push({ identity: { kind: "constraint", constraintType: constraint.type, table: qualified, name: name2 }, ...constraint.type === "unique" && !constraint.named ? { inspectionUnavailable: "sqlite-anonymous-unique-constraint" } : {} });
4160
+ const name = constraint.named ? constraint.name : constraint.type === "primaryKey" ? `${qualified.name}_pkey` : constraint.type === "foreignKey" ? `${qualified.name}_${constraint.columns.join("_")}_fkey` : constraint.name;
4161
+ objects.push({ identity: { kind: "constraint", constraintType: constraint.type, table: qualified, name }, ...constraint.type === "unique" && !constraint.named ? { inspectionUnavailable: "sqlite-anonymous-unique-constraint" } : {} });
4008
4162
  }
4009
4163
  const checks = parseSqliteNamedChecks({ tableSql: row.definition });
4010
4164
  for (const check of checks)
4011
4165
  objects.push({ identity: { kind: "constraint", constraintType: "check", table: qualified, name: check.name } });
4012
4166
  if ([...row.definition.matchAll(/\bCHECK\s*\(/gi)].length > checks.length)
4013
4167
  objects.push({ identity: { kind: "table", name: qualified }, inspectionUnavailable: "sqlite-unnamed-check-definition-unavailable" });
4014
- const query2 = renderSqliteColumnInventory({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4015
- const columns = await params.executor({ text: query2.text, values: [...query2.values] });
4168
+ const query = renderSqliteColumnInventory2({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
4169
+ const columns = await params.executor({ text: query.text, values: [...query.values] });
4016
4170
  if (columns.some((column) => Number(column.pk) > 0) && !clauses.some((clause) => clause.type === "primaryKey"))
4017
4171
  objects.push({ identity: { kind: "constraint", constraintType: "primaryKey", table: qualified, name: `${qualified.name}_pkey` } });
4018
4172
  const fkQuery = renderSqliteForeignKeyInventory({ dialect: getSqlDialect2({ dialect: params.dialect }), namespace: params.namespace, table: name });
@@ -4039,7 +4193,7 @@ async function inspectMigrationInventory(params) {
4039
4193
 
4040
4194
  // packages/migrate/src/module-ownership.ts
4041
4195
  function refusal(params) {
4042
- return new VibeError16({ code: "VIBE_MIGRATION", message: "Module ownership or dependencies cannot be reconciled with the declared and live schema; no package SQL was authorized", meta: params });
4196
+ return new VibeError17({ code: "VIBE_MIGRATION", message: "Module ownership or dependencies cannot be reconciled with the declared and live schema; no package SQL was authorized", meta: params });
4043
4197
  }
4044
4198
  function identities(params) {
4045
4199
  return [...schemaObjectIdentities({ schema: params.state.schema, dialect: params.dialect, namespace: params.namespace }), ...(params.state.schema.migrationObjects ?? []).map((object) => object.identity), ...params.state.definitions.map((definition) => definition.identity)];
@@ -4055,14 +4209,14 @@ function moduleNamespace(params) {
4055
4209
  function moduleOwnedObjects(params) {
4056
4210
  const { desiredState } = params;
4057
4211
  const namespace = params.namespace ?? (desiredState.dialect === "sqlite" ? "main" : "public");
4058
- const all = [desiredState.from, desiredState.to, ...desiredState.down === undefined ? [] : [desiredState.down]].flatMap((state2) => identities({ state: state2, dialect: desiredState.dialect, namespace }));
4212
+ const all = [desiredState.from, desiredState.to, ...desiredState.down === undefined ? [] : [desiredState.down]].flatMap((state) => identities({ state, dialect: desiredState.dialect, namespace }));
4059
4213
  return [...new Map(all.map((identity) => [sqlObjectKey6({ identity }), identity])).values()].sort((a, b) => sqlObjectKey6({ identity: a }).localeCompare(sqlObjectKey6({ identity: b })));
4060
4214
  }
4061
4215
  function assertModuleOwnership(params) {
4062
4216
  const { origin } = params;
4063
- const state2 = origin.source.desiredState;
4217
+ const state = origin.source.desiredState;
4064
4218
  const namespace = moduleNamespace({ origin });
4065
- const expected = moduleOwnedObjects({ desiredState: state2, namespace });
4219
+ const expected = moduleOwnedObjects({ desiredState: state, namespace });
4066
4220
  const owned = new Set(origin.owned.map((identity) => sqlObjectKey6({ identity })));
4067
4221
  if (expected.length !== owned.size || expected.some((identity) => !owned.has(sqlObjectKey6({ identity }))))
4068
4222
  throw refusal({ reason: "module-ownership-invalid", moduleId: origin.moduleId });
@@ -4071,10 +4225,10 @@ function assertModuleOwnership(params) {
4071
4225
  if (name?.namespace !== namespace || name.name === "_vibe_migrations")
4072
4226
  throw refusal({ reason: "module-ownership-invalid", moduleId: origin.moduleId, identity });
4073
4227
  }
4074
- for (const target of [state2.from, state2.to, ...state2.down === undefined ? [] : [state2.down]]) {
4228
+ for (const target of [state.from, state.to, ...state.down === undefined ? [] : [state.down]]) {
4075
4229
  if (target.schema.rls !== undefined || target.schema.extensions.length > 0)
4076
4230
  throw refusal({ reason: "module-schema-unsupported", moduleId: origin.moduleId });
4077
- for (const dependency of [...target.definitions.flatMap((definition) => definition.dependencies), ...(target.schema.migrationObjects ?? []).flatMap((object) => object.dependsOn), ...state2.unmanagedRemovals ?? []]) {
4231
+ for (const dependency of [...target.definitions.flatMap((definition) => definition.dependencies), ...(target.schema.migrationObjects ?? []).flatMap((object) => object.dependsOn), ...state.unmanagedRemovals ?? []]) {
4078
4232
  if (!owned.has(sqlObjectKey6({ identity: dependency })))
4079
4233
  throw refusal({ reason: "module-external-dependency", moduleId: origin.moduleId, identity: dependency });
4080
4234
  }
@@ -4095,10 +4249,39 @@ function assertModuleOwnership(params) {
4095
4249
  throw refusal({ reason: "module-source-state-mismatch", moduleId: origin.moduleId });
4096
4250
  return { ...actual, schema: { ...actual.schema, models: actual.schema.models.filter((model) => !tables.has(model.dbName ?? model.name)), enums: actual.schema.enums.filter((entry) => !enums.has(entry.dbName ?? entry.name)), migrationObjects: (actual.schema.migrationObjects ?? []).filter((object) => !owned.has(sqlObjectKey6({ identity: object.identity }))) }, definitions: actual.definitions.filter((definition) => !owned.has(sqlObjectKey6({ identity: definition.identity }))) };
4097
4251
  };
4098
- const before = canonicalMigrationJson({ value: rest(local.from, state2.from) });
4099
- if (before !== canonicalMigrationJson({ value: rest(local.to, state2.to) }) || before !== canonicalMigrationJson({ value: rest(local.down ?? local.from, state2.down ?? state2.from) }))
4252
+ const before = canonicalMigrationJson({ value: rest(local.from, state.from) });
4253
+ if (before !== canonicalMigrationJson({ value: rest(local.to, state.to) }) || before !== canonicalMigrationJson({ value: rest(local.down ?? local.from, state.down ?? state.from) }))
4100
4254
  throw refusal({ reason: "module-mutates-application-state", moduleId: origin.moduleId });
4101
4255
  }
4256
+ function dependencyUnavailable(params) {
4257
+ return new VibeError17({ code: "VIBE_MIGRATION", message: "Cannot establish module foreign-key dependencies across namespaces. MySQL requires direct global SHOW VIEW (or SELECT) without partial revokes; SHOW VIEW exposes metadata without granting external row reads. Restore catalog visibility before retrying", meta: { reason: "module-dependency-unavailable", moduleId: params.origin.moduleId }, ...params.cause === undefined ? {} : { cause: params.cause } });
4258
+ }
4259
+ async function assertCrossNamespaceModuleDependencies(params) {
4260
+ const { executor, origin } = params;
4261
+ const dialect = getSqlDialect3({ dialect: origin.dialect });
4262
+ const query = renderModuleDependencyQuery({ dialect, operation: { kind: "foreignKeys", namespace: params.namespace, tables: [...params.tables] } });
4263
+ if (query === undefined)
4264
+ return;
4265
+ const visibility = renderModuleDependencyQuery({ dialect, operation: { kind: "visibility" } });
4266
+ if (visibility !== undefined) {
4267
+ const rows = await executor({ text: visibility.text, values: [...visibility.values] }).then(undefined, (cause) => {
4268
+ throw dependencyUnavailable({ origin, cause });
4269
+ });
4270
+ if (!hasMysqlGlobalCatalogVisibility({ rows }))
4271
+ throw dependencyUnavailable({ origin });
4272
+ }
4273
+ const rows = await executor({ text: query.text, values: [...query.values] }).then(undefined, (cause) => {
4274
+ throw dependencyUnavailable({ origin, cause });
4275
+ });
4276
+ const flags = [true, false, 0, 1, "0", "1"];
4277
+ for (const row of rows) {
4278
+ const { constraint_name: name, source_namespace: namespace, source_table: table, target_namespace: targetNamespace, target_table: targetTable, source_owned: source, target_owned: target } = row;
4279
+ if (typeof name !== "string" || name.length === 0 || typeof namespace !== "string" || namespace.length === 0 || typeof table !== "string" || table.length === 0 || typeof targetNamespace !== "string" || targetNamespace.length === 0 || typeof targetTable !== "string" || targetTable.length === 0 || !flags.includes(source) || !flags.includes(target) || Number(source) + Number(target) === 0)
4280
+ throw dependencyUnavailable({ origin });
4281
+ if (Number(source) !== Number(target))
4282
+ throw refusal({ reason: "module-external-dependency", moduleId: origin.moduleId, identity: { kind: "constraint", constraintType: "foreignKey", table: { namespace, name: table }, name } });
4283
+ }
4284
+ }
4102
4285
  async function assertLiveModuleOwnership(params) {
4103
4286
  const { executor, origin } = params;
4104
4287
  const namespace = moduleNamespace({ origin });
@@ -4108,6 +4291,7 @@ async function assertLiveModuleOwnership(params) {
4108
4291
  const before = new Set(identities({ state: origin.source.desiredState.from, dialect: origin.dialect, namespace }).map((identity) => sqlObjectKey6({ identity })));
4109
4292
  const owned = new Set(origin.owned.map((identity) => sqlObjectKey6({ identity })));
4110
4293
  const tables = new Set(origin.owned.flatMap((identity) => identity.kind === "table" ? [identity.name.name] : []));
4294
+ await assertCrossNamespaceModuleDependencies({ executor, origin, namespace, tables });
4111
4295
  for (const object of inventory) {
4112
4296
  const key = sqlObjectKey6({ identity: object.identity });
4113
4297
  if (params.resume !== true && owned.has(key) && !before.has(key))
@@ -4117,7 +4301,7 @@ async function assertLiveModuleOwnership(params) {
4117
4301
  if (object.inspectionUnavailable !== undefined && (owned.has(key) || ("table" in object.identity) && tables.has(object.identity.table.name)))
4118
4302
  throw refusal({ reason: "module-dependency-unavailable", moduleId: origin.moduleId, identity: object.identity });
4119
4303
  }
4120
- const physical = origin.dialect === "postgres" ? await introspectPhysicalPostgres({ executor }) : origin.dialect === "mysql" ? await introspectMysql({ executor }) : await introspectSqlite({ executor });
4304
+ const physical = origin.dialect === "postgres" ? await introspectPhysicalPostgres({ executor }) : origin.dialect === "mysql" ? await introspectMysql({ executor }) : params.sqliteRestorePending === true ? await introspectSqliteBeforeForeignKeyRestore({ executor }) : await introspectSqlite({ executor });
4121
4305
  for (const model of physical.models)
4122
4306
  for (const relation of model.relations) {
4123
4307
  const target = physical.models.find((candidate) => candidate.name === relation.targetModel);
@@ -4125,13 +4309,23 @@ async function assertLiveModuleOwnership(params) {
4125
4309
  throw refusal({ reason: "module-external-dependency", moduleId: origin.moduleId });
4126
4310
  }
4127
4311
  }
4312
+ async function assertApplicationModuleState(params) {
4313
+ for (const origin of params.origins) {
4314
+ await assertLiveModuleOwnership({ executor: params.executor, origin, resume: true, ...params.sqliteRestorePending === true ? { sqliteRestorePending: true } : {} });
4315
+ const state = origin.source.desiredState;
4316
+ const options = { executor: params.executor, dialect: origin.dialect, from: state.from, to: state.to, removals: state.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } };
4317
+ const report = params.sqliteRestorePending === true ? await verifySqliteTransitionBeforeRestore(options) : await verifyMigrationTransition(options);
4318
+ if (!report.inSync)
4319
+ throw new VibeError17({ code: "VIBE_MIGRATION", message: `Application SQL cannot change objects owned by module ${origin.moduleId}; use its reviewed module upgrade`, meta: { reason: "module-application-mutation", moduleId: origin.moduleId, report } });
4320
+ }
4321
+ }
4128
4322
 
4129
4323
  // packages/migrate/src/sql-statements.ts
4130
- import { VibeError as VibeError17 } from "@vibeorm/schema";
4324
+ import { VibeError as VibeError18 } from "@vibeorm/schema";
4131
4325
  var COMPOUND_BODY_HEADER = /^(?:\s|--[^\n]*\n|\/\*[\s\S]*?\*\/)*CREATE\s+(?:OR\s+REPLACE\s+)?(?:(?:TEMP|TEMPORARY)\s+)?(?:DEFINER\s*=\s*\S+\s+)?(?:TRIGGER|PROCEDURE|FUNCTION|EVENT)\b/i;
4132
4326
  var BLOCK_OPENERS = new Set(["BEGIN", "CASE", "IF", "LOOP", "WHILE", "REPEAT"]);
4133
4327
  function splitSqlStatements(params) {
4134
- const { sql: sql2, dialect } = params;
4328
+ const { sql, dialect } = params;
4135
4329
  const statements = [];
4136
4330
  let current = "";
4137
4331
  let hasContent = false;
@@ -4149,65 +4343,65 @@ function splitSqlStatements(params) {
4149
4343
  compound = false;
4150
4344
  afterEnd = false;
4151
4345
  };
4152
- while (i < sql2.length) {
4153
- const ch = sql2[i];
4154
- const next = sql2[i + 1];
4155
- if (ch === "-" && next === "-" && (dialect !== "mysql" || /\s/.test(sql2[i + 2] ?? `
4346
+ while (i < sql.length) {
4347
+ const ch = sql[i];
4348
+ const next = sql[i + 1];
4349
+ if (ch === "-" && next === "-" && (dialect !== "mysql" || /\s/.test(sql[i + 2] ?? `
4156
4350
  `)) || ch === "#" && dialect === "mysql") {
4157
- while (i < sql2.length && sql2[i] !== `
4351
+ while (i < sql.length && sql[i] !== `
4158
4352
  `) {
4159
- current += sql2[i];
4353
+ current += sql[i];
4160
4354
  i++;
4161
4355
  }
4162
4356
  continue;
4163
4357
  }
4164
4358
  if (ch === "/" && next === "*") {
4165
- current += sql2.slice(i, i + 2);
4359
+ current += sql.slice(i, i + 2);
4166
4360
  i += 2;
4167
4361
  let depth = 1;
4168
- while (i < sql2.length && depth > 0) {
4169
- if (sql2[i] === "/" && sql2[i + 1] === "*" && (dialect === undefined || dialect === "postgres")) {
4362
+ while (i < sql.length && depth > 0) {
4363
+ if (sql[i] === "/" && sql[i + 1] === "*" && (dialect === undefined || dialect === "postgres")) {
4170
4364
  depth++;
4171
4365
  current += "/*";
4172
4366
  i += 2;
4173
- } else if (sql2[i] === "*" && sql2[i + 1] === "/") {
4367
+ } else if (sql[i] === "*" && sql[i + 1] === "/") {
4174
4368
  depth--;
4175
4369
  current += "*/";
4176
4370
  i += 2;
4177
4371
  } else {
4178
- current += sql2[i];
4372
+ current += sql[i];
4179
4373
  i++;
4180
4374
  }
4181
4375
  }
4182
4376
  continue;
4183
4377
  }
4184
- const escapeString = (dialect === undefined || dialect === "postgres") && (ch === "e" || ch === "E") && next === "'" && !/[A-Za-z0-9_$]/.test(sql2[i - 1] ?? "");
4378
+ const escapeString = (dialect === undefined || dialect === "postgres") && (ch === "e" || ch === "E") && next === "'" && !/[A-Za-z0-9_$]/.test(sql[i - 1] ?? "");
4185
4379
  if (escapeString) {
4186
4380
  current += ch;
4187
4381
  i++;
4188
4382
  }
4189
- const quote = sql2[i];
4383
+ const quote = sql[i];
4190
4384
  if (escapeString || quote === "'" || quote === '"' || quote === "`" && dialect !== "postgres" || quote === "[" && (dialect === undefined || dialect === "sqlite")) {
4191
4385
  hasContent = true;
4192
4386
  const endQuote = quote === "[" ? "]" : quote;
4193
4387
  current += quote;
4194
4388
  i++;
4195
- while (i < sql2.length) {
4196
- const value = sql2[i];
4389
+ while (i < sql.length) {
4390
+ const value = sql[i];
4197
4391
  current += value;
4198
4392
  if (value === "\\" && (quote === "'" || quote === '"')) {
4199
4393
  if (escapeString) {
4200
- if (sql2[i + 1] !== undefined)
4201
- current += sql2[i + 1];
4394
+ if (sql[i + 1] !== undefined)
4395
+ current += sql[i + 1];
4202
4396
  i += 2;
4203
4397
  continue;
4204
4398
  }
4205
4399
  if (dialect === "mysql" || dialect === undefined) {
4206
- throw new VibeError17({ code: "VIBE_MIGRATION", message: "SQL string backslash escaping depends on the session SQL mode; use mode-independent quoting and pass the migration dialect", meta: { reason: "sql-mode-ambiguous", dialect } });
4400
+ throw new VibeError18({ code: "VIBE_MIGRATION", message: "SQL string backslash escaping depends on the session SQL mode; use mode-independent quoting and pass the migration dialect", meta: { reason: "sql-mode-ambiguous", dialect } });
4207
4401
  }
4208
4402
  }
4209
4403
  if (value === endQuote) {
4210
- if (quote !== "[" && sql2[i + 1] === endQuote) {
4404
+ if (quote !== "[" && sql[i + 1] === endQuote) {
4211
4405
  current += endQuote;
4212
4406
  i += 2;
4213
4407
  continue;
@@ -4219,14 +4413,14 @@ function splitSqlStatements(params) {
4219
4413
  }
4220
4414
  continue;
4221
4415
  }
4222
- if (ch === "$" && (dialect === undefined || dialect === "postgres") && !/[A-Za-z0-9_$]/.test(sql2[i - 1] ?? "")) {
4223
- const tagMatch = /^\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$/.exec(sql2.slice(i));
4416
+ if (ch === "$" && (dialect === undefined || dialect === "postgres") && !/[A-Za-z0-9_$]/.test(sql[i - 1] ?? "")) {
4417
+ const tagMatch = /^\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$/.exec(sql.slice(i));
4224
4418
  if (tagMatch !== null) {
4225
4419
  hasContent = true;
4226
4420
  const tag = tagMatch[0];
4227
- const end = sql2.indexOf(tag, i + tag.length);
4228
- const stop = end === -1 ? sql2.length : end + tag.length;
4229
- current += sql2.slice(i, stop);
4421
+ const end = sql.indexOf(tag, i + tag.length);
4422
+ const stop = end === -1 ? sql.length : end + tag.length;
4423
+ current += sql.slice(i, stop);
4230
4424
  i = stop;
4231
4425
  continue;
4232
4426
  }
@@ -4241,14 +4435,14 @@ function splitSqlStatements(params) {
4241
4435
  i++;
4242
4436
  continue;
4243
4437
  }
4244
- const word = /^[A-Za-z_][A-Za-z_0-9]*/.exec(sql2.slice(i))?.[0];
4438
+ const word = /^[A-Za-z_][A-Za-z_0-9]*/.exec(sql.slice(i))?.[0];
4245
4439
  if (word !== undefined) {
4246
4440
  hasContent = true;
4247
4441
  if (!compound && COMPOUND_BODY_HEADER.test(current + word))
4248
4442
  compound = true;
4249
4443
  if (compound) {
4250
4444
  const upper = word.toUpperCase();
4251
- const rest = sql2.slice(i + word.length);
4445
+ const rest = sql.slice(i + word.length);
4252
4446
  const opens = !afterEnd && (upper === "BEGIN" || blockDepth > 0 && BLOCK_OPENERS.has(upper) && !/^\s*\(/.test(rest) && !(upper === "IF" && /^\s+(?:NOT\s+)?EXISTS\b/i.test(rest)));
4253
4447
  afterEnd = upper === "END";
4254
4448
  if (opens)
@@ -4277,10 +4471,10 @@ function joinSqlStatements(params) {
4277
4471
 
4278
4472
  // packages/migrate/src/module-origin.ts
4279
4473
  import { createHash } from "crypto";
4280
- import { VibeError as VibeError18, isSqlObjectIdentity as isSqlObjectIdentity3, sqlObjectKey as sqlObjectKey7 } from "@vibeorm/schema";
4474
+ import { VibeError as VibeError19, isSqlObjectIdentity as isSqlObjectIdentity3, sqlObjectKey as sqlObjectKey7 } from "@vibeorm/schema";
4281
4475
  var MODULE_ORIGIN_METADATA = Object.freeze({ filename: "module-origin.json", version: 1 });
4282
4476
  function invalid2() {
4283
- return new VibeError18({ code: "VIBE_MIGRATION", message: "Module migration origin is malformed or differs from its immutable package artifact; restore the reviewed artifact", meta: { reason: "module-origin-invalid" } });
4477
+ return new VibeError19({ code: "VIBE_MIGRATION", message: "Module migration origin is malformed or differs from its immutable package artifact; restore the reviewed artifact", meta: { reason: "module-origin-invalid" } });
4284
4478
  }
4285
4479
  function record2(value) {
4286
4480
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -4344,7 +4538,7 @@ function assertMaterializedModuleMigration(params) {
4344
4538
  return;
4345
4539
  const restored = restoreModuleMigration({ migration, origin: migration.moduleOrigin });
4346
4540
  if (migration.desiredState === undefined || canonicalMigrationJson({ value: restored }) !== canonicalMigrationJson({ value: migration }))
4347
- throw new VibeError18({ code: "VIBE_MIGRATION", message: "Materialized module metadata differs from its immutable source", meta: { reason: "module-source-state-mismatch", moduleId: migration.moduleOrigin.moduleId } });
4541
+ throw new VibeError19({ code: "VIBE_MIGRATION", message: "Materialized module metadata differs from its immutable source", meta: { reason: "module-source-state-mismatch", moduleId: migration.moduleOrigin.moduleId } });
4348
4542
  }
4349
4543
  function restoreModuleMigration(params) {
4350
4544
  const { migration, origin } = params;
@@ -4353,7 +4547,7 @@ function restoreModuleMigration(params) {
4353
4547
  const actual = migration[key];
4354
4548
  if (actual === undefined)
4355
4549
  continue;
4356
- const normalized = (sql2) => sql2.flatMap((text) => splitSqlStatements({ sql: text, dialect: origin.dialect }));
4550
+ const normalized = (sql) => sql.flatMap((text) => splitSqlStatements({ sql: text, dialect: origin.dialect }));
4357
4551
  if (canonicalMigrationJson({ value: normalized(actual) }) !== canonicalMigrationJson({ value: normalized(origin.source[key] ?? []) }))
4358
4552
  throw invalid2();
4359
4553
  }
@@ -4367,13 +4561,13 @@ function restoreModuleMigration(params) {
4367
4561
  // packages/migrate/src/fs.ts
4368
4562
  import { readFile, readdir } from "fs/promises";
4369
4563
  import { join } from "path";
4370
- import { VibeError as VibeError31, assertValidSchemaIR as assertValidSchemaIR4 } from "@vibeorm/schema";
4564
+ import { VibeError as VibeError33, assertValidSchemaIR as assertValidSchemaIR4 } from "@vibeorm/schema";
4371
4565
 
4372
4566
  // packages/migrate/src/migration-checksum.ts
4373
4567
  import { createHash as createHash2 } from "crypto";
4374
4568
 
4375
4569
  // packages/migrate/src/execution.ts
4376
- import { VibeError as VibeError19 } from "@vibeorm/schema";
4570
+ import { VibeError as VibeError20 } from "@vibeorm/schema";
4377
4571
  var EXECUTION_SIDECAR_FILENAME = "execution.json";
4378
4572
  var EXECUTION_SIDECAR_VERSION = 1;
4379
4573
  function isDefaultExecution(params) {
@@ -4412,7 +4606,7 @@ ${lines.join(`
4412
4606
  `)}`;
4413
4607
  }
4414
4608
  function invalid3(params) {
4415
- return new VibeError19({
4609
+ return new VibeError20({
4416
4610
  code: "VIBE_MIGRATION",
4417
4611
  message: `invalid execution metadata for migration "${params.migration}": ${params.detail}`,
4418
4612
  meta: { reason: "execution-metadata-invalid", migration: params.migration }
@@ -4463,7 +4657,7 @@ function parseExecutionSidecar(params) {
4463
4657
  try {
4464
4658
  parsed = JSON.parse(params.text);
4465
4659
  } catch (error) {
4466
- throw new VibeError19({
4660
+ throw new VibeError20({
4467
4661
  code: "VIBE_MIGRATION",
4468
4662
  message: `invalid execution metadata for migration "${migration}": not valid JSON`,
4469
4663
  meta: { reason: "execution-metadata-invalid", migration },
@@ -4561,16 +4755,35 @@ function migrationChecksum(params) {
4561
4755
  -- vibeorm:down ${JSON.stringify(params.downSql ?? null)}${executionChecksumSuffix({ ...params.downExecution === undefined ? {} : { execution: params.downExecution } })}`)).digest("hex");
4562
4756
  }
4563
4757
 
4758
+ // packages/migrate/src/shadow-guard.ts
4759
+ import { VibeError as VibeError21 } from "@vibeorm/schema";
4760
+ import { getSqlDialect as getSqlDialect4, renderShadowOperation } from "@vibeorm/sql";
4761
+ var replayExecutors = new WeakSet;
4762
+ async function assertDatabaseNotShadow(params) {
4763
+ if (params.dialect === "sqlite" || replayExecutors.has(params.executor))
4764
+ return;
4765
+ const [query] = renderShadowOperation({ dialect: getSqlDialect4({ dialect: params.dialect }), operation: { kind: "markerExists" } });
4766
+ const rows = await params.executor({ text: query.text, values: [...query.values] });
4767
+ if (rows.length !== 0)
4768
+ throw new VibeError21({ code: "VIBE_MIGRATION", message: "This database is claimed as a disposable migration shadow. Application migrations must use the deployment target.", meta: { reason: "shadow-database-is-not-target" } });
4769
+ }
4770
+ function runShadowReplay(params) {
4771
+ replayExecutors.add(params.executor);
4772
+ return Promise.resolve().then(params.run).finally(() => {
4773
+ replayExecutors.delete(params.executor);
4774
+ });
4775
+ }
4776
+
4564
4777
  // packages/migrate/src/module-history.ts
4565
- import { VibeError as VibeError20, sqlObjectKey as sqlObjectKey8 } from "@vibeorm/schema";
4778
+ import { VibeError as VibeError22, sqlObjectKey as sqlObjectKey8 } from "@vibeorm/schema";
4566
4779
  function refusal2(params) {
4567
- return new VibeError20({ code: "VIBE_MIGRATION", message: `Module ${params.moduleId} history, ownership or predecessor state is inconsistent; restore or complete the reviewed upgrade first`, meta: params });
4780
+ return new VibeError22({ code: "VIBE_MIGRATION", message: `Module ${params.moduleId} history, ownership or predecessor state is inconsistent; restore or complete the reviewed upgrade first`, meta: params });
4568
4781
  }
4569
4782
  function moduleHistoryHeads(params) {
4570
4783
  const heads = new Map;
4571
4784
  const revisions = new Map;
4572
- for (const record3 of params.records.values()) {
4573
- const origin = record3.entry?.migration.moduleOrigin;
4785
+ for (const record of params.records.values()) {
4786
+ const origin = record.entry?.migration.moduleOrigin;
4574
4787
  if (origin === undefined)
4575
4788
  continue;
4576
4789
  const previous = heads.get(origin.moduleId);
@@ -4583,10 +4796,21 @@ function moduleHistoryHeads(params) {
4583
4796
  throw refusal2({ reason: "module-predecessor-state", moduleId: origin.moduleId });
4584
4797
  seen.add(origin.revision);
4585
4798
  revisions.set(origin.moduleId, seen);
4586
- heads.set(origin.moduleId, record3);
4799
+ heads.set(origin.moduleId, record);
4587
4800
  }
4588
4801
  return heads;
4589
4802
  }
4803
+ function applicationModuleOrigins(params) {
4804
+ if (params.migration.moduleOrigin !== undefined || params.migration.desiredState !== undefined)
4805
+ return [];
4806
+ const origins = [];
4807
+ for (const [moduleId, head] of moduleHistoryHeads(params)) {
4808
+ if (!head.entry.complete || head.row.error !== undefined || head.row.statementIndex !== head.entry.migration.sql.length)
4809
+ throw refusal2({ reason: "module-chain-incomplete", moduleId });
4810
+ origins.push(head.entry.migration.moduleOrigin);
4811
+ }
4812
+ return origins;
4813
+ }
4590
4814
  function preserves(params) {
4591
4815
  const tables = new Set(params.expected.schema.models.map((model) => model.dbName ?? model.name));
4592
4816
  const enums = new Set(params.expected.schema.enums.map((entry) => entry.dbName ?? entry.name));
@@ -4617,9 +4841,9 @@ function assertModuleUpgradeHistory(params) {
4617
4841
  owners.set(key, origin.moduleId);
4618
4842
  }
4619
4843
  };
4620
- for (const record3 of params.records.values())
4621
- if (record3.entry !== undefined)
4622
- register(record3.entry.migration);
4844
+ for (const record of params.records.values())
4845
+ if (record.entry !== undefined)
4846
+ register(record.entry.migration);
4623
4847
  for (const migration of params.migrations) {
4624
4848
  const stored = params.records.get(migration.name);
4625
4849
  const origin = migration.moduleOrigin;
@@ -4631,7 +4855,7 @@ function assertModuleUpgradeHistory(params) {
4631
4855
  if (origin === undefined) {
4632
4856
  for (const [moduleId, head] of heads) {
4633
4857
  if (migration.desiredState === undefined)
4634
- throw refusal2({ reason: "module-application-state-required", moduleId });
4858
+ continue;
4635
4859
  const expected = head.entry.migration.moduleOrigin.source.desiredState.to;
4636
4860
  for (const actual of [migration.desiredState.from, migration.desiredState.to, migration.desiredState.down ?? migration.desiredState.from])
4637
4861
  preserves({ actual, expected, moduleId });
@@ -4658,22 +4882,22 @@ function assertModuleUpgradeHistory(params) {
4658
4882
  }
4659
4883
 
4660
4884
  // packages/migrate/src/module-journal.ts
4661
- import { VibeError as VibeError22 } from "@vibeorm/schema";
4662
- import { getSqlDialect as getSqlDialect3, MODULE_JOURNAL_COLUMN, renderModuleJournal } from "@vibeorm/sql";
4885
+ import { VibeError as VibeError24 } from "@vibeorm/schema";
4886
+ import { getSqlDialect as getSqlDialect5, MODULE_JOURNAL_COLUMN, renderModuleJournal } from "@vibeorm/sql";
4663
4887
 
4664
4888
  // packages/migrate/src/journal-read.ts
4665
- import { VibeError as VibeError21 } from "@vibeorm/schema";
4889
+ import { VibeError as VibeError23 } from "@vibeorm/schema";
4666
4890
  var MISSING_TABLE_IDENTIFIERS = new Set(["42P01", "42S02", "ER_NO_SUCH_TABLE"]);
4667
4891
  function isMissingTable(params) {
4668
4892
  let current = params.cause;
4669
4893
  for (let depth = 0;depth < 6 && current !== null && typeof current === "object"; depth++) {
4670
- const record3 = current;
4894
+ const record = current;
4671
4895
  for (const key of ["code", "errno", "sqlState"]) {
4672
- const value = record3[key];
4896
+ const value = record[key];
4673
4897
  if (typeof value === "string" && MISSING_TABLE_IDENTIFIERS.has(value))
4674
4898
  return true;
4675
4899
  }
4676
- current = record3.cause;
4900
+ current = record.cause;
4677
4901
  }
4678
4902
  return false;
4679
4903
  }
@@ -4686,7 +4910,7 @@ async function readJournalRows(params) {
4686
4910
  if (presence.state === "missing")
4687
4911
  return;
4688
4912
  }
4689
- throw new VibeError21({ code: "VIBE_MIGRATION", message: "Cannot inspect migration history; check SELECT privileges", meta: { reason: "history-unavailable" }, cause });
4913
+ throw new VibeError23({ code: "VIBE_MIGRATION", message: "Cannot inspect migration history; check SELECT privileges", meta: { reason: "history-unavailable" }, cause });
4690
4914
  });
4691
4915
  if (rows === undefined)
4692
4916
  return;
@@ -4694,7 +4918,7 @@ async function readJournalRows(params) {
4694
4918
  for (const row of rows) {
4695
4919
  const index = row.statement_index;
4696
4920
  if (typeof row.name !== "string" || typeof row.checksum !== "string" || typeof index !== "number" && typeof index !== "string" || typeof index === "string" && !/^-?\d+$/.test(index) || !Number.isSafeInteger(Number(index)) || row.module_origin !== null && row.module_origin !== undefined && typeof row.module_origin !== "string" || row.error !== null && row.error !== undefined && typeof row.error !== "string" || result.has(row.name)) {
4697
- throw new VibeError21({ code: "VIBE_MIGRATION", message: "Malformed migration journal row", meta: { reason: "history-unavailable" } });
4921
+ throw new VibeError23({ code: "VIBE_MIGRATION", message: "Malformed migration journal row", meta: { reason: "history-unavailable" } });
4698
4922
  }
4699
4923
  result.set(row.name, { checksum: row.checksum, statementIndex: Number(index), ...typeof row.error === "string" ? { error: row.error } : {}, ...typeof row.module_origin === "string" ? { moduleEntry: row.module_origin } : {} });
4700
4924
  }
@@ -4703,7 +4927,7 @@ async function readJournalRows(params) {
4703
4927
 
4704
4928
  // packages/migrate/src/module-journal.ts
4705
4929
  function invalid4() {
4706
- return new VibeError22({ code: "VIBE_MIGRATION", message: "Module migration history is missing, altered or inconsistent; restore the reviewed history before using this module", meta: { reason: "module-history-invalid" } });
4930
+ return new VibeError24({ code: "VIBE_MIGRATION", message: "Module migration history is missing, altered or inconsistent; restore the reviewed history before using this module", meta: { reason: "module-history-invalid" } });
4707
4931
  }
4708
4932
  function parseModuleJournalEntry(params) {
4709
4933
  return parseMigrationMetadata({ text: params.text, failure: invalid4, parse: (value) => {
@@ -4719,7 +4943,7 @@ function parseModuleJournalEntry(params) {
4719
4943
  } });
4720
4944
  }
4721
4945
  async function readModuleJournal(params) {
4722
- const query = renderModuleJournal({ dialect: getSqlDialect3({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: { kind: "read" } });
4946
+ const query = renderModuleJournal({ dialect: getSqlDialect5({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: { kind: "read" } });
4723
4947
  const rows = await readJournalRows({ ...params, query });
4724
4948
  return new Map([...rows ?? []].map(([name, row]) => {
4725
4949
  const entry = row.moduleEntry === undefined ? undefined : parseModuleJournalEntry({ text: row.moduleEntry, name, checksum: row.checksum });
@@ -4729,14 +4953,14 @@ async function readModuleJournal(params) {
4729
4953
  }));
4730
4954
  }
4731
4955
  async function ensureModuleJournal(params) {
4732
- const dialect = getSqlDialect3({ dialect: params.dialect });
4956
+ const dialect = getSqlDialect5({ dialect: params.dialect });
4733
4957
  const columns = await params.executor(renderModuleJournal({ dialect, table: MIGRATIONS_TABLE_NAME, operation: { kind: "columns" } }));
4734
4958
  if (columns.some((row) => row.name === MODULE_JOURNAL_COLUMN))
4735
4959
  return;
4736
4960
  await params.executor(renderModuleJournal({ dialect, table: MIGRATIONS_TABLE_NAME, operation: { kind: "addColumn" } }));
4737
4961
  }
4738
4962
  async function insertModuleJournal(params) {
4739
- await params.executor(renderModuleJournal({ dialect: getSqlDialect3({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4963
+ await params.executor(renderModuleJournal({ dialect: getSqlDialect5({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4740
4964
  kind: "insert",
4741
4965
  name: params.migration.name,
4742
4966
  checksum: migrationChecksum(params.migration),
@@ -4745,7 +4969,7 @@ async function insertModuleJournal(params) {
4745
4969
  } }));
4746
4970
  }
4747
4971
  async function completeModuleJournal(params) {
4748
- await params.executor(renderModuleJournal({ dialect: getSqlDialect3({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4972
+ await params.executor(renderModuleJournal({ dialect: getSqlDialect5({ dialect: params.dialect }), table: MIGRATIONS_TABLE_NAME, operation: {
4749
4973
  kind: "complete",
4750
4974
  name: params.migration.name,
4751
4975
  entry: canonicalMigrationJson({ value: { version: 1, migration: params.migration, complete: true } })
@@ -4762,19 +4986,19 @@ function moduleRecordComplete(params) {
4762
4986
  }
4763
4987
 
4764
4988
  // packages/migrate/src/runner.ts
4765
- import { VibeError as VibeError30 } from "@vibeorm/schema";
4989
+ import { VibeError as VibeError32 } from "@vibeorm/schema";
4766
4990
  import {
4767
4991
  DIALECT_CAPABILITIES as DIALECT_CAPABILITIES3,
4768
- getSqlDialect as getSqlDialect5,
4992
+ getSqlDialect as getSqlDialect7,
4769
4993
  renderMigrationSessionRead,
4770
4994
  renderMigrationSessionRestore,
4771
4995
  renderMigrationSessionSet
4772
4996
  } from "@vibeorm/sql";
4773
4997
 
4774
4998
  // packages/migrate/src/recovery.ts
4775
- import { VibeError as VibeError23 } from "@vibeorm/schema";
4999
+ import { VibeError as VibeError25 } from "@vibeorm/schema";
4776
5000
  import {
4777
- getSqlDialect as getSqlDialect4,
5001
+ getSqlDialect as getSqlDialect6,
4778
5002
  renderColumnStateQuery,
4779
5003
  renderConstraintStateQuery,
4780
5004
  renderIndexStateQuery,
@@ -4788,7 +5012,7 @@ function constraintUnverifiable(params) {
4788
5012
  });
4789
5013
  }
4790
5014
  function conflict2(params) {
4791
- return new VibeError23({
5015
+ return new VibeError25({
4792
5016
  code: "VIBE_MIGRATION",
4793
5017
  message: params.message,
4794
5018
  meta: { reason: params.reason, ...params.meta }
@@ -4813,7 +5037,7 @@ function sameShape(params) {
4813
5037
  }
4814
5038
  async function establishOperationState(params) {
4815
5039
  const { executor, operation } = params;
4816
- const dialect = getSqlDialect4({ dialect: params.dialect });
5040
+ const dialect = getSqlDialect6({ dialect: params.dialect });
4817
5041
  const run = async (query) => executor({ text: query.text, values: [...query.values] });
4818
5042
  switch (operation.kind) {
4819
5043
  case "createIndexConcurrently": {
@@ -4893,10 +5117,10 @@ async function establishOperationState(params) {
4893
5117
 
4894
5118
  // packages/migrate/src/differ.ts
4895
5119
  import { isEnumType as isEnumType6, unsupportedCapability as unsupportedCapability6 } from "@vibeorm/schema";
4896
- import { VibeError as VibeError25 } from "@vibeorm/schema";
5120
+ import { VibeError as VibeError27 } from "@vibeorm/schema";
4897
5121
 
4898
5122
  // packages/migrate/src/renames.ts
4899
- import { VibeError as VibeError24 } from "@vibeorm/schema";
5123
+ import { VibeError as VibeError26 } from "@vibeorm/schema";
4900
5124
  function tableOf(model) {
4901
5125
  return model.dbName ?? model.name;
4902
5126
  }
@@ -4907,7 +5131,7 @@ function hasColumn(params) {
4907
5131
  return params.model.fields.some((field) => (field.dbName ?? field.name) === params.column);
4908
5132
  }
4909
5133
  function ambiguous(params) {
4910
- return new VibeError24({
5134
+ return new VibeError26({
4911
5135
  code: "VIBE_MIGRATION",
4912
5136
  message: `rename refused: ${params.detail}`,
4913
5137
  meta: { reason: "rename-ambiguous", ...params.meta }
@@ -5055,7 +5279,7 @@ function diffSchemas(params) {
5055
5279
  if (before?.definition === exclusion.definition)
5056
5280
  continue;
5057
5281
  if (before?.catalogDefinition)
5058
- throw new VibeError25({ code: "VIBE_MIGRATION", message: "Exclusion comparison requires normalized evidence", meta: { reason: "exclusion-inspection-unavailable", table, name: exclusion.name } });
5282
+ throw new VibeError27({ code: "VIBE_MIGRATION", message: "Exclusion comparison requires normalized evidence", meta: { reason: "exclusion-inspection-unavailable", table, name: exclusion.name } });
5059
5283
  if (before !== undefined)
5060
5284
  buckets.dropExclusion.push({ kind: "dropExclusion", table, exclusion: before, destructive: false });
5061
5285
  buckets.addExclusion.push({ kind: "addExclusion", table, exclusion, destructive: false });
@@ -5267,7 +5491,7 @@ function diffOneTable(params) {
5267
5491
  changes.push("collation");
5268
5492
  if (changes.length === 0)
5269
5493
  continue;
5270
- if (changes.includes("type") && [...previous.checks].some(([name2, expression]) => current.checks.get(name2) === expression)) {
5494
+ if (changes.includes("type") && [...previous.checks].some(([name, expression]) => current.checks.get(name) === expression)) {
5271
5495
  throw unsupportedCapability6({ dialect, feature: "alterColumnWithRetainedCheck", hint: "CHECK dependencies and type compatibility are not proven; use a reviewed migration that replaces and revalidates the affected constraints" });
5272
5496
  }
5273
5497
  const storageChange = isEnumStringTransition({ from: before.field, to: column.field });
@@ -5331,7 +5555,7 @@ function diffOneTable(params) {
5331
5555
  if (before === expression)
5332
5556
  continue;
5333
5557
  if (before !== undefined && previous.model.checks?.some((check) => check.name === name && check.catalogExpression === true))
5334
- throw new VibeError25({ code: "VIBE_MIGRATION", message: "Unequal catalog CHECK text requires normalized evidence or explicit replacement through the live planner", meta: { reason: "check-inspection-unavailable", table, name } });
5558
+ throw new VibeError27({ code: "VIBE_MIGRATION", message: "Unequal catalog CHECK text requires normalized evidence or explicit replacement through the live planner", meta: { reason: "check-inspection-unavailable", table, name } });
5335
5559
  if (before !== undefined)
5336
5560
  buckets.dropCheck.push({ kind: "dropCheck", table, name, destructive: false });
5337
5561
  buckets.addCheck.push({ kind: "addCheck", table, name, expression, destructive: false });
@@ -5410,12 +5634,12 @@ function diffOneTable(params) {
5410
5634
  }
5411
5635
 
5412
5636
  // packages/migrate/src/ddl/render.ts
5413
- import { VibeError as VibeError29, sqlObjectKey as sqlObjectKey9 } from "@vibeorm/schema";
5637
+ import { VibeError as VibeError31, sqlObjectKey as sqlObjectKey9 } from "@vibeorm/schema";
5414
5638
 
5415
5639
  // packages/migrate/src/ddl/postgres.ts
5416
5640
  import { renderExclusionSetup } from "@vibeorm/sql";
5417
- import { VibeError as VibeError26, isEnumType as isEnumType7 } from "@vibeorm/schema";
5418
- import { postgresDialect as postgresDialect7, renderRlsPolicyPath } from "@vibeorm/sql";
5641
+ import { VibeError as VibeError28, isEnumType as isEnumType7 } from "@vibeorm/schema";
5642
+ import { postgresDialect as postgresDialect8, renderRlsPolicyPath } from "@vibeorm/sql";
5419
5643
  function renderPostgresSteps(params) {
5420
5644
  refuseSameTransactionEnumUse({ steps: params.steps });
5421
5645
  return params.steps.flatMap((step) => renderStep({ step }));
@@ -5449,7 +5673,7 @@ function refuseSameTransactionEnumUse(params) {
5449
5673
  const found = use(field);
5450
5674
  if (found === undefined)
5451
5675
  continue;
5452
- throw new VibeError26({
5676
+ throw new VibeError28({
5453
5677
  code: "VIBE_MIGRATION",
5454
5678
  message: `enum value "${found.value}" is added to "${found.enumName}" and used as a default on "${step.table}"."${field.dbName ?? field.name}" in the same migration \u2014 PostgreSQL cannot use an enum member before the transaction that added it commits. Split this into two migrations: the first containing only the ALTER TYPE ... ADD VALUE, the second the column change`,
5455
5679
  meta: { enum: found.enumName, value: found.value, table: step.table, column: field.dbName ?? field.name, rule: "enum-value-used-in-adding-transaction" }
@@ -5461,7 +5685,7 @@ function renderStep(params) {
5461
5685
  const { step } = params;
5462
5686
  switch (step.kind) {
5463
5687
  case "addExclusion":
5464
- return [...renderExclusionSetup({ dialect: postgresDialect7, exclusion: step.exclusion }), `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.exclusion.name)} ${step.exclusion.definition};`];
5688
+ return [...renderExclusionSetup({ dialect: postgresDialect8, exclusion: step.exclusion }), `ALTER TABLE ${publicName(step.table)} ADD CONSTRAINT ${q2(step.exclusion.name)} ${step.exclusion.definition};`];
5465
5689
  case "dropExclusion":
5466
5690
  return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.exclusion.name)};`];
5467
5691
  case "enableRls":
@@ -5470,7 +5694,7 @@ function renderStep(params) {
5470
5694
  case "noForceRls":
5471
5695
  case "createPolicy":
5472
5696
  case "dropPolicy":
5473
- return step.kind === "createPolicy" ? [renderRlsPolicyPath({ dialect: postgresDialect7, stage: "save" }).text, renderRlsPolicyPath({ dialect: postgresDialect7, stage: "empty" }).text, ...renderRlsStep({ step, dialect: "postgres" }), renderRlsPolicyPath({ dialect: postgresDialect7, stage: "restore" }).text] : renderRlsStep({ step, dialect: "postgres" });
5697
+ return step.kind === "createPolicy" ? [renderRlsPolicyPath({ dialect: postgresDialect8, stage: "save" }).text, renderRlsPolicyPath({ dialect: postgresDialect8, stage: "empty" }).text, ...renderRlsStep({ step, dialect: "postgres" }), renderRlsPolicyPath({ dialect: postgresDialect8, stage: "restore" }).text] : renderRlsStep({ step, dialect: "postgres" });
5474
5698
  case "createEnum": {
5475
5699
  const name = step.enumDef.dbName ?? step.enumDef.name;
5476
5700
  const values = step.enumDef.values.map((value) => quotePgString({ value })).join(", ");
@@ -5520,7 +5744,7 @@ ${lines.join(`,
5520
5744
  case "dropIndex":
5521
5745
  if (step.constraintName !== undefined) {
5522
5746
  if (step.table === undefined)
5523
- throw new VibeError26({ code: "VIBE_MIGRATION", message: "Constraint-backed index removal requires its owning table" });
5747
+ throw new VibeError28({ code: "VIBE_MIGRATION", message: "Constraint-backed index removal requires its owning table" });
5524
5748
  return [`ALTER TABLE ${publicName(step.table)} DROP CONSTRAINT ${q2(step.constraintName)};`];
5525
5749
  }
5526
5750
  return [`DROP INDEX ${publicName(step.name)};`];
@@ -5584,7 +5808,7 @@ function columnDefSql(params) {
5584
5808
  const { field } = params;
5585
5809
  const name = q2(field.dbName ?? field.name);
5586
5810
  if (field.default?.kind === "autoincrement" && !isIdentityColumn({ field })) {
5587
- throw new VibeError26({
5811
+ throw new VibeError28({
5588
5812
  code: "VIBE_MIGRATION",
5589
5813
  message: `autoincrement default on "${field.name}" requires a non-list Int or BigInt column`,
5590
5814
  meta: { field: field.name }
@@ -5620,7 +5844,7 @@ function renderAlterColumn(params) {
5620
5844
  }
5621
5845
  if (step.changes.includes("default") || droppedDefault) {
5622
5846
  if (step.to.default?.kind === "autoincrement") {
5623
- throw new VibeError26({
5847
+ throw new VibeError28({
5624
5848
  code: "VIBE_MIGRATION",
5625
5849
  message: `cannot add autoincrement to existing column "${step.table}"."${step.column}" \u2014 drop and recreate the column instead`,
5626
5850
  meta: { table: step.table, column: step.column }
@@ -5635,11 +5859,11 @@ function publicName(name) {
5635
5859
  return `${q2("public")}.${q2(name)}`;
5636
5860
  }
5637
5861
  function q2(name) {
5638
- return postgresDialect7.quoteIdent({ name });
5862
+ return postgresDialect8.quoteIdent({ name });
5639
5863
  }
5640
5864
 
5641
5865
  // packages/migrate/src/ddl/sqlite.ts
5642
- import { VibeError as VibeError27, isEnumType as isEnumType8, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
5866
+ import { VibeError as VibeError29, isEnumType as isEnumType8, unsupportedCapability as unsupportedCapability7 } from "@vibeorm/schema";
5643
5867
  import { sqliteDialect as sqliteDialect3 } from "@vibeorm/sql";
5644
5868
 
5645
5869
  // packages/migrate/src/ddl/drop-order.ts
@@ -5779,7 +6003,7 @@ function renderSqliteSteps(params) {
5779
6003
  continue;
5780
6004
  const awaitsNewParent = [...toNorm?.tables.get(table)?.fks.values() ?? []].some((fk) => createdTables.has(fk.refTable));
5781
6005
  if (awaitsNewParent) {
5782
- throw new VibeError27({
6006
+ throw new VibeError29({
5783
6007
  code: "VIBE_MIGRATION",
5784
6008
  message: `cannot order this sqlite migration safely: rebuilding "${table}" must happen BEFORE the dropped table(s) it references (${[
5785
6009
  ...droppedTables
@@ -5808,7 +6032,7 @@ function renderSqliteSteps(params) {
5808
6032
  switch (step.kind) {
5809
6033
  case "addExclusion":
5810
6034
  case "dropExclusion":
5811
- throw new VibeError27({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
6035
+ throw new VibeError29({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
5812
6036
  case "createEnum":
5813
6037
  case "dropEnum":
5814
6038
  case "addEnumValue":
@@ -5893,7 +6117,7 @@ function renderSqliteSteps(params) {
5893
6117
  case "renameColumn": {
5894
6118
  const renamed = step.kind === "renameTable" ? step.from : step.table;
5895
6119
  if (rebuildSet.has(renamed) || step.kind === "renameTable" && rebuildSet.has(step.to)) {
5896
- throw new VibeError27({
6120
+ throw new VibeError29({
5897
6121
  code: "VIBE_MIGRATION",
5898
6122
  message: `sqlite cannot rename "${renamed}" in the same migration that rebuilds it \u2014 the table-rebuild recipe is written against a single table name. Split the rename and the column/constraint change into two migrations`,
5899
6123
  meta: { reason: "rename-ambiguous", table: renamed, dialect: "sqlite" }
@@ -5947,7 +6171,7 @@ function classifyRebuilds(params) {
5947
6171
  switch (step.kind) {
5948
6172
  case "addExclusion":
5949
6173
  case "dropExclusion":
5950
- throw new VibeError27({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
6174
+ throw new VibeError29({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "sqlite", feature: "exclusionConstraints" } });
5951
6175
  case "alterColumn":
5952
6176
  case "dropForeignKey":
5953
6177
  case "addPrimaryKey":
@@ -6008,7 +6232,7 @@ function renderTableRebuild(params) {
6008
6232
  const source = from.tables.get(table);
6009
6233
  const target = to.tables.get(table);
6010
6234
  if (source === undefined || target === undefined) {
6011
- throw new VibeError27({
6235
+ throw new VibeError29({
6012
6236
  code: "VIBE_MIGRATION",
6013
6237
  message: `cannot rebuild "${table}" \u2014 the table is missing from the ${source === undefined ? "from" : "to"} schema`,
6014
6238
  meta: { table }
@@ -6143,7 +6367,7 @@ function columnDefSql2(params) {
6143
6367
  const { field, constraintTable, enums, inlinePkAutoincrement } = params;
6144
6368
  const name = field.dbName ?? field.name;
6145
6369
  if (field.default?.kind === "autoincrement" && !inlinePkAutoincrement) {
6146
- throw new VibeError27({
6370
+ throw new VibeError29({
6147
6371
  code: "VIBE_MIGRATION",
6148
6372
  message: `autoincrement on sqlite requires "${field.name}" to be the single-column Int or BigInt primary key`,
6149
6373
  meta: { field: field.name }
@@ -6162,7 +6386,7 @@ function columnDefSql2(params) {
6162
6386
  const enumName = field.type.enum;
6163
6387
  const values = resolveEnumValues({ name: enumName, enums });
6164
6388
  if (values === undefined) {
6165
- throw new VibeError27({
6389
+ throw new VibeError29({
6166
6390
  code: "VIBE_MIGRATION",
6167
6391
  message: `enum "${enumName}" on column "${field.name}" is not declared in the schema \u2014 sqlite rendering needs the target schema's enums for the CHECK constraint`,
6168
6392
  meta: { field: field.name, enum: enumName }
@@ -6197,7 +6421,7 @@ function requireSchemas(params) {
6197
6421
  const { step, fromNorm, toNorm } = params;
6198
6422
  if (fromNorm !== undefined && toNorm !== undefined)
6199
6423
  return;
6200
- throw new VibeError27({
6424
+ throw new VibeError29({
6201
6425
  code: "VIBE_MIGRATION",
6202
6426
  message: `sqlite step "${describeStep({ step })}" requires a table rebuild \u2014 renderSteps needs the { from, to } schemas to construct it`,
6203
6427
  meta: { step: step.kind }
@@ -6208,7 +6432,7 @@ function q3(name) {
6208
6432
  }
6209
6433
 
6210
6434
  // packages/migrate/src/ddl/mysql.ts
6211
- import { VibeError as VibeError28, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
6435
+ import { VibeError as VibeError30, unsupportedCapability as unsupportedCapability8 } from "@vibeorm/schema";
6212
6436
  import { mysqlDialect as mysqlDialect3 } from "@vibeorm/sql";
6213
6437
  function renderMysqlSteps(params) {
6214
6438
  for (const step of params.steps) {
@@ -6350,12 +6574,12 @@ ${lines.join(`,
6350
6574
  ];
6351
6575
  case "addExclusion":
6352
6576
  case "dropExclusion":
6353
- throw new VibeError28({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "mysql", feature: "exclusionConstraints" } });
6577
+ throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: "Exclusion constraints require PostgreSQL", meta: { dialect: "mysql", feature: "exclusionConstraints" } });
6354
6578
  case "dropCheck":
6355
6579
  return [`ALTER TABLE ${q4(step.table)} DROP CHECK ${q4(step.name)};`];
6356
6580
  case "dropIndex": {
6357
6581
  if (step.table === undefined) {
6358
- throw new VibeError28({
6582
+ throw new VibeError30({
6359
6583
  code: "VIBE_MIGRATION",
6360
6584
  message: `dropIndex "${step.name}" carries no table \u2014 mysql's DROP INDEX requires one`,
6361
6585
  meta: { index: step.name }
@@ -6411,7 +6635,7 @@ function columnDefSql3(params) {
6411
6635
  const name = q4(field.dbName ?? field.name);
6412
6636
  const autoincrement = field.default?.kind === "autoincrement";
6413
6637
  if (autoincrement && field.type !== "Int" && field.type !== "BigInt") {
6414
- throw new VibeError28({
6638
+ throw new VibeError30({
6415
6639
  code: "VIBE_MIGRATION",
6416
6640
  message: `autoincrement default on "${field.name}" requires a non-list Int or BigInt column`,
6417
6641
  meta: { field: field.name }
@@ -6433,7 +6657,7 @@ function renderAlterColumn2(params) {
6433
6657
  const { step, enums } = params;
6434
6658
  assertEnumStringTransition({ from: step.from, to: step.to, dialect: "mysql", table: step.table, column: step.column });
6435
6659
  if (step.to.default?.kind === "autoincrement" && step.from.default?.kind !== "autoincrement") {
6436
- throw new VibeError28({
6660
+ throw new VibeError30({
6437
6661
  code: "VIBE_MIGRATION",
6438
6662
  message: `cannot add autoincrement to existing column "${step.table}"."${step.column}" \u2014 drop and recreate the column instead`,
6439
6663
  meta: { table: step.table, column: step.column }
@@ -6465,32 +6689,32 @@ function declaredSqlitePreservation(params) {
6465
6689
  let to = params.to;
6466
6690
  if (params.from === undefined || to === undefined || (params.from.migrationObjects?.length ?? 0) === 0)
6467
6691
  return { to, restore, columns };
6468
- const invalid5 = sqliteInvalidatedTables({ steps: params.steps, from: params.from });
6692
+ const invalid = sqliteInvalidatedTables({ steps: params.steps, from: params.from });
6469
6693
  const retained = new Set((to.migrationObjects ?? []).map((object) => sqlObjectKey9({ identity: object.identity })));
6470
6694
  for (const object of params.from.migrationObjects ?? []) {
6471
6695
  const identity = object.identity;
6472
- if (!("table" in identity) || identity.table.namespace !== "main" || !invalid5.rebuilt.has(identity.table.name) || !retained.has(sqlObjectKey9({ identity })))
6696
+ if (!("table" in identity) || identity.table.namespace !== "main" || !invalid.rebuilt.has(identity.table.name) || !retained.has(sqlObjectKey9({ identity })))
6473
6697
  continue;
6474
6698
  const facts = object.expected?.facts;
6475
6699
  if (facts === undefined)
6476
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "SQLite rebuild requires independently declared preservation definitions", meta: { reason: "sqlite-preservation-unavailable", identity } });
6700
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "SQLite rebuild requires independently declared preservation definitions", meta: { reason: "sqlite-preservation-unavailable", identity } });
6477
6701
  if (identity.kind === "trigger" || identity.kind === "index") {
6478
6702
  if (identity.kind === "index" && to.models.some((model) => (model.dbName ?? model.name) === identity.table.name && model.indexes.some((index) => index.name === identity.name)))
6479
6703
  continue;
6480
6704
  if (typeof facts.definition !== "string")
6481
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "Missing SQLite restoration SQL", meta: { reason: "sqlite-preservation-unavailable", identity } });
6705
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "Missing SQLite restoration SQL", meta: { reason: "sqlite-preservation-unavailable", identity } });
6482
6706
  const statements = restore.get(identity.table.name) ?? [];
6483
6707
  statements.push(facts.definition);
6484
6708
  restore.set(identity.table.name, statements);
6485
6709
  } else if (identity.kind === "column" || identity.kind === "generatedColumn") {
6486
6710
  if (typeof facts.columnDefinition !== "string")
6487
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "Missing SQLite column clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6711
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "Missing SQLite column clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6488
6712
  const fields = columns.get(identity.table.name) ?? new Map;
6489
6713
  fields.set(identity.column, { sql: facts.columnDefinition, generated: Number(facts.generated) > 1 });
6490
6714
  columns.set(identity.table.name, fields);
6491
6715
  } else if (identity.kind === "columnDefault") {
6492
6716
  if (facts.definition !== null && typeof facts.definition !== "string")
6493
- throw new VibeError29({ code: "VIBE_MIGRATION", message: "Missing SQLite default clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6717
+ throw new VibeError31({ code: "VIBE_MIGRATION", message: "Missing SQLite default clause", meta: { reason: "sqlite-preservation-unavailable", identity } });
6494
6718
  const expression = facts.definition;
6495
6719
  to = { ...to, models: to.models.map((model) => (model.dbName ?? model.name) !== identity.table.name ? model : { ...model, fields: model.fields.map((field) => {
6496
6720
  if ((field.dbName ?? field.name) !== identity.column)
@@ -6634,19 +6858,19 @@ function planMissingArtifacts(params) {
6634
6858
  }
6635
6859
  async function probeInstalledExtensionState(params) {
6636
6860
  const { executor, dialect, artifacts } = params;
6637
- const state2 = {};
6861
+ const state = {};
6638
6862
  if (dialect === "postgres" && artifacts.some((artifact) => artifact.owns.kind === "postgresExtension")) {
6639
6863
  const rows = await executor({ text: "SELECT extname FROM pg_extension" });
6640
- state2.pgExtensions = new Set(rows.map((row) => String(row["extname"])));
6864
+ state.pgExtensions = new Set(rows.map((row) => String(row["extname"])));
6641
6865
  }
6642
6866
  if (dialect === "sqlite" && artifacts.some((artifact) => artifact.owns.kind === "trigger")) {
6643
6867
  const rows = await executor({
6644
6868
  text: "SELECT name FROM sqlite_master WHERE type = 'trigger'",
6645
6869
  values: []
6646
6870
  });
6647
- state2.triggers = new Set(rows.map((row) => String(row["name"])));
6871
+ state.triggers = new Set(rows.map((row) => String(row["name"])));
6648
6872
  }
6649
- return state2;
6873
+ return state;
6650
6874
  }
6651
6875
  function artifactCreateSql(params) {
6652
6876
  return params.artifacts.flatMap((artifact) => [...artifact.create]);
@@ -6659,29 +6883,29 @@ function migrationRlsSecurityChanges(params) {
6659
6883
  return securityChangesOf({ steps: withRlsSteps({ from: params.down ? source.to : source.from, to: params.down ? source.from : source.to, steps: [] }) });
6660
6884
  }
6661
6885
  function containsNativeRlsSql(params) {
6662
- const { sql: sql2, dialect } = params;
6886
+ const { sql, dialect } = params;
6663
6887
  const tokens = [];
6664
6888
  let i = 0;
6665
- while (i < sql2.length) {
6666
- const ch = sql2[i];
6889
+ while (i < sql.length) {
6890
+ const ch = sql[i];
6667
6891
  if (/\s/.test(ch)) {
6668
6892
  i++;
6669
6893
  continue;
6670
6894
  }
6671
- if (sql2.startsWith("--", i) || dialect === "mysql" && ch === "#") {
6672
- const end = sql2.indexOf(`
6895
+ if (sql.startsWith("--", i) || dialect === "mysql" && ch === "#") {
6896
+ const end = sql.indexOf(`
6673
6897
  `, i);
6674
- i = end === -1 ? sql2.length : end + 1;
6898
+ i = end === -1 ? sql.length : end + 1;
6675
6899
  continue;
6676
6900
  }
6677
- if (sql2.startsWith("/*", i)) {
6901
+ if (sql.startsWith("/*", i)) {
6678
6902
  let depth = 1;
6679
6903
  i += 2;
6680
- while (i < sql2.length && depth > 0) {
6681
- if (sql2.startsWith("/*", i)) {
6904
+ while (i < sql.length && depth > 0) {
6905
+ if (sql.startsWith("/*", i)) {
6682
6906
  depth++;
6683
6907
  i += 2;
6684
- } else if (sql2.startsWith("*/", i)) {
6908
+ } else if (sql.startsWith("*/", i)) {
6685
6909
  depth--;
6686
6910
  i += 2;
6687
6911
  } else
@@ -6691,15 +6915,15 @@ function containsNativeRlsSql(params) {
6691
6915
  }
6692
6916
  if (ch === "'" || ch === '"' || ch === "`" || dialect === "sqlite" && ch === "[") {
6693
6917
  const endQuote = ch === "[" ? "]" : ch;
6694
- const backslash = dialect === "mysql" || ch === "'" && /(?:^|[^\w$])[eE]$/.test(sql2.slice(0, i));
6918
+ const backslash = dialect === "mysql" || ch === "'" && /(?:^|[^\w$])[eE]$/.test(sql.slice(0, i));
6695
6919
  i++;
6696
- while (i < sql2.length) {
6697
- if (backslash && sql2[i] === "\\") {
6920
+ while (i < sql.length) {
6921
+ if (backslash && sql[i] === "\\") {
6698
6922
  i += 2;
6699
6923
  continue;
6700
6924
  }
6701
- if (sql2[i] === endQuote) {
6702
- if (sql2[i + 1] === endQuote) {
6925
+ if (sql[i] === endQuote) {
6926
+ if (sql[i + 1] === endQuote) {
6703
6927
  i += 2;
6704
6928
  continue;
6705
6929
  }
@@ -6712,15 +6936,15 @@ function containsNativeRlsSql(params) {
6712
6936
  continue;
6713
6937
  }
6714
6938
  if (ch === "$") {
6715
- const tag = /^(?:\$\$|\$[A-Za-z_][A-Za-z_0-9]*\$)/.exec(sql2.slice(i))?.[0];
6939
+ const tag = /^(?:\$\$|\$[A-Za-z_][A-Za-z_0-9]*\$)/.exec(sql.slice(i))?.[0];
6716
6940
  if (tag !== undefined) {
6717
- const end = sql2.indexOf(tag, i + tag.length);
6718
- i = end === -1 ? sql2.length : end + tag.length;
6941
+ const end = sql.indexOf(tag, i + tag.length);
6942
+ i = end === -1 ? sql.length : end + tag.length;
6719
6943
  tokens.push("@");
6720
6944
  continue;
6721
6945
  }
6722
6946
  }
6723
- const word = /^[A-Za-z_][A-Za-z_0-9$]*/.exec(sql2.slice(i))?.[0];
6947
+ const word = /^[A-Za-z_][A-Za-z_0-9$]*/.exec(sql.slice(i))?.[0];
6724
6948
  tokens.push(word === undefined ? ch : word.toUpperCase());
6725
6949
  i += word?.length ?? 1;
6726
6950
  }
@@ -6730,14 +6954,14 @@ function containsNativeRlsSql(params) {
6730
6954
  });
6731
6955
  }
6732
6956
  function assertNativeMigrationMetadata(params) {
6733
- const native = params.migration.rls !== undefined || params.sql.some((sql2) => containsNativeRlsSql({ sql: sql2, dialect: params.dialect }));
6957
+ const native = params.migration.rls !== undefined || params.sql.some((sql) => containsNativeRlsSql({ sql, dialect: params.dialect }));
6734
6958
  if (!native)
6735
6959
  return;
6736
6960
  if (!DIALECT_CAPABILITIES3[params.dialect].nativeRowLevelSecurity) {
6737
- throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Native RLS migrations are unsupported on ${params.dialect}`, meta: { feature: "nativeRowLevelSecurity", dialect: params.dialect } });
6961
+ throw new VibeError32({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Native RLS migrations are unsupported on ${params.dialect}`, meta: { feature: "nativeRowLevelSecurity", dialect: params.dialect } });
6738
6962
  }
6739
6963
  if (params.migration.rls === undefined) {
6740
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Native RLS migration files require trusted rls.from/rls.to schema metadata. SQL alone cannot prove policy ownership or drift; regenerate with preserved security metadata.", meta: { reason: "rls-migration-metadata-required", migration: params.migration.name } });
6964
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Native RLS migration files require trusted rls.from/rls.to schema metadata. SQL alone cannot prove policy ownership or drift; regenerate with preserved security metadata.", meta: { reason: "rls-migration-metadata-required", migration: params.migration.name } });
6741
6965
  }
6742
6966
  }
6743
6967
  var PG_ADVISORY_LOCK_KEY = 1447645253;
@@ -6779,14 +7003,14 @@ function checksumOf(params) {
6779
7003
  return migrationChecksum(migration);
6780
7004
  }
6781
7005
  async function assertForwardStart(params) {
6782
- const state2 = params.migration.desiredState;
6783
- if (state2 === undefined)
7006
+ const state = params.migration.desiredState;
7007
+ if (state === undefined)
6784
7008
  return;
6785
- const report = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state2.from, ...params.probe === undefined ? {} : { probe: params.probe } });
7009
+ const report = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state.from, ...params.probe === undefined ? {} : { probe: params.probe } });
6786
7010
  if (report.inSync)
6787
7011
  return;
6788
- if (state2.down !== undefined) {
6789
- const restored = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state2.down, ...params.probe === undefined ? {} : { probe: params.probe } });
7012
+ if (state.down !== undefined) {
7013
+ const restored = await verifyMigrationState({ executor: params.executor, dialect: params.dialect, expected: state.down, ...params.probe === undefined ? {} : { probe: params.probe } });
6790
7014
  if (restored.inSync)
6791
7015
  return;
6792
7016
  }
@@ -6806,7 +7030,7 @@ function generateMigration(params) {
6806
7030
  const steps = diffSchemas({ from: strippedFrom, to, dialect, ...params.renames === undefined ? {} : { renames: params.renames } });
6807
7031
  const coreSql = renderSteps({ steps, dialect, from: dialect === "sqlite" ? from : strippedFrom, to: dialect === "sqlite" ? sqlitePreservedSchema({ from, to, objects: [...from.migrationObjects ?? [], ...to.migrationObjects ?? []] }) : to });
6808
7032
  const missing = planMissingArtifacts({ introspected: from, artifacts: allArtifacts });
6809
- const sql2 = [
7033
+ const sql = [
6810
7034
  ...artifactCreateSql({
6811
7035
  artifacts: missing.filter((artifact) => artifact.owns.kind === "postgresExtension")
6812
7036
  }),
@@ -6816,18 +7040,18 @@ function generateMigration(params) {
6816
7040
  }),
6817
7041
  ...orderedMigrationObjects({ objects: to.migrationObjects ?? [] }).flatMap((object) => {
6818
7042
  if (object.dialect !== dialect)
6819
- throw new VibeError30({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Migration object ${object.id} requires ${object.dialect}` });
7043
+ throw new VibeError32({ code: "VIBE_UNSUPPORTED_CAPABILITY", message: `Migration object ${object.id} requires ${object.dialect}` });
6820
7044
  const previous = (params.desiredState?.from.schema.migrationObjects ?? from.migrationObjects)?.find((entry) => entry.id === object.id);
6821
7045
  if (previous === undefined)
6822
7046
  return [...object.create];
6823
7047
  if (JSON.stringify(previous) !== JSON.stringify(object))
6824
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration-owned object ${object.id} changed; supply a reviewed forward SQL migration`, meta: { reason: "migration-object-replacement-required", id: object.id } });
7048
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration-owned object ${object.id} changed; supply a reviewed forward SQL migration`, meta: { reason: "migration-object-replacement-required", shadowReusable: true, id: object.id } });
6825
7049
  return [];
6826
7050
  })
6827
7051
  ];
6828
7052
  return {
6829
7053
  name,
6830
- sql: sql2,
7054
+ sql,
6831
7055
  destructive: steps.some((step) => step.destructive),
6832
7056
  ...securityChangesOf({ steps }).length === 0 ? {} : { securityChanges: securityChangesOf({ steps }) },
6833
7057
  ...from.rls === undefined && to.rls === undefined ? {} : { rls: { from, to } },
@@ -6835,6 +7059,25 @@ function generateMigration(params) {
6835
7059
  desiredState: params.desiredState ?? { version: 1, dialect, from: createDesiredState({ schema: from, dialect }), to: createDesiredState({ schema: to, dialect }) }
6836
7060
  };
6837
7061
  }
7062
+ async function withMigrationLock(params) {
7063
+ const runLocked = async (executor) => {
7064
+ await acquireLock({ executor, dialect: params.dialect });
7065
+ return Promise.resolve().then(async () => {
7066
+ await assertDatabaseNotShadow({ executor, dialect: params.dialect });
7067
+ return params.run(executor);
7068
+ }).then(async (value) => {
7069
+ await releaseLock({ executor, dialect: params.dialect });
7070
+ return value;
7071
+ }, (cause) => releaseLock({ executor, dialect: params.dialect }).then(() => {
7072
+ throw cause;
7073
+ }, (cleanupCause) => {
7074
+ if (cause instanceof VibeError32)
7075
+ throw new VibeError32({ code: cause.code, message: cause.message, meta: { ...cause.meta, cleanupCause }, cause });
7076
+ throw cause;
7077
+ }));
7078
+ };
7079
+ return params.executor.withSession === undefined ? runLocked(params.executor) : params.executor.withSession({ run: runLocked });
7080
+ }
6838
7081
  function validateMigrationReplay(params) {
6839
7082
  const dialect = params.dialect ?? "postgres";
6840
7083
  assertProbeMode({ dialect, probe: params.probe });
@@ -6845,8 +7088,8 @@ function validateMigrationReplay(params) {
6845
7088
  assertSupportedSelfManagedScript({ sql: migration.sql, migration: migration.name, direction: "up" });
6846
7089
  assertNamedRemovals({ removals: migration.desiredState?.unmanagedRemovals ?? [], approved: params.removeUnmanaged, acceptIntegrityLoss: params.acceptIntegrityLoss });
6847
7090
  if (migration.desiredState !== undefined) {
6848
- const state2 = migration.desiredState;
6849
- assertRemovalAuthorization({ steps: diffSchemas({ from: state2.from.schema, to: state2.to.schema, dialect }), previous: state2.from, dialect, namespace: dialect === "sqlite" ? "main" : "public", ...params.acceptIntegrityLoss === undefined ? {} : { acceptIntegrityLoss: params.acceptIntegrityLoss } });
7091
+ const state = migration.desiredState;
7092
+ assertRemovalAuthorization({ steps: diffSchemas({ from: state.from.schema, to: state.to.schema, dialect }), previous: state.from, dialect, namespace: dialect === "sqlite" ? "main" : "public", ...params.acceptIntegrityLoss === undefined ? {} : { acceptIntegrityLoss: params.acceptIntegrityLoss } });
6850
7093
  }
6851
7094
  assertSecurityAcknowledgement({ securityChanges: [...migration.securityChanges ?? [], ...migrationRlsSecurityChanges({ migration, down: false })], ...params.acceptSecurityChanges === undefined ? {} : { acceptSecurityChanges: params.acceptSecurityChanges } });
6852
7095
  }
@@ -6858,11 +7101,11 @@ function assertMigrationMetadata(params) {
6858
7101
  assertModuleOwnership({ origin: migration.moduleOrigin, desiredState: migration.desiredState });
6859
7102
  }
6860
7103
  if (migration.desiredStatePending === true)
6861
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration ${migration.name} has unfinalized desired state; finalize its reviewed before/after declarations before applying`, meta: { reason: "desired-state-unfinalized", migration: migration.name } });
7104
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration ${migration.name} has unfinalized desired state; finalize its reviewed before/after declarations before applying`, meta: { reason: "desired-state-unfinalized", migration: migration.name } });
6862
7105
  if (migration.desiredState !== undefined) {
6863
7106
  assertDesiredState({ value: migration.desiredState, migration: migration.name });
6864
7107
  if (migration.desiredState.dialect !== dialect)
6865
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch", migration: migration.name } });
7108
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch", migration: migration.name } });
6866
7109
  }
6867
7110
  assertNativeMigrationMetadata({ migration, sql: migration.sql, dialect });
6868
7111
  assertExecutable({ migration, execution: migration.execution, sql: migration.sql, dialect });
@@ -6871,23 +7114,19 @@ async function applyMigrations(params) {
6871
7114
  const { executor, migrations } = params;
6872
7115
  const dialect = params.dialect ?? "postgres";
6873
7116
  if (params.history !== undefined && params.history !== "complete" && params.history !== "subset")
6874
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Unknown migration history validation mode", meta: { reason: "history-mode-invalid" } });
7117
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Unknown migration history validation mode", meta: { reason: "history-mode-invalid" } });
6875
7118
  if (params.history === "complete")
6876
7119
  assertDistinctMigrationNames({ migrations });
6877
7120
  for (const migration of migrations)
6878
7121
  assertMigrationMetadata({ migration, dialect });
6879
- if (executor.withSession !== undefined) {
6880
- return executor.withSession({ run: (session) => applyMigrations({ ...params, executor: session }) });
6881
- }
6882
- await acquireLock({ executor, dialect });
6883
- try {
6884
- const moduleRecords = migrations.some((migration) => migration.moduleOrigin !== undefined) ? await readModuleJournal({ executor, dialect }) : undefined;
6885
- const recorded = moduleRecords === undefined ? await recordedRows({ executor, dialect }) : new Map([...moduleRecords].map(([name, record3]) => [name, record3.row]));
6886
- if (moduleRecords !== undefined) {
7122
+ return withMigrationLock({ executor, dialect, run: async (executor) => {
7123
+ let moduleRecords = await readModuleJournal({ executor, dialect });
7124
+ const recorded = new Map([...moduleRecords].map(([name, record]) => [name, record.row]));
7125
+ if (migrations.some((migration) => migration.moduleOrigin !== undefined) || [...moduleRecords.values()].some((record) => record.entry !== undefined)) {
6887
7126
  assertModuleUpgradeHistory({ migrations, records: moduleRecords });
6888
7127
  const namespace = await migrationNamespace({ executor, dialect });
6889
7128
  if (migrations.some((migration) => migration.moduleOrigin !== undefined && moduleNamespace({ origin: migration.moduleOrigin }) !== namespace))
6890
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Module placement differs from the active database namespace", meta: { reason: "module-placement-mismatch" } });
7129
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Module placement differs from the active database namespace", meta: { reason: "module-placement-mismatch" } });
6891
7130
  }
6892
7131
  if (params.history === "complete")
6893
7132
  assertCompleteHistory({ migrations, recorded, dialect });
@@ -6898,7 +7137,7 @@ async function applyMigrations(params) {
6898
7137
  });
6899
7138
  validateMigrationReplay({ ...params, migrations: pending, dialect });
6900
7139
  await ensureMigrationsTable({ executor, dialect });
6901
- if (moduleRecords !== undefined)
7140
+ if (migrations.some((migration) => migration.moduleOrigin !== undefined))
6902
7141
  await ensureModuleJournal({ executor, dialect });
6903
7142
  const applied = [];
6904
7143
  const skipped = [];
@@ -6908,7 +7147,7 @@ async function applyMigrations(params) {
6908
7147
  await assertLiveModuleOwnership({ executor, origin: migration.moduleOrigin, resume: stored !== undefined });
6909
7148
  if (stored !== undefined) {
6910
7149
  if (stored.statementIndex < 0) {
6911
- throw new VibeError30({
7150
+ throw new VibeError32({
6912
7151
  code: "VIBE_MIGRATION",
6913
7152
  message: `migration "${migration.name}" is mid-rollback (${-stored.statementIndex - 1} down statement(s) done) \u2014 finish it with \`migrate down\` or repair with resolveMigration before applying`,
6914
7153
  meta: { migration: migration.name, statementIndex: stored.statementIndex }
@@ -6929,11 +7168,14 @@ async function applyMigrations(params) {
6929
7168
  dialect,
6930
7169
  migration,
6931
7170
  start: stored.statementIndex,
7171
+ moduleOrigins: applicationModuleOrigins({ migration, records: moduleRecords }),
6932
7172
  ...params.probe === undefined ? {} : { probe: params.probe },
6933
7173
  insertRecord: false,
6934
7174
  ...stored.error === undefined ? {} : { storedError: stored.error }
6935
7175
  })
6936
7176
  });
7177
+ if (migration.moduleOrigin !== undefined)
7178
+ moduleRecords = await readModuleJournal({ executor, dialect });
6937
7179
  applied.push(migration.name);
6938
7180
  continue;
6939
7181
  }
@@ -6942,11 +7184,13 @@ async function applyMigrations(params) {
6942
7184
  executor,
6943
7185
  dialect,
6944
7186
  ...migration.execution === undefined ? {} : { execution: migration.execution },
6945
- run: () => runNonTransactional({ executor, dialect, migration, start: 0, insertRecord: true, ...params.probe === undefined ? {} : { probe: params.probe } })
7187
+ run: () => runNonTransactional({ executor, dialect, migration, moduleOrigins: applicationModuleOrigins({ migration, records: moduleRecords }), start: 0, insertRecord: true, ...params.probe === undefined ? {} : { probe: params.probe } })
6946
7188
  });
6947
7189
  } else {
6948
- await runTransactional({ executor, dialect, migration, ...params.probe === undefined ? {} : { probe: params.probe } });
7190
+ await runTransactional({ executor, dialect, migration, moduleOrigins: applicationModuleOrigins({ migration, records: moduleRecords }), ...params.probe === undefined ? {} : { probe: params.probe } });
6949
7191
  }
7192
+ if (migration.moduleOrigin !== undefined)
7193
+ moduleRecords = await readModuleJournal({ executor, dialect });
6950
7194
  applied.push(migration.name);
6951
7195
  }
6952
7196
  const final = migrations.at(-1);
@@ -6961,9 +7205,7 @@ async function applyMigrations(params) {
6961
7205
  }
6962
7206
  }
6963
7207
  return { applied, skipped };
6964
- } finally {
6965
- await releaseLock({ executor, dialect });
6966
- }
7208
+ } });
6967
7209
  }
6968
7210
  async function migrationStatus(params) {
6969
7211
  const { executor, migrations } = params;
@@ -7033,19 +7275,14 @@ function classifyJournal(params) {
7033
7275
  return journal;
7034
7276
  }
7035
7277
  async function resolveMigration(params) {
7036
- if (params.executor.withSession !== undefined) {
7037
- return params.executor.withSession({ run: (executor2) => resolveMigration({ ...params, executor: executor2 }) });
7038
- }
7039
- const { executor } = params;
7040
7278
  const dialect = params.dialect ?? "postgres";
7041
- await acquireLock({ executor, dialect });
7042
- await repairMigration({ ...params, executor, dialect }).finally(() => releaseLock({ executor, dialect }));
7279
+ await withMigrationLock({ executor: params.executor, dialect, run: (executor) => repairMigration({ ...params, executor, dialect }) });
7043
7280
  }
7044
7281
  async function repairMigration(params) {
7045
7282
  const { executor, name, dialect } = params;
7046
7283
  const moduleRecord = (await readModuleJournal({ executor, dialect })).get(name);
7047
7284
  if (moduleRecord?.entry !== undefined)
7048
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Module history cannot be marked applied or deleted without verified module recovery", meta: { reason: "module-resolution-required", moduleId: moduleRecord.entry.migration.moduleOrigin.moduleId } });
7285
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Module history cannot be marked applied or deleted without verified module recovery", meta: { reason: "module-resolution-required", moduleId: moduleRecord.entry.migration.moduleOrigin.moduleId } });
7049
7286
  await ensureMigrationsTable({ executor, dialect });
7050
7287
  if (params.as === "applied") {
7051
7288
  const insert = `INSERT INTO ${q5(dialect, MIGRATIONS_TABLE_NAME)} (${q5(dialect, "name")}, ${q5(dialect, "checksum")}, ${q5(dialect, "statement_index")}) VALUES (${ph(dialect, 1)}, ${ph(dialect, 2)}, ${RESOLVED_STATEMENT_INDEX})`;
@@ -7062,38 +7299,30 @@ async function rollbackMigration(params) {
7062
7299
  const { executor, migration } = params;
7063
7300
  const dialect = params.dialect ?? "postgres";
7064
7301
  const downSql = validateRollbackFile({ ...params, dialect });
7065
- if (executor.withSession !== undefined) {
7066
- return executor.withSession({ run: (session) => rollbackMigration({ ...params, executor: session }) });
7067
- }
7068
- await acquireLock({ executor, dialect });
7069
- await Promise.resolve().then(async () => {
7070
- const recorded = await recordedRows({ executor, dialect, modules: migration.moduleOrigin !== undefined });
7302
+ await withMigrationLock({ executor, dialect, run: async (executor) => {
7303
+ const recorded = await recordedRows({ executor, dialect, modules: true });
7071
7304
  const stored = assertRollbackRecord({ migration, stored: recorded.get(migration.name), dialect });
7072
7305
  const newest = [...recorded.keys()].at(-1);
7073
7306
  if (newest !== migration.name)
7074
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${migration.name}" is not the newest recorded migration; select rollback again`, meta: { reason: "rollback-not-latest", migration: migration.name, newest } });
7307
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${migration.name}" is not the newest recorded migration; select rollback again`, meta: { reason: "rollback-not-latest", migration: migration.name, newest } });
7075
7308
  await validateRollbackRecovery({ executor, migration, downSql, stored, dialect });
7076
- await executeRollback({ ...params, dialect, downSql, stored });
7077
- }).finally(() => releaseLock({ executor, dialect }));
7309
+ await executeRollback({ ...params, executor, dialect, downSql, stored });
7310
+ } });
7078
7311
  }
7079
7312
  async function rollbackMigrations(params) {
7080
7313
  const { executor, migrations } = params;
7081
7314
  const dialect = params.dialect ?? "postgres";
7082
7315
  assertDistinctMigrationNames({ migrations });
7083
- if (executor.withSession !== undefined) {
7084
- return executor.withSession({ run: (session) => rollbackMigrations({ ...params, executor: session }) });
7085
- }
7086
- await acquireLock({ executor, dialect });
7087
- return Promise.resolve().then(async () => {
7088
- const recorded = await recordedRows({ executor, dialect, modules: migrations.some((migration) => migration.moduleOrigin !== undefined) });
7316
+ return withMigrationLock({ executor, dialect, run: async (executor) => {
7317
+ const recorded = await recordedRows({ executor, dialect, modules: true });
7089
7318
  const journal = classifyJournal({ migrations, recorded, dialect });
7090
7319
  const byName = new Map(migrations.map((migration) => [migration.name, migration]));
7091
7320
  let start = Math.max(0, journal.length - 1);
7092
7321
  if (params.to !== undefined) {
7093
- const target = journal.findIndex((row2) => row2.name === params.to);
7322
+ const target = journal.findIndex((row) => row.name === params.to);
7094
7323
  const row = journal[target];
7095
7324
  if (row?.state !== "applied")
7096
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Rollback target "${params.to}" is not a known applied migration`, meta: { reason: "rollback-target-invalid", to: params.to, state: row?.state } });
7325
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Rollback target "${params.to}" is not a known applied migration`, meta: { reason: "rollback-target-invalid", to: params.to, state: row?.state } });
7097
7326
  assertMigrationMetadata({ migration: byName.get(row.name), dialect });
7098
7327
  start = target + 1;
7099
7328
  }
@@ -7101,7 +7330,7 @@ async function rollbackMigrations(params) {
7101
7330
  for (const row of journal.slice(start).reverse()) {
7102
7331
  const migration = byName.get(row.name);
7103
7332
  if (migration === undefined)
7104
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Cannot roll back "${row.name}" without its migration file`, meta: { reason: "rollback-file-missing", migration: row.name } });
7333
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Cannot roll back "${row.name}" without its migration file`, meta: { reason: "rollback-file-missing", migration: row.name } });
7105
7334
  const stored = assertRollbackRecord({ migration, stored: recorded.get(row.name), dialect });
7106
7335
  const downSql = validateRollbackFile({ ...params, migration, dialect });
7107
7336
  plan.push({ migration, downSql, stored });
@@ -7110,28 +7339,28 @@ async function rollbackMigrations(params) {
7110
7339
  await validateRollbackRecovery({ executor, dialect, ...entry });
7111
7340
  const rolledBack = [];
7112
7341
  for (const entry of plan) {
7113
- await executeRollback({ ...params, dialect, ...entry });
7342
+ await executeRollback({ ...params, executor, dialect, ...entry });
7114
7343
  rolledBack.push(entry.migration.name);
7115
7344
  }
7116
7345
  return { rolledBack };
7117
- }).finally(() => releaseLock({ executor, dialect }));
7346
+ } });
7118
7347
  }
7119
7348
  function validateRollbackFile(params) {
7120
7349
  const { migration, dialect } = params;
7121
7350
  if (migration.desiredStatePending === true)
7122
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Unfinalized desired state cannot be rolled back", meta: { reason: "desired-state-unfinalized", migration: migration.name } });
7351
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Unfinalized desired state cannot be rolled back", meta: { reason: "desired-state-unfinalized", migration: migration.name } });
7123
7352
  if (migration.moduleOrigin !== undefined) {
7124
7353
  assertMaterializedModuleMigration({ migration });
7125
7354
  assertModuleOwnership({ origin: migration.moduleOrigin, desiredState: migration.desiredState });
7126
7355
  }
7127
7356
  const downSql = migration.downSql;
7128
7357
  if (downSql === undefined)
7129
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" has no down.sql; roll it back manually, then repair with resolveMigration (as: "rolled-back")`, meta: { reason: "rollback-down-missing", migration: migration.name } });
7358
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" has no down.sql; roll it back manually, then repair with resolveMigration (as: "rolled-back")`, meta: { reason: "rollback-down-missing", migration: migration.name } });
7130
7359
  assertProbeMode({ dialect, probe: params.probe });
7131
7360
  if (migration.desiredState !== undefined) {
7132
7361
  assertDesiredState({ value: migration.desiredState, migration: migration.name });
7133
7362
  if (migration.desiredState.dialect !== dialect)
7134
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch" } });
7363
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Migration desired-state dialect mismatch", meta: { reason: "desired-state-dialect-mismatch" } });
7135
7364
  assertRemovalAuthorization({ steps: diffSchemas({ from: migration.desiredState.to.schema, to: (migration.desiredState.down ?? migration.desiredState.from).schema, dialect }), previous: migration.desiredState.to, dialect, namespace: dialect === "sqlite" ? "main" : "public", ...params.acceptIntegrityLoss === undefined ? {} : { acceptIntegrityLoss: params.acceptIntegrityLoss } });
7136
7365
  }
7137
7366
  assertNativeMigrationMetadata({ migration, sql: downSql, dialect });
@@ -7144,10 +7373,10 @@ function validateRollbackFile(params) {
7144
7373
  function assertRollbackRecord(params) {
7145
7374
  const { migration, stored, dialect } = params;
7146
7375
  if (stored === undefined)
7147
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is not recorded as applied; nothing to roll back`, meta: { migration: migration.name } });
7376
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is not recorded as applied; nothing to roll back`, meta: { migration: migration.name } });
7148
7377
  assertChecksumMatches({ migration, stored: stored.checksum });
7149
7378
  if (stored.statementIndex >= 0 && (!isCompleteRecord({ dialect, migration, stored }) || stored.error !== undefined))
7150
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is only partially applied or has an unresolved error; its down mirrors the FULL up. Finish or repair with resolveMigration`, meta: { reason: "rollback-partial-up", migration: migration.name, statementIndex: stored.statementIndex } });
7379
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `migration "${migration.name}" is only partially applied or has an unresolved error; its down mirrors the FULL up. Finish or repair with resolveMigration`, meta: { reason: "rollback-partial-up", migration: migration.name, statementIndex: stored.statementIndex } });
7151
7380
  return stored;
7152
7381
  }
7153
7382
  async function validateRollbackRecovery(params) {
@@ -7156,7 +7385,7 @@ async function validateRollbackRecovery(params) {
7156
7385
  return;
7157
7386
  const start = -stored.statementIndex - 1;
7158
7387
  if (start > downSql.length)
7159
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Rollback progress exceeds its statement count", meta: { reason: "rollback-progress-invalid", migration: migration.name } });
7388
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Rollback progress exceeds its statement count", meta: { reason: "rollback-progress-invalid", migration: migration.name } });
7160
7389
  if (dialect === "sqlite" && usesSelfManagedTransactions({ sql: downSql }))
7161
7390
  assertSelfManagedResumeSafe({ sql: downSql, start, migration: migration.name, direction: "down" });
7162
7391
  if (!marksInflight({ dialect, execution: migration.downExecution }) || start >= downSql.length)
@@ -7169,16 +7398,17 @@ async function validateRollbackRecovery(params) {
7169
7398
  }
7170
7399
  async function executeRollback(params) {
7171
7400
  const { executor, dialect, migration, downSql, stored } = params;
7401
+ const moduleOrigins = applicationModuleOrigins({ migration, records: await readModuleJournal({ executor, dialect }) });
7172
7402
  if (usesStatementBookkeeping({ dialect, sql: downSql, ...migration.downExecution === undefined ? {} : { execution: migration.downExecution } })) {
7173
7403
  const start = stored.statementIndex < 0 ? -stored.statementIndex - 1 : 0;
7174
7404
  await withSessionLimits({
7175
7405
  executor,
7176
7406
  dialect,
7177
7407
  execution: migration.downExecution,
7178
- run: () => runNonTransactionalDown({ executor, dialect, migration, downSql, start, probe: params.probe, storedError: stored.error })
7408
+ run: () => runNonTransactionalDown({ executor, dialect, migration, moduleOrigins, downSql, start, probe: params.probe, storedError: stored.error })
7179
7409
  });
7180
7410
  } else
7181
- await runTransactionalDown({ executor, dialect, migration, downSql, probe: params.probe });
7411
+ await runTransactionalDown({ executor, dialect, migration, moduleOrigins, downSql, probe: params.probe });
7182
7412
  }
7183
7413
  async function runTransactionalDown(params) {
7184
7414
  const { executor, dialect, migration, downSql } = params;
@@ -7190,14 +7420,15 @@ async function runTransactionalDown(params) {
7190
7420
  const limits = migration.downExecution;
7191
7421
  if (wrap && dialect === "postgres" && limits !== undefined) {
7192
7422
  if ((limits.lockTimeoutMs ?? 0) > 0)
7193
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7423
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7194
7424
  if ((limits.statementTimeoutMs ?? 0) > 0)
7195
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7425
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7196
7426
  }
7197
7427
  if (migration.desiredState !== undefined)
7198
7428
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7199
7429
  if (migration.rls !== undefined)
7200
7430
  await introspectPostgres({ executor, rlsSchema: migration.rls.to, inTransaction: true, requireInstalledRls: true });
7431
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7201
7432
  for (const statement of downSql) {
7202
7433
  await executeStatement({ executor, statement, dialect });
7203
7434
  }
@@ -7205,6 +7436,7 @@ async function runTransactionalDown(params) {
7205
7436
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7206
7437
  if (migration.rls !== undefined)
7207
7438
  await introspectPostgres({ executor, rlsSchema: migration.rls.from, inTransaction: true, requireInstalledRls: true });
7439
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7208
7440
  await executor({
7209
7441
  text: `DELETE FROM ${q5(dialect, MIGRATIONS_TABLE_NAME)} WHERE ${q5(dialect, "name")} = ${ph(dialect, 1)}`,
7210
7442
  values: [migration.name]
@@ -7219,7 +7451,7 @@ async function runTransactionalDown(params) {
7219
7451
  } else {
7220
7452
  await cleanupSelfManagedFailure({ executor });
7221
7453
  }
7222
- throw new VibeError30({
7454
+ throw new VibeError32({
7223
7455
  code: "VIBE_MIGRATION",
7224
7456
  message: `rollback of "${migration.name}" failed: ${error instanceof Error ? error.message : String(error)}`,
7225
7457
  meta: { migration: migration.name, ...timeoutDiagnostic({ error }) },
@@ -7251,6 +7483,7 @@ async function runNonTransactionalDown(params) {
7251
7483
  throw uncertainStatement({ migration: migration.name, statements: downSql, index: start, dialect, direction: "down" });
7252
7484
  }
7253
7485
  const resumeState = resumeOperation === undefined ? undefined : await establishOperationState({ executor, dialect, operation: resumeOperation });
7486
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7254
7487
  if (start === 0) {
7255
7488
  if (migration.desiredState !== undefined)
7256
7489
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
@@ -7260,6 +7493,8 @@ async function runNonTransactionalDown(params) {
7260
7493
  if (resumeOperation !== undefined && resumeState === "satisfied") {
7261
7494
  if (start + 1 === downSql.length && migration.desiredState !== undefined)
7262
7495
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7496
+ if (start + 1 === downSql.length)
7497
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7263
7498
  await recordProgress(start + 1);
7264
7499
  cursor = start + 1;
7265
7500
  }
@@ -7278,11 +7513,14 @@ async function runNonTransactionalDown(params) {
7278
7513
  if (commitsBlock) {
7279
7514
  if (migration.desiredState !== undefined && downSql.slice(index + 1).every((statement) => /^\s*PRAGMA\s+foreign_keys\s*=\s*ON\s*;?\s*$/i.test(statement)))
7280
7515
  assertMigrationState({ report: await verifySqliteTransitionBeforeRestore({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7516
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe, sqliteRestorePending: true });
7281
7517
  await recordProgress(index + 1);
7282
7518
  }
7283
7519
  await executeStatement({ executor, statement: downSql[index], dialect });
7284
7520
  if (index === downSql.length - 1 && migration.desiredState !== undefined)
7285
7521
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.to, to: migration.desiredState.down ?? migration.desiredState.from, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7522
+ if (index === downSql.length - 1)
7523
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7286
7524
  if (atomic) {
7287
7525
  await recordProgress(index + 1);
7288
7526
  await executor({ text: "COMMIT" });
@@ -7296,7 +7534,7 @@ async function runNonTransactionalDown(params) {
7296
7534
  values: [marks ? `${INFLIGHT_PREFIX}${index}` : error instanceof Error ? error.message : String(error), migration.name]
7297
7535
  });
7298
7536
  } catch {}
7299
- throw new VibeError30({
7537
+ throw new VibeError32({
7300
7538
  code: "VIBE_MIGRATION",
7301
7539
  message: `rollback of "${migration.name}" failed at down statement ${index + 1} of ${downSql.length}: ${error instanceof Error ? error.message : String(error)}. ${marks ? "The statement outcome is unknown; inspect its effects before resolving or retrying." : "Progress is recorded; re-running the rollback resumes from this statement."}`,
7302
7540
  meta: { migration: migration.name, statementIndex: index, ...marks ? { outcome: "unknown" } : {}, ...timeoutDiagnostic({ error }) },
@@ -7323,11 +7561,12 @@ async function runTransactional(params) {
7323
7561
  const limits = migration.execution;
7324
7562
  if (wrap && dialect === "postgres" && limits !== undefined) {
7325
7563
  if ((limits.lockTimeoutMs ?? 0) > 0)
7326
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7564
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "lock_timeout", milliseconds: limits.lockTimeoutMs, local: true }).text });
7327
7565
  if ((limits.statementTimeoutMs ?? 0) > 0)
7328
- await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect5({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7566
+ await executor({ text: renderMigrationSessionSet({ dialect: getSqlDialect7({ dialect }), setting: "statement_timeout", milliseconds: limits.statementTimeoutMs, local: true }).text });
7329
7567
  }
7330
7568
  await assertForwardStart({ executor, dialect, migration, ...params.probe === undefined ? {} : { probe: params.probe } });
7569
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7331
7570
  if (migration.rls !== undefined)
7332
7571
  await introspectPostgres({ executor, rlsSchema: migration.rls.from, inTransaction: true, requireInstalledRls: true });
7333
7572
  let statementIndex = 0;
@@ -7339,6 +7578,7 @@ async function runTransactional(params) {
7339
7578
  assertMigrationState({ report: await verifyMigrationTransition({ executor, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, dialect, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7340
7579
  if (migration.rls !== undefined)
7341
7580
  await introspectPostgres({ executor, rlsSchema: migration.rls.to, inTransaction: true, requireInstalledRls: true });
7581
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7342
7582
  if (migration.moduleOrigin !== undefined)
7343
7583
  await insertModuleJournal({ executor, dialect, migration, index: statementIndex, complete: true });
7344
7584
  else
@@ -7356,7 +7596,7 @@ async function runTransactional(params) {
7356
7596
  } else {
7357
7597
  await cleanupSelfManagedFailure({ executor });
7358
7598
  }
7359
- throw new VibeError30({
7599
+ throw new VibeError32({
7360
7600
  code: "VIBE_MIGRATION",
7361
7601
  message: `migration "${migration.name}" failed: ${error instanceof Error ? error.message : String(error)}`,
7362
7602
  meta: { migration: migration.name },
@@ -7376,6 +7616,7 @@ async function runNonTransactional(params) {
7376
7616
  const declared = execution?.transaction === "none";
7377
7617
  const marks = marksInflight({ dialect, ...execution === undefined ? {} : { execution } });
7378
7618
  const start = selfManaged ? selfManagedResumeStart({ sql: migration.sql, start: params.start }) : params.start;
7619
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7379
7620
  if (insertRecord) {
7380
7621
  if (migration.desiredState !== undefined) {
7381
7622
  await assertForwardStart({ executor, dialect, migration, ...params.probe === undefined ? {} : { probe: params.probe } });
@@ -7400,10 +7641,12 @@ async function runNonTransactional(params) {
7400
7641
  if (marks && !insertRecord && start < migration.sql.length) {
7401
7642
  const operation = declared ? operationFor({ ...execution === undefined ? {} : { execution }, statement: start }) : undefined;
7402
7643
  if (operation !== undefined) {
7403
- const state2 = await establishOperationState({ executor, dialect, operation });
7404
- if (state2 === "satisfied") {
7644
+ const state = await establishOperationState({ executor, dialect, operation });
7645
+ if (state === "satisfied") {
7405
7646
  if (start + 1 === migration.sql.length && migration.desiredState !== undefined)
7406
7647
  assertMigrationState({ report: await verifyMigrationTransition({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7648
+ if (start + 1 === migration.sql.length)
7649
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7407
7650
  await checkpoint(start + 1);
7408
7651
  cursor = start + 1;
7409
7652
  }
@@ -7426,11 +7669,14 @@ async function runNonTransactional(params) {
7426
7669
  if (commitsBlock) {
7427
7670
  if (migration.desiredState !== undefined && migration.sql.slice(index + 1).every((statement) => /^\s*PRAGMA\s+foreign_keys\s*=\s*ON\s*;?\s*$/i.test(statement)))
7428
7671
  assertMigrationState({ report: await verifySqliteTransitionBeforeRestore({ executor, dialect, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7672
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe, sqliteRestorePending: true });
7429
7673
  await checkpoint(index + 1);
7430
7674
  }
7431
7675
  await executeStatement({ executor, statement: migration.sql[index], dialect });
7432
7676
  if (index === migration.sql.length - 1 && migration.desiredState !== undefined)
7433
7677
  assertMigrationState({ report: await verifyMigrationTransition({ executor, from: migration.desiredState.from, to: migration.desiredState.to, removals: migration.desiredState.unmanagedRemovals, dialect, ...params.probe === undefined ? {} : { probe: params.probe } }) });
7678
+ if (index === migration.sql.length - 1)
7679
+ await assertApplicationModuleState({ executor, origins: params.moduleOrigins, probe: params.probe });
7434
7680
  if (atomic) {
7435
7681
  await checkpoint(index + 1);
7436
7682
  await executor({ text: "COMMIT" });
@@ -7446,7 +7692,7 @@ async function runNonTransactional(params) {
7446
7692
  } catch {}
7447
7693
  const sqlState = sqlStateOf(error);
7448
7694
  const timeout = sqlState === "55P03" ? "lock-timeout" : sqlState === "57014" ? "statement-timeout" : undefined;
7449
- throw new VibeError30({
7695
+ throw new VibeError32({
7450
7696
  code: "VIBE_MIGRATION",
7451
7697
  message: timeout === "lock-timeout" ? `migration "${migration.name}" gave up waiting for a lock at statement ${index + 1} of ${migration.sql.length} (lock_timeout ${String(execution?.lockTimeoutMs ?? 0)}ms, SQLSTATE 55P03). Another session holds a conflicting lock; inspect the declared operation before retrying.` : timeout === "statement-timeout" ? `migration "${migration.name}" exceeded its statement_timeout at statement ${index + 1} of ${migration.sql.length} (${String(execution?.statementTimeoutMs ?? 0)}ms, SQLSTATE 57014). Inspect the declared operation before retrying.` : `migration "${migration.name}" failed at statement ${index + 1} of ${migration.sql.length}: ${error instanceof Error ? error.message : String(error)}. ${marks ? "The statement outcome is unknown; inspect its effects before resolving or retrying." : "Progress is recorded; re-running applyMigrations resumes from this statement."}`,
7452
7698
  meta: { migration: migration.name, statementIndex: index, ...marks ? { outcome: "unknown" } : {}, ...timeout === undefined ? {} : { reason: timeout, sqlState } },
@@ -7474,7 +7720,7 @@ async function acquireLock(params) {
7474
7720
  });
7475
7721
  const acquired = Number(rows[0]?.vibe_lock) === 1;
7476
7722
  if (!acquired) {
7477
- throw new VibeError30({
7723
+ throw new VibeError32({
7478
7724
  code: "VIBE_MIGRATION",
7479
7725
  message: `could not acquire the migration lock ('${MYSQL_LOCK_NAME}') within ${MYSQL_LOCK_TIMEOUT_SECONDS}s \u2014 another migration run is in progress`,
7480
7726
  meta: { lock: MYSQL_LOCK_NAME }
@@ -7484,13 +7730,11 @@ async function acquireLock(params) {
7484
7730
  }
7485
7731
  async function releaseLock(params) {
7486
7732
  const { executor, dialect } = params;
7487
- try {
7488
- if (dialect === "postgres") {
7489
- await executor({ text: `SELECT pg_advisory_unlock(${PG_ADVISORY_LOCK_KEY})` });
7490
- } else if (dialect === "mysql") {
7491
- await executor({ text: `SELECT RELEASE_LOCK('${MYSQL_LOCK_NAME}')` });
7492
- }
7493
- } catch {}
7733
+ if (dialect === "postgres") {
7734
+ await executor({ text: `SELECT pg_advisory_unlock(${PG_ADVISORY_LOCK_KEY})` });
7735
+ } else if (dialect === "mysql") {
7736
+ await executor({ text: `SELECT RELEASE_LOCK('${MYSQL_LOCK_NAME}')` });
7737
+ }
7494
7738
  }
7495
7739
  var INFLIGHT_PREFIX = "VIBE_INFLIGHT:";
7496
7740
  function inflightStatement(params) {
@@ -7511,7 +7755,7 @@ function uncertainStatement(params) {
7511
7755
  const subject = direction === "down" ? `rollback of "${migration}"` : `migration "${migration}"`;
7512
7756
  const position = `${direction === "down" ? "down statement" : "statement"} ${index + 1} of ${statements.length}`;
7513
7757
  const why = dialect === "mysql" ? "MySQL commits every statement on its own, so nothing outside the statement records whether it finished." : "That statement declares no operation whose effect recovery can read back from the catalog.";
7514
- return new VibeError30({
7758
+ return new VibeError32({
7515
7759
  code: "VIBE_MIGRATION",
7516
7760
  message: `${subject} was interrupted while ${position} was running. ${why} ` + "It may or may not have committed, and replaying it could apply it twice, so VibeORM stops here instead of guessing. " + 'Inspect what that statement did to the database, then follow "Recovering from a stopped migration" in docs/migrations.md: ' + `clear the \`error\` column of this migration's journal row if the statement did NOT land, set \`statement_index\` to ${direction === "down" ? -(index + 2) : index + 1} if it DID, ` + "or finish the whole migration by hand and record that with `vibeorm migrate resolve --applied`. " + `The statement was: ${statements[index].slice(0, 200)}`,
7517
7761
  meta: {
@@ -7529,7 +7773,7 @@ function assertExecutable(params) {
7529
7773
  if (execution === undefined || isDefaultExecution({ execution }))
7530
7774
  return;
7531
7775
  if (dialect !== "postgres") {
7532
- throw new VibeError30({
7776
+ throw new VibeError32({
7533
7777
  code: "VIBE_UNSUPPORTED_CAPABILITY",
7534
7778
  message: `migration "${migration.name}" declares explicit execution semantics (transaction: "${execution.transaction}"), which only the postgres runner implements \u2014 ${dialect} has no separate nontransactional regime to opt into`,
7535
7779
  meta: { reason: "nontransactional-unsupported", dialect, migration: migration.name, feature: "nontransactionalMigrations" }
@@ -7552,7 +7796,7 @@ async function withSessionLimits(params) {
7552
7796
  const statement = execution?.statementTimeoutMs ?? 0;
7553
7797
  if (dialect !== "postgres" || lock === 0 && statement === 0)
7554
7798
  return params.run();
7555
- const sqlDialect = getSqlDialect5({ dialect });
7799
+ const sqlDialect = getSqlDialect7({ dialect });
7556
7800
  const previous = (await executor({ text: renderMigrationSessionRead({ dialect: sqlDialect }).text, values: [] }))[0];
7557
7801
  if (lock > 0)
7558
7802
  await executor({ text: renderMigrationSessionSet({ dialect: sqlDialect, setting: "lock_timeout", milliseconds: lock }).text });
@@ -7571,12 +7815,12 @@ async function withSessionLimits(params) {
7571
7815
  }
7572
7816
  }
7573
7817
  function usesStatementBookkeeping(params) {
7574
- const { dialect, sql: sql2 } = params;
7818
+ const { dialect, sql } = params;
7575
7819
  if (params.execution?.transaction === "none")
7576
7820
  return true;
7577
7821
  if (!DIALECT_CAPABILITIES3[dialect].transactionalDdl)
7578
7822
  return true;
7579
- return dialect === "sqlite" && usesSelfManagedTransactions({ sql: sql2 });
7823
+ return dialect === "sqlite" && usesSelfManagedTransactions({ sql });
7580
7824
  }
7581
7825
  function isCompleteRecord(params) {
7582
7826
  const { dialect, migration, stored } = params;
@@ -7591,7 +7835,7 @@ function isCompleteRecord(params) {
7591
7835
  async function recordedRows(params) {
7592
7836
  const { executor, dialect } = params;
7593
7837
  if (params.modules === true)
7594
- return new Map([...await readModuleJournal({ executor, dialect })].map(([name, record3]) => [name, record3.row]));
7838
+ return new Map([...await readModuleJournal({ executor, dialect })].map(([name, record]) => [name, record.row]));
7595
7839
  const rows = await readJournalRows({ executor, dialect, query: {
7596
7840
  text: `SELECT ${q5(dialect, "name")}, ${q5(dialect, "checksum")}, ${q5(dialect, "statement_index")}, ${q5(dialect, "error")} FROM ${q5(dialect, MIGRATIONS_TABLE_NAME)} ORDER BY ${q5(dialect, "id")}`,
7597
7841
  values: []
@@ -7605,7 +7849,7 @@ function assertChecksumMatches(params) {
7605
7849
  const actual = checksumOf({ migration });
7606
7850
  if (stored === actual)
7607
7851
  return;
7608
- throw new VibeError30({
7852
+ throw new VibeError32({
7609
7853
  code: "VIBE_MIGRATION",
7610
7854
  message: `checksum mismatch for migration "${migration.name}" \u2014 its SQL changed after it was applied (recorded ${stored.slice(0, 12)}\u2026, current ${actual.slice(0, 12)}\u2026)`,
7611
7855
  meta: { migration: migration.name, recorded: stored, current: actual }
@@ -7616,7 +7860,7 @@ function assertResumable(params) {
7616
7860
  const actual = checksumOf({ migration });
7617
7861
  if (stored.checksum === actual)
7618
7862
  return;
7619
- throw new VibeError30({
7863
+ throw new VibeError32({
7620
7864
  code: "VIBE_MIGRATION",
7621
7865
  message: `migration "${migration.name}" is partially applied (${stored.statementIndex} statement(s) done) and its SQL has CHANGED since \u2014 refusing to resume; restore the original SQL or repair with resolveMigration`,
7622
7866
  meta: {
@@ -7636,7 +7880,7 @@ function assertDistinctMigrationNames(params) {
7636
7880
  const names = new Set;
7637
7881
  for (const migration of params.migrations) {
7638
7882
  if (names.has(migration.name))
7639
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Duplicate migration file identity "${migration.name}"`, meta: { reason: "history-duplicate-file", migration: migration.name } });
7883
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Duplicate migration file identity "${migration.name}"`, meta: { reason: "history-duplicate-file", migration: migration.name } });
7640
7884
  names.add(migration.name);
7641
7885
  }
7642
7886
  }
@@ -7644,15 +7888,15 @@ function assertCompleteHistory(params) {
7644
7888
  const byName = new Map(params.migrations.map((migration) => [migration.name, migration]));
7645
7889
  for (const name of params.recorded.keys()) {
7646
7890
  if (!byName.has(name))
7647
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Recorded migration "${name}" has no file in the complete chain`, meta: { reason: "history-unknown-file", migration: name } });
7891
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Recorded migration "${name}" has no file in the complete chain`, meta: { reason: "history-unknown-file", migration: name } });
7648
7892
  }
7649
7893
  let index = 0;
7650
7894
  for (const [name, stored] of params.recorded) {
7651
7895
  const migration = params.migrations[index];
7652
7896
  if (migration?.name !== name)
7653
- throw new VibeError30({ code: "VIBE_MIGRATION", message: "Recorded migration order is not a prefix of the supplied complete chain", meta: { reason: "history-order-conflict", migration: name, expected: migration?.name, position: index } });
7897
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: "Recorded migration order is not a prefix of the supplied complete chain", meta: { reason: "history-order-conflict", migration: name, expected: migration?.name, position: index } });
7654
7898
  if (stored.statementIndex >= 0 && !isCompleteRecord({ dialect: params.dialect, migration, stored }) && index !== params.recorded.size - 1)
7655
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Partial migration "${name}" precedes later recorded work`, meta: { reason: "history-partial-not-last", migration: name } });
7899
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Partial migration "${name}" precedes later recorded work`, meta: { reason: "history-partial-not-last", migration: name } });
7656
7900
  index++;
7657
7901
  }
7658
7902
  }
@@ -7661,16 +7905,16 @@ async function assertApplyHistory(params) {
7661
7905
  const byName = new Map(migrations.map((migration) => [migration.name, migration]));
7662
7906
  for (const [name, stored] of recorded) {
7663
7907
  if (stored.statementIndex < 0) {
7664
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${name}" is mid-rollback; finish or resolve it before applying`, meta: { reason: "history-rolling-back", migration: name, statementIndex: stored.statementIndex } });
7908
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${name}" is mid-rollback; finish or resolve it before applying`, meta: { reason: "history-rolling-back", migration: name, statementIndex: stored.statementIndex } });
7665
7909
  }
7666
7910
  const migration = byName.get(name);
7667
7911
  if (migration === undefined) {
7668
7912
  if (stored.error !== undefined)
7669
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error but no supplied file`, meta: { reason: "history-unknown-dirty", migration: name } });
7913
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error but no supplied file`, meta: { reason: "history-unknown-dirty", migration: name } });
7670
7914
  continue;
7671
7915
  }
7672
7916
  if (isCompleteRecord({ dialect, migration, stored }) && stored.error !== undefined)
7673
- throw new VibeError30({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error`, meta: { reason: "history-dirty", migration: name } });
7917
+ throw new VibeError32({ code: "VIBE_MIGRATION", message: `Migration "${name}" has an unresolved journal error`, meta: { reason: "history-dirty", migration: name } });
7674
7918
  if (isCompleteRecord({ dialect, migration, stored }))
7675
7919
  assertChecksumMatches({ migration, stored: stored.checksum });
7676
7920
  else
@@ -7695,10 +7939,10 @@ async function assertApplyHistory(params) {
7695
7939
  }
7696
7940
  }
7697
7941
  function q5(dialect, name) {
7698
- return getSqlDialect5({ dialect }).quoteIdent({ name });
7942
+ return getSqlDialect7({ dialect }).quoteIdent({ name });
7699
7943
  }
7700
7944
  function ph(dialect, index) {
7701
- return getSqlDialect5({ dialect }).placeholder({ index });
7945
+ return getSqlDialect7({ dialect }).placeholder({ index });
7702
7946
  }
7703
7947
 
7704
7948
  // packages/migrate/src/fs.ts
@@ -7706,7 +7950,7 @@ function absent(error) {
7706
7950
  return error !== null && typeof error === "object" && "code" in error && error.code === "ENOENT";
7707
7951
  }
7708
7952
  function failure(params) {
7709
- return new VibeError31({ code: "VIBE_MIGRATION", message: `Cannot read migration file ${params.path}`, meta: { reason: "migration-file-unreadable", path: params.path }, cause: params.cause });
7953
+ return new VibeError33({ code: "VIBE_MIGRATION", message: `Cannot read migration file ${params.path}`, meta: { reason: "migration-file-unreadable", path: params.path }, cause: params.cause });
7710
7954
  }
7711
7955
  async function optionalFile(params) {
7712
7956
  return readFile(params.path, "utf-8").catch((cause) => {
@@ -7718,15 +7962,15 @@ async function optionalFile(params) {
7718
7962
  function rlsMetadata(params) {
7719
7963
  return Promise.resolve().then(() => {
7720
7964
  const metadata = JSON.parse(params.text);
7721
- const strings2 = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
7722
- if (metadata?.version !== 1 || typeof metadata.destructive !== "boolean" || metadata.rls === undefined || !strings2(metadata.securityChanges) || !strings2(metadata.downSecurityChanges) || metadata.sqlChecksum !== migrationChecksum({ sql: params.migration.sql }) || metadata.downChecksum !== migrationChecksum({ sql: params.migration.downSql ?? [] })) {
7723
- throw new VibeError31({ code: "VIBE_MIGRATION", message: "Invalid native RLS metadata" });
7965
+ const strings = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
7966
+ if (metadata?.version !== 1 || typeof metadata.destructive !== "boolean" || metadata.rls === undefined || !strings(metadata.securityChanges) || !strings(metadata.downSecurityChanges) || metadata.sqlChecksum !== migrationChecksum({ sql: params.migration.sql }) || metadata.downChecksum !== migrationChecksum({ sql: params.migration.downSql ?? [] })) {
7967
+ throw new VibeError33({ code: "VIBE_MIGRATION", message: "Invalid native RLS metadata" });
7724
7968
  }
7725
7969
  assertValidSchemaIR4({ schema: metadata.rls.from });
7726
7970
  assertValidSchemaIR4({ schema: metadata.rls.to });
7727
7971
  return { ...params.migration, rls: metadata.rls, destructive: metadata.destructive, securityChanges: metadata.securityChanges, downSecurityChanges: metadata.downSecurityChanges };
7728
7972
  }).catch((cause) => {
7729
- throw new VibeError31({ code: "VIBE_MIGRATION", message: `Invalid native RLS metadata for migration "${params.migration.name}"`, meta: { reason: "rls-migration-metadata-invalid", migration: params.migration.name }, cause });
7973
+ throw new VibeError33({ code: "VIBE_MIGRATION", message: `Invalid native RLS metadata for migration "${params.migration.name}"`, meta: { reason: "rls-migration-metadata-invalid", migration: params.migration.name }, cause });
7730
7974
  });
7731
7975
  }
7732
7976
  async function loadMigrationFiles(params) {
@@ -7759,7 +8003,7 @@ async function loadMigrationFiles(params) {
7759
8003
  const desired = await optionalFile({ path: join(directory, DESIRED_STATE_METADATA.filename) });
7760
8004
  if (desired !== undefined) {
7761
8005
  const pending = await Promise.resolve().then(() => isUnfinalizedDesiredState({ text: desired })).catch((cause) => {
7762
- throw new VibeError31({ code: "VIBE_MIGRATION", message: `Malformed desired state for ${name}`, meta: { reason: "desired-state-invalid", migration: name }, cause });
8006
+ throw new VibeError33({ code: "VIBE_MIGRATION", message: `Malformed desired state for ${name}`, meta: { reason: "desired-state-invalid", migration: name }, cause });
7763
8007
  });
7764
8008
  migration = pending ? { ...migration, desiredStatePending: true } : { ...migration, desiredState: parseDesiredStateSidecar({ text: desired, migration: name }) };
7765
8009
  }
@@ -7771,9 +8015,9 @@ async function loadMigrationFiles(params) {
7771
8015
  return migrations;
7772
8016
  }
7773
8017
  export {
7774
- splitSqlStatements,
8018
+ joinSqlStatements,
7775
8019
  loadMigrationFiles,
7776
- joinSqlStatements
8020
+ splitSqlStatements
7777
8021
  };
7778
8022
 
7779
- //# debugId=8DB0E0F7582B731664756E2164756E21
8023
+ //# debugId=F0D645556CA0676064756E2164756E21