diff --git a/packages/@n8n/api-types/src/index.ts b/packages/@n8n/api-types/src/index.ts index ba8e7e195a..e8b21ec77a 100644 --- a/packages/@n8n/api-types/src/index.ts +++ b/packages/@n8n/api-types/src/index.ts @@ -36,6 +36,7 @@ export { type InsightsByWorkflow, type InsightsByTime, type InsightsDateRange, + type RestrictedInsightsByTime, } from './schemas/insights.schema'; export { diff --git a/packages/@n8n/config/src/index.ts b/packages/@n8n/config/src/index.ts index 31b73bb095..0fce2645d2 100644 --- a/packages/@n8n/config/src/index.ts +++ b/packages/@n8n/config/src/index.ts @@ -37,9 +37,9 @@ import { WorkflowsConfig } from './configs/workflows.config'; import { Config, Env, Nested } from './decorators'; export { Config, Env, Nested } from './decorators'; -export { DatabaseConfig } from './configs/database.config'; +export { DatabaseConfig, SqliteConfig } from './configs/database.config'; export { InstanceSettingsConfig } from './configs/instance-settings-config'; -export { TaskRunnersConfig } from './configs/runners.config'; +export { TaskRunnersConfig, TaskRunnerMode } from './configs/runners.config'; export { SecurityConfig } from './configs/security.config'; export { ExecutionsConfig } from './configs/executions.config'; export { LOG_SCOPES } from './configs/logging.config'; diff --git a/packages/@n8n/eslint-config/src/configs/frontend.ts b/packages/@n8n/eslint-config/src/configs/frontend.ts index 3a69f4d8e9..ae1570eae2 100644 --- a/packages/@n8n/eslint-config/src/configs/frontend.ts +++ b/packages/@n8n/eslint-config/src/configs/frontend.ts @@ -38,6 +38,9 @@ export const frontendConfig = tseslint.config( rules: { 'import-x/no-extraneous-dependencies': 'warn', 'vue/one-component-per-file': 'off', + + // TODO: remove these + 'n8n-local-rules/no-internal-package-import': 'warn', }, }, { @@ -98,6 +101,7 @@ export const frontendConfig = tseslint.config( 'vue/no-side-effects-in-computed-properties': 'warn', 'vue/no-v-text-v-html-on-component': 'warn', 'vue/return-in-computed-property': 'warn', + 'n8n-local-rules/no-internal-package-import': 'warn', }, }, eslintConfigPrettier, diff --git a/packages/@n8n/eslint-config/src/plugin.ts b/packages/@n8n/eslint-config/src/plugin.ts index da81092122..b0ba14cf66 100644 --- a/packages/@n8n/eslint-config/src/plugin.ts +++ b/packages/@n8n/eslint-config/src/plugin.ts @@ -24,6 +24,7 @@ export const localRulesPlugin = { 'n8n-local-rules/no-interpolation-in-regular-string': 'error', 'n8n-local-rules/no-unused-param-in-catch-clause': 'error', 'n8n-local-rules/no-useless-catch-throw': 'error', + 'n8n-local-rules/no-internal-package-import': 'error', }, }, }, diff --git a/packages/@n8n/eslint-config/src/rules/index.ts b/packages/@n8n/eslint-config/src/rules/index.ts index f68f469cc3..59c6a2636a 100644 --- a/packages/@n8n/eslint-config/src/rules/index.ts +++ b/packages/@n8n/eslint-config/src/rules/index.ts @@ -14,6 +14,7 @@ import { NoTopLevelRelativeImportsInBackendModuleRule } from './no-top-level-rel import { NoConstructorInBackendModuleRule } from './no-constructor-in-backend-module.js'; import type { AnyRuleModule } from '@typescript-eslint/utils/ts-eslint'; import { NoArgumentSpreadRule } from './no-argument-spread.js'; +import { NoInternalPackageImportRule } from './no-internal-package-import.js'; export const rules = { 'no-uncaught-json-parse': NoUncaughtJsonParseRule, @@ -31,4 +32,5 @@ export const rules = { 'no-top-level-relative-imports-in-backend-module': NoTopLevelRelativeImportsInBackendModuleRule, 'no-constructor-in-backend-module': NoConstructorInBackendModuleRule, 'no-argument-spread': NoArgumentSpreadRule, + 'no-internal-package-import': NoInternalPackageImportRule, } satisfies Record; diff --git a/packages/@n8n/eslint-config/src/rules/no-internal-package-import.test.ts b/packages/@n8n/eslint-config/src/rules/no-internal-package-import.test.ts new file mode 100644 index 0000000000..da9e0b6d0a --- /dev/null +++ b/packages/@n8n/eslint-config/src/rules/no-internal-package-import.test.ts @@ -0,0 +1,30 @@ +import { RuleTester } from '@typescript-eslint/rule-tester'; +import { NoInternalPackageImportRule } from './no-internal-package-import.js'; + +const ruleTester = new RuleTester(); + +ruleTester.run('no-internal-package-import', NoInternalPackageImportRule, { + valid: [ + { code: 'import { SomeDto } from "@n8n/api-types"' }, + { code: 'import { Logger } from "@n8n/backend-common"' }, + { code: 'import { NodeHelpers } from "@n8n/workflow"' }, + { code: 'import lodash from "lodash"' }, + { code: 'import { helper } from "./local-file"' }, + { code: 'import { utils } from "../utils"' }, + { code: 'import express from "express"' }, + { code: 'import { something } from "@other-org/package/src/file"' }, + ], + + invalid: [ + { + code: 'import { UpdateDataStoreDto } from "@n8n/api-types/src/dto/data-store/update-data-store.dto"', + output: 'import { UpdateDataStoreDto } from "@n8n/api-types"', + errors: [{ messageId: 'noInternalPackageImport' }], + }, + { + code: 'import { helper } from "@n8n/backend-common/src/utils/helper"', + output: 'import { helper } from "@n8n/backend-common"', + errors: [{ messageId: 'noInternalPackageImport' }], + }, + ], +}); diff --git a/packages/@n8n/eslint-config/src/rules/no-internal-package-import.ts b/packages/@n8n/eslint-config/src/rules/no-internal-package-import.ts new file mode 100644 index 0000000000..16ba529548 --- /dev/null +++ b/packages/@n8n/eslint-config/src/rules/no-internal-package-import.ts @@ -0,0 +1,39 @@ +import { ESLintUtils } from '@typescript-eslint/utils'; + +export const NoInternalPackageImportRule = ESLintUtils.RuleCreator.withoutDocs({ + meta: { + type: 'problem', + docs: { + description: 'Disallow imports from internal package paths (e.g. `@n8n/pkg/src/...`).', + }, + messages: { + noInternalPackageImport: + 'Import from "{{ packageRoot }}", not from the internal `/src/` path.', + }, + fixable: 'code', + schema: [], + }, + defaultOptions: [], + create(context) { + const INTERNAL_IMPORT_REGEX = /^(?@n8n\/[^/]+)\/src\//; + + return { + ImportDeclaration(node) { + if (typeof node.source.type !== 'string') return; + + const match = node.source.value.match(INTERNAL_IMPORT_REGEX); + + if (!match?.groups) return; + + const { packageRoot } = match.groups; + + context.report({ + node: node.source, + messageId: 'noInternalPackageImport', + fix: (fixer) => fixer.replaceText(node.source, `"${packageRoot}"`), + data: { packageRoot }, + }); + }, + }; + }, +}); diff --git a/packages/cli/src/databases/repositories/__tests__/execution.repository.test.ts b/packages/cli/src/databases/repositories/__tests__/execution.repository.test.ts index e2fa94acfb..ebd9c26c7c 100644 --- a/packages/cli/src/databases/repositories/__tests__/execution.repository.test.ts +++ b/packages/cli/src/databases/repositories/__tests__/execution.repository.test.ts @@ -1,6 +1,6 @@ import { mockInstance } from '@n8n/backend-test-utils'; import { GlobalConfig } from '@n8n/config'; -import type { SqliteConfig } from '@n8n/config/src/configs/database.config'; +import type { SqliteConfig } from '@n8n/config'; import type { IExecutionResponse } from '@n8n/db'; import { ExecutionEntity, ExecutionRepository } from '@n8n/db'; import { Container } from '@n8n/di'; diff --git a/packages/cli/src/modules/insights/insights.controller.ts b/packages/cli/src/modules/insights/insights.controller.ts index 2d00c9e2bb..78e890eb45 100644 --- a/packages/cli/src/modules/insights/insights.controller.ts +++ b/packages/cli/src/modules/insights/insights.controller.ts @@ -1,6 +1,10 @@ import { InsightsDateFilterDto, ListInsightsWorkflowQueryDto } from '@n8n/api-types'; -import type { InsightsSummary, InsightsByTime, InsightsByWorkflow } from '@n8n/api-types'; -import type { RestrictedInsightsByTime } from '@n8n/api-types/src/schemas/insights.schema'; +import type { + RestrictedInsightsByTime, + InsightsSummary, + InsightsByTime, + InsightsByWorkflow, +} from '@n8n/api-types'; import { AuthenticatedRequest } from '@n8n/db'; import { Get, GlobalScope, Licensed, Query, RestController } from '@n8n/decorators'; import type { UserError } from 'n8n-workflow'; diff --git a/packages/cli/src/task-runners/task-broker/errors/task-runner-execution-timeout.error.ts b/packages/cli/src/task-runners/task-broker/errors/task-runner-execution-timeout.error.ts index ebbde08da9..ee4d1e107a 100644 --- a/packages/cli/src/task-runners/task-broker/errors/task-runner-execution-timeout.error.ts +++ b/packages/cli/src/task-runners/task-broker/errors/task-runner-execution-timeout.error.ts @@ -1,4 +1,4 @@ -import type { TaskRunnerMode } from '@n8n/config/src/configs/runners.config'; +import type { TaskRunnerMode } from '@n8n/config'; import { OperationalError } from 'n8n-workflow'; export class TaskRunnerExecutionTimeoutError extends OperationalError { diff --git a/packages/frontend/editor-ui/eslint.config.mjs b/packages/frontend/editor-ui/eslint.config.mjs index a46cc4f9ab..5df1499c2a 100644 --- a/packages/frontend/editor-ui/eslint.config.mjs +++ b/packages/frontend/editor-ui/eslint.config.mjs @@ -4,6 +4,7 @@ import { frontendConfig } from '@n8n/eslint-config/frontend'; export default defineConfig(frontendConfig, { rules: { // TODO: Remove these + 'n8n-local-rules/no-internal-package-import': 'warn', '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], 'id-denylist': 'warn', 'no-case-declarations': 'warn',