mirror of
https://github.com/n8n-io/n8n.git
synced 2026-08-29 01:39:24 +08:00
chore: Migrate packages/cli to Typescript 7 (#34159)
This commit is contained in:
@@ -69,11 +69,6 @@
|
||||
"import": "./dist/esm/utils/http-proxy-agent.js",
|
||||
"require": "./dist/cjs/utils/http-proxy-agent.js"
|
||||
},
|
||||
"./lazy-import": {
|
||||
"types": "./dist/esm/utils/lazy-import.d.ts",
|
||||
"import": "./dist/esm/utils/lazy-import.js",
|
||||
"require": "./dist/cjs/utils/lazy-import.js"
|
||||
},
|
||||
"./web-search": {
|
||||
"types": "./dist/esm/web-search/index.d.ts",
|
||||
"import": "./dist/esm/web-search/index.js",
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
export { AI_NODE_SDK_VERSION } from './ai-node-sdk-version';
|
||||
|
||||
// Utils
|
||||
// NOTE: `lazyImport` is intentionally NOT re-exported here — import it from the
|
||||
// lightweight `@n8n/ai-utilities/lazy-import` subpath so callers that use it to
|
||||
// defer loading provider SDKs don't eagerly pull this barrel (which statically
|
||||
// imports @langchain/*).
|
||||
export { logWrapper } from './utils/log-wrapper';
|
||||
export { logAiEvent } from './utils/log-ai-event';
|
||||
export { parseSSEStream } from './utils/sse';
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"import": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts"
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -41,3 +41,4 @@ export type { ParseAndValidateResult, ValidationWarning } from './code-builder';
|
||||
|
||||
// SSRF guard contract for the web_fetch tool (cli injects its SsrfProtectionService here)
|
||||
export { type SsrfGuard, createPassthroughSsrfGuard } from './tools/utils/ssrf-guard';
|
||||
export { type ChatPayload } from './workflow-builder-agent';
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import type * as LangchainAnthropic from '@langchain/anthropic';
|
||||
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||
import type * as LangchainOpenAI from '@langchain/openai';
|
||||
import { lazyImport } from '@n8n/ai-utilities/lazy-import';
|
||||
import type { CustomFetch } from '@n8n/backend-network/transport';
|
||||
import { lazyImport } from '@n8n/utils/lazy-import';
|
||||
|
||||
import { MAX_OUTPUT_TOKENS } from '@/constants';
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"express": "catalog:",
|
||||
"testcontainers": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"typescript6": "npm:@typescript/typescript6@6.0.2",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { createVitestConfigWithDecorators } from '@n8n/vitest-config/node-decorators';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import ts from 'typescript';
|
||||
// Uses the legacy JS compiler via the `typescript6` alias: tsgo (typescript 7)
|
||||
// ships no programmatic API for this LanguageService-based entity transform.
|
||||
import ts from 'typescript6';
|
||||
import { mergeConfig, type Plugin } from 'vite';
|
||||
import { configDefaults } from 'vitest/config';
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ export const baseConfig = tseslint.config(
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-imports.md
|
||||
*/
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }],
|
||||
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"import": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts"
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./parsers": {
|
||||
"require": "./dist/parsers/index.js",
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
],
|
||||
"exports": {
|
||||
"./start": {
|
||||
"types": "./dist/start.d.ts",
|
||||
"require": "./dist/start.js",
|
||||
"import": "./src/start.ts",
|
||||
"types": "./dist/start.d.ts"
|
||||
"import": "./src/start.ts"
|
||||
},
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"import": "./src/index.ts",
|
||||
"types": "./dist/index.d.ts"
|
||||
"import": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -117,7 +117,8 @@
|
||||
"ts-essentials": "^7.0.3",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"typescript": "catalog:typescript",
|
||||
"typescript6": "npm:@typescript/typescript6@6.0.2",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
|
||||
@@ -1281,7 +1281,7 @@ describe('CredentialsHelper', () => {
|
||||
dynamicCredentialProxy.setResolverProvider(mockCredentialResolutionProvider);
|
||||
|
||||
const { CredentialResolutionError } = await import(
|
||||
'@/modules/dynamic-credentials.ee/errors/credential-resolution.error'
|
||||
'@/modules/dynamic-credentials.ee/errors/credential-resolution.error.js'
|
||||
);
|
||||
|
||||
const resolvableCredentialEntity = {
|
||||
@@ -1315,7 +1315,7 @@ describe('CredentialsHelper', () => {
|
||||
dynamicCredentialProxy.setResolverProvider(mockCredentialResolutionProvider);
|
||||
|
||||
const { CredentialResolutionError } = await import(
|
||||
'@/modules/dynamic-credentials.ee/errors/credential-resolution.error'
|
||||
'@/modules/dynamic-credentials.ee/errors/credential-resolution.error.js'
|
||||
);
|
||||
|
||||
const resolvableCredentialEntity = {
|
||||
|
||||
@@ -317,7 +317,7 @@ describe('CredentialsOverwrites', () => {
|
||||
});
|
||||
|
||||
// Mock Publisher service - need to import the class first
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
publisherMock = { publishCommand: vi.fn() };
|
||||
mockInstance(Publisher, publisherMock);
|
||||
|
||||
@@ -582,7 +582,7 @@ describe('CredentialsOverwrites', () => {
|
||||
});
|
||||
|
||||
// Mock Publisher service
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
publisherMock = { publishCommand: vi.fn() };
|
||||
mockInstance(Publisher, publisherMock);
|
||||
|
||||
@@ -972,7 +972,7 @@ describe('CredentialsOverwrites', () => {
|
||||
});
|
||||
|
||||
// Mock Publisher service
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
publisherMock = { publishCommand: vi.fn() };
|
||||
mockInstance(Publisher, publisherMock);
|
||||
|
||||
|
||||
@@ -584,7 +584,7 @@ describe('LoadNodesAndCredentials', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
// Import the mocked functions
|
||||
const toolGeneration = await import('@/tool-generation');
|
||||
const toolGeneration = await import('@/tool-generation/index.js');
|
||||
createAiTools = toolGeneration.createAiTools as Mock;
|
||||
createHitlTools = toolGeneration.createHitlTools as Mock;
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ describe('Webhook', () => {
|
||||
|
||||
describe('run', () => {
|
||||
beforeEach(async () => {
|
||||
const { ScalingService } = await import('@/scaling/scaling.service');
|
||||
const { ScalingService } = await import('@/scaling/scaling.service.js');
|
||||
Container.set(ScalingService, { setupQueue: vi.fn() } as unknown as InstanceType<
|
||||
typeof ScalingService
|
||||
>);
|
||||
|
||||
@@ -71,7 +71,7 @@ export class SecurityAudit extends BaseCommand<z.infer<typeof flagsSchema>> {
|
||||
throw new UserError([message, hint].join('. '));
|
||||
}
|
||||
|
||||
const { SecurityAuditService } = await import('@/security-audit/security-audit.service');
|
||||
const { SecurityAuditService } = await import('@/security-audit/security-audit.service.js');
|
||||
|
||||
const result = await Container.get(SecurityAuditService).run(
|
||||
categories,
|
||||
|
||||
@@ -141,7 +141,7 @@ export abstract class BaseCommand<F = never> {
|
||||
this.globalConfig.multiMainSetup.enabled ||
|
||||
this.globalConfig.cache.backend === 'redis';
|
||||
if (useRedisForLocking) {
|
||||
const { RedisLockService } = await import('@/scaling/redis-lock.service');
|
||||
const { RedisLockService } = await import('@/scaling/redis-lock.service.js');
|
||||
Container.get(LockService).setProvider(Container.get(RedisLockService));
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ export abstract class BaseCommand<F = never> {
|
||||
);
|
||||
}
|
||||
|
||||
const { TaskRunnerModule } = await import('@/task-runners/task-runner-module');
|
||||
const { TaskRunnerModule } = await import('@/task-runners/task-runner-module.js');
|
||||
await Container.get(TaskRunnerModule).start();
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ export abstract class BaseCommand<F = never> {
|
||||
const communityPackagesConfig = Container.get(CommunityPackagesConfig);
|
||||
if (communityPackagesConfig.enabled && this.needsCommunityPackages) {
|
||||
const { CommunityPackagesService } = await import(
|
||||
'@/modules/community-packages/community-packages.service'
|
||||
'@/modules/community-packages/community-packages.service.js'
|
||||
);
|
||||
await Container.get(CommunityPackagesService).init();
|
||||
}
|
||||
@@ -269,7 +269,7 @@ export abstract class BaseCommand<F = never> {
|
||||
const isS3WriteMode = binaryDataConfig.mode === 's3';
|
||||
const isAzureWriteMode = binaryDataConfig.mode === 'azure';
|
||||
|
||||
const { DatabaseManager } = await import('@/binary-data/database.manager');
|
||||
const { DatabaseManager } = await import('@/binary-data/database.manager.js');
|
||||
binaryDataService.setManager('database', Container.get(DatabaseManager));
|
||||
|
||||
if (isS3WriteMode) {
|
||||
@@ -340,7 +340,7 @@ export abstract class BaseCommand<F = never> {
|
||||
const objectStoreService = await this.initObjectStoreIfConfigured();
|
||||
if (objectStoreService) {
|
||||
const { ObjectStoreManager } = await import(
|
||||
'n8n-core/dist/binary-data/object-store.manager'
|
||||
'n8n-core/dist/binary-data/object-store.manager.js'
|
||||
);
|
||||
binaryDataService.setManager('s3', new ObjectStoreManager(objectStoreService));
|
||||
}
|
||||
@@ -354,7 +354,9 @@ export abstract class BaseCommand<F = never> {
|
||||
try {
|
||||
const azureBlobService = await this.initAzureStoreIfConfigured();
|
||||
if (azureBlobService) {
|
||||
const { AzureBlobManager } = await import('n8n-core/dist/binary-data/azure-blob.manager');
|
||||
const { AzureBlobManager } = await import(
|
||||
'n8n-core/dist/binary-data/azure-blob.manager.js'
|
||||
);
|
||||
binaryDataService.setManager('azure', new AzureBlobManager(azureBlobService));
|
||||
}
|
||||
} catch {
|
||||
@@ -373,12 +375,12 @@ export abstract class BaseCommand<F = never> {
|
||||
if (Container.get(ObjectStoreConfig).bucket.name === '') return undefined;
|
||||
|
||||
const { ObjectStoreService } = await import(
|
||||
'n8n-core/dist/binary-data/object-store/object-store.service.ee'
|
||||
'n8n-core/dist/binary-data/object-store/object-store.service.ee.js'
|
||||
);
|
||||
const objectStoreService = Container.get(ObjectStoreService);
|
||||
await objectStoreService.init();
|
||||
|
||||
const { S3ByteStore } = await import('@/blob-storage/s3-byte-store.ee');
|
||||
const { S3ByteStore } = await import('@/blob-storage/s3-byte-store.ee.js');
|
||||
Container.get(ExecutionDataJsonStore).registerByteStore(
|
||||
's3',
|
||||
new S3ByteStore(objectStoreService),
|
||||
@@ -391,12 +393,12 @@ export abstract class BaseCommand<F = never> {
|
||||
if (Container.get(AzureBlobConfig).containerName === '') return;
|
||||
|
||||
const { AzureBlobService } = await import(
|
||||
'n8n-core/dist/binary-data/azure-blob/azure-blob.service.ee'
|
||||
'n8n-core/dist/binary-data/azure-blob/azure-blob.service.ee.js'
|
||||
);
|
||||
const azureBlobService = Container.get(AzureBlobService);
|
||||
await azureBlobService.init();
|
||||
|
||||
const { AzureByteStore } = await import('@/blob-storage/azure-byte-store.ee');
|
||||
const { AzureByteStore } = await import('@/blob-storage/azure-byte-store.ee.js');
|
||||
Container.get(ExecutionDataJsonStore).registerByteStore(
|
||||
'az',
|
||||
new AzureByteStore(azureBlobService),
|
||||
|
||||
@@ -284,7 +284,7 @@ export class Start extends BaseCommand<z.infer<typeof flagsSchema>> {
|
||||
await this.moduleRegistry.initModules(this.instanceSettings.instanceType);
|
||||
|
||||
// Initialize auth handler registry after modules are loaded
|
||||
const { AuthHandlerRegistry } = await import('@/auth/auth-handler.registry');
|
||||
const { AuthHandlerRegistry } = await import('@/auth/auth-handler.registry.js');
|
||||
await Container.get(AuthHandlerRegistry).init();
|
||||
|
||||
if (this.instanceSettings.isMultiMain) {
|
||||
@@ -297,7 +297,7 @@ export class Start extends BaseCommand<z.infer<typeof flagsSchema>> {
|
||||
|
||||
private async initInstanceSettingsLoader(): Promise<void> {
|
||||
const { InstanceSettingsLoaderService } = await import(
|
||||
'@/instance-settings-loader/instance-settings-loader.service'
|
||||
'@/instance-settings-loader/instance-settings-loader.service.js'
|
||||
);
|
||||
await Container.get(InstanceSettingsLoaderService).init();
|
||||
}
|
||||
@@ -411,21 +411,21 @@ export class Start extends BaseCommand<z.infer<typeof flagsSchema>> {
|
||||
// Start to get active workflows and run their triggers
|
||||
if (this.globalConfig.workflows.useWorkflowPublicationService) {
|
||||
const { PublishedWorkflowEnqueuer } = await import(
|
||||
'@/workflows/publication/published-workflow-enqueuer'
|
||||
'@/workflows/publication/published-workflow-enqueuer.js'
|
||||
);
|
||||
const { WorkflowPublicationOutboxConsumer } = await import(
|
||||
'@/workflows/publication/workflow-publication-outbox-consumer'
|
||||
'@/workflows/publication/workflow-publication-outbox-consumer.js'
|
||||
);
|
||||
const { WorkflowPublicationOutboxCleanupService } = await import(
|
||||
'@/workflows/publication/workflow-publication-outbox-cleanup.service'
|
||||
'@/workflows/publication/workflow-publication-outbox-cleanup.service.js'
|
||||
);
|
||||
const { WorkflowPublicationReconciler } = await import(
|
||||
'@/workflows/publication/workflow-publication-reconciler.service'
|
||||
'@/workflows/publication/workflow-publication-reconciler.service.js'
|
||||
);
|
||||
|
||||
// Import for its side effect: registering the trigger deactivator's
|
||||
// @OnLeaderStepdown and @OnShutdown handlers. Nothing else loads this module.
|
||||
await import('@/workflows/publication/published-workflow-trigger-deactivator');
|
||||
await import('@/workflows/publication/published-workflow-trigger-deactivator.js');
|
||||
|
||||
// Enqueue needs to happen before outbox consumer init, so it can activate
|
||||
// everything on the first drain
|
||||
|
||||
@@ -98,7 +98,7 @@ export class Webhook extends BaseCommand {
|
||||
}
|
||||
|
||||
async run() {
|
||||
const { ScalingService } = await import('@/scaling/scaling.service');
|
||||
const { ScalingService } = await import('@/scaling/scaling.service.js');
|
||||
await Container.get(ScalingService).setupQueue();
|
||||
await this.server.start();
|
||||
this.server.markAsReady();
|
||||
|
||||
@@ -178,7 +178,7 @@ export class Worker extends BaseCommand<z.infer<typeof flagsSchema>> {
|
||||
}
|
||||
|
||||
async initScalingService() {
|
||||
const { ScalingService } = await import('@/scaling/scaling.service');
|
||||
const { ScalingService } = await import('@/scaling/scaling.service.js');
|
||||
this.scalingService = Container.get(ScalingService);
|
||||
|
||||
await this.scalingService.setupQueue();
|
||||
@@ -193,7 +193,7 @@ export class Worker extends BaseCommand<z.infer<typeof flagsSchema>> {
|
||||
|
||||
let workerServer: WorkerServer | undefined;
|
||||
if (Object.values(endpointsConfig).some((e) => e)) {
|
||||
const { WorkerServer } = await import('@/scaling/worker-server');
|
||||
const { WorkerServer } = await import('@/scaling/worker-server.js');
|
||||
workerServer = Container.get(WorkerServer);
|
||||
await workerServer.init(endpointsConfig);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export class CredentialsOverwrites {
|
||||
}
|
||||
|
||||
private async broadcastReloadOverwriteCredentialsCommand(): Promise<void> {
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
await Container.get(Publisher).publishCommand({ command: 'reload-overwrite-credentials' });
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ export class CredentialsOverwrites {
|
||||
private async reloadFrontendService() {
|
||||
// FrontendService has CredentialOverwrites injected via the constructor
|
||||
// to break the circular dependency we need to use the container to get the instance
|
||||
const { FrontendService } = await import('./services/frontend.service');
|
||||
const { FrontendService } = await import('./services/frontend.service.js');
|
||||
await Container.get(FrontendService)?.generateTypes();
|
||||
}
|
||||
|
||||
|
||||
@@ -1555,7 +1555,7 @@ export class TelemetryEventRelay extends EventRelay {
|
||||
}
|
||||
|
||||
private async getOtelTelemetryInfo() {
|
||||
const { OtelConfig } = await import('@/modules/otel/otel.config');
|
||||
const { OtelConfig } = await import('@/modules/otel/otel.config.js');
|
||||
const otelConfig = Container.get(OtelConfig);
|
||||
|
||||
return {
|
||||
|
||||
@@ -155,7 +155,7 @@ export class License implements LicenseProvider {
|
||||
|
||||
private async broadcastReloadLicenseCommand() {
|
||||
if (this.globalConfig.executions.mode === 'queue' && this.instanceSettings.isLeader) {
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
await Container.get(Publisher).publishCommand({ command: 'reload-license' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,11 +656,11 @@ export class LoadNodesAndCredentials {
|
||||
}
|
||||
|
||||
async setupHotReload() {
|
||||
const { default: debounce } = await import('lodash/debounce');
|
||||
const { default: debounce } = await import('lodash/debounce.js');
|
||||
|
||||
const { subscribe } = await import('@parcel/watcher');
|
||||
|
||||
const { Push } = await import('@/push');
|
||||
const { Push } = await import('@/push/index.js');
|
||||
const push = Container.get(Push);
|
||||
|
||||
for (const loader of Object.values(this.loaders)) {
|
||||
|
||||
@@ -108,7 +108,7 @@ export class AgentPublishService {
|
||||
);
|
||||
}
|
||||
|
||||
const { AgentTaskService } = await import('./agent-task.service');
|
||||
const { AgentTaskService } = await import('./agent-task.service.js');
|
||||
await Container.get(AgentTaskService)
|
||||
.requestReconcile(agentId)
|
||||
.catch((error) =>
|
||||
@@ -145,7 +145,7 @@ export class AgentPublishService {
|
||||
});
|
||||
}
|
||||
|
||||
const { AgentTaskService } = await import('./agent-task.service');
|
||||
const { AgentTaskService } = await import('./agent-task.service.js');
|
||||
await Container.get(AgentTaskService)
|
||||
.requestReconcile(agentId)
|
||||
.catch((error) =>
|
||||
|
||||
@@ -113,14 +113,14 @@ export interface ReconstructAgentRuntimeParams {
|
||||
|
||||
async function getChatIntegrationToolServices() {
|
||||
const { IntegrationMessageContextService } = await import(
|
||||
'./integrations/integration-message-context.service'
|
||||
'./integrations/integration-message-context.service.js'
|
||||
);
|
||||
// eslint-disable-next-line import-x/no-cycle
|
||||
const { ChatIntegrationActionExecutor } = await import(
|
||||
'./integrations/integration-action-executor'
|
||||
'./integrations/integration-action-executor.js'
|
||||
);
|
||||
const { ChatIntegrationContextQueryExecutor } = await import(
|
||||
'./integrations/integration-context-query-executor'
|
||||
'./integrations/integration-context-query-executor.js'
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -131,7 +131,7 @@ async function getChatIntegrationToolServices() {
|
||||
}
|
||||
|
||||
async function getWorkflowRunner(): Promise<WorkflowRunner> {
|
||||
const { WorkflowRunner } = await import('@/workflow-runner');
|
||||
const { WorkflowRunner } = await import('@/workflow-runner.js');
|
||||
return Container.get(WorkflowRunner);
|
||||
}
|
||||
|
||||
@@ -467,7 +467,7 @@ export class AgentRuntimeReconstructionService {
|
||||
private makeToolResolver(projectId: string): ToolResolver {
|
||||
return async (ref: AgentJsonToolConfig) => {
|
||||
if (ref.type === 'workflow') {
|
||||
const { resolveWorkflowTool } = await import('./tools/workflow-tool-factory');
|
||||
const { resolveWorkflowTool } = await import('./tools/workflow-tool-factory.js');
|
||||
return await resolveWorkflowTool(ref, {
|
||||
workflowRepository: this.workflowRepository,
|
||||
workflowRunner: await getWorkflowRunner(),
|
||||
@@ -478,7 +478,7 @@ export class AgentRuntimeReconstructionService {
|
||||
}
|
||||
|
||||
if (ref.type === 'node') {
|
||||
const { resolveNodeTool } = await import('./tools/node-tool-factory');
|
||||
const { resolveNodeTool } = await import('./tools/node-tool-factory.js');
|
||||
return await resolveNodeTool(ref, {
|
||||
executor: this.ephemeralNodeExecutor,
|
||||
projectId,
|
||||
@@ -524,7 +524,7 @@ export class AgentRuntimeReconstructionService {
|
||||
(await this.agentFileRepository.hasFilesForAgent(agentId))
|
||||
) {
|
||||
const { createKnowledgeRetrievalTools } = await import(
|
||||
'./tools/knowledge/search-knowledge.tool'
|
||||
'./tools/knowledge/search-knowledge.tool.js'
|
||||
);
|
||||
agent.tool(
|
||||
createKnowledgeRetrievalTools({
|
||||
|
||||
@@ -197,7 +197,7 @@ export class AgentSkillsService {
|
||||
}
|
||||
|
||||
private async clearRuntimes(agentId: string): Promise<void> {
|
||||
const { AgentRuntimeCacheService } = await import('./agent-runtime-cache.service');
|
||||
const { AgentRuntimeCacheService } = await import('./agent-runtime-cache.service.js');
|
||||
Container.get(AgentRuntimeCacheService).clearRuntimes(agentId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,50 +8,52 @@ import { InstanceSettings } from 'n8n-core';
|
||||
@BackendModule({ name: 'agents' })
|
||||
export class AgentsModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./agents-catalog.controller');
|
||||
await import('./agent-threads.controller');
|
||||
await import('./agents.controller');
|
||||
await import('./agents-config.controller');
|
||||
await import('./agents-skills.controller');
|
||||
await import('./agent-knowledge.controller');
|
||||
await import('./agent-publish.controller');
|
||||
await import('./agent-chat.controller');
|
||||
await import('./agent-integrations.controller');
|
||||
await import('./agent-vector-stores.controller');
|
||||
await import('./agent-tasks.controller');
|
||||
await import('./agent-sandbox.controller');
|
||||
await import('./agents-list.controller');
|
||||
await import('./builder/agents-builder-settings.controller');
|
||||
await import('./agents-catalog.controller.js');
|
||||
await import('./agent-threads.controller.js');
|
||||
await import('./agents.controller.js');
|
||||
await import('./agents-config.controller.js');
|
||||
await import('./agents-skills.controller.js');
|
||||
await import('./agent-knowledge.controller.js');
|
||||
await import('./agent-publish.controller.js');
|
||||
await import('./agent-chat.controller.js');
|
||||
await import('./agent-integrations.controller.js');
|
||||
await import('./agent-vector-stores.controller.js');
|
||||
await import('./agent-tasks.controller.js');
|
||||
await import('./agent-sandbox.controller.js');
|
||||
await import('./agents-list.controller.js');
|
||||
await import('./builder/agents-builder-settings.controller.js');
|
||||
|
||||
const { AgentsService } = await import('./agents.service');
|
||||
const { AgentsService } = await import('./agents.service.js');
|
||||
Container.get(AgentsService);
|
||||
|
||||
const { AgentsBuilderSettingsService } = await import(
|
||||
'./builder/agents-builder-settings.service'
|
||||
'./builder/agents-builder-settings.service.js'
|
||||
);
|
||||
Container.get(AgentsBuilderSettingsService);
|
||||
|
||||
const { AgentExecutionService } = await import('./agent-execution.service');
|
||||
const { AgentExecutionService } = await import('./agent-execution.service.js');
|
||||
Container.get(AgentExecutionService);
|
||||
|
||||
const { AgentRuntimeCacheService } = await import('./agent-runtime-cache.service');
|
||||
const { AgentRuntimeCacheService } = await import('./agent-runtime-cache.service.js');
|
||||
Container.get(AgentRuntimeCacheService);
|
||||
|
||||
const { AgentHistoryRepository } = await import('./repositories/agent-history.repository');
|
||||
const { AgentHistoryRepository } = await import('./repositories/agent-history.repository.js');
|
||||
Container.get(AgentHistoryRepository);
|
||||
|
||||
// Register the sandboxed runtime service (lazy — the V8 isolate is only
|
||||
// created on first use, so this import has negligible startup cost).
|
||||
const { AgentSecureRuntime } = await import('./runtime/agent-secure-runtime');
|
||||
const { AgentSecureRuntime } = await import('./runtime/agent-secure-runtime.js');
|
||||
Container.get(AgentSecureRuntime);
|
||||
|
||||
// Populate the integration registry with supported chat platforms.
|
||||
// Adding a new platform is adding one subclass + one register() call.
|
||||
const { ChatIntegrationRegistry } = await import('./integrations/agent-chat-integration');
|
||||
const { SlackIntegration } = await import('./integrations/platforms/slack-integration');
|
||||
const { TelegramIntegration } = await import('./integrations/platforms/telegram-integration');
|
||||
const { LinearIntegration } = await import('./integrations/platforms/linear-integration');
|
||||
const { N8nChatIntegration } = await import('./integrations/platforms/n8n-chat-integration');
|
||||
const { ChatIntegrationRegistry } = await import('./integrations/agent-chat-integration.js');
|
||||
const { SlackIntegration } = await import('./integrations/platforms/slack-integration.js');
|
||||
const { TelegramIntegration } = await import(
|
||||
'./integrations/platforms/telegram-integration.js'
|
||||
);
|
||||
const { LinearIntegration } = await import('./integrations/platforms/linear-integration.js');
|
||||
const { N8nChatIntegration } = await import('./integrations/platforms/n8n-chat-integration.js');
|
||||
const registry = Container.get(ChatIntegrationRegistry);
|
||||
registry.register(Container.get(SlackIntegration));
|
||||
registry.register(Container.get(TelegramIntegration));
|
||||
@@ -69,8 +71,8 @@ export class AgentsModule implements ModuleInterface {
|
||||
//
|
||||
// Tasks remain leader-only by design — a cron firing on multiple
|
||||
// mains would run the agent twice for the same tick.
|
||||
const { ChatIntegrationService } = await import('./integrations/chat-integration.service');
|
||||
const { AgentTaskService } = await import('./agent-task.service');
|
||||
const { ChatIntegrationService } = await import('./integrations/chat-integration.service.js');
|
||||
const { AgentTaskService } = await import('./agent-task.service.js');
|
||||
const chatService = Container.get(ChatIntegrationService);
|
||||
const taskService = Container.get(AgentTaskService);
|
||||
const logger = Container.get(Logger);
|
||||
@@ -93,7 +95,7 @@ export class AgentsModule implements ModuleInterface {
|
||||
|
||||
async settings() {
|
||||
const config = Container.get(AgentsConfig);
|
||||
const { isAgentKnowledgeBaseEnabled } = await import('./agent-knowledge-gate');
|
||||
const { isAgentKnowledgeBaseEnabled } = await import('./agent-knowledge-gate.js');
|
||||
return {
|
||||
enabled: true,
|
||||
modules: [...config.modules],
|
||||
@@ -102,33 +104,35 @@ export class AgentsModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { Agent } = await import('./entities/agent.entity');
|
||||
const { AgentFile } = await import('./entities/agent-file.entity');
|
||||
const { AgentChatSubscription } = await import('./entities/agent-chat-subscription.entity');
|
||||
const { AgentCheckpoint } = await import('./entities/agent-checkpoint.entity');
|
||||
const { AgentResourceEntity } = await import('./entities/agent-resource.entity');
|
||||
const { AgentThreadEntity } = await import('./entities/agent-thread.entity');
|
||||
const { AgentMessageEntity } = await import('./entities/agent-message.entity');
|
||||
const { AgentExecutionThread } = await import('./entities/agent-execution-thread.entity');
|
||||
const { AgentExecution } = await import('./entities/agent-execution.entity');
|
||||
const { AgentHistory } = await import('./entities/agent-history.entity');
|
||||
const { AgentTask } = await import('./entities/agent-task.entity');
|
||||
const { AgentTaskRunLock } = await import('./entities/agent-task-run-lock.entity');
|
||||
const { AgentTaskSnapshot } = await import('./entities/agent-task-snapshot.entity');
|
||||
const { AgentObservationEntity } = await import('./entities/agent-observation.entity');
|
||||
const { Agent } = await import('./entities/agent.entity.js');
|
||||
const { AgentFile } = await import('./entities/agent-file.entity.js');
|
||||
const { AgentChatSubscription } = await import('./entities/agent-chat-subscription.entity.js');
|
||||
const { AgentCheckpoint } = await import('./entities/agent-checkpoint.entity.js');
|
||||
const { AgentResourceEntity } = await import('./entities/agent-resource.entity.js');
|
||||
const { AgentThreadEntity } = await import('./entities/agent-thread.entity.js');
|
||||
const { AgentMessageEntity } = await import('./entities/agent-message.entity.js');
|
||||
const { AgentExecutionThread } = await import('./entities/agent-execution-thread.entity.js');
|
||||
const { AgentExecution } = await import('./entities/agent-execution.entity.js');
|
||||
const { AgentHistory } = await import('./entities/agent-history.entity.js');
|
||||
const { AgentTask } = await import('./entities/agent-task.entity.js');
|
||||
const { AgentTaskRunLock } = await import('./entities/agent-task-run-lock.entity.js');
|
||||
const { AgentTaskSnapshot } = await import('./entities/agent-task-snapshot.entity.js');
|
||||
const { AgentObservationEntity } = await import('./entities/agent-observation.entity.js');
|
||||
const { AgentObservationCursorEntity } = await import(
|
||||
'./entities/agent-observation-cursor.entity'
|
||||
'./entities/agent-observation-cursor.entity.js'
|
||||
);
|
||||
const { AgentObservationLockEntity } = await import('./entities/agent-observation-lock.entity');
|
||||
const { AgentMemoryEntryEntity } = await import('./entities/agent-memory-entry.entity');
|
||||
const { AgentObservationLockEntity } = await import(
|
||||
'./entities/agent-observation-lock.entity.js'
|
||||
);
|
||||
const { AgentMemoryEntryEntity } = await import('./entities/agent-memory-entry.entity.js');
|
||||
const { AgentMemoryEntryLockEntity } = await import(
|
||||
'./entities/agent-memory-entry-lock.entity'
|
||||
'./entities/agent-memory-entry-lock.entity.js'
|
||||
);
|
||||
const { AgentMemoryEntrySourceEntity } = await import(
|
||||
'./entities/agent-memory-entry-source.entity'
|
||||
'./entities/agent-memory-entry-source.entity.js'
|
||||
);
|
||||
const { AgentMemoryEntryCursorEntity } = await import(
|
||||
'./entities/agent-memory-entry-cursor.entity'
|
||||
'./entities/agent-memory-entry-cursor.entity.js'
|
||||
);
|
||||
|
||||
return [
|
||||
@@ -156,7 +160,7 @@ export class AgentsModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async context() {
|
||||
const { AgentsService } = await import('./agents.service');
|
||||
const { AgentsService } = await import('./agents.service.js');
|
||||
|
||||
return { agentsService: Container.get(AgentsService) };
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@ export class AgentsService {
|
||||
this.eventService.emit('agent-deleted', { agentId, projectId });
|
||||
|
||||
try {
|
||||
const { AgentTaskService } = await import('./agent-task.service');
|
||||
const { AgentTaskService } = await import('./agent-task.service.js');
|
||||
await Container.get(AgentTaskService).requestReconcile(agentId);
|
||||
} catch (error) {
|
||||
this.logger.warn('Failed to stop tasks on agent delete', {
|
||||
|
||||
@@ -89,7 +89,7 @@ interface DisconnectChannelOptions {
|
||||
async function getAgentExecutionOrchestratorService() {
|
||||
// eslint-disable-next-line import-x/no-cycle
|
||||
const { AgentExecutionOrchestratorService } = await import(
|
||||
'../agent-execution-orchestrator.service'
|
||||
'../agent-execution-orchestrator.service.js'
|
||||
);
|
||||
return Container.get(AgentExecutionOrchestratorService);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export async function syncAgentIntegrations(
|
||||
): Promise<void> {
|
||||
try {
|
||||
// eslint-disable-next-line import-x/no-cycle
|
||||
const { ChatIntegrationService } = await import('./chat-integration.service');
|
||||
const { ChatIntegrationService } = await import('./chat-integration.service.js');
|
||||
await Container.get(ChatIntegrationService).syncToConfig(agent, previous, next);
|
||||
} catch (error) {
|
||||
logger.warn('Failed to sync chat integrations', {
|
||||
|
||||
@@ -240,7 +240,7 @@ export class SubAgentForegroundRunner {
|
||||
async function getReconstructionService() {
|
||||
// eslint-disable-next-line import-x/no-cycle
|
||||
const { AgentRuntimeReconstructionService } = await import(
|
||||
'../agent-runtime-reconstruction.service'
|
||||
'../agent-runtime-reconstruction.service.js'
|
||||
);
|
||||
return Container.get(AgentRuntimeReconstructionService);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ export class BreakingChangesModule implements ModuleInterface {
|
||||
if (!MIGRATION_REPORT_TARGET_VERSION) return;
|
||||
|
||||
// Import rules so that they are added to the BreakingChangeRuleMetadata registry
|
||||
await import('./rules');
|
||||
await import('./rules/index.js');
|
||||
|
||||
// Register rules in the service
|
||||
const { BreakingChangeService } = await import('./breaking-changes.service');
|
||||
const { BreakingChangeService } = await import('./breaking-changes.service.js');
|
||||
Container.get(BreakingChangeService).registerRules();
|
||||
|
||||
await import('./breaking-changes.controller');
|
||||
await import('./breaking-changes.controller.js');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import { InstanceSettings } from 'n8n-core';
|
||||
@BackendModule({ name: 'chat-hub' })
|
||||
export class ChatHubModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./chat-hub.controller');
|
||||
await import('./chat-hub.settings.controller');
|
||||
const { ChatHubEventRelay } = await import('./chat-hub-event-relay.service');
|
||||
await import('./chat-hub.controller.js');
|
||||
await import('./chat-hub.settings.controller.js');
|
||||
const { ChatHubEventRelay } = await import('./chat-hub-event-relay.service.js');
|
||||
|
||||
Container.get(ChatHubEventRelay);
|
||||
|
||||
@@ -18,12 +18,12 @@ export class ChatHubModule implements ModuleInterface {
|
||||
const isQueueMode = Container.get(ExecutionsConfig).mode === 'queue';
|
||||
const isWorker = Container.get(InstanceSettings).isWorker;
|
||||
if (!isQueueMode || isWorker) {
|
||||
await import('./chat-hub-execution-watcher.service');
|
||||
await import('./chat-hub-execution-watcher.service.js');
|
||||
}
|
||||
}
|
||||
|
||||
async settings() {
|
||||
const { ChatHubSettingsService } = await import('./chat-hub.settings.service');
|
||||
const { ChatHubSettingsService } = await import('./chat-hub.settings.service.js');
|
||||
const service = Container.get(ChatHubSettingsService);
|
||||
const [enabled, providers, semanticSearch] = await Promise.all([
|
||||
service.getEnabled(),
|
||||
@@ -40,10 +40,10 @@ export class ChatHubModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { ChatHubSession } = await import('./chat-hub-session.entity');
|
||||
const { ChatHubMessage } = await import('./chat-hub-message.entity');
|
||||
const { ChatHubAgent } = await import('./chat-hub-agent.entity');
|
||||
const { ChatHubTool } = await import('./chat-hub-tool.entity');
|
||||
const { ChatHubSession } = await import('./chat-hub-session.entity.js');
|
||||
const { ChatHubMessage } = await import('./chat-hub-message.entity.js');
|
||||
const { ChatHubAgent } = await import('./chat-hub-agent.entity.js');
|
||||
const { ChatHubTool } = await import('./chat-hub-tool.entity.js');
|
||||
|
||||
return [ChatHubSession, ChatHubMessage, ChatHubAgent, ChatHubTool];
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ describe('executeNpmCommand', () => {
|
||||
|
||||
const importFreshModule = async () => {
|
||||
vi.resetModules();
|
||||
return await import('../npm-utils');
|
||||
return await import('../npm-utils.js');
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -8,23 +8,23 @@ import path from 'node:path';
|
||||
@BackendModule({ name: 'community-packages' })
|
||||
export class CommunityPackagesModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./community-packages.controller');
|
||||
await import('./community-node-types.controller');
|
||||
await import('./community-packages.controller.js');
|
||||
await import('./community-node-types.controller.js');
|
||||
}
|
||||
|
||||
async commands() {
|
||||
await import('./community-node.command');
|
||||
await import('./community-node.command.js');
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { InstalledNodes } = await import('./installed-nodes.entity');
|
||||
const { InstalledPackages } = await import('./installed-packages.entity');
|
||||
const { InstalledNodes } = await import('./installed-nodes.entity.js');
|
||||
const { InstalledPackages } = await import('./installed-packages.entity.js');
|
||||
|
||||
return [InstalledNodes, InstalledPackages] as EntityClass[];
|
||||
}
|
||||
|
||||
async settings() {
|
||||
const { CommunityPackagesConfig } = await import('./community-packages.config');
|
||||
const { CommunityPackagesConfig } = await import('./community-packages.config.js');
|
||||
|
||||
return {
|
||||
communityNodesEnabled: Container.get(CommunityPackagesConfig).enabled,
|
||||
@@ -33,7 +33,7 @@ export class CommunityPackagesModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async nodeLoaders() {
|
||||
const { CommunityPackagesConfig } = await import('./community-packages.config');
|
||||
const { CommunityPackagesConfig } = await import('./community-packages.config.js');
|
||||
if (Container.get(CommunityPackagesConfig).preventLoading) return [];
|
||||
|
||||
const dir = path.join(Container.get(InstanceSettings).nodesDownloadDir, 'node_modules');
|
||||
|
||||
@@ -5,15 +5,15 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'data-table' })
|
||||
export class DataTableModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./data-table.controller');
|
||||
await import('./data-table-aggregate.controller');
|
||||
await import('./data-table-uploads.controller');
|
||||
await import('./data-table.controller.js');
|
||||
await import('./data-table-aggregate.controller.js');
|
||||
await import('./data-table-uploads.controller.js');
|
||||
|
||||
const { DataTableService } = await import('./data-table.service');
|
||||
const { DataTableService } = await import('./data-table.service.js');
|
||||
await Container.get(DataTableService).start();
|
||||
|
||||
const { OwnershipTransferHandlerRegistry } = await import(
|
||||
'@/services/ownership-transfer/ownership-transfer-handler.registry'
|
||||
'@/services/ownership-transfer/ownership-transfer-handler.registry.js'
|
||||
);
|
||||
Container.get(OwnershipTransferHandlerRegistry).register({
|
||||
resource: 'data-table',
|
||||
@@ -29,34 +29,34 @@ export class DataTableModule implements ModuleInterface {
|
||||
},
|
||||
});
|
||||
|
||||
const { DataTableAggregateService } = await import('./data-table-aggregate.service');
|
||||
const { DataTableAggregateService } = await import('./data-table-aggregate.service.js');
|
||||
await Container.get(DataTableAggregateService).start();
|
||||
|
||||
const { DataTableFileCleanupService } = await import('./data-table-file-cleanup.service');
|
||||
const { DataTableFileCleanupService } = await import('./data-table-file-cleanup.service.js');
|
||||
await Container.get(DataTableFileCleanupService).start();
|
||||
}
|
||||
|
||||
@OnShutdown()
|
||||
async shutdown() {
|
||||
const { DataTableService } = await import('./data-table.service');
|
||||
const { DataTableService } = await import('./data-table.service.js');
|
||||
await Container.get(DataTableService).shutdown();
|
||||
|
||||
const { DataTableAggregateService } = await import('./data-table-aggregate.service');
|
||||
const { DataTableAggregateService } = await import('./data-table-aggregate.service.js');
|
||||
await Container.get(DataTableAggregateService).shutdown();
|
||||
|
||||
const { DataTableFileCleanupService } = await import('./data-table-file-cleanup.service');
|
||||
const { DataTableFileCleanupService } = await import('./data-table-file-cleanup.service.js');
|
||||
await Container.get(DataTableFileCleanupService).shutdown();
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { DataTable } = await import('./data-table.entity');
|
||||
const { DataTableColumn } = await import('./data-table-column.entity');
|
||||
const { DataTable } = await import('./data-table.entity.js');
|
||||
const { DataTableColumn } = await import('./data-table-column.entity.js');
|
||||
|
||||
return [DataTable, DataTableColumn];
|
||||
}
|
||||
|
||||
async context() {
|
||||
const { DataTableProxyService } = await import('./data-table-proxy.service');
|
||||
const { DataTableProxyService } = await import('./data-table-proxy.service.js');
|
||||
|
||||
return { dataTableProxyProvider: Container.get(DataTableProxyService) };
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ export class DataTableService {
|
||||
return result;
|
||||
}
|
||||
|
||||
async upsertRow<T extends boolean | undefined>(
|
||||
async upsertRow(
|
||||
dataTableId: string,
|
||||
projectId: string,
|
||||
dto: Omit<UpsertDataTableRowDto, 'returnData' | 'dryRun'>,
|
||||
@@ -433,7 +433,7 @@ export class DataTableService {
|
||||
return { data: transformedData, filter: transformedFilter };
|
||||
}
|
||||
|
||||
async updateRows<T extends boolean | undefined>(
|
||||
async updateRows(
|
||||
dataTableId: string,
|
||||
projectId: string,
|
||||
dto: Omit<UpdateDataTableRowDto, 'returnData' | 'dryRun'>,
|
||||
|
||||
+1
-1
@@ -304,7 +304,7 @@ describe('GET /workflows/:workflowId/execution-status - CORS Integration', () =>
|
||||
test('should set CORS headers on GET request', async () => {
|
||||
// Mock the workflow status service to return a valid response
|
||||
const { CredentialResolverWorkflowService } = await import(
|
||||
'../services/credential-resolver-workflow.service'
|
||||
'../services/credential-resolver-workflow.service.js'
|
||||
);
|
||||
const workflowService = Container.get(CredentialResolverWorkflowService);
|
||||
vi.spyOn(workflowService, 'getWorkflowStatus').mockResolvedValue([
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ beforeAll(async () => {
|
||||
mockInstance(EnterpriseCredentialsService);
|
||||
|
||||
const { CredentialResolverWorkflowService } = await import(
|
||||
'../services/credential-resolver-workflow.service'
|
||||
'../services/credential-resolver-workflow.service.js'
|
||||
);
|
||||
workflowService = Container.get(CredentialResolverWorkflowService);
|
||||
});
|
||||
|
||||
@@ -17,10 +17,12 @@ function isExternalResolversEnabled(): boolean {
|
||||
@BackendModule({ name: 'dynamic-credentials', licenseFlag: LICENSE_FEATURES.DYNAMIC_CREDENTIALS })
|
||||
export class DynamicCredentialsModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./dynamic-credentials.controller');
|
||||
await import('./dynamic-credentials.controller.js');
|
||||
|
||||
// Import the n8n oauth extractor and seeder
|
||||
const { N8nOAuthIdentitySeeder } = await import('./context-establishment-hooks/n8n-oauth');
|
||||
const { N8nOAuthIdentitySeeder } = await import(
|
||||
'./context-establishment-hooks/n8n-oauth/index.js'
|
||||
);
|
||||
|
||||
Container.get(TriggerAuthIdentitySeederProxy).registerSeeder(
|
||||
Container.get(N8nOAuthIdentitySeeder),
|
||||
@@ -28,12 +30,12 @@ export class DynamicCredentialsModule implements ModuleInterface {
|
||||
|
||||
// System resolver powers private credentials; OAuth/Slack resolvers and
|
||||
// their management/identity-extractor surfaces are external-only.
|
||||
await import('./credential-resolvers/n8n-credential-resolver');
|
||||
await import('./credential-resolvers/n8n-credential-resolver.js');
|
||||
if (isExternalResolversEnabled()) {
|
||||
await import('./credential-resolvers.controller');
|
||||
await import('./context-establishment-hooks');
|
||||
await import('./credential-resolvers/oauth-credential-resolver');
|
||||
await import('./credential-resolvers/slack-credential-resolver');
|
||||
await import('./credential-resolvers.controller.js');
|
||||
await import('./context-establishment-hooks/index.js');
|
||||
await import('./credential-resolvers/oauth-credential-resolver.js');
|
||||
await import('./credential-resolvers/slack-credential-resolver.js');
|
||||
}
|
||||
const {
|
||||
DynamicCredentialResolverRegistry,
|
||||
@@ -41,14 +43,16 @@ export class DynamicCredentialsModule implements ModuleInterface {
|
||||
DynamicCredentialService,
|
||||
N8nResolverSeeder,
|
||||
CredentialConnectionStatusService,
|
||||
} = await import('./services');
|
||||
await import('./workflow-status.controller');
|
||||
} = await import('./services/index.js');
|
||||
await import('./workflow-status.controller.js');
|
||||
|
||||
await Container.get(DynamicCredentialResolverRegistry).init();
|
||||
await Container.get(N8nResolverSeeder).seed();
|
||||
|
||||
// Register the credential resolution provider with CredentialsHelper
|
||||
const { DynamicCredentialsProxy } = await import('../../credentials/dynamic-credentials-proxy');
|
||||
const { DynamicCredentialsProxy } = await import(
|
||||
'../../credentials/dynamic-credentials-proxy.js'
|
||||
);
|
||||
const credentialsProxy = Container.get(DynamicCredentialsProxy);
|
||||
const dynamicCredentialService = Container.get(DynamicCredentialService);
|
||||
const dynamicCredentialStorageService = Container.get(DynamicCredentialStorageService);
|
||||
@@ -58,7 +62,7 @@ export class DynamicCredentialsModule implements ModuleInterface {
|
||||
// Register the per-user connection status provider so the credentials
|
||||
// service can populate `connectedByMe` on responses.
|
||||
const { CredentialConnectionStatusProxy } = await import(
|
||||
'../../credentials/credential-connection-status-proxy'
|
||||
'../../credentials/credential-connection-status-proxy.js'
|
||||
);
|
||||
Container.get(CredentialConnectionStatusProxy).setProvider(
|
||||
Container.get(CredentialConnectionStatusService),
|
||||
@@ -66,10 +70,14 @@ export class DynamicCredentialsModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { DynamicCredentialResolver } = await import('./database/entities/credential-resolver');
|
||||
const { DynamicCredentialEntry } = await import('./database/entities/dynamic-credential-entry');
|
||||
const { DynamicCredentialResolver } = await import(
|
||||
'./database/entities/credential-resolver.js'
|
||||
);
|
||||
const { DynamicCredentialEntry } = await import(
|
||||
'./database/entities/dynamic-credential-entry.js'
|
||||
);
|
||||
const { DynamicCredentialUserEntry } = await import(
|
||||
'./database/entities/dynamic-credential-user-entry'
|
||||
'./database/entities/dynamic-credential-user-entry.js'
|
||||
);
|
||||
|
||||
return [DynamicCredentialResolver, DynamicCredentialEntry, DynamicCredentialUserEntry];
|
||||
@@ -77,7 +85,7 @@ export class DynamicCredentialsModule implements ModuleInterface {
|
||||
|
||||
async context() {
|
||||
const { CredentialCheckProxyService } = await import(
|
||||
'./services/credential-check-proxy.service'
|
||||
'./services/credential-check-proxy.service.js'
|
||||
);
|
||||
return { credentialCheckProxy: Container.get(CredentialCheckProxyService) };
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ function isKeyRotationApiEnabled(): boolean {
|
||||
export class EncryptionKeyManagerModule implements ModuleInterface {
|
||||
async init() {
|
||||
if (isKeyRotationApiEnabled()) {
|
||||
await import('./key-manager.service');
|
||||
await import('./key-manager.service.js');
|
||||
if (Container.get(InstanceSettings).instanceType === 'main') {
|
||||
await import('./encryption-key.controller');
|
||||
await import('./encryption-key.controller.js');
|
||||
}
|
||||
const { EncryptionBootstrapService } = await import('./encryption-bootstrap.service');
|
||||
const { EncryptionBootstrapService } = await import('./encryption-bootstrap.service.js');
|
||||
await Container.get(EncryptionBootstrapService).run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'external-secrets', licenseFlag: 'feat:externalSecrets' })
|
||||
export class ExternalSecretsModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./external-secrets.controller.ee');
|
||||
await import('./external-secrets-settings.controller.ee');
|
||||
await import('./external-secrets.controller.ee.js');
|
||||
await import('./external-secrets-settings.controller.ee.js');
|
||||
|
||||
await import('./secrets-providers-types.controller.ee');
|
||||
await import('./secrets-providers-connections.controller.ee');
|
||||
await import('./secrets-providers-completions.controller.ee');
|
||||
await import('./secrets-providers-project.controller.ee');
|
||||
await import('./secrets-providers-types.controller.ee.js');
|
||||
await import('./secrets-providers-connections.controller.ee.js');
|
||||
await import('./secrets-providers-completions.controller.ee.js');
|
||||
await import('./secrets-providers-project.controller.ee.js');
|
||||
|
||||
const { ExternalSecretsManager } = await import('./external-secrets-manager.ee');
|
||||
const { ExternalSecretsManager } = await import('./external-secrets-manager.ee.js');
|
||||
const { ExternalSecretsProxy } = await import('n8n-core');
|
||||
|
||||
const externalSecretsManager = Container.get(ExternalSecretsManager);
|
||||
@@ -24,11 +24,11 @@ export class ExternalSecretsModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async settings() {
|
||||
const { ExternalSecretsConfig } = await import('./external-secrets.config');
|
||||
const { ExternalSecretsConfig } = await import('./external-secrets.config.js');
|
||||
const config = Container.get(ExternalSecretsConfig);
|
||||
|
||||
const { ExternalSecretsSettingsService } = await import(
|
||||
'./external-secrets-settings.service.ee'
|
||||
'./external-secrets-settings.service.ee.js'
|
||||
);
|
||||
const settingsService = Container.get(ExternalSecretsSettingsService);
|
||||
|
||||
@@ -44,7 +44,7 @@ export class ExternalSecretsModule implements ModuleInterface {
|
||||
|
||||
@OnShutdown()
|
||||
async shutdown() {
|
||||
const { ExternalSecretsManager } = await import('./external-secrets-manager.ee');
|
||||
const { ExternalSecretsManager } = await import('./external-secrets-manager.ee.js');
|
||||
|
||||
Container.get(ExternalSecretsManager).shutdown();
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'favorites', instanceTypes: ['main'] })
|
||||
export class FavoritesModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./favorites.controller');
|
||||
await import('./favorites.controller.js');
|
||||
|
||||
const { FavoritesEventRelay } = await import('./favorites.event-relay');
|
||||
const { FavoritesEventRelay } = await import('./favorites.event-relay.js');
|
||||
Container.get(FavoritesEventRelay).init();
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { UserFavorite } = await import('./database/entities/user-favorite.entity');
|
||||
const { UserFavorite } = await import('./database/entities/user-favorite.entity.js');
|
||||
return [UserFavorite] as never;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,29 +9,29 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'insights', instanceTypes: ['main', 'webhook'] })
|
||||
export class InsightsModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./insights.controller');
|
||||
await import('./insights.controller.js');
|
||||
|
||||
const { InsightsService } = await import('./insights.service');
|
||||
const { InsightsService } = await import('./insights.service.js');
|
||||
await Container.get(InsightsService).init();
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { InsightsByPeriod } = await import('./database/entities/insights-by-period');
|
||||
const { InsightsMetadata } = await import('./database/entities/insights-metadata');
|
||||
const { InsightsRaw } = await import('./database/entities/insights-raw');
|
||||
const { InsightsByPeriod } = await import('./database/entities/insights-by-period.js');
|
||||
const { InsightsMetadata } = await import('./database/entities/insights-metadata.js');
|
||||
const { InsightsRaw } = await import('./database/entities/insights-raw.js');
|
||||
|
||||
return [InsightsByPeriod, InsightsMetadata, InsightsRaw];
|
||||
}
|
||||
|
||||
async settings() {
|
||||
const { InsightsSettings } = await import('./insights.settings');
|
||||
const { InsightsSettings } = await import('./insights.settings.js');
|
||||
|
||||
return await Container.get(InsightsSettings).settings();
|
||||
}
|
||||
|
||||
@OnShutdown()
|
||||
async shutdown() {
|
||||
const { InsightsService } = await import('./insights.service');
|
||||
const { InsightsService } = await import('./insights.service.js');
|
||||
|
||||
await Container.get(InsightsService).shutdown();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export class InsightsService {
|
||||
return;
|
||||
}
|
||||
|
||||
const { InsightsCollectionService } = await import('./insights-collection.service');
|
||||
const { InsightsCollectionService } = await import('./insights-collection.service.js');
|
||||
const collectionService = Container.get(InsightsCollectionService);
|
||||
if (enable) {
|
||||
collectionService.init();
|
||||
|
||||
@@ -10,7 +10,7 @@ let findAgentNodeInTree: (
|
||||
|
||||
beforeAll(async () => {
|
||||
({ buildAgentTreeFromEvents, findAgentNodeInTree } = (await import(
|
||||
'../../../../../@n8n/instance-ai/src/utils/agent-tree'
|
||||
'../../../../../@n8n/instance-ai/src/utils/agent-tree.js'
|
||||
)) as {
|
||||
buildAgentTreeFromEvents: (events: InstanceAiEvent[]) => InstanceAiAgentNode;
|
||||
findAgentNodeInTree: (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Mock the barrel import so these adapter tests only exercise local formatting helpers.
|
||||
vi.mock('@n8n/instance-ai', async () => {
|
||||
const { WorkflowSaveConflictError } = await import(
|
||||
'../../../../../@n8n/instance-ai/src/errors/workflow-save-conflict.error'
|
||||
'../../../../../@n8n/instance-ai/src/errors/workflow-save-conflict.error.js'
|
||||
);
|
||||
return {
|
||||
WorkflowSaveConflictError,
|
||||
|
||||
@@ -59,7 +59,7 @@ afterEach(() => {
|
||||
|
||||
describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
it('should return docs when library search and docs fetch both succeed', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
// Library search
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
@@ -73,7 +73,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should cache library ID — second call does not re-fetch library search', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
// First call: library search + docs
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
@@ -92,7 +92,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should return fallback when library search returns non-200', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(500, 'Internal Server Error');
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should return fallback when library search returns empty results', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(200, []);
|
||||
|
||||
@@ -114,7 +114,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should log warning on 429 status (quota exceeded)', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(429, 'Rate limit exceeded');
|
||||
|
||||
@@ -126,7 +126,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should log warning when response body contains "Quota"', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(403, 'Quota limit reached for your plan');
|
||||
|
||||
@@ -138,7 +138,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should log warning only once per session (context7WarningLogged flag)', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
// First call — 429, should warn
|
||||
mockFetchResponse(429, 'Rate limit');
|
||||
@@ -152,7 +152,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
});
|
||||
|
||||
it('should return fallback on fetch timeout / network error', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetch.mockRejectedValueOnce(new Error('network timeout'));
|
||||
|
||||
@@ -171,7 +171,7 @@ describe('resolveLibraryId (via fetchApiDocs)', () => {
|
||||
|
||||
describe('fetchApiDocs', () => {
|
||||
it('should return docs text from Context7 on success', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(200, [{ id: '/lib/github-api', trust_score: 80 }]);
|
||||
mockFetchResponse(200, 'GET /repos/{owner}/{repo} — returns a repository');
|
||||
@@ -182,7 +182,7 @@ describe('fetchApiDocs', () => {
|
||||
});
|
||||
|
||||
it('should cache docs per serviceName + endpointQuery', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
// First call: library search + docs
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
@@ -200,7 +200,7 @@ describe('fetchApiDocs', () => {
|
||||
});
|
||||
|
||||
it('should return fallback when docs endpoint returns non-200', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
mockFetchResponse(500, 'Server Error');
|
||||
@@ -211,7 +211,7 @@ describe('fetchApiDocs', () => {
|
||||
});
|
||||
|
||||
it('should return fallback when docs response is empty text', async () => {
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
mockFetchResponse(200, ' ');
|
||||
@@ -223,7 +223,7 @@ describe('fetchApiDocs', () => {
|
||||
|
||||
it('should pass CONTEXT7_API_KEY as Bearer Authorization header when env var is set', async () => {
|
||||
process.env.CONTEXT7_API_KEY = 'test-api-key-123';
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
mockFetchResponse(200, 'docs');
|
||||
@@ -239,7 +239,7 @@ describe('fetchApiDocs', () => {
|
||||
|
||||
it('should not send Authorization header when CONTEXT7_API_KEY is not set', async () => {
|
||||
delete process.env.CONTEXT7_API_KEY;
|
||||
const { fetchApiDocs } = await import('../api-docs');
|
||||
const { fetchApiDocs } = await import('../api-docs.js');
|
||||
|
||||
mockFetchResponse(200, [{ id: '/lib/slack-api', trust_score: 90 }]);
|
||||
mockFetchResponse(200, 'docs');
|
||||
|
||||
@@ -485,7 +485,7 @@ describe('createLlmMockHandler', () => {
|
||||
});
|
||||
|
||||
it('should cache node config across calls for the same node name', async () => {
|
||||
const { extractNodeConfig } = (await import('../node-config')) as unknown as {
|
||||
const { extractNodeConfig } = (await import('../node-config.js')) as unknown as {
|
||||
extractNodeConfig: Mock;
|
||||
};
|
||||
extractNodeConfig.mockReturnValue('{"resource":"message"}');
|
||||
@@ -534,7 +534,7 @@ describe('createLlmMockHandler', () => {
|
||||
});
|
||||
|
||||
it('should extract config separately for different node names', async () => {
|
||||
const { extractNodeConfig } = (await import('../node-config')) as unknown as {
|
||||
const { extractNodeConfig } = (await import('../node-config.js')) as unknown as {
|
||||
extractNodeConfig: Mock;
|
||||
};
|
||||
extractNodeConfig.mockReturnValue('{}');
|
||||
|
||||
@@ -1699,7 +1699,7 @@ export class InstanceAiAdapterService {
|
||||
const raw = await credentialsService.decrypt(credential, true);
|
||||
const tokenData = raw.oauthTokenData;
|
||||
if (tokenData && typeof tokenData === 'object') {
|
||||
const { OauthService } = await import('@/oauth/oauth.service');
|
||||
const { OauthService } = await import('@/oauth/oauth.service.js');
|
||||
const identifier = OauthService.extractAccountIdentifier(
|
||||
tokenData as Record<string, unknown>,
|
||||
);
|
||||
|
||||
@@ -16,25 +16,25 @@ export class InstanceAiModule implements ModuleInterface {
|
||||
const logger = Container.get(Logger).scoped('instance-ai');
|
||||
logger.warn(`${YELLOW}${WARNING_MESSAGE}${CLEAR}`);
|
||||
|
||||
const { InstanceAiSettingsService } = await import('./instance-ai-settings.service');
|
||||
const { InstanceAiSettingsService } = await import('./instance-ai-settings.service.js');
|
||||
await Container.get(InstanceAiSettingsService).loadFromDb();
|
||||
await import('./instance-ai.controller');
|
||||
await import('./mcp/instance-ai-mcp-connection.controller');
|
||||
await import('./instance-ai.controller.js');
|
||||
await import('./mcp/instance-ai-mcp-connection.controller.js');
|
||||
|
||||
// Instantiating the relay registers its `user-deleted` listener, which
|
||||
// cleans up Instance AI data owned by the deleted user.
|
||||
const { InstanceAiEventRelay } = await import('./instance-ai-event-relay.service');
|
||||
const { InstanceAiEventRelay } = await import('./instance-ai-event-relay.service.js');
|
||||
Container.get(InstanceAiEventRelay);
|
||||
|
||||
if (process.env.E2E_TESTS === 'true' && process.env.NODE_ENV !== 'production') {
|
||||
await import('./instance-ai-test.controller');
|
||||
await import('./instance-ai-test.controller.js');
|
||||
}
|
||||
}
|
||||
|
||||
async settings() {
|
||||
const { GlobalConfig } = await import('@n8n/config');
|
||||
const { InstanceAiService } = await import('./instance-ai.service');
|
||||
const { InstanceAiSettingsService } = await import('./instance-ai-settings.service');
|
||||
const { InstanceAiService } = await import('./instance-ai.service.js');
|
||||
const { InstanceAiSettingsService } = await import('./instance-ai-settings.service.js');
|
||||
const globalConfig = Container.get(GlobalConfig);
|
||||
const service = Container.get(InstanceAiService);
|
||||
const settingsService = Container.get(InstanceAiSettingsService);
|
||||
@@ -56,28 +56,30 @@ export class InstanceAiModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { InstanceAiThread } = await import('./entities/instance-ai-thread.entity');
|
||||
const { InstanceAiMessage } = await import('./entities/instance-ai-message.entity');
|
||||
const { InstanceAiResource } = await import('./entities/instance-ai-resource.entity');
|
||||
const { InstanceAiRunSnapshot } = await import('./entities/instance-ai-run-snapshot.entity');
|
||||
const { InstanceAiIterationLog } = await import('./entities/instance-ai-iteration-log.entity');
|
||||
const { InstanceAiCheckpoint } = await import('./entities/instance-ai-checkpoint.entity');
|
||||
const { InstanceAiPendingConfirmation } = await import(
|
||||
'./entities/instance-ai-pending-confirmation.entity'
|
||||
const { InstanceAiThread } = await import('./entities/instance-ai-thread.entity.js');
|
||||
const { InstanceAiMessage } = await import('./entities/instance-ai-message.entity.js');
|
||||
const { InstanceAiResource } = await import('./entities/instance-ai-resource.entity.js');
|
||||
const { InstanceAiRunSnapshot } = await import('./entities/instance-ai-run-snapshot.entity.js');
|
||||
const { InstanceAiIterationLog } = await import(
|
||||
'./entities/instance-ai-iteration-log.entity.js'
|
||||
);
|
||||
const { InstanceAiObservation } = await import('./entities/instance-ai-observation.entity');
|
||||
const { InstanceAiCheckpoint } = await import('./entities/instance-ai-checkpoint.entity.js');
|
||||
const { InstanceAiPendingConfirmation } = await import(
|
||||
'./entities/instance-ai-pending-confirmation.entity.js'
|
||||
);
|
||||
const { InstanceAiObservation } = await import('./entities/instance-ai-observation.entity.js');
|
||||
const { InstanceAiObservationCursor } = await import(
|
||||
'./entities/instance-ai-observation-cursor.entity'
|
||||
'./entities/instance-ai-observation-cursor.entity.js'
|
||||
);
|
||||
const { InstanceAiObservationLock } = await import(
|
||||
'./entities/instance-ai-observation-lock.entity'
|
||||
'./entities/instance-ai-observation-lock.entity.js'
|
||||
);
|
||||
const { InstanceAiMcpRegistryConnection } = await import(
|
||||
'./entities/instance-ai-mcp-registry-connection.entity'
|
||||
'./entities/instance-ai-mcp-registry-connection.entity.js'
|
||||
);
|
||||
const { InstanceAiThreadGrant } = await import('./entities/instance-ai-thread-grant.entity');
|
||||
const { InstanceAiThreadGrant } = await import('./entities/instance-ai-thread-grant.entity.js');
|
||||
const { InstanceAiEventLogEntry } = await import(
|
||||
'./entities/instance-ai-event-log-entry.entity'
|
||||
'./entities/instance-ai-event-log-entry.entity.js'
|
||||
);
|
||||
|
||||
return [
|
||||
@@ -99,7 +101,7 @@ export class InstanceAiModule implements ModuleInterface {
|
||||
|
||||
@OnShutdown()
|
||||
async shutdown() {
|
||||
const { InstanceAiService } = await import('./instance-ai.service');
|
||||
const { InstanceAiService } = await import('./instance-ai.service.js');
|
||||
await Container.get(InstanceAiService).shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ import {
|
||||
WorkflowLoopStorage,
|
||||
ThreadTaskStorage,
|
||||
} from '@n8n/instance-ai';
|
||||
import { lazyImport } from '@n8n/utils/lazy-import';
|
||||
import { setSchemaBaseDirs } from '@n8n/workflow-sdk';
|
||||
import { ErrorReporter, InstanceSettings } from 'n8n-core';
|
||||
import { OperationalError, UnexpectedError, UserError } from 'n8n-workflow';
|
||||
@@ -102,8 +103,8 @@ import { nanoid } from 'nanoid';
|
||||
import { N8N_VERSION, WORKFLOW_SDK_VERSION } from '@/constants';
|
||||
import { EventService } from '@/events/event.service';
|
||||
import { SourceControlPreferencesService } from '@/modules/source-control.ee/source-control-preferences.service.ee';
|
||||
import type { PubSubCommandMap } from '@/scaling/pubsub/pubsub.event-map';
|
||||
import { Publisher } from '@/scaling/pubsub/publisher.service';
|
||||
import type { PubSubCommandMap } from '@/scaling/pubsub/pubsub.event-map';
|
||||
import { AiService } from '@/services/ai.service';
|
||||
import { ProxyTokenManager } from '@/services/proxy-token-manager';
|
||||
import { UrlService } from '@/services/url.service';
|
||||
@@ -115,6 +116,7 @@ import { EvalThreadCredentialAllowlistService } from './eval/thread-credential-a
|
||||
import { DurableEventLog } from './event-bus/durable-event-log';
|
||||
import { InProcessEventBus } from './event-bus/in-process-event-bus';
|
||||
import { InstanceAiCreditService } from './instance-ai-credit.service';
|
||||
import { InstanceAiErrorReporterService } from './instance-ai-error-reporter.service';
|
||||
import { BROWSER_TOOL_CATEGORY, InstanceAiGatewayService } from './instance-ai-gateway.service';
|
||||
import { InstanceAiMemoryService } from './instance-ai-memory.service';
|
||||
import { InstanceAiModelService } from './instance-ai-model.service';
|
||||
@@ -134,7 +136,6 @@ import {
|
||||
} from './internal-messages';
|
||||
import { INSTANCE_AI_RUN_TIMEOUT_REASON, InstanceAiLivenessService } from './liveness';
|
||||
import { InstanceAiMcpRegistryService } from './mcp';
|
||||
import { InstanceAiErrorReporterService } from './instance-ai-error-reporter.service';
|
||||
import {
|
||||
buildInstanceAiObservabilityContext,
|
||||
type InstanceAiObservabilityContext,
|
||||
@@ -2924,6 +2925,7 @@ export class InstanceAiService {
|
||||
* `startExecuteRun` so the promise is registered with `inFlightExecutions`
|
||||
* and shutdown can drain it before the DB closes.
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
private async executeRun(
|
||||
user: User,
|
||||
threadId: string,
|
||||
@@ -3133,7 +3135,9 @@ export class InstanceAiService {
|
||||
// When trace replay is enabled but LangSmith isn't configured,
|
||||
// create a minimal context that only supports replay/record wrapping.
|
||||
if (!tracing && process.env.E2E_TESTS === 'true') {
|
||||
const { createTraceReplayOnlyContext } = await import('@n8n/instance-ai');
|
||||
const { createTraceReplayOnlyContext } = await lazyImport<
|
||||
typeof import('@n8n/instance-ai')
|
||||
>(async () => await import('@n8n/instance-ai'));
|
||||
tracing = createTraceReplayOnlyContext();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
TraceWriter as TraceWriterType,
|
||||
TraceEvent,
|
||||
} from '@n8n/instance-ai';
|
||||
import { lazyImport } from '@n8n/utils/lazy-import';
|
||||
|
||||
const TOOL_TRACE_EVENT_KINDS = new Set(['tool-call', 'tool-suspend', 'tool-resume']);
|
||||
|
||||
@@ -155,7 +156,14 @@ export class TraceReplayState {
|
||||
return;
|
||||
}
|
||||
|
||||
const { TraceIndex: TI, IdRemapper: IR, TraceWriter: TW } = await import('@n8n/instance-ai');
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
type InstanceAiImport = typeof import('@n8n/instance-ai');
|
||||
|
||||
const {
|
||||
TraceIndex: TI,
|
||||
IdRemapper: IR,
|
||||
TraceWriter: TW,
|
||||
} = await lazyImport<InstanceAiImport>(async () => await import('@n8n/instance-ai'));
|
||||
|
||||
const slug = this.activeSlug;
|
||||
const events = slug ? this.eventsBySlug.get(slug) : undefined;
|
||||
|
||||
@@ -13,28 +13,28 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'instance-registry' })
|
||||
export class InstanceRegistryModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./instance-registry.controller');
|
||||
await import('./instance-registry.controller.js');
|
||||
|
||||
const { InstanceRegistryService } = await import('./instance-registry.service');
|
||||
const { InstanceRegistryService } = await import('./instance-registry.service.js');
|
||||
const instanceRegistryService = Container.get(InstanceRegistryService);
|
||||
await instanceRegistryService.init();
|
||||
|
||||
const { InstanceRegistryProxyService } = await import(
|
||||
'@/services/instance-registry-proxy.service'
|
||||
'@/services/instance-registry-proxy.service.js'
|
||||
);
|
||||
Container.get(InstanceRegistryProxyService).registerProvider(instanceRegistryService);
|
||||
|
||||
const { StaleMemberCleanupService } = await import('./stale-member-cleanup.service');
|
||||
const { StaleMemberCleanupService } = await import('./stale-member-cleanup.service.js');
|
||||
Container.get(StaleMemberCleanupService).init();
|
||||
|
||||
await import('./checks');
|
||||
const { CheckService } = await import('./checks/check.service');
|
||||
await import('./checks/index.js');
|
||||
const { CheckService } = await import('./checks/check.service.js');
|
||||
Container.get(CheckService).init();
|
||||
}
|
||||
|
||||
@OnShutdown()
|
||||
async shutdown() {
|
||||
const { InstanceRegistryService } = await import('./instance-registry.service');
|
||||
const { InstanceRegistryService } = await import('./instance-registry.service.js');
|
||||
await Container.get(InstanceRegistryService).shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,12 +110,12 @@ export class InstanceRegistryService {
|
||||
const useRedis = this.instanceSettings.isMultiMain || this.executionsConfig.mode === 'queue';
|
||||
|
||||
if (useRedis) {
|
||||
const { RedisInstanceStorage } = await import('./storage/redis-instance-storage');
|
||||
const { RedisInstanceStorage } = await import('./storage/redis-instance-storage.js');
|
||||
const { Container } = await import('@n8n/di');
|
||||
return Container.get(RedisInstanceStorage);
|
||||
}
|
||||
|
||||
const { MemoryInstanceStorage } = await import('./storage/memory-storage');
|
||||
const { MemoryInstanceStorage } = await import('./storage/memory-storage.js');
|
||||
return new MemoryInstanceStorage();
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -5,15 +5,15 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'instance-version-history', instanceTypes: ['main'] })
|
||||
export class InstanceVersionHistoryModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./instance-version-history.controller');
|
||||
await import('./instance-version-history.controller.js');
|
||||
|
||||
const { InstanceVersionHistoryService } = await import('./instance-version-history.service');
|
||||
const { InstanceVersionHistoryService } = await import('./instance-version-history.service.js');
|
||||
await Container.get(InstanceVersionHistoryService).init();
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { InstanceVersionHistory } = await import(
|
||||
'./database/entities/instance-version-history.entity'
|
||||
'./database/entities/instance-version-history.entity.js'
|
||||
);
|
||||
return [InstanceVersionHistory];
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import { BackendModule } from '@n8n/decorators';
|
||||
@BackendModule({ name: 'ldap', licenseFlag: 'feat:ldap', instanceTypes: ['main'] })
|
||||
export class LdapModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./ldap.controller.ee');
|
||||
await import('./ldap.controller.ee.js');
|
||||
|
||||
// Import LdapService to trigger @PasswordAuthHandler() decorator registration
|
||||
await import('./ldap.service.ee');
|
||||
await import('./ldap.service.ee.js');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import type { RunningMode, SyncStatus } from '@n8n/db';
|
||||
import type { IPasswordAuthHandler } from '@n8n/decorators';
|
||||
import { AuthHandler } from '@n8n/decorators';
|
||||
import { Constructable, Container } from '@n8n/di';
|
||||
import { lazyImport } from '@n8n/utils/lazy-import';
|
||||
import type { Entry as LdapUser, ClientOptions, Client } from 'ldapts';
|
||||
import { Cipher } from 'n8n-core';
|
||||
import { jsonParse, UnexpectedError } from 'n8n-workflow';
|
||||
@@ -51,7 +52,6 @@ export class LdapService implements IPasswordAuthHandler<User> {
|
||||
readonly metadata = { name: 'ldap', type: 'password' as const };
|
||||
private client: Client | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
||||
private ldapts: typeof import('ldapts');
|
||||
|
||||
private syncTimer: NodeJS.Timeout | undefined = undefined;
|
||||
@@ -184,7 +184,7 @@ export class LdapService implements IPasswordAuthHandler<User> {
|
||||
}
|
||||
if (this.client === undefined) {
|
||||
if (!this.ldapts) {
|
||||
this.ldapts = await import('ldapts');
|
||||
this.ldapts = await lazyImport(async () => await import('ldapts'));
|
||||
}
|
||||
|
||||
const url = formatUrl(
|
||||
|
||||
@@ -17,16 +17,18 @@ import { Container } from '@n8n/di';
|
||||
})
|
||||
export class LogStreamingModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./log-streaming.controller');
|
||||
await import('./log-streaming.controller.js');
|
||||
|
||||
const { LogStreamingDestinationService } = await import('./log-streaming-destination.service');
|
||||
const { LogStreamingDestinationService } = await import(
|
||||
'./log-streaming-destination.service.js'
|
||||
);
|
||||
const destinationService = Container.get(LogStreamingDestinationService);
|
||||
await destinationService.loadDestinationsFromDb();
|
||||
await destinationService.initialize();
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { EventDestinations } = await import('./database/entities/event-destination.entity');
|
||||
const { EventDestinations } = await import('./database/entities/event-destination.entity.js');
|
||||
return [EventDestinations];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,23 +8,23 @@ import { LoadNodesAndCredentials } from '@/load-nodes-and-credentials';
|
||||
@BackendModule({ name: 'mcp-registry' })
|
||||
export class McpRegistryModule implements ModuleInterface {
|
||||
async init() {
|
||||
const { McpRegistryService } = await import('./registry/mcp-registry.service');
|
||||
const { McpRegistryService } = await import('./registry/mcp-registry.service.js');
|
||||
await Container.get(McpRegistryService).init();
|
||||
|
||||
await import('./mcp-registry.controller');
|
||||
await import('./mcp-registry.controller.js');
|
||||
|
||||
if (process.env.E2E_TESTS === 'true' && process.env.NODE_ENV !== 'production') {
|
||||
await import('./mcp-registry-test.controller');
|
||||
await import('./mcp-registry-test.controller.js');
|
||||
}
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { McpRegistryServerEntity } = await import('./registry/mcp-registry-server.entity');
|
||||
const { McpRegistryServerEntity } = await import('./registry/mcp-registry-server.entity.js');
|
||||
return [McpRegistryServerEntity];
|
||||
}
|
||||
|
||||
async nodeLoaders() {
|
||||
const { McpRegistryNodeLoader } = await import('./mcp-registry-node-loader');
|
||||
const { McpRegistryNodeLoader } = await import('./mcp-registry-node-loader.js');
|
||||
|
||||
return [
|
||||
new McpRegistryNodeLoader(Container.get(LoadNodesAndCredentials), Container.get(Logger)),
|
||||
|
||||
@@ -84,7 +84,7 @@ describe('McpController', () => {
|
||||
Container.set(ApiKeyRepository, mock<ApiKeyRepository>());
|
||||
|
||||
// Imported here (not statically) so the Container.set above runs first.
|
||||
({ McpController } = await import('../mcp.controller'));
|
||||
({ McpController } = await import('../mcp.controller.js'));
|
||||
controller = Container.get(McpController);
|
||||
});
|
||||
|
||||
|
||||
@@ -12,14 +12,14 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'mcp', instanceTypes: ['main'] })
|
||||
export class McpModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./mcp.controller');
|
||||
await import('./mcp.settings.controller');
|
||||
await import('./mcp.controller.js');
|
||||
await import('./mcp.settings.controller.js');
|
||||
|
||||
// Register the instance MCP server as a protected resource of the shared
|
||||
// OAuth server, so its tokens are minted and verified with the right
|
||||
// audiences and its discovery metadata is served.
|
||||
const { ProtectedResourceRegistry } = await import('@/services/protected-resource.registry');
|
||||
const { McpProtectedResource } = await import('./mcp-protected-resource');
|
||||
const { ProtectedResourceRegistry } = await import('@/services/protected-resource.registry.js');
|
||||
const { McpProtectedResource } = await import('./mcp-protected-resource.js');
|
||||
Container.get(ProtectedResourceRegistry).register(Container.get(McpProtectedResource));
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ export class McpModule implements ModuleInterface {
|
||||
* `{ mcp: { mcpAccessEnabled: boolean, mcpManagedByEnv: boolean, serverUrl: string } }`.
|
||||
*/
|
||||
async settings() {
|
||||
const { McpSettingsService } = await import('./mcp.settings.service');
|
||||
const { McpProtectedResource } = await import('./mcp-protected-resource');
|
||||
const { McpSettingsService } = await import('./mcp.settings.service.js');
|
||||
const { McpProtectedResource } = await import('./mcp-protected-resource.js');
|
||||
const mcpAccessEnabled = await Container.get(McpSettingsService).getEnabled();
|
||||
const { mcpManagedByEnv } = Container.get(InstanceSettingsLoaderConfig);
|
||||
// Canonical resource URL, so the UI shows the URL clients must actually
|
||||
|
||||
@@ -16,19 +16,20 @@ import {
|
||||
WORKFLOW_PREVIEW_APP_URI,
|
||||
type McpAppTelemetryConfig,
|
||||
} from '@n8n/mcp-apps/server';
|
||||
import { lazyImport } from '@n8n/utils/lazy-import';
|
||||
import { createDeferredPromise, type IDeferredPromise } from '@n8n/utils/promise/deferred-promise';
|
||||
import { InstanceSettings } from 'n8n-core';
|
||||
import { ManualExecutionCancelledError, type IRun } from 'n8n-workflow';
|
||||
|
||||
import {
|
||||
createAddDataTableColumnTool,
|
||||
createAddDataTableRowsTool,
|
||||
createCreateDataTableTool,
|
||||
createDeleteDataTableColumnTool,
|
||||
createRenameDataTableColumnTool,
|
||||
createRenameDataTableTool,
|
||||
createSearchDataTablesTool,
|
||||
} from './tools/data-table';
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { CollaborationService } from '@/collaboration/collaboration.service';
|
||||
import { N8N_VERSION } from '@/constants';
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { SubworkflowPolicyChecker } from '@/executions/pre-execution-checks/subworkflow-policy-checker';
|
||||
import { DataTableProxyService } from '@/modules/data-table/data-table-proxy.service';
|
||||
import { NodeCatalogService } from '@/node-catalog';
|
||||
|
||||
import { createExecuteWorkflowTool } from './tools/execute-workflow.tool';
|
||||
import { createGetExecutionTool } from './tools/get-execution.tool';
|
||||
import { createSearchExecutionsTool } from './tools/search-executions.tool';
|
||||
@@ -56,13 +57,7 @@ import { createSearchWorkflowNodesTool } from './tools/workflow-builder/search-w
|
||||
import { getSdkReferenceContent } from './tools/workflow-builder/sdk-reference-content';
|
||||
import { createValidateNodeTool } from './tools/workflow-builder/validate-node.tool';
|
||||
import { createValidateWorkflowCodeTool } from './tools/workflow-builder/validate-workflow-code.tool';
|
||||
import { NodeCatalogService } from '@/node-catalog';
|
||||
|
||||
import { ActiveExecutions } from '@/active-executions';
|
||||
import { CollaborationService } from '@/collaboration/collaboration.service';
|
||||
import { N8N_VERSION } from '@/constants';
|
||||
import { CredentialsService } from '@/credentials/credentials.service';
|
||||
import { DataTableProxyService } from '@/modules/data-table/data-table-proxy.service';
|
||||
import { NodeTypes } from '@/node-types';
|
||||
import { PostHogClient } from '@/posthog';
|
||||
import { NodeResourceExplorerService } from '@/services/node-resource-explorer.service';
|
||||
@@ -77,13 +72,21 @@ import { WorkflowFinderService } from '@/workflows/workflow-finder.service';
|
||||
import { WorkflowHistoryService } from '@/workflows/workflow-history/workflow-history.service';
|
||||
import { WorkflowPublishedDataService } from '@/workflows/workflow-published-data.service';
|
||||
import { WorkflowService } from '@/workflows/workflow.service';
|
||||
import { SubworkflowPolicyChecker } from '@/executions/pre-execution-checks/subworkflow-policy-checker';
|
||||
|
||||
import { MCP_PREVIEW_RENDER_REQUESTED_EVENT } from './mcp.constants';
|
||||
import { getAllowedToolNames } from './mcp-scopes';
|
||||
import type { McpAppsTelemetryVariant, McpClientInfo, RegisterToolFn } from './mcp.types';
|
||||
import {
|
||||
createAddDataTableColumnTool,
|
||||
createAddDataTableRowsTool,
|
||||
createCreateDataTableTool,
|
||||
createDeleteDataTableColumnTool,
|
||||
createRenameDataTableColumnTool,
|
||||
createRenameDataTableTool,
|
||||
createSearchDataTablesTool,
|
||||
} from './tools/data-table';
|
||||
import { createPrepareTestPinDataTool } from './tools/prepare-workflow-pin-data.tool';
|
||||
import { createTestWorkflowTool } from './tools/test-workflow.tool';
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
|
||||
/**
|
||||
* Pending MCP execution response, used for queue mode support.
|
||||
@@ -217,7 +220,10 @@ export class McpService {
|
||||
clientInfo?: McpClientInfo,
|
||||
grantedScopes?: string[],
|
||||
) {
|
||||
const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');
|
||||
const { McpServer } = await lazyImport<
|
||||
typeof import('@modelcontextprotocol/sdk/server/mcp.js')
|
||||
>(async () => await import('@modelcontextprotocol/sdk/server/mcp.js'));
|
||||
|
||||
const builderEnabled = this.globalConfig.endpoints.mcpBuilderEnabled;
|
||||
const allowedToolNames = getAllowedToolNames(grantedScopes);
|
||||
// The builder walkthrough is only useful when the grant can actually
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { AuthenticatedRequest } from '@n8n/db';
|
||||
import { isRecord } from '@n8n/utils/is-record';
|
||||
import type { Request } from 'express';
|
||||
import type { INode } from 'n8n-workflow';
|
||||
|
||||
import { isRecord } from '@n8n/utils/is-record';
|
||||
|
||||
import { SUPPORTED_MCP_TRIGGERS, SUPPORTED_PRODUCTION_MCP_TRIGGERS } from './mcp.constants';
|
||||
import { isJSONRPCRequest } from './mcp.typeguards';
|
||||
import type { McpClientInfo } from './mcp.types';
|
||||
@@ -44,7 +43,7 @@ export const getToolArguments = (body: unknown): Record<string, unknown> => {
|
||||
if (!isJSONRPCRequest(body)) return {};
|
||||
if (!body.params) return {};
|
||||
|
||||
const { arguments: args } = body.params;
|
||||
const args = body.params.arguments;
|
||||
if (isRecord(args)) {
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@ import { BackendModule } from '@n8n/decorators';
|
||||
})
|
||||
export class N8nPackagesModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./n8n-packages.service');
|
||||
await import('./n8n-packages.service.js');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export class OAuthJweModule implements ModuleInterface {
|
||||
async init() {
|
||||
if (!isFeatureFlagEnabled()) return;
|
||||
|
||||
const { OAuthJweDecryptService } = await import('./oauth-jwe-decrypt.service');
|
||||
const { OAuthJweDecryptService } = await import('./oauth-jwe-decrypt.service.js');
|
||||
Container.get(OAuthJweServiceProxy).setHandler(Container.get(OAuthJweDecryptService));
|
||||
|
||||
// Eager key bootstrap and the JWKS controller belong on main only.
|
||||
@@ -22,9 +22,9 @@ export class OAuthJweModule implements ModuleInterface {
|
||||
// the cache is cold and main hasn't generated yet, the partial unique
|
||||
// index on `(type, algorithm)` serializes any concurrent generation.
|
||||
if (Container.get(InstanceSettings).instanceType === 'main') {
|
||||
const { OAuthJweKeyService } = await import('./oauth-jwe-key.service');
|
||||
const { OAuthJweKeyService } = await import('./oauth-jwe-key.service.js');
|
||||
await Container.get(OAuthJweKeyService).initialize();
|
||||
await import('./oauth-jwe.controller');
|
||||
await import('./oauth-jwe.controller.js');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -405,7 +405,7 @@ describe('POST /rest/consent/approve', () => {
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const { UserConsentRepository } = await import(
|
||||
'../database/repositories/oauth-user-consent.repository'
|
||||
'../database/repositories/oauth-user-consent.repository.js'
|
||||
);
|
||||
const userConsentRepository = Container.get(UserConsentRepository);
|
||||
const consent = await userConsentRepository.findOne({
|
||||
@@ -428,7 +428,7 @@ describe('POST /rest/consent/approve', () => {
|
||||
expect(response.statusCode).toBe(200);
|
||||
|
||||
const { UserConsentRepository } = await import(
|
||||
'../database/repositories/oauth-user-consent.repository'
|
||||
'../database/repositories/oauth-user-consent.repository.js'
|
||||
);
|
||||
const userConsentRepository = Container.get(UserConsentRepository);
|
||||
const consent = await userConsentRepository.findOne({
|
||||
|
||||
@@ -298,7 +298,7 @@ describe('POST /mcp-oauth/register', () => {
|
||||
});
|
||||
|
||||
test('should reject with descriptive server_error on the post-insert rollback (race path)', async () => {
|
||||
const { OAuthServerService } = await import('../oauth-server.service');
|
||||
const { OAuthServerService } = await import('../oauth-server.service.js');
|
||||
const globalConfig = Container.get(GlobalConfig);
|
||||
const originalLimit = globalConfig.endpoints.mcpMaxRegisteredClients;
|
||||
globalConfig.endpoints.mcpMaxRegisteredClients = 1;
|
||||
@@ -805,7 +805,7 @@ describe('IP rate limit configuration', () => {
|
||||
let OAuthController: typeof OAuthControllerClass;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ OAuthController } = await import('../oauth.controller'));
|
||||
({ OAuthController } = await import('../oauth.controller.js'));
|
||||
});
|
||||
|
||||
test('applies the configured limits to the shared OAuth endpoints', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients';
|
||||
import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients.js';
|
||||
import { mockInstance } from '@n8n/backend-test-utils';
|
||||
import type { Request, Response } from 'express';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
@@ -22,7 +22,7 @@ beforeAll(async () => {
|
||||
// The SDK's `clientRegistrationHandler` validates `clientsStore.registerClient`
|
||||
// when the module builds its routers, so the mock needs a real store.
|
||||
mockInstance(OAuthServerService, { clientsStore: mock<OAuthRegisteredClientsStore>() });
|
||||
({ OAuthController } = await import('../oauth.controller'));
|
||||
({ OAuthController } = await import('../oauth.controller.js'));
|
||||
});
|
||||
|
||||
const urlService = mock<UrlService>();
|
||||
|
||||
@@ -21,29 +21,29 @@ export class OAuthServerModule implements ModuleInterface {
|
||||
async init() {
|
||||
// Only import controllers in the main process, since the webhook/worker processes don't run an HTTP server and don't need them.
|
||||
if (Container.get(InstanceSettings).instanceType === 'main') {
|
||||
await import('./oauth.controller');
|
||||
await import('./oauth-consent.controller');
|
||||
await import('./oauth-clients.controller');
|
||||
await import('./oauth.controller.js');
|
||||
await import('./oauth-consent.controller.js');
|
||||
await import('./oauth-clients.controller.js');
|
||||
}
|
||||
|
||||
// Register the token service as the OAuth token verifier provider, so
|
||||
// protected-resource modules verify bearer tokens through the core
|
||||
// `OAuthTokenVerifierProxy` instead of importing this module.
|
||||
const { OAuthTokenVerifierProxy } = await import(
|
||||
'@/services/oauth-token-verifier-proxy.service'
|
||||
'@/services/oauth-token-verifier-proxy.service.js'
|
||||
);
|
||||
const { OAuthTokenService } = await import('./oauth-token.service');
|
||||
const { OAuthTokenService } = await import('./oauth-token.service.js');
|
||||
Container.get(OAuthTokenVerifierProxy).registerProvider(Container.get(OAuthTokenService));
|
||||
|
||||
const { WorkflowMcpTriggerResourceResolver } = await import(
|
||||
'./protected-resource-resolvers/workflow-mcp-trigger-resource.resolver'
|
||||
'./protected-resource-resolvers/workflow-mcp-trigger-resource.resolver.js'
|
||||
);
|
||||
Container.get(ProtectedResourceRegistry).registerResolver(
|
||||
Container.get(WorkflowMcpTriggerResourceResolver),
|
||||
);
|
||||
|
||||
const { WorkflowMcpTestTriggerResourceResolver } = await import(
|
||||
'./protected-resource-resolvers/workflow-mcp-test-trigger-resource.resolver'
|
||||
'./protected-resource-resolvers/workflow-mcp-test-trigger-resource.resolver.js'
|
||||
);
|
||||
Container.get(ProtectedResourceRegistry).registerResolver(
|
||||
Container.get(WorkflowMcpTestTriggerResourceResolver),
|
||||
@@ -51,13 +51,13 @@ export class OAuthServerModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
async entities() {
|
||||
const { OAuthClient } = await import('./database/entities/oauth-client.entity');
|
||||
const { OAuthClient } = await import('./database/entities/oauth-client.entity.js');
|
||||
const { AuthorizationCode } = await import(
|
||||
'./database/entities/oauth-authorization-code.entity'
|
||||
'./database/entities/oauth-authorization-code.entity.js'
|
||||
);
|
||||
const { AccessToken } = await import('./database/entities/oauth-access-token.entity');
|
||||
const { RefreshToken } = await import('./database/entities/oauth-refresh-token.entity');
|
||||
const { UserConsent } = await import('./database/entities/oauth-user-consent.entity');
|
||||
const { AccessToken } = await import('./database/entities/oauth-access-token.entity.js');
|
||||
const { RefreshToken } = await import('./database/entities/oauth-refresh-token.entity.js');
|
||||
const { UserConsent } = await import('./database/entities/oauth-user-consent.entity.js');
|
||||
|
||||
return [OAuthClient, AuthorizationCode, AccessToken, RefreshToken, UserConsent] as never;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients';
|
||||
import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients.js';
|
||||
import {
|
||||
InvalidGrantError,
|
||||
InvalidTargetError,
|
||||
@@ -6,18 +6,20 @@ import {
|
||||
import type {
|
||||
AuthorizationParams,
|
||||
OAuthServerProvider,
|
||||
} from '@modelcontextprotocol/sdk/server/auth/provider';
|
||||
import type { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types';
|
||||
} from '@modelcontextprotocol/sdk/server/auth/provider.js';
|
||||
import type { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
|
||||
import type {
|
||||
OAuthClientInformationFull,
|
||||
OAuthTokens,
|
||||
OAuthTokenRevocationRequest,
|
||||
} from '@modelcontextprotocol/sdk/shared/auth';
|
||||
} from '@modelcontextprotocol/sdk/shared/auth.js';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { GlobalConfig } from '@n8n/config';
|
||||
import { Service } from '@n8n/di';
|
||||
import type { Response } from 'express';
|
||||
|
||||
import { ProtectedResourceRegistry } from '@/services/protected-resource.registry';
|
||||
|
||||
import { OAuthClient } from './database/entities/oauth-client.entity';
|
||||
import { OAuthClientRepository } from './database/repositories/oauth-client.repository';
|
||||
import { UserConsentRepository } from './database/repositories/oauth-user-consent.repository';
|
||||
@@ -25,7 +27,6 @@ import { OAuthAuthorizationCodeService } from './oauth-authorization-code.servic
|
||||
import { OAuthSessionService } from './oauth-session.service';
|
||||
import { OAuthTokenService } from './oauth-token.service';
|
||||
import { OAuthClientLimitReachedError } from './oauth.errors';
|
||||
import { ProtectedResourceRegistry } from '@/services/protected-resource.registry';
|
||||
|
||||
/** Maximum number of redirect URIs per client */
|
||||
const MAX_REDIRECT_URIS = 10;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { InvalidGrantError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
||||
import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types';
|
||||
import { OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth';
|
||||
import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
|
||||
import { OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
||||
import { Logger } from '@n8n/backend-common';
|
||||
import { Time } from '@n8n/constants';
|
||||
import { UserRepository, withTransaction } from '@n8n/db';
|
||||
@@ -10,19 +10,19 @@ import { ensureError } from '@n8n/utils/errors/ensure-error';
|
||||
import { UnexpectedError } from 'n8n-workflow';
|
||||
import { randomBytes, randomUUID } from 'node:crypto';
|
||||
|
||||
import { AccessToken } from './database/entities/oauth-access-token.entity';
|
||||
import { RefreshToken } from './database/entities/oauth-refresh-token.entity';
|
||||
import { AccessTokenRepository } from './database/repositories/oauth-access-token.repository';
|
||||
import { RefreshTokenRepository } from './database/repositories/oauth-refresh-token.repository';
|
||||
import type { ProtectedResource } from '@/services/protected-resource.registry';
|
||||
import { ProtectedResourceRegistry } from '@/services/protected-resource.registry';
|
||||
import { AccessTokenNotFoundError, JWTVerificationError } from './oauth.errors';
|
||||
|
||||
import { JwtService } from '@/services/jwt.service';
|
||||
import type {
|
||||
OAuthTokenVerifier,
|
||||
UserWithContext,
|
||||
} from '@/services/oauth-token-verifier-proxy.service';
|
||||
import type { ProtectedResource } from '@/services/protected-resource.registry';
|
||||
import { ProtectedResourceRegistry } from '@/services/protected-resource.registry';
|
||||
|
||||
import { AccessToken } from './database/entities/oauth-access-token.entity';
|
||||
import { RefreshToken } from './database/entities/oauth-refresh-token.entity';
|
||||
import { AccessTokenRepository } from './database/repositories/oauth-access-token.repository';
|
||||
import { RefreshTokenRepository } from './database/repositories/oauth-refresh-token.repository';
|
||||
import { AccessTokenNotFoundError, JWTVerificationError } from './oauth.errors';
|
||||
|
||||
/**
|
||||
* Manages the OAuth 2.1 token lifecycle for the shared OAuth server.
|
||||
|
||||
@@ -9,24 +9,24 @@ import { InstanceSettings } from 'n8n-core';
|
||||
})
|
||||
export class OtelModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./otel-lifecycle-handler');
|
||||
await import('./otel-lifecycle-handler.js');
|
||||
|
||||
const { OtelService } = await import('./otel.service');
|
||||
const { OtelService } = await import('./otel.service.js');
|
||||
await Container.get(OtelService).init();
|
||||
|
||||
if (Container.get(InstanceSettings).instanceType === 'main') {
|
||||
await import('./otel-settings.controller');
|
||||
await import('./otel-settings.controller.js');
|
||||
}
|
||||
}
|
||||
|
||||
async settings() {
|
||||
const { OtelSettingsService } = await import('./otel-settings.service');
|
||||
const { OtelSettingsService } = await import('./otel-settings.service.js');
|
||||
const { enabled } = Container.get(OtelSettingsService).getSettings();
|
||||
return { enabled };
|
||||
}
|
||||
|
||||
async context(): Promise<ModuleContext> {
|
||||
const { ExecutionLevelTracer } = await import('./execution-level-tracer');
|
||||
const { ExecutionLevelTracer } = await import('./execution-level-tracer.js');
|
||||
const tracer = Container.get(ExecutionLevelTracer);
|
||||
|
||||
return {
|
||||
@@ -36,7 +36,7 @@ export class OtelModule implements ModuleInterface {
|
||||
|
||||
@OnShutdown()
|
||||
async shutdown() {
|
||||
const { OtelService } = await import('./otel.service');
|
||||
const { OtelService } = await import('./otel.service.js');
|
||||
await Container.get(OtelService).shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,16 @@ import { Container } from '@n8n/di';
|
||||
})
|
||||
export class ProvisioningModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./provisioning.controller.ee');
|
||||
await import('./role-mapping-rule.controller.ee');
|
||||
await import('./provisioning.controller.ee.js');
|
||||
await import('./role-mapping-rule.controller.ee.js');
|
||||
|
||||
// Register the role-deletion checker so the core `RoleService` blocks
|
||||
// deleting a role still targeted by a mapping rule, without importing
|
||||
// this module.
|
||||
const { RoleDeletionCheckProxy } = await import('@/services/role-deletion-check-proxy.service');
|
||||
const { ProvisioningRoleDeletionChecker } = await import('./role-deletion-checker.ee');
|
||||
const { RoleDeletionCheckProxy } = await import(
|
||||
'@/services/role-deletion-check-proxy.service.js'
|
||||
);
|
||||
const { ProvisioningRoleDeletionChecker } = await import('./role-deletion-checker.ee.js');
|
||||
Container.get(RoleDeletionCheckProxy).registerProvider(
|
||||
Container.get(ProvisioningRoleDeletionChecker),
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Container } from '@n8n/di';
|
||||
export class QuickConnectModule implements ModuleInterface {
|
||||
async init() {
|
||||
await this.registerHandlers();
|
||||
await import('./quick-connect.controller');
|
||||
await import('./quick-connect.controller.js');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,7 +16,7 @@ export class QuickConnectModule implements ModuleInterface {
|
||||
* Note: backendFlowConfig is intentionally excluded from the response to keep it server-side only.
|
||||
*/
|
||||
async settings() {
|
||||
const { QuickConnectConfig } = await import('./quick-connect.config');
|
||||
const { QuickConnectConfig } = await import('./quick-connect.config.js');
|
||||
const { options } = Container.get(QuickConnectConfig);
|
||||
// Strip backendFlowConfig before sending options to frontend
|
||||
return {
|
||||
@@ -27,7 +27,7 @@ export class QuickConnectModule implements ModuleInterface {
|
||||
}
|
||||
|
||||
private async registerHandlers() {
|
||||
const { QuickConnectService } = await import('./quick-connect.service');
|
||||
const { QuickConnectService } = await import('./quick-connect.service.js');
|
||||
const quickConnectService = Container.get(QuickConnectService);
|
||||
await quickConnectService.registerHandlers();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { QuickConnectConfig } from './quick-connect.config';
|
||||
import { QuickConnectError } from './quick-connect.errors';
|
||||
|
||||
const backendHandlers = {
|
||||
firecrawl: async () => (await import('./handlers/firecrawl.handler')).FirecrawlHandler,
|
||||
firecrawl: async () => (await import('./handlers/firecrawl.handler.js')).FirecrawlHandler,
|
||||
};
|
||||
|
||||
@Service()
|
||||
|
||||
@@ -7,16 +7,18 @@ import { ExecutionRedactionServiceProxy } from '@/executions/execution-redaction
|
||||
@BackendModule({ name: 'redaction', instanceTypes: ['main'] })
|
||||
export class RedactionModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./redaction-context-hook');
|
||||
await import('./redaction-context-hook.js');
|
||||
|
||||
// Importing the service here registers its @OnPubSubEvent handler with the
|
||||
// pubsub metadata before PubSubRegistry.init() wires up the listeners.
|
||||
// The decorator runs at class-evaluation (import) time, so the import
|
||||
// side-effect alone is sufficient — the registry instantiates the handler
|
||||
// lazily on event receipt, so we must not eagerly resolve it here.
|
||||
await import('./instance-redaction-enforcement.service');
|
||||
await import('./instance-redaction-enforcement.service.js');
|
||||
|
||||
const { ExecutionRedactionService } = await import('./executions/execution-redaction.service');
|
||||
const { ExecutionRedactionService } = await import(
|
||||
'./executions/execution-redaction.service.js'
|
||||
);
|
||||
const executionRedactionService = Container.get(ExecutionRedactionService);
|
||||
await executionRedactionService.init();
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ export class RuntimeCredentialsModule implements ModuleInterface {
|
||||
async init() {
|
||||
if (!isFeatureFlagEnabled()) return;
|
||||
|
||||
const { RuntimeCredentialsService } = await import('./runtime-credentials.service');
|
||||
const { RuntimeCredentialsService } = await import('./runtime-credentials.service.js');
|
||||
Container.get(RuntimeCredentialsService).init();
|
||||
|
||||
await import('./runtime-credentials-context-hook');
|
||||
await import('./runtime-credentials.config');
|
||||
await import('./runtime-credentials-context-hook.js');
|
||||
await import('./runtime-credentials.config.js');
|
||||
const { RuntimeCredentialsAccessService } = await import(
|
||||
'./runtime-credentials-access.service'
|
||||
'./runtime-credentials-access.service.js'
|
||||
);
|
||||
Container.get(RuntimeCredentialProxyService).registerProvider(
|
||||
Container.get(RuntimeCredentialsAccessService),
|
||||
|
||||
+4
-4
@@ -525,7 +525,7 @@ describe('Source Control Helper', () => {
|
||||
const filePath = 'invalid/path/tags-and-mappings.json';
|
||||
// Import the function after resetting modules
|
||||
const { readTagAndMappingsFromSourceControlFile } = await import(
|
||||
'@/modules/source-control.ee/source-control-helper.ee'
|
||||
'@/modules/source-control.ee/source-control-helper.ee.js'
|
||||
);
|
||||
const result = await readTagAndMappingsFromSourceControlFile(filePath);
|
||||
expect(result).toEqual({
|
||||
@@ -546,7 +546,7 @@ describe('Source Control Helper', () => {
|
||||
const filePath = 'invalid/path/folders.json';
|
||||
// Import the function after resetting modules
|
||||
const { readFoldersFromSourceControlFile } = await import(
|
||||
'@/modules/source-control.ee/source-control-helper.ee'
|
||||
'@/modules/source-control.ee/source-control-helper.ee.js'
|
||||
);
|
||||
const result = await readFoldersFromSourceControlFile(filePath);
|
||||
expect(result).toEqual({
|
||||
@@ -566,7 +566,7 @@ describe('Source Control Helper', () => {
|
||||
const filePath = 'invalid/path/data_tables.json';
|
||||
// Import the function after resetting modules
|
||||
const { readDataTablesFromSourceControlFile } = await import(
|
||||
'@/modules/source-control.ee/source-control-helper.ee'
|
||||
'@/modules/source-control.ee/source-control-helper.ee.js'
|
||||
);
|
||||
const result = await readDataTablesFromSourceControlFile(filePath);
|
||||
expect(result).toEqual([]);
|
||||
@@ -594,7 +594,7 @@ describe('Source Control Helper', () => {
|
||||
|
||||
// Import the function after mocking
|
||||
const { readDataTablesFromSourceControlFile } = await import(
|
||||
'@/modules/source-control.ee/source-control-helper.ee'
|
||||
'@/modules/source-control.ee/source-control-helper.ee.js'
|
||||
);
|
||||
|
||||
const result = await readDataTablesFromSourceControlFile('valid/path/data_tables.json');
|
||||
|
||||
@@ -283,7 +283,10 @@ export function isSourceControlLicensed() {
|
||||
}
|
||||
|
||||
export async function generateSshKeyPair(keyType: KeyPairType) {
|
||||
const sshpk = await import('sshpk');
|
||||
// sshpk is CommonJS (`export =`): under nodenext, a native dynamic import only
|
||||
// hoists some named exports onto the namespace (parsePrivateKey is missed), so
|
||||
// read the real module.exports off `.default`.
|
||||
const { default: sshpk } = await import('sshpk');
|
||||
const keyPair: KeyPair = {
|
||||
publicKey: '',
|
||||
privateKey: '',
|
||||
|
||||
@@ -323,7 +323,7 @@ export class SourceControlPreferencesService {
|
||||
*/
|
||||
private async broadcastReloadSourceControlConfiguration(): Promise<void> {
|
||||
if (this.instanceSettings.isMultiMain) {
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
await Container.get(Publisher).publishCommand({ command: 'reload-source-control-config' });
|
||||
this.logger.debug('Broadcasting source control configuration reload to other main instances');
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import { Container } from '@n8n/di';
|
||||
})
|
||||
export class SourceControlModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./source-control.controller.ee');
|
||||
await import('./source-control.controller.ee.js');
|
||||
|
||||
const { SourceControlService } = await import('./source-control.service.ee');
|
||||
const { SourceControlService } = await import('./source-control.service.ee.js');
|
||||
await Container.get(SourceControlService).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ export class OidcService {
|
||||
|
||||
private async broadcastReloadOIDCConfigurationCommand(): Promise<void> {
|
||||
if (this.instanceSettings.isMultiMain) {
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
await Container.get(Publisher).publishCommand({ command: 'reload-oidc-config' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'sso-oidc', licenseFlag: 'feat:oidc', instanceTypes: ['main'] })
|
||||
export class OidcModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./oidc.controller.ee');
|
||||
await import('./oidc.controller.ee.js');
|
||||
|
||||
const { OidcService } = await import('./oidc.service.ee');
|
||||
const { OidcService } = await import('./oidc.service.ee.js');
|
||||
await Container.get(OidcService).init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,24 +57,24 @@ export class SamlValidator {
|
||||
|
||||
// dynamically load schema files
|
||||
private async loadSchemas(): Promise<void> {
|
||||
this.xmlProtocol = (await import('./schema/saml-schema-protocol-2.0.xsd')).xmlFileInfo;
|
||||
this.xmlMetadata = (await import('./schema/saml-schema-metadata-2.0.xsd')).xmlFileInfo;
|
||||
this.xmlProtocol = (await import('./schema/saml-schema-protocol-2.0.xsd.js')).xmlFileInfo;
|
||||
this.xmlMetadata = (await import('./schema/saml-schema-metadata-2.0.xsd.js')).xmlFileInfo;
|
||||
this.preload = (
|
||||
await Promise.all([
|
||||
// SAML
|
||||
import('./schema/saml-schema-assertion-2.0.xsd'),
|
||||
import('./schema/xmldsig-core-schema.xsd'),
|
||||
import('./schema/xenc-schema.xsd'),
|
||||
import('./schema/xml.xsd'),
|
||||
import('./schema/saml-schema-assertion-2.0.xsd.js'),
|
||||
import('./schema/xmldsig-core-schema.xsd.js'),
|
||||
import('./schema/xenc-schema.xsd.js'),
|
||||
import('./schema/xml.xsd.js'),
|
||||
|
||||
// WS-Federation
|
||||
import('./schema/ws-federation.xsd'),
|
||||
import('./schema/oasis-200401-wss-wssecurity-secext-1.0.xsd'),
|
||||
import('./schema/oasis-200401-wss-wssecurity-utility-1.0.xsd'),
|
||||
import('./schema/ws-addr.xsd'),
|
||||
import('./schema/metadata-exchange.xsd'),
|
||||
import('./schema/ws-securitypolicy-1.2.xsd'),
|
||||
import('./schema/ws-authorization.xsd'),
|
||||
import('./schema/ws-federation.xsd.js'),
|
||||
import('./schema/oasis-200401-wss-wssecurity-secext-1.0.xsd.js'),
|
||||
import('./schema/oasis-200401-wss-wssecurity-utility-1.0.xsd.js'),
|
||||
import('./schema/ws-addr.xsd.js'),
|
||||
import('./schema/metadata-exchange.xsd.js'),
|
||||
import('./schema/ws-securitypolicy-1.2.xsd.js'),
|
||||
import('./schema/ws-authorization.xsd.js'),
|
||||
])
|
||||
).map((m) => m.xmlFileInfo);
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ export class SamlService {
|
||||
|
||||
private async broadcastReloadSAMLConfigurationCommand(): Promise<void> {
|
||||
if (this.instanceSettings.isMultiMain) {
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service');
|
||||
const { Publisher } = await import('@/scaling/pubsub/publisher.service.js');
|
||||
await Container.get(Publisher).publishCommand({ command: 'reload-saml-config' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import { Container } from '@n8n/di';
|
||||
@BackendModule({ name: 'sso-saml', licenseFlag: 'feat:saml', instanceTypes: ['main'] })
|
||||
export class SamlModule implements ModuleInterface {
|
||||
async init() {
|
||||
await import('./saml.controller.ee');
|
||||
await import('./saml.controller.ee.js');
|
||||
|
||||
const { SamlService } = await import('./saml.service.ee');
|
||||
const { SamlService } = await import('./saml.service.ee.js');
|
||||
await Container.get(SamlService).init();
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -188,8 +188,8 @@ describe('EmbedAuthController', () => {
|
||||
const req = mock<AuthlessRequest>({ browserId: 'browser-id-789', ip: '10.0.0.1' });
|
||||
const res = mock<Response>();
|
||||
const query = new EmbedLoginQueryDto({ token: 'bad-token' });
|
||||
const { TokenExchangeAuthError } = await import('../../token-exchange.errors');
|
||||
const { TokenExchangeFailureReason } = await import('../../token-exchange.types');
|
||||
const { TokenExchangeAuthError } = await import('../../token-exchange.errors.js');
|
||||
const { TokenExchangeFailureReason } = await import('../../token-exchange.types.js');
|
||||
tokenExchangeService.embedLogin.mockRejectedValue(
|
||||
new TokenExchangeAuthError(
|
||||
TokenExchangeFailureReason.InvalidSignature,
|
||||
@@ -213,7 +213,7 @@ describe('EmbedAuthController', () => {
|
||||
const req = mock<AuthlessRequest>({ browserId: 'browser-id-789', ip: '10.0.0.1' });
|
||||
const res = mock<Response>();
|
||||
const query = new EmbedLoginQueryDto({ token: 'bad-token' });
|
||||
const { TokenExchangeFailureReason } = await import('../../token-exchange.types');
|
||||
const { TokenExchangeFailureReason } = await import('../../token-exchange.types.js');
|
||||
tokenExchangeService.embedLogin.mockRejectedValue(new Error('Some unexpected error'));
|
||||
|
||||
await expect(controller.getLogin(req, res, query)).rejects.toThrow('Some unexpected error');
|
||||
|
||||
@@ -14,11 +14,11 @@ function isFeatureFlagEnabled(): boolean {
|
||||
})
|
||||
export class TokenExchangeModule implements ModuleInterface {
|
||||
async entities() {
|
||||
const { TokenExchangeJti } = await import('./database/entities/token-exchange-jti.entity');
|
||||
const { TokenExchangeJti } = await import('./database/entities/token-exchange-jti.entity.js');
|
||||
const { TrustedKeySourceEntity } = await import(
|
||||
'./database/entities/trusted-key-source.entity'
|
||||
'./database/entities/trusted-key-source.entity.js'
|
||||
);
|
||||
const { TrustedKeyEntity } = await import('./database/entities/trusted-key.entity');
|
||||
const { TrustedKeyEntity } = await import('./database/entities/trusted-key.entity.js');
|
||||
return [TokenExchangeJti, TrustedKeySourceEntity, TrustedKeyEntity] as never;
|
||||
}
|
||||
|
||||
@@ -27,19 +27,19 @@ export class TokenExchangeModule implements ModuleInterface {
|
||||
return;
|
||||
}
|
||||
|
||||
const { TrustedKeyService } = await import('./services/trusted-key.service');
|
||||
const { TrustedKeyService } = await import('./services/trusted-key.service.js');
|
||||
await Container.get(TrustedKeyService).initialize();
|
||||
|
||||
await import('./controllers/token-exchange.controller');
|
||||
await import('./controllers/embed-auth.controller');
|
||||
await import('./controllers/token-exchange.controller.js');
|
||||
await import('./controllers/embed-auth.controller.js');
|
||||
|
||||
const { JtiCleanupService } = await import('./services/jti-cleanup.service');
|
||||
const { JtiCleanupService } = await import('./services/jti-cleanup.service.js');
|
||||
Container.get(JtiCleanupService).init();
|
||||
|
||||
// Register the scoped JWT auth strategy into the public API auth chain.
|
||||
// ScopedJwtStrategy runs after ApiKeyAuthStrategy (which abstains for token-exchange JWTs).
|
||||
const { ScopedJwtStrategy } = await import('./services/scoped-jwt.strategy');
|
||||
const { AuthStrategyRegistry } = await import('@/services/auth-strategy.registry');
|
||||
const { ScopedJwtStrategy } = await import('./services/scoped-jwt.strategy.js');
|
||||
const { AuthStrategyRegistry } = await import('@/services/auth-strategy.registry.js');
|
||||
Container.get(AuthStrategyRegistry).register(Container.get(ScopedJwtStrategy));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { BackendModule } from '@n8n/decorators';
|
||||
@BackendModule({ name: 'workflow-builder', instanceTypes: ['main'] })
|
||||
export class WorkflowBuilderModule implements ModuleInterface {
|
||||
async entities() {
|
||||
const { WorkflowBuilderSession } = await import('./workflow-builder-session.entity');
|
||||
const { WorkflowBuilderSession } = await import('./workflow-builder-session.entity.js');
|
||||
return [WorkflowBuilderSession];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export async function userHasScopes(
|
||||
throw new NotFoundError(`Data table with ID "${dataTableId}" not found.`);
|
||||
}
|
||||
|
||||
const { DataTableRepository } = await import('@/modules/data-table/data-table.repository');
|
||||
const { DataTableRepository } = await import('@/modules/data-table/data-table.repository.js');
|
||||
const dataTable = await Container.get(DataTableRepository).findOne({
|
||||
where: { id: dataTableId },
|
||||
relations: ['project'],
|
||||
|
||||
@@ -13,7 +13,7 @@ const auditHandlers: AuditHandlers = {
|
||||
generateAudit: [
|
||||
apiKeyHasScopeWithGlobalScopeFallback({ scope: 'securityAudit:generate' }),
|
||||
async (req, res) => {
|
||||
const { SecurityAuditService } = await import('@/security-audit/security-audit.service');
|
||||
const { SecurityAuditService } = await import('@/security-audit/security-audit.service.js');
|
||||
const result = await Container.get(SecurityAuditService).run(
|
||||
req.body?.additionalOptions?.categories,
|
||||
req.body?.additionalOptions?.daysAbandonedWorkflow,
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ vi.spyOn(middlewares, 'publicApiScope').mockReturnValue(mockMiddleware);
|
||||
let handler: Record<string, Array<(...args: unknown[]) => unknown>>;
|
||||
|
||||
beforeAll(async () => {
|
||||
handler = (await import('../community-packages.handler')) as unknown as typeof handler;
|
||||
handler = (await import('../community-packages.handler.js')) as unknown as typeof handler;
|
||||
});
|
||||
|
||||
describe('CommunityPackages Handler', () => {
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ let mainHandler: Record<string, Array<(...args: unknown[]) => unknown>>;
|
||||
let handler: Record<string, Array<(...args: unknown[]) => unknown>>;
|
||||
|
||||
beforeAll(async () => {
|
||||
mainHandler = (await import('../data-tables.handler')) as unknown as typeof mainHandler;
|
||||
handler = (await import('../data-tables.rows.handler')) as unknown as typeof handler;
|
||||
mainHandler = (await import('../data-tables.handler.js')) as unknown as typeof mainHandler;
|
||||
handler = (await import('../data-tables.rows.handler.js')) as unknown as typeof handler;
|
||||
});
|
||||
|
||||
describe('DataTable Handler', () => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import * as discoverService from '../discover.service';
|
||||
let handler: Record<string, Array<(...args: unknown[]) => unknown>>;
|
||||
|
||||
beforeAll(async () => {
|
||||
handler = (await import('../discover.handler')) as unknown as typeof handler;
|
||||
handler = (await import('../discover.handler.js')) as unknown as typeof handler;
|
||||
});
|
||||
|
||||
describe('Discover Handler', () => {
|
||||
|
||||
@@ -32,11 +32,11 @@ vi.spyOn(middlewares, 'isLicensed').mockReturnValue(createMockMiddleware as any)
|
||||
// `discover.service` builds its endpoint registry at module-evaluation time by
|
||||
// reading middleware metadata, so it must be imported *after* the spies above
|
||||
// are installed. A static import is hoisted above them, so load it dynamically.
|
||||
let buildDiscoverResponse: typeof import('../discover.service').buildDiscoverResponse;
|
||||
let _resetCache: typeof import('../discover.service')._resetCache;
|
||||
let buildDiscoverResponse: typeof import('../discover.service.js').buildDiscoverResponse;
|
||||
let _resetCache: typeof import('../discover.service.js')._resetCache;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ buildDiscoverResponse, _resetCache } = await import('../discover.service'));
|
||||
({ buildDiscoverResponse, _resetCache } = await import('../discover.service.js'));
|
||||
// Warm the registry once. The first call cold-loads and transforms all
|
||||
// handler modules (and their transitive graph) through Vite, which can
|
||||
// approach the default 5s test timeout. Paying it here in the hook keeps
|
||||
|
||||
@@ -118,7 +118,10 @@ async function _parseEndpointsFromSpec(): Promise<EndpointInfo[]> {
|
||||
let handlerModule = handlerCache.get(handlerPath);
|
||||
if (!handlerModule) {
|
||||
try {
|
||||
const fullHandlerPath = path.join(publicApiRoot, handlerPath);
|
||||
// The `.js` extension is required: under NodeNext, `await import()` is emitted
|
||||
// as a native dynamic import, which (unlike `require`) does no extension guessing.
|
||||
// The spec's handler paths are extensionless, so append it here.
|
||||
const fullHandlerPath = path.join(publicApiRoot, `${handlerPath}.js`);
|
||||
const imported: unknown = await import(fullHandlerPath);
|
||||
if (!isRecord(imported)) continue;
|
||||
// Handlers use `export = xHandlers`, which surfaces as `.default`
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ let exportPackage: (...args: unknown[]) => unknown;
|
||||
let importPackage: (...args: unknown[]) => unknown;
|
||||
|
||||
beforeAll(async () => {
|
||||
handler = (await import('../n8n-packages.handler')) as unknown as typeof handler;
|
||||
handler = (await import('../n8n-packages.handler.js')) as unknown as typeof handler;
|
||||
exportPackage = handler.exportPackage[1];
|
||||
importPackage = handler.importPackage[1];
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user