UNPKG

@opra/nestjs-http

Version:
168 lines (167 loc) 7.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpraHttpNestjsAdapter = void 0; const tslib_1 = require("tslib"); const node_path_1 = tslib_1.__importDefault(require("node:path")); const objects_1 = require("@jsopen/objects"); const common_1 = require("@nestjs/common"); const common_2 = require("@opra/common"); const http_1 = require("@opra/http"); const nestjs_1 = require("@opra/nestjs"); const ts_gems_1 = require("ts-gems"); class OpraHttpNestjsAdapter extends http_1.HttpAdapter { constructor(options) { super(options); this.nestControllers = []; this._addRootController(options.schemaIsPublic); if (options.controllers) { for (const c of options.controllers) { this._addToNestControllers(c, this.basePath, []); } } } async close() { // } _addRootController(isPublic) { const _this = this; let RootController = class RootController { schema(_req, next) { _this.handler.sendDocumentSchema(_req.opraContext).catch(() => next()); } }; tslib_1.__decorate([ (0, common_1.Get)('/\\$schema'), tslib_1.__param(0, (0, common_1.Req)()), tslib_1.__param(1, (0, common_1.Next)()), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object, Function]), tslib_1.__metadata("design:returntype", void 0) ], RootController.prototype, "schema", null); RootController = tslib_1.__decorate([ (0, common_1.Controller)({ path: this.basePath, }) ], RootController); if (isPublic) { (0, nestjs_1.Public)()(RootController.prototype, 'schema', Object.getOwnPropertyDescriptor(RootController.prototype, 'schema')); } this.nestControllers.push(RootController); } _addToNestControllers(sourceClass, currentPath, parentTree) { const metadata = Reflect.getMetadata(common_2.HTTP_CONTROLLER_METADATA, sourceClass); if (!metadata) return; /** Create a new controller class */ const newClass = { [sourceClass.name]: class extends sourceClass { }, }[sourceClass.name]; /** Copy metadata keys from source class to new one */ nestjs_1.OpraNestUtils.copyDecoratorMetadata(newClass, ...parentTree); (0, common_1.Controller)()(newClass); const newPath = metadata.path ? node_path_1.default.join(currentPath, metadata.path) : currentPath; const adapter = this; // adapter.logger = /** Disable default error handler. Errors will be handled by OpraExceptionFilter */ adapter.handler.onError = (context, error) => { throw error; }; this.nestControllers.push(newClass); let metadataKeys; if (metadata.operations) { for (const [k, v] of Object.entries(metadata.operations)) { const operationHandler = sourceClass.prototype[k]; Object.defineProperty(newClass.prototype, k, { writable: true, /** NestJS handler method */ async value(_req, _res) { _res.statusCode = 200; const api = adapter.document.api; const controller = api.findController(sourceClass); const operation = controller?.operations.get(k); const context = (0, ts_gems_1.asMutable)(_req.opraContext); if (!(context && operation && typeof operationHandler === 'function')) { throw new common_2.NotFoundError({ message: `No endpoint found for [${_req.method}]${_req.baseUrl}`, details: { path: _req.baseUrl, method: _req.method, }, }); } /** Configure the HttpContext */ context.operation = operation; context.controller = operation.owner; context.controllerInstance = this; context.operationHandler = operationHandler; /** Handle request */ await adapter.handler.handleRequest(context); }, }); /** Copy metadata keys from source function to new one */ metadataKeys = Reflect.getOwnMetadataKeys(operationHandler); const newFn = newClass.prototype[k]; for (const key of metadataKeys) { const m = Reflect.getMetadata(key, operationHandler); Reflect.defineMetadata(key, m, newFn); } (0, common_1.Req)()(newClass.prototype, k, 0); (0, common_1.Res)()(newClass.prototype, k, 1); const descriptor = Object.getOwnPropertyDescriptor(newClass.prototype, k); const operationPath = v.mergePath ? newPath + (v.path || '') : node_path_1.default.posix.join(newPath, v.path || ''); switch (v.method || 'GET') { case 'DELETE': /** Call @Delete decorator over new property */ (0, common_1.Delete)(operationPath)(newClass.prototype, k, descriptor); break; case 'GET': /** Call @Get decorator over new property */ (0, common_1.Get)(operationPath)(newClass.prototype, k, descriptor); break; case 'HEAD': /** Call @Head decorator over new property */ (0, common_1.Head)(operationPath)(newClass.prototype, k, descriptor); break; case 'OPTIONS': /** Call @Options decorator over new property */ (0, common_1.Options)(operationPath)(newClass.prototype, k, descriptor); break; case 'PATCH': /** Call @Patch decorator over new property */ (0, common_1.Patch)(operationPath)(newClass.prototype, k, descriptor); break; case 'POST': /** Call @Post decorator over new property */ (0, common_1.Post)(operationPath)(newClass.prototype, k, descriptor); break; case 'PUT': /** Call @Put decorator over new property */ (0, common_1.Put)(operationPath)(newClass.prototype, k, descriptor); break; case 'SEARCH': /** Call @Search decorator over new property */ (0, common_1.Search)(operationPath)(newClass.prototype, k, descriptor); break; default: break; } } } if (metadata.controllers) { for (const child of metadata.controllers) { if (!(0, objects_1.isConstructor)(child)) throw new TypeError('Controllers should be injectable a class'); this._addToNestControllers(child, newPath, [ ...parentTree, sourceClass, ]); } } } } exports.OpraHttpNestjsAdapter = OpraHttpNestjsAdapter;