@happyvertical/smrt-core 0.43.10 → 0.44.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 (47) hide show
  1. package/agents/generators.md +70 -0
  2. package/agents/schema-paths.md +99 -0
  3. package/dist/generators/custom-action.d.ts.map +1 -1
  4. package/dist/generators/custom-action.js +1 -1
  5. package/dist/generators/custom-action.js.map +1 -1
  6. package/dist/index.js +2 -2
  7. package/dist/knowledge.d.ts +17 -1
  8. package/dist/knowledge.d.ts.map +1 -1
  9. package/dist/knowledge.js +33 -3
  10. package/dist/knowledge.js.map +1 -1
  11. package/dist/manifest/static-manifest.js +1 -1
  12. package/dist/manifest/static-manifest.js.map +1 -1
  13. package/dist/manifest/store.js +1 -1
  14. package/dist/manifest.json +1 -1
  15. package/dist/migrations/differ.d.ts +49 -0
  16. package/dist/migrations/differ.d.ts.map +1 -1
  17. package/dist/migrations/differ.js +220 -4
  18. package/dist/migrations/differ.js.map +1 -1
  19. package/dist/migrations/orchestrate.d.ts +23 -0
  20. package/dist/migrations/orchestrate.d.ts.map +1 -1
  21. package/dist/migrations/orchestrate.js +12 -3
  22. package/dist/migrations/orchestrate.js.map +1 -1
  23. package/dist/registry/types.d.ts +8 -3
  24. package/dist/registry/types.d.ts.map +1 -1
  25. package/dist/schema/foreign-key-ddl.d.ts +7 -0
  26. package/dist/schema/foreign-key-ddl.d.ts.map +1 -1
  27. package/dist/schema/foreign-key-ddl.js +7 -1
  28. package/dist/schema/foreign-key-ddl.js.map +1 -1
  29. package/dist/schema/schema-manager.d.ts +15 -0
  30. package/dist/schema/schema-manager.d.ts.map +1 -1
  31. package/dist/schema/schema-manager.js +52 -9
  32. package/dist/schema/schema-manager.js.map +1 -1
  33. package/dist/schema/types.d.ts +10 -0
  34. package/dist/schema/types.d.ts.map +1 -1
  35. package/dist/schema/uuid-convergence.d.ts +142 -0
  36. package/dist/schema/uuid-convergence.d.ts.map +1 -0
  37. package/dist/schema/uuid-convergence.js +0 -0
  38. package/dist/schema/uuid-convergence.js.map +1 -0
  39. package/dist/smrt-knowledge.json +7 -7
  40. package/dist/utils/scanner-module.d.ts +44 -0
  41. package/dist/utils/scanner-module.d.ts.map +1 -1
  42. package/dist/vite-plugin/index.d.ts +14 -1
  43. package/dist/vite-plugin/index.d.ts.map +1 -1
  44. package/dist/vite-plugin/index.js +54 -2
  45. package/dist/vite-plugin/index.js.map +1 -1
  46. package/dist/vite-plugin.js +3 -2
  47. package/package.json +4 -4
@@ -155,4 +155,27 @@ export declare function getPendingSchemaStatements(db: DatabaseInterface, option
155
155
  * field, the result would look indistinguishable from "already in sync."
156
156
  */
157
157
  export declare function migrateSmrtSchemas(options: MigrateSmrtSchemasOptions): Promise<MigrateSmrtSchemasResult>;
158
+ /**
159
+ * Materialize the diff into the engine-correct SQL statements.
160
+ *
161
+ * For new tables we delegate to the engine's `DDLStrategy` so column types
162
+ * (`REAL` → `DOUBLE PRECISION` on Postgres, `JSON` → `JSONB`, etc.),
163
+ * partial-index `WHERE` clauses, and trigger syntax all match what the
164
+ * SchemaComparer would expect on subsequent runs. Emitting the raw
165
+ * abstract `SchemaDefinition.ddl` here would cause immediate type-drift
166
+ * migrations on Postgres/DuckDB.
167
+ *
168
+ * Column/index/trigger changes for existing tables continue to come from
169
+ * `getSQLFromDiff`, which is already engine-aware via the differ's per-
170
+ * change `sqlStatements`.
171
+ *
172
+ * Exported for statement-ordering tests; it is not part of the package's
173
+ * public entry point (`migrations/index.ts` re-exports names explicitly).
174
+ *
175
+ * @param diff - Schema diff to materialize.
176
+ * @param db - Database whose URL selects the DDL strategy.
177
+ * @param engineHint - Explicit engine when `db.url` is empty or ambiguous.
178
+ * @returns Ordered, executable DDL statements.
179
+ */
180
+ export declare function collectStatementsFromDiff(diff: Awaited<ReturnType<typeof generateSchemaDiff>>, db: DatabaseInterface, engineHint?: DatabaseEngine): string[];
158
181
  //# sourceMappingURL=orchestrate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrate.d.ts","sourceRoot":"","sources":["../../src/migrations/orchestrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EACL,kBAAkB,EAGnB,MAAM,aAAa,CAAC;AAOrB,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,iBAAiB,CAAC;IACtB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wFAAwF;IACxF,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;OAGG;IACH,0BAA0B,CAAC,EAAE;QAAE,cAAc,EAAE,KAAK,CAAA;KAAE,CAAC;CACxD;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,mBAAmB,EAAE,YAAY,EAAE,CAAC;IACpC;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;;OAOG;IACH,mBAAmB,EAAE,YAAY,EAAE,CAAC;IACpC;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,0BAA0B,CAAC,EAAE;QAAE,cAAc,EAAE,KAAK,CAAA;KAAE,CAAC;CACnD,GACL,OAAO,CAAC,6BAA6B,CAAC,CAqBxC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CA0DnC"}
1
+ {"version":3,"file":"orchestrate.d.ts","sourceRoot":"","sources":["../../src/migrations/orchestrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EACL,kBAAkB,EAGnB,MAAM,aAAa,CAAC;AAOrB,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,iBAAiB,CAAC;IACtB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wFAAwF;IACxF,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;OAGG;IACH,0BAA0B,CAAC,EAAE;QAAE,cAAc,EAAE,KAAK,CAAA;KAAE,CAAC;CACxD;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,mBAAmB,EAAE,YAAY,EAAE,CAAC;IACpC;;;;;OAKG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;;OAOG;IACH,mBAAmB,EAAE,YAAY,EAAE,CAAC;IACpC;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE;IACP,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,0BAA0B,CAAC,EAAE;QAAE,cAAc,EAAE,KAAK,CAAA;KAAE,CAAC;CACnD,GACL,OAAO,CAAC,6BAA6B,CAAC,CAqBxC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CA0DnC;AAcD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,EACpD,EAAE,EAAE,iBAAiB,EACrB,UAAU,CAAC,EAAE,cAAc,GAC1B,MAAM,EAAE,CAwCV"}
@@ -1,7 +1,7 @@
1
1
  import { detectEngine, getDDLStrategy } from "../schema/ddl/index.js";
2
2
  import { ObjectRegistry } from "../registry.js";
3
3
  import { planForeignKeyCreation } from "../schema/foreign-key-planner.js";
4
- import { generateSchemaDiff, getSQLFromDiff, hasActionableChanges } from "./differ.js";
4
+ import { generateSchemaDiff, getSQLFromChanges, hasActionableChanges } from "./differ.js";
5
5
  import { createMigrationDefinition, generateMigrationTimestamp } from "./generator.js";
6
6
  import { MigrationTracker } from "./tracker.js";
7
7
  //#region src/migrations/orchestrate.ts
@@ -135,18 +135,27 @@ function resolveDatabaseUrl(db) {
135
135
  * Column/index/trigger changes for existing tables continue to come from
136
136
  * `getSQLFromDiff`, which is already engine-aware via the differ's per-
137
137
  * change `sqlStatements`.
138
+ *
139
+ * Exported for statement-ordering tests; it is not part of the package's
140
+ * public entry point (`migrations/index.ts` re-exports names explicitly).
141
+ *
142
+ * @param diff - Schema diff to materialize.
143
+ * @param db - Database whose URL selects the DDL strategy.
144
+ * @param engineHint - Explicit engine when `db.url` is empty or ambiguous.
145
+ * @returns Ordered, executable DDL statements.
138
146
  */
139
147
  function collectStatementsFromDiff(diff, db, engineHint) {
140
148
  const strategy = getDDLStrategy(detectEngine(resolveDatabaseUrl(db), engineHint));
141
149
  const statements = [];
142
150
  const tablePlan = planForeignKeyCreation(diff.added_tables, strategy.engine);
151
+ statements.push(...getSQLFromChanges(diff.changes.filter((change) => change.phase === "pre_foreign_key")));
143
152
  for (const schema of tablePlan.schemas) {
144
153
  statements.push(strategy.generateCreateTable(schema));
145
154
  statements.push(...strategy.generateIndexes(schema));
146
155
  statements.push(...strategy.generateTriggers(schema));
147
156
  }
148
157
  statements.push(...tablePlan.deferredStatements);
149
- statements.push(...getSQLFromDiff(diff));
158
+ statements.push(...getSQLFromChanges(diff.changes.filter((change) => change.phase !== "pre_foreign_key")));
150
159
  return statements.filter((statement) => {
151
160
  const trimmed = statement.trim();
152
161
  if (trimmed.length === 0) return false;
@@ -216,6 +225,6 @@ function collectUnactionableChanges(diff) {
216
225
  return unactionable;
217
226
  }
218
227
  //#endregion
219
- export { getPendingSchemaStatements, migrateSmrtSchemas };
228
+ export { collectStatementsFromDiff, getPendingSchemaStatements, migrateSmrtSchemas };
220
229
 
221
230
  //# sourceMappingURL=orchestrate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrate.js","names":[],"sources":["../../src/migrations/orchestrate.ts"],"sourcesContent":["/**\n * High-level \"make my SMRT app's schema match its database\" orchestration.\n *\n * Wraps `ObjectRegistry.getAllSchemasAsDefinitions()` → `generateSchemaDiff`\n * → `MigrationTracker.applyAll`. Apps that just want to run pending\n * schema changes call `migrateSmrtSchemas({ db, packageName, version })`\n * and don't have to assemble the migration definition by hand.\n *\n * The migration name is timestamped, so re-running on an up-to-date\n * database is a no-op (the diff is empty, no statements are generated,\n * `applied: false` is returned).\n */\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ObjectRegistry } from '../registry.js';\nimport { detectEngine, getDDLStrategy } from '../schema/ddl/index.js';\nimport type { DatabaseEngine } from '../schema/ddl/types.js';\nimport { planForeignKeyCreation } from '../schema/foreign-key-planner.js';\nimport type { MigrationResult, SchemaChange } from '../schema/types.js';\nimport {\n generateSchemaDiff,\n getSQLFromDiff,\n hasActionableChanges,\n} from './differ.js';\nimport {\n createMigrationDefinition,\n generateMigrationTimestamp,\n} from './generator.js';\nimport { MigrationTracker } from './tracker.js';\n\nexport interface MigrateSmrtSchemasOptions {\n db: DatabaseInterface;\n /** Stored on the migration record so the audit log shows which app applied it. */\n packageName: string;\n /**\n * Stored on the migration record. Typically the app's package.json\n * version. Optional because most apps don't have a runtime-readable\n * version handy and would hardcode a stale string if forced to supply\n * one — `'unknown'` is honest. Pass an explicit value when you can\n * (e.g. `version: process.env.APP_VERSION`).\n */\n version?: string;\n /** Override the description on the synthetic migration definition. */\n description?: string;\n /** Override the migration name (default: `<timestamp>_smrt_schema_sync`). */\n name?: string;\n /** Forwarded to MigrationTracker — defaults to true for pg-safe runs. */\n postgresSafe?: boolean;\n /** Forwarded to MigrationTracker — defaults to true. */\n reconcile?: boolean;\n /** Forwarded to MigrationTracker — defaults to true for `CREATE INDEX CONCURRENTLY`. */\n useConcurrentIndexes?: boolean;\n /**\n * Forwarded to MigrationTracker (Postgres lock timeout, milliseconds).\n * Lets apps that customize tracker timeouts directly preserve their\n * tuning when going through the orchestrator. Falls back to the\n * tracker's default (30000ms) when omitted.\n */\n lockTimeout?: number;\n /**\n * Forwarded to MigrationTracker (Postgres statement timeout, ms). Falls\n * back to the tracker's default (60000ms) when omitted.\n */\n statementTimeout?: number;\n /**\n * Explicit engine hint forwarded to `detectEngine`, `SchemaComparer`, and\n * `MigrationTracker`. Useful when `db.url` doesn't unambiguously identify\n * the engine (e.g. the JSON adapter, which uses DuckDB internally and may\n * not be recognizable by URL alone). All three layers honor the same hint\n * so the generated DDL, drift comparison, and execution path stay\n * consistent — without it, an empty-URL connection could produce\n * Postgres-flavored DDL but run through the SQLite tracker path.\n *\n * Typed as `DatabaseEngine` so unsupported values (e.g. `'mysql'`) fail at\n * compile time rather than silently falling back to `'sqlite'` at runtime.\n */\n engineHint?: DatabaseEngine;\n /**\n * Confirm that historical PostgreSQL Date writers used UTC wall times before\n * reinterpreting legacy TIMESTAMP/TEXT/JSON columns as TIMESTAMPTZ.\n */\n postgresTimestampMigration?: { legacyTimezone: 'UTC' };\n}\n\nexport interface MigrateSmrtSchemasResult {\n applied: boolean;\n results: MigrationResult[];\n statements: string[];\n schemaCount: number;\n /**\n * Schema changes the orchestrator detected but cannot apply automatically\n * (incompatible type mismatches, SQLite type upgrades that require table\n * recreation, etc.). Empty when the schema is fully reconciled. Inspect\n * this to surface a \"manual migration required\" warning in CLI output.\n */\n unactionableChanges: SchemaChange[];\n /**\n * Convenience: `unactionableChanges.length > 0`. Lets a caller write\n * `if (result.hasManualDrift) ...` without iterating the array first,\n * and makes the case visible to anyone scanning the result shape (the\n * full array is easy to gloss over when `applied: false`).\n */\n hasManualDrift: boolean;\n}\n\nexport interface PendingSchemaStatementsResult {\n diff: Awaited<ReturnType<typeof generateSchemaDiff>>;\n statements: string[];\n schemaCount: number;\n hasChanges: boolean;\n /**\n * Schema changes the differ detected but that have no executable SQL\n * (incompatible `type_mismatch` entries, or `type_upgrade` entries whose\n * only generated SQL is an advisory comment because the engine cannot\n * upgrade the column in place — e.g. SQLite type widening). Surfacing\n * these lets status commands distinguish \"no drift\" from \"drift the\n * orchestrator can't fix on its own.\"\n */\n unactionableChanges: SchemaChange[];\n /**\n * Convenience: `unactionableChanges.length > 0`. Mirrors the\n * `MigrateSmrtSchemasResult.hasManualDrift` shortcut.\n */\n hasManualDrift: boolean;\n}\n\n/**\n * Compute the SQL statements needed to bring `db` in sync with the\n * currently-registered SMRT object schemas. Pure inspection — no writes.\n *\n * Useful for status commands (\"how far behind is the schema?\") and as the\n * inner step of `migrateSmrtSchemas`.\n *\n * **Note on the returned `statements`:** these are the engine-correct DDL\n * statements as the differ + DDL strategy produce them, *prior to* any\n * Postgres-specific rewrites the `MigrationTracker` applies at execution\n * time (e.g. rewriting `CREATE INDEX` → `CREATE INDEX CONCURRENTLY` and\n * moving CONCURRENTLY statements outside the surrounding transaction).\n * The list is suitable for preview/status/\"what would change?\" use cases.\n * For the exact byte-for-byte SQL the tracker ran, inspect the\n * `MigrationResult`s from `migrateSmrtSchemas` or the tracker's own logs.\n */\nexport async function getPendingSchemaStatements(\n db: DatabaseInterface,\n options: {\n engineHint?: DatabaseEngine;\n postgresTimestampMigration?: { legacyTimezone: 'UTC' };\n } = {},\n): Promise<PendingSchemaStatementsResult> {\n const schemas = ObjectRegistry.getAllSchemasAsDefinitions();\n // Forward engineHint into the diff itself so the SchemaComparer's\n // existing-table SQL (ALTER/index drift) uses the same DDL strategy\n // we use for newly-added tables — otherwise the two halves of the\n // statement list can land on different engines (split-brain) when\n // `db.url` is empty or ambiguous.\n const diff = await generateSchemaDiff(db, schemas, {\n engineHint: options.engineHint,\n postgresTimestampMigration: options.postgresTimestampMigration,\n });\n const statements = collectStatementsFromDiff(diff, db, options.engineHint);\n const unactionableChanges = collectUnactionableChanges(diff);\n return {\n diff,\n schemaCount: Object.keys(schemas).length,\n statements,\n hasChanges: hasActionableChanges(diff),\n unactionableChanges,\n hasManualDrift: unactionableChanges.length > 0,\n };\n}\n\n/**\n * Apply any pending schema changes from `ObjectRegistry` to `db`.\n *\n * Returns `applied: false` (with no error) if the database is already in\n * sync. Throws on the first migration failure with the underlying error\n * preserved (callers should let it propagate to the CLI).\n *\n * **Note on the returned `statements`:** mirrors `getPendingSchemaStatements`\n * — the list is the planned DDL, prior to Postgres-specific tracker rewrites\n * (CONCURRENTLY, transaction reordering). The actual executed SQL is\n * tracked in the returned `results`.\n *\n * **Note on `applied` semantics under `reconcile: true` (the default):**\n * the tracker may re-execute a migration that is already in `completed`\n * state when the checksum matches — that counts as `applied: true` in the\n * returned `MigrationResult`. So `result.applied === true` means \"the\n * tracker ran the migration\", not specifically \"the database changed for\n * the first time.\" Pass `reconcile: false` if you need to distinguish a\n * fresh apply from a reconcile-replay over an existing completed record.\n *\n * **Note on repeated failures:** the migration name defaults to a fresh\n * timestamp on every call, so a sequence of failed runs leaves one\n * `failed` row in `_smrt_schema_migrations` per attempt. Pass an explicit\n * `name` if you want to overwrite the same record across retries.\n *\n * **Note on `unactionableChanges`:** the differ can detect schema drift\n * the migration step can't auto-resolve — incompatible type mismatches,\n * SQLite type widening that needs table recreation, etc. Those changes\n * appear in `result.unactionableChanges` and are NOT applied (the\n * statements list is filtered to executable DDL only). When the diff\n * contains *only* unactionable changes, the function returns\n * `applied: false` with a populated `unactionableChanges` so callers can\n * surface a \"manual migration required\" signal. Without inspecting that\n * field, the result would look indistinguishable from \"already in sync.\"\n */\nexport async function migrateSmrtSchemas(\n options: MigrateSmrtSchemasOptions,\n): Promise<MigrateSmrtSchemasResult> {\n const pending = await getPendingSchemaStatements(options.db, {\n engineHint: options.engineHint,\n postgresTimestampMigration: options.postgresTimestampMigration,\n });\n if (!pending.hasChanges || pending.statements.length === 0) {\n return {\n applied: false,\n results: [],\n statements: [],\n schemaCount: pending.schemaCount,\n unactionableChanges: pending.unactionableChanges,\n hasManualDrift: pending.hasManualDrift,\n };\n }\n\n const tracker = new MigrationTracker({\n db: options.db,\n engineHint: options.engineHint,\n lockTimeout: options.lockTimeout,\n statementTimeout: options.statementTimeout,\n useConcurrentIndexes: options.useConcurrentIndexes ?? true,\n });\n const migration = createMigrationDefinition(\n options.name ?? `${generateMigrationTimestamp()}_smrt_schema_sync`,\n pending.statements,\n [],\n {\n description: options.description ?? 'Synchronize SMRT object schemas',\n packageName: options.packageName,\n version: options.version ?? 'unknown',\n },\n );\n\n const results = await tracker.applyAll([migration], {\n postgresSafe: options.postgresSafe ?? true,\n reconcile: options.reconcile ?? true,\n });\n\n const failed = results.find((result) => !result.success);\n if (failed) {\n throw failed.error instanceof Error\n ? failed.error\n : new Error(String(failed.error ?? `Migration ${failed.name} failed`));\n }\n\n const applied = results.some(\n (result) => result.applied !== false && result.skipped !== true,\n );\n\n return {\n applied,\n results,\n statements: pending.statements,\n schemaCount: pending.schemaCount,\n unactionableChanges: pending.unactionableChanges,\n hasManualDrift: pending.hasManualDrift,\n };\n}\n\n/** Mirror of the `getDatabaseUrl` helper in class.ts — some adapters\n * (JSON, certain in-memory wrappers) leave `db.url` undefined and expose\n * the URL on `db.config?.url` instead. Detecting the engine from a raw\n * `db.url` would throw or silently fall through to the sqlite default.\n */\nfunction resolveDatabaseUrl(db: DatabaseInterface): string {\n const dbWithConfig = db as DatabaseInterface & {\n config?: { url?: string };\n };\n return db.url || dbWithConfig.config?.url || '';\n}\n\n/**\n * Materialize the diff into the engine-correct SQL statements.\n *\n * For new tables we delegate to the engine's `DDLStrategy` so column types\n * (`REAL` → `DOUBLE PRECISION` on Postgres, `JSON` → `JSONB`, etc.),\n * partial-index `WHERE` clauses, and trigger syntax all match what the\n * SchemaComparer would expect on subsequent runs. Emitting the raw\n * abstract `SchemaDefinition.ddl` here would cause immediate type-drift\n * migrations on Postgres/DuckDB.\n *\n * Column/index/trigger changes for existing tables continue to come from\n * `getSQLFromDiff`, which is already engine-aware via the differ's per-\n * change `sqlStatements`.\n */\nfunction collectStatementsFromDiff(\n diff: Awaited<ReturnType<typeof generateSchemaDiff>>,\n db: DatabaseInterface,\n engineHint?: DatabaseEngine,\n): string[] {\n const strategy = getDDLStrategy(\n detectEngine(resolveDatabaseUrl(db), engineHint),\n );\n const statements: string[] = [];\n const tablePlan = planForeignKeyCreation(diff.added_tables, strategy.engine);\n for (const schema of tablePlan.schemas) {\n statements.push(strategy.generateCreateTable(schema));\n statements.push(...strategy.generateIndexes(schema));\n statements.push(...strategy.generateTriggers(schema));\n }\n statements.push(...tablePlan.deferredStatements);\n statements.push(...getSQLFromDiff(diff));\n // Drop empty and comment-only entries. SQLite type-widening upgrades\n // surface as `-- SQLite: Type upgrade for X requires table recreation`\n // — passing those through to the tracker records a successful migration\n // without actually fixing the column, so the same drift re-appears on\n // every subsequent run. Those changes are surfaced separately via\n // `unactionableChanges` so callers can prompt for manual remediation.\n return statements.filter((statement) => {\n const trimmed = statement.trim();\n if (trimmed.length === 0) return false;\n return !isCommentOnlySql(trimmed);\n });\n}\n\n/**\n * True if `sql` contains no executable DDL — only line comments (`--`)\n * and/or block comments (`/* … *​/`). Used to discard advisory comments\n * the differ emits when a column upgrade can't be performed in place\n * (e.g. SQLite type widening). Defensive: strips block comments first so\n * a future differ that emits `/* type_upgrade: no-op *​/` doesn't slip\n * through.\n */\nfunction isCommentOnlySql(sql: string): boolean {\n // Strip /* ... */ block comments (non-greedy, spans newlines).\n const withoutBlockComments = sql.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n const lines = withoutBlockComments\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n if (lines.length === 0) return sql.trim().length > 0;\n return lines.every((line) => line.startsWith('--'));\n}\n\n/**\n * True if `sql` is an advisory comment that says *nothing needs to happen* —\n * as opposed to one that says a human has to act.\n *\n * The differ emits both kinds. \"This SQLite column already stores JSON as\n * TEXT\" and \"#2370: this column is rebuilt together with its sibling\" are\n * no-ops; \"requires table recreation\" / \"blocked: …\" are real manual drift.\n * Treating the first kind as drift makes a fully auto-repairable migration\n * report `hasManualDrift: true`.\n *\n * Keep in sync with `classifyTypeUpgradeSql`'s `noop` arm in\n * `@happyvertical/smrt-cli` (`src/commands/db-migrate-actions.ts`), which\n * applies the same rule on the CLI side.\n */\nfunction isNoOpAdvisorySql(sql: string): boolean {\n const trimmed = sql.trim();\n return (\n /no change needed/i.test(trimmed) || /already stores .* as /i.test(trimmed)\n );\n}\n\n/**\n * Surface changes the differ produced but that the migrator cannot apply\n * automatically — `type_mismatch` entries (the differ explicitly gives up on\n * these), `type_upgrade`/`alter_column` entries whose generated SQL is\n * advisory-comment-only (a SQLite rebuild that would be unsafe, an in-place\n * constraint change SQLite cannot perform), and warning-level report-only\n * advisories (an orphan NOT NULL column that will break inserts, a required\n * column that could not be enforced, a stale unique constraint, a relaxation\n * the caller has not opted into). Info-level advisories (a harmless orphan\n * column, a stale default) and comments that mean \"already handled\" (the\n * no-op advisories a table rebuild leaves on covered siblings, #2370) are\n * deliberately excluded so `hasManualDrift` keeps meaning \"something needs\n * an operator\". Callers use this to distinguish \"schema is in sync\" from\n * \"schema is drifted but we can't fix it from here\".\n */\nfunction collectUnactionableChanges(\n diff: Awaited<ReturnType<typeof generateSchemaDiff>>,\n): SchemaChange[] {\n const unactionable: SchemaChange[] = [];\n for (const change of diff.changes) {\n if (change.type === 'type_mismatch') {\n unactionable.push(change);\n continue;\n }\n const statements = change.sqlStatements ?? (change.sql ? [change.sql] : []);\n if (statements.length === 0) {\n if (change.advisory?.severity === 'warning') {\n unactionable.push(change);\n }\n continue;\n }\n if (\n statements.every((stmt) => isCommentOnlySql(stmt.trim())) &&\n !statements.every((stmt) => isNoOpAdvisorySql(stmt))\n ) {\n unactionable.push(change);\n }\n }\n return unactionable;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orchestrate.js","names":[],"sources":["../../src/migrations/orchestrate.ts"],"sourcesContent":["/**\n * High-level \"make my SMRT app's schema match its database\" orchestration.\n *\n * Wraps `ObjectRegistry.getAllSchemasAsDefinitions()` → `generateSchemaDiff`\n * → `MigrationTracker.applyAll`. Apps that just want to run pending\n * schema changes call `migrateSmrtSchemas({ db, packageName, version })`\n * and don't have to assemble the migration definition by hand.\n *\n * The migration name is timestamped, so re-running on an up-to-date\n * database is a no-op (the diff is empty, no statements are generated,\n * `applied: false` is returned).\n */\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { ObjectRegistry } from '../registry.js';\nimport { detectEngine, getDDLStrategy } from '../schema/ddl/index.js';\nimport type { DatabaseEngine } from '../schema/ddl/types.js';\nimport { planForeignKeyCreation } from '../schema/foreign-key-planner.js';\nimport type { MigrationResult, SchemaChange } from '../schema/types.js';\nimport {\n generateSchemaDiff,\n getSQLFromChanges,\n hasActionableChanges,\n} from './differ.js';\nimport {\n createMigrationDefinition,\n generateMigrationTimestamp,\n} from './generator.js';\nimport { MigrationTracker } from './tracker.js';\n\nexport interface MigrateSmrtSchemasOptions {\n db: DatabaseInterface;\n /** Stored on the migration record so the audit log shows which app applied it. */\n packageName: string;\n /**\n * Stored on the migration record. Typically the app's package.json\n * version. Optional because most apps don't have a runtime-readable\n * version handy and would hardcode a stale string if forced to supply\n * one — `'unknown'` is honest. Pass an explicit value when you can\n * (e.g. `version: process.env.APP_VERSION`).\n */\n version?: string;\n /** Override the description on the synthetic migration definition. */\n description?: string;\n /** Override the migration name (default: `<timestamp>_smrt_schema_sync`). */\n name?: string;\n /** Forwarded to MigrationTracker — defaults to true for pg-safe runs. */\n postgresSafe?: boolean;\n /** Forwarded to MigrationTracker — defaults to true. */\n reconcile?: boolean;\n /** Forwarded to MigrationTracker — defaults to true for `CREATE INDEX CONCURRENTLY`. */\n useConcurrentIndexes?: boolean;\n /**\n * Forwarded to MigrationTracker (Postgres lock timeout, milliseconds).\n * Lets apps that customize tracker timeouts directly preserve their\n * tuning when going through the orchestrator. Falls back to the\n * tracker's default (30000ms) when omitted.\n */\n lockTimeout?: number;\n /**\n * Forwarded to MigrationTracker (Postgres statement timeout, ms). Falls\n * back to the tracker's default (60000ms) when omitted.\n */\n statementTimeout?: number;\n /**\n * Explicit engine hint forwarded to `detectEngine`, `SchemaComparer`, and\n * `MigrationTracker`. Useful when `db.url` doesn't unambiguously identify\n * the engine (e.g. the JSON adapter, which uses DuckDB internally and may\n * not be recognizable by URL alone). All three layers honor the same hint\n * so the generated DDL, drift comparison, and execution path stay\n * consistent — without it, an empty-URL connection could produce\n * Postgres-flavored DDL but run through the SQLite tracker path.\n *\n * Typed as `DatabaseEngine` so unsupported values (e.g. `'mysql'`) fail at\n * compile time rather than silently falling back to `'sqlite'` at runtime.\n */\n engineHint?: DatabaseEngine;\n /**\n * Confirm that historical PostgreSQL Date writers used UTC wall times before\n * reinterpreting legacy TIMESTAMP/TEXT/JSON columns as TIMESTAMPTZ.\n */\n postgresTimestampMigration?: { legacyTimezone: 'UTC' };\n}\n\nexport interface MigrateSmrtSchemasResult {\n applied: boolean;\n results: MigrationResult[];\n statements: string[];\n schemaCount: number;\n /**\n * Schema changes the orchestrator detected but cannot apply automatically\n * (incompatible type mismatches, SQLite type upgrades that require table\n * recreation, etc.). Empty when the schema is fully reconciled. Inspect\n * this to surface a \"manual migration required\" warning in CLI output.\n */\n unactionableChanges: SchemaChange[];\n /**\n * Convenience: `unactionableChanges.length > 0`. Lets a caller write\n * `if (result.hasManualDrift) ...` without iterating the array first,\n * and makes the case visible to anyone scanning the result shape (the\n * full array is easy to gloss over when `applied: false`).\n */\n hasManualDrift: boolean;\n}\n\nexport interface PendingSchemaStatementsResult {\n diff: Awaited<ReturnType<typeof generateSchemaDiff>>;\n statements: string[];\n schemaCount: number;\n hasChanges: boolean;\n /**\n * Schema changes the differ detected but that have no executable SQL\n * (incompatible `type_mismatch` entries, or `type_upgrade` entries whose\n * only generated SQL is an advisory comment because the engine cannot\n * upgrade the column in place — e.g. SQLite type widening). Surfacing\n * these lets status commands distinguish \"no drift\" from \"drift the\n * orchestrator can't fix on its own.\"\n */\n unactionableChanges: SchemaChange[];\n /**\n * Convenience: `unactionableChanges.length > 0`. Mirrors the\n * `MigrateSmrtSchemasResult.hasManualDrift` shortcut.\n */\n hasManualDrift: boolean;\n}\n\n/**\n * Compute the SQL statements needed to bring `db` in sync with the\n * currently-registered SMRT object schemas. Pure inspection — no writes.\n *\n * Useful for status commands (\"how far behind is the schema?\") and as the\n * inner step of `migrateSmrtSchemas`.\n *\n * **Note on the returned `statements`:** these are the engine-correct DDL\n * statements as the differ + DDL strategy produce them, *prior to* any\n * Postgres-specific rewrites the `MigrationTracker` applies at execution\n * time (e.g. rewriting `CREATE INDEX` → `CREATE INDEX CONCURRENTLY` and\n * moving CONCURRENTLY statements outside the surrounding transaction).\n * The list is suitable for preview/status/\"what would change?\" use cases.\n * For the exact byte-for-byte SQL the tracker ran, inspect the\n * `MigrationResult`s from `migrateSmrtSchemas` or the tracker's own logs.\n */\nexport async function getPendingSchemaStatements(\n db: DatabaseInterface,\n options: {\n engineHint?: DatabaseEngine;\n postgresTimestampMigration?: { legacyTimezone: 'UTC' };\n } = {},\n): Promise<PendingSchemaStatementsResult> {\n const schemas = ObjectRegistry.getAllSchemasAsDefinitions();\n // Forward engineHint into the diff itself so the SchemaComparer's\n // existing-table SQL (ALTER/index drift) uses the same DDL strategy\n // we use for newly-added tables — otherwise the two halves of the\n // statement list can land on different engines (split-brain) when\n // `db.url` is empty or ambiguous.\n const diff = await generateSchemaDiff(db, schemas, {\n engineHint: options.engineHint,\n postgresTimestampMigration: options.postgresTimestampMigration,\n });\n const statements = collectStatementsFromDiff(diff, db, options.engineHint);\n const unactionableChanges = collectUnactionableChanges(diff);\n return {\n diff,\n schemaCount: Object.keys(schemas).length,\n statements,\n hasChanges: hasActionableChanges(diff),\n unactionableChanges,\n hasManualDrift: unactionableChanges.length > 0,\n };\n}\n\n/**\n * Apply any pending schema changes from `ObjectRegistry` to `db`.\n *\n * Returns `applied: false` (with no error) if the database is already in\n * sync. Throws on the first migration failure with the underlying error\n * preserved (callers should let it propagate to the CLI).\n *\n * **Note on the returned `statements`:** mirrors `getPendingSchemaStatements`\n * — the list is the planned DDL, prior to Postgres-specific tracker rewrites\n * (CONCURRENTLY, transaction reordering). The actual executed SQL is\n * tracked in the returned `results`.\n *\n * **Note on `applied` semantics under `reconcile: true` (the default):**\n * the tracker may re-execute a migration that is already in `completed`\n * state when the checksum matches — that counts as `applied: true` in the\n * returned `MigrationResult`. So `result.applied === true` means \"the\n * tracker ran the migration\", not specifically \"the database changed for\n * the first time.\" Pass `reconcile: false` if you need to distinguish a\n * fresh apply from a reconcile-replay over an existing completed record.\n *\n * **Note on repeated failures:** the migration name defaults to a fresh\n * timestamp on every call, so a sequence of failed runs leaves one\n * `failed` row in `_smrt_schema_migrations` per attempt. Pass an explicit\n * `name` if you want to overwrite the same record across retries.\n *\n * **Note on `unactionableChanges`:** the differ can detect schema drift\n * the migration step can't auto-resolve — incompatible type mismatches,\n * SQLite type widening that needs table recreation, etc. Those changes\n * appear in `result.unactionableChanges` and are NOT applied (the\n * statements list is filtered to executable DDL only). When the diff\n * contains *only* unactionable changes, the function returns\n * `applied: false` with a populated `unactionableChanges` so callers can\n * surface a \"manual migration required\" signal. Without inspecting that\n * field, the result would look indistinguishable from \"already in sync.\"\n */\nexport async function migrateSmrtSchemas(\n options: MigrateSmrtSchemasOptions,\n): Promise<MigrateSmrtSchemasResult> {\n const pending = await getPendingSchemaStatements(options.db, {\n engineHint: options.engineHint,\n postgresTimestampMigration: options.postgresTimestampMigration,\n });\n if (!pending.hasChanges || pending.statements.length === 0) {\n return {\n applied: false,\n results: [],\n statements: [],\n schemaCount: pending.schemaCount,\n unactionableChanges: pending.unactionableChanges,\n hasManualDrift: pending.hasManualDrift,\n };\n }\n\n const tracker = new MigrationTracker({\n db: options.db,\n engineHint: options.engineHint,\n lockTimeout: options.lockTimeout,\n statementTimeout: options.statementTimeout,\n useConcurrentIndexes: options.useConcurrentIndexes ?? true,\n });\n const migration = createMigrationDefinition(\n options.name ?? `${generateMigrationTimestamp()}_smrt_schema_sync`,\n pending.statements,\n [],\n {\n description: options.description ?? 'Synchronize SMRT object schemas',\n packageName: options.packageName,\n version: options.version ?? 'unknown',\n },\n );\n\n const results = await tracker.applyAll([migration], {\n postgresSafe: options.postgresSafe ?? true,\n reconcile: options.reconcile ?? true,\n });\n\n const failed = results.find((result) => !result.success);\n if (failed) {\n throw failed.error instanceof Error\n ? failed.error\n : new Error(String(failed.error ?? `Migration ${failed.name} failed`));\n }\n\n const applied = results.some(\n (result) => result.applied !== false && result.skipped !== true,\n );\n\n return {\n applied,\n results,\n statements: pending.statements,\n schemaCount: pending.schemaCount,\n unactionableChanges: pending.unactionableChanges,\n hasManualDrift: pending.hasManualDrift,\n };\n}\n\n/** Mirror of the `getDatabaseUrl` helper in class.ts — some adapters\n * (JSON, certain in-memory wrappers) leave `db.url` undefined and expose\n * the URL on `db.config?.url` instead. Detecting the engine from a raw\n * `db.url` would throw or silently fall through to the sqlite default.\n */\nfunction resolveDatabaseUrl(db: DatabaseInterface): string {\n const dbWithConfig = db as DatabaseInterface & {\n config?: { url?: string };\n };\n return db.url || dbWithConfig.config?.url || '';\n}\n\n/**\n * Materialize the diff into the engine-correct SQL statements.\n *\n * For new tables we delegate to the engine's `DDLStrategy` so column types\n * (`REAL` → `DOUBLE PRECISION` on Postgres, `JSON` → `JSONB`, etc.),\n * partial-index `WHERE` clauses, and trigger syntax all match what the\n * SchemaComparer would expect on subsequent runs. Emitting the raw\n * abstract `SchemaDefinition.ddl` here would cause immediate type-drift\n * migrations on Postgres/DuckDB.\n *\n * Column/index/trigger changes for existing tables continue to come from\n * `getSQLFromDiff`, which is already engine-aware via the differ's per-\n * change `sqlStatements`.\n *\n * Exported for statement-ordering tests; it is not part of the package's\n * public entry point (`migrations/index.ts` re-exports names explicitly).\n *\n * @param diff - Schema diff to materialize.\n * @param db - Database whose URL selects the DDL strategy.\n * @param engineHint - Explicit engine when `db.url` is empty or ambiguous.\n * @returns Ordered, executable DDL statements.\n */\nexport function collectStatementsFromDiff(\n diff: Awaited<ReturnType<typeof generateSchemaDiff>>,\n db: DatabaseInterface,\n engineHint?: DatabaseEngine,\n): string[] {\n const strategy = getDDLStrategy(\n detectEngine(resolveDatabaseUrl(db), engineHint),\n );\n const statements: string[] = [];\n const tablePlan = planForeignKeyCreation(diff.added_tables, strategy.engine);\n // #2608: the pre-R11 uuid convergence has to precede *every* foreign-key\n // statement. `planForeignKeyCreation` only defers the constraints inside a\n // mutual cycle, so an acyclic new child table keeps its FK **inline in\n // CREATE TABLE** — a fresh `uuid` child pointing at a legacy `text` parent\n // would fail with SQLSTATE 42804 before the parent could be converted.\n // Conversions only ever rewrite columns that already exist, so they are\n // safe to run ahead of every CREATE TABLE in this batch.\n statements.push(\n ...getSQLFromChanges(\n diff.changes.filter((change) => change.phase === 'pre_foreign_key'),\n ),\n );\n for (const schema of tablePlan.schemas) {\n statements.push(strategy.generateCreateTable(schema));\n statements.push(...strategy.generateIndexes(schema));\n statements.push(...strategy.generateTriggers(schema));\n }\n statements.push(...tablePlan.deferredStatements);\n statements.push(\n ...getSQLFromChanges(\n diff.changes.filter((change) => change.phase !== 'pre_foreign_key'),\n ),\n );\n // Drop empty and comment-only entries. SQLite type-widening upgrades\n // surface as `-- SQLite: Type upgrade for X requires table recreation`\n // — passing those through to the tracker records a successful migration\n // without actually fixing the column, so the same drift re-appears on\n // every subsequent run. Those changes are surfaced separately via\n // `unactionableChanges` so callers can prompt for manual remediation.\n return statements.filter((statement) => {\n const trimmed = statement.trim();\n if (trimmed.length === 0) return false;\n return !isCommentOnlySql(trimmed);\n });\n}\n\n/**\n * True if `sql` contains no executable DDL — only line comments (`--`)\n * and/or block comments (`/* … *​/`). Used to discard advisory comments\n * the differ emits when a column upgrade can't be performed in place\n * (e.g. SQLite type widening). Defensive: strips block comments first so\n * a future differ that emits `/* type_upgrade: no-op *​/` doesn't slip\n * through.\n */\nfunction isCommentOnlySql(sql: string): boolean {\n // Strip /* ... */ block comments (non-greedy, spans newlines).\n const withoutBlockComments = sql.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n const lines = withoutBlockComments\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n if (lines.length === 0) return sql.trim().length > 0;\n return lines.every((line) => line.startsWith('--'));\n}\n\n/**\n * True if `sql` is an advisory comment that says *nothing needs to happen* —\n * as opposed to one that says a human has to act.\n *\n * The differ emits both kinds. \"This SQLite column already stores JSON as\n * TEXT\" and \"#2370: this column is rebuilt together with its sibling\" are\n * no-ops; \"requires table recreation\" / \"blocked: …\" are real manual drift.\n * Treating the first kind as drift makes a fully auto-repairable migration\n * report `hasManualDrift: true`.\n *\n * Keep in sync with `classifyTypeUpgradeSql`'s `noop` arm in\n * `@happyvertical/smrt-cli` (`src/commands/db-migrate-actions.ts`), which\n * applies the same rule on the CLI side.\n */\nfunction isNoOpAdvisorySql(sql: string): boolean {\n const trimmed = sql.trim();\n return (\n /no change needed/i.test(trimmed) || /already stores .* as /i.test(trimmed)\n );\n}\n\n/**\n * Surface changes the differ produced but that the migrator cannot apply\n * automatically — `type_mismatch` entries (the differ explicitly gives up on\n * these), `type_upgrade`/`alter_column` entries whose generated SQL is\n * advisory-comment-only (a SQLite rebuild that would be unsafe, an in-place\n * constraint change SQLite cannot perform), and warning-level report-only\n * advisories (an orphan NOT NULL column that will break inserts, a required\n * column that could not be enforced, a stale unique constraint, a relaxation\n * the caller has not opted into). Info-level advisories (a harmless orphan\n * column, a stale default) and comments that mean \"already handled\" (the\n * no-op advisories a table rebuild leaves on covered siblings, #2370) are\n * deliberately excluded so `hasManualDrift` keeps meaning \"something needs\n * an operator\". Callers use this to distinguish \"schema is in sync\" from\n * \"schema is drifted but we can't fix it from here\".\n */\nfunction collectUnactionableChanges(\n diff: Awaited<ReturnType<typeof generateSchemaDiff>>,\n): SchemaChange[] {\n const unactionable: SchemaChange[] = [];\n for (const change of diff.changes) {\n if (change.type === 'type_mismatch') {\n unactionable.push(change);\n continue;\n }\n const statements = change.sqlStatements ?? (change.sql ? [change.sql] : []);\n if (statements.length === 0) {\n if (change.advisory?.severity === 'warning') {\n unactionable.push(change);\n }\n continue;\n }\n if (\n statements.every((stmt) => isCommentOnlySql(stmt.trim())) &&\n !statements.every((stmt) => isNoOpAdvisorySql(stmt))\n ) {\n unactionable.push(change);\n }\n }\n return unactionable;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { DomainKnowledgeConfig } from '@happyvertical/smrt-types';
1
+ import { CapabilityEffect, DomainKnowledgeConfig } from '@happyvertical/smrt-types';
2
2
  import { SmrtCollection } from '../collection';
3
3
  import { CollectionCacheConfig } from '../collection-cache';
4
4
  import { FieldOptions } from '../decorators/index.js';
@@ -11,8 +11,13 @@ import { DeclaredIndexDefinition, SchemaDefinition } from '../schema/types.js';
11
11
  */
12
12
  export type SmrtObjectConstructor = new (...args: any[]) => SmrtObject;
13
13
  export type ApiHttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
14
- /** Browser/agent-visible effect classification for a generated API action. */
15
- export type ToolEffect = 'read' | 'write' | 'destructive';
14
+ /**
15
+ * Browser/agent-visible effect classification for a generated API action.
16
+ * Aliases the shared `smrt-types` contract (#2587) — see
17
+ * `CapabilityEffect` there for the fail-closed defaulting rule this
18
+ * classification is bound by.
19
+ */
20
+ export type ToolEffect = CapabilityEffect;
16
21
  export interface ApiSerializerReference {
17
22
  /**
18
23
  * Module specifier to import the serializer from.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/registry/types.ts"],"names":[],"mappings":"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"}
@@ -21,6 +21,13 @@ export declare function renderForeignKeyOrphanRepair(tableName: string, foreignK
21
21
  uuidCastSide?: ForeignKeyUuidCastSide;
22
22
  nullable?: boolean;
23
23
  }): string;
24
+ /**
25
+ * Canonical UUID text shape used by every PostgreSQL guard that has to decide
26
+ * whether a `text` column can be reinterpreted as `uuid`. Exported so the
27
+ * orphan probe, the FK provisioning guard, and the uuid convergence planner
28
+ * all test the same shape (#2608).
29
+ */
30
+ export declare const CANONICAL_UUID_PATTERN = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
24
31
  export declare function schemaForeignKeys(schema: Pick<SchemaDefinition, 'columns'> & Partial<Pick<SchemaDefinition, 'foreignKeys'>>): ForeignKeyDefinition[];
25
32
  /** Stable identity for one physical relationship, independent of allocation. */
26
33
  export declare function foreignKeyRelationshipKey(foreignKey: Pick<ForeignKeyDefinition, 'column' | 'referencesColumn' | 'referencesTable'>): string;
@@ -1 +1 @@
1
- {"version":3,"file":"foreign-key-ddl.d.ts","sourceRoot":"","sources":["../../src/schema/foreign-key-ddl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,MAAM,CAIR;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,MAAM,CAmBR;AAED,4EAA4E;AAC5E,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,MAAM,CAER;AAED,yDAAyD;AACzD,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,MAAM,CAER;AAED,mFAAmF;AACnF,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,sBAAsB,CAAC;CAClC,GACL,MAAM,CAcR;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,GACL,MAAM,CAuBR;AA2CD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC,GAC/C,oBAAoB,EAAE,CAmBxB;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,IAAI,CACd,oBAAoB,EACpB,QAAQ,GAAG,kBAAkB,GAAG,iBAAiB,CAClD,GACA,MAAM,CAMR;AAED,yEAAyE;AACzE,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC,EAChD,MAAM,EAAE,cAAc,GACrB,oBAAoB,EAAE,CAuBxB;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,GAAG,aAAa,CAAC,CAAC,EACjE,MAAM,EAAE,cAAc,GACrB,MAAM,EAAE,CA0BV"}
1
+ {"version":3,"file":"foreign-key-ddl.d.ts","sourceRoot":"","sources":["../../src/schema/foreign-key-ddl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1E,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,MAAM,CAIR;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,GAC/B,MAAM,CAmBR;AAED,4EAA4E;AAC5E,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,MAAM,CAER;AAED,yDAAyD;AACzD,wBAAgB,kCAAkC,CAChD,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,MAAM,CAER;AAED,mFAAmF;AACnF,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED,wBAAgB,8BAA8B,CAC5C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,sBAAsB,CAAC;CAClC,GACL,MAAM,CAcR;AAED,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACf,GACL,MAAM,CAuBR;AAID;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,mEAC+B,CAAC;AAsCnE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC,GAC/C,oBAAoB,EAAE,CAmBxB;AAED,gFAAgF;AAChF,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,IAAI,CACd,oBAAoB,EACpB,QAAQ,GAAG,kBAAkB,GAAG,iBAAiB,CAClD,GACA,MAAM,CAMR;AAED,yEAAyE;AACzE,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC,EAChD,MAAM,EAAE,cAAc,GACrB,oBAAoB,EAAE,CAuBxB;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,GAAG,aAAa,CAAC,CAAC,EACjE,MAAM,EAAE,cAAc,GACrB,MAAM,EAAE,CA0BV"}
@@ -45,6 +45,12 @@ function renderForeignKeyOrphanRepair(tableName, foreignKey, options = {}) {
45
45
  }
46
46
  var FOREIGN_KEY_CHILD_ALIAS = "smrt_fk_child";
47
47
  var FOREIGN_KEY_PARENT_ALIAS = "smrt_fk_parent";
48
+ /**
49
+ * Canonical UUID text shape used by every PostgreSQL guard that has to decide
50
+ * whether a `text` column can be reinterpreted as `uuid`. Exported so the
51
+ * orphan probe, the FK provisioning guard, and the uuid convergence planner
52
+ * all test the same shape (#2608).
53
+ */
48
54
  var CANONICAL_UUID_PATTERN = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
49
55
  function foreignKeyOrphanParts(tableName, foreignKey, engine = "postgres", uuidComparison = false, uuidCastSide) {
50
56
  const childAlias = quoteIdentifier(FOREIGN_KEY_CHILD_ALIAS);
@@ -110,6 +116,6 @@ function schemaDependenciesForEngine(schema, engine) {
110
116
  return Array.from(/* @__PURE__ */ new Set([...(schema.dependencies ?? []).filter((dependency) => !disabledTargets.has(dependency) || enabledTargets.has(dependency)), ...enabledTargets]));
111
117
  }
112
118
  //#endregion
113
- export { foreignKeyConstraintName, foreignKeyRelationshipKey, renderForeignKeyConstraint, renderForeignKeyConstraintComment, renderForeignKeyConstraintDrop, renderForeignKeyConstraintValidate, renderForeignKeyOrphanDetector, renderForeignKeyOrphanRepair, schemaDependenciesForEngine, schemaForeignKeys, schemaForeignKeysForEngine };
119
+ export { CANONICAL_UUID_PATTERN, foreignKeyConstraintName, foreignKeyRelationshipKey, renderForeignKeyConstraint, renderForeignKeyConstraintComment, renderForeignKeyConstraintDrop, renderForeignKeyConstraintValidate, renderForeignKeyOrphanDetector, renderForeignKeyOrphanRepair, schemaDependenciesForEngine, schemaForeignKeys, schemaForeignKeysForEngine };
114
120
 
115
121
  //# sourceMappingURL=foreign-key-ddl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"foreign-key-ddl.js","names":[],"sources":["../../src/schema/foreign-key-ddl.ts"],"sourcesContent":["import type { DatabaseEngine } from './ddl/types.js';\nimport { requireForeignKeyAction } from './foreign-key-policy.js';\nimport { shortenIdentifier } from './index-utils.js';\nimport { quoteIdentifier, quoteStringLiteral } from './sql-identifiers.js';\nimport type { ForeignKeyDefinition, SchemaDefinition } from './types.js';\n\nexport type ForeignKeyUuidCastSide = 'child' | 'parent' | 'both' | 'none';\n\nexport function foreignKeyConstraintName(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n): string {\n return shortenIdentifier(\n `${tableName}_${foreignKey.column}_${foreignKey.referencesTable}_${foreignKey.referencesColumn}_fkey`,\n );\n}\n\nexport function renderForeignKeyConstraint(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n): string {\n const action = (value: unknown, clause: 'DELETE' | 'UPDATE') => {\n if (value === undefined) return undefined;\n return requireForeignKeyAction(\n value,\n `${tableName}.${foreignKey.column} ON ${clause}`,\n );\n };\n const onDelete = action(foreignKey.onDelete, 'DELETE');\n const onUpdate = action(foreignKey.onUpdate, 'UPDATE');\n const name = foreignKeyConstraintName(tableName, foreignKey);\n const parts = [\n `CONSTRAINT ${quoteIdentifier(name)}`,\n `FOREIGN KEY (${quoteIdentifier(foreignKey.column)})`,\n `REFERENCES ${quoteIdentifier(foreignKey.referencesTable)} (${quoteIdentifier(foreignKey.referencesColumn)})`,\n ];\n if (onDelete) parts.push(`ON DELETE ${onDelete}`);\n if (onUpdate) parts.push(`ON UPDATE ${onUpdate}`);\n return parts.join(' ');\n}\n\n/** Render a PostgreSQL DROP CONSTRAINT statement for a catalog-owned FK. */\nexport function renderForeignKeyConstraintDrop(\n tableName: string,\n constraintName: string,\n): string {\n return `ALTER TABLE ${quoteIdentifier(tableName)} DROP CONSTRAINT ${quoteIdentifier(constraintName)};`;\n}\n\n/** Render a PostgreSQL VALIDATE CONSTRAINT statement. */\nexport function renderForeignKeyConstraintValidate(\n tableName: string,\n constraintName: string,\n): string {\n return `ALTER TABLE ${quoteIdentifier(tableName)} VALIDATE CONSTRAINT ${quoteIdentifier(constraintName)};`;\n}\n\n/** Render a PostgreSQL constraint comment used to identify framework ownership. */\nexport function renderForeignKeyConstraintComment(\n tableName: string,\n constraintName: string,\n comment: string,\n): string {\n return `COMMENT ON CONSTRAINT ${quoteIdentifier(constraintName)} ON ${quoteIdentifier(tableName)} IS ${quoteStringLiteral(comment)};`;\n}\n\nexport function renderForeignKeyOrphanDetector(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n options: {\n engine?: DatabaseEngine;\n limitOne?: boolean;\n uuidComparison?: boolean;\n uuidCastSide?: ForeignKeyUuidCastSide;\n } = {},\n): string {\n const parts = foreignKeyOrphanParts(\n tableName,\n foreignKey,\n options.engine,\n options.uuidComparison,\n options.uuidCastSide,\n );\n return (\n `SELECT ${parts.childColumn} AS orphan_key FROM ${parts.childTable} ` +\n `LEFT JOIN ${parts.parentTable} ON ${parts.joinPredicate} ` +\n `WHERE ${parts.childColumn} IS NOT NULL AND ${parts.parentColumn} IS NULL` +\n (options.limitOne ? ' LIMIT 1' : '')\n );\n}\n\nexport function renderForeignKeyOrphanRepair(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n options: {\n engine?: DatabaseEngine;\n uuidComparison?: boolean;\n uuidCastSide?: ForeignKeyUuidCastSide;\n nullable?: boolean;\n } = {},\n): string {\n const parts = foreignKeyOrphanParts(\n tableName,\n foreignKey,\n options.engine,\n options.uuidComparison,\n options.uuidCastSide,\n );\n const orphanPredicate =\n `${parts.childColumn} IS NOT NULL AND NOT EXISTS (` +\n `SELECT 1 FROM ${parts.parentTable} WHERE ${parts.joinPredicate})`;\n if (options.nullable === false) {\n return (\n `-- Manual repair required: ${quoteIdentifier(tableName)}.${quoteIdentifier(foreignKey.column)} is NOT NULL. ` +\n `Reassign each orphaned reference to a valid ${quoteIdentifier(foreignKey.referencesTable)}.${quoteIdentifier(foreignKey.referencesColumn)} value, ` +\n 'or deliberately delete rows only after preserving any required child data.'\n );\n }\n return (\n `UPDATE ${quoteIdentifier(tableName)} AS ${parts.childAlias} ` +\n `SET ${quoteIdentifier(foreignKey.column)} = NULL ` +\n `WHERE ${orphanPredicate}`\n );\n}\n\nconst FOREIGN_KEY_CHILD_ALIAS = 'smrt_fk_child';\nconst FOREIGN_KEY_PARENT_ALIAS = 'smrt_fk_parent';\nconst CANONICAL_UUID_PATTERN =\n '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$';\n\nfunction foreignKeyOrphanParts(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n engine: DatabaseEngine = 'postgres',\n uuidComparison = false,\n uuidCastSide?: ForeignKeyUuidCastSide,\n) {\n const childAlias = quoteIdentifier(FOREIGN_KEY_CHILD_ALIAS);\n const parentAlias = quoteIdentifier(FOREIGN_KEY_PARENT_ALIAS);\n const childColumn = `${childAlias}.${quoteIdentifier(foreignKey.column)}`;\n const parentColumn = `${parentAlias}.${quoteIdentifier(foreignKey.referencesColumn)}`;\n const guardedUuidValue = (column: string) =>\n `CASE WHEN ${column}::text ~* '${CANONICAL_UUID_PATTERN}' THEN ${column}::uuid ELSE NULL END`;\n const effectiveUuidCastSide =\n engine === 'postgres' && uuidComparison\n ? (uuidCastSide ?? 'child')\n : undefined;\n const childValue =\n effectiveUuidCastSide === 'child' || effectiveUuidCastSide === 'both'\n ? guardedUuidValue(childColumn)\n : childColumn;\n const parentValue =\n effectiveUuidCastSide === 'parent' || effectiveUuidCastSide === 'both'\n ? guardedUuidValue(parentColumn)\n : parentColumn;\n\n return {\n childAlias,\n childColumn,\n childTable: `${quoteIdentifier(tableName)} AS ${childAlias}`,\n joinPredicate: `${parentValue} = ${childValue}`,\n parentColumn,\n parentTable: `${quoteIdentifier(foreignKey.referencesTable)} AS ${parentAlias}`,\n };\n}\n\nexport function schemaForeignKeys(\n schema: Pick<SchemaDefinition, 'columns'> &\n Partial<Pick<SchemaDefinition, 'foreignKeys'>>,\n): ForeignKeyDefinition[] {\n if (schema.foreignKeys && schema.foreignKeys.length > 0) {\n return schema.foreignKeys;\n }\n return Object.entries(schema.columns).flatMap(([column, definition]) => {\n if (!definition.foreignKey) return [];\n return [\n {\n column,\n referencesTable: definition.foreignKey.table,\n referencesColumn: definition.foreignKey.column,\n onDelete: definition.foreignKey.onDelete,\n onUpdate: definition.foreignKey.onUpdate,\n ...(definition.foreignKey.engines\n ? { engines: definition.foreignKey.engines }\n : {}),\n },\n ];\n });\n}\n\n/** Stable identity for one physical relationship, independent of allocation. */\nexport function foreignKeyRelationshipKey(\n foreignKey: Pick<\n ForeignKeyDefinition,\n 'column' | 'referencesColumn' | 'referencesTable'\n >,\n): string {\n return JSON.stringify([\n foreignKey.column,\n foreignKey.referencesTable,\n foreignKey.referencesColumn,\n ]);\n}\n\n/** Return only physical constraints explicitly enabled for an engine. */\nexport function schemaForeignKeysForEngine(\n schema: Pick<SchemaDefinition, 'columns'> &\n Partial<Pick<SchemaDefinition, 'foreignKeys'>>,\n engine: DatabaseEngine,\n): ForeignKeyDefinition[] {\n return schemaForeignKeys(schema).filter((foreignKey) => {\n if (foreignKey.engines === undefined) return true;\n\n const validEngines = new Set<DatabaseEngine>([\n 'postgres',\n 'sqlite',\n 'duckdb',\n 'json',\n ]);\n if (\n foreignKey.engines.length === 0 ||\n foreignKey.engines.some(\n (declaredEngine) => !validEngines.has(declaredEngine),\n )\n ) {\n throw new Error(\n `[DDL:${engine}] Foreign key ${foreignKey.column} declares an invalid physical constraint engine allowlist. Use one or more of: postgres, sqlite, duckdb, json.`,\n );\n }\n\n return foreignKey.engines.includes(engine);\n });\n}\n\n/** Return declared schema dependencies after excluding engine-disabled FKs. */\nexport function schemaDependenciesForEngine(\n schema: Pick<SchemaDefinition, 'columns'> &\n Partial<Pick<SchemaDefinition, 'dependencies' | 'foreignKeys'>>,\n engine: DatabaseEngine,\n): string[] {\n const foreignKeys = schemaForeignKeys(schema);\n const enabledForeignKeys = schemaForeignKeysForEngine(schema, engine);\n const enabledKeys = new Set(\n enabledForeignKeys.map(foreignKeyRelationshipKey),\n );\n const enabledTargets = new Set(\n enabledForeignKeys.map((foreignKey) => foreignKey.referencesTable),\n );\n const disabledTargets = new Set(\n foreignKeys\n .filter(\n (foreignKey) => !enabledKeys.has(foreignKeyRelationshipKey(foreignKey)),\n )\n .map((foreignKey) => foreignKey.referencesTable),\n );\n\n return Array.from(\n new Set([\n ...(schema.dependencies ?? []).filter(\n (dependency) =>\n !disabledTargets.has(dependency) || enabledTargets.has(dependency),\n ),\n ...enabledTargets,\n ]),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"foreign-key-ddl.js","names":[],"sources":["../../src/schema/foreign-key-ddl.ts"],"sourcesContent":["import type { DatabaseEngine } from './ddl/types.js';\nimport { requireForeignKeyAction } from './foreign-key-policy.js';\nimport { shortenIdentifier } from './index-utils.js';\nimport { quoteIdentifier, quoteStringLiteral } from './sql-identifiers.js';\nimport type { ForeignKeyDefinition, SchemaDefinition } from './types.js';\n\nexport type ForeignKeyUuidCastSide = 'child' | 'parent' | 'both' | 'none';\n\nexport function foreignKeyConstraintName(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n): string {\n return shortenIdentifier(\n `${tableName}_${foreignKey.column}_${foreignKey.referencesTable}_${foreignKey.referencesColumn}_fkey`,\n );\n}\n\nexport function renderForeignKeyConstraint(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n): string {\n const action = (value: unknown, clause: 'DELETE' | 'UPDATE') => {\n if (value === undefined) return undefined;\n return requireForeignKeyAction(\n value,\n `${tableName}.${foreignKey.column} ON ${clause}`,\n );\n };\n const onDelete = action(foreignKey.onDelete, 'DELETE');\n const onUpdate = action(foreignKey.onUpdate, 'UPDATE');\n const name = foreignKeyConstraintName(tableName, foreignKey);\n const parts = [\n `CONSTRAINT ${quoteIdentifier(name)}`,\n `FOREIGN KEY (${quoteIdentifier(foreignKey.column)})`,\n `REFERENCES ${quoteIdentifier(foreignKey.referencesTable)} (${quoteIdentifier(foreignKey.referencesColumn)})`,\n ];\n if (onDelete) parts.push(`ON DELETE ${onDelete}`);\n if (onUpdate) parts.push(`ON UPDATE ${onUpdate}`);\n return parts.join(' ');\n}\n\n/** Render a PostgreSQL DROP CONSTRAINT statement for a catalog-owned FK. */\nexport function renderForeignKeyConstraintDrop(\n tableName: string,\n constraintName: string,\n): string {\n return `ALTER TABLE ${quoteIdentifier(tableName)} DROP CONSTRAINT ${quoteIdentifier(constraintName)};`;\n}\n\n/** Render a PostgreSQL VALIDATE CONSTRAINT statement. */\nexport function renderForeignKeyConstraintValidate(\n tableName: string,\n constraintName: string,\n): string {\n return `ALTER TABLE ${quoteIdentifier(tableName)} VALIDATE CONSTRAINT ${quoteIdentifier(constraintName)};`;\n}\n\n/** Render a PostgreSQL constraint comment used to identify framework ownership. */\nexport function renderForeignKeyConstraintComment(\n tableName: string,\n constraintName: string,\n comment: string,\n): string {\n return `COMMENT ON CONSTRAINT ${quoteIdentifier(constraintName)} ON ${quoteIdentifier(tableName)} IS ${quoteStringLiteral(comment)};`;\n}\n\nexport function renderForeignKeyOrphanDetector(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n options: {\n engine?: DatabaseEngine;\n limitOne?: boolean;\n uuidComparison?: boolean;\n uuidCastSide?: ForeignKeyUuidCastSide;\n } = {},\n): string {\n const parts = foreignKeyOrphanParts(\n tableName,\n foreignKey,\n options.engine,\n options.uuidComparison,\n options.uuidCastSide,\n );\n return (\n `SELECT ${parts.childColumn} AS orphan_key FROM ${parts.childTable} ` +\n `LEFT JOIN ${parts.parentTable} ON ${parts.joinPredicate} ` +\n `WHERE ${parts.childColumn} IS NOT NULL AND ${parts.parentColumn} IS NULL` +\n (options.limitOne ? ' LIMIT 1' : '')\n );\n}\n\nexport function renderForeignKeyOrphanRepair(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n options: {\n engine?: DatabaseEngine;\n uuidComparison?: boolean;\n uuidCastSide?: ForeignKeyUuidCastSide;\n nullable?: boolean;\n } = {},\n): string {\n const parts = foreignKeyOrphanParts(\n tableName,\n foreignKey,\n options.engine,\n options.uuidComparison,\n options.uuidCastSide,\n );\n const orphanPredicate =\n `${parts.childColumn} IS NOT NULL AND NOT EXISTS (` +\n `SELECT 1 FROM ${parts.parentTable} WHERE ${parts.joinPredicate})`;\n if (options.nullable === false) {\n return (\n `-- Manual repair required: ${quoteIdentifier(tableName)}.${quoteIdentifier(foreignKey.column)} is NOT NULL. ` +\n `Reassign each orphaned reference to a valid ${quoteIdentifier(foreignKey.referencesTable)}.${quoteIdentifier(foreignKey.referencesColumn)} value, ` +\n 'or deliberately delete rows only after preserving any required child data.'\n );\n }\n return (\n `UPDATE ${quoteIdentifier(tableName)} AS ${parts.childAlias} ` +\n `SET ${quoteIdentifier(foreignKey.column)} = NULL ` +\n `WHERE ${orphanPredicate}`\n );\n}\n\nconst FOREIGN_KEY_CHILD_ALIAS = 'smrt_fk_child';\nconst FOREIGN_KEY_PARENT_ALIAS = 'smrt_fk_parent';\n/**\n * Canonical UUID text shape used by every PostgreSQL guard that has to decide\n * whether a `text` column can be reinterpreted as `uuid`. Exported so the\n * orphan probe, the FK provisioning guard, and the uuid convergence planner\n * all test the same shape (#2608).\n */\nexport const CANONICAL_UUID_PATTERN =\n '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$';\n\nfunction foreignKeyOrphanParts(\n tableName: string,\n foreignKey: ForeignKeyDefinition,\n engine: DatabaseEngine = 'postgres',\n uuidComparison = false,\n uuidCastSide?: ForeignKeyUuidCastSide,\n) {\n const childAlias = quoteIdentifier(FOREIGN_KEY_CHILD_ALIAS);\n const parentAlias = quoteIdentifier(FOREIGN_KEY_PARENT_ALIAS);\n const childColumn = `${childAlias}.${quoteIdentifier(foreignKey.column)}`;\n const parentColumn = `${parentAlias}.${quoteIdentifier(foreignKey.referencesColumn)}`;\n const guardedUuidValue = (column: string) =>\n `CASE WHEN ${column}::text ~* '${CANONICAL_UUID_PATTERN}' THEN ${column}::uuid ELSE NULL END`;\n const effectiveUuidCastSide =\n engine === 'postgres' && uuidComparison\n ? (uuidCastSide ?? 'child')\n : undefined;\n const childValue =\n effectiveUuidCastSide === 'child' || effectiveUuidCastSide === 'both'\n ? guardedUuidValue(childColumn)\n : childColumn;\n const parentValue =\n effectiveUuidCastSide === 'parent' || effectiveUuidCastSide === 'both'\n ? guardedUuidValue(parentColumn)\n : parentColumn;\n\n return {\n childAlias,\n childColumn,\n childTable: `${quoteIdentifier(tableName)} AS ${childAlias}`,\n joinPredicate: `${parentValue} = ${childValue}`,\n parentColumn,\n parentTable: `${quoteIdentifier(foreignKey.referencesTable)} AS ${parentAlias}`,\n };\n}\n\nexport function schemaForeignKeys(\n schema: Pick<SchemaDefinition, 'columns'> &\n Partial<Pick<SchemaDefinition, 'foreignKeys'>>,\n): ForeignKeyDefinition[] {\n if (schema.foreignKeys && schema.foreignKeys.length > 0) {\n return schema.foreignKeys;\n }\n return Object.entries(schema.columns).flatMap(([column, definition]) => {\n if (!definition.foreignKey) return [];\n return [\n {\n column,\n referencesTable: definition.foreignKey.table,\n referencesColumn: definition.foreignKey.column,\n onDelete: definition.foreignKey.onDelete,\n onUpdate: definition.foreignKey.onUpdate,\n ...(definition.foreignKey.engines\n ? { engines: definition.foreignKey.engines }\n : {}),\n },\n ];\n });\n}\n\n/** Stable identity for one physical relationship, independent of allocation. */\nexport function foreignKeyRelationshipKey(\n foreignKey: Pick<\n ForeignKeyDefinition,\n 'column' | 'referencesColumn' | 'referencesTable'\n >,\n): string {\n return JSON.stringify([\n foreignKey.column,\n foreignKey.referencesTable,\n foreignKey.referencesColumn,\n ]);\n}\n\n/** Return only physical constraints explicitly enabled for an engine. */\nexport function schemaForeignKeysForEngine(\n schema: Pick<SchemaDefinition, 'columns'> &\n Partial<Pick<SchemaDefinition, 'foreignKeys'>>,\n engine: DatabaseEngine,\n): ForeignKeyDefinition[] {\n return schemaForeignKeys(schema).filter((foreignKey) => {\n if (foreignKey.engines === undefined) return true;\n\n const validEngines = new Set<DatabaseEngine>([\n 'postgres',\n 'sqlite',\n 'duckdb',\n 'json',\n ]);\n if (\n foreignKey.engines.length === 0 ||\n foreignKey.engines.some(\n (declaredEngine) => !validEngines.has(declaredEngine),\n )\n ) {\n throw new Error(\n `[DDL:${engine}] Foreign key ${foreignKey.column} declares an invalid physical constraint engine allowlist. Use one or more of: postgres, sqlite, duckdb, json.`,\n );\n }\n\n return foreignKey.engines.includes(engine);\n });\n}\n\n/** Return declared schema dependencies after excluding engine-disabled FKs. */\nexport function schemaDependenciesForEngine(\n schema: Pick<SchemaDefinition, 'columns'> &\n Partial<Pick<SchemaDefinition, 'dependencies' | 'foreignKeys'>>,\n engine: DatabaseEngine,\n): string[] {\n const foreignKeys = schemaForeignKeys(schema);\n const enabledForeignKeys = schemaForeignKeysForEngine(schema, engine);\n const enabledKeys = new Set(\n enabledForeignKeys.map(foreignKeyRelationshipKey),\n );\n const enabledTargets = new Set(\n enabledForeignKeys.map((foreignKey) => foreignKey.referencesTable),\n );\n const disabledTargets = new Set(\n foreignKeys\n .filter(\n (foreignKey) => !enabledKeys.has(foreignKeyRelationshipKey(foreignKey)),\n )\n .map((foreignKey) => foreignKey.referencesTable),\n );\n\n return Array.from(\n new Set([\n ...(schema.dependencies ?? []).filter(\n (dependency) =>\n !disabledTargets.has(dependency) || enabledTargets.has(dependency),\n ),\n ...enabledTargets,\n ]),\n );\n}\n"],"mappings":"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"}
@@ -79,6 +79,21 @@ export declare class SchemaManager {
79
79
  uuidComparison?: boolean;
80
80
  uuidCastSide?: ForeignKeyUuidCastSide;
81
81
  }): Promise<void>;
82
+ /**
83
+ * Read the live physical types of one child/parent column pair.
84
+ *
85
+ * Returns `undefined` when either side cannot be introspected (adapter
86
+ * without `getTableSchema`, table not created yet) — callers then keep the
87
+ * pre-#2608 behaviour rather than guessing at a mismatch.
88
+ */
89
+ private resolveLiveForeignKeyTypes;
90
+ /**
91
+ * Classify which side of an orphan probe needs a guarded uuid cast.
92
+ *
93
+ * Only reachable with matching live types while the #2608 guard rejects
94
+ * every mismatch, but the classification stays correct for callers that
95
+ * reuse the helper with an unguarded pair.
96
+ */
82
97
  private resolvePostgresForeignKeyProbeOptions;
83
98
  private normalizeForeignKeyProbeType;
84
99
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"schema-manager.d.ts","sourceRoot":"","sources":["../../src/schema/schema-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,sBAAsB,EAK5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAiBzE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAuB;IAGtC,OAAO,CAAC,MAAM,CAAkC;gBAEpC,EAAE,EAAE,iBAAiB,EAAE,OAAO,GAAE,oBAAyB;IAkBrE;;;;;;;OAOG;IACG,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmH1D;;;;;;;;;OASG;YACW,kBAAkB;IAwChC;;;;;;;;;;;;;OAaG;YACW,iBAAiB;IAqE/B,OAAO,CAAC,eAAe;IAIvB;;;;OAIG;IACG,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9D;;;;;;OAMG;IACG,wBAAwB,CAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;QACP,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,YAAY,CAAC,EAAE,sBAAsB,CAAC;KAClC,GACL,OAAO,CAAC,IAAI,CAAC;YAsDF,qCAAqC;IAkCnD,OAAO,CAAC,4BAA4B;IAOpC;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB;IASxD;;OAEG;IACH,SAAS,IAAI,cAAc;CAG5B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,iBAAiB,EACrB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,aAAa,CAEf"}
1
+ {"version":3,"file":"schema-manager.d.ts","sourceRoot":"","sources":["../../src/schema/schema-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,sBAAsB,EAK5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAqBzE;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,mDAAmD;IACnD,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAuB;IAGtC,OAAO,CAAC,MAAM,CAAkC;gBAEpC,EAAE,EAAE,iBAAiB,EAAE,OAAO,GAAE,oBAAyB;IAkBrE;;;;;;;OAOG;IACG,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmH1D;;;;;;;;;OASG;YACW,kBAAkB;IAwChC;;;;;;;;;;;;;OAaG;YACW,iBAAiB;IAqE/B,OAAO,CAAC,eAAe;IAIvB;;;;OAIG;IACG,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB9D;;;;;;OAMG;IACG,wBAAwB,CAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,oBAAoB,EAChC,OAAO,GAAE;QACP,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,YAAY,CAAC,EAAE,sBAAsB,CAAC;KAClC,GACL,OAAO,CAAC,IAAI,CAAC;IAuGhB;;;;;;OAMG;YACW,0BAA0B;IA4BxC;;;;;;OAMG;IACH,OAAO,CAAC,qCAAqC;IA0B7C,OAAO,CAAC,4BAA4B;IAOpC;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB;IASxD;;OAEG;IACH,SAAS,IAAI,cAAc;CAG5B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,iBAAiB,EACrB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,aAAa,CAEf"}
@@ -1,6 +1,7 @@
1
1
  import { foreignKeyConstraintName, renderForeignKeyConstraint, renderForeignKeyOrphanDetector, renderForeignKeyOrphanRepair } from "./foreign-key-ddl.js";
2
2
  import { detectEngine, getDDLStrategy } from "./ddl/index.js";
3
3
  import { planForeignKeyCreation } from "./foreign-key-planner.js";
4
+ import { describeForeignKeyTypeConflict, renderUuidConvergenceRepairHint } from "./uuid-convergence.js";
4
5
  import { createLogger } from "@happyvertical/logger";
5
6
  //#region src/schema/schema-manager.ts
6
7
  /**
@@ -199,7 +200,27 @@ var SchemaManager = class {
199
200
  }
200
201
  const existingRows = extractRows(existing);
201
202
  if (existingRows[0]?.convalidated === true) return;
202
- const probeOptions = await this.resolvePostgresForeignKeyProbeOptions(tableName, foreignKey, options);
203
+ const liveTypes = await this.resolveLiveForeignKeyTypes(tableName, foreignKey);
204
+ if (liveTypes && liveTypes.childNormalized !== liveTypes.parentNormalized) {
205
+ const conflict = describeForeignKeyTypeConflict({
206
+ childTable: tableName,
207
+ childColumn: foreignKey.column,
208
+ childType: liveTypes.childType,
209
+ parentTable: foreignKey.referencesTable,
210
+ parentColumn: foreignKey.referencesColumn,
211
+ parentType: liveTypes.parentType
212
+ });
213
+ const textNodes = options.uuidComparison ? [liveTypes.childNormalized === "TEXT" ? {
214
+ table: tableName,
215
+ column: foreignKey.column
216
+ } : void 0, liveTypes.parentNormalized === "TEXT" ? {
217
+ table: foreignKey.referencesTable,
218
+ column: foreignKey.referencesColumn
219
+ } : void 0].filter((node) => node !== void 0) : [];
220
+ const repair = textNodes.length > 0 ? ` Suggested repair: ${renderUuidConvergenceRepairHint(textNodes).join("; ")}` : ` Align ${tableName}.${foreignKey.column} (${liveTypes.childType}) and ${foreignKey.referencesTable}.${foreignKey.referencesColumn} (${liveTypes.parentType}) on one physical type deliberately, then retry.`;
221
+ throw new Error(`[SchemaManager] Cannot add ${constraintName}: incompatible column types. ${conflict}. Converge the columns first, then retry.${repair}`);
222
+ }
223
+ const probeOptions = this.resolvePostgresForeignKeyProbeOptions(options, liveTypes);
203
224
  const detector = renderForeignKeyOrphanDetector(tableName, foreignKey, {
204
225
  engine: "postgres",
205
226
  limitOne: true,
@@ -221,24 +242,46 @@ var SchemaManager = class {
221
242
  if (existingRows.length === 0) await this.db.query(`ALTER TABLE ${this.quoteIdentifier(tableName)} ADD ${renderForeignKeyConstraint(tableName, foreignKey)} NOT VALID`);
222
243
  await this.db.query(`ALTER TABLE ${this.quoteIdentifier(tableName)} VALIDATE CONSTRAINT ${this.quoteIdentifier(constraintName)}`);
223
244
  }
224
- async resolvePostgresForeignKeyProbeOptions(tableName, foreignKey, options) {
225
- if (!options.uuidComparison || options.uuidCastSide) return options;
245
+ /**
246
+ * Read the live physical types of one child/parent column pair.
247
+ *
248
+ * Returns `undefined` when either side cannot be introspected (adapter
249
+ * without `getTableSchema`, table not created yet) — callers then keep the
250
+ * pre-#2608 behaviour rather than guessing at a mismatch.
251
+ */
252
+ async resolveLiveForeignKeyTypes(tableName, foreignKey) {
226
253
  const childSchema = await this.db.getTableSchema?.(tableName);
227
254
  const parentSchema = foreignKey.referencesTable === tableName ? childSchema : await this.db.getTableSchema?.(foreignKey.referencesTable);
228
255
  const childType = childSchema?.columns[foreignKey.column]?.type;
229
256
  const parentType = parentSchema?.columns[foreignKey.referencesColumn]?.type;
230
- if (!childType || !parentType) return options;
231
- const childTypeNormalized = this.normalizeForeignKeyProbeType(childType);
232
- const parentTypeNormalized = this.normalizeForeignKeyProbeType(parentType);
233
- if (childTypeNormalized === parentTypeNormalized) return {
257
+ if (!childType || !parentType) return void 0;
258
+ return {
259
+ childType,
260
+ parentType,
261
+ childNormalized: this.normalizeForeignKeyProbeType(childType),
262
+ parentNormalized: this.normalizeForeignKeyProbeType(parentType)
263
+ };
264
+ }
265
+ /**
266
+ * Classify which side of an orphan probe needs a guarded uuid cast.
267
+ *
268
+ * Only reachable with matching live types while the #2608 guard rejects
269
+ * every mismatch, but the classification stays correct for callers that
270
+ * reuse the helper with an unguarded pair.
271
+ */
272
+ resolvePostgresForeignKeyProbeOptions(options, liveTypes) {
273
+ if (!options.uuidComparison || options.uuidCastSide) return options;
274
+ if (!liveTypes) return options;
275
+ const { childNormalized, parentNormalized } = liveTypes;
276
+ if (childNormalized === parentNormalized) return {
234
277
  ...options,
235
278
  uuidCastSide: "none"
236
279
  };
237
- if (childTypeNormalized === "UUID") return {
280
+ if (childNormalized === "UUID") return {
238
281
  ...options,
239
282
  uuidCastSide: "parent"
240
283
  };
241
- if (parentTypeNormalized === "UUID") return {
284
+ if (parentNormalized === "UUID") return {
242
285
  ...options,
243
286
  uuidCastSide: "child"
244
287
  };