@opra/nestjs 0.33.13 → 1.0.0-alpha.10

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.
Files changed (74) hide show
  1. package/README.md +1 -0
  2. package/cjs/augmentation/http-controller.augmentation.js +16 -0
  3. package/cjs/constants.js +2 -7
  4. package/cjs/decorators/public.decorator.js +7 -0
  5. package/cjs/index.js +4 -5
  6. package/cjs/interfaces/opra-module-options.interface.js +16 -1
  7. package/cjs/opra-http-core.module.js +60 -0
  8. package/cjs/opra-http.module.js +24 -0
  9. package/cjs/opra-nestjs-adapter.js +160 -0
  10. package/cjs/services/opra-exception-filter.js +14 -13
  11. package/cjs/services/opra-middleware.js +24 -0
  12. package/esm/augmentation/http-controller.augmentation.js +16 -0
  13. package/esm/constants.js +1 -6
  14. package/esm/decorators/public.decorator.js +3 -0
  15. package/esm/index.js +4 -5
  16. package/esm/interfaces/opra-module-options.interface.js +17 -1
  17. package/esm/opra-http-core.module.js +57 -0
  18. package/esm/opra-http.module.js +21 -0
  19. package/esm/opra-nestjs-adapter.js +156 -0
  20. package/esm/services/opra-exception-filter.js +13 -13
  21. package/esm/services/opra-middleware.js +21 -0
  22. package/package.json +16 -13
  23. package/types/augmentation/http-controller.augmentation.d.ts +0 -0
  24. package/types/constants.d.ts +1 -6
  25. package/types/decorators/public.decorator.d.ts +1 -0
  26. package/types/index.d.ts +4 -5
  27. package/types/interfaces/opra-module-options.interface.d.ts +0 -25
  28. package/types/opra-http-core.module.d.ts +10 -0
  29. package/types/opra-http.module.d.ts +20 -0
  30. package/types/opra-nestjs-adapter.d.ts +12 -0
  31. package/types/services/opra-exception-filter.d.ts +6 -2
  32. package/types/services/opra-middleware.d.ts +5 -0
  33. package/cjs/augmentation/common-decorator.augmentation.js +0 -40
  34. package/cjs/decorators/context.decorator.js +0 -10
  35. package/cjs/enums/handler-paramtype.enum.js +0 -9
  36. package/cjs/factories/opra-api.factory.js +0 -200
  37. package/cjs/factories/params.factory.js +0 -23
  38. package/cjs/opra-core.module.js +0 -140
  39. package/cjs/opra-module-ref.js +0 -16
  40. package/cjs/opra.module.js +0 -25
  41. package/cjs/services/nest-explorer.js +0 -38
  42. package/cjs/services/opra-api-loader.js +0 -85
  43. package/cjs/types.js +0 -2
  44. package/cjs/utils/class.utils.js +0 -25
  45. package/cjs/utils/function.utils.js +0 -37
  46. package/cjs/utils/param.utils.js +0 -24
  47. package/esm/augmentation/common-decorator.augmentation.js +0 -38
  48. package/esm/decorators/context.decorator.js +0 -7
  49. package/esm/enums/handler-paramtype.enum.js +0 -6
  50. package/esm/factories/opra-api.factory.js +0 -197
  51. package/esm/factories/params.factory.js +0 -19
  52. package/esm/opra-core.module.js +0 -137
  53. package/esm/opra-module-ref.js +0 -12
  54. package/esm/opra.module.js +0 -22
  55. package/esm/services/nest-explorer.js +0 -34
  56. package/esm/services/opra-api-loader.js +0 -81
  57. package/esm/types.js +0 -1
  58. package/esm/utils/class.utils.js +0 -19
  59. package/esm/utils/function.utils.js +0 -33
  60. package/esm/utils/param.utils.js +0 -20
  61. package/types/augmentation/common-decorator.augmentation.d.ts +0 -1
  62. package/types/decorators/context.decorator.d.ts +0 -5
  63. package/types/enums/handler-paramtype.enum.d.ts +0 -5
  64. package/types/factories/opra-api.factory.d.ts +0 -15
  65. package/types/factories/params.factory.d.ts +0 -4
  66. package/types/opra-core.module.d.ts +0 -17
  67. package/types/opra-module-ref.d.ts +0 -11
  68. package/types/opra.module.d.ts +0 -6
  69. package/types/services/nest-explorer.d.ts +0 -8
  70. package/types/services/opra-api-loader.d.ts +0 -19
  71. package/types/types.d.ts +0 -2
  72. package/types/utils/class.utils.d.ts +0 -4
  73. package/types/utils/function.utils.d.ts +0 -1
  74. package/types/utils/param.utils.d.ts +0 -8
@@ -1,23 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpraParamsFactory = void 0;
4
- const handler_paramtype_enum_js_1 = require("../enums/handler-paramtype.enum.js");
5
- class OpraParamsFactory {
6
- exchangeKeyForValue(type, data, args) {
7
- if (!args) {
8
- return null;
9
- }
10
- args = Array.isArray(args) ? args : [];
11
- switch (type) {
12
- case handler_paramtype_enum_js_1.HandlerParamType.CONTEXT:
13
- return args[3];
14
- case handler_paramtype_enum_js_1.HandlerParamType.REQUEST:
15
- return args[3].request;
16
- case handler_paramtype_enum_js_1.HandlerParamType.RESPONSE:
17
- return args[3].response;
18
- default:
19
- return null;
20
- }
21
- }
22
- }
23
- exports.OpraParamsFactory = OpraParamsFactory;
@@ -1,140 +0,0 @@
1
- "use strict";
2
- var OpraCoreModule_1;
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.OpraCoreModule = void 0;
5
- const tslib_1 = require("tslib");
6
- const crypto = tslib_1.__importStar(require("crypto"));
7
- const common_1 = require("@nestjs/common");
8
- const core_1 = require("@nestjs/core");
9
- const metadata_scanner_1 = require("@nestjs/core/metadata-scanner");
10
- const constants_js_1 = require("./constants.js");
11
- const opra_api_factory_js_1 = require("./factories/opra-api.factory.js");
12
- const opra_module_ref_js_1 = require("./opra-module-ref.js");
13
- const nest_explorer_js_1 = require("./services/nest-explorer.js");
14
- const opra_api_loader_js_1 = require("./services/opra-api-loader.js");
15
- let OpraCoreModule = OpraCoreModule_1 = class OpraCoreModule {
16
- constructor(httpAdapterHost, modulesContainer, options, apiLoader) {
17
- this.httpAdapterHost = httpAdapterHost;
18
- this.modulesContainer = modulesContainer;
19
- this.options = options;
20
- this.apiLoader = apiLoader;
21
- }
22
- static forRoot(options) {
23
- const providers = [
24
- ...(options.providers || []),
25
- {
26
- provide: constants_js_1.OPRA_MODULE_OPTIONS,
27
- useValue: options,
28
- },
29
- {
30
- provide: constants_js_1.OPRA_INITIALIZER,
31
- useClass: opra_api_loader_js_1.OpraApiLoader
32
- },
33
- {
34
- provide: options.id || opra_module_ref_js_1.OpraModuleRef,
35
- inject: [constants_js_1.OPRA_INITIALIZER],
36
- useFactory: (apiLoader) => {
37
- return apiLoader.opraModuleRef;
38
- }
39
- }
40
- ];
41
- return {
42
- module: OpraCoreModule_1,
43
- imports: [...(options.imports || [])],
44
- exports: [...(options.exports || [])],
45
- providers
46
- };
47
- }
48
- static forRootAsync(asyncOptions) {
49
- return {
50
- module: OpraCoreModule_1,
51
- imports: [...(asyncOptions.imports || [])],
52
- providers: [
53
- ...(asyncOptions.providers || []),
54
- {
55
- provide: constants_js_1.OPRA_MODULE_ID,
56
- useValue: crypto.randomUUID()
57
- },
58
- {
59
- provide: constants_js_1.OPRA_INITIALIZER,
60
- useClass: opra_api_loader_js_1.OpraApiLoader
61
- },
62
- {
63
- provide: asyncOptions.id || opra_module_ref_js_1.OpraModuleRef,
64
- inject: [constants_js_1.OPRA_INITIALIZER],
65
- useFactory: (apiLoader) => {
66
- return apiLoader.opraModuleRef;
67
- }
68
- },
69
- ...this.createAsyncProviders(asyncOptions)
70
- ]
71
- };
72
- }
73
- static createAsyncProviders(asyncOptions) {
74
- if (asyncOptions.useExisting || asyncOptions.useFactory)
75
- return [this.createAsyncOptionsProvider(asyncOptions)];
76
- if (asyncOptions.useClass)
77
- return [
78
- this.createAsyncOptionsProvider(asyncOptions),
79
- {
80
- provide: asyncOptions.useClass,
81
- useClass: asyncOptions.useClass
82
- }
83
- ];
84
- throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
85
- }
86
- static createAsyncOptionsProvider(asyncOptions) {
87
- if (asyncOptions.useFactory) {
88
- return {
89
- provide: constants_js_1.OPRA_MODULE_OPTIONS,
90
- useFactory: asyncOptions.useFactory,
91
- inject: asyncOptions.inject || []
92
- };
93
- }
94
- const useClass = asyncOptions.useClass || asyncOptions.useExisting;
95
- if (useClass) {
96
- return {
97
- provide: constants_js_1.OPRA_MODULE_OPTIONS,
98
- useFactory: (optionsFactory) => optionsFactory.createOptions(),
99
- inject: [useClass]
100
- };
101
- }
102
- throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
103
- }
104
- async onModuleInit() {
105
- const httpAdapter = this.httpAdapterHost?.httpAdapter;
106
- if (!httpAdapter)
107
- return;
108
- const opraModule = (() => {
109
- for (const m of this.modulesContainer.values()) {
110
- for (const imp of m.imports.values()) {
111
- for (const prv of imp.providers.values())
112
- if (prv.instance === this) {
113
- return imp;
114
- }
115
- }
116
- }
117
- })();
118
- if (opraModule) {
119
- await this.apiLoader.initialize(opraModule);
120
- }
121
- }
122
- async onModuleDestroy() {
123
- await this.apiLoader.stop();
124
- }
125
- };
126
- exports.OpraCoreModule = OpraCoreModule;
127
- exports.OpraCoreModule = OpraCoreModule = OpraCoreModule_1 = tslib_1.__decorate([
128
- (0, common_1.Module)({
129
- providers: [
130
- opra_api_factory_js_1.OpraApiFactory,
131
- metadata_scanner_1.MetadataScanner,
132
- nest_explorer_js_1.NestExplorer
133
- ]
134
- }),
135
- (0, common_1.Global)(),
136
- tslib_1.__param(2, (0, common_1.Inject)(constants_js_1.OPRA_MODULE_OPTIONS)),
137
- tslib_1.__param(3, (0, common_1.Inject)(constants_js_1.OPRA_INITIALIZER)),
138
- tslib_1.__metadata("design:paramtypes", [core_1.HttpAdapterHost,
139
- core_1.ModulesContainer, Object, opra_api_loader_js_1.OpraApiLoader])
140
- ], OpraCoreModule);
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpraModuleRef = void 0;
4
- const constants_js_1 = require("./constants.js");
5
- class OpraModuleRef {
6
- get adapter() {
7
- return this[constants_js_1.kAdapter];
8
- }
9
- get api() {
10
- return this[constants_js_1.kAdapter].api;
11
- }
12
- get options() {
13
- return this[constants_js_1.kOptions];
14
- }
15
- }
16
- exports.OpraModuleRef = OpraModuleRef;
@@ -1,25 +0,0 @@
1
- "use strict";
2
- var OpraModule_1;
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.OpraModule = void 0;
5
- const tslib_1 = require("tslib");
6
- const common_1 = require("@nestjs/common");
7
- const opra_core_module_js_1 = require("./opra-core.module.js");
8
- let OpraModule = OpraModule_1 = class OpraModule {
9
- static forRoot(options) {
10
- return {
11
- module: OpraModule_1,
12
- imports: [opra_core_module_js_1.OpraCoreModule.forRoot(options)]
13
- };
14
- }
15
- static forRootAsync(asyncOptions) {
16
- return {
17
- module: OpraModule_1,
18
- imports: [opra_core_module_js_1.OpraCoreModule.forRootAsync(asyncOptions)]
19
- };
20
- }
21
- };
22
- exports.OpraModule = OpraModule;
23
- exports.OpraModule = OpraModule = OpraModule_1 = tslib_1.__decorate([
24
- (0, common_1.Module)({})
25
- ], OpraModule);
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NestExplorer = void 0;
4
- const common_1 = require("@opra/common");
5
- class NestExplorer {
6
- exploreProviders(rootModule, callback) {
7
- const modules = new Set();
8
- const tree = [];
9
- const scanModules = (m) => {
10
- if (modules.has(m))
11
- return;
12
- modules.add(m);
13
- tree.push(m);
14
- for (const mm of m.imports.values()) {
15
- scanModules(mm);
16
- }
17
- for (const wrapper of m.providers.values()) {
18
- callback(wrapper, tree);
19
- if (wrapper.host)
20
- scanModules(wrapper.host);
21
- }
22
- tree.pop();
23
- };
24
- scanModules(rootModule);
25
- }
26
- exploreResources(rootModule, callback) {
27
- this.exploreProviders(rootModule, (wrapper, tree) => {
28
- if (wrapper.instance
29
- && typeof wrapper.instance === 'object'
30
- && wrapper.instance.constructor
31
- && common_1.OpraSchema.isResource(Reflect.getMetadata(common_1.RESOURCE_METADATA, wrapper.instance.constructor))) {
32
- callback(wrapper, tree);
33
- }
34
- return false;
35
- });
36
- }
37
- }
38
- exports.NestExplorer = NestExplorer;
@@ -1,85 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpraApiLoader = void 0;
4
- const tslib_1 = require("tslib");
5
- const common_1 = require("@nestjs/common");
6
- const core_1 = require("@nestjs/core");
7
- const common_2 = require("@opra/common");
8
- const core_2 = require("@opra/core");
9
- const constants_js_1 = require("../constants.js");
10
- const opra_api_factory_js_1 = require("../factories/opra-api.factory.js");
11
- const opra_module_ref_js_1 = require("../opra-module-ref.js");
12
- class OpraApiLoader {
13
- constructor() {
14
- this.logger = new common_1.Logger(OpraApiLoader.name, { timestamp: true });
15
- this.opraModuleRef = new opra_module_ref_js_1.OpraModuleRef();
16
- }
17
- async initialize(rootModule) {
18
- const httpAdapter = this.httpAdapterHost?.httpAdapter;
19
- const globalPrefix = this.applicationConfig.getGlobalPrefix();
20
- const platformName = httpAdapter.getType();
21
- const moduleOptions = this.options;
22
- this.opraModuleRef[constants_js_1.kOptions] = this.options;
23
- let prefixPath = new common_2.OpraURLPath((moduleOptions.useGlobalPrefix !== false ? globalPrefix : ''));
24
- if (moduleOptions.basePath)
25
- prefixPath = prefixPath.join(moduleOptions.basePath);
26
- const name = moduleOptions.document?.info?.title || 'untitled service';
27
- const options = {
28
- ...moduleOptions,
29
- basePath: prefixPath.toString()
30
- };
31
- try {
32
- const apiDocument = await this.opraFactory.generateService(rootModule, 'http', options.document);
33
- if (!Object.keys(apiDocument.root).length) {
34
- this.logger.warn(`No Sources found (${name})`);
35
- return;
36
- }
37
- if (platformName === 'express') {
38
- this.opraModuleRef[constants_js_1.kAdapter] = await this.registerExpress(apiDocument, options);
39
- // else if (platformName === 'fastify')
40
- // await this.registerFastify();
41
- }
42
- else { // noinspection ExceptionCaughtLocallyJS
43
- throw new Error(`No support for current HttpAdapter: ${platformName}`);
44
- }
45
- this.logger.log(`Mapped {${prefixPath.toString() || '/'}} to "${name}" service`);
46
- }
47
- catch (e) {
48
- this.logger.error(e);
49
- throw e;
50
- }
51
- }
52
- async stop() {
53
- //
54
- }
55
- async registerExpress(apiDocument, moduleOptions) {
56
- const httpAdapter = this.httpAdapterHost.httpAdapter;
57
- /* istanbul ignore next */
58
- if (!httpAdapter)
59
- throw new Error('HttpAdapterHost is not initialized');
60
- const app = httpAdapter.getInstance();
61
- const logger = moduleOptions.logger ||
62
- (process.env.NODE_ENV === 'test' ? undefined : new common_1.Logger(apiDocument.info.title));
63
- return await core_2.ExpressAdapter.create(app, apiDocument, {
64
- ...moduleOptions,
65
- logger,
66
- });
67
- }
68
- }
69
- exports.OpraApiLoader = OpraApiLoader;
70
- tslib_1.__decorate([
71
- (0, common_1.Inject)(),
72
- tslib_1.__metadata("design:type", core_1.HttpAdapterHost)
73
- ], OpraApiLoader.prototype, "httpAdapterHost", void 0);
74
- tslib_1.__decorate([
75
- (0, common_1.Inject)(),
76
- tslib_1.__metadata("design:type", core_1.ApplicationConfig)
77
- ], OpraApiLoader.prototype, "applicationConfig", void 0);
78
- tslib_1.__decorate([
79
- (0, common_1.Inject)(),
80
- tslib_1.__metadata("design:type", opra_api_factory_js_1.OpraApiFactory)
81
- ], OpraApiLoader.prototype, "opraFactory", void 0);
82
- tslib_1.__decorate([
83
- (0, common_1.Inject)(constants_js_1.OPRA_MODULE_OPTIONS),
84
- tslib_1.__metadata("design:type", Object)
85
- ], OpraApiLoader.prototype, "options", void 0);
package/cjs/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getClassName = exports.getClassOrUndefined = exports.isConstructor = void 0;
4
- const shared_utils_1 = require("@nestjs/common/utils/shared.utils");
5
- function isConstructor(obj) {
6
- return typeof obj === 'function' &&
7
- !!(obj.prototype && obj.prototype.constructor);
8
- }
9
- exports.isConstructor = isConstructor;
10
- function getClassOrUndefined(typeOrFunc) {
11
- return isConstructor(typeOrFunc)
12
- ? typeOrFunc
13
- : (0, shared_utils_1.isFunction)(typeOrFunc)
14
- ? typeOrFunc()
15
- : undefined;
16
- }
17
- exports.getClassOrUndefined = getClassOrUndefined;
18
- function getClassName(nameOrType) {
19
- if ((0, shared_utils_1.isString)(nameOrType)) {
20
- return nameOrType;
21
- }
22
- const classOrUndefined = getClassOrUndefined(nameOrType);
23
- return classOrUndefined && classOrUndefined.name;
24
- }
25
- exports.getClassName = getClassName;
@@ -1,37 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getNumberOfArguments = void 0;
4
- const fast_tokenizer_1 = require("fast-tokenizer");
5
- function getNumberOfArguments(fn) {
6
- const functionAsString = fn.toString();
7
- const tokenizer = (0, fast_tokenizer_1.tokenize)(functionAsString, {
8
- // keepBrackets: true,
9
- keepDelimiters: true,
10
- keepQuotes: true,
11
- brackets: {}
12
- });
13
- let k = 0;
14
- let s = '';
15
- for (const token of tokenizer) {
16
- if (token.startsWith('(')) {
17
- s += token.substring(1);
18
- k++;
19
- }
20
- else if (token.startsWith(')')) {
21
- if (k === 1)
22
- break;
23
- }
24
- else if (k)
25
- s += token;
26
- }
27
- const x = (0, fast_tokenizer_1.splitString)(s, {
28
- brackets: {
29
- '{': '}',
30
- '(': ')',
31
- '[': ']',
32
- '/*': '*/'
33
- }, delimiters: ','
34
- });
35
- return x.length > 1 ? x.length : (x[0] ? 1 : 0);
36
- }
37
- exports.getNumberOfArguments = getNumberOfArguments;
@@ -1,24 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createOpraParamDecorator = void 0;
4
- require("reflect-metadata");
5
- const constants_js_1 = require("../constants.js");
6
- function assignMetadata(args, paramType, index, data, ...pipes) {
7
- return {
8
- ...args,
9
- [`${paramType}:${index}`]: {
10
- index,
11
- data,
12
- pipes,
13
- },
14
- };
15
- }
16
- function createOpraParamDecorator(paramType) {
17
- return (target, key, index) => {
18
- if (!key)
19
- return;
20
- const args = Reflect.getMetadata(constants_js_1.PARAM_ARGS_METADATA, target.constructor, key) || {};
21
- Reflect.defineMetadata(constants_js_1.PARAM_ARGS_METADATA, assignMetadata(args, paramType, index), target.constructor, key);
22
- };
23
- }
24
- exports.createOpraParamDecorator = createOpraParamDecorator;
@@ -1,38 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { Collection, DECORATOR, Singleton, Storage } from '@opra/common';
3
- /*
4
- Overrides Collection decorator function to call NestJS's Injectable() when Collection decorator called
5
- */
6
- const oldCollectionDecorator = Collection[DECORATOR];
7
- Collection[DECORATOR] = function CollectionDecorator(...args) {
8
- const collectionDecorator = oldCollectionDecorator(...args);
9
- const injectableDecorator = Injectable();
10
- return (target) => {
11
- collectionDecorator(target);
12
- injectableDecorator(target);
13
- };
14
- };
15
- /*
16
- Overrides Singleton decorator function to call NestJS's Injectable() when Singleton decorator called
17
- */
18
- const oldSingletonDecorator = Singleton[DECORATOR];
19
- Singleton[DECORATOR] = function SingletonDecorator(...args) {
20
- const singletonDecorator = oldSingletonDecorator(...args);
21
- const injectableDecorator = Injectable();
22
- return (target) => {
23
- singletonDecorator(target);
24
- injectableDecorator(target);
25
- };
26
- };
27
- /*
28
- Overrides Singleton decorator function to call NestJS's Injectable() when Singleton decorator called
29
- */
30
- const oldStorageDecorator = Storage[DECORATOR];
31
- Storage[DECORATOR] = function StorageDecorator(...args) {
32
- const storageDecorator = oldStorageDecorator(...args);
33
- const injectableDecorator = Injectable();
34
- return (target) => {
35
- storageDecorator(target);
36
- injectableDecorator(target);
37
- };
38
- };
@@ -1,7 +0,0 @@
1
- import { HandlerParamType } from '../enums/handler-paramtype.enum.js';
2
- import { createOpraParamDecorator } from '../utils/param.utils.js';
3
- /**
4
- * Handler method parameter decorator. Populates the decorated
5
- * parameter with the value of `RequestContext`.
6
- */
7
- export const Context = createOpraParamDecorator(HandlerParamType.CONTEXT);
@@ -1,6 +0,0 @@
1
- export var HandlerParamType;
2
- (function (HandlerParamType) {
3
- HandlerParamType[HandlerParamType["CONTEXT"] = 0] = "CONTEXT";
4
- HandlerParamType[HandlerParamType["REQUEST"] = 1] = "REQUEST";
5
- HandlerParamType[HandlerParamType["RESPONSE"] = 2] = "RESPONSE";
6
- })(HandlerParamType || (HandlerParamType = {}));
@@ -1,197 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import head from 'lodash.head';
3
- import { Inject, Injectable } from '@nestjs/common';
4
- import { ContextIdFactory, createContextId, ModulesContainer, REQUEST } from '@nestjs/core';
5
- import { ExternalContextCreator } from '@nestjs/core/helpers/external-context-creator';
6
- import { Injector } from '@nestjs/core/injector/injector';
7
- import { InternalCoreModule } from '@nestjs/core/injector/internal-core-module';
8
- import { REQUEST_CONTEXT_ID } from '@nestjs/core/router/request/request-constants';
9
- import { ApiDocumentFactory, OpraSchema, RESOURCE_METADATA } from '@opra/common';
10
- import { PARAM_ARGS_METADATA } from '../constants.js';
11
- import { HandlerParamType } from '../enums/handler-paramtype.enum.js';
12
- import { NestExplorer } from '../services/nest-explorer.js';
13
- import { getNumberOfArguments } from '../utils/function.utils.js';
14
- import { OpraParamsFactory } from './params.factory.js';
15
- const noOpFunction = () => void 0;
16
- let OpraApiFactory = class OpraApiFactory {
17
- constructor() {
18
- this.paramsFactory = new OpraParamsFactory();
19
- this.injector = new Injector();
20
- }
21
- async generateService(rootModule, contextType, apiSchema) {
22
- const info = { ...apiSchema?.info };
23
- info.title = info.title || 'Untitled service';
24
- info.version = info.version || '1';
25
- const root = {
26
- resources: []
27
- };
28
- const apiInit = {
29
- version: OpraSchema.SpecVersion,
30
- ...apiSchema,
31
- info,
32
- types: apiSchema?.types || [],
33
- root
34
- };
35
- /*
36
- * Walk through modules and add Resource instances to the api schema
37
- */
38
- this.explorerService.exploreResources(rootModule, (wrapper, modulePath) => {
39
- const instance = wrapper.instance;
40
- const ctor = instance.constructor;
41
- const metadata = Reflect.getMetadata(RESOURCE_METADATA, ctor);
42
- let node = root;
43
- modulePath.forEach(m => {
44
- const mt = Reflect.getMetadata(RESOURCE_METADATA, m._metatype);
45
- if (mt) {
46
- let n = node.resources.find(x => x.controller === m.instance);
47
- if (!n) {
48
- n = {
49
- ...mt,
50
- kind: 'Container',
51
- resources: [...(mt.resources || [])],
52
- controller: m.instance
53
- };
54
- node.resources.push(n);
55
- }
56
- node = n;
57
- }
58
- });
59
- // Do not add Modules decorated with @Container
60
- if (wrapper.metatype !== wrapper.host?.metatype)
61
- node.resources.push(instance);
62
- /* Wrap operation and action functions */
63
- const isRequestScoped = !wrapper.isDependencyTreeStatic();
64
- const methodNames = [...Object.keys(metadata.operations || []), ...Object.keys(metadata.actions || [])];
65
- for (const methodName of methodNames) {
66
- const endpointFunction = instance[methodName];
67
- const nestHandlerName = methodName + '_nestjs';
68
- // Skip patch if controller do not have function for endpoint or already patched before
69
- if (typeof endpointFunction !== 'function')
70
- continue;
71
- // NestJs requires calling handler function in different order than Opra.
72
- // In NestJS, handler functions must be called with these parameters (req, res, next)
73
- // In Opra, handler functions must be called with these parameters (context)
74
- // To work handlers properly we create new handlers that will work as a proxy to wrap parameters
75
- // Opra request (context) -> Nest (req, res, next, context: QueryRequestContext) -> Opra response (context)
76
- const paramArgsMetadata = Reflect.getMetadata(PARAM_ARGS_METADATA, instance.constructor, methodName);
77
- const hasParamsArgs = !!paramArgsMetadata;
78
- const patchedFn = instance[nestHandlerName] = function (...args) {
79
- if (hasParamsArgs)
80
- return endpointFunction.apply(this, args);
81
- return endpointFunction.call(this, args[3]);
82
- };
83
- if (paramArgsMetadata)
84
- Reflect.defineMetadata(PARAM_ARGS_METADATA, paramArgsMetadata, instance.constructor, nestHandlerName);
85
- // Copy all metadata from old Function to new one
86
- Reflect.getMetadataKeys(endpointFunction).forEach(k => {
87
- const m = Reflect.getMetadata(k, endpointFunction);
88
- Reflect.defineMetadata(k, m, patchedFn);
89
- });
90
- this._createContextCallback(instance, wrapper, rootModule, methodName, isRequestScoped, contextType);
91
- }
92
- });
93
- // Create api document
94
- return ApiDocumentFactory.createDocument(apiInit);
95
- }
96
- _createHandler(callback) {
97
- return function (ctx) {
98
- switch (ctx.protocol) {
99
- case 'http':
100
- const httpContext = ctx.switchToHttp();
101
- return callback(httpContext.incoming, httpContext.outgoing, noOpFunction, ctx);
102
- default:
103
- throw new Error(`"${ctx.protocol}" context type is not implemented yet`);
104
- }
105
- };
106
- }
107
- _createContextCallback(instance, wrapper, moduleRef, methodName, isRequestScoped, contextType, options) {
108
- const paramsFactory = this.paramsFactory;
109
- const nestHandlerName = methodName + '_nestjs';
110
- const callback = isRequestScoped
111
- ? async (...args) => {
112
- const opraContext = paramsFactory.exchangeKeyForValue(HandlerParamType.CONTEXT, undefined, args);
113
- const contextId = this.getContextId(opraContext);
114
- this.registerContextProvider(opraContext, contextId);
115
- const contextInstance = await this.injector.loadPerContext(instance, moduleRef, moduleRef.providers, contextId);
116
- const contextCallback = this.externalContextCreator.create(contextInstance, contextInstance[methodName], nestHandlerName, PARAM_ARGS_METADATA, paramsFactory, contextId, wrapper.id, options, opraContext.protocol);
117
- contextInstance[methodName] = this._createHandler(contextCallback);
118
- return contextCallback(...args);
119
- }
120
- : this.externalContextCreator.create(instance, instance[nestHandlerName], nestHandlerName, PARAM_ARGS_METADATA, paramsFactory, undefined, undefined, options, contextType);
121
- instance[methodName] = this._createHandler(callback);
122
- return callback;
123
- }
124
- // noinspection JSMethodCanBeStatic
125
- getContextId(gqlContext) {
126
- const numberOfArguments = getNumberOfArguments(ContextIdFactory.getByRequest);
127
- if (numberOfArguments === 2) {
128
- // @ts-ignore
129
- const contextId = ContextIdFactory.getByRequest(gqlContext, ['req']);
130
- if (!gqlContext[REQUEST_CONTEXT_ID]) {
131
- Object.defineProperty(gqlContext, REQUEST_CONTEXT_ID, {
132
- value: contextId,
133
- enumerable: false,
134
- configurable: false,
135
- writable: false,
136
- });
137
- }
138
- return contextId;
139
- }
140
- else {
141
- // TODO remove in the next version (backward-compatibility layer)
142
- // Left for backward compatibility purposes
143
- let contextId;
144
- if (gqlContext && gqlContext[REQUEST_CONTEXT_ID]) {
145
- contextId = gqlContext[REQUEST_CONTEXT_ID];
146
- }
147
- else if (gqlContext &&
148
- gqlContext.req &&
149
- gqlContext.req[REQUEST_CONTEXT_ID]) {
150
- contextId = gqlContext.req[REQUEST_CONTEXT_ID];
151
- }
152
- else {
153
- contextId = createContextId();
154
- Object.defineProperty(gqlContext, REQUEST_CONTEXT_ID, {
155
- value: contextId,
156
- enumerable: false,
157
- configurable: false,
158
- writable: false,
159
- });
160
- }
161
- return contextId;
162
- }
163
- }
164
- registerContextProvider(request, contextId) {
165
- const coreModuleArray = [...this.modulesContainer.entries()]
166
- .filter(
167
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
168
- ([key, { metatype }]) => metatype && metatype.name === InternalCoreModule.name)
169
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
170
- .map(([key, value]) => value);
171
- const coreModuleRef = head(coreModuleArray);
172
- if (!coreModuleRef) {
173
- return;
174
- }
175
- const wrapper = coreModuleRef.getProviderByKey(REQUEST);
176
- wrapper.setInstanceByContextId(contextId, {
177
- instance: request,
178
- isResolved: true,
179
- });
180
- }
181
- };
182
- __decorate([
183
- Inject(),
184
- __metadata("design:type", ModulesContainer)
185
- ], OpraApiFactory.prototype, "modulesContainer", void 0);
186
- __decorate([
187
- Inject(),
188
- __metadata("design:type", ExternalContextCreator)
189
- ], OpraApiFactory.prototype, "externalContextCreator", void 0);
190
- __decorate([
191
- Inject(),
192
- __metadata("design:type", NestExplorer)
193
- ], OpraApiFactory.prototype, "explorerService", void 0);
194
- OpraApiFactory = __decorate([
195
- Injectable()
196
- ], OpraApiFactory);
197
- export { OpraApiFactory };