awilixify 2.2.1 → 3.0.0
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 +12 -6
- package/dist/index.d.ts +18 -0
- package/dist/index.js +15 -0
- package/dist/lib/decorators/decorator-state.d.ts +15 -0
- package/dist/lib/decorators/decorator-state.js +72 -0
- package/dist/lib/decorators/decorator-state.types.d.ts +35 -0
- package/dist/lib/decorators/decorator-state.types.js +1 -0
- package/dist/lib/di/common.types.d.ts +6 -0
- package/dist/lib/di/common.types.js +1 -0
- package/dist/lib/di/contexts/container-context-base.d.ts +53 -0
- package/dist/lib/di/contexts/container-context-base.js +194 -0
- package/dist/lib/di/contexts/context-overrides.d.ts +22 -0
- package/dist/lib/di/contexts/context-overrides.js +93 -0
- package/dist/lib/di/contexts/di-context-async.d.ts +14 -0
- package/dist/lib/di/contexts/di-context-async.js +112 -0
- package/dist/lib/di/contexts/di-context-base.d.ts +19 -0
- package/dist/lib/di/contexts/di-context-base.js +32 -0
- package/dist/lib/di/contexts/di-context.d.ts +7 -0
- package/dist/lib/di/contexts/di-context.js +9 -0
- package/dist/lib/di/contexts/module-graph-ensurer.d.ts +31 -0
- package/dist/lib/di/contexts/module-graph-ensurer.js +45 -0
- package/dist/lib/di/contexts/module-overrides.d.ts +70 -0
- package/dist/lib/di/contexts/module-overrides.js +3 -0
- package/dist/lib/di/contexts/override-value.types.d.ts +6 -0
- package/dist/lib/di/contexts/override-value.types.js +1 -0
- package/dist/lib/di/contexts/overrides-processor.d.ts +22 -0
- package/dist/lib/di/contexts/overrides-processor.js +93 -0
- package/dist/lib/di/contexts/provider-overrides.types.d.ts +19 -0
- package/dist/lib/di/contexts/provider-overrides.types.js +1 -0
- package/dist/lib/di/errors.d.ts +66 -0
- package/dist/lib/di/errors.js +148 -0
- package/dist/lib/di/modules/module-def.types.d.ts +117 -0
- package/dist/lib/di/modules/module-def.types.js +1 -0
- package/dist/lib/di/modules/module-factories.d.ts +16 -0
- package/dist/lib/di/modules/module-factories.js +46 -0
- package/dist/lib/di/modules/module-overrides.d.ts +70 -0
- package/dist/lib/di/modules/module-overrides.js +3 -0
- package/dist/lib/di/modules/module-ref.types.d.ts +13 -0
- package/dist/lib/di/modules/module-ref.types.js +1 -0
- package/dist/lib/di/modules/module.types.d.ts +178 -0
- package/dist/lib/di/modules/module.types.js +1 -0
- package/dist/lib/di/modules/provider-overrides.types.d.ts +19 -0
- package/dist/lib/di/modules/provider-overrides.types.js +1 -0
- package/dist/lib/di/modules/runtime-module.types.d.ts +25 -0
- package/dist/lib/di/modules/runtime-module.types.js +1 -0
- package/dist/lib/di/processors/controller-processor.d.ts +13 -0
- package/dist/lib/di/processors/controller-processor.js +76 -0
- package/dist/lib/di/processors/handler-processor.d.ts +15 -0
- package/dist/lib/di/processors/handler-processor.js +69 -0
- package/dist/lib/di/processors/initializer-processor.d.ts +19 -0
- package/dist/lib/di/processors/initializer-processor.js +91 -0
- package/dist/lib/di/processors/interceptor-processor.d.ts +18 -0
- package/dist/lib/di/processors/interceptor-processor.js +101 -0
- package/dist/lib/di/processors/keyed-feature-registrar.d.ts +19 -0
- package/dist/lib/di/processors/keyed-feature-registrar.js +112 -0
- package/dist/lib/di/processors/lifecycle-processor.d.ts +38 -0
- package/dist/lib/di/processors/lifecycle-processor.js +178 -0
- package/dist/lib/di/processors/overrides-processor.d.ts +24 -0
- package/dist/lib/di/processors/overrides-processor.js +69 -0
- package/dist/lib/di/providers/basic-provider-resolver.d.ts +35 -0
- package/dist/lib/di/providers/basic-provider-resolver.js +88 -0
- package/dist/lib/di/providers/provider-dependency-sorter.d.ts +9 -0
- package/dist/lib/di/providers/provider-dependency-sorter.js +76 -0
- package/dist/lib/di/providers/provider-resolver.d.ts +31 -0
- package/dist/lib/di/providers/provider-resolver.js +128 -0
- package/dist/lib/di/providers/provider.types.d.ts +1 -0
- package/dist/lib/di/providers/provider.types.js +1 -0
- package/dist/lib/di/providers/types/controller.types.d.ts +9 -0
- package/dist/lib/di/providers/types/controller.types.js +1 -0
- package/dist/lib/di/providers/types/decorator-context.types.d.ts +9 -0
- package/dist/lib/di/providers/types/decorator-context.types.js +1 -0
- package/dist/lib/di/providers/types/handler.types.d.ts +9 -0
- package/dist/lib/di/providers/types/handler.types.js +1 -0
- package/dist/lib/di/providers/types/index.d.ts +7 -0
- package/dist/lib/di/providers/types/index.js +7 -0
- package/dist/lib/di/providers/types/initializer.types.d.ts +16 -0
- package/dist/lib/di/providers/types/initializer.types.js +3 -0
- package/dist/lib/di/providers/types/interceptor.types.d.ts +18 -0
- package/dist/lib/di/providers/types/interceptor.types.js +1 -0
- package/dist/lib/di/providers/types/middleware.types.d.ts +10 -0
- package/dist/lib/di/providers/types/middleware.types.js +1 -0
- package/dist/lib/di/providers/types/provider.types.d.ts +26 -0
- package/dist/lib/di/providers/types/provider.types.js +1 -0
- package/dist/lib/di/request-scope-context.d.ts +5 -0
- package/dist/lib/di/request-scope-context.js +28 -0
- package/dist/lib/di/type-guards.d.ts +35 -0
- package/dist/lib/di/type-guards.js +84 -0
- package/dist/lib/http/decorators.d.ts +33 -0
- package/dist/lib/http/decorators.js +151 -0
- package/dist/lib/http/exceptions.d.ts +58 -0
- package/dist/lib/http/exceptions.js +71 -0
- package/dist/lib/http/http-verbs.d.ts +12 -0
- package/dist/lib/http/http-verbs.js +11 -0
- package/dist/lib/http/index.d.ts +3 -0
- package/dist/lib/http/index.js +3 -0
- package/dist/lib/http/openapi-builder.d.ts +27 -0
- package/dist/lib/http/openapi-builder.js +83 -0
- package/dist/lib/mediator/contract.types.d.ts +159 -0
- package/dist/lib/mediator/contract.types.js +1 -0
- package/dist/lib/mediator/errors.d.ts +15 -0
- package/dist/lib/mediator/errors.js +33 -0
- package/dist/lib/mediator/global-middlewares.types.d.ts +13 -0
- package/dist/lib/mediator/global-middlewares.types.js +1 -0
- package/dist/lib/mediator/handler.types.d.ts +16 -0
- package/dist/lib/mediator/handler.types.js +1 -0
- package/dist/lib/mediator/mediator.d.ts +21 -0
- package/dist/lib/mediator/mediator.js +123 -0
- package/dist/lib/mediator/mediator.types.d.ts +64 -0
- package/dist/lib/mediator/mediator.types.js +1 -0
- package/dist/lib/mediator/middleware.types.d.ts +41 -0
- package/dist/lib/mediator/middleware.types.js +1 -0
- package/dist/lib/mediator/result.d.ts +18 -0
- package/dist/lib/mediator/result.js +24 -0
- package/dist/lib/react/errors.d.ts +12 -0
- package/dist/lib/react/errors.js +24 -0
- package/dist/lib/react/react-component-processor.d.ts +10 -0
- package/dist/lib/react/react-component-processor.js +62 -0
- package/dist/lib/react/react-di-context.d.ts +21 -0
- package/dist/lib/react/react-di-context.js +55 -0
- package/dist/lib/react/react-module-factories.d.ts +6 -0
- package/dist/lib/react/react-module-factories.js +34 -0
- package/dist/lib/react/react-module.types.d.ts +183 -0
- package/dist/lib/react/react-module.types.js +1 -0
- package/dist/react.d.ts +4 -0
- package/dist/react.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +29 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
|
|
3
|
+
import type { ControllerRuntimeEntry } from "./initializer-processor.js";
|
|
4
|
+
import type { InterceptorProcessor } from "./interceptor-processor.js";
|
|
5
|
+
export declare class ControllerProcessor {
|
|
6
|
+
private readonly interceptorProcessor;
|
|
7
|
+
private readonly providerOptions;
|
|
8
|
+
private readonly skipRegisterRoutes;
|
|
9
|
+
private readonly registeredControllers;
|
|
10
|
+
constructor(interceptorProcessor: InterceptorProcessor, providerOptions: Partial<Awilix.BuildResolverOptions<any>>, skipRegisterRoutes: boolean);
|
|
11
|
+
processControllers(m: M, diScope: Awilix.AwilixContainer): ControllerRuntimeEntry[];
|
|
12
|
+
private resolveBySymbol;
|
|
13
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import * as ERRORS from "../errors.js";
|
|
3
|
+
import { resolveFromRequestScope } from "../request-scope-context.js";
|
|
4
|
+
import { hasUseClass } from "../type-guards.js";
|
|
5
|
+
export class ControllerProcessor {
|
|
6
|
+
interceptorProcessor;
|
|
7
|
+
providerOptions;
|
|
8
|
+
skipRegisterRoutes;
|
|
9
|
+
registeredControllers = new WeakMap();
|
|
10
|
+
constructor(interceptorProcessor, providerOptions, skipRegisterRoutes) {
|
|
11
|
+
this.interceptorProcessor = interceptorProcessor;
|
|
12
|
+
this.providerOptions = providerOptions;
|
|
13
|
+
this.skipRegisterRoutes = skipRegisterRoutes;
|
|
14
|
+
}
|
|
15
|
+
processControllers(m, diScope) {
|
|
16
|
+
if (!m.controllers?.length)
|
|
17
|
+
return [];
|
|
18
|
+
if (m.registerControllers === false)
|
|
19
|
+
return [];
|
|
20
|
+
const runtimeEntries = [];
|
|
21
|
+
if (new Set(m.controllers).size !== m.controllers.length) {
|
|
22
|
+
throw new ERRORS.DuplicateControllersInModuleError(m.name);
|
|
23
|
+
}
|
|
24
|
+
for (const c of m.controllers) {
|
|
25
|
+
const { useClass, ...awilixOptions } = hasUseClass(c)
|
|
26
|
+
? c
|
|
27
|
+
: { useClass: c };
|
|
28
|
+
const existingModule = this.registeredControllers.get(useClass);
|
|
29
|
+
if (!existingModule) {
|
|
30
|
+
this.registeredControllers.set(useClass, m);
|
|
31
|
+
const controllerSymbol = Symbol(`controller_${useClass.name}`);
|
|
32
|
+
const options = {
|
|
33
|
+
...this.providerOptions,
|
|
34
|
+
...m.providerOptions,
|
|
35
|
+
...awilixOptions,
|
|
36
|
+
};
|
|
37
|
+
const isWithNewScope = options.lifetime !== Awilix.Lifetime.SINGLETON;
|
|
38
|
+
const baseResolver = Awilix.asClass(useClass, {
|
|
39
|
+
...options,
|
|
40
|
+
...(isWithNewScope && {
|
|
41
|
+
injector: () => ({
|
|
42
|
+
resolveSelf: () => this.resolveBySymbol(controllerSymbol, diScope, isWithNewScope),
|
|
43
|
+
}),
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
diScope.register({
|
|
47
|
+
[controllerSymbol]: this.interceptorProcessor.createInterceptedProviderResolver({
|
|
48
|
+
module: m,
|
|
49
|
+
useClass,
|
|
50
|
+
options,
|
|
51
|
+
resolver: baseResolver,
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
if (!this.skipRegisterRoutes &&
|
|
55
|
+
typeof useClass.prototype.registerRoutes === "function") {
|
|
56
|
+
baseResolver.resolve(diScope).registerRoutes();
|
|
57
|
+
}
|
|
58
|
+
runtimeEntries.push({
|
|
59
|
+
controllerClass: useClass,
|
|
60
|
+
resolve: () => this.resolveBySymbol(controllerSymbol, diScope, isWithNewScope),
|
|
61
|
+
});
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (existingModule === m) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
throw new ERRORS.ControllerAlreadyRegisteredError(useClass.name, existingModule.name);
|
|
68
|
+
}
|
|
69
|
+
return runtimeEntries;
|
|
70
|
+
}
|
|
71
|
+
resolveBySymbol(symbol, scope, withNewScope) {
|
|
72
|
+
if (withNewScope)
|
|
73
|
+
return resolveFromRequestScope(scope, symbol);
|
|
74
|
+
return scope.resolve(symbol);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import type { RegisteredModuleScope } from "../contexts/container-context-base.js";
|
|
3
|
+
import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
|
|
4
|
+
export declare const HandlerType: {
|
|
5
|
+
readonly Query: "query";
|
|
6
|
+
readonly Command: "command";
|
|
7
|
+
};
|
|
8
|
+
export type HandlerType = (typeof HandlerType)[keyof typeof HandlerType];
|
|
9
|
+
export declare class HandlerProcessor {
|
|
10
|
+
private readonly providerOptions;
|
|
11
|
+
private readonly keyedFeatureRegistrar;
|
|
12
|
+
private static readonly handlerConfig;
|
|
13
|
+
constructor(providerOptions: Partial<Awilix.BuildResolverOptions<any>>);
|
|
14
|
+
processHandlers(m: M, scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[], handlerType: HandlerType): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import { Mediator } from "../../mediator/mediator.js";
|
|
3
|
+
import * as ERRORS from "../errors.js";
|
|
4
|
+
import { ProviderResolver } from "../providers/provider-resolver.js";
|
|
5
|
+
import { getOrCreateRequestScope } from "../request-scope-context.js";
|
|
6
|
+
import { hasUseClass } from "../type-guards.js";
|
|
7
|
+
import { KeyedFeatureRegistrar } from "./keyed-feature-registrar.js";
|
|
8
|
+
export const HandlerType = {
|
|
9
|
+
Query: "query",
|
|
10
|
+
Command: "command",
|
|
11
|
+
};
|
|
12
|
+
export class HandlerProcessor {
|
|
13
|
+
providerOptions;
|
|
14
|
+
keyedFeatureRegistrar;
|
|
15
|
+
static handlerConfig = {
|
|
16
|
+
query: {
|
|
17
|
+
handlersKey: "queryHandlers",
|
|
18
|
+
preHandlersKey: "queryPreHandlers",
|
|
19
|
+
mediatorKey: "queryMediator",
|
|
20
|
+
},
|
|
21
|
+
command: {
|
|
22
|
+
handlersKey: "commandHandlers",
|
|
23
|
+
preHandlersKey: "commandPreHandlers",
|
|
24
|
+
mediatorKey: "commandMediator",
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
constructor(providerOptions) {
|
|
28
|
+
this.providerOptions = providerOptions;
|
|
29
|
+
this.keyedFeatureRegistrar = new KeyedFeatureRegistrar(providerOptions);
|
|
30
|
+
}
|
|
31
|
+
processHandlers(m, scope, importedModulesWithScope, handlerType) {
|
|
32
|
+
const { handlersKey, mediatorKey, preHandlersKey } = HandlerProcessor.handlerConfig[handlerType];
|
|
33
|
+
const middlewareResolvers = this.keyedFeatureRegistrar.register({
|
|
34
|
+
featureKind: preHandlersKey,
|
|
35
|
+
module: m,
|
|
36
|
+
scope,
|
|
37
|
+
importedModulesWithScope,
|
|
38
|
+
});
|
|
39
|
+
const handlers = m[handlersKey];
|
|
40
|
+
if (!handlers?.length)
|
|
41
|
+
return;
|
|
42
|
+
const mediator = new Mediator(middlewareResolvers, m.name);
|
|
43
|
+
for (const h of handlers) {
|
|
44
|
+
const { useClass: HandlerClass, ...handlerOptions } = hasUseClass(h)
|
|
45
|
+
? h
|
|
46
|
+
: { useClass: h };
|
|
47
|
+
const handlerKey = HandlerClass.key;
|
|
48
|
+
if (typeof handlerKey !== "string" || !handlerKey.length) {
|
|
49
|
+
throw new ERRORS.HandlerMissingStaticKeyError(HandlerClass.name);
|
|
50
|
+
}
|
|
51
|
+
const options = ProviderResolver.mergeResolverOptions(m, this.providerOptions, handlerOptions);
|
|
52
|
+
const handlerSymbol = Symbol(`${handlerKey}_${HandlerClass.name}`);
|
|
53
|
+
scope.register({
|
|
54
|
+
[handlerSymbol]: Awilix.asClass(HandlerClass, options),
|
|
55
|
+
});
|
|
56
|
+
mediator.register(handlerKey, (payload, context) => {
|
|
57
|
+
const requestScope = options.lifetime === Awilix.Lifetime.SINGLETON
|
|
58
|
+
? scope
|
|
59
|
+
: getOrCreateRequestScope(scope);
|
|
60
|
+
return requestScope
|
|
61
|
+
.resolve(handlerSymbol)
|
|
62
|
+
.executor(payload, context);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
scope.register({
|
|
66
|
+
[mediatorKey]: Awilix.asValue(mediator),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as Awilix from "awilix";
|
|
2
|
+
import type { RegisteredModuleScope } from "../contexts/container-context-base.js";
|
|
3
|
+
import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
|
|
4
|
+
import type { ConstructorController } from "../providers/provider.types.js";
|
|
5
|
+
import type { ModuleInitOptions } from "./lifecycle-processor.js";
|
|
6
|
+
export type ControllerRuntimeEntry = {
|
|
7
|
+
controllerClass: ConstructorController;
|
|
8
|
+
resolve: () => any;
|
|
9
|
+
};
|
|
10
|
+
export type InitializerTask = (options?: ModuleInitOptions) => Promise<void>;
|
|
11
|
+
export declare class InitializerProcessor {
|
|
12
|
+
private readonly keyedFeatureRegistrar;
|
|
13
|
+
private readonly resolversByModule;
|
|
14
|
+
collectInitializers(m: M, scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[], controllers: ControllerRuntimeEntry[]): InitializerTask | null;
|
|
15
|
+
private ensureNoMultiInvokableInitializersPerMethod;
|
|
16
|
+
private filterActiveInitializers;
|
|
17
|
+
private processInitializerResolvers;
|
|
18
|
+
private getControllerMethodNames;
|
|
19
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { resolveDecoratorState } from "../../decorators/decorator-state.js";
|
|
2
|
+
import * as ERRORS from "../errors.js";
|
|
3
|
+
import { runInRequestScopeContext } from "../request-scope-context.js";
|
|
4
|
+
import { KeyedFeatureRegistrar } from "./keyed-feature-registrar.js";
|
|
5
|
+
export class InitializerProcessor {
|
|
6
|
+
keyedFeatureRegistrar = new KeyedFeatureRegistrar({});
|
|
7
|
+
resolversByModule = new WeakMap();
|
|
8
|
+
collectInitializers(m, scope, importedModulesWithScope, controllers) {
|
|
9
|
+
this.processInitializerResolvers(m, scope, importedModulesWithScope);
|
|
10
|
+
const initializers = [
|
|
11
|
+
...(this.resolversByModule.get(m) ??
|
|
12
|
+
new Map()).entries(),
|
|
13
|
+
];
|
|
14
|
+
if (initializers.length === 0 || controllers.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
return async (options) => {
|
|
17
|
+
const activeInitializers = this.filterActiveInitializers(initializers, options);
|
|
18
|
+
if (activeInitializers.length === 0)
|
|
19
|
+
return;
|
|
20
|
+
for (const controller of controllers) {
|
|
21
|
+
for (const methodName of this.getControllerMethodNames(controller.controllerClass)) {
|
|
22
|
+
const invoke = (...args) => runInRequestScopeContext(() => controller.resolve()[methodName](...args));
|
|
23
|
+
this.ensureNoMultiInvokableInitializersPerMethod(m.name, methodName, controller, activeInitializers);
|
|
24
|
+
for (const [, resolveInitializer] of activeInitializers) {
|
|
25
|
+
const initializer = resolveInitializer();
|
|
26
|
+
const decoratorState = resolveDecoratorState(controller.controllerClass, initializer.token);
|
|
27
|
+
if (decoratorState === null)
|
|
28
|
+
continue;
|
|
29
|
+
const metadata = decoratorState.methods.get(methodName);
|
|
30
|
+
if (metadata === undefined)
|
|
31
|
+
continue;
|
|
32
|
+
await initializer.initialize({
|
|
33
|
+
moduleName: m.name,
|
|
34
|
+
target: controller.controllerClass,
|
|
35
|
+
methodName,
|
|
36
|
+
metadata,
|
|
37
|
+
decoratorState,
|
|
38
|
+
...(initializer.usesInvoke ? { invoke } : {}),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
ensureNoMultiInvokableInitializersPerMethod(moduleName, methodName, controller, initializers) {
|
|
46
|
+
const invokableInitializers = initializers
|
|
47
|
+
.map(([, resolver]) => resolver())
|
|
48
|
+
.filter((initializer) => {
|
|
49
|
+
const decoratorState = resolveDecoratorState(controller.controllerClass, initializer.token);
|
|
50
|
+
return (decoratorState?.methods.has(methodName) === true &&
|
|
51
|
+
initializer.usesInvoke === true);
|
|
52
|
+
});
|
|
53
|
+
if (invokableInitializers.length > 1) {
|
|
54
|
+
throw new ERRORS.MultipleInvokeInitializersPerMethodError(moduleName, controller.controllerClass.name, String(methodName), invokableInitializers.map((initializer) => initializer.constructor.name));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
filterActiveInitializers(initializers, options) {
|
|
58
|
+
if (options?.excludeInitializers === true)
|
|
59
|
+
return [];
|
|
60
|
+
if (!Array.isArray(options?.excludeInitializers))
|
|
61
|
+
return initializers;
|
|
62
|
+
const excludedKeys = new Set(options.excludeInitializers);
|
|
63
|
+
return initializers.filter(([key]) => !excludedKeys.has(key));
|
|
64
|
+
}
|
|
65
|
+
processInitializerResolvers(m, scope, importedModulesWithScope) {
|
|
66
|
+
this.resolversByModule.set(m, this.keyedFeatureRegistrar.register({
|
|
67
|
+
featureKind: "initializers",
|
|
68
|
+
module: m,
|
|
69
|
+
scope,
|
|
70
|
+
importedModulesWithScope,
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
getControllerMethodNames(controllerClass) {
|
|
74
|
+
const collected = new Set();
|
|
75
|
+
let proto = controllerClass.prototype;
|
|
76
|
+
while (proto && proto !== Object.prototype) {
|
|
77
|
+
Object.getOwnPropertyNames(proto)
|
|
78
|
+
.filter((name) => name !== "constructor" && typeof proto[name] === "function")
|
|
79
|
+
.forEach((name) => {
|
|
80
|
+
collected.add(name);
|
|
81
|
+
});
|
|
82
|
+
Object.getOwnPropertySymbols(proto)
|
|
83
|
+
.filter((symbol) => typeof proto[symbol] === "function")
|
|
84
|
+
.forEach((symbol) => {
|
|
85
|
+
collected.add(symbol);
|
|
86
|
+
});
|
|
87
|
+
proto = Object.getPrototypeOf(proto);
|
|
88
|
+
}
|
|
89
|
+
return [...collected];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import type { RegisteredModuleScope } from "../contexts/container-context-base.js";
|
|
3
|
+
import type { DiContextOptions } from "../contexts/di-context-base.js";
|
|
4
|
+
import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
|
|
5
|
+
export declare class InterceptorProcessor {
|
|
6
|
+
private readonly keyedFeatureRegistrar;
|
|
7
|
+
private readonly resolversByModule;
|
|
8
|
+
constructor(providerOptions: DiContextOptions["providerOptions"]);
|
|
9
|
+
processInterceptors(m: M, scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[]): void;
|
|
10
|
+
createInterceptedProviderResolver({ module, useClass, options, resolver, }: {
|
|
11
|
+
module: M;
|
|
12
|
+
useClass: new (...args: any[]) => object;
|
|
13
|
+
options: Awilix.BuildResolverOptions<any>;
|
|
14
|
+
resolver?: Awilix.Resolver<any>;
|
|
15
|
+
}): Awilix.Resolver<any>;
|
|
16
|
+
private createInterceptedProviderInstance;
|
|
17
|
+
private callWithInterceptorChain;
|
|
18
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import { hasDecoratorMethodMetadata, resolveDecoratorState, } from "../../decorators/decorator-state.js";
|
|
3
|
+
import { KeyedFeatureRegistrar } from "./keyed-feature-registrar.js";
|
|
4
|
+
export class InterceptorProcessor {
|
|
5
|
+
keyedFeatureRegistrar;
|
|
6
|
+
resolversByModule = new WeakMap();
|
|
7
|
+
constructor(providerOptions) {
|
|
8
|
+
this.keyedFeatureRegistrar = new KeyedFeatureRegistrar(providerOptions ?? {});
|
|
9
|
+
}
|
|
10
|
+
processInterceptors(m, scope, importedModulesWithScope) {
|
|
11
|
+
const resolverMap = this.keyedFeatureRegistrar.register({
|
|
12
|
+
featureKind: "interceptors",
|
|
13
|
+
module: m,
|
|
14
|
+
scope,
|
|
15
|
+
importedModulesWithScope,
|
|
16
|
+
});
|
|
17
|
+
this.resolversByModule.set(m, resolverMap);
|
|
18
|
+
}
|
|
19
|
+
createInterceptedProviderResolver({ module, useClass, options, resolver, }) {
|
|
20
|
+
const baseResolver = resolver || Awilix.asClass(useClass, options);
|
|
21
|
+
const interceptors = [
|
|
22
|
+
...(this.resolversByModule.get(module)?.values() ?? []),
|
|
23
|
+
];
|
|
24
|
+
if (interceptors.length === 0) {
|
|
25
|
+
return baseResolver;
|
|
26
|
+
}
|
|
27
|
+
if (!hasDecoratorMethodMetadata(useClass)) {
|
|
28
|
+
return baseResolver;
|
|
29
|
+
}
|
|
30
|
+
return Awilix.createBuildResolver({
|
|
31
|
+
...options,
|
|
32
|
+
resolve: (container) => this.createInterceptedProviderInstance(baseResolver.resolve(container), useClass, interceptors, module.name),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
createInterceptedProviderInstance(instance, metadataTarget, resolveInterceptors, moduleName) {
|
|
36
|
+
const wrappers = new Map();
|
|
37
|
+
const self = this;
|
|
38
|
+
return new Proxy(instance, {
|
|
39
|
+
get(target, propertyKey, proxyReceiver) {
|
|
40
|
+
const value = Reflect.get(target, propertyKey, proxyReceiver);
|
|
41
|
+
if (typeof value !== "function")
|
|
42
|
+
return value;
|
|
43
|
+
const existing = wrappers.get(propertyKey);
|
|
44
|
+
if (existing)
|
|
45
|
+
return existing;
|
|
46
|
+
const wrapped = (...args) => {
|
|
47
|
+
const interceptors = resolveInterceptors.map((resolve) => resolve());
|
|
48
|
+
const metadataByToken = new Map();
|
|
49
|
+
for (const interceptor of interceptors) {
|
|
50
|
+
const state = resolveDecoratorState(metadataTarget, interceptor.token);
|
|
51
|
+
if (state === null)
|
|
52
|
+
continue;
|
|
53
|
+
const method = state.methods.get(propertyKey);
|
|
54
|
+
if (method !== undefined) {
|
|
55
|
+
metadataByToken.set(interceptor.token.stateSymbol, {
|
|
56
|
+
state,
|
|
57
|
+
method,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (metadataByToken.size === 0)
|
|
62
|
+
return value.apply(target, args);
|
|
63
|
+
return self.callWithInterceptorChain({
|
|
64
|
+
target,
|
|
65
|
+
methodName: propertyKey,
|
|
66
|
+
moduleName,
|
|
67
|
+
args,
|
|
68
|
+
metadataByToken,
|
|
69
|
+
interceptors,
|
|
70
|
+
proceed: () => value.apply(target, args),
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
wrappers.set(propertyKey, wrapped);
|
|
74
|
+
return wrapped;
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
callWithInterceptorChain({ target, methodName, moduleName, args, metadataByToken, interceptors, proceed, }) {
|
|
79
|
+
const invoke = (index, next) => {
|
|
80
|
+
if (index >= interceptors.length)
|
|
81
|
+
return next();
|
|
82
|
+
const current = interceptors[index];
|
|
83
|
+
if (!current)
|
|
84
|
+
return next();
|
|
85
|
+
const metadata = metadataByToken.get(current.token.stateSymbol);
|
|
86
|
+
if (metadata === undefined) {
|
|
87
|
+
return invoke(index + 1, next);
|
|
88
|
+
}
|
|
89
|
+
return current.intercept({
|
|
90
|
+
target,
|
|
91
|
+
methodName,
|
|
92
|
+
args,
|
|
93
|
+
moduleName,
|
|
94
|
+
metadata: metadata.method,
|
|
95
|
+
decoratorState: metadata.state,
|
|
96
|
+
proceed: () => invoke(index + 1, next),
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
return invoke(0, proceed);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import type { RegisteredModuleScope } from "../contexts/container-context-base.js";
|
|
3
|
+
import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
|
|
4
|
+
type KeyedFeatureKind = "queryPreHandlers" | "commandPreHandlers" | "interceptors" | "initializers";
|
|
5
|
+
type RegisterKeyedFeatureParams = {
|
|
6
|
+
featureKind: KeyedFeatureKind;
|
|
7
|
+
module: M;
|
|
8
|
+
scope: Awilix.AwilixContainer;
|
|
9
|
+
importedModulesWithScope: RegisteredModuleScope[];
|
|
10
|
+
};
|
|
11
|
+
export declare class KeyedFeatureRegistrar {
|
|
12
|
+
private readonly providerOptions;
|
|
13
|
+
constructor(providerOptions: Partial<Awilix.BuildResolverOptions<any>>);
|
|
14
|
+
private readonly featureConfig;
|
|
15
|
+
register<T>({ featureKind, module, scope, importedModulesWithScope, }: RegisterKeyedFeatureParams): Map<string, () => T>;
|
|
16
|
+
private getProviderOptions;
|
|
17
|
+
private ensureInitializerTokenUniqueness;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import * as ERRORS from "../errors.js";
|
|
3
|
+
import { ProviderResolver } from "../providers/provider-resolver.js";
|
|
4
|
+
import { getOrCreateRequestScope, resolveFromRequestScope, } from "../request-scope-context.js";
|
|
5
|
+
export class KeyedFeatureRegistrar {
|
|
6
|
+
providerOptions;
|
|
7
|
+
constructor(providerOptions) {
|
|
8
|
+
this.providerOptions = providerOptions;
|
|
9
|
+
}
|
|
10
|
+
featureConfig = {
|
|
11
|
+
queryPreHandlers: {
|
|
12
|
+
exportKey: "queryPreHandlerExports",
|
|
13
|
+
featureName: "pre-handler",
|
|
14
|
+
},
|
|
15
|
+
commandPreHandlers: {
|
|
16
|
+
exportKey: "commandPreHandlerExports",
|
|
17
|
+
featureName: "pre-handler",
|
|
18
|
+
},
|
|
19
|
+
interceptors: {
|
|
20
|
+
exportKey: "interceptorExports",
|
|
21
|
+
featureName: "interceptor",
|
|
22
|
+
},
|
|
23
|
+
initializers: {
|
|
24
|
+
exportKey: "initializerExports",
|
|
25
|
+
featureName: "initializer",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
register({ featureKind, module, scope, importedModulesWithScope, }) {
|
|
29
|
+
const ownerByKey = new Map();
|
|
30
|
+
const resolverMap = new Map();
|
|
31
|
+
const ownerByInitializerToken = new Map();
|
|
32
|
+
const config = this.featureConfig[featureKind];
|
|
33
|
+
const providerResolver = new ProviderResolver(undefined, this.getProviderOptions(featureKind), getOrCreateRequestScope);
|
|
34
|
+
for (const { module: importedModule, moduleScope: importedModuleScope, } of importedModulesWithScope) {
|
|
35
|
+
for (const key of importedModule[config.exportKey] ?? []) {
|
|
36
|
+
const feature = importedModule[featureKind]?.[key];
|
|
37
|
+
if (!feature) {
|
|
38
|
+
throw new ERRORS.InvalidProviderDefinitionError(importedModule.name, key);
|
|
39
|
+
}
|
|
40
|
+
if (ownerByKey.has(key)) {
|
|
41
|
+
throw new ERRORS.FeatureNameConflictError(module.name, config.featureName, key, ownerByKey.get(key) ?? importedModule.name);
|
|
42
|
+
}
|
|
43
|
+
const symbol = Symbol(`${featureKind}_export_${importedModule.name}_${key}`);
|
|
44
|
+
scope.register({
|
|
45
|
+
[symbol]: providerResolver.resolveClassProvider({
|
|
46
|
+
provider: feature,
|
|
47
|
+
resolutionScope: importedModuleScope.scope,
|
|
48
|
+
module: importedModule,
|
|
49
|
+
wrapForExport: true,
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
if (featureKind === "initializers") {
|
|
53
|
+
this.ensureInitializerTokenUniqueness({
|
|
54
|
+
scope,
|
|
55
|
+
symbol,
|
|
56
|
+
ownerByInitializerToken,
|
|
57
|
+
moduleName: module.name,
|
|
58
|
+
featureName: feature.name || key,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
resolverMap.set(key, featureKind === "initializers"
|
|
62
|
+
? () => scope.resolve(symbol)
|
|
63
|
+
: () => resolveFromRequestScope(scope, symbol));
|
|
64
|
+
ownerByKey.set(key, importedModule.name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for (const [key, feature] of Object.entries(module[featureKind] ?? {})) {
|
|
68
|
+
if (ownerByKey.has(key)) {
|
|
69
|
+
throw new ERRORS.FeatureNameConflictError(module.name, config.featureName, key, ownerByKey.get(key) ?? module.name);
|
|
70
|
+
}
|
|
71
|
+
const symbol = Symbol(`${featureKind}_${module.name}_${key}`);
|
|
72
|
+
scope.register({
|
|
73
|
+
[symbol]: providerResolver.resolveClassProvider({
|
|
74
|
+
provider: feature,
|
|
75
|
+
resolutionScope: scope,
|
|
76
|
+
module,
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
if (featureKind === "initializers") {
|
|
80
|
+
this.ensureInitializerTokenUniqueness({
|
|
81
|
+
scope,
|
|
82
|
+
symbol,
|
|
83
|
+
ownerByInitializerToken,
|
|
84
|
+
moduleName: module.name,
|
|
85
|
+
featureName: feature.name || key,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
resolverMap.set(key, featureKind === "initializers"
|
|
89
|
+
? () => scope.resolve(symbol)
|
|
90
|
+
: () => resolveFromRequestScope(scope, symbol));
|
|
91
|
+
ownerByKey.set(key, module.name);
|
|
92
|
+
}
|
|
93
|
+
return resolverMap;
|
|
94
|
+
}
|
|
95
|
+
getProviderOptions(featureKind) {
|
|
96
|
+
if (featureKind === "initializers") {
|
|
97
|
+
return {
|
|
98
|
+
lifetime: Awilix.Lifetime.SINGLETON,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return this.providerOptions;
|
|
102
|
+
}
|
|
103
|
+
ensureInitializerTokenUniqueness({ scope, symbol, ownerByInitializerToken, moduleName, featureName, }) {
|
|
104
|
+
const initializer = scope.resolve(symbol);
|
|
105
|
+
const token = initializer.token.stateSymbol;
|
|
106
|
+
const existingModuleName = ownerByInitializerToken.get(token);
|
|
107
|
+
if (existingModuleName) {
|
|
108
|
+
throw new ERRORS.DuplicateInitializerTokenError(moduleName, featureName, existingModuleName);
|
|
109
|
+
}
|
|
110
|
+
ownerByInitializerToken.set(token, moduleName);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as Awilix from "awilix";
|
|
2
|
+
import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
|
|
3
|
+
import type { InitializerTask } from "./initializer-processor.js";
|
|
4
|
+
export interface ModuleInitOptions {
|
|
5
|
+
excludeInitializers?: true | readonly string[];
|
|
6
|
+
excludePostInit?: true | readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export interface LifecycleMethods {
|
|
9
|
+
init(options?: ModuleInitOptions): Promise<void>;
|
|
10
|
+
dispose(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare class LifecycleProcessor {
|
|
13
|
+
private readonly providerOptions;
|
|
14
|
+
private readonly eagerProviderRefs;
|
|
15
|
+
private readonly initializerTasks;
|
|
16
|
+
private readonly createdScopes;
|
|
17
|
+
private initPromise?;
|
|
18
|
+
private disposePromise?;
|
|
19
|
+
constructor(providerOptions: Partial<Awilix.BuildResolverOptions<any>>);
|
|
20
|
+
collectEagerProviders(m: M, scope: Awilix.AwilixContainer): void;
|
|
21
|
+
trackScope(scope: Awilix.AwilixContainer): void;
|
|
22
|
+
addInitializerTask(task: InitializerTask | null): void;
|
|
23
|
+
init(options?: ModuleInitOptions): Promise<void>;
|
|
24
|
+
dispose(): Promise<void>;
|
|
25
|
+
private executeInit;
|
|
26
|
+
private executeDispose;
|
|
27
|
+
private shouldSkipProviderPostInit;
|
|
28
|
+
private getEagerProviderKeys;
|
|
29
|
+
private ensureEagerProviderUsesSingletonLifetime;
|
|
30
|
+
private resolveEagerProvider;
|
|
31
|
+
private callProviderInitAsync;
|
|
32
|
+
private callProviderPostInitAsync;
|
|
33
|
+
private sortEagerProviderRefs;
|
|
34
|
+
private getProviderInitAfter;
|
|
35
|
+
private sortEagerProviderIds;
|
|
36
|
+
private static buildEagerProviderNodeKeyMap;
|
|
37
|
+
private static createEagerProviderId;
|
|
38
|
+
}
|