diff --git a/packages/cli/src/AbstractServer.ts b/packages/cli/src/AbstractServer.ts index 4050b65a80..66ce5855f0 100644 --- a/packages/cli/src/AbstractServer.ts +++ b/packages/cli/src/AbstractServer.ts @@ -11,13 +11,14 @@ import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import * as Db from '@/Db'; import type { N8nInstanceType, IExternalHooksClass } from '@/Interfaces'; import { ExternalHooks } from '@/ExternalHooks'; -import { send, sendErrorResponse, ServiceUnavailableError } from '@/ResponseHelper'; +import { send, sendErrorResponse } from '@/ResponseHelper'; import { rawBodyReader, bodyParser, corsMiddleware } from '@/middlewares'; import { TestWebhooks } from '@/TestWebhooks'; import { WaitingWebhooks } from '@/WaitingWebhooks'; import { webhookRequestHandler } from '@/WebhookHelpers'; import { generateHostInstanceId } from './databases/utils/generators'; import { Logger } from '@/Logger'; +import { ServiceUnavailableError } from './errors/response-errors/service-unavailable.error'; export abstract class AbstractServer { protected logger: Logger; diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index efa7e47521..1c8d1cc7a7 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -42,7 +42,6 @@ import type { WebhookAccessControlOptions, WebhookRequest, } from '@/Interfaces'; -import * as ResponseHelper from '@/ResponseHelper'; import * as WebhookHelpers from '@/WebhookHelpers'; import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'; @@ -68,6 +67,7 @@ import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.reposi import { WorkflowRepository } from '@db/repositories/workflow.repository'; import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee'; import { ActivationErrorsService } from '@/ActivationErrors.service'; +import { NotFoundError } from './errors/response-errors/not-found.error'; const WEBHOOK_PROD_UNREGISTERED_HINT = "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"; @@ -165,9 +165,7 @@ export class ActiveWorkflowRunner implements IWebhookManager { }); if (workflowData === null) { - throw new ResponseHelper.NotFoundError( - `Could not find workflow with id "${webhook.workflowId}"`, - ); + throw new NotFoundError(`Could not find workflow with id "${webhook.workflowId}"`); } const workflow = new Workflow({ @@ -196,7 +194,7 @@ export class ActiveWorkflowRunner implements IWebhookManager { const workflowStartNode = workflow.getNode(webhookData.node); if (workflowStartNode === null) { - throw new ResponseHelper.NotFoundError('Could not find node to process webhook.'); + throw new NotFoundError('Could not find node to process webhook.'); } return new Promise((resolve, reject) => { @@ -252,7 +250,7 @@ export class ActiveWorkflowRunner implements IWebhookManager { const webhook = await this.webhookService.findWebhook(httpMethod, path); if (webhook === null) { - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( webhookNotFoundErrorMessage(path, httpMethod), WEBHOOK_PROD_UNREGISTERED_HINT, ); diff --git a/packages/cli/src/CredentialsHelper.ts b/packages/cli/src/CredentialsHelper.ts index 9144c9fb2d..8b6876944c 100644 --- a/packages/cli/src/CredentialsHelper.ts +++ b/packages/cli/src/CredentialsHelper.ts @@ -32,7 +32,6 @@ import type { INodeTypes, IWorkflowExecuteAdditionalData, ICredentialTestFunctions, - Severity, } from 'n8n-workflow'; import { ICredentialsHelper, @@ -55,6 +54,7 @@ import { isObjectLiteral } from './utils'; import { Logger } from '@/Logger'; import { CredentialsRepository } from '@db/repositories/credentials.repository'; import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository'; +import { CredentialNotFoundError } from './errors/credential-not-found.error'; const { OAUTH2_CREDENTIAL_TEST_SUCCEEDED, OAUTH2_CREDENTIAL_TEST_FAILED } = RESPONSE_ERROR_MESSAGES; @@ -87,15 +87,6 @@ const mockNodeTypes: INodeTypes = { }, }; -class CredentialNotFoundError extends Error { - severity: Severity; - - constructor(credentialId: string, credentialType: string) { - super(`Credential with ID "${credentialId}" does not exist for type "${credentialType}".`); - this.severity = 'warning'; - } -} - @Service() export class CredentialsHelper extends ICredentialsHelper { constructor( diff --git a/packages/cli/src/ExternalSecrets/ExternalSecrets.controller.ee.ts b/packages/cli/src/ExternalSecrets/ExternalSecrets.controller.ee.ts index 10eed808a6..d46bcc6113 100644 --- a/packages/cli/src/ExternalSecrets/ExternalSecrets.controller.ee.ts +++ b/packages/cli/src/ExternalSecrets/ExternalSecrets.controller.ee.ts @@ -1,9 +1,10 @@ import { Authorized, Get, Post, RestController } from '@/decorators'; import { ExternalSecretsRequest } from '@/requests'; -import { NotFoundError } from '@/ResponseHelper'; import { Response } from 'express'; import { Service } from 'typedi'; -import { ProviderNotFoundError, ExternalSecretsService } from './ExternalSecrets.service.ee'; +import { ExternalSecretsService } from './ExternalSecrets.service.ee'; +import { ExternalSecretsProviderNotFoundError } from '@/errors/external-secrets-provider-not-found.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; @Service() @Authorized(['global', 'owner']) @@ -22,7 +23,7 @@ export class ExternalSecretsController { try { return this.secretsService.getProvider(providerName); } catch (e) { - if (e instanceof ProviderNotFoundError) { + if (e instanceof ExternalSecretsProviderNotFoundError) { throw new NotFoundError(`Could not find provider "${e.providerName}"`); } throw e; @@ -41,7 +42,7 @@ export class ExternalSecretsController { } return result; } catch (e) { - if (e instanceof ProviderNotFoundError) { + if (e instanceof ExternalSecretsProviderNotFoundError) { throw new NotFoundError(`Could not find provider "${e.providerName}"`); } throw e; @@ -54,7 +55,7 @@ export class ExternalSecretsController { try { await this.secretsService.saveProviderSettings(providerName, req.body, req.user.id); } catch (e) { - if (e instanceof ProviderNotFoundError) { + if (e instanceof ExternalSecretsProviderNotFoundError) { throw new NotFoundError(`Could not find provider "${e.providerName}"`); } throw e; @@ -68,7 +69,7 @@ export class ExternalSecretsController { try { await this.secretsService.saveProviderConnected(providerName, req.body.connected); } catch (e) { - if (e instanceof ProviderNotFoundError) { + if (e instanceof ExternalSecretsProviderNotFoundError) { throw new NotFoundError(`Could not find provider "${e.providerName}"`); } throw e; @@ -88,7 +89,7 @@ export class ExternalSecretsController { } return { updated: resp }; } catch (e) { - if (e instanceof ProviderNotFoundError) { + if (e instanceof ExternalSecretsProviderNotFoundError) { throw new NotFoundError(`Could not find provider "${e.providerName}"`); } throw e; diff --git a/packages/cli/src/ExternalSecrets/ExternalSecrets.service.ee.ts b/packages/cli/src/ExternalSecrets/ExternalSecrets.service.ee.ts index ab630e27e6..1087443ddb 100644 --- a/packages/cli/src/ExternalSecrets/ExternalSecrets.service.ee.ts +++ b/packages/cli/src/ExternalSecrets/ExternalSecrets.service.ee.ts @@ -5,12 +5,7 @@ import type { IDataObject } from 'n8n-workflow'; import { deepCopy } from 'n8n-workflow'; import Container, { Service } from 'typedi'; import { ExternalSecretsManager } from './ExternalSecretsManager.ee'; - -export class ProviderNotFoundError extends Error { - constructor(public providerName: string) { - super(undefined); - } -} +import { ExternalSecretsProviderNotFoundError } from '@/errors/external-secrets-provider-not-found.error'; @Service() export class ExternalSecretsService { @@ -18,7 +13,7 @@ export class ExternalSecretsService { const providerAndSettings = Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); if (!providerAndSettings) { - throw new ProviderNotFoundError(providerName); + throw new ExternalSecretsProviderNotFoundError(providerName); } const { provider, settings } = providerAndSettings; return { @@ -110,7 +105,7 @@ export class ExternalSecretsService { const providerAndSettings = Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); if (!providerAndSettings) { - throw new ProviderNotFoundError(providerName); + throw new ExternalSecretsProviderNotFoundError(providerName); } const { settings } = providerAndSettings; const newData = this.unredact(data, settings.settings); @@ -121,7 +116,7 @@ export class ExternalSecretsService { const providerAndSettings = Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); if (!providerAndSettings) { - throw new ProviderNotFoundError(providerName); + throw new ExternalSecretsProviderNotFoundError(providerName); } await Container.get(ExternalSecretsManager).setProviderConnected(providerName, connected); return this.getProvider(providerName); @@ -135,7 +130,7 @@ export class ExternalSecretsService { const providerAndSettings = Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); if (!providerAndSettings) { - throw new ProviderNotFoundError(providerName); + throw new ExternalSecretsProviderNotFoundError(providerName); } const { settings } = providerAndSettings; const newData = this.unredact(data, settings.settings); @@ -146,7 +141,7 @@ export class ExternalSecretsService { const providerAndSettings = Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); if (!providerAndSettings) { - throw new ProviderNotFoundError(providerName); + throw new ExternalSecretsProviderNotFoundError(providerName); } return Container.get(ExternalSecretsManager).updateProvider(providerName); } diff --git a/packages/cli/src/GenericHelpers.ts b/packages/cli/src/GenericHelpers.ts index e27ad52967..054422bdeb 100644 --- a/packages/cli/src/GenericHelpers.ts +++ b/packages/cli/src/GenericHelpers.ts @@ -11,7 +11,6 @@ import { Container } from 'typedi'; import { Like } from 'typeorm'; import config from '@/config'; import type { ExecutionPayload, ICredentialsDb, IWorkflowDb } from '@/Interfaces'; -import * as ResponseHelper from '@/ResponseHelper'; import type { WorkflowEntity } from '@db/entities/WorkflowEntity'; import type { CredentialsEntity } from '@db/entities/CredentialsEntity'; import type { TagEntity } from '@db/entities/TagEntity'; @@ -20,6 +19,7 @@ import type { UserUpdatePayload } from '@/requests'; import { CredentialsRepository } from '@db/repositories/credentials.repository'; import { ExecutionRepository } from '@db/repositories/execution.repository'; import { WorkflowRepository } from '@db/repositories/workflow.repository'; +import { BadRequestError } from './errors/response-errors/bad-request.error'; /** * Returns the base URL n8n is reachable from @@ -109,7 +109,7 @@ export async function validateEntity( .join(' | '); if (errorMessages) { - throw new ResponseHelper.BadRequestError(errorMessages); + throw new BadRequestError(errorMessages); } } diff --git a/packages/cli/src/Ldap/helpers.ts b/packages/cli/src/Ldap/helpers.ts index b43533c9d4..adf66e63f0 100644 --- a/packages/cli/src/Ldap/helpers.ts +++ b/packages/cli/src/Ldap/helpers.ts @@ -29,13 +29,14 @@ import { isLdapCurrentAuthenticationMethod, setCurrentAuthenticationMethod, } from '@/sso/ssoHelpers'; -import { BadRequestError, InternalServerError } from '../ResponseHelper'; import { RoleService } from '@/services/role.service'; import { Logger } from '@/Logger'; import { UserRepository } from '@db/repositories/user.repository'; import { SettingsRepository } from '@db/repositories/settings.repository'; import { AuthProviderSyncHistoryRepository } from '@db/repositories/authProviderSyncHistory.repository'; import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; /** * Check whether the LDAP feature is disabled in the instance diff --git a/packages/cli/src/License.ts b/packages/cli/src/License.ts index fa9f6ca32d..4a12ad99f6 100644 --- a/packages/cli/src/License.ts +++ b/packages/cli/src/License.ts @@ -24,14 +24,6 @@ type FeatureReturnType = Partial< } & { [K in NumericLicenseFeature]: number } & { [K in BooleanLicenseFeature]: boolean } >; -export class FeatureNotLicensedError extends Error { - constructor(feature: (typeof LICENSE_FEATURES)[keyof typeof LICENSE_FEATURES]) { - super( - `Your license does not allow for ${feature}. To enable ${feature}, please upgrade to a license that supports this feature.`, - ); - } -} - @Service() export class License { private manager: LicenseManager | undefined; diff --git a/packages/cli/src/NodeTypes.ts b/packages/cli/src/NodeTypes.ts index 19b052a208..0ce7af0578 100644 --- a/packages/cli/src/NodeTypes.ts +++ b/packages/cli/src/NodeTypes.ts @@ -12,14 +12,7 @@ import { LoadNodesAndCredentials } from './LoadNodesAndCredentials'; import { join, dirname } from 'path'; import { readdir } from 'fs/promises'; import type { Dirent } from 'fs'; - -class UnrecognizedNodeError extends Error { - severity = 'warning'; - - constructor(nodeType: string) { - super(`Unrecognized node type: ${nodeType}".`); - } -} +import { UnrecognizedNodeTypeError } from './errors/unrecognized-node-type.error'; @Service() export class NodeTypes implements INodeTypes { @@ -75,7 +68,7 @@ export class NodeTypes implements INodeTypes { return loadedNodes[type]; } - throw new UnrecognizedNodeError(type); + throw new UnrecognizedNodeTypeError(type); } async getNodeTranslationPath({ diff --git a/packages/cli/src/ResponseHelper.ts b/packages/cli/src/ResponseHelper.ts index 3581d4e51b..4684aac2a1 100644 --- a/packages/cli/src/ResponseHelper.ts +++ b/packages/cli/src/ResponseHelper.ts @@ -12,76 +12,7 @@ import type { IWorkflowDb, } from '@/Interfaces'; import { inDevelopment } from '@/constants'; - -/** - * Special Error which allows to return also an error code and http status code - */ -abstract class ResponseError extends Error { - /** - * Creates an instance of ResponseError. - * Must be used inside a block with `ResponseHelper.send()`. - */ - constructor( - message: string, - // The HTTP status code of response - readonly httpStatusCode: number, - // The error code in the response - readonly errorCode: number = httpStatusCode, - // The error hint the response - readonly hint: string | undefined = undefined, - ) { - super(message); - this.name = 'ResponseError'; - } -} - -export class BadRequestError extends ResponseError { - constructor(message: string, errorCode?: number) { - super(message, 400, errorCode); - } -} - -export class AuthError extends ResponseError { - constructor(message: string, errorCode?: number) { - super(message, 401, errorCode); - } -} - -export class UnauthorizedError extends ResponseError { - constructor(message: string, hint: string | undefined = undefined) { - super(message, 403, 403, hint); - } -} - -export class NotFoundError extends ResponseError { - constructor(message: string, hint: string | undefined = undefined) { - super(message, 404, 404, hint); - } -} - -export class ConflictError extends ResponseError { - constructor(message: string, hint: string | undefined = undefined) { - super(message, 409, 409, hint); - } -} - -export class UnprocessableRequestError extends ResponseError { - constructor(message: string, hint: string | undefined = undefined) { - super(message, 422, 422, hint); - } -} - -export class InternalServerError extends ResponseError { - constructor(message: string, errorCode = 500) { - super(message, 500, errorCode); - } -} - -export class ServiceUnavailableError extends ResponseError { - constructor(message: string, errorCode = 503) { - super(message, 503, errorCode); - } -} +import { ResponseError } from './errors/response-errors/abstract/response.error'; export function sendSuccessResponse( res: Response, diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index f5f3af489b..4d6e0c05d6 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -117,6 +117,8 @@ import { OrchestrationController } from './controllers/orchestration.controller' import { WorkflowHistoryController } from './workflows/workflowHistory/workflowHistory.controller.ee'; import { InvitationController } from './controllers/invitation.controller'; import { CollaborationService } from './collaboration/collaboration.service'; +import { BadRequestError } from './errors/response-errors/bad-request.error'; +import { NotFoundError } from './errors/response-errors/not-found.error'; const exec = promisify(callbackExec); @@ -466,9 +468,7 @@ export class Server extends AbstractServer { userId: req.user.id, }); - throw new ResponseHelper.BadRequestError( - `Workflow with ID "${workflowId}" could not be found.`, - ); + throw new BadRequestError(`Workflow with ID "${workflowId}" could not be found.`); } return this.activeWorkflowRunner.getActivationError(workflowId); @@ -491,7 +491,7 @@ export class Server extends AbstractServer { const parameters = toHttpNodeParameters(curlCommand); return ResponseHelper.flattenObject(parameters, 'parameters'); } catch (e) { - throw new ResponseHelper.BadRequestError('Invalid cURL command'); + throw new BadRequestError('Invalid cURL command'); } }, ), @@ -624,7 +624,7 @@ export class Server extends AbstractServer { const sharedWorkflowIds = await getSharedWorkflowIds(req.user); if (!sharedWorkflowIds.length) { - throw new ResponseHelper.NotFoundError('Execution not found'); + throw new NotFoundError('Execution not found'); } const fullExecutionData = await Container.get(ExecutionRepository).findSingleExecution( @@ -637,7 +637,7 @@ export class Server extends AbstractServer { ); if (!fullExecutionData) { - throw new ResponseHelper.NotFoundError('Execution not found'); + throw new NotFoundError('Execution not found'); } if (config.getEnv('executions.mode') === 'queue') { diff --git a/packages/cli/src/TestWebhooks.ts b/packages/cli/src/TestWebhooks.ts index a31e37ea6b..f8a5eafab2 100644 --- a/packages/cli/src/TestWebhooks.ts +++ b/packages/cli/src/TestWebhooks.ts @@ -20,9 +20,9 @@ import type { } from '@/Interfaces'; import { Push } from '@/push'; import { NodeTypes } from '@/NodeTypes'; -import * as ResponseHelper from '@/ResponseHelper'; import * as WebhookHelpers from '@/WebhookHelpers'; import { webhookNotFoundErrorMessage } from './utils'; +import { NotFoundError } from './errors/response-errors/not-found.error'; const WEBHOOK_TEST_UNREGISTERED_HINT = "Click the 'Execute workflow' button on the canvas, then try again. (In test mode, the webhook only works for one call after you click this button)"; @@ -80,7 +80,7 @@ export class TestWebhooks implements IWebhookManager { if (webhookData === undefined) { // The requested webhook is not registered const methods = await this.getWebhookMethods(path); - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( webhookNotFoundErrorMessage(path, httpMethod, methods), WEBHOOK_TEST_UNREGISTERED_HINT, ); @@ -108,7 +108,7 @@ export class TestWebhooks implements IWebhookManager { if (testWebhookData[webhookKey] === undefined) { // The requested webhook is not registered const methods = await this.getWebhookMethods(path); - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( webhookNotFoundErrorMessage(path, httpMethod, methods), WEBHOOK_TEST_UNREGISTERED_HINT, ); @@ -121,7 +121,7 @@ export class TestWebhooks implements IWebhookManager { // get additional data const workflowStartNode = workflow.getNode(webhookData.node); if (workflowStartNode === null) { - throw new ResponseHelper.NotFoundError('Could not find node to process webhook.'); + throw new NotFoundError('Could not find node to process webhook.'); } return new Promise(async (resolve, reject) => { @@ -168,10 +168,7 @@ export class TestWebhooks implements IWebhookManager { const webhookMethods = this.activeWebhooks.getWebhookMethods(path); if (!webhookMethods.length) { // The requested webhook is not registered - throw new ResponseHelper.NotFoundError( - webhookNotFoundErrorMessage(path), - WEBHOOK_TEST_UNREGISTERED_HINT, - ); + throw new NotFoundError(webhookNotFoundErrorMessage(path), WEBHOOK_TEST_UNREGISTERED_HINT); } return webhookMethods; diff --git a/packages/cli/src/UserManagement/UserManagementHelper.ts b/packages/cli/src/UserManagement/UserManagementHelper.ts index 50de670329..448a469a6c 100644 --- a/packages/cli/src/UserManagement/UserManagementHelper.ts +++ b/packages/cli/src/UserManagement/UserManagementHelper.ts @@ -2,7 +2,6 @@ import { In } from 'typeorm'; import { compare, genSaltSync, hash } from 'bcryptjs'; import { Container } from 'typedi'; -import * as ResponseHelper from '@/ResponseHelper'; import type { WhereClause } from '@/Interfaces'; import type { User } from '@db/entities/User'; import { MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from '@db/entities/User'; @@ -11,6 +10,7 @@ import { License } from '@/License'; import { getWebhookBaseUrl } from '@/WebhookHelpers'; import { RoleService } from '@/services/role.service'; import { UserRepository } from '@db/repositories/user.repository'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; export function isSharingEnabled(): boolean { return Container.get(License).isSharingEnabled(); @@ -43,7 +43,7 @@ export function generateUserInviteUrl(inviterId: string, inviteeId: string): str // TODO: Enforce at model level export function validatePassword(password?: string): string { if (!password) { - throw new ResponseHelper.BadRequestError('Password is mandatory'); + throw new BadRequestError('Password is mandatory'); } const hasInvalidLength = @@ -70,7 +70,7 @@ export function validatePassword(password?: string): string { message.push('Password must contain at least 1 uppercase letter.'); } - throw new ResponseHelper.BadRequestError(message.join(' ')); + throw new BadRequestError(message.join(' ')); } return password; diff --git a/packages/cli/src/WaitingWebhooks.ts b/packages/cli/src/WaitingWebhooks.ts index a37f76ad51..7368c29369 100644 --- a/packages/cli/src/WaitingWebhooks.ts +++ b/packages/cli/src/WaitingWebhooks.ts @@ -2,7 +2,6 @@ import { NodeHelpers, Workflow } from 'n8n-workflow'; import { Service } from 'typedi'; import type express from 'express'; -import * as ResponseHelper from '@/ResponseHelper'; import * as WebhookHelpers from '@/WebhookHelpers'; import { NodeTypes } from '@/NodeTypes'; import type { @@ -15,6 +14,8 @@ import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData' import { ExecutionRepository } from '@db/repositories/execution.repository'; import { OwnershipService } from './services/ownership.service'; import { Logger } from '@/Logger'; +import { ConflictError } from './errors/response-errors/conflict.error'; +import { NotFoundError } from './errors/response-errors/not-found.error'; @Service() export class WaitingWebhooks implements IWebhookManager { @@ -43,11 +44,11 @@ export class WaitingWebhooks implements IWebhookManager { }); if (!execution) { - throw new ResponseHelper.NotFoundError(`The execution "${executionId} does not exist.`); + throw new NotFoundError(`The execution "${executionId} does not exist.`); } if (execution.finished || execution.data.resultData.error) { - throw new ResponseHelper.ConflictError(`The execution "${executionId} has finished already.`); + throw new ConflictError(`The execution "${executionId} has finished already.`); } const lastNodeExecuted = execution.data.resultData.lastNodeExecuted as string; @@ -79,12 +80,12 @@ export class WaitingWebhooks implements IWebhookManager { try { workflowOwner = await this.ownershipService.getWorkflowOwnerCached(workflowData.id!); } catch (error) { - throw new ResponseHelper.NotFoundError('Could not find workflow'); + throw new NotFoundError('Could not find workflow'); } const workflowStartNode = workflow.getNode(lastNodeExecuted); if (workflowStartNode === null) { - throw new ResponseHelper.NotFoundError('Could not find node to process webhook.'); + throw new NotFoundError('Could not find node to process webhook.'); } const additionalData = await WorkflowExecuteAdditionalData.getBase(workflowOwner.id); @@ -103,7 +104,7 @@ export class WaitingWebhooks implements IWebhookManager { // If no data got found it means that the execution can not be started via a webhook. // Return 404 because we do not want to give any data if the execution exists or not. const errorMessage = `The workflow for execution "${executionId}" does not contain a waiting webhook with a matching path/method.`; - throw new ResponseHelper.NotFoundError(errorMessage); + throw new NotFoundError(errorMessage); } const runExecutionData = execution.data; diff --git a/packages/cli/src/WebhookHelpers.ts b/packages/cli/src/WebhookHelpers.ts index ae87e130e9..d80ab2c415 100644 --- a/packages/cli/src/WebhookHelpers.ts +++ b/packages/cli/src/WebhookHelpers.ts @@ -63,6 +63,9 @@ import { OwnershipService } from './services/ownership.service'; import { parseBody } from './middlewares'; import { WorkflowsService } from './workflows/workflows.services'; import { Logger } from './Logger'; +import { NotFoundError } from './errors/response-errors/not-found.error'; +import { InternalServerError } from './errors/response-errors/internal-server.error'; +import { UnprocessableRequestError } from './errors/response-errors/unprocessable.error'; const pipeline = promisify(stream.pipeline); @@ -237,7 +240,7 @@ export async function executeWebhook( if (nodeType === undefined) { const errorMessage = `The type of the webhook node "${workflowStartNode.name}" is not known`; responseCallback(new Error(errorMessage), {}); - throw new ResponseHelper.InternalServerError(errorMessage); + throw new InternalServerError(errorMessage); } const additionalKeys: IWorkflowDataProxyAdditionalKeys = { @@ -254,7 +257,7 @@ export async function executeWebhook( try { user = await Container.get(OwnershipService).getWorkflowOwnerCached(workflowData.id); } catch (error) { - throw new ResponseHelper.NotFoundError('Cannot find workflow'); + throw new NotFoundError('Cannot find workflow'); } } @@ -294,7 +297,7 @@ export async function executeWebhook( // that something does not resolve properly. const errorMessage = `The response mode '${responseMode}' is not valid!`; responseCallback(new Error(errorMessage), {}); - throw new ResponseHelper.InternalServerError(errorMessage); + throw new InternalServerError(errorMessage); } // Add the Response and Request so that this data can be accessed in the node @@ -781,13 +784,13 @@ export async function executeWebhook( responseCallback(new Error('There was a problem executing the workflow'), {}); } - throw new ResponseHelper.InternalServerError(e.message); + throw new InternalServerError(e.message); }); } return executionId; } catch (e) { const error = - e instanceof ResponseHelper.UnprocessableRequestError + e instanceof UnprocessableRequestError ? e : new Error('There was a problem executing the workflow', { cause: e }); if (didSendResponse) throw error; diff --git a/packages/cli/src/auth/jwt.ts b/packages/cli/src/auth/jwt.ts index 3b2a810eb0..52c57533e8 100644 --- a/packages/cli/src/auth/jwt.ts +++ b/packages/cli/src/auth/jwt.ts @@ -4,11 +4,12 @@ import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants'; import type { JwtPayload, JwtToken } from '@/Interfaces'; import type { User } from '@db/entities/User'; import config from '@/config'; -import * as ResponseHelper from '@/ResponseHelper'; import { License } from '@/License'; import { Container } from 'typedi'; import { UserRepository } from '@db/repositories/user.repository'; import { JwtService } from '@/services/jwt.service'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; +import { AuthError } from '@/errors/response-errors/auth.error'; export function issueJWT(user: User): JwtToken { const { id, email, password } = user; @@ -26,7 +27,7 @@ export function issueJWT(user: User): JwtToken { !user.isOwner && !isWithinUsersLimit ) { - throw new ResponseHelper.UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED); + throw new UnauthorizedError(RESPONSE_ERROR_MESSAGES.USERS_QUOTA_REACHED); } if (password) { payload.password = createHash('sha256') @@ -63,7 +64,7 @@ export async function resolveJwtContent(jwtPayload: JwtPayload): Promise { // currently only LDAP users during synchronization // can be set to disabled if (user?.disabled) { - throw new ResponseHelper.AuthError('Unauthorized'); + throw new AuthError('Unauthorized'); } if (!user || jwtPayload.password !== passwordHash || user.email !== jwtPayload.email) { diff --git a/packages/cli/src/auth/methods/email.ts b/packages/cli/src/auth/methods/email.ts index 5f8f79005d..7850441697 100644 --- a/packages/cli/src/auth/methods/email.ts +++ b/packages/cli/src/auth/methods/email.ts @@ -1,10 +1,10 @@ import type { User } from '@db/entities/User'; import { compareHash } from '@/UserManagement/UserManagementHelper'; -import * as ResponseHelper from '@/ResponseHelper'; import { Container } from 'typedi'; import { InternalHooks } from '@/InternalHooks'; import { isLdapLoginEnabled } from '@/Ldap/helpers'; import { UserRepository } from '@db/repositories/user.repository'; +import { AuthError } from '@/errors/response-errors/auth.error'; export const handleEmailLogin = async ( email: string, @@ -27,7 +27,7 @@ export const handleEmailLogin = async ( user_id: user.id, }); - throw new ResponseHelper.AuthError('Reset your password to gain access to the instance.'); + throw new AuthError('Reset your password to gain access to the instance.'); } return undefined; diff --git a/packages/cli/src/commands/start.ts b/packages/cli/src/commands/start.ts index c9526c924f..42a5b463f5 100644 --- a/packages/cli/src/commands/start.ts +++ b/packages/cli/src/commands/start.ts @@ -23,7 +23,7 @@ import { EDITOR_UI_DIST_DIR, LICENSE_FEATURES } from '@/constants'; import { eventBus } from '@/eventbus'; import { BaseCommand } from './BaseCommand'; import { InternalHooks } from '@/InternalHooks'; -import { License, FeatureNotLicensedError } from '@/License'; +import { License } from '@/License'; import type { IConfig } from '@oclif/config'; import { SingleMainSetup } from '@/services/orchestration/main/SingleMainSetup'; import { OrchestrationHandlerMainService } from '@/services/orchestration/main/orchestration.handler.main.service'; @@ -31,6 +31,7 @@ import { PruningService } from '@/services/pruning.service'; import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee'; import { SettingsRepository } from '@db/repositories/settings.repository'; import { ExecutionRepository } from '@db/repositories/execution.repository'; +import { FeatureNotLicensedError } from '@/errors/feature-not-licensed.error'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires const open = require('open'); diff --git a/packages/cli/src/commands/worker.ts b/packages/cli/src/commands/worker.ts index d65f39d089..0f7b0d7f15 100644 --- a/packages/cli/src/commands/worker.ts +++ b/packages/cli/src/commands/worker.ts @@ -40,6 +40,7 @@ import type { IConfig } from '@oclif/config'; import { OrchestrationHandlerWorkerService } from '@/services/orchestration/worker/orchestration.handler.worker.service'; import { OrchestrationWorkerService } from '@/services/orchestration/worker/orchestration.worker.service'; import type { WorkerJobStatusSummary } from '../services/orchestration/worker/types'; +import { ServiceUnavailableError } from '@/errors/response-errors/service-unavailable.error'; export class Worker extends BaseCommand { static description = '\nStarts a n8n worker'; @@ -413,7 +414,7 @@ export class Worker extends BaseCommand { await connection.query('SELECT 1'); } catch (e) { this.logger.error('No Database connection!', e as Error); - const error = new ResponseHelper.ServiceUnavailableError('No Database connection!'); + const error = new ServiceUnavailableError('No Database connection!'); return ResponseHelper.sendErrorResponse(res, error); } @@ -424,7 +425,7 @@ export class Worker extends BaseCommand { await Worker.jobQueue.ping(); } catch (e) { this.logger.error('No Redis connection!', e as Error); - const error = new ResponseHelper.ServiceUnavailableError('No Redis connection!'); + const error = new ServiceUnavailableError('No Redis connection!'); return ResponseHelper.sendErrorResponse(res, error); } diff --git a/packages/cli/src/config/utils.ts b/packages/cli/src/config/utils.ts index 4fee1a4110..9fe2fcec85 100644 --- a/packages/cli/src/config/utils.ts +++ b/packages/cli/src/config/utils.ts @@ -1,11 +1,6 @@ +import { NotStringArrayError } from '@/errors/not-string-array.error'; import type { SchemaObj } from 'convict'; -class NotStringArrayError extends Error { - constructor(env: string) { - super(`${env} is not a string array.`); - } -} - export const ensureStringArray = (values: string[], { env }: SchemaObj) => { if (!env) throw new Error(`Missing env: ${env}`); diff --git a/packages/cli/src/controllers/auth.controller.ts b/packages/cli/src/controllers/auth.controller.ts index d70c68691c..d3b1b4140c 100644 --- a/packages/cli/src/controllers/auth.controller.ts +++ b/packages/cli/src/controllers/auth.controller.ts @@ -2,12 +2,6 @@ import validator from 'validator'; import { In } from 'typeorm'; import { Service } from 'typedi'; import { Authorized, Get, Post, RestController } from '@/decorators'; -import { - AuthError, - BadRequestError, - InternalServerError, - UnauthorizedError, -} from '@/ResponseHelper'; import { issueCookie, resolveJwt } from '@/auth/jwt'; import { AUTH_COOKIE_NAME, RESPONSE_ERROR_MESSAGES } from '@/constants'; import { Request, Response } from 'express'; @@ -27,6 +21,10 @@ import { License } from '@/License'; import { UserService } from '@/services/user.service'; import { MfaService } from '@/Mfa/mfa.service'; import { Logger } from '@/Logger'; +import { AuthError } from '@/errors/response-errors/auth.error'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; @Service() @RestController() diff --git a/packages/cli/src/controllers/communityPackages.controller.ts b/packages/cli/src/controllers/communityPackages.controller.ts index 7438ae69d8..689ae3bbdb 100644 --- a/packages/cli/src/controllers/communityPackages.controller.ts +++ b/packages/cli/src/controllers/communityPackages.controller.ts @@ -8,12 +8,13 @@ import { } from '@/constants'; import { Authorized, Delete, Get, Middleware, Patch, Post, RestController } from '@/decorators'; import { NodeRequest } from '@/requests'; -import { BadRequestError, InternalServerError } from '@/ResponseHelper'; import type { InstalledPackages } from '@db/entities/InstalledPackages'; import type { CommunityPackages } from '@/Interfaces'; import { InternalHooks } from '@/InternalHooks'; import { Push } from '@/push'; import { CommunityPackagesService } from '@/services/communityPackages.service'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; const { PACKAGE_NOT_INSTALLED, diff --git a/packages/cli/src/controllers/dynamicNodeParameters.controller.ts b/packages/cli/src/controllers/dynamicNodeParameters.controller.ts index bfb6e7cc37..599b71e65c 100644 --- a/packages/cli/src/controllers/dynamicNodeParameters.controller.ts +++ b/packages/cli/src/controllers/dynamicNodeParameters.controller.ts @@ -12,7 +12,7 @@ import { Authorized, Get, Middleware, RestController } from '@/decorators'; import { getBase } from '@/WorkflowExecuteAdditionalData'; import { DynamicNodeParametersService } from '@/services/dynamicNodeParameters.service'; import { DynamicNodeParametersRequest } from '@/requests'; -import { BadRequestError } from '@/ResponseHelper'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; const assertMethodName: RequestHandler = (req, res, next) => { const { methodName } = req.query as DynamicNodeParametersRequest.BaseRequest['query']; diff --git a/packages/cli/src/controllers/invitation.controller.ts b/packages/cli/src/controllers/invitation.controller.ts index ce94cf4edc..5dc0c23829 100644 --- a/packages/cli/src/controllers/invitation.controller.ts +++ b/packages/cli/src/controllers/invitation.controller.ts @@ -1,7 +1,6 @@ import { In } from 'typeorm'; import Container, { Service } from 'typedi'; import { Authorized, NoAuthRequired, Post, RestController } from '@/decorators'; -import { BadRequestError, UnauthorizedError } from '@/ResponseHelper'; import { issueCookie } from '@/auth/jwt'; import { RESPONSE_ERROR_MESSAGES } from '@/constants'; import { Response } from 'express'; @@ -16,6 +15,8 @@ import { hashPassword, validatePassword } from '@/UserManagement/UserManagementH import { PostHogClient } from '@/posthog'; import type { User } from '@/databases/entities/User'; import validator from 'validator'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; @Service() @RestController('/invitations') diff --git a/packages/cli/src/controllers/ldap.controller.ts b/packages/cli/src/controllers/ldap.controller.ts index 25c19d5d21..827d846487 100644 --- a/packages/cli/src/controllers/ldap.controller.ts +++ b/packages/cli/src/controllers/ldap.controller.ts @@ -4,9 +4,9 @@ import { getLdapConfig, getLdapSynchronizations, updateLdapConfig } from '@/Ldap import { LdapService } from '@/Ldap/LdapService.ee'; import { LdapSync } from '@/Ldap/LdapSync.ee'; import { LdapConfiguration } from '@/Ldap/types'; -import { BadRequestError } from '@/ResponseHelper'; import { NON_SENSIBLE_LDAP_CONFIG_PROPERTIES } from '@/Ldap/constants'; import { InternalHooks } from '@/InternalHooks'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Authorized(['global', 'owner']) @RestController('/ldap') diff --git a/packages/cli/src/controllers/me.controller.ts b/packages/cli/src/controllers/me.controller.ts index 3edfd6bbd2..c7d05cb8cb 100644 --- a/packages/cli/src/controllers/me.controller.ts +++ b/packages/cli/src/controllers/me.controller.ts @@ -5,7 +5,6 @@ import { Service } from 'typedi'; import { randomBytes } from 'crypto'; import { Authorized, Delete, Get, Patch, Post, RestController } from '@/decorators'; import { compareHash, hashPassword, validatePassword } from '@/UserManagement/UserManagementHelper'; -import { BadRequestError } from '@/ResponseHelper'; import { validateEntity } from '@/GenericHelpers'; import { issueCookie } from '@/auth/jwt'; import type { User } from '@db/entities/User'; @@ -21,6 +20,7 @@ import { UserService } from '@/services/user.service'; import { Logger } from '@/Logger'; import { ExternalHooks } from '@/ExternalHooks'; import { InternalHooks } from '@/InternalHooks'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Service() @Authorized() diff --git a/packages/cli/src/controllers/mfa.controller.ts b/packages/cli/src/controllers/mfa.controller.ts index 415b4b1716..5bdc140728 100644 --- a/packages/cli/src/controllers/mfa.controller.ts +++ b/packages/cli/src/controllers/mfa.controller.ts @@ -1,8 +1,8 @@ import { Service } from 'typedi'; import { Authorized, Delete, Get, Post, RestController } from '@/decorators'; import { AuthenticatedRequest, MFA } from '@/requests'; -import { BadRequestError } from '@/ResponseHelper'; import { MfaService } from '@/Mfa/mfa.service'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Service() @Authorized() diff --git a/packages/cli/src/controllers/oauth/abstractOAuth.controller.ts b/packages/cli/src/controllers/oauth/abstractOAuth.controller.ts index babf90f4c6..9229c3aaa4 100644 --- a/packages/cli/src/controllers/oauth/abstractOAuth.controller.ts +++ b/packages/cli/src/controllers/oauth/abstractOAuth.controller.ts @@ -9,12 +9,13 @@ import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials. import type { ICredentialsDb } from '@/Interfaces'; import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper'; import type { OAuthRequest } from '@/requests'; -import { BadRequestError, NotFoundError } from '@/ResponseHelper'; import { RESPONSE_ERROR_MESSAGES } from '@/constants'; import { CredentialsHelper } from '@/CredentialsHelper'; import * as WorkflowExecuteAdditionalData from '@/WorkflowExecuteAdditionalData'; import { Logger } from '@/Logger'; import { ExternalHooks } from '@/ExternalHooks'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; @Service() export abstract class AbstractOAuthController { diff --git a/packages/cli/src/controllers/oauth/oAuth1Credential.controller.ts b/packages/cli/src/controllers/oauth/oAuth1Credential.controller.ts index c9d3d31e00..e0d72ac05f 100644 --- a/packages/cli/src/controllers/oauth/oAuth1Credential.controller.ts +++ b/packages/cli/src/controllers/oauth/oAuth1Credential.controller.ts @@ -8,8 +8,10 @@ import { createHmac } from 'crypto'; import { RESPONSE_ERROR_MESSAGES } from '@/constants'; import { Authorized, Get, RestController } from '@/decorators'; import { OAuthRequest } from '@/requests'; -import { NotFoundError, sendErrorResponse, ServiceUnavailableError } from '@/ResponseHelper'; +import { sendErrorResponse } from '@/ResponseHelper'; import { AbstractOAuthController } from './abstractOAuth.controller'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { ServiceUnavailableError } from '@/errors/response-errors/service-unavailable.error'; interface OAuth1CredentialData { signatureMethod: 'HMAC-SHA256' | 'HMAC-SHA512' | 'HMAC-SHA1'; diff --git a/packages/cli/src/controllers/owner.controller.ts b/packages/cli/src/controllers/owner.controller.ts index f16588d9f6..a1d4da3bf7 100644 --- a/packages/cli/src/controllers/owner.controller.ts +++ b/packages/cli/src/controllers/owner.controller.ts @@ -1,7 +1,6 @@ import validator from 'validator'; import { validateEntity } from '@/GenericHelpers'; import { Authorized, Post, RestController } from '@/decorators'; -import { BadRequestError } from '@/ResponseHelper'; import { hashPassword, validatePassword } from '@/UserManagement/UserManagementHelper'; import { issueCookie } from '@/auth/jwt'; import { Response } from 'express'; @@ -12,6 +11,7 @@ import { SettingsRepository } from '@db/repositories/settings.repository'; import { PostHogClient } from '@/posthog'; import { UserService } from '@/services/user.service'; import { Logger } from '@/Logger'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Authorized(['global', 'owner']) @RestController('/owner') diff --git a/packages/cli/src/controllers/passwordReset.controller.ts b/packages/cli/src/controllers/passwordReset.controller.ts index 6396e2d689..902a2071a8 100644 --- a/packages/cli/src/controllers/passwordReset.controller.ts +++ b/packages/cli/src/controllers/passwordReset.controller.ts @@ -5,13 +5,6 @@ import { IsNull, Not } from 'typeorm'; import validator from 'validator'; import { Get, Post, RestController } from '@/decorators'; -import { - BadRequestError, - InternalServerError, - NotFoundError, - UnauthorizedError, - UnprocessableRequestError, -} from '@/ResponseHelper'; import { getInstanceBaseUrl, hashPassword, @@ -29,6 +22,11 @@ import { MfaService } from '@/Mfa/mfa.service'; import { Logger } from '@/Logger'; import { ExternalHooks } from '@/ExternalHooks'; import { InternalHooks } from '@/InternalHooks'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error'; const throttle = rateLimit({ windowMs: 5 * 60 * 1000, // 5 minutes diff --git a/packages/cli/src/controllers/tags.controller.ts b/packages/cli/src/controllers/tags.controller.ts index ab81357daf..01e40c842c 100644 --- a/packages/cli/src/controllers/tags.controller.ts +++ b/packages/cli/src/controllers/tags.controller.ts @@ -2,9 +2,9 @@ import { Request, Response, NextFunction } from 'express'; import config from '@/config'; import { Authorized, Delete, Get, Middleware, Patch, Post, RestController } from '@/decorators'; import { TagService } from '@/services/tag.service'; -import { BadRequestError } from '@/ResponseHelper'; import { TagsRequest } from '@/requests'; import { Service } from 'typedi'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Authorized() @RestController('/tags') diff --git a/packages/cli/src/controllers/translation.controller.ts b/packages/cli/src/controllers/translation.controller.ts index 8238e73ebd..e7ef6bc3cd 100644 --- a/packages/cli/src/controllers/translation.controller.ts +++ b/packages/cli/src/controllers/translation.controller.ts @@ -3,9 +3,10 @@ import { ICredentialTypes } from 'n8n-workflow'; import { join } from 'path'; import { access } from 'fs/promises'; import { Authorized, Get, RestController } from '@/decorators'; -import { BadRequestError, InternalServerError } from '@/ResponseHelper'; import { Config } from '@/config'; import { NODES_BASE_DIR } from '@/constants'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; export const CREDENTIAL_TRANSLATIONS_DIR = 'n8n-nodes-base/dist/credentials/translations'; export const NODE_HEADERS_PATH = join(NODES_BASE_DIR, 'dist/nodes/headers'); diff --git a/packages/cli/src/controllers/users.controller.ts b/packages/cli/src/controllers/users.controller.ts index 3e239c7adc..3aab71ce75 100644 --- a/packages/cli/src/controllers/users.controller.ts +++ b/packages/cli/src/controllers/users.controller.ts @@ -4,7 +4,6 @@ import { User } from '@db/entities/User'; import { SharedCredentials } from '@db/entities/SharedCredentials'; import { SharedWorkflow } from '@db/entities/SharedWorkflow'; import { Authorized, Delete, Get, RestController, Patch } from '@/decorators'; -import { BadRequestError, NotFoundError, UnauthorizedError } from '@/ResponseHelper'; import { ListQuery, UserRequest, UserSettingsUpdatePayload } from '@/requests'; import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; import { IExternalHooksClass, IInternalHooksClass } from '@/Interfaces'; @@ -17,6 +16,9 @@ import { RoleService } from '@/services/role.service'; import { UserService } from '@/services/user.service'; import { listQueryMiddleware } from '@/middlewares'; import { Logger } from '@/Logger'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Authorized() @RestController('/users') diff --git a/packages/cli/src/controllers/workflowStatistics.controller.ts b/packages/cli/src/controllers/workflowStatistics.controller.ts index ef80374296..5492f9884c 100644 --- a/packages/cli/src/controllers/workflowStatistics.controller.ts +++ b/packages/cli/src/controllers/workflowStatistics.controller.ts @@ -7,9 +7,9 @@ import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.reposi import { WorkflowStatisticsRepository } from '@db/repositories/workflowStatistics.repository'; import { ExecutionRequest } from '@/requests'; import { whereClause } from '@/UserManagement/UserManagementHelper'; -import { NotFoundError } from '@/ResponseHelper'; import type { IWorkflowStatisticsDataLoaded } from '@/Interfaces'; import { Logger } from '@/Logger'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; interface WorkflowStatisticsData { productionSuccess: T; diff --git a/packages/cli/src/credentials/credentials.controller.ee.ts b/packages/cli/src/credentials/credentials.controller.ee.ts index 8ebfcb657b..0bc21d869a 100644 --- a/packages/cli/src/credentials/credentials.controller.ee.ts +++ b/packages/cli/src/credentials/credentials.controller.ee.ts @@ -11,6 +11,9 @@ import { OwnershipService } from '@/services/ownership.service'; import { Container } from 'typedi'; import { InternalHooks } from '@/InternalHooks'; import type { CredentialsEntity } from '@db/entities/CredentialsEntity'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; export const EECredentialsController = express.Router(); @@ -40,7 +43,7 @@ EECredentialsController.get( )) as CredentialsEntity; if (!credential) { - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( 'Could not load the credential. If you think this is an error, ask the owner to share it with you again', ); } @@ -48,7 +51,7 @@ EECredentialsController.get( const userSharing = credential.shared?.find((shared) => shared.user.id === req.user.id); if (!userSharing && req.user.globalRole.name !== 'owner') { - throw new ResponseHelper.UnauthorizedError('Forbidden.'); + throw new UnauthorizedError('Forbidden.'); } credential = Container.get(OwnershipService).addOwnedByAndSharedWith(credential); @@ -82,7 +85,7 @@ EECredentialsController.post( const sharing = await EECredentials.getSharing(req.user, credentialId); if (!ownsCredential) { if (!sharing) { - throw new ResponseHelper.UnauthorizedError('Forbidden'); + throw new UnauthorizedError('Forbidden'); } const decryptedData = EECredentials.decrypt(sharing.credentials); @@ -115,12 +118,12 @@ EECredentialsController.put( !Array.isArray(shareWithIds) || !shareWithIds.every((userId) => typeof userId === 'string') ) { - throw new ResponseHelper.BadRequestError('Bad request'); + throw new BadRequestError('Bad request'); } const { ownsCredential, credential } = await EECredentials.isOwned(req.user, credentialId); if (!ownsCredential || !credential) { - throw new ResponseHelper.UnauthorizedError('Forbidden'); + throw new UnauthorizedError('Forbidden'); } let amountRemoved: number | null = null; diff --git a/packages/cli/src/credentials/credentials.controller.ts b/packages/cli/src/credentials/credentials.controller.ts index 3eddddc3d9..11ba2c0f38 100644 --- a/packages/cli/src/credentials/credentials.controller.ts +++ b/packages/cli/src/credentials/credentials.controller.ts @@ -14,6 +14,7 @@ import { Container } from 'typedi'; import { InternalHooks } from '@/InternalHooks'; import { listQueryMiddleware } from '@/middlewares'; import { Logger } from '@/Logger'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; export const credentialsController = express.Router(); credentialsController.use('/', EECredentialsController); @@ -60,9 +61,7 @@ credentialsController.get( const sharing = await CredentialsService.getSharing(req.user, credentialId, ['credentials']); if (!sharing) { - throw new ResponseHelper.NotFoundError( - `Credential with ID "${credentialId}" could not be found.`, - ); + throw new NotFoundError(`Credential with ID "${credentialId}" could not be found.`); } const { credentials: credential } = sharing; @@ -145,7 +144,7 @@ credentialsController.patch( userId: req.user.id, }, ); - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( 'Credential to be updated not found. You can only update credentials owned by you', ); } @@ -165,9 +164,7 @@ credentialsController.patch( const responseData = await CredentialsService.update(credentialId, newCredentialData); if (responseData === null) { - throw new ResponseHelper.NotFoundError( - `Credential ID "${credentialId}" could not be found to be updated.`, - ); + throw new NotFoundError(`Credential ID "${credentialId}" could not be found to be updated.`); } // Remove the encrypted data as it is not needed in the frontend @@ -197,7 +194,7 @@ credentialsController.delete( userId: req.user.id, }, ); - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( 'Credential to be deleted not found. You can only removed credentials owned by you', ); } diff --git a/packages/cli/src/environments/sourceControl/sourceControl.controller.ee.ts b/packages/cli/src/environments/sourceControl/sourceControl.controller.ee.ts index 63642c70fc..1a808c3b30 100644 --- a/packages/cli/src/environments/sourceControl/sourceControl.controller.ee.ts +++ b/packages/cli/src/environments/sourceControl/sourceControl.controller.ee.ts @@ -12,11 +12,11 @@ import { SourceControlPreferencesService } from './sourceControlPreferences.serv import type { SourceControlPreferences } from './types/sourceControlPreferences'; import type { SourceControlledFile } from './types/sourceControlledFile'; import { SOURCE_CONTROL_API_ROOT, SOURCE_CONTROL_DEFAULT_BRANCH } from './constants'; -import { BadRequestError } from '@/ResponseHelper'; import type { ImportResult } from './types/importResult'; import { InternalHooks } from '../../InternalHooks'; import { getRepoType } from './sourceControlHelper.ee'; import { SourceControlGetStatus } from './types/sourceControlGetStatus'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Service() @RestController(`/${SOURCE_CONTROL_API_ROOT}`) diff --git a/packages/cli/src/environments/sourceControl/sourceControl.service.ee.ts b/packages/cli/src/environments/sourceControl/sourceControl.service.ee.ts index d3c5c48155..990e90c0bd 100644 --- a/packages/cli/src/environments/sourceControl/sourceControl.service.ee.ts +++ b/packages/cli/src/environments/sourceControl/sourceControl.service.ee.ts @@ -17,7 +17,6 @@ import { import { SourceControlGitService } from './sourceControlGit.service.ee'; import type { PushResult } from 'simple-git'; import { SourceControlExportService } from './sourceControlExport.service.ee'; -import { BadRequestError } from '@/ResponseHelper'; import type { ImportResult } from './types/importResult'; import type { SourceControlPushWorkFolder } from './types/sourceControlPushWorkFolder'; import type { SourceControllPullOptions } from './types/sourceControlPullWorkFolder'; @@ -35,6 +34,7 @@ import type { ExportableCredential } from './types/exportableCredential'; import { InternalHooks } from '@/InternalHooks'; import { TagRepository } from '@db/repositories/tag.repository'; import { Logger } from '@/Logger'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; @Service() export class SourceControlService { diff --git a/packages/cli/src/environments/variables/variables.controller.ee.ts b/packages/cli/src/environments/variables/variables.controller.ee.ts index 9651b5173e..42e1b8153c 100644 --- a/packages/cli/src/environments/variables/variables.controller.ee.ts +++ b/packages/cli/src/environments/variables/variables.controller.ee.ts @@ -1,14 +1,14 @@ import { Container, Service } from 'typedi'; -import * as ResponseHelper from '@/ResponseHelper'; import { VariablesRequest } from '@/requests'; import { Authorized, Delete, Get, Licensed, Patch, Post, RestController } from '@/decorators'; -import { - VariablesService, - VariablesLicenseError, - VariablesValidationError, -} from './variables.service.ee'; +import { VariablesService } from './variables.service.ee'; import { Logger } from '@/Logger'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { VariableValidationError } from '@/errors/variable-validation.error'; +import { VariableCountLimitReachedError } from '@/errors/variable-count-limit-reached.error'; @Service() @Authorized() @@ -31,17 +31,17 @@ export class VariablesController { this.logger.info('Attempt to update a variable blocked due to lack of permissions', { userId: req.user.id, }); - throw new ResponseHelper.UnauthorizedError('Unauthorized'); + throw new UnauthorizedError('Unauthorized'); } const variable = req.body; delete variable.id; try { return await Container.get(VariablesService).create(variable); } catch (error) { - if (error instanceof VariablesLicenseError) { - throw new ResponseHelper.BadRequestError(error.message); - } else if (error instanceof VariablesValidationError) { - throw new ResponseHelper.BadRequestError(error.message); + if (error instanceof VariableCountLimitReachedError) { + throw new BadRequestError(error.message); + } else if (error instanceof VariableValidationError) { + throw new BadRequestError(error.message); } throw error; } @@ -52,7 +52,7 @@ export class VariablesController { const id = req.params.id; const variable = await Container.get(VariablesService).getCached(id); if (variable === null) { - throw new ResponseHelper.NotFoundError(`Variable with id ${req.params.id} not found`); + throw new NotFoundError(`Variable with id ${req.params.id} not found`); } return variable; } @@ -66,17 +66,17 @@ export class VariablesController { id, userId: req.user.id, }); - throw new ResponseHelper.UnauthorizedError('Unauthorized'); + throw new UnauthorizedError('Unauthorized'); } const variable = req.body; delete variable.id; try { return await Container.get(VariablesService).update(id, variable); } catch (error) { - if (error instanceof VariablesLicenseError) { - throw new ResponseHelper.BadRequestError(error.message); - } else if (error instanceof VariablesValidationError) { - throw new ResponseHelper.BadRequestError(error.message); + if (error instanceof VariableCountLimitReachedError) { + throw new BadRequestError(error.message); + } else if (error instanceof VariableValidationError) { + throw new BadRequestError(error.message); } throw error; } @@ -90,7 +90,7 @@ export class VariablesController { id, userId: req.user.id, }); - throw new ResponseHelper.UnauthorizedError('Unauthorized'); + throw new UnauthorizedError('Unauthorized'); } await this.variablesService.delete(id); diff --git a/packages/cli/src/environments/variables/variables.service.ee.ts b/packages/cli/src/environments/variables/variables.service.ee.ts index 8253603f99..a962896de4 100644 --- a/packages/cli/src/environments/variables/variables.service.ee.ts +++ b/packages/cli/src/environments/variables/variables.service.ee.ts @@ -6,9 +6,8 @@ import { canCreateNewVariable } from './enviromentHelpers'; import { CacheService } from '@/services/cache.service'; import { VariablesRepository } from '@db/repositories/variables.repository'; import type { DeepPartial } from 'typeorm'; - -export class VariablesLicenseError extends Error {} -export class VariablesValidationError extends Error {} +import { VariableCountLimitReachedError } from '@/errors/variable-count-limit-reached.error'; +import { VariableValidationError } from '@/errors/variable-validation.error'; @Service() export class VariablesService { @@ -59,19 +58,19 @@ export class VariablesService { validateVariable(variable: Omit): void { if (variable.key.length > 50) { - throw new VariablesValidationError('key cannot be longer than 50 characters'); + throw new VariableValidationError('key cannot be longer than 50 characters'); } if (variable.key.replace(/[A-Za-z0-9_]/g, '').length !== 0) { - throw new VariablesValidationError('key can only contain characters A-Za-z0-9_'); + throw new VariableValidationError('key can only contain characters A-Za-z0-9_'); } if (variable.value?.length > 255) { - throw new VariablesValidationError('value cannot be longer than 255 characters'); + throw new VariableValidationError('value cannot be longer than 255 characters'); } } async create(variable: Omit): Promise { if (!canCreateNewVariable(await this.getCount())) { - throw new VariablesLicenseError('Variables limit reached'); + throw new VariableCountLimitReachedError('Variables limit reached'); } this.validateVariable(variable); diff --git a/packages/cli/src/errors/credential-not-found.error.ts b/packages/cli/src/errors/credential-not-found.error.ts new file mode 100644 index 0000000000..3826dc70bd --- /dev/null +++ b/packages/cli/src/errors/credential-not-found.error.ts @@ -0,0 +1,10 @@ +import { ApplicationError, type Severity } from 'n8n-workflow'; + +export class CredentialNotFoundError extends ApplicationError { + severity: Severity; + + constructor(credentialId: string, credentialType: string) { + super(`Credential with ID "${credentialId}" does not exist for type "${credentialType}".`); + this.severity = 'warning'; + } +} diff --git a/packages/cli/src/errors/external-secrets-provider-not-found.error.ts b/packages/cli/src/errors/external-secrets-provider-not-found.error.ts new file mode 100644 index 0000000000..422236d148 --- /dev/null +++ b/packages/cli/src/errors/external-secrets-provider-not-found.error.ts @@ -0,0 +1,7 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class ExternalSecretsProviderNotFoundError extends ApplicationError { + constructor(public providerName: string) { + super(`External secrets provider not found: ${providerName}`); + } +} diff --git a/packages/cli/src/errors/feature-not-licensed.error.ts b/packages/cli/src/errors/feature-not-licensed.error.ts new file mode 100644 index 0000000000..1419501941 --- /dev/null +++ b/packages/cli/src/errors/feature-not-licensed.error.ts @@ -0,0 +1,10 @@ +import type { LICENSE_FEATURES } from '@/constants'; +import { ApplicationError } from 'n8n-workflow'; + +export class FeatureNotLicensedError extends ApplicationError { + constructor(feature: (typeof LICENSE_FEATURES)[keyof typeof LICENSE_FEATURES]) { + super( + `Your license does not allow for ${feature}. To enable ${feature}, please upgrade to a license that supports this feature.`, + ); + } +} diff --git a/packages/cli/src/errors/invalid-role.error.ts b/packages/cli/src/errors/invalid-role.error.ts new file mode 100644 index 0000000000..fc5ebb8aa9 --- /dev/null +++ b/packages/cli/src/errors/invalid-role.error.ts @@ -0,0 +1,3 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class InvalidRoleError extends ApplicationError {} diff --git a/packages/cli/src/errors/not-string-array.error.ts b/packages/cli/src/errors/not-string-array.error.ts new file mode 100644 index 0000000000..22e9fae902 --- /dev/null +++ b/packages/cli/src/errors/not-string-array.error.ts @@ -0,0 +1,7 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class NotStringArrayError extends ApplicationError { + constructor(env: string) { + super(`${env} is not a string array.`); + } +} diff --git a/packages/cli/src/errors/response-errors/abstract/response.error.ts b/packages/cli/src/errors/response-errors/abstract/response.error.ts new file mode 100644 index 0000000000..f756afce41 --- /dev/null +++ b/packages/cli/src/errors/response-errors/abstract/response.error.ts @@ -0,0 +1,23 @@ +import { ApplicationError } from 'n8n-workflow'; + +/** + * Special Error which allows to return also an error code and http status code + */ +export abstract class ResponseError extends ApplicationError { + /** + * Creates an instance of ResponseError. + * Must be used inside a block with `ResponseHelper.send()`. + */ + constructor( + message: string, + // The HTTP status code of response + readonly httpStatusCode: number, + // The error code in the response + readonly errorCode: number = httpStatusCode, + // The error hint the response + readonly hint: string | undefined = undefined, + ) { + super(message); + this.name = 'ResponseError'; + } +} diff --git a/packages/cli/src/errors/response-errors/auth.error.ts b/packages/cli/src/errors/response-errors/auth.error.ts new file mode 100644 index 0000000000..cb3441211b --- /dev/null +++ b/packages/cli/src/errors/response-errors/auth.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class AuthError extends ResponseError { + constructor(message: string, errorCode?: number) { + super(message, 401, errorCode); + } +} diff --git a/packages/cli/src/errors/response-errors/bad-request.error.ts b/packages/cli/src/errors/response-errors/bad-request.error.ts new file mode 100644 index 0000000000..560688f2cb --- /dev/null +++ b/packages/cli/src/errors/response-errors/bad-request.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class BadRequestError extends ResponseError { + constructor(message: string, errorCode?: number) { + super(message, 400, errorCode); + } +} diff --git a/packages/cli/src/errors/response-errors/conflict.error.ts b/packages/cli/src/errors/response-errors/conflict.error.ts new file mode 100644 index 0000000000..fdf3390371 --- /dev/null +++ b/packages/cli/src/errors/response-errors/conflict.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class ConflictError extends ResponseError { + constructor(message: string, hint: string | undefined = undefined) { + super(message, 409, 409, hint); + } +} diff --git a/packages/cli/src/errors/response-errors/internal-server.error.ts b/packages/cli/src/errors/response-errors/internal-server.error.ts new file mode 100644 index 0000000000..4c10e93f95 --- /dev/null +++ b/packages/cli/src/errors/response-errors/internal-server.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class InternalServerError extends ResponseError { + constructor(message: string, errorCode = 500) { + super(message, 500, errorCode); + } +} diff --git a/packages/cli/src/errors/response-errors/not-found.error.ts b/packages/cli/src/errors/response-errors/not-found.error.ts new file mode 100644 index 0000000000..9d9e0e12d5 --- /dev/null +++ b/packages/cli/src/errors/response-errors/not-found.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class NotFoundError extends ResponseError { + constructor(message: string, hint: string | undefined = undefined) { + super(message, 404, 404, hint); + } +} diff --git a/packages/cli/src/errors/response-errors/service-unavailable.error.ts b/packages/cli/src/errors/response-errors/service-unavailable.error.ts new file mode 100644 index 0000000000..7736e85f5f --- /dev/null +++ b/packages/cli/src/errors/response-errors/service-unavailable.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class ServiceUnavailableError extends ResponseError { + constructor(message: string, errorCode = 503) { + super(message, 503, errorCode); + } +} diff --git a/packages/cli/src/errors/response-errors/unauthorized.error.ts b/packages/cli/src/errors/response-errors/unauthorized.error.ts new file mode 100644 index 0000000000..bc8993c014 --- /dev/null +++ b/packages/cli/src/errors/response-errors/unauthorized.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class UnauthorizedError extends ResponseError { + constructor(message: string, hint: string | undefined = undefined) { + super(message, 403, 403, hint); + } +} diff --git a/packages/cli/src/errors/response-errors/unprocessable.error.ts b/packages/cli/src/errors/response-errors/unprocessable.error.ts new file mode 100644 index 0000000000..723acbfbaf --- /dev/null +++ b/packages/cli/src/errors/response-errors/unprocessable.error.ts @@ -0,0 +1,7 @@ +import { ResponseError } from './abstract/response.error'; + +export class UnprocessableRequestError extends ResponseError { + constructor(message: string, hint: string | undefined = undefined) { + super(message, 422, 422, hint); + } +} diff --git a/packages/cli/src/errors/shared-workflow-not-found.error.ts b/packages/cli/src/errors/shared-workflow-not-found.error.ts new file mode 100644 index 0000000000..ae4c99f3f3 --- /dev/null +++ b/packages/cli/src/errors/shared-workflow-not-found.error.ts @@ -0,0 +1,3 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class SharedWorkflowNotFoundError extends ApplicationError {} diff --git a/packages/cli/src/errors/unrecognized-node-type.error.ts b/packages/cli/src/errors/unrecognized-node-type.error.ts new file mode 100644 index 0000000000..1ca5281de5 --- /dev/null +++ b/packages/cli/src/errors/unrecognized-node-type.error.ts @@ -0,0 +1,9 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class UnrecognizedNodeTypeError extends ApplicationError { + severity = 'warning'; + + constructor(nodeType: string) { + super(`Unrecognized node type: ${nodeType}".`); + } +} diff --git a/packages/cli/src/errors/variable-count-limit-reached.error.ts b/packages/cli/src/errors/variable-count-limit-reached.error.ts new file mode 100644 index 0000000000..67d14efebf --- /dev/null +++ b/packages/cli/src/errors/variable-count-limit-reached.error.ts @@ -0,0 +1,3 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class VariableCountLimitReachedError extends ApplicationError {} diff --git a/packages/cli/src/errors/variable-validation.error.ts b/packages/cli/src/errors/variable-validation.error.ts new file mode 100644 index 0000000000..bd2026e7ef --- /dev/null +++ b/packages/cli/src/errors/variable-validation.error.ts @@ -0,0 +1,3 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class VariableValidationError extends ApplicationError {} diff --git a/packages/cli/src/errors/workflow-history-version-not-found.error.ts b/packages/cli/src/errors/workflow-history-version-not-found.error.ts new file mode 100644 index 0000000000..104385672f --- /dev/null +++ b/packages/cli/src/errors/workflow-history-version-not-found.error.ts @@ -0,0 +1,3 @@ +import { ApplicationError } from 'n8n-workflow'; + +export class WorkflowHistoryVersionNotFoundError extends ApplicationError {} diff --git a/packages/cli/src/eventbus/eventBus.controller.ee.ts b/packages/cli/src/eventbus/eventBus.controller.ee.ts index 4815e8545d..a7d16e1b65 100644 --- a/packages/cli/src/eventbus/eventBus.controller.ee.ts +++ b/packages/cli/src/eventbus/eventBus.controller.ee.ts @@ -9,7 +9,6 @@ import { MessageEventBusDestinationSyslog, } from './MessageEventBusDestination/MessageEventBusDestinationSyslog.ee'; import { MessageEventBusDestinationWebhook } from './MessageEventBusDestination/MessageEventBusDestinationWebhook.ee'; -import { BadRequestError } from '@/ResponseHelper'; import type { MessageEventBusDestinationWebhookOptions, MessageEventBusDestinationOptions, @@ -20,6 +19,7 @@ import type { MessageEventBusDestination } from './MessageEventBusDestination/Me import type { DeleteResult } from 'typeorm'; import { AuthenticatedRequest } from '@/requests'; import { logStreamingLicensedMiddleware } from './middleware/logStreamingEnabled.middleware.ee'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; // ---------------------------------------- // TypeGuards diff --git a/packages/cli/src/eventbus/eventBus.controller.ts b/packages/cli/src/eventbus/eventBus.controller.ts index d17fdf884a..6fecc8bf69 100644 --- a/packages/cli/src/eventbus/eventBus.controller.ts +++ b/packages/cli/src/eventbus/eventBus.controller.ts @@ -9,13 +9,13 @@ import type { EventMessageTypes, FailedEventSummary } from './EventMessageClasse import { eventNamesAll } from './EventMessageClasses'; import type { EventMessageAuditOptions } from './EventMessageClasses/EventMessageAudit'; import { EventMessageAudit } from './EventMessageClasses/EventMessageAudit'; -import { BadRequestError } from '@/ResponseHelper'; import type { IRunExecutionData } from 'n8n-workflow'; import { EventMessageTypeNames } from 'n8n-workflow'; import type { EventMessageNodeOptions } from './EventMessageClasses/EventMessageNode'; import { EventMessageNode } from './EventMessageClasses/EventMessageNode'; import { recoverExecutionDataFromEventLogMessages } from './MessageEventBus/recoverEvents'; import { RestController, Get, Post, Authorized } from '@/decorators'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; // ---------------------------------------- // TypeGuards diff --git a/packages/cli/src/executions/executions.service.ts b/packages/cli/src/executions/executions.service.ts index 04479b0539..006481b465 100644 --- a/packages/cli/src/executions/executions.service.ts +++ b/packages/cli/src/executions/executions.service.ts @@ -15,7 +15,6 @@ import type { import { NodeTypes } from '@/NodeTypes'; import { Queue } from '@/Queue'; import type { ExecutionRequest } from '@/requests'; -import * as ResponseHelper from '@/ResponseHelper'; import { getSharedWorkflowIds } from '@/WorkflowHelpers'; import { WorkflowRunner } from '@/WorkflowRunner'; import * as GenericHelpers from '@/GenericHelpers'; @@ -24,6 +23,8 @@ import { getStatusUsingPreviousExecutionStatusMethod } from './executionHelpers' import { ExecutionRepository } from '@db/repositories/execution.repository'; import { WorkflowRepository } from '@db/repositories/workflow.repository'; import { Logger } from '@/Logger'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; export interface IGetExecutionsQueryFilter { id?: FindOperator | string; @@ -114,9 +115,7 @@ export class ExecutionsService { userId: req.user.id, filter: req.query.filter, }); - throw new ResponseHelper.InternalServerError( - 'Parameter "filter" contained invalid JSON string.', - ); + throw new InternalServerError('Parameter "filter" contained invalid JSON string.'); } } @@ -231,9 +230,7 @@ export class ExecutionsService { executionId, }, ); - throw new ResponseHelper.NotFoundError( - `The execution with the ID "${executionId}" does not exist.`, - ); + throw new NotFoundError(`The execution with the ID "${executionId}" does not exist.`); } if (execution.finished) { @@ -351,9 +348,7 @@ export class ExecutionsService { requestFilters = requestFiltersRaw as IGetExecutionsQueryFilter; } } catch (error) { - throw new ResponseHelper.InternalServerError( - 'Parameter "filter" contained invalid JSON string.', - ); + throw new InternalServerError('Parameter "filter" contained invalid JSON string.'); } } diff --git a/packages/cli/src/license/license.controller.ts b/packages/cli/src/license/license.controller.ts index 0aa27b74bb..b907def729 100644 --- a/packages/cli/src/license/license.controller.ts +++ b/packages/cli/src/license/license.controller.ts @@ -8,6 +8,8 @@ import { LicenseService } from './License.service'; import { License } from '@/License'; import type { AuthenticatedRequest, LicenseRequest } from '@/requests'; import { InternalHooks } from '@/InternalHooks'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; export const licenseController = express.Router(); @@ -24,9 +26,7 @@ licenseController.use((req: AuthenticatedRequest, res, next) => { }); ResponseHelper.sendErrorResponse( res, - new ResponseHelper.UnauthorizedError( - 'Only an instance owner may activate or renew a license', - ), + new UnauthorizedError('Only an instance owner may activate or renew a license'), ); return; } @@ -85,7 +85,7 @@ licenseController.post( Container.get(Logger).error(message, { stack: error.stack ?? 'n/a' }); } - throw new ResponseHelper.BadRequestError(message); + throw new BadRequestError(message); } // Return the read data, plus the management JWT @@ -113,7 +113,7 @@ licenseController.post( // not awaiting so as not to make the endpoint hang void Container.get(InternalHooks).onLicenseRenewAttempt({ success: false }); if (error instanceof Error) { - throw new ResponseHelper.BadRequestError(error.message); + throw new BadRequestError(error.message); } } diff --git a/packages/cli/src/middlewares/bodyParser.ts b/packages/cli/src/middlewares/bodyParser.ts index 2f2efe709e..f7ee9615b4 100644 --- a/packages/cli/src/middlewares/bodyParser.ts +++ b/packages/cli/src/middlewares/bodyParser.ts @@ -7,7 +7,7 @@ import { Parser as XmlParser } from 'xml2js'; import { parseIncomingMessage } from 'n8n-core'; import { jsonParse } from 'n8n-workflow'; import config from '@/config'; -import { UnprocessableRequestError } from '@/ResponseHelper'; +import { UnprocessableRequestError } from '@/errors/response-errors/unprocessable.error'; const xmlParser = new XmlParser({ async: true, diff --git a/packages/cli/src/services/role.service.ts b/packages/cli/src/services/role.service.ts index 8be8350dcc..e105232235 100644 --- a/packages/cli/src/services/role.service.ts +++ b/packages/cli/src/services/role.service.ts @@ -3,8 +3,7 @@ import { RoleRepository } from '@db/repositories/role.repository'; import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository'; import { CacheService } from './cache.service'; import type { RoleNames, RoleScopes } from '@db/entities/Role'; - -class InvalidRoleError extends Error {} +import { InvalidRoleError } from '@/errors/invalid-role.error'; @Service() export class RoleService { diff --git a/packages/cli/src/services/user.service.ts b/packages/cli/src/services/user.service.ts index 3b3a649731..5f6e39625c 100644 --- a/packages/cli/src/services/user.service.ts +++ b/packages/cli/src/services/user.service.ts @@ -15,8 +15,8 @@ import { UserManagementMailer } from '@/UserManagement/email'; import { InternalHooks } from '@/InternalHooks'; import { RoleService } from '@/services/role.service'; import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow'; -import { InternalServerError } from '@/ResponseHelper'; import type { UserRequest } from '@/requests'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; @Service() export class UserService { diff --git a/packages/cli/src/sso/saml/routes/saml.controller.ee.ts b/packages/cli/src/sso/saml/routes/saml.controller.ee.ts index 67d441a37c..aa5f98dd67 100644 --- a/packages/cli/src/sso/saml/routes/saml.controller.ee.ts +++ b/packages/cli/src/sso/saml/routes/saml.controller.ee.ts @@ -9,7 +9,6 @@ import { } from '../middleware/samlEnabledMiddleware'; import { SamlService } from '../saml.service.ee'; import { SamlConfiguration } from '../types/requests'; -import { AuthError, BadRequestError } from '@/ResponseHelper'; import { getInitSSOFormView } from '../views/initSsoPost'; import { issueCookie } from '@/auth/jwt'; import { validate } from 'class-validator'; @@ -27,6 +26,8 @@ import { getSamlConnectionTestFailedView } from '../views/samlConnectionTestFail import { InternalHooks } from '@/InternalHooks'; import url from 'url'; import querystring from 'querystring'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { AuthError } from '@/errors/response-errors/auth.error'; @Service() @RestController('/sso/saml') diff --git a/packages/cli/src/sso/saml/saml.service.ee.ts b/packages/cli/src/sso/saml/saml.service.ee.ts index 354686cbb3..fc170ff2ca 100644 --- a/packages/cli/src/sso/saml/saml.service.ee.ts +++ b/packages/cli/src/sso/saml/saml.service.ee.ts @@ -2,7 +2,6 @@ import type express from 'express'; import Container, { Service } from 'typedi'; import type { User } from '@db/entities/User'; import { jsonParse } from 'n8n-workflow'; -import { AuthError, BadRequestError } from '@/ResponseHelper'; import { getServiceProviderInstance } from './serviceProvider.ee'; import type { SamlUserAttributes } from './types/samlUserAttributes'; import { isSsoJustInTimeProvisioningEnabled } from '../ssoHelpers'; @@ -29,6 +28,8 @@ import { getInstanceBaseUrl } from '@/UserManagement/UserManagementHelper'; import { Logger } from '@/Logger'; import { UserRepository } from '@db/repositories/user.repository'; import { SettingsRepository } from '@db/repositories/settings.repository'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { AuthError } from '@/errors/response-errors/auth.error'; @Service() export class SamlService { diff --git a/packages/cli/src/sso/saml/samlHelpers.ts b/packages/cli/src/sso/saml/samlHelpers.ts index d55b751be7..5b3f28c25e 100644 --- a/packages/cli/src/sso/saml/samlHelpers.ts +++ b/packages/cli/src/sso/saml/samlHelpers.ts @@ -3,7 +3,6 @@ import config from '@/config'; import { AuthIdentity } from '@db/entities/AuthIdentity'; import { User } from '@db/entities/User'; import { License } from '@/License'; -import { AuthError, InternalServerError } from '@/ResponseHelper'; import { hashPassword } from '@/UserManagement/UserManagementHelper'; import type { SamlPreferences } from './types/samlPreferences'; import type { SamlUserAttributes } from './types/samlUserAttributes'; @@ -21,6 +20,9 @@ import type { SamlConfiguration } from './types/requests'; import { RoleService } from '@/services/role.service'; import { UserRepository } from '@db/repositories/user.repository'; import { AuthIdentityRepository } from '@db/repositories/authIdentity.repository'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; +import { AuthError } from '@/errors/response-errors/auth.error'; + /** * Check whether the SAML feature is licensed and enabled in the instance */ diff --git a/packages/cli/src/workflows/workflowHistory/workflowHistory.controller.ee.ts b/packages/cli/src/workflows/workflowHistory/workflowHistory.controller.ee.ts index 89e78a4d15..c5f7159a14 100644 --- a/packages/cli/src/workflows/workflowHistory/workflowHistory.controller.ee.ts +++ b/packages/cli/src/workflows/workflowHistory/workflowHistory.controller.ee.ts @@ -1,15 +1,14 @@ import { Authorized, RestController, Get, Middleware } from '@/decorators'; import { WorkflowHistoryRequest } from '@/requests'; import { Service } from 'typedi'; -import { - HistoryVersionNotFoundError, - SharedWorkflowNotFoundError, - WorkflowHistoryService, -} from './workflowHistory.service.ee'; +import { WorkflowHistoryService } from './workflowHistory.service.ee'; import { Request, Response, NextFunction } from 'express'; import { isWorkflowHistoryEnabled, isWorkflowHistoryLicensed } from './workflowHistoryHelper.ee'; -import { NotFoundError } from '@/ResponseHelper'; + import { paginationListQueryMiddleware } from '@/middlewares/listQuery/pagination'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { SharedWorkflowNotFoundError } from '@/errors/shared-workflow-not-found.error'; +import { WorkflowHistoryVersionNotFoundError } from '@/errors/workflow-history-version-not-found.error'; const DEFAULT_TAKE = 20; @@ -67,7 +66,7 @@ export class WorkflowHistoryController { } catch (e) { if (e instanceof SharedWorkflowNotFoundError) { throw new NotFoundError('Could not find workflow'); - } else if (e instanceof HistoryVersionNotFoundError) { + } else if (e instanceof WorkflowHistoryVersionNotFoundError) { throw new NotFoundError('Could not find version'); } throw e; diff --git a/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts b/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts index 89b0698748..84cb05f9a6 100644 --- a/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts +++ b/packages/cli/src/workflows/workflowHistory/workflowHistory.service.ee.ts @@ -7,9 +7,8 @@ import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repo import { Service } from 'typedi'; import { isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee'; import { Logger } from '@/Logger'; - -export class SharedWorkflowNotFoundError extends Error {} -export class HistoryVersionNotFoundError extends Error {} +import { SharedWorkflowNotFoundError } from '@/errors/shared-workflow-not-found.error'; +import { WorkflowHistoryVersionNotFoundError } from '@/errors/workflow-history-version-not-found.error'; @Service() export class WorkflowHistoryService { @@ -36,7 +35,7 @@ export class WorkflowHistoryService { ): Promise>> { const sharedWorkflow = await this.getSharedWorkflow(user, workflowId); if (!sharedWorkflow) { - throw new SharedWorkflowNotFoundError(); + throw new SharedWorkflowNotFoundError(''); } return this.workflowHistoryRepository.find({ where: { @@ -52,7 +51,7 @@ export class WorkflowHistoryService { async getVersion(user: User, workflowId: string, versionId: string): Promise { const sharedWorkflow = await this.getSharedWorkflow(user, workflowId); if (!sharedWorkflow) { - throw new SharedWorkflowNotFoundError(); + throw new SharedWorkflowNotFoundError(''); } const hist = await this.workflowHistoryRepository.findOne({ where: { @@ -61,7 +60,7 @@ export class WorkflowHistoryService { }, }); if (!hist) { - throw new HistoryVersionNotFoundError(); + throw new WorkflowHistoryVersionNotFoundError(''); } return hist; } diff --git a/packages/cli/src/workflows/workflows.controller.ee.ts b/packages/cli/src/workflows/workflows.controller.ee.ts index a5c60ac043..6fd345060f 100644 --- a/packages/cli/src/workflows/workflows.controller.ee.ts +++ b/packages/cli/src/workflows/workflows.controller.ee.ts @@ -23,6 +23,10 @@ import { listQueryMiddleware } from '@/middlewares'; import { TagService } from '@/services/tag.service'; import { Logger } from '@/Logger'; import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee'; +import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; export const EEWorkflowController = express.Router(); @@ -52,13 +56,13 @@ EEWorkflowController.put( !Array.isArray(shareWithIds) || !shareWithIds.every((userId) => typeof userId === 'string') ) { - throw new ResponseHelper.BadRequestError('Bad request'); + throw new BadRequestError('Bad request'); } const { ownsWorkflow, workflow } = await EEWorkflows.isOwned(req.user, workflowId); if (!ownsWorkflow || !workflow) { - throw new ResponseHelper.UnauthorizedError('Forbidden'); + throw new UnauthorizedError('Forbidden'); } let newShareeIds: string[] = []; @@ -101,13 +105,13 @@ EEWorkflowController.get( const workflow = await EEWorkflows.get({ id: workflowId }, { relations }); if (!workflow) { - throw new ResponseHelper.NotFoundError(`Workflow with ID "${workflowId}" does not exist`); + throw new NotFoundError(`Workflow with ID "${workflowId}" does not exist`); } const userSharing = workflow.shared?.find((shared) => shared.user.id === req.user.id); if (!userSharing && req.user.globalRole.name !== 'owner') { - throw new ResponseHelper.UnauthorizedError( + throw new UnauthorizedError( 'You do not have permission to access this workflow. Ask the owner to share it with you', ); } @@ -156,7 +160,7 @@ EEWorkflowController.post( try { EEWorkflows.validateCredentialPermissionsToUser(newWorkflow, allCredentials); } catch (error) { - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( 'The workflow you are trying to save contains credentials that are not shared with you', ); } @@ -181,7 +185,7 @@ EEWorkflowController.post( if (!savedWorkflow) { Container.get(Logger).error('Failed to create workflow', { userId: req.user.id }); - throw new ResponseHelper.InternalServerError( + throw new InternalServerError( 'An error occurred while saving your workflow. Please try again.', ); } diff --git a/packages/cli/src/workflows/workflows.controller.ts b/packages/cli/src/workflows/workflows.controller.ts index fc187b9b84..588a1040d3 100644 --- a/packages/cli/src/workflows/workflows.controller.ts +++ b/packages/cli/src/workflows/workflows.controller.ts @@ -27,6 +27,9 @@ import { TagService } from '@/services/tag.service'; import { WorkflowHistoryService } from './workflowHistory/workflowHistory.service.ee'; import { Logger } from '@/Logger'; import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; +import { InternalServerError } from '@/errors/response-errors/internal-server.error'; export const workflowsController = express.Router(); workflowsController.use('/', EEWorkflowController); @@ -84,7 +87,7 @@ workflowsController.post( if (!savedWorkflow) { Container.get(Logger).error('Failed to create workflow', { userId: req.user.id }); - throw new ResponseHelper.InternalServerError('Failed to save workflow'); + throw new InternalServerError('Failed to save workflow'); } await Container.get(WorkflowHistoryService).saveVersion( @@ -160,10 +163,10 @@ workflowsController.get( '/from-url', ResponseHelper.send(async (req: express.Request): Promise => { if (req.query.url === undefined) { - throw new ResponseHelper.BadRequestError('The parameter "url" is missing!'); + throw new BadRequestError('The parameter "url" is missing!'); } if (!/^http[s]?:\/\/.*\.json$/i.exec(req.query.url as string)) { - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( 'The parameter "url" is not valid! It does not seem to be a URL pointing to a n8n workflow JSON file.', ); } @@ -172,7 +175,7 @@ workflowsController.get( const { data } = await axios.get(req.query.url as string); workflowData = data; } catch (error) { - throw new ResponseHelper.BadRequestError('The URL does not point to valid JSON file!'); + throw new BadRequestError('The URL does not point to valid JSON file!'); } // Do a very basic check if it is really a n8n-workflow-json @@ -183,7 +186,7 @@ workflowsController.get( typeof workflowData.connections !== 'object' || Array.isArray(workflowData.connections) ) { - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( 'The data in the file does not seem to be a n8n workflow JSON file!', ); } @@ -221,7 +224,7 @@ workflowsController.get( workflowId, userId: req.user.id, }); - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( 'Could not load the workflow - you can only access workflows owned by you', ); } @@ -271,7 +274,7 @@ workflowsController.delete( workflowId, userId: req.user.id, }); - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( 'Could not delete the workflow - you can only remove workflows owned by you', ); } diff --git a/packages/cli/src/workflows/workflows.services.ee.ts b/packages/cli/src/workflows/workflows.services.ee.ts index 04448e76cb..f865e2f382 100644 --- a/packages/cli/src/workflows/workflows.services.ee.ts +++ b/packages/cli/src/workflows/workflows.services.ee.ts @@ -1,6 +1,5 @@ import type { DeleteResult, EntityManager } from 'typeorm'; import { In, Not } from 'typeorm'; -import * as ResponseHelper from '@/ResponseHelper'; import * as WorkflowHelpers from '@/WorkflowHelpers'; import { SharedWorkflow } from '@db/entities/SharedWorkflow'; import type { User } from '@db/entities/User'; @@ -17,6 +16,8 @@ import { RoleService } from '@/services/role.service'; import Container from 'typedi'; import type { CredentialsEntity } from '@db/entities/CredentialsEntity'; import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; export class EEWorkflowsService extends WorkflowsService { static async isOwned( @@ -170,7 +171,7 @@ export class EEWorkflowsService extends WorkflowsService { const previousVersion = await EEWorkflowsService.get({ id: workflowId }); if (!previousVersion) { - throw new ResponseHelper.NotFoundError('Workflow not found'); + throw new NotFoundError('Workflow not found'); } const allCredentials = await CredentialsService.getMany(user); @@ -183,9 +184,9 @@ export class EEWorkflowsService extends WorkflowsService { ); } catch (error) { if (error instanceof NodeOperationError) { - throw new ResponseHelper.BadRequestError(error.message); + throw new BadRequestError(error.message); } - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( 'Invalid workflow credentials - make sure you have access to all credentials and try again.', ); } diff --git a/packages/cli/src/workflows/workflows.services.ts b/packages/cli/src/workflows/workflows.services.ts index 162ad2aaf5..40ad9cede9 100644 --- a/packages/cli/src/workflows/workflows.services.ts +++ b/packages/cli/src/workflows/workflows.services.ts @@ -6,7 +6,6 @@ import { In, Like } from 'typeorm'; import pick from 'lodash/pick'; import { v4 as uuid } from 'uuid'; import { ActiveWorkflowRunner } from '@/ActiveWorkflowRunner'; -import * as ResponseHelper from '@/ResponseHelper'; import * as WorkflowHelpers from '@/WorkflowHelpers'; import config from '@/config'; import type { SharedWorkflow } from '@db/entities/SharedWorkflow'; @@ -34,6 +33,8 @@ import { MultiMainSetup } from '@/services/orchestration/main/MultiMainSetup.ee' import { SharedWorkflowRepository } from '@db/repositories/sharedWorkflow.repository'; import { WorkflowTagMappingRepository } from '@db/repositories/workflowTagMapping.repository'; import { ExecutionRepository } from '@db/repositories/execution.repository'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; export class WorkflowsService { static async getSharing( @@ -208,7 +209,7 @@ export class WorkflowsService { workflowId, userId: user.id, }); - throw new ResponseHelper.NotFoundError( + throw new NotFoundError( 'You do not have permission to update this workflow. Ask the owner to share it with you.', ); } @@ -220,7 +221,7 @@ export class WorkflowsService { workflow.versionId !== '' && workflow.versionId !== shared.workflow.versionId ) { - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( 'Your most recent changes may be lost, because someone else just updated this workflow. Open this workflow in a new tab to see those new updates.', 100, ); @@ -330,7 +331,7 @@ export class WorkflowsService { }); if (updatedWorkflow === null) { - throw new ResponseHelper.BadRequestError( + throw new BadRequestError( `Workflow with ID "${workflowId}" could not be found to be updated.`, ); } @@ -368,7 +369,7 @@ export class WorkflowsService { message = message ?? (error as Error).message; // Now return the original error for UI to display - throw new ResponseHelper.BadRequestError(message); + throw new BadRequestError(message); } } diff --git a/packages/cli/test/unit/controllers/me.controller.test.ts b/packages/cli/test/unit/controllers/me.controller.test.ts index 1ea28820ff..c27f071102 100644 --- a/packages/cli/test/unit/controllers/me.controller.test.ts +++ b/packages/cli/test/unit/controllers/me.controller.test.ts @@ -6,7 +6,6 @@ import type { PublicUser } from '@/Interfaces'; import type { User } from '@db/entities/User'; import { MeController } from '@/controllers/me.controller'; import { AUTH_COOKIE_NAME } from '@/constants'; -import { BadRequestError } from '@/ResponseHelper'; import type { AuthenticatedRequest, MeRequest } from '@/requests'; import { UserService } from '@/services/user.service'; import { ExternalHooks } from '@/ExternalHooks'; @@ -14,6 +13,7 @@ import { InternalHooks } from '@/InternalHooks'; import { License } from '@/License'; import { badPasswords } from '../shared/testData'; import { mockInstance } from '../../shared/mocking'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; describe('MeController', () => { const externalHooks = mockInstance(ExternalHooks); diff --git a/packages/cli/test/unit/controllers/oAuth1Credential.controller.test.ts b/packages/cli/test/unit/controllers/oAuth1Credential.controller.test.ts index fb278f1616..0ea169261c 100644 --- a/packages/cli/test/unit/controllers/oAuth1Credential.controller.test.ts +++ b/packages/cli/test/unit/controllers/oAuth1Credential.controller.test.ts @@ -7,7 +7,6 @@ import { OAuth1CredentialController } from '@/controllers/oauth/oAuth1Credential import type { CredentialsEntity } from '@db/entities/CredentialsEntity'; import type { User } from '@db/entities/User'; import type { OAuthRequest } from '@/requests'; -import { BadRequestError, NotFoundError } from '@/ResponseHelper'; import { CredentialsRepository } from '@db/repositories/credentials.repository'; import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository'; import { ExternalHooks } from '@/ExternalHooks'; @@ -17,6 +16,8 @@ import { SecretsHelper } from '@/SecretsHelpers'; import { CredentialsHelper } from '@/CredentialsHelper'; import { mockInstance } from '../../shared/mocking'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; describe('OAuth1CredentialController', () => { mockInstance(Logger); diff --git a/packages/cli/test/unit/controllers/oAuth2Credential.controller.test.ts b/packages/cli/test/unit/controllers/oAuth2Credential.controller.test.ts index 72c9d8bfe2..3498f6a532 100644 --- a/packages/cli/test/unit/controllers/oAuth2Credential.controller.test.ts +++ b/packages/cli/test/unit/controllers/oAuth2Credential.controller.test.ts @@ -9,7 +9,6 @@ import { OAuth2CredentialController } from '@/controllers/oauth/oAuth2Credential import type { CredentialsEntity } from '@db/entities/CredentialsEntity'; import type { User } from '@db/entities/User'; import type { OAuthRequest } from '@/requests'; -import { BadRequestError, NotFoundError } from '@/ResponseHelper'; import { CredentialsRepository } from '@db/repositories/credentials.repository'; import { SharedCredentialsRepository } from '@db/repositories/sharedCredentials.repository'; import { ExternalHooks } from '@/ExternalHooks'; @@ -19,6 +18,8 @@ import { SecretsHelper } from '@/SecretsHelpers'; import { CredentialsHelper } from '@/CredentialsHelper'; import { mockInstance } from '../../shared/mocking'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; +import { NotFoundError } from '@/errors/response-errors/not-found.error'; describe('OAuth2CredentialController', () => { mockInstance(Logger); diff --git a/packages/cli/test/unit/controllers/owner.controller.test.ts b/packages/cli/test/unit/controllers/owner.controller.test.ts index 099f3bf47a..1f45e54bb7 100644 --- a/packages/cli/test/unit/controllers/owner.controller.test.ts +++ b/packages/cli/test/unit/controllers/owner.controller.test.ts @@ -5,7 +5,6 @@ import type { IInternalHooksClass } from '@/Interfaces'; import type { User } from '@db/entities/User'; import type { SettingsRepository } from '@db/repositories/settings.repository'; import type { Config } from '@/config'; -import { BadRequestError } from '@/ResponseHelper'; import type { OwnerRequest } from '@/requests'; import { OwnerController } from '@/controllers/owner.controller'; import { AUTH_COOKIE_NAME } from '@/constants'; @@ -14,6 +13,7 @@ import { License } from '@/License'; import { mockInstance } from '../../shared/mocking'; import { badPasswords } from '../shared/testData'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; describe('OwnerController', () => { const config = mock(); diff --git a/packages/cli/test/unit/controllers/translation.controller.test.ts b/packages/cli/test/unit/controllers/translation.controller.test.ts index e23f196d0d..3abaf7f933 100644 --- a/packages/cli/test/unit/controllers/translation.controller.test.ts +++ b/packages/cli/test/unit/controllers/translation.controller.test.ts @@ -6,7 +6,7 @@ import { TranslationController, CREDENTIAL_TRANSLATIONS_DIR, } from '@/controllers/translation.controller'; -import { BadRequestError } from '@/ResponseHelper'; +import { BadRequestError } from '@/errors/response-errors/bad-request.error'; describe('TranslationController', () => { const config = mock();