From bca1e08ea81605471ba467b1ebd9ddeb4d05e03e Mon Sep 17 00:00:00 2001 From: Tomi Turtiainen <10324676+tomi@users.noreply.github.com> Date: Thu, 4 Jun 2026 16:42:27 +0300 Subject: [PATCH] chore(core): Require SQLite migration recreate acknowledgements (#31202) --- .../plugins/n8n/skills/db-migrations/SKILL.md | 56 +- .code-health-baseline.json | 804 +++++++++++++----- ...690000000030-RemoveResetPasswordColumns.ts | 13 +- .../common/1690000000040-AddMfaColumns.ts | 18 +- .../1693491613982-ExecutionSoftDelete.ts | 6 +- .../1693554410387-DisallowOrphanExecutions.ts | 4 +- .../1695128658538-AddWorkflowMetadata.ts | 4 +- ...odifyWorkflowHistoryNodesAndConnections.ts | 16 +- .../common/1705429061930-DropRoleMapping.ts | 12 +- .../common/1712044305787-RemoveNodesAccess.ts | 2 +- .../common/1714133768519-CreateProject.ts | 4 +- ...33768521-MakeExecutionStatusNonNullable.ts | 4 +- .../common/1724951148974-AddApiKeysTable.ts | 2 +- ...0136-SeparateExecutionCreationFromStart.ts | 14 +- ...64-UpdateProcessedDataValueColumnToText.ts | 4 +- .../common/1729607673469-AddProjectIcons.ts | 4 +- ...04028106-AddDescriptionToTestDefinition.ts | 6 +- .../1742918400000-AddScopesColumnToApiKeys.ts | 4 +- .../1750252139168-LinkRoleToUserTable.ts | 6 +- .../1750252139170-RemoveOldRoleColumn.ts | 6 +- ...000-AddInputsOutputsToTestCaseExecution.ts | 8 +- ...57570-AddTimestampsToRoleAndRoleIndexes.ts | 12 +- ...1758731786132-AddAudienceColumnToApiKey.ts | 10 +- .../1760020000000-CreateChatHubAgentTable.ts | 38 +- .../1760965142113-DropUnusedChatHubColumns.ts | 50 +- ...3155024-AddAttachmentsToChatHubMessages.ts | 16 +- ...830340990-AddToolsColumnToChatHubTables.ts | 32 +- ...2177736257-AddWorkflowDescriptionColumn.ts | 6 +- ...4-BackfillMissingWorkflowHistoryRecords.ts | 4 +- ...206508-AddWorkflowHistoryAutoSaveFields.ts | 18 +- .../1763047800000-AddActiveVersionIdColumn.ts | 8 +- ...764276827837-AddCreatorIdToProjectTable.ts | 10 +- ...448000-AddResolvableFieldsToCredentials.ts | 24 +- .../1765788427674-AddIconToAgentTable.ts | 4 +- .../1766068346315-AddChatMessageIndices.ts | 4 +- ...dPublishedVersionIdToWorkflowDependency.ts | 8 +- .../1770000000000-CreateChatHubToolsTable.ts | 12 +- ...500000002-AddFilesColumnToChatHubAgents.ts | 6 +- ...0000000-AddSuggestedPromptsToAgentTable.ts | 6 +- ...oleColumnToProjectSecretsProviderAccess.ts | 18 +- .../1772700000000-AddTypeToChatHubSessions.ts | 18 +- ...ddRestoreFieldsToWorkflowBuilderSession.ts | 21 +- ...orkflowPublishHistoryVersionIdToSetNull.ts | 4 +- ...7045000000-AddTracingContextToExecution.ts | 6 +- ...AddLangsmithIdsToInstanceAiRunSnapshots.ts | 24 +- ...8000000000-AddExecutionDeduplicationKey.ts | 6 +- ...000-AddEvaluationConfigColumnsToTestRun.ts | 10 +- ...778496086558-CreateEvaluationCollection.ts | 6 +- ...0000002-DropAgentExecutionWorkingMemory.ts | 6 +- ...AddNodeGroupsColumnToWorkflowAndHistory.ts | 12 +- ...0000007-CreateInstanceAiCheckpointTable.ts | 16 +- .../1784000000011-CreateAgentHistoryTable.ts | 24 +- ...4-PersistInstanceAiPendingConfirmations.ts | 26 +- ...000000015-AddSourceWorkflowIdToWorkflow.ts | 8 +- .../1784000000017-AddLastUsedAtToApiKey.ts | 6 +- .../1784000000018-CreateAgentFilesTable.ts | 6 +- ...0000019-AddCustomTelemetryTagsToProject.ts | 6 +- ...00000021-CreateAgentTaskDefinitionTable.ts | 28 +- ...dSubAgentLinkageToAgentExecutionThreads.ts | 20 +- ...24-AddResourceToOAuthAuthorizationCodes.ts | 22 +- packages/@n8n/db/src/migrations/dsl/index.ts | 118 ++- packages/@n8n/db/src/migrations/dsl/table.ts | 3 + ...58794506893-AddProjectIdToVariableTable.ts | 6 +- ...764276827837-AddCreatorIdToProjectTable.ts | 10 +- ...448000-AddResolvableFieldsToCredentials.ts | 24 +- 65 files changed, 1238 insertions(+), 481 deletions(-) diff --git a/.claude/plugins/n8n/skills/db-migrations/SKILL.md b/.claude/plugins/n8n/skills/db-migrations/SKILL.md index 41be3831741..0e01653c366 100644 --- a/.claude/plugins/n8n/skills/db-migrations/SKILL.md +++ b/.claude/plugins/n8n/skills/db-migrations/SKILL.md @@ -117,6 +117,7 @@ Run through this before requesting review. Each item is a real, recurring review - [ ] **Sparse-unique columns:** use a partial index `WHERE col IS NOT NULL`. — [Index Management](#index-management) - [ ] **Composite index column order** matches your actual `WHERE` / `ORDER BY` usage. — [Index Management](#index-management) - [ ] **Entity ↔ migration parity**: column types, `notNull`, defaults, FKs, `@Index` decorators all match. — [Schema/Entity Drift](#schemaentity-drift) +- [ ] **If using `addColumns`, `dropColumns`, `addNotNull`, `dropNotNull`, `addEnumCheck`, or `dropEnumCheck`:** verified whether the target table has incoming FKs. If so, either set `withFKsDisabled = true as const` (in a `sqlite/` subclass if this is a `common/` migration) or use raw `ALTER TABLE ADD COLUMN` for nullable/defaulted columns. — [SQLite table recreation risk](#sqlite-table-recreation-risk) - [ ] **No live-app value imports** in the migration body. Inline types/utility code locally. — [Never import entities as values](#never-import-entities-as-values) - [ ] **`async down()` was tested locally**: `pnpm start && pnpm start -- db:revert && pnpm start` on **both** SQLite and Postgres. — [Reversibility](#reversibility) - [ ] **One logical change per migration**; split unrelated table changes into separate files. — [Don't combine independent schema changes](#dont-combine-independent-schema-changes) @@ -218,7 +219,7 @@ export class MigrateThing1234567890000 implements IrreversibleMigration { const { schemaBuilder: { addColumns, column, createIndex } } = ctx; // One-liner DSL calls stay inline — naming them adds no information. - await addColumns('my_table', [column('slug').varchar(255)]); + await addColumns('my_table', [column('slug').varchar(255)], { recreatesOnSqlite: true }); // The non-trivial step gets a named method. await this.backfillSlugs(ctx); @@ -350,6 +351,51 @@ export class CreateMyTable1234567890000 implements ReversibleMigration { } ``` +### SQLite table recreation risk + +Six DSL methods trigger **full table recreation** on SQLite — TypeORM internally creates a temp copy, drops the original, and renames: + +| Method | TypeORM internal call | +|---|---| +| `addColumns()` | `queryRunner.addColumns()` | +| `dropColumns()` | `queryRunner.dropColumns()` | +| `addNotNull()` | `queryRunner.changeColumn()` | +| `dropNotNull()` | `queryRunner.changeColumn()` | +| `addEnumCheck()` | `queryRunner.changeColumn()` | +| `dropEnumCheck()` | `queryRunner.changeColumn()` | + +All six require a final options parameter with `recreatesOnSqlite: true` — TypeScript rejects calls that omit it. + +**The danger:** If the target table has incoming FK constraints with `CASCADE` from other tables, the `DROP TABLE` during recreation fires cascading deletes and **wipes rows from those referencing tables**. + +**Decision tree:** + +1. Does the target table have incoming FK constraints from other tables? + - **No** → Safe to use the DSL method directly (with the ack parameter). + - **Yes** → Continue to step 2. +2. Is this an `addColumns` call where every new column is nullable or has a default? + - **Yes** → Use raw `ALTER TABLE ADD COLUMN` instead (avoids table recreation entirely): + ```typescript + await runQuery( + `ALTER TABLE ${escape.tableName('my_table')} ADD COLUMN ${escape.columnName('col')} TEXT`, + ); + ``` + See `1733133775640-AddMockedNodesColumnToTestDefinition.ts` for a real example. + - **No** → Continue to step 3. +3. Set `withFKsDisabled = true as const` on the migration class. For common migrations, create a SQLite subclass in `sqlite/` that extends the common migration and adds the flag: + ```typescript + // sqlite/1234567890000-MyMigration.ts + import { MyMigration1234567890000 as BaseMigration } from '../common/1234567890000-MyMigration'; + + export class MyMigration1234567890000 extends BaseMigration { + withFKsDisabled = true as const; + } + ``` + +**How `withFKsDisabled` works:** The migration wrapper calls `PRAGMA foreign_keys=OFF` before `up()`/`down()`, runs the migration inside a manual transaction, then re-enables foreign keys. This prevents CASCADE from firing during the internal table drop. It also sets `transaction = false` to avoid TypeORM's default transaction (since SQLite can't nest transactions with PRAGMA changes). + +> **Note:** On Postgres, these methods use `ALTER TABLE` directly and don't recreate the table. The risk is SQLite-specific. + ### Column types **Match column type to value semantics.** Never `varchar` as a catch-all for non-string values — storing numbers as strings loses sort order, range queries, and SUM/AVG aggregations. @@ -570,7 +616,11 @@ When a migration both adds a column and backfills data, structure it clearly wit ```typescript export class AddAndBackfillColumn1234567890000 implements IrreversibleMigration { async up(ctx: MigrationContext) { - await ctx.schemaBuilder.addColumns('my_table', [ctx.schemaBuilder.column('newCol').text]); + await ctx.schemaBuilder.addColumns( + 'my_table', + [ctx.schemaBuilder.column('newCol').text], + { recreatesOnSqlite: true }, + ); await this.backfillNewCol(ctx); } @@ -633,7 +683,7 @@ Some migrations override with `transaction = false as const` for big DDL on engi - **Small differences** (a single statement, a CHECK constraint, slightly different syntax): keep one migration in `common/` and branch on `isSqlite` / `isPostgres`. - **Large differences** (different table recreation strategies, different intermediate steps, fundamentally different SQL): write **separate files** in `postgresdb/` and `sqlite/`. A common migration full of `if (isSqlite) { ... }` blocks is harder to read and review than two focused files. -If only Postgres needs the change, just put the file in `postgresdb/`; don't write a no-op SQLite migration with `if (isPostgres)`. SQLite no longer needs separate migrations for column adds (the recreate-table path was fixed) — verify before duplicating. +If only Postgres needs the change, just put the file in `postgresdb/`; don't write a no-op SQLite migration with `if (isPostgres)`. For SQLite column adds, follow the [SQLite table recreation risk](#sqlite-table-recreation-risk) decision tree before deciding whether a common migration is enough or a SQLite subclass/raw `ALTER TABLE` path is needed. ### SQLite supports modern syntax diff --git a/.code-health-baseline.json b/.code-health-baseline.json index 84744f7d80c..4fd32e04709 100644 --- a/.code-health-baseline.json +++ b/.code-health-baseline.json @@ -1,42 +1,36 @@ { "version": 1, - "generated": "2026-05-18T09:49:47.866Z", - "totalViolations": 99, + "generated": "2026-06-04T06:55:45.363Z", + "totalViolations": 148, "violations": { "packages/@n8n/ai-workflow-builder.ee/package.json": [ { "rule": "catalog-violations", - "line": 73, + "line": 76, "message": "langsmith@^0.4.6 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "6ee5e003d795" }, { "rule": "catalog-violations", - "line": 61, + "line": 63, "message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "d2120f012c93" }, { "rule": "catalog-violations", - "line": 70, - "message": "csv-parse appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "94f80b083b76" - }, - { - "rule": "catalog-violations", - "line": 71, + "line": 74, "message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "9c770d66baf2" }, { "rule": "catalog-violations", - "line": 77, + "line": 80, "message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "85c311d87491" }, { "rule": "catalog-violations", - "line": 83, + "line": 87, "message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "407c8d1b3428" } @@ -44,7 +38,7 @@ "packages/@n8n/json-schema-to-zod/package.json": [ { "rule": "catalog-violations", - "line": 63, + "line": 64, "message": "zod@^3.25.76 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "0e18482e8781" } @@ -52,87 +46,81 @@ "packages/@n8n/nodes-langchain/package.json": [ { "rule": "catalog-violations", - "line": 268, + "line": 272, "message": "@n8n/typeorm@0.3.20-16 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "a7c1bca1c439" }, { "rule": "catalog-violations", - "line": 269, + "line": 273, "message": "mysql2@3.17.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "2d7d1b715d0c" }, { "rule": "catalog-violations", - "line": 295, + "line": 301, "message": "openai@^6.34.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "3c1f53f0afe3" }, { "rule": "catalog-violations", - "line": 302, + "line": 307, "message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "88d67e2ef747" }, { "rule": "catalog-violations", - "line": 261, + "line": 265, "message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "69d6fa7e46f9" }, { "rule": "catalog-violations", - "line": 277, + "line": 283, "message": "cheerio appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "8cd029bb871e" }, { "rule": "catalog-violations", - "line": 287, + "line": 293, "message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "26f20ebea4b1" }, { "rule": "catalog-violations", - "line": 292, + "line": 298, "message": "mongodb appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "46cb48884e22" - }, - { - "rule": "catalog-violations", - "line": 296, - "message": "pdf-parse appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "0c7d44a9c2e4" } ], "packages/@n8n/tournament/package.json": [ { "rule": "catalog-violations", - "line": 44, + "line": 47, "message": "@types/node@^18.13.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "6368b5d3b924" }, { "rule": "catalog-violations", - "line": 52, + "line": 55, "message": "typescript@^5.0.0 should use \"catalog:\" (exists in pnpm-workspace.yaml)", "hash": "f668021a144e" }, { "rule": "catalog-violations", - "line": 55, + "line": 58, "message": "ast-types appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "27edcbb2b4f8" }, { "rule": "catalog-violations", - "line": 56, + "line": 59, "message": "esprima-next appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "75058f9a4d30" }, { "rule": "catalog-violations", - "line": 57, + "line": 60, "message": "recast appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "5f2b50fef19d" } @@ -140,7 +128,7 @@ "packages/frontend/@n8n/chat/package.json": [ { "rule": "catalog-violations", - "line": 56, + "line": 60, "message": "unplugin-icons@^0.19.0 should use \"catalog:frontend\" (exists in pnpm-workspace.yaml [frontend])", "hash": "a0d24d761026" } @@ -148,7 +136,7 @@ "packages/frontend/@n8n/design-system/package.json": [ { "rule": "catalog-violations", - "line": 73, + "line": 88, "message": "@vueuse/core@* should use \"catalog:frontend\" (exists in pnpm-workspace.yaml [frontend])", "hash": "237e9d17c4ba" } @@ -156,55 +144,43 @@ "packages/cli/package.json": [ { "rule": "catalog-violations", - "line": 98, - "message": "@ai-sdk/anthropic appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "1e3686e1923b" - }, - { - "rule": "catalog-violations", - "line": 139, + "line": 146, "message": "@opentelemetry/sdk-trace-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "1cf7f6bcf5d1" }, { "rule": "catalog-violations", - "line": 140, + "line": 147, "message": "@opentelemetry/sdk-trace-node appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "a3dad0b8dc21" }, { "rule": "catalog-violations", - "line": 150, + "line": 157, "message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "949e802528f7" }, { "rule": "catalog-violations", - "line": 202, + "line": 212, "message": "prettier appears in 3 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "3cab98902302" }, { "rule": "catalog-violations", - "line": 209, - "message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "5b7e9b03fb10" - }, - { - "rule": "catalog-violations", - "line": 217, + "line": 228, "message": "undici appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "91c29775e961" }, { "rule": "catalog-violations", - "line": 220, + "line": 231, "message": "ws appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "cd07242e8163" }, { "rule": "catalog-violations", - "line": 75, + "line": 80, "message": "@types/psl appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "6e62e0076b0a" } @@ -212,89 +188,33 @@ "packages/@n8n/agents/package.json": [ { "rule": "catalog-violations", - "line": 28, - "message": "@ai-sdk/anthropic appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "b58f03d0d5c1" - }, - { - "rule": "catalog-violations", - "line": 50, + "line": 76, "message": "@opentelemetry/sdk-trace-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "c5c495ac3508" }, { "rule": "catalog-violations", - "line": 51, + "line": 77, "message": "@opentelemetry/sdk-trace-node appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "a77ced903cdf" } ], - "packages/@n8n/instance-ai/package.json": [ - { - "rule": "catalog-violations", - "line": 81, - "message": "@ai-sdk/anthropic appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "5b2153508e47" - }, - { - "rule": "catalog-violations", - "line": 87, - "message": "@types/psl appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "56dabb51b433" - }, - { - "rule": "catalog-violations", - "line": 57, - "message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "8fa6b9a8fc91" - }, - { - "rule": "catalog-violations", - "line": 65, - "message": "csv-parse appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "8f082fc2e8b6" - }, - { - "rule": "catalog-violations", - "line": 72, - "message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "9a9d97065952" - }, - { - "rule": "catalog-violations", - "line": 88, - "message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "12e346c47b39" - }, - { - "rule": "catalog-violations", - "line": 51, - "message": "@joplin/turndown-plugin-gfm appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "a3cf1504b5c2" - }, - { - "rule": "catalog-violations", - "line": 69, - "message": "pdf-parse appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "283fa9114c03" - } - ], "packages/node-dev/package.json": [ { "rule": "catalog-violations", - "line": 47, + "line": 49, "message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "6988b9f58c92" }, { "rule": "catalog-violations", - "line": 46, + "line": 48, "message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "da9b64834300" }, { "rule": "catalog-violations", - "line": 53, + "line": 55, "message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "632a744e397e" } @@ -302,61 +222,49 @@ "packages/nodes-base/package.json": [ { "rule": "catalog-violations", - "line": 913, + "line": 920, "message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "2d1fab7a5b05" }, { "rule": "catalog-violations", - "line": 963, - "message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "2daf37aa14e4" - }, - { - "rule": "catalog-violations", - "line": 968, + "line": 976, "message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "3f93c404ae9c" }, { "rule": "catalog-violations", - "line": 902, + "line": 909, "message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "ca4ac788adc6" }, { "rule": "catalog-violations", - "line": 914, + "line": 921, "message": "cheerio appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "1a1b5bbc50c9" }, { "rule": "catalog-violations", - "line": 917, - "message": "csv-parse appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "781db4a1e068" - }, - { - "rule": "catalog-violations", - "line": 919, + "line": 926, "message": "eventsource appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "9795e6c6d9e9" }, { "rule": "catalog-violations", - "line": 932, + "line": 940, "message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "02341f2b5e3e" }, { "rule": "catalog-violations", - "line": 943, + "line": 951, "message": "mongodb appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "f688907d087a" }, { "rule": "catalog-violations", - "line": 894, + "line": 901, "message": "eslint-plugin-n8n-nodes-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "ac254baa61f9" } @@ -364,25 +272,25 @@ "packages/@n8n/node-cli/package.json": [ { "rule": "catalog-violations", - "line": 52, + "line": 53, "message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "da74ed210d07" }, { "rule": "catalog-violations", - "line": 59, + "line": 60, "message": "prettier appears in 3 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "188baf266f61" }, { "rule": "catalog-violations", - "line": 51, + "line": 52, "message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "9711a9b00bf9" }, { "rule": "catalog-violations", - "line": 55, + "line": 56, "message": "eslint-plugin-n8n-nodes-base appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "6a9e12780943" } @@ -390,53 +298,39 @@ "packages/frontend/editor-ui/package.json": [ { "rule": "catalog-violations", - "line": 69, + "line": 71, "message": "change-case appears in 5 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "bd9a2eeb072b" }, { "rule": "catalog-violations", - "line": 91, + "line": 93, "message": "prettier appears in 3 packages with 3 different versions — add to pnpm-workspace.yaml catalog", "hash": "9e9c7ec09a0b" }, { "rule": "catalog-violations", - "line": 93, - "message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "d8c606e42c92" - }, - { - "rule": "catalog-violations", - "line": 78, + "line": 80, "message": "esprima-next appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "62156c2613b2" } ], - "packages/@n8n/scan-community-package/package.json": [ - { - "rule": "catalog-violations", - "line": 20, - "message": "semver appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", - "hash": "ac0e4301d694" - } - ], "packages/@n8n/ai-utilities/package.json": [ { "rule": "catalog-violations", - "line": 69, + "line": 107, "message": "undici appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "c14cd05614e8" }, { "rule": "catalog-violations", - "line": 65, + "line": 102, "message": "tmp-promise appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "884a45bdbcf2" }, { "rule": "catalog-violations", - "line": 72, + "line": 110, "message": "n8n-workflow appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "ea4fbfff30ba" } @@ -444,37 +338,37 @@ "packages/@n8n/mcp-browser/package.json": [ { "rule": "catalog-violations", - "line": 36, + "line": 37, "message": "ws appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "9650c1b55f3c" }, { "rule": "catalog-violations", - "line": 28, + "line": 29, "message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "0c97891a24f4" }, { "rule": "catalog-violations", - "line": 30, + "line": 31, "message": "jsdom appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "8466b03b1044" }, { "rule": "catalog-violations", - "line": 35, + "line": 36, "message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "f23a9d3d7aa2" }, { "rule": "catalog-violations", - "line": 42, + "line": 44, "message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "3f9e46e56803" }, { "rule": "catalog-violations", - "line": 26, + "line": 27, "message": "@joplin/turndown-plugin-gfm appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "743e3a7dbb32" } @@ -482,15 +376,47 @@ "packages/@n8n/task-runner/package.json": [ { "rule": "catalog-violations", - "line": 50, + "line": 51, "message": "ws appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "51cb5069f382" } ], + "packages/@n8n/instance-ai/package.json": [ + { + "rule": "catalog-violations", + "line": 89, + "message": "@types/psl appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", + "hash": "56dabb51b433" + }, + { + "rule": "catalog-violations", + "line": 56, + "message": "@mozilla/readability appears in 5 packages with 2 different versions — add to pnpm-workspace.yaml catalog", + "hash": "8fa6b9a8fc91" + }, + { + "rule": "catalog-violations", + "line": 76, + "message": "turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", + "hash": "9a9d97065952" + }, + { + "rule": "catalog-violations", + "line": 90, + "message": "@types/turndown appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", + "hash": "12e346c47b39" + }, + { + "rule": "catalog-violations", + "line": 55, + "message": "@joplin/turndown-plugin-gfm appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", + "hash": "a3cf1504b5c2" + } + ], "packages/@n8n/benchmark/package.json": [ { "rule": "catalog-violations", - "line": 36, + "line": 38, "message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "67f9d81d9528" } @@ -498,7 +424,7 @@ "packages/@n8n/cli/package.json": [ { "rule": "catalog-violations", - "line": 74, + "line": 75, "message": "@oclif/core appears in 4 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "733c3960022e" } @@ -506,7 +432,7 @@ "packages/@n8n/computer-use/package.json": [ { "rule": "catalog-violations", - "line": 47, + "line": 48, "message": "eventsource appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "f50c1eee2ed6" } @@ -514,19 +440,19 @@ "packages/workflow/package.json": [ { "rule": "catalog-violations", - "line": 58, + "line": 64, "message": "ast-types appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "1c7d7cf0b0fe" }, { "rule": "catalog-violations", - "line": 60, + "line": 66, "message": "esprima-next appears in 3 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "627a716b5d23" }, { "rule": "catalog-violations", - "line": 68, + "line": 74, "message": "recast appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "b660317b5f6f" } @@ -534,7 +460,7 @@ "packages/@n8n/eslint-plugin-community-nodes/package.json": [ { "rule": "catalog-violations", - "line": 47, + "line": 49, "message": "n8n-workflow appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "c5830b76ff8e" } @@ -542,107 +468,595 @@ "packages/@n8n/stylelint-config/package.json": [ { "rule": "catalog-violations", - "line": 29, + "line": 30, "message": "stylelint appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "955f3fe044c7" }, { "rule": "catalog-violations", - "line": 45, + "line": 46, "message": "stylelint appears in 2 packages with 2 different versions — add to pnpm-workspace.yaml catalog", "hash": "955f3fe044c7" } ], + "packages/@n8n/db/src/migrations/common/1690000000030-RemoveResetPasswordColumns.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1690000000030-RemoveResetPasswordColumns.ts (1690000000030) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "c524a9ca4292" + } + ], + "packages/@n8n/db/src/migrations/common/1690000000040-AddMfaColumns.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1690000000040-AddMfaColumns.ts (1690000000040) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "9d571251376b" + } + ], + "packages/@n8n/db/src/migrations/common/1693491613982-ExecutionSoftDelete.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1693491613982-ExecutionSoftDelete.ts (1693491613982) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "7ade19d27ea8" + } + ], + "packages/@n8n/db/src/migrations/common/1693554410387-DisallowOrphanExecutions.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1693554410387-DisallowOrphanExecutions.ts (1693554410387) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "d46b0ae69b38" + } + ], + "packages/@n8n/db/src/migrations/common/1695128658538-AddWorkflowMetadata.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1695128658538-AddWorkflowMetadata.ts (1695128658538) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "52c9ad1e00dc" + } + ], + "packages/@n8n/db/src/migrations/common/1695829275184-ModifyWorkflowHistoryNodesAndConnections.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1695829275184-ModifyWorkflowHistoryNodesAndConnections.ts (1695829275184) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "e05c9af6e2f9" + } + ], + "packages/@n8n/db/src/migrations/common/1705429061930-DropRoleMapping.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1705429061930-DropRoleMapping.ts (1705429061930) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "8d325473bce5" + } + ], + "packages/@n8n/db/src/migrations/common/1712044305787-RemoveNodesAccess.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1712044305787-RemoveNodesAccess.ts (1712044305787) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "8d2bbe7bc09d" + } + ], + "packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1714133768519-CreateProject.ts (1714133768519) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "cdd159d80c55" + } + ], + "packages/@n8n/db/src/migrations/common/1714133768521-MakeExecutionStatusNonNullable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1714133768521-MakeExecutionStatusNonNullable.ts (1714133768521) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "7e726215f602" + } + ], + "packages/@n8n/db/src/migrations/common/1724951148974-AddApiKeysTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1724951148974-AddApiKeysTable.ts (1724951148974) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "3eaa3fa96ad1" + } + ], + "packages/@n8n/db/src/migrations/common/1727427440136-SeparateExecutionCreationFromStart.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1727427440136-SeparateExecutionCreationFromStart.ts (1727427440136) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "702281e1c037" + } + ], + "packages/@n8n/db/src/migrations/common/1729607673464-UpdateProcessedDataValueColumnToText.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1729607673464-UpdateProcessedDataValueColumnToText.ts (1729607673464) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "cf281457e81a" + } + ], + "packages/@n8n/db/src/migrations/common/1729607673469-AddProjectIcons.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1729607673469-AddProjectIcons.ts (1729607673469) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "d3c84ea555a6" + } + ], + "packages/@n8n/db/src/migrations/common/1731404028106-AddDescriptionToTestDefinition.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1731404028106-AddDescriptionToTestDefinition.ts (1731404028106) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "c0b12dc71971" + } + ], + "packages/@n8n/db/src/migrations/common/1742918400000-AddScopesColumnToApiKeys.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1742918400000-AddScopesColumnToApiKeys.ts (1742918400000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "1bd84c6e2704" + } + ], + "packages/@n8n/db/src/migrations/common/1750252139168-LinkRoleToUserTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1750252139168-LinkRoleToUserTable.ts (1750252139168) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "ae1fdf257787" + } + ], + "packages/@n8n/db/src/migrations/common/1750252139170-RemoveOldRoleColumn.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1750252139170-RemoveOldRoleColumn.ts (1750252139170) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "121d2727ab80" + } + ], + "packages/@n8n/db/src/migrations/common/1752669793000-AddInputsOutputsToTestCaseExecution.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1752669793000-AddInputsOutputsToTestCaseExecution.ts (1752669793000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "01857ec1a3d0" + } + ], + "packages/@n8n/db/src/migrations/common/1756906557570-AddTimestampsToRoleAndRoleIndexes.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1756906557570-AddTimestampsToRoleAndRoleIndexes.ts (1756906557570) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "3170ea3366de" + } + ], + "packages/@n8n/db/src/migrations/common/1758731786132-AddAudienceColumnToApiKey.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1758731786132-AddAudienceColumnToApiKey.ts (1758731786132) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "d52a1dd1e54e" + } + ], + "packages/@n8n/db/src/migrations/common/1760020000000-CreateChatHubAgentTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1760020000000-CreateChatHubAgentTable.ts (1760020000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "f8b39208c141" + } + ], + "packages/@n8n/db/src/migrations/common/1760965142113-DropUnusedChatHubColumns.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1760965142113-DropUnusedChatHubColumns.ts (1760965142113) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "55d389c0489c" + } + ], + "packages/@n8n/db/src/migrations/common/1761773155024-AddAttachmentsToChatHubMessages.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1761773155024-AddAttachmentsToChatHubMessages.ts (1761773155024) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "5f07b3ecd092" + } + ], + "packages/@n8n/db/src/migrations/common/1761830340990-AddToolsColumnToChatHubTables.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1761830340990-AddToolsColumnToChatHubTables.ts (1761830340990) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "77e018405eed" + } + ], + "packages/@n8n/db/src/migrations/common/1762177736257-AddWorkflowDescriptionColumn.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1762177736257-AddWorkflowDescriptionColumn.ts (1762177736257) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "f660693c50e8" + } + ], + "packages/@n8n/db/src/migrations/common/1762763704614-BackfillMissingWorkflowHistoryRecords.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1762763704614-BackfillMissingWorkflowHistoryRecords.ts (1762763704614) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "9918ff139099" + } + ], + "packages/@n8n/db/src/migrations/common/1762847206508-AddWorkflowHistoryAutoSaveFields.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1762847206508-AddWorkflowHistoryAutoSaveFields.ts (1762847206508) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "806cf49b747e" + } + ], + "packages/@n8n/db/src/migrations/common/1763047800000-AddActiveVersionIdColumn.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1763047800000-AddActiveVersionIdColumn.ts (1763047800000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "35d686155538" + } + ], + "packages/@n8n/db/src/migrations/common/1764276827837-AddCreatorIdToProjectTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1764276827837-AddCreatorIdToProjectTable.ts (1764276827837) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "1ed16ec75965" + } + ], + "packages/@n8n/db/src/migrations/common/1765459448000-AddResolvableFieldsToCredentials.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1765459448000-AddResolvableFieldsToCredentials.ts (1765459448000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "94d3e53d35b4" + } + ], + "packages/@n8n/db/src/migrations/common/1765788427674-AddIconToAgentTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1765788427674-AddIconToAgentTable.ts (1765788427674) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "8886bd530de2" + } + ], + "packages/@n8n/db/src/migrations/common/1766068346315-AddChatMessageIndices.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1766068346315-AddChatMessageIndices.ts (1766068346315) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "dc5d53f65c2a" + } + ], + "packages/@n8n/db/src/migrations/common/1769000000000-AddPublishedVersionIdToWorkflowDependency.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1769000000000-AddPublishedVersionIdToWorkflowDependency.ts (1769000000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "e6f6c0d42f7f" + } + ], + "packages/@n8n/db/src/migrations/common/1770000000000-CreateChatHubToolsTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1770000000000-CreateChatHubToolsTable.ts (1770000000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "61f4de8f7db3" + } + ], + "packages/@n8n/db/src/migrations/common/1771500000002-AddFilesColumnToChatHubAgents.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1771500000002-AddFilesColumnToChatHubAgents.ts (1771500000002) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "5ee6be686a28" + } + ], + "packages/@n8n/db/src/migrations/common/1772000000000-AddSuggestedPromptsToAgentTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1772000000000-AddSuggestedPromptsToAgentTable.ts (1772000000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "48bcd6bfe745" + } + ], + "packages/@n8n/db/src/migrations/common/1772619247761-AddRoleColumnToProjectSecretsProviderAccess.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1772619247761-AddRoleColumnToProjectSecretsProviderAccess.ts (1772619247761) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "acc7cac40f87" + } + ], + "packages/@n8n/db/src/migrations/common/1772700000000-AddTypeToChatHubSessions.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1772700000000-AddTypeToChatHubSessions.ts (1772700000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "0279dc26f034" + } + ], + "packages/@n8n/db/src/migrations/common/1774280963551-AddRestoreFieldsToWorkflowBuilderSession.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1774280963551-AddRestoreFieldsToWorkflowBuilderSession.ts (1774280963551) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "5bb3e906cdbb" + } + ], + "packages/@n8n/db/src/migrations/common/1775740765000-ChangeWorkflowPublishHistoryVersionIdToSetNull.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1775740765000-ChangeWorkflowPublishHistoryVersionIdToSetNull.ts (1775740765000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "c7e78794aefa" + } + ], + "packages/@n8n/db/src/migrations/common/1777045000000-AddTracingContextToExecution.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1777045000000-AddTracingContextToExecution.ts (1777045000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "41a43f631a32" + } + ], + "packages/@n8n/db/src/migrations/common/1777100000000-AddLangsmithIdsToInstanceAiRunSnapshots.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1777100000000-AddLangsmithIdsToInstanceAiRunSnapshots.ts (1777100000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "b541b874f037" + } + ], + "packages/@n8n/db/src/migrations/common/1778000000000-AddExecutionDeduplicationKey.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1778000000000-AddExecutionDeduplicationKey.ts (1778000000000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "278684d916e8" + } + ], + "packages/@n8n/db/src/migrations/common/1778100002000-AddEvaluationConfigColumnsToTestRun.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1778100002000-AddEvaluationConfigColumnsToTestRun.ts (1778100002000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "f61392909be0" + } + ], + "packages/@n8n/db/src/migrations/common/1778496086558-CreateEvaluationCollection.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1778496086558-CreateEvaluationCollection.ts (1778496086558) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "7a5d5dd7ac85" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000002-DropAgentExecutionWorkingMemory.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000002-DropAgentExecutionWorkingMemory.ts (1784000000002) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "88c53222237a" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000006-AddNodeGroupsColumnToWorkflowAndHistory.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000006-AddNodeGroupsColumnToWorkflowAndHistory.ts (1784000000006) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "e946194f33ec" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000007-CreateInstanceAiCheckpointTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000007-CreateInstanceAiCheckpointTable.ts (1784000000007) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "e5ea3b8289ec" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000011-CreateAgentHistoryTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000011-CreateAgentHistoryTable.ts (1784000000011) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "696e69444d0a" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000014-PersistInstanceAiPendingConfirmations.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000014-PersistInstanceAiPendingConfirmations.ts (1784000000014) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "bd255e8eeb5b" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000015-AddSourceWorkflowIdToWorkflow.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000015-AddSourceWorkflowIdToWorkflow.ts (1784000000015) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "45b35ca6fa25" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000017-AddLastUsedAtToApiKey.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000017-AddLastUsedAtToApiKey.ts (1784000000017) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "bc7d45e6e54e" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000018-CreateAgentFilesTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000018-CreateAgentFilesTable.ts (1784000000018) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "11a6b05559ae" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000019-AddCustomTelemetryTagsToProject.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000019-AddCustomTelemetryTagsToProject.ts (1784000000019) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "357263c229a1" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000021-CreateAgentTaskDefinitionTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000021-CreateAgentTaskDefinitionTable.ts (1784000000021) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "a161a7d7e616" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000022-AddSubAgentLinkageToAgentExecutionThreads.ts (1784000000022) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "287b98643496" + } + ], + "packages/@n8n/db/src/migrations/common/1784000000024-AddResourceToOAuthAuthorizationCodes.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1784000000024-AddResourceToOAuthAuthorizationCodes.ts (1784000000024) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "f3aa84779924" + } + ], + "packages/@n8n/db/src/migrations/postgresdb/1758794506893-AddProjectIdToVariableTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1758794506893-AddProjectIdToVariableTable.ts (1758794506893) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "7aebfa806bd9" + } + ], + "packages/@n8n/db/src/migrations/sqlite/1764276827837-AddCreatorIdToProjectTable.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1764276827837-AddCreatorIdToProjectTable.ts (1764276827837) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "e50608c0e078" + } + ], + "packages/@n8n/db/src/migrations/sqlite/1764689448000-AddResolvableFieldsToCredentials.ts": [ + { + "rule": "migration-timestamp", + "line": 1, + "message": "1764689448000-AddResolvableFieldsToCredentials.ts (1764689448000) is at or below the highest existing migration timestamp (1784000000025). New migrations must be strictly ordered — pick a timestamp greater than 1784000000025.", + "hash": "ac2493848228" + } + ], "package.json": [ { "rule": "stale-overrides", - "line": 100, + "line": 107, "message": "Override \"@azure/identity\" duplicates a catalog entry for @azure/identity — set the override to \"catalog:\" or remove it", "hash": "ef24d04a4347" }, { "rule": "stale-overrides", - "line": 101, + "line": 108, "message": "Override \"@lezer/common\" duplicates a catalog entry for @lezer/common — set the override to \"catalog:\" or remove it", "hash": "1e5d2fb72ef8" }, { "rule": "stale-overrides", - "line": 104, + "line": 111, "message": "Override \"@types/node\" duplicates a catalog entry for @types/node — set the override to \"catalog:\" or remove it", "hash": "d3577ed2e92d" }, { "rule": "stale-overrides", - "line": 105, + "line": 112, "message": "Override \"chokidar\" duplicates a catalog entry for chokidar — set the override to \"catalog:\" or remove it", "hash": "8496c5755ef0" }, { "rule": "stale-overrides", - "line": 115, + "line": 122, "message": "Override \"vue-tsc\" duplicates a catalog entry for vue-tsc — set the override to \"catalog:frontend\" or remove it", "hash": "5414a6c2842f" }, { "rule": "stale-overrides", - "line": 121, + "line": 128, "message": "Override \"form-data\" duplicates a catalog entry for form-data — set the override to \"catalog:\" or remove it", "hash": "ec13014b18ab" }, { "rule": "stale-overrides", - "line": 123, + "line": 131, "message": "Override \"nodemailer\" duplicates a catalog entry for nodemailer — set the override to \"catalog:\" or remove it", "hash": "1a696378ebfc" }, { "rule": "stale-overrides", - "line": 125, + "line": 133, "message": "Override \"zod\" duplicates a catalog entry for zod — set the override to \"catalog:\" or remove it", "hash": "6224a1e7997d" }, { "rule": "stale-overrides", - "line": 135, + "line": 142, "message": "Override \"@rudderstack/rudder-sdk-node@<=3.0.0\" duplicates a catalog entry for @rudderstack/rudder-sdk-node — set the override to \"catalog:\" or remove it", "hash": "71f703e2c449" }, { "rule": "stale-overrides", - "line": 146, + "line": 153, "message": "Override \"lodash\" duplicates a catalog entry for lodash — set the override to \"catalog:\" or remove it", "hash": "3cbb69cc0ff8" }, { "rule": "stale-overrides", - "line": 155, + "line": 161, "message": "Override \"flatted\" duplicates a catalog entry for flatted — set the override to \"catalog:\" or remove it", "hash": "7fe03ed5fec2" }, { "rule": "stale-overrides", - "line": 164, - "message": "Override \"langsmith\" duplicates a catalog entry for langsmith — set the override to \"catalog:\" or remove it", - "hash": "170e854b445c" - }, - { - "rule": "stale-overrides", - "line": 165, + "line": 170, "message": "Override \"yaml@<=2.8.3\" duplicates a catalog entry for yaml — set the override to \"catalog:\" or remove it", "hash": "a5ab421c217c" }, { "rule": "stale-overrides", - "line": 166, + "line": 171, "message": "Override \"axios\" duplicates a catalog entry for axios — set the override to \"catalog:\" or remove it", "hash": "3bd62181cb8d" }, { "rule": "stale-overrides", - "line": 170, + "line": 175, "message": "Override \"uuid@<=13.0.1\" duplicates a catalog entry for uuid — set the override to \"catalog:\" or remove it", "hash": "abd23b6d69fe" + }, + { + "rule": "stale-overrides", + "line": 184, + "message": "Override \"langsmith\" duplicates a catalog entry for langsmith — set the override to \"catalog:\" or remove it", + "hash": "170e854b445c" } ] } diff --git a/packages/@n8n/db/src/migrations/common/1690000000030-RemoveResetPasswordColumns.ts b/packages/@n8n/db/src/migrations/common/1690000000030-RemoveResetPasswordColumns.ts index 01843b46aea..fe08b5bb43d 100644 --- a/packages/@n8n/db/src/migrations/common/1690000000030-RemoveResetPasswordColumns.ts +++ b/packages/@n8n/db/src/migrations/common/1690000000030-RemoveResetPasswordColumns.ts @@ -2,13 +2,16 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class RemoveResetPasswordColumns1690000000030 implements ReversibleMigration { async up({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('user', ['resetPasswordToken', 'resetPasswordTokenExpiration']); + await dropColumns('user', ['resetPasswordToken', 'resetPasswordTokenExpiration'], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('user', [ - column('resetPasswordToken').varchar(), - column('resetPasswordTokenExpiration').int, - ]); + await addColumns( + 'user', + [column('resetPasswordToken').varchar(), column('resetPasswordTokenExpiration').int], + { recreatesOnSqlite: true }, + ); } } diff --git a/packages/@n8n/db/src/migrations/common/1690000000040-AddMfaColumns.ts b/packages/@n8n/db/src/migrations/common/1690000000040-AddMfaColumns.ts index eb1e2b609b5..23f71c50972 100644 --- a/packages/@n8n/db/src/migrations/common/1690000000040-AddMfaColumns.ts +++ b/packages/@n8n/db/src/migrations/common/1690000000040-AddMfaColumns.ts @@ -2,14 +2,20 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddMfaColumns1690000000030 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('user', [ - column('mfaEnabled').bool.notNull.default(false), - column('mfaSecret').text, - column('mfaRecoveryCodes').text, - ]); + await addColumns( + 'user', + [ + column('mfaEnabled').bool.notNull.default(false), + column('mfaSecret').text, + column('mfaRecoveryCodes').text, + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('user', ['mfaEnabled', 'mfaSecret', 'mfaRecoveryCodes']); + await dropColumns('user', ['mfaEnabled', 'mfaSecret', 'mfaRecoveryCodes'], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1693491613982-ExecutionSoftDelete.ts b/packages/@n8n/db/src/migrations/common/1693491613982-ExecutionSoftDelete.ts index bf6af3c20c7..0436048d3fc 100644 --- a/packages/@n8n/db/src/migrations/common/1693491613982-ExecutionSoftDelete.ts +++ b/packages/@n8n/db/src/migrations/common/1693491613982-ExecutionSoftDelete.ts @@ -6,7 +6,9 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; */ export class ExecutionSoftDelete1693491613982 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column, createIndex } }: MigrationContext) { - await addColumns('execution_entity', [column('deletedAt').timestamp()]); + await addColumns('execution_entity', [column('deletedAt').timestamp()], { + recreatesOnSqlite: true, + }); await createIndex('execution_entity', ['deletedAt']); await createIndex('execution_entity', ['stoppedAt']); } @@ -14,6 +16,6 @@ export class ExecutionSoftDelete1693491613982 implements ReversibleMigration { async down({ schemaBuilder: { dropColumns, dropIndex } }: MigrationContext) { await dropIndex('execution_entity', ['stoppedAt']); await dropIndex('execution_entity', ['deletedAt']); - await dropColumns('execution_entity', ['deletedAt']); + await dropColumns('execution_entity', ['deletedAt'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1693554410387-DisallowOrphanExecutions.ts b/packages/@n8n/db/src/migrations/common/1693554410387-DisallowOrphanExecutions.ts index 86bd272a10b..2e5680bbe9c 100644 --- a/packages/@n8n/db/src/migrations/common/1693554410387-DisallowOrphanExecutions.ts +++ b/packages/@n8n/db/src/migrations/common/1693554410387-DisallowOrphanExecutions.ts @@ -10,13 +10,13 @@ export class DisallowOrphanExecutions1693554410387 implements ReversibleMigratio await runQuery(`DELETE FROM ${executionEntity} WHERE ${workflowId} IS NULL;`); - await addNotNull('execution_entity', 'workflowId'); + await addNotNull('execution_entity', 'workflowId', { recreatesOnSqlite: true }); } /** * Reversal excludes restoring deleted rows. */ async down({ schemaBuilder: { dropNotNull } }: MigrationContext) { - await dropNotNull('execution_entity', 'workflowId'); + await dropNotNull('execution_entity', 'workflowId', { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1695128658538-AddWorkflowMetadata.ts b/packages/@n8n/db/src/migrations/common/1695128658538-AddWorkflowMetadata.ts index c742fad8408..6263c29276f 100644 --- a/packages/@n8n/db/src/migrations/common/1695128658538-AddWorkflowMetadata.ts +++ b/packages/@n8n/db/src/migrations/common/1695128658538-AddWorkflowMetadata.ts @@ -2,10 +2,10 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddWorkflowMetadata1695128658538 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('workflow_entity', [column('meta').json]); + await addColumns('workflow_entity', [column('meta').json], { recreatesOnSqlite: true }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('workflow_entity', ['meta']); + await dropColumns('workflow_entity', ['meta'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1695829275184-ModifyWorkflowHistoryNodesAndConnections.ts b/packages/@n8n/db/src/migrations/common/1695829275184-ModifyWorkflowHistoryNodesAndConnections.ts index d224e42785e..c4a4958622d 100644 --- a/packages/@n8n/db/src/migrations/common/1695829275184-ModifyWorkflowHistoryNodesAndConnections.ts +++ b/packages/@n8n/db/src/migrations/common/1695829275184-ModifyWorkflowHistoryNodesAndConnections.ts @@ -4,12 +4,20 @@ const tableName = 'workflow_history'; export class ModifyWorkflowHistoryNodesAndConnections1695829275184 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, dropColumns, column } }: MigrationContext) { - await dropColumns(tableName, ['nodes', 'connections']); - await addColumns(tableName, [column('nodes').json.notNull, column('connections').json.notNull]); + await dropColumns(tableName, ['nodes', 'connections'], { recreatesOnSqlite: true }); + await addColumns( + tableName, + [column('nodes').json.notNull, column('connections').json.notNull], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns, addColumns, column } }: MigrationContext) { - await dropColumns(tableName, ['nodes', 'connections']); - await addColumns(tableName, [column('nodes').text.notNull, column('connections').text.notNull]); + await dropColumns(tableName, ['nodes', 'connections'], { recreatesOnSqlite: true }); + await addColumns( + tableName, + [column('nodes').text.notNull, column('connections').text.notNull], + { recreatesOnSqlite: true }, + ); } } diff --git a/packages/@n8n/db/src/migrations/common/1705429061930-DropRoleMapping.ts b/packages/@n8n/db/src/migrations/common/1705429061930-DropRoleMapping.ts index 1570e5fbe47..49e651bf93e 100644 --- a/packages/@n8n/db/src/migrations/common/1705429061930-DropRoleMapping.ts +++ b/packages/@n8n/db/src/migrations/common/1705429061930-DropRoleMapping.ts @@ -48,7 +48,7 @@ export class DropRoleMapping1705429061930 implements ReversibleMigration { tablePrefix, }: MigrationContext, ) { - await addColumns(table, [column('role').text]); + await addColumns(table, [column('role').text], { recreatesOnSqlite: true }); const roleTable = escape.tableName('role'); const tableName = escape.tableName(table); @@ -74,7 +74,7 @@ export class DropRoleMapping1705429061930 implements ReversibleMigration { ${where}`; await runQuery(swQuery); - await addNotNull(table, 'role'); + await addNotNull(table, 'role', { recreatesOnSqlite: true }); await dropForeignKey( table, @@ -82,7 +82,7 @@ export class DropRoleMapping1705429061930 implements ReversibleMigration { ['role', 'id'], `FK_${tablePrefix}${foreignKeySuffixes[table]}`, ); - await dropColumns(table, [roleColumnName]); + await dropColumns(table, [roleColumnName], { recreatesOnSqlite: true }); } private async migrateDown( @@ -95,7 +95,7 @@ export class DropRoleMapping1705429061930 implements ReversibleMigration { }: MigrationContext, ) { const roleColumnName = table === 'user' ? 'globalRoleId' : 'roleId'; - await addColumns(table, [column(roleColumnName).int]); + await addColumns(table, [column(roleColumnName).int], { recreatesOnSqlite: true }); const roleTable = escape.tableName('role'); const tableName = escape.tableName(table); @@ -118,7 +118,7 @@ export class DropRoleMapping1705429061930 implements ReversibleMigration { ${where}`; await runQuery(query); - await addNotNull(table, roleColumnName); + await addNotNull(table, roleColumnName, { recreatesOnSqlite: true }); await addForeignKey( table, roleColumnName, @@ -126,6 +126,6 @@ export class DropRoleMapping1705429061930 implements ReversibleMigration { `FK_${tablePrefix}${foreignKeySuffixes[table]}`, ); - await dropColumns(table, ['role']); + await dropColumns(table, ['role'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1712044305787-RemoveNodesAccess.ts b/packages/@n8n/db/src/migrations/common/1712044305787-RemoveNodesAccess.ts index 1ffe4fbff2b..c2eeb5fa74c 100644 --- a/packages/@n8n/db/src/migrations/common/1712044305787-RemoveNodesAccess.ts +++ b/packages/@n8n/db/src/migrations/common/1712044305787-RemoveNodesAccess.ts @@ -2,6 +2,6 @@ import type { IrreversibleMigration, MigrationContext } from '../migration-types export class RemoveNodesAccess1712044305787 implements IrreversibleMigration { async up({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('credentials_entity', ['nodesAccess']); + await dropColumns('credentials_entity', ['nodesAccess'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts b/packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts index f06bdf16fad..f4334583d3d 100644 --- a/packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts +++ b/packages/@n8n/db/src/migrations/common/1714133768519-CreateProject.ts @@ -80,7 +80,7 @@ export class CreateProject1714133768519 implements ReversibleMigration { }: MigrationContext, ) { const projectIdColumn = column('projectId').varchar(36).default('NULL'); - await addColumns(relationTableName, [projectIdColumn]); + await addColumns(relationTableName, [projectIdColumn], { recreatesOnSqlite: true }); const relationTable = escape.tableName(relationTableName); const { t, c } = escapeNames(escape); @@ -104,7 +104,7 @@ export class CreateProject1714133768519 implements ReversibleMigration { await addForeignKey(relationTableName, 'projectId', ['project', 'id']); - await addNotNull(relationTableName, 'projectId'); + await addNotNull(relationTableName, 'projectId', { recreatesOnSqlite: true }); // Index the new projectId column await createIndex(relationTableName, ['projectId']); diff --git a/packages/@n8n/db/src/migrations/common/1714133768521-MakeExecutionStatusNonNullable.ts b/packages/@n8n/db/src/migrations/common/1714133768521-MakeExecutionStatusNonNullable.ts index 08e27e27b53..e1759baba6d 100644 --- a/packages/@n8n/db/src/migrations/common/1714133768521-MakeExecutionStatusNonNullable.ts +++ b/packages/@n8n/db/src/migrations/common/1714133768521-MakeExecutionStatusNonNullable.ts @@ -17,6 +17,8 @@ export class MakeExecutionStatusNonNullable1714133768521 implements Irreversible await runQuery(query); - await schemaBuilder.addNotNull('execution_entity', 'status'); + await schemaBuilder.addNotNull('execution_entity', 'status', { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1724951148974-AddApiKeysTable.ts b/packages/@n8n/db/src/migrations/common/1724951148974-AddApiKeysTable.ts index 7a135d41d87..bfe17f6e742 100644 --- a/packages/@n8n/db/src/migrations/common/1724951148974-AddApiKeysTable.ts +++ b/packages/@n8n/db/src/migrations/common/1724951148974-AddApiKeysTable.ts @@ -70,7 +70,7 @@ export class AddApiKeysTable1724951148974 implements ReversibleMigration { const idColumn = escape.columnName('id'); const createdAtColumn = escape.columnName('createdAt'); - await addColumns('user', [column('apiKey').varchar()]); + await addColumns('user', [column('apiKey').varchar()], { recreatesOnSqlite: true }); await createIndex('user', ['apiKey'], true); diff --git a/packages/@n8n/db/src/migrations/common/1727427440136-SeparateExecutionCreationFromStart.ts b/packages/@n8n/db/src/migrations/common/1727427440136-SeparateExecutionCreationFromStart.ts index 568b4b58d83..1bd40c813fd 100644 --- a/packages/@n8n/db/src/migrations/common/1727427440136-SeparateExecutionCreationFromStart.ts +++ b/packages/@n8n/db/src/migrations/common/1727427440136-SeparateExecutionCreationFromStart.ts @@ -6,11 +6,13 @@ export class SeparateExecutionCreationFromStart1727427440136 implements Reversib runQuery, escape, }: MigrationContext) { - await addColumns('execution_entity', [ - column('createdAt').notNull.timestamp().default('NOW()'), - ]); + await addColumns( + 'execution_entity', + [column('createdAt').notNull.timestamp().default('NOW()')], + { recreatesOnSqlite: true }, + ); - await dropNotNull('execution_entity', 'startedAt'); + await dropNotNull('execution_entity', 'startedAt', { recreatesOnSqlite: true }); const executionEntity = escape.tableName('execution_entity'); const createdAt = escape.columnName('createdAt'); @@ -21,7 +23,7 @@ export class SeparateExecutionCreationFromStart1727427440136 implements Reversib } async down({ schemaBuilder: { dropColumns, addNotNull } }: MigrationContext) { - await dropColumns('execution_entity', ['createdAt']); - await addNotNull('execution_entity', 'startedAt'); + await dropColumns('execution_entity', ['createdAt'], { recreatesOnSqlite: true }); + await addNotNull('execution_entity', 'startedAt', { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1729607673464-UpdateProcessedDataValueColumnToText.ts b/packages/@n8n/db/src/migrations/common/1729607673464-UpdateProcessedDataValueColumnToText.ts index 79e2b8e4357..418c9c26f77 100644 --- a/packages/@n8n/db/src/migrations/common/1729607673464-UpdateProcessedDataValueColumnToText.ts +++ b/packages/@n8n/db/src/migrations/common/1729607673464-UpdateProcessedDataValueColumnToText.ts @@ -9,7 +9,7 @@ export class UpdateProcessedDataValueColumnToText1729607673464 implements Revers await runQuery(`ALTER TABLE ${prefixedTableName} DROP COLUMN value;`); await runQuery(`ALTER TABLE ${prefixedTableName} RENAME COLUMN value_temp TO value`); - await addNotNull(processedDataTableName, 'value'); + await addNotNull(processedDataTableName, 'value', { recreatesOnSqlite: true }); } async down({ schemaBuilder: { addNotNull }, runQuery, tablePrefix }: MigrationContext) { @@ -19,6 +19,6 @@ export class UpdateProcessedDataValueColumnToText1729607673464 implements Revers await runQuery(`ALTER TABLE ${prefixedTableName} DROP COLUMN value;`); await runQuery(`ALTER TABLE ${prefixedTableName} RENAME COLUMN value_temp TO value`); - await addNotNull(processedDataTableName, 'value'); + await addNotNull(processedDataTableName, 'value', { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1729607673469-AddProjectIcons.ts b/packages/@n8n/db/src/migrations/common/1729607673469-AddProjectIcons.ts index 41ee3283775..a9afb3a1dbe 100644 --- a/packages/@n8n/db/src/migrations/common/1729607673469-AddProjectIcons.ts +++ b/packages/@n8n/db/src/migrations/common/1729607673469-AddProjectIcons.ts @@ -1,10 +1,10 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddProjectIcons1729607673469 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('project', [column('icon').json]); + await addColumns('project', [column('icon').json], { recreatesOnSqlite: true }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('project', ['icon']); + await dropColumns('project', ['icon'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1731404028106-AddDescriptionToTestDefinition.ts b/packages/@n8n/db/src/migrations/common/1731404028106-AddDescriptionToTestDefinition.ts index 6165b1ba520..41b7ae447c3 100644 --- a/packages/@n8n/db/src/migrations/common/1731404028106-AddDescriptionToTestDefinition.ts +++ b/packages/@n8n/db/src/migrations/common/1731404028106-AddDescriptionToTestDefinition.ts @@ -2,10 +2,12 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddDescriptionToTestDefinition1731404028106 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('test_definition', [column('description').text]); + await addColumns('test_definition', [column('description').text], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('test_definition', ['description']); + await dropColumns('test_definition', ['description'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1742918400000-AddScopesColumnToApiKeys.ts b/packages/@n8n/db/src/migrations/common/1742918400000-AddScopesColumnToApiKeys.ts index 7455bbf3380..10ca38a0a57 100644 --- a/packages/@n8n/db/src/migrations/common/1742918400000-AddScopesColumnToApiKeys.ts +++ b/packages/@n8n/db/src/migrations/common/1742918400000-AddScopesColumnToApiKeys.ts @@ -14,7 +14,7 @@ export class AddScopesColumnToApiKeys1742918400000 implements ReversibleMigratio queryRunner, schemaBuilder: { addColumns, column }, }: MigrationContext) { - await addColumns('user_api_keys', [column('scopes').json]); + await addColumns('user_api_keys', [column('scopes').json], { recreatesOnSqlite: true }); const userApiKeysTable = escape.tableName('user_api_keys'); const userTable = escape.tableName('user'); @@ -36,6 +36,6 @@ export class AddScopesColumnToApiKeys1742918400000 implements ReversibleMigratio } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('user_api_keys', ['scopes']); + await dropColumns('user_api_keys', ['scopes'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1750252139168-LinkRoleToUserTable.ts b/packages/@n8n/db/src/migrations/common/1750252139168-LinkRoleToUserTable.ts index b0909a45ad2..1be772c9790 100644 --- a/packages/@n8n/db/src/migrations/common/1750252139168-LinkRoleToUserTable.ts +++ b/packages/@n8n/db/src/migrations/common/1750252139168-LinkRoleToUserTable.ts @@ -36,7 +36,9 @@ export class LinkRoleToUserTable1750252139168 implements ReversibleMigration { }); } - await addColumns('user', [column('roleSlug').varchar(128).default("'global:member'").notNull]); + await addColumns('user', [column('roleSlug').varchar(128).default("'global:member'").notNull], { + recreatesOnSqlite: true, + }); await runQuery( `UPDATE ${userTableName} SET ${roleSlugColumn} = ${roleColumn} WHERE ${roleColumn} != ${roleSlugColumn}`, @@ -54,6 +56,6 @@ export class LinkRoleToUserTable1750252139168 implements ReversibleMigration { async down({ schemaBuilder: { dropForeignKey, dropColumns } }: MigrationContext) { await dropForeignKey('user', 'roleSlug', ['role', 'slug']); - await dropColumns('user', ['roleSlug']); + await dropColumns('user', ['roleSlug'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1750252139170-RemoveOldRoleColumn.ts b/packages/@n8n/db/src/migrations/common/1750252139170-RemoveOldRoleColumn.ts index 1e9d9a5f9dd..c69c69a2a69 100644 --- a/packages/@n8n/db/src/migrations/common/1750252139170-RemoveOldRoleColumn.ts +++ b/packages/@n8n/db/src/migrations/common/1750252139170-RemoveOldRoleColumn.ts @@ -26,7 +26,7 @@ export class RemoveOldRoleColumn1750252139170 implements ReversibleMigration { `UPDATE ${userTableName} SET ${roleSlugColumn} = ${roleColumn} WHERE ${roleColumn} != ${roleSlugColumn}`, ); - await dropColumns('user', ['role']); + await dropColumns('user', ['role'], { recreatesOnSqlite: true }); } async down({ schemaBuilder: { addColumns, column }, escape, runQuery }: MigrationContext) { @@ -34,7 +34,9 @@ export class RemoveOldRoleColumn1750252139170 implements ReversibleMigration { const roleColumn = escape.columnName('role'); const roleSlugColumn = escape.columnName('roleSlug'); - await addColumns('user', [column('role').varchar(128).default("'global:member'").notNull]); + await addColumns('user', [column('role').varchar(128).default("'global:member'").notNull], { + recreatesOnSqlite: true, + }); await runQuery( `UPDATE ${userTableName} SET ${roleColumn} = ${roleSlugColumn} WHERE ${roleSlugColumn} != ${roleColumn}`, diff --git a/packages/@n8n/db/src/migrations/common/1752669793000-AddInputsOutputsToTestCaseExecution.ts b/packages/@n8n/db/src/migrations/common/1752669793000-AddInputsOutputsToTestCaseExecution.ts index a622d490468..8cb6c6b0802 100644 --- a/packages/@n8n/db/src/migrations/common/1752669793000-AddInputsOutputsToTestCaseExecution.ts +++ b/packages/@n8n/db/src/migrations/common/1752669793000-AddInputsOutputsToTestCaseExecution.ts @@ -2,10 +2,14 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddInputsOutputsToTestCaseExecution1752669793000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('test_case_execution', [column('inputs').json, column('outputs').json]); + await addColumns('test_case_execution', [column('inputs').json, column('outputs').json], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('test_case_execution', ['inputs', 'outputs']); + await dropColumns('test_case_execution', ['inputs', 'outputs'], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1756906557570-AddTimestampsToRoleAndRoleIndexes.ts b/packages/@n8n/db/src/migrations/common/1756906557570-AddTimestampsToRoleAndRoleIndexes.ts index 4a8e0d44d64..278ce2c6dc4 100644 --- a/packages/@n8n/db/src/migrations/common/1756906557570-AddTimestampsToRoleAndRoleIndexes.ts +++ b/packages/@n8n/db/src/migrations/common/1756906557570-AddTimestampsToRoleAndRoleIndexes.ts @@ -16,10 +16,14 @@ export class AddTimestampsToRoleAndRoleIndexes1756906557570 implements Irreversi // add the columns twice in the same statement. await queryRunner.getTable(`${tablePrefix}${USER_TABLE_NAME}`); - await schemaBuilder.addColumns(ROLE_TABLE_NAME, [ - new Column('createdAt').timestampTimezone().notNull.default('NOW()'), - new Column('updatedAt').timestampTimezone().notNull.default('NOW()'), - ]); + await schemaBuilder.addColumns( + ROLE_TABLE_NAME, + [ + new Column('createdAt').timestampTimezone().notNull.default('NOW()'), + new Column('updatedAt').timestampTimezone().notNull.default('NOW()'), + ], + { recreatesOnSqlite: true }, + ); // This index should allow us to efficiently query project relations by their role // This will be used for counting how many users have a specific project role diff --git a/packages/@n8n/db/src/migrations/common/1758731786132-AddAudienceColumnToApiKey.ts b/packages/@n8n/db/src/migrations/common/1758731786132-AddAudienceColumnToApiKey.ts index 6c52d7735b9..d4fd7c5ce00 100644 --- a/packages/@n8n/db/src/migrations/common/1758731786132-AddAudienceColumnToApiKey.ts +++ b/packages/@n8n/db/src/migrations/common/1758731786132-AddAudienceColumnToApiKey.ts @@ -2,12 +2,14 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddAudienceColumnToApiKeys1758731786132 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('user_api_keys', [ - column('audience').varchar().notNull.default("'public-api'"), - ]); + await addColumns( + 'user_api_keys', + [column('audience').varchar().notNull.default("'public-api'")], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('user_api_keys', ['audience']); + await dropColumns('user_api_keys', ['audience'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1760020000000-CreateChatHubAgentTable.ts b/packages/@n8n/db/src/migrations/common/1760020000000-CreateChatHubAgentTable.ts index ee919f6a31e..a0aa75818c3 100644 --- a/packages/@n8n/db/src/migrations/common/1760020000000-CreateChatHubAgentTable.ts +++ b/packages/@n8n/db/src/migrations/common/1760020000000-CreateChatHubAgentTable.ts @@ -38,26 +38,34 @@ export class CreateChatHubAgentTable1760020000000 implements ReversibleMigration }).withTimestamps; // Add agentId and agentName to chat_hub_sessions - await addColumns(table.sessions, [ - column('agentId') - .varchar(36) - .comment('ID of the custom agent (if provider is "custom-agent")'), - column('agentName') - .varchar(128) - .comment('Cached name of the custom agent (if provider is "custom-agent")'), - ]); + await addColumns( + table.sessions, + [ + column('agentId') + .varchar(36) + .comment('ID of the custom agent (if provider is "custom-agent")'), + column('agentName') + .varchar(128) + .comment('Cached name of the custom agent (if provider is "custom-agent")'), + ], + { recreatesOnSqlite: true }, + ); // Add agentId to chat_hub_messages - await addColumns(table.messages, [ - column('agentId') - .varchar(36) - .comment('ID of the custom agent (if provider is "custom-agent")'), - ]); + await addColumns( + table.messages, + [ + column('agentId') + .varchar(36) + .comment('ID of the custom agent (if provider is "custom-agent")'), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropTable, dropColumns } }: MigrationContext) { - await dropColumns(table.messages, ['agentId']); - await dropColumns(table.sessions, ['agentId', 'agentName']); + await dropColumns(table.messages, ['agentId'], { recreatesOnSqlite: true }); + await dropColumns(table.sessions, ['agentId', 'agentName'], { recreatesOnSqlite: true }); await dropTable(table.agents); } } diff --git a/packages/@n8n/db/src/migrations/common/1760965142113-DropUnusedChatHubColumns.ts b/packages/@n8n/db/src/migrations/common/1760965142113-DropUnusedChatHubColumns.ts index 2d53ee65305..c1dbd769323 100644 --- a/packages/@n8n/db/src/migrations/common/1760965142113-DropUnusedChatHubColumns.ts +++ b/packages/@n8n/db/src/migrations/common/1760965142113-DropUnusedChatHubColumns.ts @@ -6,31 +6,41 @@ const table = { export class DropUnusedChatHubColumns1760965142113 implements ReversibleMigration { async up({ schemaBuilder: { dropColumns, addColumns, column } }: MigrationContext) { - await dropColumns(table.messages, ['turnId', 'runIndex', 'state']); - await addColumns(table.messages, [ - column('status') - .varchar(16) - .default("'success'") - .notNull.comment( - 'ChatHubMessageStatus enum, eg. "success", "error", "running", "cancelled"', - ), - ]); + await dropColumns(table.messages, ['turnId', 'runIndex', 'state'], { + recreatesOnSqlite: true, + }); + await addColumns( + table.messages, + [ + column('status') + .varchar(16) + .default("'success'") + .notNull.comment( + 'ChatHubMessageStatus enum, eg. "success", "error", "running", "cancelled"', + ), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns, addColumns, column, addForeignKey }, }: MigrationContext) { - await dropColumns(table.messages, ['status']); - await addColumns(table.messages, [ - column('turnId').uuid, - column('runIndex') - .int.notNull.default(0) - .comment('The nth attempt this message has been generated/retried this turn'), - column('state') - .varchar(16) - .default("'active'") - .notNull.comment('ChatHubMessageState enum: "active", "superseded", "hidden", "deleted"'), - ]); + await dropColumns(table.messages, ['status'], { recreatesOnSqlite: true }); + await addColumns( + table.messages, + [ + column('turnId').uuid, + column('runIndex') + .int.notNull.default(0) + .comment('The nth attempt this message has been generated/retried this turn'), + column('state') + .varchar(16) + .default("'active'") + .notNull.comment('ChatHubMessageState enum: "active", "superseded", "hidden", "deleted"'), + ], + { recreatesOnSqlite: true }, + ); await addForeignKey(table.messages, 'turnId', [table.messages, 'id'], undefined, 'CASCADE'); } } diff --git a/packages/@n8n/db/src/migrations/common/1761773155024-AddAttachmentsToChatHubMessages.ts b/packages/@n8n/db/src/migrations/common/1761773155024-AddAttachmentsToChatHubMessages.ts index 732f569d31b..0e557de1a83 100644 --- a/packages/@n8n/db/src/migrations/common/1761773155024-AddAttachmentsToChatHubMessages.ts +++ b/packages/@n8n/db/src/migrations/common/1761773155024-AddAttachmentsToChatHubMessages.ts @@ -6,14 +6,18 @@ const table = { export class AddAttachmentsToChatHubMessages1761773155024 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(table.messages, [ - column('attachments').json.comment( - 'File attachments for the message (if any), stored as JSON. Files are stored as base64-encoded data URLs.', - ), - ]); + await addColumns( + table.messages, + [ + column('attachments').json.comment( + 'File attachments for the message (if any), stored as JSON. Files are stored as base64-encoded data URLs.', + ), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(table.messages, ['attachments']); + await dropColumns(table.messages, ['attachments'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1761830340990-AddToolsColumnToChatHubTables.ts b/packages/@n8n/db/src/migrations/common/1761830340990-AddToolsColumnToChatHubTables.ts index 6019c8d9228..6543b2b9a3e 100644 --- a/packages/@n8n/db/src/migrations/common/1761830340990-AddToolsColumnToChatHubTables.ts +++ b/packages/@n8n/db/src/migrations/common/1761830340990-AddToolsColumnToChatHubTables.ts @@ -7,20 +7,28 @@ const table = { export class AddToolsColumnToChatHubTables1761830340990 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(table.sessions, [ - column('tools') - .json.notNull.default("'[]'") - .comment('Tools available to the agent as JSON node definitions'), - ]); - await addColumns(table.agents, [ - column('tools') - .json.notNull.default("'[]'") - .comment('Tools available to the agent as JSON node definitions'), - ]); + await addColumns( + table.sessions, + [ + column('tools') + .json.notNull.default("'[]'") + .comment('Tools available to the agent as JSON node definitions'), + ], + { recreatesOnSqlite: true }, + ); + await addColumns( + table.agents, + [ + column('tools') + .json.notNull.default("'[]'") + .comment('Tools available to the agent as JSON node definitions'), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(table.sessions, ['tools']); - await dropColumns(table.agents, ['tools']); + await dropColumns(table.sessions, ['tools'], { recreatesOnSqlite: true }); + await dropColumns(table.agents, ['tools'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1762177736257-AddWorkflowDescriptionColumn.ts b/packages/@n8n/db/src/migrations/common/1762177736257-AddWorkflowDescriptionColumn.ts index b59338d2bb3..2db064e8631 100644 --- a/packages/@n8n/db/src/migrations/common/1762177736257-AddWorkflowDescriptionColumn.ts +++ b/packages/@n8n/db/src/migrations/common/1762177736257-AddWorkflowDescriptionColumn.ts @@ -2,10 +2,12 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddWorkflowDescriptionColumn1762177736257 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('workflow_entity', [column('description').text]); + await addColumns('workflow_entity', [column('description').text], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('workflow_entity', ['description']); + await dropColumns('workflow_entity', ['description'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1762763704614-BackfillMissingWorkflowHistoryRecords.ts b/packages/@n8n/db/src/migrations/common/1762763704614-BackfillMissingWorkflowHistoryRecords.ts index acb78dfcc45..ba5ee1885bc 100644 --- a/packages/@n8n/db/src/migrations/common/1762763704614-BackfillMissingWorkflowHistoryRecords.ts +++ b/packages/@n8n/db/src/migrations/common/1762763704614-BackfillMissingWorkflowHistoryRecords.ts @@ -94,6 +94,8 @@ export class BackfillMissingWorkflowHistoryRecords1762763704614 implements Irrev ); // Step 3: Make versionId NOT NULL - await schemaBuilder.addNotNull('workflow_entity', 'versionId'); + await schemaBuilder.addNotNull('workflow_entity', 'versionId', { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1762847206508-AddWorkflowHistoryAutoSaveFields.ts b/packages/@n8n/db/src/migrations/common/1762847206508-AddWorkflowHistoryAutoSaveFields.ts index cd689e74687..bb917374d3b 100644 --- a/packages/@n8n/db/src/migrations/common/1762847206508-AddWorkflowHistoryAutoSaveFields.ts +++ b/packages/@n8n/db/src/migrations/common/1762847206508-AddWorkflowHistoryAutoSaveFields.ts @@ -7,14 +7,20 @@ const description = 'description'; export class AddWorkflowHistoryAutoSaveFields1762847206508 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(tableName, [ - column(name).varchar(128), - column(autosaved).bool.notNull.default(false), - column(description).text, - ]); + await addColumns( + tableName, + [ + column(name).varchar(128), + column(autosaved).bool.notNull.default(false), + column(description).text, + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(tableName, [name, autosaved, description]); + await dropColumns(tableName, [name, autosaved, description], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1763047800000-AddActiveVersionIdColumn.ts b/packages/@n8n/db/src/migrations/common/1763047800000-AddActiveVersionIdColumn.ts index 89b4189ddc9..4b125d1364a 100644 --- a/packages/@n8n/db/src/migrations/common/1763047800000-AddActiveVersionIdColumn.ts +++ b/packages/@n8n/db/src/migrations/common/1763047800000-AddActiveVersionIdColumn.ts @@ -12,7 +12,9 @@ export class AddActiveVersionIdColumn1763047800000 implements ReversibleMigratio }: MigrationContext) { const workflowsTableName = escape.tableName(WORKFLOWS_TABLE_NAME); - await addColumns(WORKFLOWS_TABLE_NAME, [column('activeVersionId').varchar(36)]); + await addColumns(WORKFLOWS_TABLE_NAME, [column('activeVersionId').varchar(36)], { + recreatesOnSqlite: true, + }); await addForeignKey( WORKFLOWS_TABLE_NAME, @@ -43,7 +45,9 @@ export class AddActiveVersionIdColumn1763047800000 implements ReversibleMigratio WORKFLOW_HISTORY_TABLE_NAME, 'versionId', ]); - await dropColumns(WORKFLOWS_TABLE_NAME, ['activeVersionId']); + await dropColumns(WORKFLOWS_TABLE_NAME, ['activeVersionId'], { + recreatesOnSqlite: true, + }); } // Create workflow_history records for workflows missing them diff --git a/packages/@n8n/db/src/migrations/common/1764276827837-AddCreatorIdToProjectTable.ts b/packages/@n8n/db/src/migrations/common/1764276827837-AddCreatorIdToProjectTable.ts index 0a93a80863c..a09976b0817 100644 --- a/packages/@n8n/db/src/migrations/common/1764276827837-AddCreatorIdToProjectTable.ts +++ b/packages/@n8n/db/src/migrations/common/1764276827837-AddCreatorIdToProjectTable.ts @@ -13,9 +13,11 @@ export class AddCreatorIdToProjectTable1764276827837 implements ReversibleMigrat schemaBuilder: { addColumns, addForeignKey, column }, queryRunner, }: MigrationContext) { - await addColumns(table.project, [ - column('creatorId').uuid.comment('ID of the user who created the project'), - ]); + await addColumns( + table.project, + [column('creatorId').uuid.comment('ID of the user who created the project')], + { recreatesOnSqlite: true }, + ); await addForeignKey(table.project, 'creatorId', ['user', 'id'], FOREIGN_KEY_NAME, 'SET NULL'); @@ -37,6 +39,6 @@ export class AddCreatorIdToProjectTable1764276827837 implements ReversibleMigrat async down({ schemaBuilder: { dropColumns, dropForeignKey } }: MigrationContext) { await dropForeignKey(table.project, 'creatorId', ['user', 'id'], FOREIGN_KEY_NAME); - await dropColumns(table.project, ['creatorId']); + await dropColumns(table.project, ['creatorId'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1765459448000-AddResolvableFieldsToCredentials.ts b/packages/@n8n/db/src/migrations/common/1765459448000-AddResolvableFieldsToCredentials.ts index 1feba94db88..668d36f4224 100644 --- a/packages/@n8n/db/src/migrations/common/1765459448000-AddResolvableFieldsToCredentials.ts +++ b/packages/@n8n/db/src/migrations/common/1765459448000-AddResolvableFieldsToCredentials.ts @@ -6,11 +6,15 @@ const FOREIGN_KEY_NAME = 'credentials_entity_resolverId_foreign'; export class AddResolvableFieldsToCredentials1765459448000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, addForeignKey, column } }: MigrationContext) { - await addColumns(credentialsTableName, [ - column('isResolvable').bool.notNull.default(false), - column('resolvableAllowFallback').bool.notNull.default(false), - column('resolverId').varchar(16), - ]); + await addColumns( + credentialsTableName, + [ + column('isResolvable').bool.notNull.default(false), + column('resolvableAllowFallback').bool.notNull.default(false), + column('resolverId').varchar(16), + ], + { recreatesOnSqlite: true }, + ); await addForeignKey( credentialsTableName, @@ -29,10 +33,10 @@ export class AddResolvableFieldsToCredentials1765459448000 implements Reversible FOREIGN_KEY_NAME, ); - await dropColumns(credentialsTableName, [ - 'isResolvable', - 'resolvableAllowFallback', - 'resolverId', - ]); + await dropColumns( + credentialsTableName, + ['isResolvable', 'resolvableAllowFallback', 'resolverId'], + { recreatesOnSqlite: true }, + ); } } diff --git a/packages/@n8n/db/src/migrations/common/1765788427674-AddIconToAgentTable.ts b/packages/@n8n/db/src/migrations/common/1765788427674-AddIconToAgentTable.ts index 5052ea85c1e..84185f51967 100644 --- a/packages/@n8n/db/src/migrations/common/1765788427674-AddIconToAgentTable.ts +++ b/packages/@n8n/db/src/migrations/common/1765788427674-AddIconToAgentTable.ts @@ -5,11 +5,11 @@ const table = 'chat_hub_agents'; export class AddIconToAgentTable1765788427674 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { // Add icon column to agents table (nullable) - await addColumns(table, [column('icon').json]); + await addColumns(table, [column('icon').json], { recreatesOnSqlite: true }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { // Drop icon column - await dropColumns(table, ['icon']); + await dropColumns(table, ['icon'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1766068346315-AddChatMessageIndices.ts b/packages/@n8n/db/src/migrations/common/1766068346315-AddChatMessageIndices.ts index a7cfb408744..53259bbf1d2 100644 --- a/packages/@n8n/db/src/migrations/common/1766068346315-AddChatMessageIndices.ts +++ b/packages/@n8n/db/src/migrations/common/1766068346315-AddChatMessageIndices.ts @@ -18,7 +18,7 @@ export class AddChatMessageIndices1766068346315 implements ReversibleMigration { WHERE ${lastMessageAtColumn} IS NULL`, ); - await addNotNull('chat_hub_sessions', 'lastMessageAt'); + await addNotNull('chat_hub_sessions', 'lastMessageAt', { recreatesOnSqlite: true }); // Index intended for faster sessionRepository.getManyByUserId queries await runQuery( @@ -39,6 +39,6 @@ export class AddChatMessageIndices1766068346315 implements ReversibleMigration { ); await runQuery(`DROP INDEX IF EXISTS ${escape.indexName('chat_hub_messages_sessionId')}`); - await dropNotNull('chat_hub_sessions', 'lastMessageAt'); + await dropNotNull('chat_hub_sessions', 'lastMessageAt', { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1769000000000-AddPublishedVersionIdToWorkflowDependency.ts b/packages/@n8n/db/src/migrations/common/1769000000000-AddPublishedVersionIdToWorkflowDependency.ts index b60a598d665..91dceb6552f 100644 --- a/packages/@n8n/db/src/migrations/common/1769000000000-AddPublishedVersionIdToWorkflowDependency.ts +++ b/packages/@n8n/db/src/migrations/common/1769000000000-AddPublishedVersionIdToWorkflowDependency.ts @@ -2,12 +2,16 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddPublishedVersionIdToWorkflowDependency1769000000000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column, createIndex } }: MigrationContext) { - await addColumns('workflow_dependency', [column('publishedVersionId').varchar(36)]); + await addColumns('workflow_dependency', [column('publishedVersionId').varchar(36)], { + recreatesOnSqlite: true, + }); await createIndex('workflow_dependency', ['publishedVersionId']); } async down({ schemaBuilder: { dropColumns, dropIndex } }: MigrationContext) { await dropIndex('workflow_dependency', ['publishedVersionId']); - await dropColumns('workflow_dependency', ['publishedVersionId']); + await dropColumns('workflow_dependency', ['publishedVersionId'], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1770000000000-CreateChatHubToolsTable.ts b/packages/@n8n/db/src/migrations/common/1770000000000-CreateChatHubToolsTable.ts index cf7f699ff7a..233d6f53b31 100644 --- a/packages/@n8n/db/src/migrations/common/1770000000000-CreateChatHubToolsTable.ts +++ b/packages/@n8n/db/src/migrations/common/1770000000000-CreateChatHubToolsTable.ts @@ -198,8 +198,8 @@ export class CreateChatHubToolsTable1770000000000 implements ReversibleMigration ); // Drop the tools columns from chat hub sessions and agents - await dropColumns(table.sessions, ['tools']); - await dropColumns(table.agents, ['tools']); + await dropColumns(table.sessions, ['tools'], { recreatesOnSqlite: true }); + await dropColumns(table.agents, ['tools'], { recreatesOnSqlite: true }); } async down({ schemaBuilder: { addColumns, column, dropTable } }: MigrationContext) { @@ -210,7 +210,11 @@ export class CreateChatHubToolsTable1770000000000 implements ReversibleMigration // This loses data, but we can't really restore it. // Impact of losing the configured tools should be fairly minimal, as credentials remain intact // and users can easily re-add the search tools to chat hub sessions and agents after the rollback if needed. - await addColumns(table.sessions, [column('tools').json.notNull.default("'[]'")]); - await addColumns(table.agents, [column('tools').json.notNull.default("'[]'")]); + await addColumns(table.sessions, [column('tools').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); + await addColumns(table.agents, [column('tools').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1771500000002-AddFilesColumnToChatHubAgents.ts b/packages/@n8n/db/src/migrations/common/1771500000002-AddFilesColumnToChatHubAgents.ts index 4d61a84d891..961ab0c714b 100644 --- a/packages/@n8n/db/src/migrations/common/1771500000002-AddFilesColumnToChatHubAgents.ts +++ b/packages/@n8n/db/src/migrations/common/1771500000002-AddFilesColumnToChatHubAgents.ts @@ -4,10 +4,12 @@ const table = 'chat_hub_agents'; export class AddFilesColumnToChatHubAgents1771500000002 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(table, [column('files').json.notNull.default("'[]'")]); + await addColumns(table, [column('files').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(table, ['files']); + await dropColumns(table, ['files'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1772000000000-AddSuggestedPromptsToAgentTable.ts b/packages/@n8n/db/src/migrations/common/1772000000000-AddSuggestedPromptsToAgentTable.ts index 91472b21e48..a994a486dca 100644 --- a/packages/@n8n/db/src/migrations/common/1772000000000-AddSuggestedPromptsToAgentTable.ts +++ b/packages/@n8n/db/src/migrations/common/1772000000000-AddSuggestedPromptsToAgentTable.ts @@ -4,10 +4,12 @@ const table = 'chat_hub_agents'; export class AddSuggestedPromptsToAgentTable1772000000000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(table, [column('suggestedPrompts').json.notNull.default("'[]'")]); + await addColumns(table, [column('suggestedPrompts').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(table, ['suggestedPrompts']); + await dropColumns(table, ['suggestedPrompts'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1772619247761-AddRoleColumnToProjectSecretsProviderAccess.ts b/packages/@n8n/db/src/migrations/common/1772619247761-AddRoleColumnToProjectSecretsProviderAccess.ts index 9e4f4a970b2..d27ef6dd4c1 100644 --- a/packages/@n8n/db/src/migrations/common/1772619247761-AddRoleColumnToProjectSecretsProviderAccess.ts +++ b/packages/@n8n/db/src/migrations/common/1772619247761-AddRoleColumnToProjectSecretsProviderAccess.ts @@ -6,18 +6,22 @@ export class AddRoleColumnToProjectSecretsProviderAccess1772619247761 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(table, [ - column('role') - .varchar(128) - .notNull.default("'secretsProviderConnection:user'") - .withEnumCheck(['secretsProviderConnection:owner', 'secretsProviderConnection:user']), - ]); + await addColumns( + table, + [ + column('role') + .varchar(128) + .notNull.default("'secretsProviderConnection:user'") + .withEnumCheck(['secretsProviderConnection:owner', 'secretsProviderConnection:user']), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns }, tablePrefix, queryRunner }: MigrationContext) { const fullTableName = `${tablePrefix}${table}`; const checkName = `CHK_${tablePrefix}${table}_role`; await queryRunner.dropCheckConstraint(fullTableName, checkName); - await dropColumns(table, ['role']); + await dropColumns(table, ['role'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1772700000000-AddTypeToChatHubSessions.ts b/packages/@n8n/db/src/migrations/common/1772700000000-AddTypeToChatHubSessions.ts index 5fd1c4d0c43..be364838824 100644 --- a/packages/@n8n/db/src/migrations/common/1772700000000-AddTypeToChatHubSessions.ts +++ b/packages/@n8n/db/src/migrations/common/1772700000000-AddTypeToChatHubSessions.ts @@ -2,15 +2,19 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddTypeToChatHubSessions1772700000000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('chat_hub_sessions', [ - column('type') - .varchar(16) - .notNull.default("'production'") - .withEnumCheck(['production', 'manual']), - ]); + await addColumns( + 'chat_hub_sessions', + [ + column('type') + .varchar(16) + .notNull.default("'production'") + .withEnumCheck(['production', 'manual']), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('chat_hub_sessions', ['type']); + await dropColumns('chat_hub_sessions', ['type'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1774280963551-AddRestoreFieldsToWorkflowBuilderSession.ts b/packages/@n8n/db/src/migrations/common/1774280963551-AddRestoreFieldsToWorkflowBuilderSession.ts index 837b34af13f..c6cbc32fb96 100644 --- a/packages/@n8n/db/src/migrations/common/1774280963551-AddRestoreFieldsToWorkflowBuilderSession.ts +++ b/packages/@n8n/db/src/migrations/common/1774280963551-AddRestoreFieldsToWorkflowBuilderSession.ts @@ -2,16 +2,21 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddRestoreFieldsToWorkflowBuilderSession1774280963551 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('workflow_builder_session', [ - column('activeVersionCardId').varchar(255), - column('resumeAfterRestoreMessageId').varchar(255), - ]); + await addColumns( + 'workflow_builder_session', + [ + column('activeVersionCardId').varchar(255), + column('resumeAfterRestoreMessageId').varchar(255), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('workflow_builder_session', [ - 'activeVersionCardId', - 'resumeAfterRestoreMessageId', - ]); + await dropColumns( + 'workflow_builder_session', + ['activeVersionCardId', 'resumeAfterRestoreMessageId'], + { recreatesOnSqlite: true }, + ); } } diff --git a/packages/@n8n/db/src/migrations/common/1775740765000-ChangeWorkflowPublishHistoryVersionIdToSetNull.ts b/packages/@n8n/db/src/migrations/common/1775740765000-ChangeWorkflowPublishHistoryVersionIdToSetNull.ts index c7a3ace6b4f..ed13de36370 100644 --- a/packages/@n8n/db/src/migrations/common/1775740765000-ChangeWorkflowPublishHistoryVersionIdToSetNull.ts +++ b/packages/@n8n/db/src/migrations/common/1775740765000-ChangeWorkflowPublishHistoryVersionIdToSetNull.ts @@ -15,7 +15,7 @@ export class ChangeWorkflowPublishHistoryVersionIdToSetNull1775740765000 { async up({ schemaBuilder: { dropForeignKey, addForeignKey, dropNotNull } }: MigrationContext) { await dropForeignKey(tableName, columnName, reference); - await dropNotNull(tableName, columnName); + await dropNotNull(tableName, columnName, { recreatesOnSqlite: true }); await addForeignKey(tableName, columnName, reference, undefined, 'SET NULL'); } @@ -26,7 +26,7 @@ export class ChangeWorkflowPublishHistoryVersionIdToSetNull1775740765000 await dropForeignKey(tableName, columnName, reference); await mc.runQuery(`DELETE FROM ${tableName} WHERE ${columnName} IS NULL`); - await addNotNull(tableName, columnName); + await addNotNull(tableName, columnName, { recreatesOnSqlite: true }); await addForeignKey(tableName, columnName, reference, undefined, 'CASCADE'); } } diff --git a/packages/@n8n/db/src/migrations/common/1777045000000-AddTracingContextToExecution.ts b/packages/@n8n/db/src/migrations/common/1777045000000-AddTracingContextToExecution.ts index d839d152bfe..46c77600361 100644 --- a/packages/@n8n/db/src/migrations/common/1777045000000-AddTracingContextToExecution.ts +++ b/packages/@n8n/db/src/migrations/common/1777045000000-AddTracingContextToExecution.ts @@ -2,10 +2,12 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddTracingContextToExecution1777045000000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('execution_entity', [column('tracingContext').json]); + await addColumns('execution_entity', [column('tracingContext').json], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('execution_entity', ['tracingContext']); + await dropColumns('execution_entity', ['tracingContext'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1777100000000-AddLangsmithIdsToInstanceAiRunSnapshots.ts b/packages/@n8n/db/src/migrations/common/1777100000000-AddLangsmithIdsToInstanceAiRunSnapshots.ts index 7de0daa48df..0a25d0235cc 100644 --- a/packages/@n8n/db/src/migrations/common/1777100000000-AddLangsmithIdsToInstanceAiRunSnapshots.ts +++ b/packages/@n8n/db/src/migrations/common/1777100000000-AddLangsmithIdsToInstanceAiRunSnapshots.ts @@ -2,17 +2,23 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddLangsmithIdsToInstanceAiRunSnapshots1777100000000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('instance_ai_run_snapshots', [ - column('langsmithRunId') - .varchar(36) - .comment('LangSmith run ID (UUID v4, e.g. "f47ac10b-58cc-4372-a567-0e02b2c3d479").'), - column('langsmithTraceId') - .varchar(36) - .comment('LangSmith trace ID (UUID v4, e.g. "f47ac10b-58cc-4372-a567-0e02b2c3d479").'), - ]); + await addColumns( + 'instance_ai_run_snapshots', + [ + column('langsmithRunId') + .varchar(36) + .comment('LangSmith run ID (UUID v4, e.g. "f47ac10b-58cc-4372-a567-0e02b2c3d479").'), + column('langsmithTraceId') + .varchar(36) + .comment('LangSmith trace ID (UUID v4, e.g. "f47ac10b-58cc-4372-a567-0e02b2c3d479").'), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('instance_ai_run_snapshots', ['langsmithRunId', 'langsmithTraceId']); + await dropColumns('instance_ai_run_snapshots', ['langsmithRunId', 'langsmithTraceId'], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1778000000000-AddExecutionDeduplicationKey.ts b/packages/@n8n/db/src/migrations/common/1778000000000-AddExecutionDeduplicationKey.ts index 6e9ab30359c..7bb519a282d 100644 --- a/packages/@n8n/db/src/migrations/common/1778000000000-AddExecutionDeduplicationKey.ts +++ b/packages/@n8n/db/src/migrations/common/1778000000000-AddExecutionDeduplicationKey.ts @@ -13,7 +13,9 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; */ export class AddExecutionDeduplicationKey1778000000000 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column, createIndex } }: MigrationContext) { - await addColumns('execution_entity', [column('deduplicationKey').varchar(255)]); + await addColumns('execution_entity', [column('deduplicationKey').varchar(255)], { + recreatesOnSqlite: true, + }); // NOTE: partial unique index. Two inserts with the same non-null key race and the // second fails, so duplicates can be detected. Null rows are excluded from the index // entirely — executions without a dedupe key don't occupy index space and aren't @@ -29,6 +31,6 @@ export class AddExecutionDeduplicationKey1778000000000 implements ReversibleMigr async down({ schemaBuilder: { dropIndex, dropColumns } }: MigrationContext) { await dropIndex('execution_entity', ['deduplicationKey']); - await dropColumns('execution_entity', ['deduplicationKey']); + await dropColumns('execution_entity', ['deduplicationKey'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1778100002000-AddEvaluationConfigColumnsToTestRun.ts b/packages/@n8n/db/src/migrations/common/1778100002000-AddEvaluationConfigColumnsToTestRun.ts index aaf486e1fd7..08f1d3b26b3 100644 --- a/packages/@n8n/db/src/migrations/common/1778100002000-AddEvaluationConfigColumnsToTestRun.ts +++ b/packages/@n8n/db/src/migrations/common/1778100002000-AddEvaluationConfigColumnsToTestRun.ts @@ -11,7 +11,9 @@ export class AddEvaluationConfigColumnsToTestRun1778100002000 implements Reversi runQuery, dbType, }: MigrationContext) { - await addColumns(TEST_RUN_TABLE, [column('evaluationConfigId').varchar(36)]); + await addColumns(TEST_RUN_TABLE, [column('evaluationConfigId').varchar(36)], { + recreatesOnSqlite: true, + }); await addForeignKey( TEST_RUN_TABLE, @@ -31,7 +33,9 @@ export class AddEvaluationConfigColumnsToTestRun1778100002000 implements Reversi } async down({ schemaBuilder: { dropColumns, dropForeignKey, dropIndex } }: MigrationContext) { - await dropColumns(TEST_RUN_TABLE, ['evaluationConfigSnapshot']); + await dropColumns(TEST_RUN_TABLE, ['evaluationConfigSnapshot'], { + recreatesOnSqlite: true, + }); await dropIndex(TEST_RUN_TABLE, ['evaluationConfigId']); await dropForeignKey( TEST_RUN_TABLE, @@ -39,6 +43,6 @@ export class AddEvaluationConfigColumnsToTestRun1778100002000 implements Reversi [EVALUATION_CONFIG_TABLE, 'id'], FK_NAME, ); - await dropColumns(TEST_RUN_TABLE, ['evaluationConfigId']); + await dropColumns(TEST_RUN_TABLE, ['evaluationConfigId'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1778496086558-CreateEvaluationCollection.ts b/packages/@n8n/db/src/migrations/common/1778496086558-CreateEvaluationCollection.ts index 191d42369dd..0400f262f25 100644 --- a/packages/@n8n/db/src/migrations/common/1778496086558-CreateEvaluationCollection.ts +++ b/packages/@n8n/db/src/migrations/common/1778496086558-CreateEvaluationCollection.ts @@ -56,7 +56,9 @@ export class CreateEvaluationCollection1778496086558 implements ReversibleMigrat await queryRunner.getTable(TEST_RUN_TABLE); } - await addColumns(TEST_RUN_TABLE, [column('collectionId').varchar(36)]); + await addColumns(TEST_RUN_TABLE, [column('collectionId').varchar(36)], { + recreatesOnSqlite: true, + }); await addForeignKey( TEST_RUN_TABLE, @@ -79,7 +81,7 @@ export class CreateEvaluationCollection1778496086558 implements ReversibleMigrat [EVALUATION_COLLECTION_TABLE, 'id'], FK_TEST_RUN_COLLECTION, ); - await dropColumns(TEST_RUN_TABLE, ['collectionId']); + await dropColumns(TEST_RUN_TABLE, ['collectionId'], { recreatesOnSqlite: true }); await dropTable(EVALUATION_COLLECTION_TABLE); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000002-DropAgentExecutionWorkingMemory.ts b/packages/@n8n/db/src/migrations/common/1784000000002-DropAgentExecutionWorkingMemory.ts index ac8aa4d575d..51286cdad65 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000002-DropAgentExecutionWorkingMemory.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000002-DropAgentExecutionWorkingMemory.ts @@ -2,10 +2,12 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class DropAgentExecutionWorkingMemory1784000000002 implements ReversibleMigration { async up({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('agent_execution', ['workingMemory']); + await dropColumns('agent_execution', ['workingMemory'], { recreatesOnSqlite: true }); } async down({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('agent_execution', [column('workingMemory').text]); + await addColumns('agent_execution', [column('workingMemory').text], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000006-AddNodeGroupsColumnToWorkflowAndHistory.ts b/packages/@n8n/db/src/migrations/common/1784000000006-AddNodeGroupsColumnToWorkflowAndHistory.ts index cad077e86e7..7148ef3fe8f 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000006-AddNodeGroupsColumnToWorkflowAndHistory.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000006-AddNodeGroupsColumnToWorkflowAndHistory.ts @@ -2,12 +2,16 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddNodeGroupsColumnToWorkflowAndHistory1784000000006 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('workflow_entity', [column('nodeGroups').json.notNull.default("'[]'")]); - await addColumns('workflow_history', [column('nodeGroups').json.notNull.default("'[]'")]); + await addColumns('workflow_entity', [column('nodeGroups').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); + await addColumns('workflow_history', [column('nodeGroups').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('workflow_entity', ['nodeGroups']); - await dropColumns('workflow_history', ['nodeGroups']); + await dropColumns('workflow_entity', ['nodeGroups'], { recreatesOnSqlite: true }); + await dropColumns('workflow_history', ['nodeGroups'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000007-CreateInstanceAiCheckpointTable.ts b/packages/@n8n/db/src/migrations/common/1784000000007-CreateInstanceAiCheckpointTable.ts index 2fc6b06a82f..9092f5fc6a1 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000007-CreateInstanceAiCheckpointTable.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000007-CreateInstanceAiCheckpointTable.ts @@ -5,10 +5,16 @@ const runSnapshotsTable = 'instance_ai_run_snapshots'; export class CreateInstanceAiCheckpointTable1784000000007 implements ReversibleMigration { async up({ schemaBuilder: { createTable, addColumns, column } }: MigrationContext) { - await addColumns(runSnapshotsTable, [ - column('traceId').varchar(64).comment('OpenTelemetry trace ID for the root Instance AI run.'), - column('spanId').varchar(64).comment('OpenTelemetry span ID for the root Instance AI run.'), - ]); + await addColumns( + runSnapshotsTable, + [ + column('traceId') + .varchar(64) + .comment('OpenTelemetry trace ID for the root Instance AI run.'), + column('spanId').varchar(64).comment('OpenTelemetry span ID for the root Instance AI run.'), + ], + { recreatesOnSqlite: true }, + ); await createTable(checkpointTable) .withColumns( @@ -34,6 +40,6 @@ export class CreateInstanceAiCheckpointTable1784000000007 implements ReversibleM async down({ schemaBuilder: { dropTable, dropColumns } }: MigrationContext) { await dropTable(checkpointTable); - await dropColumns(runSnapshotsTable, ['traceId', 'spanId']); + await dropColumns(runSnapshotsTable, ['traceId', 'spanId'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000011-CreateAgentHistoryTable.ts b/packages/@n8n/db/src/migrations/common/1784000000011-CreateAgentHistoryTable.ts index b0a8eeda0b4..51771b7d5c3 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000011-CreateAgentHistoryTable.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000011-CreateAgentHistoryTable.ts @@ -43,7 +43,9 @@ export class CreateAgentHistoryTable1784000000011 implements ReversibleMigration onDelete: 'SET NULL', }).withTimestamps; - await addColumns('agents', [column('activeVersionId').varchar(36)]); + await addColumns('agents', [column('activeVersionId').varchar(36)], { + recreatesOnSqlite: true, + }); await addForeignKey( 'agents', 'activeVersionId', @@ -59,7 +61,9 @@ export class CreateAgentHistoryTable1784000000011 implements ReversibleMigration await dropTable('agent_published_version'); // These columns were left from previous refactors and never actually used in the live system - await dropColumns('agents', ['credentialId', 'provider', 'model']); + await dropColumns('agents', ['credentialId', 'provider', 'model'], { + recreatesOnSqlite: true, + }); } async down(ctx: MigrationContext) { @@ -67,11 +71,15 @@ export class CreateAgentHistoryTable1784000000011 implements ReversibleMigration const { createTable, addColumns, dropForeignKey, dropColumns, dropTable, column } = schemaBuilder; - await addColumns('agents', [ - column('credentialId').varchar(255), - column('provider').varchar(128), - column('model').varchar(128), - ]); + await addColumns( + 'agents', + [ + column('credentialId').varchar(255), + column('provider').varchar(128), + column('model').varchar(128), + ], + { recreatesOnSqlite: true }, + ); await createTable('agent_published_version') .withColumns( @@ -99,7 +107,7 @@ export class CreateAgentHistoryTable1784000000011 implements ReversibleMigration await this.restoreActiveHistoryToPublishedVersion(ctx); await dropForeignKey('agents', 'activeVersionId', ['agent_history', 'versionId']); - await dropColumns('agents', ['activeVersionId']); + await dropColumns('agents', ['activeVersionId'], { recreatesOnSqlite: true }); await dropTable('agent_history'); } diff --git a/packages/@n8n/db/src/migrations/common/1784000000014-PersistInstanceAiPendingConfirmations.ts b/packages/@n8n/db/src/migrations/common/1784000000014-PersistInstanceAiPendingConfirmations.ts index 3acd9345c73..a0780240596 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000014-PersistInstanceAiPendingConfirmations.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000014-PersistInstanceAiPendingConfirmations.ts @@ -34,16 +34,24 @@ export class PersistInstanceAiPendingConfirmations1784000000014 implements Rever // Reshape `instance_ai_checkpoints` first, then create the table that // FKs into it. SQLite's `dropNotNull` recreates the table; doing that // while a FK already points at it would force a more fragile rebuild. - await schemaBuilder.addColumns(checkpointsTable, [ - schemaBuilder - .column('expiredAt') - .timestampTimezone() - .comment('Soft-delete timestamp: null means live; non-null marks the row as a tombstone.'), - ]); + await schemaBuilder.addColumns( + checkpointsTable, + [ + schemaBuilder + .column('expiredAt') + .timestampTimezone() + .comment( + 'Soft-delete timestamp: null means live; non-null marks the row as a tombstone.', + ), + ], + { recreatesOnSqlite: true }, + ); // Soft-delete sets `state = null` on consumed/pruned snapshots, so the // column must be nullable. Created NOT NULL in `1784000000007`. - await schemaBuilder.dropNotNull(checkpointsTable, 'state'); + await schemaBuilder.dropNotNull(checkpointsTable, 'state', { + recreatesOnSqlite: true, + }); // Enforce the soft-delete invariant at the DB level: a tombstoned row // (`expiredAt` set) must have released its `state` blob. @@ -80,8 +88,8 @@ export class PersistInstanceAiPendingConfirmations1784000000014 implements Rever const stateCol = escape.columnName('state'); await runQuery(`DELETE FROM ${table} WHERE ${stateCol} IS NULL`); - await addNotNull(checkpointsTable, 'state'); - await dropColumns(checkpointsTable, ['expiredAt']); + await addNotNull(checkpointsTable, 'state', { recreatesOnSqlite: true }); + await dropColumns(checkpointsTable, ['expiredAt'], { recreatesOnSqlite: true }); } private async createPendingConfirmationsTable({ diff --git a/packages/@n8n/db/src/migrations/common/1784000000015-AddSourceWorkflowIdToWorkflow.ts b/packages/@n8n/db/src/migrations/common/1784000000015-AddSourceWorkflowIdToWorkflow.ts index 8fdbd294eb1..71ccaca7bb7 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000015-AddSourceWorkflowIdToWorkflow.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000015-AddSourceWorkflowIdToWorkflow.ts @@ -2,7 +2,9 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddSourceWorkflowIdToWorkflow1784000000015 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column, createIndex } }: MigrationContext) { - await addColumns('workflow_entity', [column('sourceWorkflowId').varchar()]); + await addColumns('workflow_entity', [column('sourceWorkflowId').varchar()], { + recreatesOnSqlite: true, + }); await createIndex( 'workflow_entity', @@ -15,6 +17,8 @@ export class AddSourceWorkflowIdToWorkflow1784000000015 implements ReversibleMig async down({ schemaBuilder: { dropColumns, dropIndex } }: MigrationContext) { await dropIndex('workflow_entity', ['sourceWorkflowId']); - await dropColumns('workflow_entity', ['sourceWorkflowId']); + await dropColumns('workflow_entity', ['sourceWorkflowId'], { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000017-AddLastUsedAtToApiKey.ts b/packages/@n8n/db/src/migrations/common/1784000000017-AddLastUsedAtToApiKey.ts index f58da86718b..a919cd1e087 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000017-AddLastUsedAtToApiKey.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000017-AddLastUsedAtToApiKey.ts @@ -2,10 +2,12 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddLastUsedAtToApiKey1784000000017 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns('user_api_keys', [column('lastUsedAt').timestampTimezone()]); + await addColumns('user_api_keys', [column('lastUsedAt').timestampTimezone()], { + recreatesOnSqlite: true, + }); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns('user_api_keys', ['lastUsedAt']); + await dropColumns('user_api_keys', ['lastUsedAt'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000018-CreateAgentFilesTable.ts b/packages/@n8n/db/src/migrations/common/1784000000018-CreateAgentFilesTable.ts index 250b6c3a3ac..f47a783ce9b 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000018-CreateAgentFilesTable.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000018-CreateAgentFilesTable.ts @@ -46,7 +46,9 @@ export class CreateAgentFilesTable1784000000018 implements ReversibleMigration { { schemaBuilder: { addEnumCheck, dropEnumCheck } }: MigrationContext, sourceTypes: string[], ) { - await dropEnumCheck(binaryDataTableName, sourceTypeColumn); - await addEnumCheck(binaryDataTableName, sourceTypeColumn, sourceTypes); + await dropEnumCheck(binaryDataTableName, sourceTypeColumn, { recreatesOnSqlite: true }); + await addEnumCheck(binaryDataTableName, sourceTypeColumn, sourceTypes, { + recreatesOnSqlite: true, + }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000019-AddCustomTelemetryTagsToProject.ts b/packages/@n8n/db/src/migrations/common/1784000000019-AddCustomTelemetryTagsToProject.ts index 048d1a87d48..7472f3319ca 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000019-AddCustomTelemetryTagsToProject.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000019-AddCustomTelemetryTagsToProject.ts @@ -2,12 +2,14 @@ import type { MigrationContext, ReversibleMigration } from '../migration-types'; export class AddCustomTelemetryTagsToProject1784000000019 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column, createIndex } }: MigrationContext) { - await addColumns('project', [column('customTelemetryTags').json.notNull.default("'[]'")]); + await addColumns('project', [column('customTelemetryTags').json.notNull.default("'[]'")], { + recreatesOnSqlite: true, + }); await createIndex('shared_workflow', ['projectId']); } async down({ schemaBuilder: { dropColumns, dropIndex } }: MigrationContext) { await dropIndex('shared_workflow', ['projectId']); - await dropColumns('project', ['customTelemetryTags']); + await dropColumns('project', ['customTelemetryTags'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/common/1784000000021-CreateAgentTaskDefinitionTable.ts b/packages/@n8n/db/src/migrations/common/1784000000021-CreateAgentTaskDefinitionTable.ts index a03300eb1b1..2c7d985bfda 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000021-CreateAgentTaskDefinitionTable.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000021-CreateAgentTaskDefinitionTable.ts @@ -82,16 +82,20 @@ export class CreateAgentTaskDefinitionTable1784000000021 implements ReversibleMi onDelete: 'CASCADE', }).withTimestamps; - await addColumns('agent_execution_threads', [ - column('taskId') - .varchar(32) - .comment( - 'Published task ID that triggered this session; not an FK because published runs can outlive draft task definition rows', - ), - column('taskVersionId') - .varchar(36) - .comment('Published agent_history version that supplied the task snapshot'), - ]); + await addColumns( + 'agent_execution_threads', + [ + column('taskId') + .varchar(32) + .comment( + 'Published task ID that triggered this session; not an FK because published runs can outlive draft task definition rows', + ), + column('taskVersionId') + .varchar(36) + .comment('Published agent_history version that supplied the task snapshot'), + ], + { recreatesOnSqlite: true }, + ); await addForeignKey( 'agent_execution_threads', 'taskVersionId', @@ -110,7 +114,9 @@ export class CreateAgentTaskDefinitionTable1784000000021 implements ReversibleMi 'agent_history', 'versionId', ]); - await dropColumns('agent_execution_threads', ['taskId', 'taskVersionId']); + await dropColumns('agent_execution_threads', ['taskId', 'taskVersionId'], { + recreatesOnSqlite: true, + }); await dropTable('agent_task_run_lock'); await dropTable('agent_task_snapshot'); await dropTable('agent_task_definition'); diff --git a/packages/@n8n/db/src/migrations/common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads.ts b/packages/@n8n/db/src/migrations/common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads.ts index 5daa7194ccf..385c90906b9 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000022-AddSubAgentLinkageToAgentExecutionThreads.ts @@ -45,14 +45,18 @@ export class AddSubAgentLinkageToAgentExecutionThreads1784000000022 escape, tablePrefix, }: MigrationContext) { - await addColumns('agent_execution_threads', [ - column('parentThreadId') - .varchar(128) - .comment('Parent session thread id that delegated this subagent run.'), - column('parentAgentId') - .varchar(36) - .comment('Saved agent id of the parent that delegated this subagent run.'), - ]); + await addColumns( + 'agent_execution_threads', + [ + column('parentThreadId') + .varchar(128) + .comment('Parent session thread id that delegated this subagent run.'), + column('parentAgentId') + .varchar(36) + .comment('Saved agent id of the parent that delegated this subagent run.'), + ], + { recreatesOnSqlite: true }, + ); if (isPostgres) { for (const { table, column: columnName } of COLUMNS_TO_WIDEN) { diff --git a/packages/@n8n/db/src/migrations/common/1784000000024-AddResourceToOAuthAuthorizationCodes.ts b/packages/@n8n/db/src/migrations/common/1784000000024-AddResourceToOAuthAuthorizationCodes.ts index 02798315f62..1e84fa49236 100644 --- a/packages/@n8n/db/src/migrations/common/1784000000024-AddResourceToOAuthAuthorizationCodes.ts +++ b/packages/@n8n/db/src/migrations/common/1784000000024-AddResourceToOAuthAuthorizationCodes.ts @@ -7,17 +7,21 @@ const COLUMN_NAME = 'resource'; // instance's canonical MCP resource URL when consuming the code. export class AddResourceToOAuthAuthorizationCodes1784000000024 implements ReversibleMigration { async up({ schemaBuilder: { addColumns, column } }: MigrationContext) { - await addColumns(TABLE_NAME, [ - column(COLUMN_NAME) - .varchar() - .comment( - 'RFC 8707 resource indicator URI (e.g. https://n8n.example.com/mcp-server/http). ' + - 'NULL = legacy flow predating resource indicator support; defaults to the instance canonical MCP resource URL.', - ), - ]); + await addColumns( + TABLE_NAME, + [ + column(COLUMN_NAME) + .varchar() + .comment( + 'RFC 8707 resource indicator URI (e.g. https://n8n.example.com/mcp-server/http). ' + + 'NULL = legacy flow predating resource indicator support; defaults to the instance canonical MCP resource URL.', + ), + ], + { recreatesOnSqlite: true }, + ); } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(TABLE_NAME, [COLUMN_NAME]); + await dropColumns(TABLE_NAME, [COLUMN_NAME], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/dsl/index.ts b/packages/@n8n/db/src/migrations/dsl/index.ts index 1e349172143..307e9e41607 100644 --- a/packages/@n8n/db/src/migrations/dsl/index.ts +++ b/packages/@n8n/db/src/migrations/dsl/index.ts @@ -15,6 +15,14 @@ import { DropTable, } from './table'; +/** + * Marks an operation that recreates the entire table on SQLite. + * Adding this option is an explicit acknowledgment of that risk. + * + * @see {@link BaseMigration.withFKsDisabled} + */ +type RecreatesOnSqliteAck = { recreatesOnSqlite: true }; + export const createSchemaBuilder = (tablePrefix: string, queryRunner: QueryRunner) => ({ column: (name: string) => new Column(name), /* eslint-disable @typescript-eslint/promise-function-async */ @@ -23,9 +31,41 @@ export const createSchemaBuilder = (tablePrefix: string, queryRunner: QueryRunne dropTable: (tableName: string) => new DropTable(tableName, tablePrefix, queryRunner), - addColumns: (tableName: string, columns: Column[]) => + /** + * Adds columns to an existing table. + * + * **WARNING — SQLite table recreation:** On SQLite, TypeORM implements this by + * recreating the entire table (create temp → copy data → drop original → rename). + * If other tables have incoming FK constraints with CASCADE on the target table, + * the DROP triggers cascading deletes and **wipes data from those tables**. + * + * **Mitigation:** On SQLite migrations, set `withFKsDisabled = true as const` + * when the target table has incoming FKs. For common migrations, add a + * SQLite-only subclass with the flag instead of setting it on the common class. + * + * **Safer alternative:** When all new columns are nullable or have defaults, + * raw `ALTER TABLE ADD COLUMN` avoids table recreation entirely. + * + * @see {@link BaseMigration.withFKsDisabled} + */ + addColumns: (tableName: string, columns: Column[], _opts: RecreatesOnSqliteAck) => new AddColumns(tableName, columns, tablePrefix, queryRunner), - dropColumns: (tableName: string, columnNames: string[]) => + + /** + * Drops columns from an existing table. + * + * **WARNING — SQLite table recreation:** On SQLite, TypeORM implements this by + * recreating the entire table. If other tables have incoming FK constraints with + * CASCADE on the target table, the DROP triggers cascading deletes and **wipes + * data from those tables**. + * + * **Mitigation:** On SQLite migrations, set `withFKsDisabled = true as const` + * when the target table has incoming FKs. For common migrations, add a + * SQLite-only subclass with the flag instead of setting it on the common class. + * + * @see {@link BaseMigration.withFKsDisabled} + */ + dropColumns: (tableName: string, columnNames: string[], _opts: RecreatesOnSqliteAck) => new DropColumns(tableName, columnNames, tablePrefix, queryRunner), /** @@ -91,16 +131,76 @@ export const createSchemaBuilder = (tablePrefix: string, queryRunner: QueryRunne customConstraintName, ), - addNotNull: (tableName: string, columnName: string) => + /** + * Adds a NOT NULL constraint to an existing column. + * + * **WARNING — SQLite table recreation:** On SQLite, TypeORM implements + * `changeColumn` by recreating the entire table. If other tables have incoming + * FK constraints with CASCADE on the target table, the DROP triggers cascading + * deletes and **wipes data from those tables**. + * + * **Mitigation:** On SQLite migrations, set `withFKsDisabled = true as const` + * when the target table has incoming FKs. For common migrations, add a + * SQLite-only subclass with the flag instead of setting it on the common class. + * + * @see {@link BaseMigration.withFKsDisabled} + */ + addNotNull: (tableName: string, columnName: string, _opts: RecreatesOnSqliteAck) => new AddNotNull(tableName, columnName, tablePrefix, queryRunner), - dropNotNull: (tableName: string, columnName: string) => + + /** + * Drops the NOT NULL constraint from an existing column. + * + * **WARNING — SQLite table recreation:** On SQLite, TypeORM implements + * `changeColumn` by recreating the entire table. If other tables have incoming + * FK constraints with CASCADE on the target table, the DROP triggers cascading + * deletes and **wipes data from those tables**. + * + * **Mitigation:** On SQLite migrations, set `withFKsDisabled = true as const` + * when the target table has incoming FKs. For common migrations, add a + * SQLite-only subclass with the flag instead of setting it on the common class. + * + * @see {@link BaseMigration.withFKsDisabled} + */ + dropNotNull: (tableName: string, columnName: string, _opts: RecreatesOnSqliteAck) => new DropNotNull(tableName, columnName, tablePrefix, queryRunner), - /** WARNING: This recreates the entire table on SQLite. */ - addEnumCheck: (tableName: string, columnName: string, values: string[]) => - new AddEnumCheck(tableName, columnName, values, tablePrefix, queryRunner), - /** WARNING: This recreates the entire table on SQLite. */ - dropEnumCheck: (tableName: string, columnName: string) => + /** + * Adds a CHECK constraint that emulates an enum on the given column. + * + * **WARNING — SQLite table recreation:** On SQLite, TypeORM implements this by + * recreating the entire table. If other tables have incoming FK constraints with + * CASCADE on the target table, the DROP triggers cascading deletes and **wipes + * data from those tables**. + * + * **Mitigation:** On SQLite migrations, set `withFKsDisabled = true as const` + * when the target table has incoming FKs. For common migrations, add a + * SQLite-only subclass with the flag instead of setting it on the common class. + * + * @see {@link BaseMigration.withFKsDisabled} + */ + addEnumCheck: ( + tableName: string, + columnName: string, + values: string[], + _opts: RecreatesOnSqliteAck, + ) => new AddEnumCheck(tableName, columnName, values, tablePrefix, queryRunner), + + /** + * Drops a CHECK constraint that emulates an enum on the given column. + * + * **WARNING — SQLite table recreation:** On SQLite, TypeORM implements this by + * recreating the entire table. If other tables have incoming FK constraints with + * CASCADE on the target table, the DROP triggers cascading deletes and **wipes + * data from those tables**. + * + * **Mitigation:** On SQLite migrations, set `withFKsDisabled = true as const` + * when the target table has incoming FKs. For common migrations, add a + * SQLite-only subclass with the flag instead of setting it on the common class. + * + * @see {@link BaseMigration.withFKsDisabled} + */ + dropEnumCheck: (tableName: string, columnName: string, _opts: RecreatesOnSqliteAck) => new DropEnumCheck(tableName, columnName, tablePrefix, queryRunner), /* eslint-enable */ diff --git a/packages/@n8n/db/src/migrations/dsl/table.ts b/packages/@n8n/db/src/migrations/dsl/table.ts index 1ca54fc292c..ad85d0bf3f5 100644 --- a/packages/@n8n/db/src/migrations/dsl/table.ts +++ b/packages/@n8n/db/src/migrations/dsl/table.ts @@ -152,6 +152,7 @@ export class DropTable extends TableOperation { } } +/** SQLite: TypeORM recreates the table internally — beware CASCADE FK data loss. */ export class AddColumns extends TableOperation { constructor( tableName: string, @@ -179,6 +180,7 @@ export class AddColumns extends TableOperation { } } +/** SQLite: TypeORM recreates the table internally — beware CASCADE FK data loss. */ export class DropColumns extends TableOperation { constructor( tableName: string, @@ -233,6 +235,7 @@ export class DropForeignKey extends ForeignKeyOperation { } } +/** SQLite: TypeORM recreates the table internally via changeColumn — beware CASCADE FK data loss. */ class ModifyNotNull extends TableOperation { constructor( tableName: string, diff --git a/packages/@n8n/db/src/migrations/postgresdb/1758794506893-AddProjectIdToVariableTable.ts b/packages/@n8n/db/src/migrations/postgresdb/1758794506893-AddProjectIdToVariableTable.ts index 01b50b83776..cccb608a09a 100644 --- a/packages/@n8n/db/src/migrations/postgresdb/1758794506893-AddProjectIdToVariableTable.ts +++ b/packages/@n8n/db/src/migrations/postgresdb/1758794506893-AddProjectIdToVariableTable.ts @@ -26,7 +26,9 @@ export class AddProjectIdToVariableTable1758794506893 implements ReversibleMigra `ALTER TABLE ${variablesTableName} DROP CONSTRAINT ${tablePrefix}variables_key_key;`, ); - await addColumns(VARIABLES_TABLE_NAME, [column('projectId').varchar(36)]); + await addColumns(VARIABLES_TABLE_NAME, [column('projectId').varchar(36)], { + recreatesOnSqlite: true, + }); await addForeignKey(VARIABLES_TABLE_NAME, 'projectId', ['project', 'id'], undefined, 'CASCADE'); // Create index for unique project key (projectId not null) @@ -65,7 +67,7 @@ export class AddProjectIdToVariableTable1758794506893 implements ReversibleMigra // Remove foreign key constraints and drop the projectId column await dropForeignKey(VARIABLES_TABLE_NAME, 'projectId', ['project', 'id']); - await dropColumns(VARIABLES_TABLE_NAME, ['projectId']); + await dropColumns(VARIABLES_TABLE_NAME, ['projectId'], { recreatesOnSqlite: true }); // Recreate the original unique index on key await queryRunner.query(` diff --git a/packages/@n8n/db/src/migrations/sqlite/1764276827837-AddCreatorIdToProjectTable.ts b/packages/@n8n/db/src/migrations/sqlite/1764276827837-AddCreatorIdToProjectTable.ts index 87154ce34e0..5d8e319fda8 100644 --- a/packages/@n8n/db/src/migrations/sqlite/1764276827837-AddCreatorIdToProjectTable.ts +++ b/packages/@n8n/db/src/migrations/sqlite/1764276827837-AddCreatorIdToProjectTable.ts @@ -15,9 +15,11 @@ export class AddCreatorIdToProjectTable1764276827837 implements ReversibleMigrat schemaBuilder: { addColumns, addForeignKey, column }, queryRunner, }: MigrationContext) { - await addColumns(table.project, [ - column('creatorId').uuid.comment('ID of the user who created the project'), - ]); + await addColumns( + table.project, + [column('creatorId').uuid.comment('ID of the user who created the project')], + { recreatesOnSqlite: true }, + ); await addForeignKey(table.project, 'creatorId', ['user', 'id'], FOREIGN_KEY_NAME, 'SET NULL'); @@ -38,6 +40,6 @@ export class AddCreatorIdToProjectTable1764276827837 implements ReversibleMigrat } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(table.project, ['creatorId']); + await dropColumns(table.project, ['creatorId'], { recreatesOnSqlite: true }); } } diff --git a/packages/@n8n/db/src/migrations/sqlite/1764689448000-AddResolvableFieldsToCredentials.ts b/packages/@n8n/db/src/migrations/sqlite/1764689448000-AddResolvableFieldsToCredentials.ts index 2fa97444f4c..aa956ca9e0c 100644 --- a/packages/@n8n/db/src/migrations/sqlite/1764689448000-AddResolvableFieldsToCredentials.ts +++ b/packages/@n8n/db/src/migrations/sqlite/1764689448000-AddResolvableFieldsToCredentials.ts @@ -8,11 +8,15 @@ export class AddResolvableFieldsToCredentials1764689448000 implements Reversible withFKsDisabled = true as const; async up({ schemaBuilder: { addColumns, addForeignKey, column } }: MigrationContext) { - await addColumns(credentialsTableName, [ - column('isResolvable').bool.notNull.default(false), - column('resolvableAllowFallback').bool.notNull.default(false), - column('resolverId').varchar(16), - ]); + await addColumns( + credentialsTableName, + [ + column('isResolvable').bool.notNull.default(false), + column('resolvableAllowFallback').bool.notNull.default(false), + column('resolverId').varchar(16), + ], + { recreatesOnSqlite: true }, + ); await addForeignKey( credentialsTableName, @@ -24,10 +28,10 @@ export class AddResolvableFieldsToCredentials1764689448000 implements Reversible } async down({ schemaBuilder: { dropColumns } }: MigrationContext) { - await dropColumns(credentialsTableName, [ - 'isResolvable', - 'resolvableAllowFallback', - 'resolverId', - ]); + await dropColumns( + credentialsTableName, + ['isResolvable', 'resolvableAllowFallback', 'resolverId'], + { recreatesOnSqlite: true }, + ); } }