@opra/nestjs 0.33.13 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/cjs/augmentation/http-controller.augmentation.js +16 -0
- package/cjs/index.js +2 -5
- package/cjs/interfaces/opra-module-options.interface.js +16 -1
- package/cjs/opra-http-core.module.js +52 -0
- package/cjs/opra-http.module.js +23 -0
- package/cjs/opra-nestjs-adapter.js +138 -0
- package/cjs/services/opra-exception-filter.js +14 -13
- package/esm/augmentation/http-controller.augmentation.js +16 -0
- package/esm/index.js +2 -5
- package/esm/interfaces/opra-module-options.interface.js +17 -1
- package/esm/opra-http-core.module.js +49 -0
- package/esm/opra-http.module.js +20 -0
- package/esm/opra-nestjs-adapter.js +133 -0
- package/esm/services/opra-exception-filter.js +13 -13
- package/package.json +10 -9
- package/types/augmentation/http-controller.augmentation.d.ts +0 -0
- package/types/index.d.ts +2 -5
- package/types/interfaces/opra-module-options.interface.d.ts +0 -25
- package/types/opra-http-core.module.d.ts +9 -0
- package/types/opra-http.module.d.ts +16 -0
- package/types/opra-nestjs-adapter.d.ts +10 -0
- package/types/services/opra-exception-filter.d.ts +6 -2
- package/cjs/augmentation/common-decorator.augmentation.js +0 -40
- package/cjs/constants.js +0 -9
- package/cjs/decorators/context.decorator.js +0 -10
- package/cjs/enums/handler-paramtype.enum.js +0 -9
- package/cjs/factories/opra-api.factory.js +0 -200
- package/cjs/factories/params.factory.js +0 -23
- package/cjs/opra-core.module.js +0 -140
- package/cjs/opra-module-ref.js +0 -16
- package/cjs/opra.module.js +0 -25
- package/cjs/services/nest-explorer.js +0 -38
- package/cjs/services/opra-api-loader.js +0 -85
- package/cjs/types.js +0 -2
- package/cjs/utils/class.utils.js +0 -25
- package/cjs/utils/function.utils.js +0 -37
- package/cjs/utils/param.utils.js +0 -24
- package/esm/augmentation/common-decorator.augmentation.js +0 -38
- package/esm/constants.js +0 -6
- package/esm/decorators/context.decorator.js +0 -7
- package/esm/enums/handler-paramtype.enum.js +0 -6
- package/esm/factories/opra-api.factory.js +0 -197
- package/esm/factories/params.factory.js +0 -19
- package/esm/opra-core.module.js +0 -137
- package/esm/opra-module-ref.js +0 -12
- package/esm/opra.module.js +0 -22
- package/esm/services/nest-explorer.js +0 -34
- package/esm/services/opra-api-loader.js +0 -81
- package/esm/types.js +0 -1
- package/esm/utils/class.utils.js +0 -19
- package/esm/utils/function.utils.js +0 -33
- package/esm/utils/param.utils.js +0 -20
- package/types/augmentation/common-decorator.augmentation.d.ts +0 -1
- package/types/constants.d.ts +0 -6
- package/types/decorators/context.decorator.d.ts +0 -5
- package/types/enums/handler-paramtype.enum.d.ts +0 -5
- package/types/factories/opra-api.factory.d.ts +0 -15
- package/types/factories/params.factory.d.ts +0 -4
- package/types/opra-core.module.d.ts +0 -17
- package/types/opra-module-ref.d.ts +0 -11
- package/types/opra.module.d.ts +0 -6
- package/types/services/nest-explorer.d.ts +0 -8
- package/types/services/opra-api-loader.d.ts +0 -19
- package/types/types.d.ts +0 -2
- package/types/utils/class.utils.d.ts +0 -4
- package/types/utils/function.utils.d.ts +0 -1
- package/types/utils/param.utils.d.ts +0 -8
package/README.md
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { Controller } from '@nestjs/common';
|
|
3
|
+
// import { DECORATOR, HttpController } from '@opra/common';
|
|
4
|
+
//
|
|
5
|
+
// /*
|
|
6
|
+
// Overrides HttpController decorator function to call NestJS's Controller() when decorator called
|
|
7
|
+
// */
|
|
8
|
+
// const oldHttpControllerDecorator = HttpController[DECORATOR];
|
|
9
|
+
// HttpController[DECORATOR] = function HttpControllerDecorator(options?: HttpController.Options) {
|
|
10
|
+
// const opraControllerDecorator = oldHttpControllerDecorator(options);
|
|
11
|
+
// const nestControllerDecorator = Controller({});
|
|
12
|
+
// return (target: Function) => {
|
|
13
|
+
// opraControllerDecorator(target);
|
|
14
|
+
// nestControllerDecorator(target);
|
|
15
|
+
// };
|
|
16
|
+
// };
|
package/cjs/index.js
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
require("reflect-metadata");
|
|
5
|
-
require("./augmentation/common-decorator.augmentation.js");
|
|
6
5
|
require("./augmentation/nestjs.augmentation.js");
|
|
7
|
-
tslib_1.__exportStar(require("./opra.module.js"), exports);
|
|
8
|
-
tslib_1.__exportStar(require("./
|
|
9
|
-
tslib_1.__exportStar(require("./interfaces/opra-module-options.interface.js"), exports);
|
|
10
|
-
tslib_1.__exportStar(require("./opra-module-ref.js"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./opra-http.module.js"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./opra-nestjs-adapter.js"), exports);
|
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
2
|
+
// import { ApiDocumentFactory } from '@opra/common';
|
|
3
|
+
// import { ExpressAdapter, HttpAdapter } from '@opra/core';
|
|
4
|
+
// export interface OpraModuleOptions extends HttpAdapter.Options {
|
|
5
|
+
// id?: any;
|
|
6
|
+
// document?: Partial<ApiDocumentFactory.InitArguments>;
|
|
7
|
+
//
|
|
8
|
+
// /**
|
|
9
|
+
// * @default true
|
|
10
|
+
// */
|
|
11
|
+
// useGlobalPrefix?: boolean;
|
|
12
|
+
// }
|
|
13
|
+
// export interface ExpressModuleOptions extends OpraModuleOptions, HttpAdapter.Options {}
|
|
14
|
+
// type OpraModuleOptionsWithoutId = Omit<OpraModuleOptions, 'id'>;
|
|
15
|
+
// export interface OpraModuleOptionsFactory {
|
|
16
|
+
// createOptions(): Promise<OpraModuleOptionsWithoutId> | OpraModuleOptionsWithoutId;
|
|
17
|
+
// }
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var OpraHttpCoreModule_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.OpraHttpCoreModule = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const ts_gems_1 = require("ts-gems");
|
|
7
|
+
const common_1 = require("@nestjs/common");
|
|
8
|
+
const common_2 = require("@opra/common");
|
|
9
|
+
const opra_nestjs_adapter_js_1 = require("./opra-nestjs-adapter.js");
|
|
10
|
+
let OpraHttpCoreModule = OpraHttpCoreModule_1 = class OpraHttpCoreModule {
|
|
11
|
+
constructor(opraAdapter) {
|
|
12
|
+
this.opraAdapter = opraAdapter;
|
|
13
|
+
}
|
|
14
|
+
static forRoot(options) {
|
|
15
|
+
const opraAdapter = new opra_nestjs_adapter_js_1.OpraNestAdapter(options);
|
|
16
|
+
const token = options?.id || opra_nestjs_adapter_js_1.OpraNestAdapter;
|
|
17
|
+
const providers = [
|
|
18
|
+
...(options?.providers || []),
|
|
19
|
+
{
|
|
20
|
+
provide: opra_nestjs_adapter_js_1.OpraNestAdapter,
|
|
21
|
+
useFactory: async () => {
|
|
22
|
+
(0, ts_gems_1.asMutable)(opraAdapter).document = await common_2.ApiDocumentFactory.createDocument({
|
|
23
|
+
...options,
|
|
24
|
+
api: { protocol: 'http', name: options.name, controllers: opraAdapter.controllers },
|
|
25
|
+
});
|
|
26
|
+
return opraAdapter;
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
if (token !== opra_nestjs_adapter_js_1.OpraNestAdapter)
|
|
31
|
+
providers.push({
|
|
32
|
+
provide: token,
|
|
33
|
+
useValue: opraAdapter,
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
module: OpraHttpCoreModule_1,
|
|
37
|
+
controllers: opraAdapter.controllers,
|
|
38
|
+
imports: [...(options?.imports || [])],
|
|
39
|
+
exports: [...(options?.exports || []), token],
|
|
40
|
+
providers,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async onModuleDestroy() {
|
|
44
|
+
await this.opraAdapter.close();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.OpraHttpCoreModule = OpraHttpCoreModule;
|
|
48
|
+
exports.OpraHttpCoreModule = OpraHttpCoreModule = OpraHttpCoreModule_1 = tslib_1.__decorate([
|
|
49
|
+
(0, common_1.Module)({}),
|
|
50
|
+
(0, common_1.Global)(),
|
|
51
|
+
tslib_1.__metadata("design:paramtypes", [opra_nestjs_adapter_js_1.OpraNestAdapter])
|
|
52
|
+
], OpraHttpCoreModule);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var OpraHttpModule_1;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.OpraHttpModule = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const opra_http_core_module_js_1 = require("./opra-http-core.module.js");
|
|
8
|
+
let OpraHttpModule = OpraHttpModule_1 = class OpraHttpModule {
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param options
|
|
12
|
+
*/
|
|
13
|
+
static forRoot(options) {
|
|
14
|
+
return {
|
|
15
|
+
module: OpraHttpModule_1,
|
|
16
|
+
imports: [opra_http_core_module_js_1.OpraHttpCoreModule.forRoot(options)],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.OpraHttpModule = OpraHttpModule;
|
|
21
|
+
exports.OpraHttpModule = OpraHttpModule = OpraHttpModule_1 = tslib_1.__decorate([
|
|
22
|
+
(0, common_1.Module)({})
|
|
23
|
+
], OpraHttpModule);
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OpraNestAdapter = exports.kHandler = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
6
|
+
const common_1 = require("@nestjs/common");
|
|
7
|
+
const common_2 = require("@opra/common");
|
|
8
|
+
const core_1 = require("@opra/core");
|
|
9
|
+
const opra_exception_filter_js_1 = require("./services/opra-exception-filter.js");
|
|
10
|
+
exports.kHandler = Symbol.for('kHandler');
|
|
11
|
+
class OpraNestAdapter extends core_1.HttpAdapter {
|
|
12
|
+
constructor(options) {
|
|
13
|
+
super((function () {
|
|
14
|
+
const document = new common_2.ApiDocument();
|
|
15
|
+
document.api = new common_2.HttpApi(document);
|
|
16
|
+
return document;
|
|
17
|
+
})(), options);
|
|
18
|
+
// protected _platform: string = 'express';
|
|
19
|
+
this.controllers = [];
|
|
20
|
+
let basePath = options.basePath || '/';
|
|
21
|
+
if (!basePath.startsWith('/'))
|
|
22
|
+
basePath = '/' + basePath;
|
|
23
|
+
if (options.controllers)
|
|
24
|
+
options.controllers.forEach(c => this._createNestControllers(c, basePath));
|
|
25
|
+
}
|
|
26
|
+
async close() {
|
|
27
|
+
//
|
|
28
|
+
}
|
|
29
|
+
_createNestControllers(source, currentPath) {
|
|
30
|
+
const metadata = Reflect.getMetadata(common_2.HTTP_CONTROLLER_METADATA, source);
|
|
31
|
+
if (!metadata)
|
|
32
|
+
return;
|
|
33
|
+
const newClass = {
|
|
34
|
+
[source.name]: class extends source {
|
|
35
|
+
},
|
|
36
|
+
}[source.name];
|
|
37
|
+
const newPath = metadata.path ? path_1.default.join(currentPath, metadata.path) : currentPath;
|
|
38
|
+
const adapter = this;
|
|
39
|
+
/** Inject exception filter */
|
|
40
|
+
(0, common_1.UseFilters)(new opra_exception_filter_js_1.OpraExceptionFilter(adapter))(newClass);
|
|
41
|
+
(0, common_1.Controller)()(newClass);
|
|
42
|
+
this.controllers.push(newClass);
|
|
43
|
+
if (metadata.operations) {
|
|
44
|
+
for (const [k, v] of Object.entries(metadata.operations)) {
|
|
45
|
+
const operationHandler = source.prototype[k];
|
|
46
|
+
Object.defineProperty(newClass.prototype, k, {
|
|
47
|
+
writable: true,
|
|
48
|
+
/** NestJS handler method */
|
|
49
|
+
async value(_req, _res) {
|
|
50
|
+
const request = core_1.HttpIncoming.from(_req);
|
|
51
|
+
const response = core_1.HttpOutgoing.from(_res);
|
|
52
|
+
const api = adapter.document.api;
|
|
53
|
+
const controller = api.findController(newClass);
|
|
54
|
+
const operation = controller?.operations.get(k);
|
|
55
|
+
if (!(operation && typeof operationHandler === 'function'))
|
|
56
|
+
throw new common_2.NotFoundError({
|
|
57
|
+
message: `No endpoint found for [${request.method}]${request.baseUrl}`,
|
|
58
|
+
details: {
|
|
59
|
+
path: request.baseUrl,
|
|
60
|
+
method: request.method,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
/** Create the HttpContext */
|
|
64
|
+
const context = new core_1.HttpContext({
|
|
65
|
+
adapter,
|
|
66
|
+
platform: _req.route ? 'express' : 'fastify',
|
|
67
|
+
platformArgs: {
|
|
68
|
+
request,
|
|
69
|
+
response,
|
|
70
|
+
},
|
|
71
|
+
request,
|
|
72
|
+
response,
|
|
73
|
+
operation,
|
|
74
|
+
controller: operation.owner,
|
|
75
|
+
controllerInstance: this,
|
|
76
|
+
operationHandler,
|
|
77
|
+
});
|
|
78
|
+
/** Handle request */
|
|
79
|
+
await adapter[exports.kHandler].handleRequest(context);
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
(0, common_1.Req)()(newClass.prototype, k, 0);
|
|
83
|
+
(0, common_1.Res)()(newClass.prototype, k, 1);
|
|
84
|
+
/** Copy metadata keys from source function to new one */
|
|
85
|
+
const metadataKeys = Reflect.getOwnMetadataKeys(operationHandler);
|
|
86
|
+
const newFn = newClass.prototype[k];
|
|
87
|
+
for (const key of metadataKeys) {
|
|
88
|
+
const m = Reflect.getMetadata(key, operationHandler);
|
|
89
|
+
Reflect.defineMetadata(key, m, newFn);
|
|
90
|
+
}
|
|
91
|
+
const descriptor = Object.getOwnPropertyDescriptor(newClass.prototype, k);
|
|
92
|
+
const operationPath = newPath + (v.path || '');
|
|
93
|
+
switch (v.method || 'GET') {
|
|
94
|
+
case 'DELETE':
|
|
95
|
+
/** Call @Delete decorator over new property */
|
|
96
|
+
(0, common_1.Delete)(operationPath)(newClass.prototype, k, descriptor);
|
|
97
|
+
break;
|
|
98
|
+
case 'GET':
|
|
99
|
+
/** Call @Get decorator over new property */
|
|
100
|
+
(0, common_1.Get)(operationPath)(newClass.prototype, k, descriptor);
|
|
101
|
+
break;
|
|
102
|
+
case 'HEAD':
|
|
103
|
+
/** Call @Head decorator over new property */
|
|
104
|
+
(0, common_1.Head)(operationPath)(newClass.prototype, k, descriptor);
|
|
105
|
+
break;
|
|
106
|
+
case 'OPTIONS':
|
|
107
|
+
/** Call @Options decorator over new property */
|
|
108
|
+
(0, common_1.Options)(operationPath)(newClass.prototype, k, descriptor);
|
|
109
|
+
break;
|
|
110
|
+
case 'PATCH':
|
|
111
|
+
/** Call @Patch decorator over new property */
|
|
112
|
+
(0, common_1.Patch)(operationPath)(newClass.prototype, k, descriptor);
|
|
113
|
+
break;
|
|
114
|
+
case 'POST':
|
|
115
|
+
/** Call @Post decorator over new property */
|
|
116
|
+
(0, common_1.Post)(operationPath)(newClass.prototype, k, descriptor);
|
|
117
|
+
break;
|
|
118
|
+
case 'PUT':
|
|
119
|
+
/** Call @Put decorator over new property */
|
|
120
|
+
(0, common_1.Put)(operationPath)(newClass.prototype, k, descriptor);
|
|
121
|
+
break;
|
|
122
|
+
case 'SEARCH':
|
|
123
|
+
/** Call @Search decorator over new property */
|
|
124
|
+
(0, common_1.Search)(operationPath)(newClass.prototype, k, descriptor);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (metadata.controllers) {
|
|
130
|
+
for (const child of metadata.controllers) {
|
|
131
|
+
if (!(0, common_2.isConstructor)(child))
|
|
132
|
+
throw new TypeError('Controllers should be injectable a class');
|
|
133
|
+
this._createNestControllers(child, newPath);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.OpraNestAdapter = OpraNestAdapter;
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.OpraExceptionFilter = void 0;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (exception instanceof common_2.OpraException)
|
|
10
|
-
return true;
|
|
11
|
-
throw exception;
|
|
3
|
+
exports.OpraExceptionFilter = exports.kHandler = void 0;
|
|
4
|
+
const core_1 = require("@opra/core");
|
|
5
|
+
exports.kHandler = Symbol.for('kHandler');
|
|
6
|
+
class OpraExceptionFilter {
|
|
7
|
+
constructor(adapter) {
|
|
8
|
+
this.adapter = adapter;
|
|
12
9
|
}
|
|
13
|
-
|
|
10
|
+
catch(exception, host) {
|
|
11
|
+
const ctx = host.switchToHttp();
|
|
12
|
+
const _res = ctx.getResponse();
|
|
13
|
+
const error = (0, core_1.wrapException)(exception);
|
|
14
|
+
const response = core_1.HttpOutgoing.from(_res);
|
|
15
|
+
return this.adapter[exports.kHandler].sendErrorResponse(response, [error]);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
14
18
|
exports.OpraExceptionFilter = OpraExceptionFilter;
|
|
15
|
-
exports.OpraExceptionFilter = OpraExceptionFilter = tslib_1.__decorate([
|
|
16
|
-
(0, common_1.Catch)(common_2.OpraException)
|
|
17
|
-
], OpraExceptionFilter);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { Controller } from '@nestjs/common';
|
|
3
|
+
// import { DECORATOR, HttpController } from '@opra/common';
|
|
4
|
+
//
|
|
5
|
+
// /*
|
|
6
|
+
// Overrides HttpController decorator function to call NestJS's Controller() when decorator called
|
|
7
|
+
// */
|
|
8
|
+
// const oldHttpControllerDecorator = HttpController[DECORATOR];
|
|
9
|
+
// HttpController[DECORATOR] = function HttpControllerDecorator(options?: HttpController.Options) {
|
|
10
|
+
// const opraControllerDecorator = oldHttpControllerDecorator(options);
|
|
11
|
+
// const nestControllerDecorator = Controller({});
|
|
12
|
+
// return (target: Function) => {
|
|
13
|
+
// opraControllerDecorator(target);
|
|
14
|
+
// nestControllerDecorator(target);
|
|
15
|
+
// };
|
|
16
|
+
// };
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import './augmentation/common-decorator.augmentation.js';
|
|
3
2
|
import './augmentation/nestjs.augmentation.js';
|
|
4
|
-
export * from './opra.module.js';
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './interfaces/opra-module-options.interface.js';
|
|
7
|
-
export * from './opra-module-ref.js';
|
|
3
|
+
export * from './opra-http.module.js';
|
|
4
|
+
export * from './opra-nestjs-adapter.js';
|
|
@@ -1 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
// import { ApiDocumentFactory } from '@opra/common';
|
|
3
|
+
// import { ExpressAdapter, HttpAdapter } from '@opra/core';
|
|
4
|
+
// export interface OpraModuleOptions extends HttpAdapter.Options {
|
|
5
|
+
// id?: any;
|
|
6
|
+
// document?: Partial<ApiDocumentFactory.InitArguments>;
|
|
7
|
+
//
|
|
8
|
+
// /**
|
|
9
|
+
// * @default true
|
|
10
|
+
// */
|
|
11
|
+
// useGlobalPrefix?: boolean;
|
|
12
|
+
// }
|
|
13
|
+
// export interface ExpressModuleOptions extends OpraModuleOptions, HttpAdapter.Options {}
|
|
14
|
+
// type OpraModuleOptionsWithoutId = Omit<OpraModuleOptions, 'id'>;
|
|
15
|
+
// export interface OpraModuleOptionsFactory {
|
|
16
|
+
// createOptions(): Promise<OpraModuleOptionsWithoutId> | OpraModuleOptionsWithoutId;
|
|
17
|
+
// }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
var OpraHttpCoreModule_1;
|
|
2
|
+
import { __decorate, __metadata } from "tslib";
|
|
3
|
+
import { asMutable } from 'ts-gems';
|
|
4
|
+
import { Global, Module } from '@nestjs/common';
|
|
5
|
+
import { ApiDocumentFactory } from '@opra/common';
|
|
6
|
+
import { OpraNestAdapter } from './opra-nestjs-adapter.js';
|
|
7
|
+
let OpraHttpCoreModule = OpraHttpCoreModule_1 = class OpraHttpCoreModule {
|
|
8
|
+
constructor(opraAdapter) {
|
|
9
|
+
this.opraAdapter = opraAdapter;
|
|
10
|
+
}
|
|
11
|
+
static forRoot(options) {
|
|
12
|
+
const opraAdapter = new OpraNestAdapter(options);
|
|
13
|
+
const token = options?.id || OpraNestAdapter;
|
|
14
|
+
const providers = [
|
|
15
|
+
...(options?.providers || []),
|
|
16
|
+
{
|
|
17
|
+
provide: OpraNestAdapter,
|
|
18
|
+
useFactory: async () => {
|
|
19
|
+
asMutable(opraAdapter).document = await ApiDocumentFactory.createDocument({
|
|
20
|
+
...options,
|
|
21
|
+
api: { protocol: 'http', name: options.name, controllers: opraAdapter.controllers },
|
|
22
|
+
});
|
|
23
|
+
return opraAdapter;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
if (token !== OpraNestAdapter)
|
|
28
|
+
providers.push({
|
|
29
|
+
provide: token,
|
|
30
|
+
useValue: opraAdapter,
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
module: OpraHttpCoreModule_1,
|
|
34
|
+
controllers: opraAdapter.controllers,
|
|
35
|
+
imports: [...(options?.imports || [])],
|
|
36
|
+
exports: [...(options?.exports || []), token],
|
|
37
|
+
providers,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async onModuleDestroy() {
|
|
41
|
+
await this.opraAdapter.close();
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
OpraHttpCoreModule = OpraHttpCoreModule_1 = __decorate([
|
|
45
|
+
Module({}),
|
|
46
|
+
Global(),
|
|
47
|
+
__metadata("design:paramtypes", [OpraNestAdapter])
|
|
48
|
+
], OpraHttpCoreModule);
|
|
49
|
+
export { OpraHttpCoreModule };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
var OpraHttpModule_1;
|
|
2
|
+
import { __decorate } from "tslib";
|
|
3
|
+
import { Module } from '@nestjs/common';
|
|
4
|
+
import { OpraHttpCoreModule } from './opra-http-core.module.js';
|
|
5
|
+
let OpraHttpModule = OpraHttpModule_1 = class OpraHttpModule {
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param options
|
|
9
|
+
*/
|
|
10
|
+
static forRoot(options) {
|
|
11
|
+
return {
|
|
12
|
+
module: OpraHttpModule_1,
|
|
13
|
+
imports: [OpraHttpCoreModule.forRoot(options)],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
OpraHttpModule = OpraHttpModule_1 = __decorate([
|
|
18
|
+
Module({})
|
|
19
|
+
], OpraHttpModule);
|
|
20
|
+
export { OpraHttpModule };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import nodePath from 'path';
|
|
2
|
+
import { Controller, Delete, Get, Head, Options, Patch, Post, Put, Req, Res, Search, UseFilters, } from '@nestjs/common';
|
|
3
|
+
import { ApiDocument, HTTP_CONTROLLER_METADATA, HttpApi, isConstructor, NotFoundError, } from '@opra/common';
|
|
4
|
+
import { HttpAdapter, HttpContext, HttpIncoming, HttpOutgoing } from '@opra/core';
|
|
5
|
+
import { OpraExceptionFilter } from './services/opra-exception-filter.js';
|
|
6
|
+
export const kHandler = Symbol.for('kHandler');
|
|
7
|
+
export class OpraNestAdapter extends HttpAdapter {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super((function () {
|
|
10
|
+
const document = new ApiDocument();
|
|
11
|
+
document.api = new HttpApi(document);
|
|
12
|
+
return document;
|
|
13
|
+
})(), options);
|
|
14
|
+
// protected _platform: string = 'express';
|
|
15
|
+
this.controllers = [];
|
|
16
|
+
let basePath = options.basePath || '/';
|
|
17
|
+
if (!basePath.startsWith('/'))
|
|
18
|
+
basePath = '/' + basePath;
|
|
19
|
+
if (options.controllers)
|
|
20
|
+
options.controllers.forEach(c => this._createNestControllers(c, basePath));
|
|
21
|
+
}
|
|
22
|
+
async close() {
|
|
23
|
+
//
|
|
24
|
+
}
|
|
25
|
+
_createNestControllers(source, currentPath) {
|
|
26
|
+
const metadata = Reflect.getMetadata(HTTP_CONTROLLER_METADATA, source);
|
|
27
|
+
if (!metadata)
|
|
28
|
+
return;
|
|
29
|
+
const newClass = {
|
|
30
|
+
[source.name]: class extends source {
|
|
31
|
+
},
|
|
32
|
+
}[source.name];
|
|
33
|
+
const newPath = metadata.path ? nodePath.join(currentPath, metadata.path) : currentPath;
|
|
34
|
+
const adapter = this;
|
|
35
|
+
/** Inject exception filter */
|
|
36
|
+
UseFilters(new OpraExceptionFilter(adapter))(newClass);
|
|
37
|
+
Controller()(newClass);
|
|
38
|
+
this.controllers.push(newClass);
|
|
39
|
+
if (metadata.operations) {
|
|
40
|
+
for (const [k, v] of Object.entries(metadata.operations)) {
|
|
41
|
+
const operationHandler = source.prototype[k];
|
|
42
|
+
Object.defineProperty(newClass.prototype, k, {
|
|
43
|
+
writable: true,
|
|
44
|
+
/** NestJS handler method */
|
|
45
|
+
async value(_req, _res) {
|
|
46
|
+
const request = HttpIncoming.from(_req);
|
|
47
|
+
const response = HttpOutgoing.from(_res);
|
|
48
|
+
const api = adapter.document.api;
|
|
49
|
+
const controller = api.findController(newClass);
|
|
50
|
+
const operation = controller?.operations.get(k);
|
|
51
|
+
if (!(operation && typeof operationHandler === 'function'))
|
|
52
|
+
throw new NotFoundError({
|
|
53
|
+
message: `No endpoint found for [${request.method}]${request.baseUrl}`,
|
|
54
|
+
details: {
|
|
55
|
+
path: request.baseUrl,
|
|
56
|
+
method: request.method,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
/** Create the HttpContext */
|
|
60
|
+
const context = new HttpContext({
|
|
61
|
+
adapter,
|
|
62
|
+
platform: _req.route ? 'express' : 'fastify',
|
|
63
|
+
platformArgs: {
|
|
64
|
+
request,
|
|
65
|
+
response,
|
|
66
|
+
},
|
|
67
|
+
request,
|
|
68
|
+
response,
|
|
69
|
+
operation,
|
|
70
|
+
controller: operation.owner,
|
|
71
|
+
controllerInstance: this,
|
|
72
|
+
operationHandler,
|
|
73
|
+
});
|
|
74
|
+
/** Handle request */
|
|
75
|
+
await adapter[kHandler].handleRequest(context);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
Req()(newClass.prototype, k, 0);
|
|
79
|
+
Res()(newClass.prototype, k, 1);
|
|
80
|
+
/** Copy metadata keys from source function to new one */
|
|
81
|
+
const metadataKeys = Reflect.getOwnMetadataKeys(operationHandler);
|
|
82
|
+
const newFn = newClass.prototype[k];
|
|
83
|
+
for (const key of metadataKeys) {
|
|
84
|
+
const m = Reflect.getMetadata(key, operationHandler);
|
|
85
|
+
Reflect.defineMetadata(key, m, newFn);
|
|
86
|
+
}
|
|
87
|
+
const descriptor = Object.getOwnPropertyDescriptor(newClass.prototype, k);
|
|
88
|
+
const operationPath = newPath + (v.path || '');
|
|
89
|
+
switch (v.method || 'GET') {
|
|
90
|
+
case 'DELETE':
|
|
91
|
+
/** Call @Delete decorator over new property */
|
|
92
|
+
Delete(operationPath)(newClass.prototype, k, descriptor);
|
|
93
|
+
break;
|
|
94
|
+
case 'GET':
|
|
95
|
+
/** Call @Get decorator over new property */
|
|
96
|
+
Get(operationPath)(newClass.prototype, k, descriptor);
|
|
97
|
+
break;
|
|
98
|
+
case 'HEAD':
|
|
99
|
+
/** Call @Head decorator over new property */
|
|
100
|
+
Head(operationPath)(newClass.prototype, k, descriptor);
|
|
101
|
+
break;
|
|
102
|
+
case 'OPTIONS':
|
|
103
|
+
/** Call @Options decorator over new property */
|
|
104
|
+
Options(operationPath)(newClass.prototype, k, descriptor);
|
|
105
|
+
break;
|
|
106
|
+
case 'PATCH':
|
|
107
|
+
/** Call @Patch decorator over new property */
|
|
108
|
+
Patch(operationPath)(newClass.prototype, k, descriptor);
|
|
109
|
+
break;
|
|
110
|
+
case 'POST':
|
|
111
|
+
/** Call @Post decorator over new property */
|
|
112
|
+
Post(operationPath)(newClass.prototype, k, descriptor);
|
|
113
|
+
break;
|
|
114
|
+
case 'PUT':
|
|
115
|
+
/** Call @Put decorator over new property */
|
|
116
|
+
Put(operationPath)(newClass.prototype, k, descriptor);
|
|
117
|
+
break;
|
|
118
|
+
case 'SEARCH':
|
|
119
|
+
/** Call @Search decorator over new property */
|
|
120
|
+
Search(operationPath)(newClass.prototype, k, descriptor);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (metadata.controllers) {
|
|
126
|
+
for (const child of metadata.controllers) {
|
|
127
|
+
if (!isConstructor(child))
|
|
128
|
+
throw new TypeError('Controllers should be injectable a class');
|
|
129
|
+
this._createNestControllers(child, newPath);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (exception instanceof OpraException)
|
|
7
|
-
return true;
|
|
8
|
-
throw exception;
|
|
1
|
+
import { HttpOutgoing, wrapException } from '@opra/core';
|
|
2
|
+
export const kHandler = Symbol.for('kHandler');
|
|
3
|
+
export class OpraExceptionFilter {
|
|
4
|
+
constructor(adapter) {
|
|
5
|
+
this.adapter = adapter;
|
|
9
6
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
catch(exception, host) {
|
|
8
|
+
const ctx = host.switchToHttp();
|
|
9
|
+
const _res = ctx.getResponse();
|
|
10
|
+
const error = wrapException(exception);
|
|
11
|
+
const response = HttpOutgoing.from(_res);
|
|
12
|
+
return this.adapter[kHandler].sendErrorResponse(response, [error]);
|
|
13
|
+
}
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/nestjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-alpha.1",
|
|
4
4
|
"description": "Opra NestJS module",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"build:esm": "tsc -b tsconfig-build-esm.json",
|
|
18
18
|
"postbuild": "cp README.md package.json ../../LICENSE ../../build/nestjs && cp ../../package.cjs.json ../../build/nestjs/cjs/package.json",
|
|
19
19
|
"lint": "eslint . --max-warnings=0",
|
|
20
|
+
"format": "prettier . --write --log-level=warn",
|
|
20
21
|
"test": "jest",
|
|
21
22
|
"cover": "jest --collect-coverage",
|
|
22
23
|
"clean": "npm run clean:src && npm run clean:test && npm run clean:dist && npm run clean:cover",
|
|
@@ -28,20 +29,20 @@
|
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"@opra/common": "^0.33.13",
|
|
30
31
|
"@opra/core": "^0.33.13",
|
|
31
|
-
"fast-tokenizer": "^1.
|
|
32
|
+
"fast-tokenizer": "^1.3.0",
|
|
32
33
|
"lodash.head": "^4.0.1",
|
|
33
|
-
"reflect-metadata": "^0.
|
|
34
|
+
"reflect-metadata": "^0.2.2"
|
|
34
35
|
},
|
|
35
36
|
"peerDependencies": {
|
|
36
|
-
"@nestjs/common": "^10.3.
|
|
37
|
-
"@nestjs/core": "^10.3.
|
|
37
|
+
"@nestjs/common": "^10.3.9",
|
|
38
|
+
"@nestjs/core": "^10.3.9"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
|
-
"@nestjs/platform-express": "^10.3.
|
|
41
|
-
"@nestjs/testing": "^10.3.
|
|
41
|
+
"@nestjs/platform-express": "^10.3.9",
|
|
42
|
+
"@nestjs/testing": "^10.3.9",
|
|
42
43
|
"@types/lodash.head": "^4.0.9",
|
|
43
44
|
"filedirname": "^3.4.0",
|
|
44
|
-
"ts-gems": "^3.
|
|
45
|
+
"ts-gems": "^3.4.0"
|
|
45
46
|
},
|
|
46
47
|
"type": "module",
|
|
47
48
|
"module": "./esm/index.js",
|
|
@@ -63,4 +64,4 @@
|
|
|
63
64
|
"opra",
|
|
64
65
|
"nestjs"
|
|
65
66
|
]
|
|
66
|
-
}
|
|
67
|
+
}
|
|
File without changes
|
package/types/index.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import './augmentation/common-decorator.augmentation.js';
|
|
3
2
|
import './augmentation/nestjs.augmentation.js';
|
|
4
|
-
export * from './opra.module.js';
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './interfaces/opra-module-options.interface.js';
|
|
7
|
-
export * from './opra-module-ref.js';
|
|
3
|
+
export * from './opra-http.module.js';
|
|
4
|
+
export * from './opra-nestjs-adapter.js';
|