@opra/nestjs 0.0.5

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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/cjs/constants.js +7 -0
  4. package/cjs/decorators/context.decorator.js +30 -0
  5. package/cjs/enums/handler-paramtype.enum.js +12 -0
  6. package/cjs/factories/params.factory.js +29 -0
  7. package/cjs/factories/service.factory.js +164 -0
  8. package/cjs/index.js +9 -0
  9. package/cjs/interfaces/opra-execution-context.js +10 -0
  10. package/cjs/interfaces/opra-module-options.interface.js +2 -0
  11. package/cjs/opra-core.module.js +149 -0
  12. package/cjs/opra.module.js +25 -0
  13. package/cjs/package.json +3 -0
  14. package/cjs/services/nest-explorer.js +35 -0
  15. package/cjs/services/service-loader.js +88 -0
  16. package/cjs/types.js +2 -0
  17. package/cjs/utils/class.utils.js +25 -0
  18. package/cjs/utils/function.utils.js +23 -0
  19. package/cjs/utils/param.utils.js +22 -0
  20. package/esm/constants.d.ts +4 -0
  21. package/esm/constants.js +4 -0
  22. package/esm/decorators/context.decorator.d.ts +25 -0
  23. package/esm/decorators/context.decorator.js +27 -0
  24. package/esm/enums/handler-paramtype.enum.d.ts +8 -0
  25. package/esm/enums/handler-paramtype.enum.js +9 -0
  26. package/esm/factories/params.factory.d.ts +4 -0
  27. package/esm/factories/params.factory.js +25 -0
  28. package/esm/factories/service.factory.d.ts +15 -0
  29. package/esm/factories/service.factory.js +161 -0
  30. package/esm/index.d.ts +5 -0
  31. package/esm/index.js +6 -0
  32. package/esm/interfaces/opra-execution-context.d.ts +6 -0
  33. package/esm/interfaces/opra-execution-context.js +7 -0
  34. package/esm/interfaces/opra-module-options.interface.d.ts +49 -0
  35. package/esm/interfaces/opra-module-options.interface.js +1 -0
  36. package/esm/opra-core.module.d.ts +18 -0
  37. package/esm/opra-core.module.js +146 -0
  38. package/esm/opra.module.d.ts +6 -0
  39. package/esm/opra.module.js +22 -0
  40. package/esm/services/nest-explorer.d.ts +6 -0
  41. package/esm/services/nest-explorer.js +31 -0
  42. package/esm/services/service-loader.d.ts +18 -0
  43. package/esm/services/service-loader.js +84 -0
  44. package/esm/types.d.ts +2 -0
  45. package/esm/types.js +1 -0
  46. package/esm/utils/class.utils.d.ts +4 -0
  47. package/esm/utils/class.utils.js +19 -0
  48. package/esm/utils/function.utils.d.ts +1 -0
  49. package/esm/utils/function.utils.js +19 -0
  50. package/esm/utils/param.utils.d.ts +8 -0
  51. package/esm/utils/param.utils.js +18 -0
  52. package/package.json +73 -0
@@ -0,0 +1,22 @@
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
+ const args = Reflect.getMetadata(constants_js_1.PARAM_ARGS_METADATA, target.constructor, key) || {};
19
+ Reflect.defineMetadata(constants_js_1.PARAM_ARGS_METADATA, assignMetadata(args, paramType, index), target.constructor, key);
20
+ };
21
+ }
22
+ exports.createOpraParamDecorator = createOpraParamDecorator;
@@ -0,0 +1,4 @@
1
+ export declare const OPRA_MODULE_OPTIONS = "opra:module_options";
2
+ export declare const OPRA_MODULE_ID = "opra:module_id";
3
+ export declare const OPRA_INITIALIZER = "opra_initializer";
4
+ export declare const PARAM_ARGS_METADATA = "__routeArguments__";
@@ -0,0 +1,4 @@
1
+ export const OPRA_MODULE_OPTIONS = 'opra:module_options';
2
+ export const OPRA_MODULE_ID = 'opra:module_id';
3
+ export const OPRA_INITIALIZER = 'opra_initializer';
4
+ export const PARAM_ARGS_METADATA = '__routeArguments__';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Handler method parameter decorator. Populates the decorated
3
+ * parameter with the value of `ExecutionContext`.
4
+ */
5
+ export declare const Context: ParameterDecorator;
6
+ /**
7
+ * Handler method parameter decorator. Populates the decorated
8
+ * parameter with the value of `ExecutionRequest`.
9
+ */
10
+ export declare const Request: ParameterDecorator;
11
+ /**
12
+ * Handler method parameter decorator. Populates the decorated
13
+ * parameter with the value of `ExecutionResponse`.
14
+ */
15
+ export declare const Response: ParameterDecorator;
16
+ /**
17
+ * Handler method parameter decorator. Populates the decorated
18
+ * parameter with the value of `OpraService`.
19
+ */
20
+ export declare const Service: ParameterDecorator;
21
+ /**
22
+ * Handler method parameter decorator. Populates the decorated
23
+ * parameter with the value of `OpraService`.
24
+ */
25
+ export declare const Query: ParameterDecorator;
@@ -0,0 +1,27 @@
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 `ExecutionContext`.
6
+ */
7
+ export const Context = createOpraParamDecorator(HandlerParamType.CONTEXT);
8
+ /**
9
+ * Handler method parameter decorator. Populates the decorated
10
+ * parameter with the value of `ExecutionRequest`.
11
+ */
12
+ export const Request = createOpraParamDecorator(HandlerParamType.REQUEST);
13
+ /**
14
+ * Handler method parameter decorator. Populates the decorated
15
+ * parameter with the value of `ExecutionResponse`.
16
+ */
17
+ export const Response = createOpraParamDecorator(HandlerParamType.RESPONSE);
18
+ /**
19
+ * Handler method parameter decorator. Populates the decorated
20
+ * parameter with the value of `OpraService`.
21
+ */
22
+ export const Service = createOpraParamDecorator(HandlerParamType.SERVICE);
23
+ /**
24
+ * Handler method parameter decorator. Populates the decorated
25
+ * parameter with the value of `OpraService`.
26
+ */
27
+ export const Query = createOpraParamDecorator(HandlerParamType.QUERY);
@@ -0,0 +1,8 @@
1
+ export declare enum HandlerParamType {
2
+ CONTEXT = 0,
3
+ SERVICE = 1,
4
+ REQUEST = 2,
5
+ QUERY = 3,
6
+ RESPONSE = 4,
7
+ USER_CONTEXT = 5
8
+ }
@@ -0,0 +1,9 @@
1
+ export var HandlerParamType;
2
+ (function (HandlerParamType) {
3
+ HandlerParamType[HandlerParamType["CONTEXT"] = 0] = "CONTEXT";
4
+ HandlerParamType[HandlerParamType["SERVICE"] = 1] = "SERVICE";
5
+ HandlerParamType[HandlerParamType["REQUEST"] = 2] = "REQUEST";
6
+ HandlerParamType[HandlerParamType["QUERY"] = 3] = "QUERY";
7
+ HandlerParamType[HandlerParamType["RESPONSE"] = 4] = "RESPONSE";
8
+ HandlerParamType[HandlerParamType["USER_CONTEXT"] = 5] = "USER_CONTEXT";
9
+ })(HandlerParamType || (HandlerParamType = {}));
@@ -0,0 +1,4 @@
1
+ import { ParamsFactory } from '@nestjs/core/helpers/external-context-creator.js';
2
+ export declare class OpraParamsFactory implements ParamsFactory {
3
+ exchangeKeyForValue(type: number, data: any, args: any): any;
4
+ }
@@ -0,0 +1,25 @@
1
+ import { HandlerParamType } from '../enums/handler-paramtype.enum.js';
2
+ export class OpraParamsFactory {
3
+ exchangeKeyForValue(type, data, args) {
4
+ if (!args) {
5
+ return null;
6
+ }
7
+ args = Array.isArray(args) ? args : [];
8
+ switch (type) {
9
+ case HandlerParamType.CONTEXT:
10
+ return args[3];
11
+ case HandlerParamType.SERVICE:
12
+ return args[3].service;
13
+ case HandlerParamType.REQUEST:
14
+ return args[3].request;
15
+ case HandlerParamType.QUERY:
16
+ return args[3].request.query;
17
+ case HandlerParamType.RESPONSE:
18
+ return args[3].response;
19
+ case HandlerParamType.USER_CONTEXT:
20
+ return args[3].userContext;
21
+ default:
22
+ return null;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,15 @@
1
+ import { ContextType } from '@nestjs/common';
2
+ import { Module } from '@nestjs/core/injector/module.js';
3
+ import { OpraService } from '@opra/core';
4
+ import { OpraModuleOptions } from '../interfaces/opra-module-options.interface.js';
5
+ export declare class ServiceFactory {
6
+ private readonly paramsFactory;
7
+ private readonly injector;
8
+ private readonly modulesContainer;
9
+ private readonly externalContextCreator;
10
+ private readonly explorerService;
11
+ generateService(rootModule: Module, moduleOptions: OpraModuleOptions, contextType: ContextType): Promise<OpraService>;
12
+ private _createContextCallback;
13
+ private getContextId;
14
+ private registerContextProvider;
15
+ }
@@ -0,0 +1,161 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import _ from 'lodash';
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 { OpraService, RESOURCE_METADATA } from '@opra/core';
10
+ import { OpraSchema } from '@opra/schema';
11
+ import { PARAM_ARGS_METADATA } from '../constants.js';
12
+ import { HandlerParamType } from '../enums/handler-paramtype.enum.js';
13
+ import { NestExplorer } from '../services/nest-explorer.js';
14
+ import { getNumberOfArguments } from '../utils/function.utils.js';
15
+ import { OpraParamsFactory } from './params.factory.js';
16
+ const entityHandlers = ['search', 'create', 'read', 'update', 'updateMany', 'delete', 'deleteMany'];
17
+ const noOpFunction = () => void 0;
18
+ let ServiceFactory = class ServiceFactory {
19
+ paramsFactory = new OpraParamsFactory();
20
+ injector = new Injector();
21
+ modulesContainer;
22
+ externalContextCreator;
23
+ explorerService;
24
+ async generateService(rootModule, moduleOptions, contextType) {
25
+ const info = { title: '', version: '', ...moduleOptions.info };
26
+ info.title = info.title || 'Untitled service';
27
+ info.version = info.version || '1';
28
+ const serviceArgs = {
29
+ info,
30
+ types: [],
31
+ resources: [],
32
+ };
33
+ const wrappers = this.explorerService.exploreResourceWrappers(rootModule);
34
+ for (const wrapper of wrappers) {
35
+ const instance = wrapper.instance;
36
+ const resourceDef = Reflect.getMetadata(RESOURCE_METADATA, instance.constructor);
37
+ /* istanbul ignore next */
38
+ if (!resourceDef)
39
+ continue;
40
+ serviceArgs.resources.push(instance);
41
+ /* Wrap resolver functions */
42
+ const prototype = Object.getPrototypeOf(instance);
43
+ const isRequestScoped = !wrapper.isDependencyTreeStatic();
44
+ if (OpraSchema.isEntityResource(resourceDef)) {
45
+ for (const x of entityHandlers) {
46
+ const fn = instance[x];
47
+ if (typeof fn === 'function') {
48
+ const methodName = fn.name || x;
49
+ const callback = this._createContextCallback(instance, prototype, wrapper, rootModule, methodName, isRequestScoped, undefined, contextType);
50
+ const newFn = instance[x] = (ctx) => {
51
+ switch (ctx.type) {
52
+ case 'http':
53
+ const http = ctx.switchToHttp();
54
+ return callback(http.getRequest().getInstance(), http.getResponse().getInstance(), noOpFunction, ctx);
55
+ default:
56
+ throw new Error(`"${ctx.type}" context type is not implemented yet`);
57
+ }
58
+ };
59
+ if (methodName && newFn.name !== methodName)
60
+ Object.defineProperty(newFn, 'name', {
61
+ configurable: false,
62
+ writable: false,
63
+ enumerable: true,
64
+ value: methodName
65
+ });
66
+ }
67
+ }
68
+ }
69
+ }
70
+ return await OpraService.create(serviceArgs);
71
+ }
72
+ _createContextCallback(instance, prototype, wrapper, moduleRef, methodName, isRequestScoped, transform = _.identity, contextType) {
73
+ const paramsFactory = this.paramsFactory;
74
+ if (isRequestScoped) {
75
+ return async (...args) => {
76
+ const opraContext = paramsFactory.exchangeKeyForValue(HandlerParamType.CONTEXT, undefined, args);
77
+ const contextId = this.getContextId(opraContext);
78
+ this.registerContextProvider(opraContext, contextId);
79
+ const contextInstance = await this.injector.loadPerContext(instance, moduleRef, moduleRef.providers, contextId);
80
+ const callback = this.externalContextCreator.create(contextInstance, transform(contextInstance[methodName]), methodName, PARAM_ARGS_METADATA, paramsFactory, contextId, wrapper.id, undefined, // contextOptions
81
+ opraContext.type);
82
+ return callback(...args);
83
+ };
84
+ }
85
+ return this.externalContextCreator.create(instance, prototype[methodName], methodName, PARAM_ARGS_METADATA, paramsFactory, undefined, undefined, undefined, // contextOptions
86
+ contextType);
87
+ }
88
+ // noinspection JSMethodCanBeStatic
89
+ getContextId(gqlContext) {
90
+ const numberOfArguments = getNumberOfArguments(ContextIdFactory.getByRequest);
91
+ if (numberOfArguments === 2) {
92
+ // @ts-ignore
93
+ const contextId = ContextIdFactory.getByRequest(gqlContext, ['req']);
94
+ if (!gqlContext[REQUEST_CONTEXT_ID]) {
95
+ Object.defineProperty(gqlContext, REQUEST_CONTEXT_ID, {
96
+ value: contextId,
97
+ enumerable: false,
98
+ configurable: false,
99
+ writable: false,
100
+ });
101
+ }
102
+ return contextId;
103
+ }
104
+ else {
105
+ // TODO remove in the next version (backward-compatibility layer)
106
+ // Left for backward compatibility purposes
107
+ let contextId;
108
+ if (gqlContext && gqlContext[REQUEST_CONTEXT_ID]) {
109
+ contextId = gqlContext[REQUEST_CONTEXT_ID];
110
+ }
111
+ else if (gqlContext &&
112
+ gqlContext.req &&
113
+ gqlContext.req[REQUEST_CONTEXT_ID]) {
114
+ contextId = gqlContext.req[REQUEST_CONTEXT_ID];
115
+ }
116
+ else {
117
+ contextId = createContextId();
118
+ Object.defineProperty(gqlContext, REQUEST_CONTEXT_ID, {
119
+ value: contextId,
120
+ enumerable: false,
121
+ configurable: false,
122
+ writable: false,
123
+ });
124
+ }
125
+ return contextId;
126
+ }
127
+ }
128
+ registerContextProvider(request, contextId) {
129
+ const coreModuleArray = [...this.modulesContainer.entries()]
130
+ .filter(
131
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
132
+ ([key, { metatype }]) => metatype && metatype.name === InternalCoreModule.name)
133
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
134
+ .map(([key, value]) => value);
135
+ const coreModuleRef = _.head(coreModuleArray);
136
+ if (!coreModuleRef) {
137
+ return;
138
+ }
139
+ const wrapper = coreModuleRef.getProviderByKey(REQUEST);
140
+ wrapper.setInstanceByContextId(contextId, {
141
+ instance: request,
142
+ isResolved: true,
143
+ });
144
+ }
145
+ };
146
+ __decorate([
147
+ Inject(),
148
+ __metadata("design:type", ModulesContainer)
149
+ ], ServiceFactory.prototype, "modulesContainer", void 0);
150
+ __decorate([
151
+ Inject(),
152
+ __metadata("design:type", ExternalContextCreator)
153
+ ], ServiceFactory.prototype, "externalContextCreator", void 0);
154
+ __decorate([
155
+ Inject(),
156
+ __metadata("design:type", NestExplorer)
157
+ ], ServiceFactory.prototype, "explorerService", void 0);
158
+ ServiceFactory = __decorate([
159
+ Injectable()
160
+ ], ServiceFactory);
161
+ export { ServiceFactory };
package/esm/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import 'reflect-metadata';
2
+ export * from './opra.module.js';
3
+ export * from './decorators/context.decorator.js';
4
+ export * from './interfaces/opra-execution-context.js';
5
+ export * from './interfaces/opra-module-options.interface.js';
package/esm/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import 'reflect-metadata';
2
+ export * from './opra.module.js';
3
+ export * from './decorators/context.decorator.js';
4
+ export * from './interfaces/opra-execution-context.js';
5
+ export * from './interfaces/opra-module-options.interface.js';
6
+ // export * as Api from './decorators/api.ns.js';
@@ -0,0 +1,6 @@
1
+ import { ExecutionContext } from '@nestjs/common';
2
+ import * as Opra from '@opra/core';
3
+ export declare type OpraExecutionContext = Opra.ExecutionContext;
4
+ export declare namespace OpraExecutionContext {
5
+ function from(source: ExecutionContext): OpraExecutionContext;
6
+ }
@@ -0,0 +1,7 @@
1
+ export var OpraExecutionContext;
2
+ (function (OpraExecutionContext) {
3
+ function from(source) {
4
+ return source.getArgByIndex(4);
5
+ }
6
+ OpraExecutionContext.from = from;
7
+ })(OpraExecutionContext || (OpraExecutionContext = {}));
@@ -0,0 +1,49 @@
1
+ import { ModuleMetadata, Type } from '@nestjs/common';
2
+ import { FallbackLng, LanguageResource } from '@opra/i18n';
3
+ import { OpraSchema } from '@opra/schema';
4
+ export declare type OpraModuleOptions = {
5
+ /**
6
+ * @default true
7
+ */
8
+ useGlobalPrefix?: boolean;
9
+ prefix?: string;
10
+ info?: OpraSchema.DocumentInfo;
11
+ i18n?: I18nInitOptions;
12
+ context?: object | ((request: any, platformName: string) => object | Promise<object>);
13
+ };
14
+ export interface I18nInitOptions {
15
+ /**
16
+ * Language to use
17
+ * @default undefined
18
+ */
19
+ lng?: string;
20
+ /**
21
+ * Language to use if translations in user language are not available.
22
+ * @default 'dev'
23
+ */
24
+ fallbackLng?: false | FallbackLng;
25
+ /**
26
+ * Default namespace used if not passed to translation function
27
+ * @default 'translation'
28
+ */
29
+ defaultNS?: string;
30
+ /**
31
+ * Resources to initialize with
32
+ * @default undefined
33
+ */
34
+ resources?: LanguageResource;
35
+ /**
36
+ * Resource directories to initialize with (if not using loading or not appending using addResourceBundle)
37
+ * @default undefined
38
+ */
39
+ resourceDirs?: string[];
40
+ }
41
+ export interface OpraModuleOptionsFactory {
42
+ createOptions(): Promise<OpraModuleOptions> | OpraModuleOptions;
43
+ }
44
+ export interface OpraModuleAsyncOptions extends Pick<ModuleMetadata, 'imports' | 'providers'> {
45
+ useExisting?: Type<OpraModuleOptionsFactory>;
46
+ useClass?: Type<OpraModuleOptionsFactory>;
47
+ useFactory?: (...args: any[]) => Promise<OpraModuleOptions> | OpraModuleOptions;
48
+ inject?: any[];
49
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import { DynamicModule, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
+ import { HttpAdapterHost, ModulesContainer } from '@nestjs/core';
3
+ import { OpraModuleAsyncOptions, OpraModuleOptions } from './interfaces/opra-module-options.interface.js';
4
+ import { OpraServiceLoader } from './services/service-loader.js';
5
+ export declare class OpraCoreModule implements OnModuleInit, OnModuleDestroy {
6
+ private readonly httpAdapterHost;
7
+ protected readonly modulesContainer: ModulesContainer;
8
+ private readonly options;
9
+ private readonly opraServiceLoader;
10
+ constructor(httpAdapterHost: HttpAdapterHost, modulesContainer: ModulesContainer, options: OpraModuleOptions, opraServiceLoader: OpraServiceLoader);
11
+ static forRoot(options: OpraModuleOptions & Pick<DynamicModule, 'imports' | 'providers' | 'exports'>): DynamicModule;
12
+ static forRootAsync(asyncOptions: OpraModuleAsyncOptions): DynamicModule;
13
+ private static createI18nProvider;
14
+ private static createAsyncProviders;
15
+ private static createAsyncOptionsProvider;
16
+ onModuleInit(): Promise<void>;
17
+ onModuleDestroy(): Promise<void>;
18
+ }
@@ -0,0 +1,146 @@
1
+ var OpraCoreModule_1;
2
+ import { __decorate, __metadata, __param } from "tslib";
3
+ import * as crypto from 'crypto';
4
+ import { Inject, Module } from '@nestjs/common';
5
+ import { HttpAdapterHost, ModulesContainer } from '@nestjs/core';
6
+ import { MetadataScanner } from '@nestjs/core/metadata-scanner';
7
+ import { I18n } from '@opra/i18n';
8
+ import { OPRA_INITIALIZER, OPRA_MODULE_ID, OPRA_MODULE_OPTIONS } from './constants.js';
9
+ import { ServiceFactory } from './factories/service.factory.js';
10
+ import { NestExplorer } from './services/nest-explorer.js';
11
+ import { OpraServiceLoader } from './services/service-loader.js';
12
+ let OpraCoreModule = OpraCoreModule_1 = class OpraCoreModule {
13
+ httpAdapterHost;
14
+ modulesContainer;
15
+ options;
16
+ opraServiceLoader;
17
+ constructor(httpAdapterHost, modulesContainer, options, opraServiceLoader) {
18
+ this.httpAdapterHost = httpAdapterHost;
19
+ this.modulesContainer = modulesContainer;
20
+ this.options = options;
21
+ this.opraServiceLoader = opraServiceLoader;
22
+ }
23
+ static forRoot(options) {
24
+ return {
25
+ module: OpraCoreModule_1,
26
+ imports: [...(options.imports || [])],
27
+ providers: [
28
+ ...(options.providers || []),
29
+ {
30
+ provide: OPRA_MODULE_OPTIONS,
31
+ useValue: options,
32
+ },
33
+ {
34
+ provide: OPRA_INITIALIZER,
35
+ useClass: OpraServiceLoader
36
+ },
37
+ this.createI18nProvider()
38
+ ],
39
+ exports: [...(options.exports || [])]
40
+ };
41
+ }
42
+ static forRootAsync(asyncOptions) {
43
+ return {
44
+ module: OpraCoreModule_1,
45
+ imports: [...(asyncOptions.imports || [])],
46
+ providers: [
47
+ ...(asyncOptions.providers || []),
48
+ {
49
+ provide: OPRA_MODULE_ID,
50
+ useValue: crypto.randomUUID()
51
+ },
52
+ {
53
+ provide: OPRA_INITIALIZER,
54
+ useClass: OpraServiceLoader
55
+ },
56
+ ...this.createAsyncProviders(asyncOptions),
57
+ this.createI18nProvider(),
58
+ ]
59
+ };
60
+ }
61
+ static createI18nProvider() {
62
+ return {
63
+ provide: I18n,
64
+ inject: [OPRA_MODULE_OPTIONS],
65
+ useFactory: async (options) => {
66
+ const opts = options.i18n;
67
+ const initOptions = {
68
+ lng: opts?.lng,
69
+ fallbackLng: opts?.fallbackLng,
70
+ defaultNS: opts?.defaultNS,
71
+ resources: opts?.resources,
72
+ resourceDirs: opts?.resourceDirs
73
+ };
74
+ const instance = I18n.createInstance();
75
+ await instance.init(initOptions);
76
+ return instance;
77
+ }
78
+ };
79
+ }
80
+ static createAsyncProviders(asyncOptions) {
81
+ if (asyncOptions.useExisting || asyncOptions.useFactory)
82
+ return [this.createAsyncOptionsProvider(asyncOptions)];
83
+ if (asyncOptions.useClass)
84
+ return [
85
+ this.createAsyncOptionsProvider(asyncOptions),
86
+ {
87
+ provide: asyncOptions.useClass,
88
+ useClass: asyncOptions.useClass
89
+ }
90
+ ];
91
+ throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
92
+ }
93
+ static createAsyncOptionsProvider(asyncOptions) {
94
+ if (asyncOptions.useFactory) {
95
+ return {
96
+ provide: OPRA_MODULE_OPTIONS,
97
+ useFactory: asyncOptions.useFactory,
98
+ inject: asyncOptions.inject || []
99
+ };
100
+ }
101
+ const useClass = asyncOptions.useClass || asyncOptions.useExisting;
102
+ if (useClass) {
103
+ return {
104
+ provide: OPRA_MODULE_OPTIONS,
105
+ useFactory: (optionsFactory) => optionsFactory.createOptions(),
106
+ inject: [useClass]
107
+ };
108
+ }
109
+ throw new Error('Invalid configuration. Must provide useFactory, useClass or useExisting');
110
+ }
111
+ async onModuleInit() {
112
+ const httpAdapter = this.httpAdapterHost?.httpAdapter;
113
+ if (!httpAdapter)
114
+ return;
115
+ const opraModule = (() => {
116
+ for (const m of this.modulesContainer.values()) {
117
+ for (const imp of m.imports.values()) {
118
+ for (const prv of imp.providers.values())
119
+ if (prv.instance === this) {
120
+ return imp;
121
+ }
122
+ }
123
+ }
124
+ })();
125
+ if (opraModule) {
126
+ await this.opraServiceLoader.initialize(opraModule);
127
+ }
128
+ }
129
+ async onModuleDestroy() {
130
+ await this.opraServiceLoader.stop();
131
+ }
132
+ };
133
+ OpraCoreModule = OpraCoreModule_1 = __decorate([
134
+ Module({
135
+ providers: [
136
+ ServiceFactory,
137
+ MetadataScanner,
138
+ NestExplorer
139
+ ]
140
+ }),
141
+ __param(2, Inject(OPRA_MODULE_OPTIONS)),
142
+ __param(3, Inject(OPRA_INITIALIZER)),
143
+ __metadata("design:paramtypes", [HttpAdapterHost,
144
+ ModulesContainer, Object, OpraServiceLoader])
145
+ ], OpraCoreModule);
146
+ export { OpraCoreModule };
@@ -0,0 +1,6 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { OpraModuleAsyncOptions, OpraModuleOptions } from './interfaces/opra-module-options.interface.js';
3
+ export declare class OpraModule {
4
+ static forRoot(options: OpraModuleOptions & Pick<DynamicModule, 'imports' | 'providers' | 'exports'>): DynamicModule;
5
+ static forRootAsync(asyncOptions: OpraModuleAsyncOptions): DynamicModule;
6
+ }
@@ -0,0 +1,22 @@
1
+ var OpraModule_1;
2
+ import { __decorate } from "tslib";
3
+ import { Module } from '@nestjs/common';
4
+ import { OpraCoreModule } from './opra-core.module.js';
5
+ let OpraModule = OpraModule_1 = class OpraModule {
6
+ static forRoot(options) {
7
+ return {
8
+ module: OpraModule_1,
9
+ imports: [OpraCoreModule.forRoot(options)]
10
+ };
11
+ }
12
+ static forRootAsync(asyncOptions) {
13
+ return {
14
+ module: OpraModule_1,
15
+ imports: [OpraCoreModule.forRootAsync(asyncOptions)]
16
+ };
17
+ }
18
+ };
19
+ OpraModule = OpraModule_1 = __decorate([
20
+ Module({})
21
+ ], OpraModule);
22
+ export { OpraModule };
@@ -0,0 +1,6 @@
1
+ import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
2
+ import { Module } from '@nestjs/core/injector/module';
3
+ export declare class NestExplorer {
4
+ exploreProviders(rootModule: Module, predicate: (wrapper: InstanceWrapper) => boolean): InstanceWrapper<any>[];
5
+ exploreResourceWrappers(rootModule: Module): InstanceWrapper[];
6
+ }
@@ -0,0 +1,31 @@
1
+ import { RESOURCE_METADATA } from '@opra/core';
2
+ export class NestExplorer {
3
+ exploreProviders(rootModule, predicate) {
4
+ const modules = new Set();
5
+ const wrappers = new Set();
6
+ const scanModules = (m) => {
7
+ if (modules.has(m))
8
+ return;
9
+ modules.add(m);
10
+ for (const mm of m.imports.values()) {
11
+ scanModules(mm);
12
+ }
13
+ for (const wrapper of m.providers.values()) {
14
+ if (!wrappers.has(wrapper) && predicate(wrapper))
15
+ wrappers.add(wrapper);
16
+ if (wrapper.host)
17
+ scanModules(wrapper.host);
18
+ }
19
+ };
20
+ scanModules(rootModule);
21
+ return Array.from(wrappers.values());
22
+ }
23
+ exploreResourceWrappers(rootModule) {
24
+ return this.exploreProviders(rootModule, (wrapper) => {
25
+ return !!(wrapper.instance
26
+ && typeof wrapper.instance === 'object'
27
+ && wrapper.instance.constructor
28
+ && Reflect.hasMetadata(RESOURCE_METADATA, wrapper.instance.constructor));
29
+ });
30
+ }
31
+ }
@@ -0,0 +1,18 @@
1
+ import { ApplicationConfig, HttpAdapterHost } from '@nestjs/core';
2
+ import { Module } from '@nestjs/core/injector/module.js';
3
+ import { OpraExpressAdapter, OpraService } from '@opra/core';
4
+ import { I18n } from '@opra/i18n';
5
+ import { ServiceFactory } from '../factories/service.factory.js';
6
+ import { OpraModuleOptions } from '../interfaces/opra-module-options.interface.js';
7
+ export declare class OpraServiceLoader {
8
+ private readonly logger;
9
+ private adapter;
10
+ protected readonly httpAdapterHost: HttpAdapterHost;
11
+ protected readonly applicationConfig: ApplicationConfig;
12
+ protected readonly opraFactory: ServiceFactory;
13
+ protected readonly opraModuleOptions: OpraModuleOptions;
14
+ protected readonly i18n: I18n;
15
+ initialize(rootModule: Module): Promise<void>;
16
+ stop(): Promise<void>;
17
+ protected registerExpress(service: OpraService, moduleOptions: OpraModuleOptions): Promise<OpraExpressAdapter | undefined>;
18
+ }