mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
refactor(core): Move push message types to a new shared package (no-changelog) (#10742)
This commit is contained in:
parent
7f1c131b72
commit
2f8c8448d3
|
@ -26,7 +26,7 @@ jobs:
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Build relevant packages
|
- name: Build relevant packages
|
||||||
run: pnpm --filter @n8n/client-oauth2 --filter @n8n/imap --filter n8n-workflow --filter n8n-core --filter n8n-nodes-base --filter @n8n/n8n-nodes-langchain build
|
run: pnpm build:nodes
|
||||||
|
|
||||||
- run: npm install --prefix=.github/scripts --no-package-lock
|
- run: npm install --prefix=.github/scripts --no-package-lock
|
||||||
|
|
||||||
|
|
7
packages/@n8n/api-types/.eslintrc.js
Normal file
7
packages/@n8n/api-types/.eslintrc.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
const sharedOptions = require('@n8n_io/eslint-config/shared');
|
||||||
|
|
||||||
|
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||||
|
module.exports = {
|
||||||
|
extends: ['@n8n_io/eslint-config/base'],
|
||||||
|
...sharedOptions(__dirname),
|
||||||
|
};
|
3
packages/@n8n/api-types/README.md
Normal file
3
packages/@n8n/api-types/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## @n8n/api-types
|
||||||
|
|
||||||
|
This package contains types and schema definitions for the n8n internal API, so that these can be shared between the backend and the frontend code.
|
2
packages/@n8n/api-types/jest.config.js
Normal file
2
packages/@n8n/api-types/jest.config.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/** @type {import('jest').Config} */
|
||||||
|
module.exports = require('../../../jest.config');
|
24
packages/@n8n/api-types/package.json
Normal file
24
packages/@n8n/api-types/package.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "@n8n/api-types",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist .turbo",
|
||||||
|
"dev": "pnpm watch",
|
||||||
|
"typecheck": "tsc --noEmit",
|
||||||
|
"build": "tsc -p tsconfig.build.json",
|
||||||
|
"format": "prettier --write . --ignore-path ../../../.prettierignore",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lintfix": "eslint . --fix",
|
||||||
|
"watch": "tsc -p tsconfig.build.json --watch",
|
||||||
|
"test": "echo \"No tests yet\" && exit 0"
|
||||||
|
},
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "src/index.ts",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist/**/*"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"n8n-workflow": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
2
packages/@n8n/api-types/src/datetime.ts
Normal file
2
packages/@n8n/api-types/src/datetime.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/** Date time in the ISO 8601 format, e.g. 2024-10-31T00:00:00.123Z */
|
||||||
|
export type Iso8601DateTimeString = string;
|
7
packages/@n8n/api-types/src/index.ts
Normal file
7
packages/@n8n/api-types/src/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export type * from './push';
|
||||||
|
export type * from './scaling';
|
||||||
|
export type * from './datetime';
|
||||||
|
export type * from './user';
|
||||||
|
|
||||||
|
export type { Collaborator } from './push/collaboration';
|
||||||
|
export type { SendWorkerStatusMessage } from './push/worker';
|
17
packages/@n8n/api-types/src/push/collaboration.ts
Normal file
17
packages/@n8n/api-types/src/push/collaboration.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import type { Iso8601DateTimeString } from '../datetime';
|
||||||
|
import type { MinimalUser } from '../user';
|
||||||
|
|
||||||
|
export type Collaborator = {
|
||||||
|
user: MinimalUser;
|
||||||
|
lastSeen: Iso8601DateTimeString;
|
||||||
|
};
|
||||||
|
|
||||||
|
type CollaboratorsChanged = {
|
||||||
|
type: 'collaboratorsChanged';
|
||||||
|
data: {
|
||||||
|
workflowId: string;
|
||||||
|
collaborators: Collaborator[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CollaborationPushMessage = CollaboratorsChanged;
|
9
packages/@n8n/api-types/src/push/debug.ts
Normal file
9
packages/@n8n/api-types/src/push/debug.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
type SendConsoleMessage = {
|
||||||
|
type: 'sendConsoleMessage';
|
||||||
|
data: {
|
||||||
|
source: string;
|
||||||
|
messages: unknown[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DebugPushMessage = SendConsoleMessage;
|
53
packages/@n8n/api-types/src/push/execution.ts
Normal file
53
packages/@n8n/api-types/src/push/execution.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import type { IRun, ITaskData, WorkflowExecuteMode } from 'n8n-workflow';
|
||||||
|
|
||||||
|
type ExecutionStarted = {
|
||||||
|
type: 'executionStarted';
|
||||||
|
data: {
|
||||||
|
executionId: string;
|
||||||
|
mode: WorkflowExecuteMode;
|
||||||
|
startedAt: Date;
|
||||||
|
workflowId: string;
|
||||||
|
workflowName?: string;
|
||||||
|
retryOf?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExecutionFinished = {
|
||||||
|
type: 'executionFinished';
|
||||||
|
data: {
|
||||||
|
executionId: string;
|
||||||
|
data: IRun;
|
||||||
|
retryOf?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type ExecutionRecovered = {
|
||||||
|
type: 'executionRecovered';
|
||||||
|
data: {
|
||||||
|
executionId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type NodeExecuteBefore = {
|
||||||
|
type: 'nodeExecuteBefore';
|
||||||
|
data: {
|
||||||
|
executionId: string;
|
||||||
|
nodeName: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type NodeExecuteAfter = {
|
||||||
|
type: 'nodeExecuteAfter';
|
||||||
|
data: {
|
||||||
|
executionId: string;
|
||||||
|
nodeName: string;
|
||||||
|
data: ITaskData;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExecutionPushMessage =
|
||||||
|
| ExecutionStarted
|
||||||
|
| ExecutionFinished
|
||||||
|
| ExecutionRecovered
|
||||||
|
| NodeExecuteBefore
|
||||||
|
| NodeExecuteAfter;
|
21
packages/@n8n/api-types/src/push/hot-reload.ts
Normal file
21
packages/@n8n/api-types/src/push/hot-reload.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
type NodeTypeData = {
|
||||||
|
name: string;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ReloadNodeType = {
|
||||||
|
type: 'reloadNodeType';
|
||||||
|
data: NodeTypeData;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RemoveNodeType = {
|
||||||
|
type: 'removeNodeType';
|
||||||
|
data: NodeTypeData;
|
||||||
|
};
|
||||||
|
|
||||||
|
type NodeDescriptionUpdated = {
|
||||||
|
type: 'nodeDescriptionUpdated';
|
||||||
|
data: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type HotReloadPushMessage = ReloadNodeType | RemoveNodeType | NodeDescriptionUpdated;
|
20
packages/@n8n/api-types/src/push/index.ts
Normal file
20
packages/@n8n/api-types/src/push/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import type { ExecutionPushMessage } from './execution';
|
||||||
|
import type { WorkflowPushMessage } from './workflow';
|
||||||
|
import type { HotReloadPushMessage } from './hot-reload';
|
||||||
|
import type { WorkerPushMessage } from './worker';
|
||||||
|
import type { WebhookPushMessage } from './webhook';
|
||||||
|
import type { CollaborationPushMessage } from './collaboration';
|
||||||
|
import type { DebugPushMessage } from './debug';
|
||||||
|
|
||||||
|
export type PushMessage =
|
||||||
|
| ExecutionPushMessage
|
||||||
|
| WorkflowPushMessage
|
||||||
|
| HotReloadPushMessage
|
||||||
|
| WebhookPushMessage
|
||||||
|
| WorkerPushMessage
|
||||||
|
| CollaborationPushMessage
|
||||||
|
| DebugPushMessage;
|
||||||
|
|
||||||
|
export type PushType = PushMessage['type'];
|
||||||
|
|
||||||
|
export type PushPayload<T extends PushType> = Extract<PushMessage, { type: T }>['data'];
|
17
packages/@n8n/api-types/src/push/webhook.ts
Normal file
17
packages/@n8n/api-types/src/push/webhook.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
type TestWebhookDeleted = {
|
||||||
|
type: 'testWebhookDeleted';
|
||||||
|
data: {
|
||||||
|
executionId?: string;
|
||||||
|
workflowId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type TestWebhookReceived = {
|
||||||
|
type: 'testWebhookReceived';
|
||||||
|
data: {
|
||||||
|
executionId: string;
|
||||||
|
workflowId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WebhookPushMessage = TestWebhookDeleted | TestWebhookReceived;
|
11
packages/@n8n/api-types/src/push/worker.ts
Normal file
11
packages/@n8n/api-types/src/push/worker.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import type { WorkerStatus } from '../scaling';
|
||||||
|
|
||||||
|
export type SendWorkerStatusMessage = {
|
||||||
|
type: 'sendWorkerStatusMessage';
|
||||||
|
data: {
|
||||||
|
workerId: string;
|
||||||
|
status: WorkerStatus;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkerPushMessage = SendWorkerStatusMessage;
|
26
packages/@n8n/api-types/src/push/workflow.ts
Normal file
26
packages/@n8n/api-types/src/push/workflow.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
type WorkflowActivated = {
|
||||||
|
type: 'workflowActivated';
|
||||||
|
data: {
|
||||||
|
workflowId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type WorkflowFailedToActivate = {
|
||||||
|
type: 'workflowFailedToActivate';
|
||||||
|
data: {
|
||||||
|
workflowId: string;
|
||||||
|
errorMessage: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type WorkflowDeactivated = {
|
||||||
|
type: 'workflowDeactivated';
|
||||||
|
data: {
|
||||||
|
workflowId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowPushMessage =
|
||||||
|
| WorkflowActivated
|
||||||
|
| WorkflowFailedToActivate
|
||||||
|
| WorkflowDeactivated;
|
30
packages/@n8n/api-types/src/scaling.ts
Normal file
30
packages/@n8n/api-types/src/scaling.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import type { ExecutionStatus, WorkflowExecuteMode } from 'n8n-workflow';
|
||||||
|
|
||||||
|
export type RunningJobSummary = {
|
||||||
|
executionId: string;
|
||||||
|
workflowId: string;
|
||||||
|
workflowName: string;
|
||||||
|
mode: WorkflowExecuteMode;
|
||||||
|
startedAt: Date;
|
||||||
|
retryOf: string;
|
||||||
|
status: ExecutionStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkerStatus = {
|
||||||
|
workerId: string;
|
||||||
|
runningJobsSummary: RunningJobSummary[];
|
||||||
|
freeMem: number;
|
||||||
|
totalMem: number;
|
||||||
|
uptime: number;
|
||||||
|
loadAvg: number[];
|
||||||
|
cpus: string;
|
||||||
|
arch: string;
|
||||||
|
platform: NodeJS.Platform;
|
||||||
|
hostname: string;
|
||||||
|
interfaces: Array<{
|
||||||
|
family: 'IPv4' | 'IPv6';
|
||||||
|
address: string;
|
||||||
|
internal: boolean;
|
||||||
|
}>;
|
||||||
|
version: string;
|
||||||
|
};
|
6
packages/@n8n/api-types/src/user.ts
Normal file
6
packages/@n8n/api-types/src/user.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export type MinimalUser = {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
};
|
11
packages/@n8n/api-types/tsconfig.build.json
Normal file
11
packages/@n8n/api-types/tsconfig.build.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"extends": ["./tsconfig.json", "../../../tsconfig.build.json"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"tsBuildInfoFile": "dist/build.tsbuildinfo"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["test/**", "src/**/__tests__/**"]
|
||||||
|
}
|
10
packages/@n8n/api-types/tsconfig.json
Normal file
10
packages/@n8n/api-types/tsconfig.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"extends": "../../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": ".",
|
||||||
|
"types": ["node", "jest"],
|
||||||
|
"baseUrl": "src",
|
||||||
|
"tsBuildInfoFile": "dist/typecheck.tsbuildinfo"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "test/**/*.ts"]
|
||||||
|
}
|
|
@ -85,6 +85,7 @@
|
||||||
"@azure/identity": "^4.3.0",
|
"@azure/identity": "^4.3.0",
|
||||||
"@azure/keyvault-secrets": "^4.8.0",
|
"@azure/keyvault-secrets": "^4.8.0",
|
||||||
"@google-cloud/secret-manager": "^5.6.0",
|
"@google-cloud/secret-manager": "^5.6.0",
|
||||||
|
"@n8n/api-types": "workspace:*",
|
||||||
"@n8n/client-oauth2": "workspace:*",
|
"@n8n/client-oauth2": "workspace:*",
|
||||||
"@n8n/config": "workspace:*",
|
"@n8n/config": "workspace:*",
|
||||||
"@n8n/localtunnel": "3.0.0",
|
"@n8n/localtunnel": "3.0.0",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { PushPayload } from '@n8n/api-types';
|
||||||
import type { Workflow } from 'n8n-workflow';
|
import type { Workflow } from 'n8n-workflow';
|
||||||
import { ApplicationError, ErrorReporterProxy } from 'n8n-workflow';
|
import { ApplicationError, ErrorReporterProxy } from 'n8n-workflow';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
@ -5,7 +6,6 @@ import { Service } from 'typedi';
|
||||||
import { CollaborationState } from '@/collaboration/collaboration.state';
|
import { CollaborationState } from '@/collaboration/collaboration.state';
|
||||||
import type { User } from '@/databases/entities/user';
|
import type { User } from '@/databases/entities/user';
|
||||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||||
import type { ICollaboratorsChanged } from '@/interfaces';
|
|
||||||
import { Push } from '@/push';
|
import { Push } from '@/push';
|
||||||
import type { OnPushMessage } from '@/push/types';
|
import type { OnPushMessage } from '@/push/types';
|
||||||
import { AccessService } from '@/services/access.service';
|
import { AccessService } from '@/services/access.service';
|
||||||
|
@ -92,7 +92,7 @@ export class CollaborationService {
|
||||||
user: user.toIUser(),
|
user: user.toIUser(),
|
||||||
lastSeen: collaborators.find(({ userId }) => userId === user.id)!.lastSeen,
|
lastSeen: collaborators.find(({ userId }) => userId === user.id)!.lastSeen,
|
||||||
}));
|
}));
|
||||||
const msgData: ICollaboratorsChanged = {
|
const msgData: PushPayload<'collaboratorsChanged'> = {
|
||||||
workflowId,
|
workflowId,
|
||||||
collaborators: activeCollaborators,
|
collaborators: activeCollaborators,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import type { Iso8601DateTimeString } from '@n8n/api-types';
|
||||||
import type { Workflow } from 'n8n-workflow';
|
import type { Workflow } from 'n8n-workflow';
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
|
||||||
import { Time } from '@/constants';
|
import { Time } from '@/constants';
|
||||||
import type { User } from '@/databases/entities/user';
|
import type { User } from '@/databases/entities/user';
|
||||||
import type { Iso8601DateTimeString } from '@/interfaces';
|
|
||||||
import { CacheService } from '@/services/cache/cache.service';
|
import { CacheService } from '@/services/cache/cache.service';
|
||||||
|
|
||||||
type WorkflowCacheHash = Record<User['id'], Iso8601DateTimeString>;
|
type WorkflowCacheHash = Record<User['id'], Iso8601DateTimeString>;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { PushPayload, PushType } from '@n8n/api-types';
|
||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
@ -10,7 +11,7 @@ import { SettingsRepository } from '@/databases/repositories/settings.repository
|
||||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||||
import { Patch, Post, RestController } from '@/decorators';
|
import { Patch, Post, RestController } from '@/decorators';
|
||||||
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
|
||||||
import type { BooleanLicenseFeature, IPushDataType, NumericLicenseFeature } from '@/interfaces';
|
import type { BooleanLicenseFeature, NumericLicenseFeature } from '@/interfaces';
|
||||||
import { License } from '@/license';
|
import { License } from '@/license';
|
||||||
import { Logger } from '@/logger';
|
import { Logger } from '@/logger';
|
||||||
import { MfaService } from '@/mfa/mfa.service';
|
import { MfaService } from '@/mfa/mfa.service';
|
||||||
|
@ -56,13 +57,13 @@ type ResetRequest = Request<
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
type PushRequest = Request<
|
type PushRequest<T extends PushType> = Request<
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
type: IPushDataType;
|
type: T;
|
||||||
pushRef: string;
|
pushRef: string;
|
||||||
data: object;
|
data: PushPayload<T>;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ export class E2EController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('/push', { skipAuth: true })
|
@Post('/push', { skipAuth: true })
|
||||||
async pushSend(req: PushRequest) {
|
async pushSend(req: PushRequest<any>) {
|
||||||
this.push.broadcast(req.body.type, req.body.data);
|
this.push.broadcast(req.body.type, req.body.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import type {
|
||||||
IExecuteResponsePromiseData,
|
IExecuteResponsePromiseData,
|
||||||
IRun,
|
IRun,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
ITaskData,
|
|
||||||
ITelemetryTrackProperties,
|
ITelemetryTrackProperties,
|
||||||
IWorkflowBase,
|
IWorkflowBase,
|
||||||
CredentialLoadingDetails,
|
CredentialLoadingDetails,
|
||||||
|
@ -23,7 +22,6 @@ import type {
|
||||||
INodeProperties,
|
INodeProperties,
|
||||||
IUserSettings,
|
IUserSettings,
|
||||||
IWorkflowExecutionDataProcess,
|
IWorkflowExecutionDataProcess,
|
||||||
IUser,
|
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import type PCancelable from 'p-cancelable';
|
import type PCancelable from 'p-cancelable';
|
||||||
|
|
||||||
|
@ -40,7 +38,6 @@ import type { WorkflowRepository } from '@/databases/repositories/workflow.repos
|
||||||
|
|
||||||
import type { LICENSE_FEATURES, LICENSE_QUOTAS } from './constants';
|
import type { LICENSE_FEATURES, LICENSE_QUOTAS } from './constants';
|
||||||
import type { ExternalHooks } from './external-hooks';
|
import type { ExternalHooks } from './external-hooks';
|
||||||
import type { RunningJobSummary } from './scaling/scaling.types';
|
|
||||||
import type { WorkflowWithSharingsAndCredentials } from './workflows/workflows.types';
|
import type { WorkflowWithSharingsAndCredentials } from './workflows/workflows.types';
|
||||||
|
|
||||||
export interface ICredentialsTypeData {
|
export interface ICredentialsTypeData {
|
||||||
|
@ -139,11 +136,6 @@ export interface IExecutionDb extends IExecutionBase {
|
||||||
*/
|
*/
|
||||||
export type ExecutionPayload = Omit<IExecutionDb, 'id'>;
|
export type ExecutionPayload = Omit<IExecutionDb, 'id'>;
|
||||||
|
|
||||||
export interface IExecutionPushResponse {
|
|
||||||
executionId?: string;
|
|
||||||
waitingForWebhook?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IExecutionResponse extends IExecutionBase {
|
export interface IExecutionResponse extends IExecutionBase {
|
||||||
id: string;
|
id: string;
|
||||||
data: IRunExecutionData;
|
data: IRunExecutionData;
|
||||||
|
@ -271,207 +263,6 @@ export interface IPackageVersions {
|
||||||
cli: string;
|
cli: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IPushDataType = IPushData['type'];
|
|
||||||
|
|
||||||
export type IPushData =
|
|
||||||
| PushDataExecutionFinished
|
|
||||||
| PushDataExecutionStarted
|
|
||||||
| PushDataExecuteAfter
|
|
||||||
| PushDataExecuteBefore
|
|
||||||
| PushDataConsoleMessage
|
|
||||||
| PushDataReloadNodeType
|
|
||||||
| PushDataRemoveNodeType
|
|
||||||
| PushDataTestWebhook
|
|
||||||
| PushDataNodeDescriptionUpdated
|
|
||||||
| PushDataExecutionRecovered
|
|
||||||
| PushDataWorkerStatusMessage
|
|
||||||
| PushDataWorkflowActivated
|
|
||||||
| PushDataWorkflowDeactivated
|
|
||||||
| PushDataWorkflowFailedToActivate
|
|
||||||
| PushDataCollaboratorsChanged;
|
|
||||||
|
|
||||||
type PushDataCollaboratorsChanged = {
|
|
||||||
data: ICollaboratorsChanged;
|
|
||||||
type: 'collaboratorsChanged';
|
|
||||||
};
|
|
||||||
|
|
||||||
type PushDataWorkflowFailedToActivate = {
|
|
||||||
data: IWorkflowFailedToActivate;
|
|
||||||
type: 'workflowFailedToActivate';
|
|
||||||
};
|
|
||||||
|
|
||||||
type PushDataWorkflowActivated = {
|
|
||||||
data: IActiveWorkflowChanged;
|
|
||||||
type: 'workflowActivated';
|
|
||||||
};
|
|
||||||
|
|
||||||
type PushDataWorkflowDeactivated = {
|
|
||||||
data: IActiveWorkflowChanged;
|
|
||||||
type: 'workflowDeactivated';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecutionRecovered = {
|
|
||||||
data: IPushDataExecutionRecovered;
|
|
||||||
type: 'executionRecovered';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecutionFinished = {
|
|
||||||
data: IPushDataExecutionFinished;
|
|
||||||
type: 'executionFinished';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecutionStarted = {
|
|
||||||
data: IPushDataExecutionStarted;
|
|
||||||
type: 'executionStarted';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecuteAfter = {
|
|
||||||
data: IPushDataNodeExecuteAfter;
|
|
||||||
type: 'nodeExecuteAfter';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecuteBefore = {
|
|
||||||
data: IPushDataNodeExecuteBefore;
|
|
||||||
type: 'nodeExecuteBefore';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataConsoleMessage = {
|
|
||||||
data: IPushDataConsoleMessage;
|
|
||||||
type: 'sendConsoleMessage';
|
|
||||||
};
|
|
||||||
|
|
||||||
type PushDataWorkerStatusMessage = {
|
|
||||||
data: IPushDataWorkerStatusMessage;
|
|
||||||
type: 'sendWorkerStatusMessage';
|
|
||||||
};
|
|
||||||
|
|
||||||
type PushDataReloadNodeType = {
|
|
||||||
data: IPushDataReloadNodeType;
|
|
||||||
type: 'reloadNodeType';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataRemoveNodeType = {
|
|
||||||
data: IPushDataRemoveNodeType;
|
|
||||||
type: 'removeNodeType';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataTestWebhook = {
|
|
||||||
data: IPushDataTestWebhook;
|
|
||||||
type: 'testWebhookDeleted' | 'testWebhookReceived';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataNodeDescriptionUpdated = {
|
|
||||||
data: undefined;
|
|
||||||
type: 'nodeDescriptionUpdated';
|
|
||||||
};
|
|
||||||
|
|
||||||
/** DateTime in the Iso8601 format, e.g. 2024-10-31T00:00:00.123Z */
|
|
||||||
export type Iso8601DateTimeString = string;
|
|
||||||
|
|
||||||
export interface ICollaborator {
|
|
||||||
user: IUser;
|
|
||||||
lastSeen: Iso8601DateTimeString;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICollaboratorsChanged {
|
|
||||||
workflowId: Workflow['id'];
|
|
||||||
collaborators: ICollaborator[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IActiveWorkflowAdded {
|
|
||||||
workflowId: Workflow['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IActiveWorkflowChanged {
|
|
||||||
workflowId: Workflow['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IWorkflowFailedToActivate {
|
|
||||||
workflowId: Workflow['id'];
|
|
||||||
errorMessage: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataExecutionRecovered {
|
|
||||||
executionId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataExecutionFinished {
|
|
||||||
data: IRun;
|
|
||||||
executionId: string;
|
|
||||||
retryOf?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataExecutionStarted {
|
|
||||||
executionId: string;
|
|
||||||
mode: WorkflowExecuteMode;
|
|
||||||
startedAt: Date;
|
|
||||||
retryOf?: string;
|
|
||||||
workflowId: string;
|
|
||||||
workflowName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataNodeExecuteAfter {
|
|
||||||
data: ITaskData;
|
|
||||||
executionId: string;
|
|
||||||
nodeName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataNodeExecuteBefore {
|
|
||||||
executionId: string;
|
|
||||||
nodeName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataReloadNodeType {
|
|
||||||
name: string;
|
|
||||||
version: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataRemoveNodeType {
|
|
||||||
name: string;
|
|
||||||
version: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataTestWebhook {
|
|
||||||
executionId: string;
|
|
||||||
workflowId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataConsoleMessage {
|
|
||||||
source: string;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataWorkerStatusMessage {
|
|
||||||
workerId: string;
|
|
||||||
status: IPushDataWorkerStatusPayload;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataWorkerStatusPayload {
|
|
||||||
workerId: string;
|
|
||||||
runningJobsSummary: RunningJobSummary[];
|
|
||||||
freeMem: number;
|
|
||||||
totalMem: number;
|
|
||||||
uptime: number;
|
|
||||||
loadAvg: number[];
|
|
||||||
cpus: string;
|
|
||||||
arch: string;
|
|
||||||
platform: NodeJS.Platform;
|
|
||||||
hostname: string;
|
|
||||||
interfaces: Array<{
|
|
||||||
family: 'IPv4' | 'IPv6';
|
|
||||||
address: string;
|
|
||||||
internal: boolean;
|
|
||||||
}>;
|
|
||||||
version: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface INodesTypeData {
|
|
||||||
[key: string]: {
|
|
||||||
className: string;
|
|
||||||
sourcePath: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWorkflowErrorData {
|
export interface IWorkflowErrorData {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
execution?: {
|
execution?: {
|
||||||
|
|
|
@ -375,7 +375,7 @@ export class LoadNodesAndCredentials {
|
||||||
loader.reset();
|
loader.reset();
|
||||||
await loader.loadAll();
|
await loader.loadAll();
|
||||||
await this.postProcessLoaders();
|
await this.postProcessLoaders();
|
||||||
push.broadcast('nodeDescriptionUpdated');
|
push.broadcast('nodeDescriptionUpdated', {});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
const toWatch = loader.isLazyLoaded
|
const toWatch = loader.isLazyLoaded
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import type { PushMessage } from '@n8n/api-types';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import type WebSocket from 'ws';
|
import type WebSocket from 'ws';
|
||||||
|
|
||||||
import type { User } from '@/databases/entities/user';
|
import type { User } from '@/databases/entities/user';
|
||||||
import type { PushDataExecutionRecovered } from '@/interfaces';
|
|
||||||
import { Logger } from '@/logger';
|
import { Logger } from '@/logger';
|
||||||
import { WebSocketPush } from '@/push/websocket.push';
|
import { WebSocketPush } from '@/push/websocket.push';
|
||||||
import { mockInstance } from '@test/mocking';
|
import { mockInstance } from '@test/mocking';
|
||||||
|
@ -28,6 +28,18 @@ describe('WebSocketPush', () => {
|
||||||
const pushRef1 = 'test-session1';
|
const pushRef1 = 'test-session1';
|
||||||
const pushRef2 = 'test-session2';
|
const pushRef2 = 'test-session2';
|
||||||
const userId: User['id'] = 'test-user';
|
const userId: User['id'] = 'test-user';
|
||||||
|
const pushMessage: PushMessage = {
|
||||||
|
type: 'executionRecovered',
|
||||||
|
data: {
|
||||||
|
executionId: 'test-execution-id',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const expectedMsg = JSON.stringify({
|
||||||
|
type: 'executionRecovered',
|
||||||
|
data: {
|
||||||
|
executionId: 'test-execution-id',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
mockInstance(Logger);
|
mockInstance(Logger);
|
||||||
const webSocketPush = Container.get(WebSocketPush);
|
const webSocketPush = Container.get(WebSocketPush);
|
||||||
|
@ -61,50 +73,17 @@ describe('WebSocketPush', () => {
|
||||||
it('sends data to one connection', () => {
|
it('sends data to one connection', () => {
|
||||||
webSocketPush.add(pushRef1, userId, mockWebSocket1);
|
webSocketPush.add(pushRef1, userId, mockWebSocket1);
|
||||||
webSocketPush.add(pushRef2, userId, mockWebSocket2);
|
webSocketPush.add(pushRef2, userId, mockWebSocket2);
|
||||||
const data: PushDataExecutionRecovered = {
|
webSocketPush.sendToOne(pushMessage.type, pushMessage.data, pushRef1);
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
executionId: 'test-execution-id',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
webSocketPush.sendToOne('executionRecovered', data, pushRef1);
|
expect(mockWebSocket1.send).toHaveBeenCalledWith(expectedMsg);
|
||||||
|
|
||||||
expect(mockWebSocket1.send).toHaveBeenCalledWith(
|
|
||||||
JSON.stringify({
|
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
executionId: 'test-execution-id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
expect(mockWebSocket2.send).not.toHaveBeenCalled();
|
expect(mockWebSocket2.send).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sends data to all connections', () => {
|
it('sends data to all connections', () => {
|
||||||
webSocketPush.add(pushRef1, userId, mockWebSocket1);
|
webSocketPush.add(pushRef1, userId, mockWebSocket1);
|
||||||
webSocketPush.add(pushRef2, userId, mockWebSocket2);
|
webSocketPush.add(pushRef2, userId, mockWebSocket2);
|
||||||
const data: PushDataExecutionRecovered = {
|
webSocketPush.sendToAll(pushMessage.type, pushMessage.data);
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
executionId: 'test-execution-id',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
webSocketPush.sendToAll('executionRecovered', data);
|
|
||||||
|
|
||||||
const expectedMsg = JSON.stringify({
|
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
executionId: 'test-execution-id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(mockWebSocket1.send).toHaveBeenCalledWith(expectedMsg);
|
expect(mockWebSocket1.send).toHaveBeenCalledWith(expectedMsg);
|
||||||
expect(mockWebSocket2.send).toHaveBeenCalledWith(expectedMsg);
|
expect(mockWebSocket2.send).toHaveBeenCalledWith(expectedMsg);
|
||||||
});
|
});
|
||||||
|
@ -122,24 +101,8 @@ describe('WebSocketPush', () => {
|
||||||
it('sends data to all users connections', () => {
|
it('sends data to all users connections', () => {
|
||||||
webSocketPush.add(pushRef1, userId, mockWebSocket1);
|
webSocketPush.add(pushRef1, userId, mockWebSocket1);
|
||||||
webSocketPush.add(pushRef2, userId, mockWebSocket2);
|
webSocketPush.add(pushRef2, userId, mockWebSocket2);
|
||||||
const data: PushDataExecutionRecovered = {
|
webSocketPush.sendToUsers(pushMessage.type, pushMessage.data, [userId]);
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
executionId: 'test-execution-id',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
webSocketPush.sendToUsers('executionRecovered', data, [userId]);
|
|
||||||
|
|
||||||
const expectedMsg = JSON.stringify({
|
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
type: 'executionRecovered',
|
|
||||||
data: {
|
|
||||||
executionId: 'test-execution-id',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(mockWebSocket1.send).toHaveBeenCalledWith(expectedMsg);
|
expect(mockWebSocket1.send).toHaveBeenCalledWith(expectedMsg);
|
||||||
expect(mockWebSocket2.send).toHaveBeenCalledWith(expectedMsg);
|
expect(mockWebSocket2.send).toHaveBeenCalledWith(expectedMsg);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
import type { PushPayload, PushType } from '@n8n/api-types';
|
||||||
import { assert, jsonStringify } from 'n8n-workflow';
|
import { assert, jsonStringify } from 'n8n-workflow';
|
||||||
|
|
||||||
import type { User } from '@/databases/entities/user';
|
import type { User } from '@/databases/entities/user';
|
||||||
import type { IPushDataType } from '@/interfaces';
|
|
||||||
import type { Logger } from '@/logger';
|
import type { Logger } from '@/logger';
|
||||||
import type { OnPushMessage } from '@/push/types';
|
import type { OnPushMessage } from '@/push/types';
|
||||||
import { TypedEmitter } from '@/typed-emitter';
|
import { TypedEmitter } from '@/typed-emitter';
|
||||||
|
@ -16,19 +16,19 @@ export interface AbstractPushEvents {
|
||||||
*
|
*
|
||||||
* @emits message when a message is received from a client
|
* @emits message when a message is received from a client
|
||||||
*/
|
*/
|
||||||
export abstract class AbstractPush<T> extends TypedEmitter<AbstractPushEvents> {
|
export abstract class AbstractPush<Connection> extends TypedEmitter<AbstractPushEvents> {
|
||||||
protected connections: Record<string, T> = {};
|
protected connections: Record<string, Connection> = {};
|
||||||
|
|
||||||
protected userIdByPushRef: Record<string, string> = {};
|
protected userIdByPushRef: Record<string, string> = {};
|
||||||
|
|
||||||
protected abstract close(connection: T): void;
|
protected abstract close(connection: Connection): void;
|
||||||
protected abstract sendToOneConnection(connection: T, data: string): void;
|
protected abstract sendToOneConnection(connection: Connection, data: string): void;
|
||||||
|
|
||||||
constructor(protected readonly logger: Logger) {
|
constructor(protected readonly logger: Logger) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected add(pushRef: string, userId: User['id'], connection: T) {
|
protected add(pushRef: string, userId: User['id'], connection: Connection) {
|
||||||
const { connections, userIdByPushRef } = this;
|
const { connections, userIdByPushRef } = this;
|
||||||
this.logger.debug('Add editor-UI session', { pushRef });
|
this.logger.debug('Add editor-UI session', { pushRef });
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ export abstract class AbstractPush<T> extends TypedEmitter<AbstractPushEvents> {
|
||||||
delete this.userIdByPushRef[pushRef];
|
delete this.userIdByPushRef[pushRef];
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendTo(type: IPushDataType, data: unknown, pushRefs: string[]) {
|
private sendTo<Type extends PushType>(type: Type, data: PushPayload<Type>, pushRefs: string[]) {
|
||||||
this.logger.debug(`Send data of type "${type}" to editor-UI`, {
|
this.logger.debug(`Send data of type "${type}" to editor-UI`, {
|
||||||
dataType: type,
|
dataType: type,
|
||||||
pushRefs: pushRefs.join(', '),
|
pushRefs: pushRefs.join(', '),
|
||||||
|
@ -75,11 +75,11 @@ export abstract class AbstractPush<T> extends TypedEmitter<AbstractPushEvents> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToAll(type: IPushDataType, data?: unknown) {
|
sendToAll<Type extends PushType>(type: Type, data: PushPayload<Type>) {
|
||||||
this.sendTo(type, data, Object.keys(this.connections));
|
this.sendTo(type, data, Object.keys(this.connections));
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToOne(type: IPushDataType, data: unknown, pushRef: string) {
|
sendToOne<Type extends PushType>(type: Type, data: PushPayload<Type>, pushRef: string) {
|
||||||
if (this.connections[pushRef] === undefined) {
|
if (this.connections[pushRef] === undefined) {
|
||||||
this.logger.error(`The session "${pushRef}" is not registered.`, { pushRef });
|
this.logger.error(`The session "${pushRef}" is not registered.`, { pushRef });
|
||||||
return;
|
return;
|
||||||
|
@ -88,7 +88,11 @@ export abstract class AbstractPush<T> extends TypedEmitter<AbstractPushEvents> {
|
||||||
this.sendTo(type, data, [pushRef]);
|
this.sendTo(type, data, [pushRef]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToUsers(type: IPushDataType, data: unknown, userIds: Array<User['id']>) {
|
sendToUsers<Type extends PushType>(
|
||||||
|
type: Type,
|
||||||
|
data: PushPayload<Type>,
|
||||||
|
userIds: Array<User['id']>,
|
||||||
|
) {
|
||||||
const { connections } = this;
|
const { connections } = this;
|
||||||
const userPushRefs = Object.keys(connections).filter((pushRef) =>
|
const userPushRefs = Object.keys(connections).filter((pushRef) =>
|
||||||
userIds.includes(this.userIdByPushRef[pushRef]),
|
userIds.includes(this.userIdByPushRef[pushRef]),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { PushPayload, PushType } from '@n8n/api-types';
|
||||||
import type { Application } from 'express';
|
import type { Application } from 'express';
|
||||||
import { ServerResponse } from 'http';
|
import { ServerResponse } from 'http';
|
||||||
import type { Server } from 'http';
|
import type { Server } from 'http';
|
||||||
|
@ -11,7 +12,6 @@ import config from '@/config';
|
||||||
import type { User } from '@/databases/entities/user';
|
import type { User } from '@/databases/entities/user';
|
||||||
import { OnShutdown } from '@/decorators/on-shutdown';
|
import { OnShutdown } from '@/decorators/on-shutdown';
|
||||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||||
import type { IPushDataType } from '@/interfaces';
|
|
||||||
import { OrchestrationService } from '@/services/orchestration.service';
|
import { OrchestrationService } from '@/services/orchestration.service';
|
||||||
import { TypedEmitter } from '@/typed-emitter';
|
import { TypedEmitter } from '@/typed-emitter';
|
||||||
|
|
||||||
|
@ -45,6 +45,10 @@ export class Push extends TypedEmitter<PushEvents> {
|
||||||
if (useWebSockets) this.backend.on('message', (msg) => this.emit('message', msg));
|
if (useWebSockets) this.backend.on('message', (msg) => this.emit('message', msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackend() {
|
||||||
|
return this.backend;
|
||||||
|
}
|
||||||
|
|
||||||
handleRequest(req: SSEPushRequest | WebSocketPushRequest, res: PushResponse) {
|
handleRequest(req: SSEPushRequest | WebSocketPushRequest, res: PushResponse) {
|
||||||
const {
|
const {
|
||||||
ws,
|
ws,
|
||||||
|
@ -73,11 +77,11 @@ export class Push extends TypedEmitter<PushEvents> {
|
||||||
this.emit('editorUiConnected', pushRef);
|
this.emit('editorUiConnected', pushRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcast(type: IPushDataType, data?: unknown) {
|
broadcast<Type extends PushType>(type: Type, data: PushPayload<Type>) {
|
||||||
this.backend.sendToAll(type, data);
|
this.backend.sendToAll(type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
send(type: IPushDataType, data: unknown, pushRef: string) {
|
send<Type extends PushType>(type: Type, data: PushPayload<Type>, pushRef: string) {
|
||||||
/**
|
/**
|
||||||
* Multi-main setup: In a manual webhook execution, the main process that
|
* Multi-main setup: In a manual webhook execution, the main process that
|
||||||
* handles a webhook might not be the same as the main process that created
|
* handles a webhook might not be the same as the main process that created
|
||||||
|
@ -93,11 +97,11 @@ export class Push extends TypedEmitter<PushEvents> {
|
||||||
this.backend.sendToOne(type, data, pushRef);
|
this.backend.sendToOne(type, data, pushRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBackend() {
|
sendToUsers<Type extends PushType>(
|
||||||
return this.backend;
|
type: Type,
|
||||||
}
|
data: PushPayload<Type>,
|
||||||
|
userIds: Array<User['id']>,
|
||||||
sendToUsers(type: IPushDataType, data: unknown, userIds: Array<User['id']>) {
|
) {
|
||||||
this.backend.sendToUsers(type, data, userIds);
|
this.backend.sendToUsers(type, data, userIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { RunningJobSummary } from '@n8n/api-types';
|
||||||
import { WorkflowExecute } from 'n8n-core';
|
import { WorkflowExecute } from 'n8n-core';
|
||||||
import { BINARY_ENCODING, ApplicationError, Workflow } from 'n8n-workflow';
|
import { BINARY_ENCODING, ApplicationError, Workflow } from 'n8n-workflow';
|
||||||
import type { ExecutionStatus, IExecuteResponsePromiseData, IRun } from 'n8n-workflow';
|
import type { ExecutionStatus, IExecuteResponsePromiseData, IRun } from 'n8n-workflow';
|
||||||
|
@ -11,7 +12,7 @@ import { Logger } from '@/logger';
|
||||||
import { NodeTypes } from '@/node-types';
|
import { NodeTypes } from '@/node-types';
|
||||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||||
|
|
||||||
import type { Job, JobId, JobResult, RunningJob, RunningJobSummary } from './scaling.types';
|
import type { Job, JobId, JobResult, RunningJob } from './scaling.types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for processing jobs from the queue, i.e. running enqueued executions.
|
* Responsible for processing jobs from the queue, i.e. running enqueued executions.
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
|
import type { RunningJobSummary } from '@n8n/api-types';
|
||||||
import type Bull from 'bull';
|
import type Bull from 'bull';
|
||||||
import type {
|
import type { ExecutionError, IExecuteResponsePromiseData, IRun } from 'n8n-workflow';
|
||||||
ExecutionError,
|
|
||||||
ExecutionStatus,
|
|
||||||
IExecuteResponsePromiseData,
|
|
||||||
IRun,
|
|
||||||
WorkflowExecuteMode as WorkflowExecutionMode,
|
|
||||||
} from 'n8n-workflow';
|
|
||||||
import type PCancelable from 'p-cancelable';
|
import type PCancelable from 'p-cancelable';
|
||||||
|
|
||||||
export type JobQueue = Bull.Queue<JobData>;
|
export type JobQueue = Bull.Queue<JobData>;
|
||||||
|
@ -30,11 +25,11 @@ export type JobOptions = Bull.JobOptions;
|
||||||
|
|
||||||
export type PubSubMessage = MessageToMain | MessageToWorker;
|
export type PubSubMessage = MessageToMain | MessageToWorker;
|
||||||
|
|
||||||
type MessageToMain = RepondToWebhookMessage;
|
type MessageToMain = RespondToWebhookMessage;
|
||||||
|
|
||||||
type MessageToWorker = AbortJobMessage;
|
type MessageToWorker = AbortJobMessage;
|
||||||
|
|
||||||
type RepondToWebhookMessage = {
|
type RespondToWebhookMessage = {
|
||||||
kind: 'respond-to-webhook';
|
kind: 'respond-to-webhook';
|
||||||
executionId: string;
|
executionId: string;
|
||||||
response: IExecuteResponsePromiseData;
|
response: IExecuteResponsePromiseData;
|
||||||
|
@ -44,19 +39,10 @@ type AbortJobMessage = {
|
||||||
kind: 'abort-job';
|
kind: 'abort-job';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RunningJob = {
|
export type RunningJob = RunningJobSummary & {
|
||||||
executionId: string;
|
|
||||||
workflowId: string;
|
|
||||||
workflowName: string;
|
|
||||||
mode: WorkflowExecutionMode;
|
|
||||||
startedAt: Date;
|
|
||||||
retryOf: string;
|
|
||||||
status: ExecutionStatus;
|
|
||||||
run: PCancelable<IRun>;
|
run: PCancelable<IRun>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RunningJobSummary = Omit<RunningJob, 'run'>;
|
|
||||||
|
|
||||||
export type QueueRecoveryContext = {
|
export type QueueRecoveryContext = {
|
||||||
/** ID of timeout for next scheduled recovery cycle. */
|
/** ID of timeout for next scheduled recovery cycle. */
|
||||||
timeout?: NodeJS.Timeout;
|
timeout?: NodeJS.Timeout;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import * as os from 'os';
|
import os from 'node:os';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
|
|
||||||
import { Logger } from '@/logger';
|
import { Logger } from '@/logger';
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { WorkerStatus } from '@n8n/api-types';
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ export async function handleWorkerResponseMessageMain(
|
||||||
case 'getStatus':
|
case 'getStatus':
|
||||||
Container.get(Push).broadcast('sendWorkerStatusMessage', {
|
Container.get(Push).broadcast('sendWorkerStatusMessage', {
|
||||||
workerId: workerResponse.workerId,
|
workerId: workerResponse.workerId,
|
||||||
status: workerResponse.payload,
|
status: workerResponse.payload as WorkerStatus,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'getId':
|
case 'getId':
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type { IPushDataType, IWorkflowDb } from '@/interfaces';
|
import type { PushType, WorkerStatus } from '@n8n/api-types';
|
||||||
import type { RunningJobSummary } from '@/scaling/scaling.types';
|
|
||||||
|
import type { IWorkflowDb } from '@/interfaces';
|
||||||
|
|
||||||
export type PubSubMessageMap = {
|
export type PubSubMessageMap = {
|
||||||
// #region Lifecycle
|
// #region Lifecycle
|
||||||
|
@ -43,24 +44,7 @@ export type PubSubMessageMap = {
|
||||||
|
|
||||||
'get-worker-id': never;
|
'get-worker-id': never;
|
||||||
|
|
||||||
'get-worker-status': {
|
'get-worker-status': WorkerStatus;
|
||||||
workerId: string;
|
|
||||||
runningJobsSummary: RunningJobSummary[];
|
|
||||||
freeMem: number;
|
|
||||||
totalMem: number;
|
|
||||||
uptime: number;
|
|
||||||
loadAvg: number[];
|
|
||||||
cpus: string;
|
|
||||||
arch: string;
|
|
||||||
platform: NodeJS.Platform;
|
|
||||||
hostname: string;
|
|
||||||
interfaces: Array<{
|
|
||||||
family: 'IPv4' | 'IPv6';
|
|
||||||
address: string;
|
|
||||||
internal: boolean;
|
|
||||||
}>;
|
|
||||||
version: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
@ -89,7 +73,7 @@ export type PubSubMessageMap = {
|
||||||
};
|
};
|
||||||
|
|
||||||
'relay-execution-lifecycle-event': {
|
'relay-execution-lifecycle-event': {
|
||||||
type: IPushDataType;
|
type: PushType;
|
||||||
args: Record<string, unknown>;
|
args: Record<string, unknown>;
|
||||||
pushRef: string;
|
pushRef: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { jsonParse } from 'n8n-workflow';
|
import { jsonParse } from 'n8n-workflow';
|
||||||
import * as os from 'os';
|
import os from 'node:os';
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
|
|
||||||
import { N8N_VERSION } from '@/constants';
|
import { N8N_VERSION } from '@/constants';
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
import type { RunningJobSummary } from '@n8n/api-types';
|
||||||
import type { ExecutionStatus, WorkflowExecuteMode } from 'n8n-workflow';
|
import type { ExecutionStatus, WorkflowExecuteMode } from 'n8n-workflow';
|
||||||
|
|
||||||
import type { RunningJobSummary } from '@/scaling/scaling.types';
|
|
||||||
|
|
||||||
import type { RedisServicePubSubPublisher } from '../../redis/redis-service-pub-sub-publisher';
|
import type { RedisServicePubSubPublisher } from '../../redis/redis-service-pub-sub-publisher';
|
||||||
|
|
||||||
export interface WorkerCommandReceivedHandlerOptions {
|
export interface WorkerCommandReceivedHandlerOptions {
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import type { IPushDataType, IPushDataWorkerStatusPayload, IWorkflowDb } from '@/interfaces';
|
import type { PushType, WorkerStatus } from '@n8n/api-types';
|
||||||
|
|
||||||
|
import type { IWorkflowDb } from '@/interfaces';
|
||||||
|
|
||||||
export type RedisServiceCommand =
|
export type RedisServiceCommand =
|
||||||
| 'getStatus'
|
| 'getStatus'
|
||||||
|
@ -42,7 +44,7 @@ export type RedisServiceBaseCommand =
|
||||||
| {
|
| {
|
||||||
senderId: string;
|
senderId: string;
|
||||||
command: 'relay-execution-lifecycle-event';
|
command: 'relay-execution-lifecycle-event';
|
||||||
payload: { type: IPushDataType; args: Record<string, unknown>; pushRef: string };
|
payload: { type: PushType; args: Record<string, unknown>; pushRef: string };
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
senderId: string;
|
senderId: string;
|
||||||
|
@ -64,7 +66,7 @@ export type RedisServiceWorkerResponseObject = {
|
||||||
| RedisServiceBaseCommand
|
| RedisServiceBaseCommand
|
||||||
| {
|
| {
|
||||||
command: 'getStatus';
|
command: 'getStatus';
|
||||||
payload: IPushDataWorkerStatusPayload;
|
payload: WorkerStatus;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
command: 'getId';
|
command: 'getId';
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
import type { PushType } from '@n8n/api-types';
|
||||||
import { GlobalConfig } from '@n8n/config';
|
import { GlobalConfig } from '@n8n/config';
|
||||||
import { WorkflowExecute } from 'n8n-core';
|
import { WorkflowExecute } from 'n8n-core';
|
||||||
import type {
|
import type {
|
||||||
|
@ -40,13 +41,7 @@ import config from '@/config';
|
||||||
import { CredentialsHelper } from '@/credentials-helper';
|
import { CredentialsHelper } from '@/credentials-helper';
|
||||||
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
|
||||||
import { ExternalHooks } from '@/external-hooks';
|
import { ExternalHooks } from '@/external-hooks';
|
||||||
import type {
|
import type { IWorkflowExecuteProcess, IWorkflowErrorData, ExecutionPayload } from '@/interfaces';
|
||||||
IPushDataExecutionFinished,
|
|
||||||
IWorkflowExecuteProcess,
|
|
||||||
IWorkflowErrorData,
|
|
||||||
IPushDataType,
|
|
||||||
ExecutionPayload,
|
|
||||||
} from '@/interfaces';
|
|
||||||
import { NodeTypes } from '@/node-types';
|
import { NodeTypes } from '@/node-types';
|
||||||
import { Push } from '@/push';
|
import { Push } from '@/push';
|
||||||
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
import { WorkflowStatisticsService } from '@/services/workflow-statistics.service';
|
||||||
|
@ -299,7 +294,6 @@ function hookFunctionsPush(): IWorkflowExecuteHooks {
|
||||||
startedAt: new Date(),
|
startedAt: new Date(),
|
||||||
retryOf: this.retryOf,
|
retryOf: this.retryOf,
|
||||||
workflowId,
|
workflowId,
|
||||||
pushRef,
|
|
||||||
workflowName,
|
workflowName,
|
||||||
},
|
},
|
||||||
pushRef,
|
pushRef,
|
||||||
|
@ -346,13 +340,15 @@ function hookFunctionsPush(): IWorkflowExecuteHooks {
|
||||||
workflowId,
|
workflowId,
|
||||||
});
|
});
|
||||||
// TODO: Look at this again
|
// TODO: Look at this again
|
||||||
const sendData: IPushDataExecutionFinished = {
|
pushInstance.send(
|
||||||
executionId,
|
'executionFinished',
|
||||||
data: pushRunData,
|
{
|
||||||
retryOf,
|
executionId,
|
||||||
};
|
data: pushRunData,
|
||||||
|
retryOf,
|
||||||
pushInstance.send('executionFinished', sendData, pushRef);
|
},
|
||||||
|
pushRef,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -938,7 +934,7 @@ export function setExecutionStatus(status: ExecutionStatus) {
|
||||||
Container.get(ActiveExecutions).setStatus(this.executionId, status);
|
Container.get(ActiveExecutions).setStatus(this.executionId, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendDataToUI(type: string, data: IDataObject | IDataObject[]) {
|
export function sendDataToUI(type: PushType, data: IDataObject | IDataObject[]) {
|
||||||
const { pushRef } = this;
|
const { pushRef } = this;
|
||||||
if (pushRef === undefined) {
|
if (pushRef === undefined) {
|
||||||
return;
|
return;
|
||||||
|
@ -947,7 +943,7 @@ export function sendDataToUI(type: string, data: IDataObject | IDataObject[]) {
|
||||||
// Push data to session which started workflow
|
// Push data to session which started workflow
|
||||||
try {
|
try {
|
||||||
const pushInstance = Container.get(Push);
|
const pushInstance = Container.get(Push);
|
||||||
pushInstance.send(type as IPushDataType, data, pushRef);
|
pushInstance.send(type, data, pushRef);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const logger = Container.get(Logger);
|
const logger = Container.get(Logger);
|
||||||
logger.warn(`There was a problem sending message to UI: ${error.message}`);
|
logger.warn(`There was a problem sending message to UI: ${error.message}`);
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../workflow/tsconfig.build.json" },
|
{ "path": "../workflow/tsconfig.build.json" },
|
||||||
{ "path": "../core/tsconfig.build.json" },
|
{ "path": "../core/tsconfig.build.json" },
|
||||||
|
{ "path": "../@n8n/api-types/tsconfig.build.json" },
|
||||||
{ "path": "../@n8n/client-oauth2/tsconfig.build.json" },
|
{ "path": "../@n8n/client-oauth2/tsconfig.build.json" },
|
||||||
{ "path": "../@n8n/config/tsconfig.build.json" },
|
{ "path": "../@n8n/config/tsconfig.build.json" },
|
||||||
{ "path": "../@n8n/permissions/tsconfig.build.json" }
|
{ "path": "../@n8n/permissions/tsconfig.build.json" }
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"@jsplumb/core": "^5.13.2",
|
"@jsplumb/core": "^5.13.2",
|
||||||
"@jsplumb/util": "^5.13.2",
|
"@jsplumb/util": "^5.13.2",
|
||||||
"@lezer/common": "^1.0.4",
|
"@lezer/common": "^1.0.4",
|
||||||
|
"@n8n/api-types": "workspace:*",
|
||||||
"@n8n/chat": "workspace:*",
|
"@n8n/chat": "workspace:*",
|
||||||
"@n8n/codemirror-lang": "workspace:*",
|
"@n8n/codemirror-lang": "workspace:*",
|
||||||
"@n8n/codemirror-lang-sql": "^1.0.2",
|
"@n8n/codemirror-lang-sql": "^1.0.2",
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
import type {
|
import type { Component } from 'vue';
|
||||||
AI_NODE_CREATOR_VIEW,
|
import type { NotificationOptions as ElementNotificationOptions } from 'element-plus';
|
||||||
CREDENTIAL_EDIT_MODAL_KEY,
|
import type { Connection } from '@jsplumb/core';
|
||||||
SignInType,
|
import type { Iso8601DateTimeString } from '@n8n/api-types';
|
||||||
FAKE_DOOR_FEATURES,
|
import type { Scope } from '@n8n/permissions';
|
||||||
TRIGGER_NODE_CREATOR_VIEW,
|
|
||||||
REGULAR_NODE_CREATOR_VIEW,
|
|
||||||
AI_OTHERS_NODE_CREATOR_VIEW,
|
|
||||||
ROLE,
|
|
||||||
} from '@/constants';
|
|
||||||
import type { IMenuItem, NodeCreatorTag } from 'n8n-design-system';
|
import type { IMenuItem, NodeCreatorTag } from 'n8n-design-system';
|
||||||
import type {
|
import type {
|
||||||
GenericValue,
|
GenericValue,
|
||||||
|
@ -22,9 +17,7 @@ import type {
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
IPinData,
|
IPinData,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
IRun,
|
|
||||||
IRunData,
|
IRunData,
|
||||||
ITaskData,
|
|
||||||
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
IWorkflowSettings as IWorkflowSettingsWorkflow,
|
||||||
WorkflowExecuteMode,
|
WorkflowExecuteMode,
|
||||||
PublicInstalledPackage,
|
PublicInstalledPackage,
|
||||||
|
@ -51,13 +44,21 @@ import type {
|
||||||
IPersonalizationSurveyAnswersV4,
|
IPersonalizationSurveyAnswersV4,
|
||||||
AnnotationVote,
|
AnnotationVote,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
AI_NODE_CREATOR_VIEW,
|
||||||
|
CREDENTIAL_EDIT_MODAL_KEY,
|
||||||
|
SignInType,
|
||||||
|
FAKE_DOOR_FEATURES,
|
||||||
|
TRIGGER_NODE_CREATOR_VIEW,
|
||||||
|
REGULAR_NODE_CREATOR_VIEW,
|
||||||
|
AI_OTHERS_NODE_CREATOR_VIEW,
|
||||||
|
ROLE,
|
||||||
|
} from '@/constants';
|
||||||
import type { BulkCommand, Undoable } from '@/models/history';
|
import type { BulkCommand, Undoable } from '@/models/history';
|
||||||
import type { PartialBy, TupleToUnion } from '@/utils/typeHelpers';
|
import type { PartialBy, TupleToUnion } from '@/utils/typeHelpers';
|
||||||
import type { Component } from 'vue';
|
|
||||||
import type { Scope } from '@n8n/permissions';
|
|
||||||
import type { NotificationOptions as ElementNotificationOptions } from 'element-plus';
|
|
||||||
import type { ProjectSharingData } from '@/types/projects.types';
|
import type { ProjectSharingData } from '@/types/projects.types';
|
||||||
import type { Connection } from '@jsplumb/core';
|
|
||||||
import type { BaseTextKey } from './plugins/i18n';
|
import type { BaseTextKey } from './plugins/i18n';
|
||||||
|
|
||||||
export * from 'n8n-design-system/types';
|
export * from 'n8n-design-system/types';
|
||||||
|
@ -119,9 +120,6 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** String that represents a timestamp in the ISO8601 format, i.e. YYYY-MM-DDTHH:MM:SS.sssZ */
|
|
||||||
export type Iso8601String = string;
|
|
||||||
|
|
||||||
export type EndpointStyle = {
|
export type EndpointStyle = {
|
||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
|
@ -336,8 +334,8 @@ export interface IShareWorkflowsPayload {
|
||||||
|
|
||||||
export interface ICredentialsResponse extends ICredentialsEncrypted {
|
export interface ICredentialsResponse extends ICredentialsEncrypted {
|
||||||
id: string;
|
id: string;
|
||||||
createdAt: Iso8601String;
|
createdAt: Iso8601DateTimeString;
|
||||||
updatedAt: Iso8601String;
|
updatedAt: Iso8601DateTimeString;
|
||||||
sharedWithProjects?: ProjectSharingData[];
|
sharedWithProjects?: ProjectSharingData[];
|
||||||
homeProject?: ProjectSharingData;
|
homeProject?: ProjectSharingData;
|
||||||
currentUserHasAccess?: boolean;
|
currentUserHasAccess?: boolean;
|
||||||
|
@ -346,8 +344,8 @@ export interface ICredentialsResponse extends ICredentialsEncrypted {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICredentialsBase {
|
export interface ICredentialsBase {
|
||||||
createdAt: Iso8601String;
|
createdAt: Iso8601DateTimeString;
|
||||||
updatedAt: Iso8601String;
|
updatedAt: Iso8601DateTimeString;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICredentialsDecryptedResponse extends ICredentialsBase, ICredentialsDecrypted {
|
export interface ICredentialsDecryptedResponse extends ICredentialsBase, ICredentialsDecrypted {
|
||||||
|
@ -422,213 +420,6 @@ export interface IExecutionDeleteFilter {
|
||||||
ids?: string[];
|
ids?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Collaborator {
|
|
||||||
user: IUser;
|
|
||||||
lastSeen: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PushDataCollaborators = {
|
|
||||||
workflowId: string;
|
|
||||||
collaborators: Collaborator[];
|
|
||||||
};
|
|
||||||
|
|
||||||
type PushDataCollaboratorsChanged = {
|
|
||||||
data: PushDataCollaborators;
|
|
||||||
type: 'collaboratorsChanged';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type IPushData =
|
|
||||||
| PushDataExecutionFinished
|
|
||||||
| PushDataExecutionStarted
|
|
||||||
| PushDataExecuteAfter
|
|
||||||
| PushDataExecuteBefore
|
|
||||||
| PushDataNodeDescriptionUpdated
|
|
||||||
| PushDataConsoleMessage
|
|
||||||
| PushDataReloadNodeType
|
|
||||||
| PushDataRemoveNodeType
|
|
||||||
| PushDataTestWebhook
|
|
||||||
| PushDataExecutionRecovered
|
|
||||||
| PushDataWorkerStatusMessage
|
|
||||||
| PushDataActiveWorkflowAdded
|
|
||||||
| PushDataActiveWorkflowRemoved
|
|
||||||
| PushDataCollaboratorsChanged
|
|
||||||
| PushDataWorkflowFailedToActivate;
|
|
||||||
|
|
||||||
export type PushDataActiveWorkflowAdded = {
|
|
||||||
data: IActiveWorkflowAdded;
|
|
||||||
type: 'workflowActivated';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataActiveWorkflowRemoved = {
|
|
||||||
data: IActiveWorkflowRemoved;
|
|
||||||
type: 'workflowDeactivated';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataWorkflowFailedToActivate = {
|
|
||||||
data: IWorkflowFailedToActivate;
|
|
||||||
type: 'workflowFailedToActivate';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecutionRecovered = {
|
|
||||||
data: IPushDataExecutionRecovered;
|
|
||||||
type: 'executionRecovered';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecutionFinished = {
|
|
||||||
data: IPushDataExecutionFinished;
|
|
||||||
type: 'executionFinished';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecutionStarted = {
|
|
||||||
data: IPushDataExecutionStarted;
|
|
||||||
type: 'executionStarted';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecuteAfter = {
|
|
||||||
data: IPushDataNodeExecuteAfter;
|
|
||||||
type: 'nodeExecuteAfter';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataExecuteBefore = {
|
|
||||||
data: IPushDataNodeExecuteBefore;
|
|
||||||
type: 'nodeExecuteBefore';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataNodeDescriptionUpdated = {
|
|
||||||
data: {};
|
|
||||||
type: 'nodeDescriptionUpdated';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataConsoleMessage = {
|
|
||||||
data: IPushDataConsoleMessage;
|
|
||||||
type: 'sendConsoleMessage';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataReloadNodeType = {
|
|
||||||
data: IPushDataReloadNodeType;
|
|
||||||
type: 'reloadNodeType';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataRemoveNodeType = {
|
|
||||||
data: IPushDataRemoveNodeType;
|
|
||||||
type: 'removeNodeType';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataTestWebhook = {
|
|
||||||
data: IPushDataTestWebhook;
|
|
||||||
type: 'testWebhookDeleted' | 'testWebhookReceived';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PushDataWorkerStatusMessage = {
|
|
||||||
data: IPushDataWorkerStatusMessage;
|
|
||||||
type: 'sendWorkerStatusMessage';
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IPushDataExecutionStarted {
|
|
||||||
executionId: string;
|
|
||||||
mode: WorkflowExecuteMode;
|
|
||||||
startedAt: Date;
|
|
||||||
retryOf?: string;
|
|
||||||
workflowId: string;
|
|
||||||
workflowName?: string;
|
|
||||||
}
|
|
||||||
export interface IPushDataExecutionRecovered {
|
|
||||||
executionId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataExecutionFinished {
|
|
||||||
data: IRun;
|
|
||||||
executionId: string;
|
|
||||||
retryOf?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IActiveWorkflowAdded {
|
|
||||||
workflowId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IActiveWorkflowRemoved {
|
|
||||||
workflowId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IWorkflowFailedToActivate {
|
|
||||||
workflowId: string;
|
|
||||||
errorMessage: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataUnsavedExecutionFinished {
|
|
||||||
executionId: string;
|
|
||||||
data: { finished: true; stoppedAt: Date };
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataExecutionStarted {
|
|
||||||
executionId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataNodeExecuteAfter {
|
|
||||||
data: ITaskData;
|
|
||||||
executionId: string;
|
|
||||||
nodeName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataNodeExecuteBefore {
|
|
||||||
executionId: string;
|
|
||||||
nodeName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataReloadNodeType {
|
|
||||||
name: string;
|
|
||||||
version: number;
|
|
||||||
}
|
|
||||||
export interface IPushDataRemoveNodeType {
|
|
||||||
name: string;
|
|
||||||
version: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataTestWebhook {
|
|
||||||
executionId: string;
|
|
||||||
workflowId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataConsoleMessage {
|
|
||||||
source: string;
|
|
||||||
messages: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WorkerJobStatusSummary {
|
|
||||||
jobId: string;
|
|
||||||
executionId: string;
|
|
||||||
retryOf?: string;
|
|
||||||
startedAt: Date;
|
|
||||||
mode: WorkflowExecuteMode;
|
|
||||||
workflowName: string;
|
|
||||||
workflowId: string;
|
|
||||||
status: ExecutionStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataWorkerStatusPayload {
|
|
||||||
workerId: string;
|
|
||||||
runningJobsSummary: WorkerJobStatusSummary[];
|
|
||||||
freeMem: number;
|
|
||||||
totalMem: number;
|
|
||||||
uptime: number;
|
|
||||||
loadAvg: number[];
|
|
||||||
cpus: string;
|
|
||||||
arch: string;
|
|
||||||
platform: NodeJS.Platform;
|
|
||||||
hostname: string;
|
|
||||||
interfaces: Array<{
|
|
||||||
family: 'IPv4' | 'IPv6';
|
|
||||||
address: string;
|
|
||||||
internal: boolean;
|
|
||||||
}>;
|
|
||||||
version: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPushDataWorkerStatusMessage {
|
|
||||||
workerId: string;
|
|
||||||
status: IPushDataWorkerStatusPayload;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type IPersonalizationSurveyAnswersV1 = {
|
export type IPersonalizationSurveyAnswersV1 = {
|
||||||
codingSkill?: string | null;
|
codingSkill?: string | null;
|
||||||
companyIndustry?: string[] | null;
|
companyIndustry?: string[] | null;
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
import { mapStores } from 'pinia';
|
import { mapStores } from 'pinia';
|
||||||
|
import type { WorkerStatus } from '@n8n/api-types';
|
||||||
|
import type { ExecutionStatus } from 'n8n-workflow';
|
||||||
|
|
||||||
import PushConnectionTracker from '@/components/PushConnectionTracker.vue';
|
import PushConnectionTracker from '@/components/PushConnectionTracker.vue';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
import type { IPushDataWorkerStatusPayload } from '@/Interface';
|
|
||||||
import type { ExecutionStatus } from 'n8n-workflow';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
||||||
import { setPageTitle } from '@/utils/htmlUtils';
|
import { setPageTitle } from '@/utils/htmlUtils';
|
||||||
import WorkerCard from './Workers/WorkerCard.ee.vue';
|
import WorkerCard from './Workers/WorkerCard.ee.vue';
|
||||||
import { usePushConnection } from '@/composables/usePushConnection';
|
import { usePushConnection } from '@/composables/usePushConnection';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||||
import { useRootStore } from '@/stores/root.store';
|
import { useRootStore } from '@/stores/root.store';
|
||||||
|
|
||||||
|
@ -39,8 +40,8 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useRootStore, useUIStore, usePushConnectionStore, useOrchestrationStore),
|
...mapStores(useRootStore, useUIStore, usePushConnectionStore, useOrchestrationStore),
|
||||||
combinedWorkers(): IPushDataWorkerStatusPayload[] {
|
combinedWorkers(): WorkerStatus[] {
|
||||||
const returnData: IPushDataWorkerStatusPayload[] = [];
|
const returnData: WorkerStatus[] = [];
|
||||||
for (const workerId in this.orchestrationManagerStore.workers) {
|
for (const workerId in this.orchestrationManagerStore.workers) {
|
||||||
returnData.push(this.orchestrationManagerStore.workers[workerId]);
|
returnData.push(this.orchestrationManagerStore.workers[workerId]);
|
||||||
}
|
}
|
||||||
|
@ -85,14 +86,14 @@ export default defineComponent({
|
||||||
averageLoadAvg(loads: number[]) {
|
averageLoadAvg(loads: number[]) {
|
||||||
return (loads.reduce((prev, curr) => prev + curr, 0) / loads.length).toFixed(2);
|
return (loads.reduce((prev, curr) => prev + curr, 0) / loads.length).toFixed(2);
|
||||||
},
|
},
|
||||||
getStatus(payload: IPushDataWorkerStatusPayload): ExecutionStatus {
|
getStatus(payload: WorkerStatus): ExecutionStatus {
|
||||||
if (payload.runningJobsSummary.length > 0) {
|
if (payload.runningJobsSummary.length > 0) {
|
||||||
return 'running';
|
return 'running';
|
||||||
} else {
|
} else {
|
||||||
return 'success';
|
return 'success';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getRowClass(payload: IPushDataWorkerStatusPayload): string {
|
getRowClass(payload: WorkerStatus): string {
|
||||||
return [this.$style.execRow, this.$style[this.getStatus(payload)]].join(' ');
|
return [this.$style.execRow, this.$style[this.getStatus(payload)]].join(' ');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
|
||||||
import type { IPushDataWorkerStatusPayload } from '@/Interface';
|
|
||||||
import { computed, onMounted, onBeforeUnmount, ref } from 'vue';
|
import { computed, onMounted, onBeforeUnmount, ref } from 'vue';
|
||||||
|
import type { WorkerStatus } from '@n8n/api-types';
|
||||||
|
|
||||||
|
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
||||||
import { averageWorkerLoadFromLoadsAsString, memAsGb } from '../../utils/workerUtils';
|
import { averageWorkerLoadFromLoadsAsString, memAsGb } from '../../utils/workerUtils';
|
||||||
import WorkerJobAccordion from './WorkerJobAccordion.ee.vue';
|
import WorkerJobAccordion from './WorkerJobAccordion.ee.vue';
|
||||||
import WorkerNetAccordion from './WorkerNetAccordion.ee.vue';
|
import WorkerNetAccordion from './WorkerNetAccordion.ee.vue';
|
||||||
|
@ -18,7 +19,7 @@ const props = defineProps<{
|
||||||
const secondsSinceLastUpdateString = ref<string>('0');
|
const secondsSinceLastUpdateString = ref<string>('0');
|
||||||
const stale = ref<boolean>(false);
|
const stale = ref<boolean>(false);
|
||||||
|
|
||||||
const worker = computed((): IPushDataWorkerStatusPayload | undefined => {
|
const worker = computed((): WorkerStatus | undefined => {
|
||||||
return orchestrationStore.getWorkerStatus(props.workerId);
|
return orchestrationStore.getWorkerStatus(props.workerId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { WorkerJobStatusSummary } from '@/Interface';
|
import type { RunningJobSummary } from '@n8n/api-types';
|
||||||
import WorkerAccordion from './WorkerAccordion.ee.vue';
|
import WorkerAccordion from './WorkerAccordion.ee.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
items: WorkerJobStatusSummary[];
|
items: RunningJobSummary[];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
function runningSince(started: Date): string {
|
function runningSince(started: Date): string {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { IPushDataWorkerStatusPayload } from '@/Interface';
|
import type { WorkerStatus } from '@n8n/api-types';
|
||||||
import WorkerAccordion from './WorkerAccordion.ee.vue';
|
import WorkerAccordion from './WorkerAccordion.ee.vue';
|
||||||
import { useClipboard } from '@/composables/useClipboard';
|
import { useClipboard } from '@/composables/useClipboard';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useToast } from '@/composables/useToast';
|
import { useToast } from '@/composables/useToast';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
items: IPushDataWorkerStatusPayload['interfaces'];
|
items: WorkerStatus['interfaces'];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { usePushConnection } from '@/composables/usePushConnection';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { createPinia, setActivePinia } from 'pinia';
|
import { createPinia, setActivePinia } from 'pinia';
|
||||||
|
import type { PushMessage, PushPayload } from '@n8n/api-types';
|
||||||
|
|
||||||
|
import { usePushConnection } from '@/composables/usePushConnection';
|
||||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||||
import type { IPushData, PushDataWorkerStatusMessage } from '@/Interface';
|
|
||||||
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
||||||
|
|
||||||
vi.mock('vue-router', () => {
|
vi.mock('vue-router', () => {
|
||||||
|
@ -56,13 +57,13 @@ describe('usePushConnection()', () => {
|
||||||
|
|
||||||
describe('queuePushMessage()', () => {
|
describe('queuePushMessage()', () => {
|
||||||
it('should add message to the queue and sets timeout if not already set', () => {
|
it('should add message to the queue and sets timeout if not already set', () => {
|
||||||
const event: IPushData = {
|
const event: PushMessage = {
|
||||||
type: 'sendWorkerStatusMessage',
|
type: 'sendWorkerStatusMessage',
|
||||||
data: {
|
data: {
|
||||||
workerId: '1',
|
workerId: '1',
|
||||||
status: {},
|
status: {} as PushPayload<'sendWorkerStatusMessage'>['status'],
|
||||||
},
|
},
|
||||||
} as PushDataWorkerStatusMessage;
|
};
|
||||||
|
|
||||||
pushConnection.queuePushMessage(event, 5);
|
pushConnection.queuePushMessage(event, 5);
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ describe('usePushConnection()', () => {
|
||||||
|
|
||||||
describe('processWaitingPushMessages()', () => {
|
describe('processWaitingPushMessages()', () => {
|
||||||
it('should clear the queue and reset the timeout', async () => {
|
it('should clear the queue and reset the timeout', async () => {
|
||||||
const event: IPushData = { type: 'executionRecovered', data: { executionId: '1' } };
|
const event: PushMessage = { type: 'executionRecovered', data: { executionId: '1' } };
|
||||||
|
|
||||||
pushConnection.queuePushMessage(event, 0);
|
pushConnection.queuePushMessage(event, 0);
|
||||||
expect(pushConnection.pushMessageQueue.value).toHaveLength(1);
|
expect(pushConnection.pushMessageQueue.value).toHaveLength(1);
|
||||||
|
@ -91,13 +92,13 @@ describe('usePushConnection()', () => {
|
||||||
describe('sendWorkerStatusMessage', () => {
|
describe('sendWorkerStatusMessage', () => {
|
||||||
it('should handle event type correctly', async () => {
|
it('should handle event type correctly', async () => {
|
||||||
const spy = vi.spyOn(orchestrationStore, 'updateWorkerStatus').mockImplementation(() => {});
|
const spy = vi.spyOn(orchestrationStore, 'updateWorkerStatus').mockImplementation(() => {});
|
||||||
const event: IPushData = {
|
const event: PushMessage = {
|
||||||
type: 'sendWorkerStatusMessage',
|
type: 'sendWorkerStatusMessage',
|
||||||
data: {
|
data: {
|
||||||
workerId: '1',
|
workerId: '1',
|
||||||
status: {},
|
status: {} as PushPayload<'sendWorkerStatusMessage'>['status'],
|
||||||
},
|
},
|
||||||
} as PushDataWorkerStatusMessage;
|
};
|
||||||
|
|
||||||
const result = await pushConnection.pushMessageReceived(event);
|
const result = await pushConnection.pushMessageReceived(event);
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
import type {
|
import { parse } from 'flatted';
|
||||||
IExecutionResponse,
|
import { h, ref } from 'vue';
|
||||||
IExecutionsCurrentSummaryExtended,
|
import type { useRouter } from 'vue-router';
|
||||||
IPushData,
|
|
||||||
IPushDataExecutionFinished,
|
|
||||||
} from '@/Interface';
|
|
||||||
|
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
|
||||||
import { useTitleChange } from '@/composables/useTitleChange';
|
|
||||||
import { useToast } from '@/composables/useToast';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExpressionError,
|
ExpressionError,
|
||||||
IDataObject,
|
IDataObject,
|
||||||
|
@ -22,7 +14,12 @@ import type {
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import { TelemetryHelpers } from 'n8n-workflow';
|
import { TelemetryHelpers } from 'n8n-workflow';
|
||||||
|
import type { PushMessage, PushPayload } from '@n8n/api-types';
|
||||||
|
|
||||||
|
import type { IExecutionResponse, IExecutionsCurrentSummaryExtended } from '@/Interface';
|
||||||
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
|
import { useTitleChange } from '@/composables/useTitleChange';
|
||||||
|
import { useToast } from '@/composables/useToast';
|
||||||
import { WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
import { WORKFLOW_SETTINGS_MODAL_KEY } from '@/constants';
|
||||||
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
import { getTriggerNodeServiceName } from '@/utils/nodeTypesUtils';
|
||||||
import { codeNodeEditorEventBus, globalLinkActionsEventBus } from '@/event-bus';
|
import { codeNodeEditorEventBus, globalLinkActionsEventBus } from '@/event-bus';
|
||||||
|
@ -31,12 +28,9 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
import { useCredentialsStore } from '@/stores/credentials.store';
|
import { useCredentialsStore } from '@/stores/credentials.store';
|
||||||
import { useSettingsStore } from '@/stores/settings.store';
|
import { useSettingsStore } from '@/stores/settings.store';
|
||||||
import { parse } from 'flatted';
|
|
||||||
import { h, ref } from 'vue';
|
|
||||||
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
||||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||||
import type { useRouter } from 'vue-router';
|
|
||||||
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
import { useWorkflowHelpers } from '@/composables/useWorkflowHelpers';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
|
@ -44,6 +38,8 @@ import type { PushMessageQueueItem } from '@/types';
|
||||||
import { useAssistantStore } from '@/stores/assistant.store';
|
import { useAssistantStore } from '@/stores/assistant.store';
|
||||||
import NodeExecutionErrorMessage from '@/components/NodeExecutionErrorMessage.vue';
|
import NodeExecutionErrorMessage from '@/components/NodeExecutionErrorMessage.vue';
|
||||||
|
|
||||||
|
type IPushDataExecutionFinishedPayload = PushPayload<'executionFinished'>;
|
||||||
|
|
||||||
export function usePushConnection({ router }: { router: ReturnType<typeof useRouter> }) {
|
export function usePushConnection({ router }: { router: ReturnType<typeof useRouter> }) {
|
||||||
const workflowHelpers = useWorkflowHelpers({ router });
|
const workflowHelpers = useWorkflowHelpers({ router });
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
|
@ -83,7 +79,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
* is currently active. So internally resend the message
|
* is currently active. So internally resend the message
|
||||||
* a few more times
|
* a few more times
|
||||||
*/
|
*/
|
||||||
function queuePushMessage(event: IPushData, retryAttempts: number) {
|
function queuePushMessage(event: PushMessage, retryAttempts: number) {
|
||||||
pushMessageQueue.value.push({ message: event, retriesLeft: retryAttempts });
|
pushMessageQueue.value.push({ message: event, retriesLeft: retryAttempts });
|
||||||
|
|
||||||
if (retryTimeout.value === null) {
|
if (retryTimeout.value === null) {
|
||||||
|
@ -125,7 +121,10 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
/**
|
/**
|
||||||
* Process a newly received message
|
* Process a newly received message
|
||||||
*/
|
*/
|
||||||
async function pushMessageReceived(receivedData: IPushData, isRetry?: boolean): Promise<boolean> {
|
async function pushMessageReceived(
|
||||||
|
receivedData: PushMessage,
|
||||||
|
isRetry?: boolean,
|
||||||
|
): Promise<boolean> {
|
||||||
const retryAttempts = 5;
|
const retryAttempts = 5;
|
||||||
|
|
||||||
if (receivedData.type === 'sendWorkerStatusMessage') {
|
if (receivedData.type === 'sendWorkerStatusMessage') {
|
||||||
|
@ -161,7 +160,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
// The data is not for the currently active execution or
|
// The data is not for the currently active execution or
|
||||||
// we do not have the execution id yet.
|
// we do not have the execution id yet.
|
||||||
if (isRetry !== true) {
|
if (isRetry !== true) {
|
||||||
queuePushMessage(event as unknown as IPushData, retryAttempts);
|
queuePushMessage(event as unknown as PushMessage, retryAttempts);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +168,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
|
|
||||||
// recovered execution data is handled like executionFinished data, however for security reasons
|
// recovered execution data is handled like executionFinished data, however for security reasons
|
||||||
// we need to fetch the data from the server again rather than push it to all clients
|
// we need to fetch the data from the server again rather than push it to all clients
|
||||||
let recoveredPushData: IPushDataExecutionFinished | undefined = undefined;
|
let recoveredPushData: IPushDataExecutionFinishedPayload | undefined = undefined;
|
||||||
if (receivedData.type === 'executionRecovered') {
|
if (receivedData.type === 'executionRecovered') {
|
||||||
const recoveredExecutionId = receivedData.data?.executionId;
|
const recoveredExecutionId = receivedData.data?.executionId;
|
||||||
const isWorkflowRunning = uiStore.isActionActive['workflowRunning'];
|
const isWorkflowRunning = uiStore.isActionActive['workflowRunning'];
|
||||||
|
@ -242,11 +241,11 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
|
|
||||||
if (receivedData.type === 'executionFinished' || receivedData.type === 'executionRecovered') {
|
if (receivedData.type === 'executionFinished' || receivedData.type === 'executionRecovered') {
|
||||||
// The workflow finished executing
|
// The workflow finished executing
|
||||||
let pushData: IPushDataExecutionFinished;
|
let pushData: IPushDataExecutionFinishedPayload;
|
||||||
if (receivedData.type === 'executionRecovered' && recoveredPushData !== undefined) {
|
if (receivedData.type === 'executionRecovered' && recoveredPushData !== undefined) {
|
||||||
pushData = recoveredPushData;
|
pushData = recoveredPushData;
|
||||||
} else {
|
} else {
|
||||||
pushData = receivedData.data as IPushDataExecutionFinished;
|
pushData = receivedData.data as IPushDataExecutionFinishedPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { activeExecutionId } = workflowsStore;
|
const { activeExecutionId } = workflowsStore;
|
||||||
|
@ -274,7 +273,7 @@ export function usePushConnection({ router }: { router: ReturnType<typeof useRou
|
||||||
// The workflow which did finish execution did either not get started
|
// The workflow which did finish execution did either not get started
|
||||||
// by this session or we do not have the execution id yet.
|
// by this session or we do not have the execution id yet.
|
||||||
if (isRetry !== true) {
|
if (isRetry !== true) {
|
||||||
queuePushMessage(event as unknown as IPushData, retryAttempts);
|
queuePushMessage(event as unknown as PushMessage, retryAttempts);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import type {
|
import type {
|
||||||
IExecutionPushResponse,
|
IExecutionPushResponse,
|
||||||
IExecutionResponse,
|
IExecutionResponse,
|
||||||
IPushDataExecutionFinished,
|
|
||||||
IStartRunData,
|
IStartRunData,
|
||||||
IWorkflowDb,
|
IWorkflowDb,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
@ -34,6 +33,7 @@ import { isEmpty } from '@/utils/typesUtils';
|
||||||
import { useI18n } from '@/composables/useI18n';
|
import { useI18n } from '@/composables/useI18n';
|
||||||
import { get } from 'lodash-es';
|
import { get } from 'lodash-es';
|
||||||
import { useExecutionsStore } from '@/stores/executions.store';
|
import { useExecutionsStore } from '@/stores/executions.store';
|
||||||
|
import type { PushPayload } from '@n8n/api-types';
|
||||||
|
|
||||||
export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof useRouter> }) {
|
export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof useRouter> }) {
|
||||||
const nodeHelpers = useNodeHelpers();
|
const nodeHelpers = useNodeHelpers();
|
||||||
|
@ -375,7 +375,7 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
// execution finished but was not saved (e.g. due to low connectivity)
|
// execution finished but was not saved (e.g. due to low connectivity)
|
||||||
workflowsStore.finishActiveExecution({
|
workflowsStore.finishActiveExecution({
|
||||||
executionId,
|
executionId,
|
||||||
data: { finished: true, stoppedAt: new Date() },
|
data: { finished: true, stoppedAt: new Date() } as IRun,
|
||||||
});
|
});
|
||||||
workflowsStore.executingNode.length = 0;
|
workflowsStore.executingNode.length = 0;
|
||||||
uiStore.removeActiveAction('workflowRunning');
|
uiStore.removeActiveAction('workflowRunning');
|
||||||
|
@ -395,11 +395,11 @@ export function useRunWorkflow(useRunWorkflowOpts: { router: ReturnType<typeof u
|
||||||
startedAt: execution.startedAt,
|
startedAt: execution.startedAt,
|
||||||
stoppedAt: execution.stoppedAt,
|
stoppedAt: execution.stoppedAt,
|
||||||
} as IRun;
|
} as IRun;
|
||||||
const pushData = {
|
const pushData: PushPayload<'executionFinished'> = {
|
||||||
data: executedData,
|
data: executedData,
|
||||||
executionId,
|
executionId,
|
||||||
retryOf: execution.retryOf,
|
retryOf: execution.retryOf,
|
||||||
} as IPushDataExecutionFinished;
|
};
|
||||||
workflowsStore.finishActiveExecution(pushData);
|
workflowsStore.finishActiveExecution(pushData);
|
||||||
titleSet(execution.workflowData.name, 'IDLE');
|
titleSet(execution.workflowData.name, 'IDLE');
|
||||||
workflowsStore.executingNode.length = 0;
|
workflowsStore.executingNode.length = 0;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
import type { ChatRequest } from '@/types/assistant.types';
|
import type { ChatRequest } from '@/types/assistant.types';
|
||||||
import type { ChatUI } from 'n8n-design-system/types/assistant';
|
import type { ChatUI } from 'n8n-design-system/types/assistant';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
|
import type { PushPayload } from '@n8n/api-types';
|
||||||
import { computed, h, ref, watch } from 'vue';
|
import { computed, h, ref, watch } from 'vue';
|
||||||
import { useRootStore } from './root.store';
|
import { useRootStore } from './root.store';
|
||||||
import { useUsersStore } from './users.store';
|
import { useUsersStore } from './users.store';
|
||||||
|
@ -20,7 +21,7 @@ import type { ICredentialType, INodeParameters } from 'n8n-workflow';
|
||||||
import { deepCopy } from 'n8n-workflow';
|
import { deepCopy } from 'n8n-workflow';
|
||||||
import { ndvEventBus, codeNodeEditorEventBus } from '@/event-bus';
|
import { ndvEventBus, codeNodeEditorEventBus } from '@/event-bus';
|
||||||
import { useNDVStore } from './ndv.store';
|
import { useNDVStore } from './ndv.store';
|
||||||
import type { IPushDataNodeExecuteAfter, IUpdateInformation } from '@/Interface';
|
import type { IUpdateInformation } from '@/Interface';
|
||||||
import {
|
import {
|
||||||
getMainAuthField,
|
getMainAuthField,
|
||||||
getNodeAuthOptions,
|
getNodeAuthOptions,
|
||||||
|
@ -473,7 +474,7 @@ export const useAssistantStore = defineStore(STORES.ASSISTANT, () => {
|
||||||
(e) => handleServiceError(e, id),
|
(e) => handleServiceError(e, id),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function onNodeExecution(pushEvent: IPushDataNodeExecuteAfter) {
|
async function onNodeExecution(pushEvent: PushPayload<'nodeExecuteAfter'>) {
|
||||||
if (!chatSessionError.value || pushEvent.nodeName !== chatSessionError.value.node.name) {
|
if (!chatSessionError.value || pushEvent.nodeName !== chatSessionError.value.node.name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import type { Collaborator } from '@n8n/api-types';
|
||||||
|
|
||||||
import { STORES, PLACEHOLDER_EMPTY_WORKFLOW_ID, TIME } from '@/constants';
|
import { STORES, PLACEHOLDER_EMPTY_WORKFLOW_ID, TIME } from '@/constants';
|
||||||
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
||||||
import type { Collaborator } from '@/Interface';
|
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||||
import { useUsersStore } from '@/stores/users.store';
|
import { useUsersStore } from '@/stores/users.store';
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import type { IPushDataWorkerStatusPayload } from '../Interface';
|
import type { WorkerStatus } from '@n8n/api-types';
|
||||||
|
|
||||||
import { useRootStore } from './root.store';
|
import { useRootStore } from './root.store';
|
||||||
import { sendGetWorkerStatus } from '../api/orchestration';
|
import { sendGetWorkerStatus } from '../api/orchestration';
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ const STALE_SECONDS = 120 * 1000;
|
||||||
|
|
||||||
export interface IOrchestrationStoreState {
|
export interface IOrchestrationStoreState {
|
||||||
initialStatusReceived: boolean;
|
initialStatusReceived: boolean;
|
||||||
workers: { [id: string]: IPushDataWorkerStatusPayload };
|
workers: { [id: string]: WorkerStatus };
|
||||||
workersHistory: {
|
workersHistory: {
|
||||||
[id: string]: IWorkerHistoryItem[];
|
[id: string]: IWorkerHistoryItem[];
|
||||||
};
|
};
|
||||||
|
@ -18,7 +19,7 @@ export interface IOrchestrationStoreState {
|
||||||
|
|
||||||
export interface IWorkerHistoryItem {
|
export interface IWorkerHistoryItem {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
data: IPushDataWorkerStatusPayload;
|
data: WorkerStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useOrchestrationStore = defineStore('orchestrationManager', {
|
export const useOrchestrationStore = defineStore('orchestrationManager', {
|
||||||
|
@ -30,7 +31,7 @@ export const useOrchestrationStore = defineStore('orchestrationManager', {
|
||||||
statusInterval: null,
|
statusInterval: null,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
updateWorkerStatus(data: IPushDataWorkerStatusPayload) {
|
updateWorkerStatus(data: WorkerStatus) {
|
||||||
this.workers[data.workerId] = data;
|
this.workers[data.workerId] = data;
|
||||||
if (!this.workersHistory[data.workerId]) {
|
if (!this.workersHistory[data.workerId]) {
|
||||||
this.workersHistory[data.workerId] = [];
|
this.workersHistory[data.workerId] = [];
|
||||||
|
@ -70,7 +71,7 @@ export const useOrchestrationStore = defineStore('orchestrationManager', {
|
||||||
getWorkerLastUpdated(workerId: string): number {
|
getWorkerLastUpdated(workerId: string): number {
|
||||||
return this.workersLastUpdated[workerId] ?? 0;
|
return this.workersLastUpdated[workerId] ?? 0;
|
||||||
},
|
},
|
||||||
getWorkerStatus(workerId: string): IPushDataWorkerStatusPayload | undefined {
|
getWorkerStatus(workerId: string): WorkerStatus | undefined {
|
||||||
return this.workers[workerId];
|
return this.workers[workerId];
|
||||||
},
|
},
|
||||||
getWorkerStatusHistory(workerId: string): IWorkerHistoryItem[] {
|
getWorkerStatusHistory(workerId: string): IWorkerHistoryItem[] {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { STORES, TIME } from '@/constants';
|
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
import type { PushMessage } from '@n8n/api-types';
|
||||||
|
|
||||||
|
import { STORES, TIME } from '@/constants';
|
||||||
import { useSettingsStore } from './settings.store';
|
import { useSettingsStore } from './settings.store';
|
||||||
import { useRootStore } from './root.store';
|
import { useRootStore } from './root.store';
|
||||||
import type { IPushData } from '../Interface';
|
|
||||||
|
|
||||||
export interface PushState {
|
export interface PushState {
|
||||||
pushRef: string;
|
pushRef: string;
|
||||||
|
@ -17,7 +18,7 @@ export interface PushState {
|
||||||
isConnectionOpen: boolean;
|
isConnectionOpen: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OnPushMessageHandler = (event: IPushData) => void;
|
export type OnPushMessageHandler = (event: PushMessage) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store for managing a push connection to the server
|
* Store for managing a push connection to the server
|
||||||
|
@ -139,7 +140,7 @@ export const usePushConnectionStore = defineStore(STORES.PUSH, () => {
|
||||||
* Process a newly received message
|
* Process a newly received message
|
||||||
*/
|
*/
|
||||||
async function pushMessageReceived(event: Event) {
|
async function pushMessageReceived(event: Event) {
|
||||||
let receivedData: IPushData;
|
let receivedData: PushMessage;
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
receivedData = JSON.parse(event.data);
|
receivedData = JSON.parse(event.data);
|
||||||
|
|
|
@ -18,9 +18,6 @@ import type {
|
||||||
INodeMetadata,
|
INodeMetadata,
|
||||||
INodeUi,
|
INodeUi,
|
||||||
INodeUpdatePropertiesInformation,
|
INodeUpdatePropertiesInformation,
|
||||||
IPushDataExecutionFinished,
|
|
||||||
IPushDataNodeExecuteAfter,
|
|
||||||
IPushDataUnsavedExecutionFinished,
|
|
||||||
IStartRunData,
|
IStartRunData,
|
||||||
IUpdateInformation,
|
IUpdateInformation,
|
||||||
IUsedCredential,
|
IUsedCredential,
|
||||||
|
@ -74,6 +71,7 @@ import { i18n } from '@/plugins/i18n';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useProjectsStore } from '@/stores/projects.store';
|
import { useProjectsStore } from '@/stores/projects.store';
|
||||||
import type { ProjectSharingData } from '@/types/projects.types';
|
import type { ProjectSharingData } from '@/types/projects.types';
|
||||||
|
import type { PushPayload } from '@n8n/api-types';
|
||||||
|
|
||||||
const defaults: Omit<IWorkflowDb, 'id'> & { settings: NonNullable<IWorkflowDb['settings']> } = {
|
const defaults: Omit<IWorkflowDb, 'id'> & { settings: NonNullable<IWorkflowDb['settings']> } = {
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -1185,7 +1183,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNodeExecutionData(pushData: IPushDataNodeExecuteAfter): void {
|
function addNodeExecutionData(pushData: PushPayload<'nodeExecuteAfter'>): void {
|
||||||
if (!workflowExecutionData.value?.data) {
|
if (!workflowExecutionData.value?.data) {
|
||||||
throw new Error('The "workflowExecutionData" is not initialized!');
|
throw new Error('The "workflowExecutionData" is not initialized!');
|
||||||
}
|
}
|
||||||
|
@ -1257,9 +1255,7 @@ export const useWorkflowsStore = defineStore(STORES.WORKFLOWS, () => {
|
||||||
activeExecutionId.value = newActiveExecution.id;
|
activeExecutionId.value = newActiveExecution.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishActiveExecution(
|
function finishActiveExecution(finishedActiveExecution: PushPayload<'executionFinished'>): void {
|
||||||
finishedActiveExecution: IPushDataExecutionFinished | IPushDataUnsavedExecutionFinished,
|
|
||||||
): void {
|
|
||||||
// Find the execution to set to finished
|
// Find the execution to set to finished
|
||||||
const activeExecutionIndex = activeExecutions.value.findIndex((execution) => {
|
const activeExecutionIndex = activeExecutions.value.findIndex((execution) => {
|
||||||
return execution.id === finishedActiveExecution.executionId;
|
return execution.id === finishedActiveExecution.executionId;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { IPushData } from '@/Interface';
|
import type { PushMessage } from '@n8n/api-types';
|
||||||
|
|
||||||
export type PushMessageQueueItem = {
|
export type PushMessageQueueItem = {
|
||||||
message: IPushData;
|
message: PushMessage;
|
||||||
retriesLeft: number;
|
retriesLeft: number;
|
||||||
};
|
};
|
||||||
|
|
|
@ -103,7 +103,6 @@ import type {
|
||||||
NodeCreatorOpenSource,
|
NodeCreatorOpenSource,
|
||||||
AddedNodesAndConnections,
|
AddedNodesAndConnections,
|
||||||
ToggleNodeCreatorOptions,
|
ToggleNodeCreatorOptions,
|
||||||
IPushDataExecutionFinished,
|
|
||||||
NodeFilterType,
|
NodeFilterType,
|
||||||
} from '@/Interface';
|
} from '@/Interface';
|
||||||
|
|
||||||
|
@ -183,6 +182,7 @@ import { useNpsSurveyStore } from '@/stores/npsSurvey.store';
|
||||||
import { getResourcePermissions } from '@/permissions';
|
import { getResourcePermissions } from '@/permissions';
|
||||||
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
import { useBeforeUnload } from '@/composables/useBeforeUnload';
|
||||||
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
import NodeViewUnfinishedWorkflowMessage from '@/components/NodeViewUnfinishedWorkflowMessage.vue';
|
||||||
|
import type { PushPayload } from '@n8n/api-types';
|
||||||
|
|
||||||
interface AddNodeOptions {
|
interface AddNodeOptions {
|
||||||
position?: XYPosition;
|
position?: XYPosition;
|
||||||
|
@ -1714,7 +1714,7 @@ export default defineComponent({
|
||||||
|
|
||||||
this.workflowsStore.finishActiveExecution({
|
this.workflowsStore.finishActiveExecution({
|
||||||
executionId,
|
executionId,
|
||||||
data: { finished: true, stoppedAt: new Date() },
|
data: { finished: true, stoppedAt: new Date() } as IRun,
|
||||||
});
|
});
|
||||||
this.workflowsStore.executingNode.length = 0;
|
this.workflowsStore.executingNode.length = 0;
|
||||||
this.uiStore.removeActiveAction('workflowRunning');
|
this.uiStore.removeActiveAction('workflowRunning');
|
||||||
|
@ -1737,11 +1737,11 @@ export default defineComponent({
|
||||||
startedAt: execution.startedAt,
|
startedAt: execution.startedAt,
|
||||||
stoppedAt: execution.stoppedAt,
|
stoppedAt: execution.stoppedAt,
|
||||||
} as IRun;
|
} as IRun;
|
||||||
const pushData = {
|
const pushData: PushPayload<'executionFinished'> = {
|
||||||
data: executedData,
|
data: executedData,
|
||||||
executionId,
|
executionId,
|
||||||
retryOf: execution.retryOf,
|
retryOf: execution.retryOf,
|
||||||
} as IPushDataExecutionFinished;
|
};
|
||||||
this.workflowsStore.finishActiveExecution(pushData);
|
this.workflowsStore.finishActiveExecution(pushData);
|
||||||
this.titleSet(execution.workflowData.name, 'IDLE');
|
this.titleSet(execution.workflowData.name, 'IDLE');
|
||||||
this.workflowsStore.executingNode.length = 0;
|
this.workflowsStore.executingNode.length = 0;
|
||||||
|
|
|
@ -221,6 +221,12 @@ importers:
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../packages/workflow
|
version: link:../packages/workflow
|
||||||
|
|
||||||
|
packages/@n8n/api-types:
|
||||||
|
devDependencies:
|
||||||
|
n8n-workflow:
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../workflow
|
||||||
|
|
||||||
packages/@n8n/benchmark:
|
packages/@n8n/benchmark:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@oclif/core':
|
'@oclif/core':
|
||||||
|
@ -662,6 +668,9 @@ importers:
|
||||||
'@google-cloud/secret-manager':
|
'@google-cloud/secret-manager':
|
||||||
specifier: ^5.6.0
|
specifier: ^5.6.0
|
||||||
version: 5.6.0(encoding@0.1.13)
|
version: 5.6.0(encoding@0.1.13)
|
||||||
|
'@n8n/api-types':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../@n8n/api-types
|
||||||
'@n8n/client-oauth2':
|
'@n8n/client-oauth2':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../@n8n/client-oauth2
|
version: link:../@n8n/client-oauth2
|
||||||
|
@ -1286,6 +1295,9 @@ importers:
|
||||||
'@lezer/common':
|
'@lezer/common':
|
||||||
specifier: ^1.0.4
|
specifier: ^1.0.4
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
|
'@n8n/api-types':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../@n8n/api-types
|
||||||
'@n8n/chat':
|
'@n8n/chat':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../@n8n/chat
|
version: link:../@n8n/chat
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
"format": {},
|
"format": {},
|
||||||
"lint:backend": {
|
"lint:backend": {
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
|
"@n8n/api-types#lint",
|
||||||
"@n8n/config#lint",
|
"@n8n/config#lint",
|
||||||
"@n8n/client-oauth2#lint",
|
"@n8n/client-oauth2#lint",
|
||||||
"@n8n/imap#lint",
|
"@n8n/imap#lint",
|
||||||
|
@ -52,6 +53,7 @@
|
||||||
"lintfix": {},
|
"lintfix": {},
|
||||||
"test:backend": {
|
"test:backend": {
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
|
"@n8n/api-types#test",
|
||||||
"@n8n/config#test",
|
"@n8n/config#test",
|
||||||
"@n8n/client-oauth2#test",
|
"@n8n/client-oauth2#test",
|
||||||
"@n8n/imap#test",
|
"@n8n/imap#test",
|
||||||
|
|
Loading…
Reference in a new issue