n8n
Version:
n8n Workflow Automation Tool
136 lines • 5.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HTTP_METHODS = void 0;
exports.resolveRouteArgs = resolveRouteArgs;
exports.resolveSuccessStatus = resolveSuccessStatus;
exports.apiKeyScopesSatisfy = apiKeyScopesSatisfy;
exports.scopesInRequirement = scopesInRequirement;
exports.scopeRequirementFromString = scopeRequirementFromString;
exports.scopeRequirementToString = scopeRequirementToString;
exports.toOpenApiPathTemplate = toOpenApiPathTemplate;
exports.resolvePublicApiRoutes = resolvePublicApiRoutes;
const decorators_1 = require("@n8n/decorators");
const di_1 = require("@n8n/di");
const n8n_workflow_1 = require("n8n-workflow");
exports.HTTP_METHODS = [
'get',
'post',
'put',
'patch',
'delete',
'options',
'head',
'trace',
];
function isDtoArg(arg, type) {
return arg.type === type;
}
function resolveRouteArgs(controllerClass, handlerName, args) {
const argTypes = Reflect.getMetadata('design:paramtypes', controllerClass.prototype, handlerName);
const resolved = [];
let sawDecoratedArg = false;
const paramCount = Math.max(args.length, argTypes?.length ?? 0);
for (let index = 0; index < paramCount; index++) {
const arg = args[index];
if (!arg) {
if (sawDecoratedArg) {
throw new n8n_workflow_1.UnexpectedError(`Public API route ${controllerClass.name}.${handlerName} has an undecorated parameter ` +
`at index ${index}, after an already-decorated one. Every parameter after the first ` +
'@Param/@Body/@Query must also be decorated, or a later argument would silently bind ' +
'to the wrong parameter.');
}
continue;
}
sawDecoratedArg = true;
if (arg.type === 'param') {
resolved.push(arg);
continue;
}
const paramType = argTypes?.[index];
if (!paramType || !('safeParse' in paramType)) {
throw new n8n_workflow_1.UnexpectedError(`Public API route ${controllerClass.name}.${handlerName} is missing a Zod DTO for @${arg.type}`);
}
resolved.push({ type: arg.type, dto: paramType });
}
return resolved;
}
function resolveSuccessStatus(controllerName, handlerName, successStatus) {
if (successStatus === undefined) {
throw new n8n_workflow_1.UnexpectedError(`Public API route ${controllerName}.${handlerName} does not declare a success status. Add ` +
'`@ApiResponse(200, SomeDto)` if it returns a body, or `@ApiResponse(204)` if it does not.');
}
return successStatus;
}
function apiKeyScopesSatisfy(granted, requirement) {
if (!granted)
return false;
if (typeof requirement === 'string') {
return granted.includes(requirement);
}
if ('anyOf' in requirement) {
return requirement.anyOf.some((scope) => granted.includes(scope));
}
return requirement.allOf.every((scope) => granted.includes(scope));
}
function scopesInRequirement(requirement) {
if (typeof requirement === 'string')
return [requirement];
return 'anyOf' in requirement ? requirement.anyOf : requirement.allOf;
}
function scopeRequirementFromString(serialized) {
const scopes = serialized
.split(',')
.map((scope) => scope.trim())
.filter(Boolean);
return scopes.length === 1 ? scopes[0] : { anyOf: scopes };
}
function scopeRequirementToString(requirement) {
if (typeof requirement === 'string') {
return requirement;
}
if ('anyOf' in requirement) {
return requirement.anyOf.join(',');
}
return requirement.allOf.join(',');
}
function toOpenApiPathTemplate(path) {
return path.replace(/:([A-Za-z0-9_]+)/g, '{$1}');
}
function resolvePublicApiRoutes() {
const metadata = di_1.Container.get(decorators_1.ControllerRegistryMetadata);
const resolved = [];
for (const controllerClass of metadata.controllerClasses) {
const controllerMetadata = metadata.getControllerMetadata(controllerClass);
if (!controllerMetadata.isPublicApi) {
continue;
}
const prefix = controllerMetadata.basePath.replace(/\/+/g, '/').replace(/\/$/, '');
for (const [handlerName, route] of controllerMetadata.routes) {
const args = resolveRouteArgs(controllerClass, handlerName, route.args);
const requestBodyDto = args.find((arg) => isDtoArg(arg, 'body'))?.dto;
const requestQueryDto = args.find((arg) => isDtoArg(arg, 'query'))?.dto;
const joined = `${prefix}${route.path}`.replace(/\/+/g, '/');
const path = joined.length > 1 ? joined.replace(/\/$/, '') : joined || '/';
resolved.push({
controllerClass,
controllerName: controllerClass.name,
handlerName,
method: route.method,
path,
args,
requestBodyDto,
requestQueryDto,
responseDto: route.responseDto,
successStatus: resolveSuccessStatus(controllerClass.name, handlerName, route.successStatus),
apiKeyScope: route.apiKeyScope,
summary: route.summary,
description: route.description,
tags: route.tags,
errorResponses: route.errorResponses,
deprecated: route.deprecated,
});
}
}
return resolved;
}
//# sourceMappingURL=public-api-route-resolver.js.map