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.
Files changed (127) hide show
  1. package/README.md +12 -6
  2. package/dist/index.d.ts +18 -0
  3. package/dist/index.js +15 -0
  4. package/dist/lib/decorators/decorator-state.d.ts +15 -0
  5. package/dist/lib/decorators/decorator-state.js +72 -0
  6. package/dist/lib/decorators/decorator-state.types.d.ts +35 -0
  7. package/dist/lib/decorators/decorator-state.types.js +1 -0
  8. package/dist/lib/di/common.types.d.ts +6 -0
  9. package/dist/lib/di/common.types.js +1 -0
  10. package/dist/lib/di/contexts/container-context-base.d.ts +53 -0
  11. package/dist/lib/di/contexts/container-context-base.js +194 -0
  12. package/dist/lib/di/contexts/context-overrides.d.ts +22 -0
  13. package/dist/lib/di/contexts/context-overrides.js +93 -0
  14. package/dist/lib/di/contexts/di-context-async.d.ts +14 -0
  15. package/dist/lib/di/contexts/di-context-async.js +112 -0
  16. package/dist/lib/di/contexts/di-context-base.d.ts +19 -0
  17. package/dist/lib/di/contexts/di-context-base.js +32 -0
  18. package/dist/lib/di/contexts/di-context.d.ts +7 -0
  19. package/dist/lib/di/contexts/di-context.js +9 -0
  20. package/dist/lib/di/contexts/module-graph-ensurer.d.ts +31 -0
  21. package/dist/lib/di/contexts/module-graph-ensurer.js +45 -0
  22. package/dist/lib/di/contexts/module-overrides.d.ts +70 -0
  23. package/dist/lib/di/contexts/module-overrides.js +3 -0
  24. package/dist/lib/di/contexts/override-value.types.d.ts +6 -0
  25. package/dist/lib/di/contexts/override-value.types.js +1 -0
  26. package/dist/lib/di/contexts/overrides-processor.d.ts +22 -0
  27. package/dist/lib/di/contexts/overrides-processor.js +93 -0
  28. package/dist/lib/di/contexts/provider-overrides.types.d.ts +19 -0
  29. package/dist/lib/di/contexts/provider-overrides.types.js +1 -0
  30. package/dist/lib/di/errors.d.ts +66 -0
  31. package/dist/lib/di/errors.js +148 -0
  32. package/dist/lib/di/modules/module-def.types.d.ts +117 -0
  33. package/dist/lib/di/modules/module-def.types.js +1 -0
  34. package/dist/lib/di/modules/module-factories.d.ts +16 -0
  35. package/dist/lib/di/modules/module-factories.js +46 -0
  36. package/dist/lib/di/modules/module-overrides.d.ts +70 -0
  37. package/dist/lib/di/modules/module-overrides.js +3 -0
  38. package/dist/lib/di/modules/module-ref.types.d.ts +13 -0
  39. package/dist/lib/di/modules/module-ref.types.js +1 -0
  40. package/dist/lib/di/modules/module.types.d.ts +178 -0
  41. package/dist/lib/di/modules/module.types.js +1 -0
  42. package/dist/lib/di/modules/provider-overrides.types.d.ts +19 -0
  43. package/dist/lib/di/modules/provider-overrides.types.js +1 -0
  44. package/dist/lib/di/modules/runtime-module.types.d.ts +25 -0
  45. package/dist/lib/di/modules/runtime-module.types.js +1 -0
  46. package/dist/lib/di/processors/controller-processor.d.ts +13 -0
  47. package/dist/lib/di/processors/controller-processor.js +76 -0
  48. package/dist/lib/di/processors/handler-processor.d.ts +15 -0
  49. package/dist/lib/di/processors/handler-processor.js +69 -0
  50. package/dist/lib/di/processors/initializer-processor.d.ts +19 -0
  51. package/dist/lib/di/processors/initializer-processor.js +91 -0
  52. package/dist/lib/di/processors/interceptor-processor.d.ts +18 -0
  53. package/dist/lib/di/processors/interceptor-processor.js +101 -0
  54. package/dist/lib/di/processors/keyed-feature-registrar.d.ts +19 -0
  55. package/dist/lib/di/processors/keyed-feature-registrar.js +112 -0
  56. package/dist/lib/di/processors/lifecycle-processor.d.ts +38 -0
  57. package/dist/lib/di/processors/lifecycle-processor.js +178 -0
  58. package/dist/lib/di/processors/overrides-processor.d.ts +24 -0
  59. package/dist/lib/di/processors/overrides-processor.js +69 -0
  60. package/dist/lib/di/providers/basic-provider-resolver.d.ts +35 -0
  61. package/dist/lib/di/providers/basic-provider-resolver.js +88 -0
  62. package/dist/lib/di/providers/provider-dependency-sorter.d.ts +9 -0
  63. package/dist/lib/di/providers/provider-dependency-sorter.js +76 -0
  64. package/dist/lib/di/providers/provider-resolver.d.ts +31 -0
  65. package/dist/lib/di/providers/provider-resolver.js +128 -0
  66. package/dist/lib/di/providers/provider.types.d.ts +1 -0
  67. package/dist/lib/di/providers/provider.types.js +1 -0
  68. package/dist/lib/di/providers/types/controller.types.d.ts +9 -0
  69. package/dist/lib/di/providers/types/controller.types.js +1 -0
  70. package/dist/lib/di/providers/types/decorator-context.types.d.ts +9 -0
  71. package/dist/lib/di/providers/types/decorator-context.types.js +1 -0
  72. package/dist/lib/di/providers/types/handler.types.d.ts +9 -0
  73. package/dist/lib/di/providers/types/handler.types.js +1 -0
  74. package/dist/lib/di/providers/types/index.d.ts +7 -0
  75. package/dist/lib/di/providers/types/index.js +7 -0
  76. package/dist/lib/di/providers/types/initializer.types.d.ts +16 -0
  77. package/dist/lib/di/providers/types/initializer.types.js +3 -0
  78. package/dist/lib/di/providers/types/interceptor.types.d.ts +18 -0
  79. package/dist/lib/di/providers/types/interceptor.types.js +1 -0
  80. package/dist/lib/di/providers/types/middleware.types.d.ts +10 -0
  81. package/dist/lib/di/providers/types/middleware.types.js +1 -0
  82. package/dist/lib/di/providers/types/provider.types.d.ts +26 -0
  83. package/dist/lib/di/providers/types/provider.types.js +1 -0
  84. package/dist/lib/di/request-scope-context.d.ts +5 -0
  85. package/dist/lib/di/request-scope-context.js +28 -0
  86. package/dist/lib/di/type-guards.d.ts +35 -0
  87. package/dist/lib/di/type-guards.js +84 -0
  88. package/dist/lib/http/decorators.d.ts +33 -0
  89. package/dist/lib/http/decorators.js +151 -0
  90. package/dist/lib/http/exceptions.d.ts +58 -0
  91. package/dist/lib/http/exceptions.js +71 -0
  92. package/dist/lib/http/http-verbs.d.ts +12 -0
  93. package/dist/lib/http/http-verbs.js +11 -0
  94. package/dist/lib/http/index.d.ts +3 -0
  95. package/dist/lib/http/index.js +3 -0
  96. package/dist/lib/http/openapi-builder.d.ts +27 -0
  97. package/dist/lib/http/openapi-builder.js +83 -0
  98. package/dist/lib/mediator/contract.types.d.ts +159 -0
  99. package/dist/lib/mediator/contract.types.js +1 -0
  100. package/dist/lib/mediator/errors.d.ts +15 -0
  101. package/dist/lib/mediator/errors.js +33 -0
  102. package/dist/lib/mediator/global-middlewares.types.d.ts +13 -0
  103. package/dist/lib/mediator/global-middlewares.types.js +1 -0
  104. package/dist/lib/mediator/handler.types.d.ts +16 -0
  105. package/dist/lib/mediator/handler.types.js +1 -0
  106. package/dist/lib/mediator/mediator.d.ts +21 -0
  107. package/dist/lib/mediator/mediator.js +123 -0
  108. package/dist/lib/mediator/mediator.types.d.ts +64 -0
  109. package/dist/lib/mediator/mediator.types.js +1 -0
  110. package/dist/lib/mediator/middleware.types.d.ts +41 -0
  111. package/dist/lib/mediator/middleware.types.js +1 -0
  112. package/dist/lib/mediator/result.d.ts +18 -0
  113. package/dist/lib/mediator/result.js +24 -0
  114. package/dist/lib/react/errors.d.ts +12 -0
  115. package/dist/lib/react/errors.js +24 -0
  116. package/dist/lib/react/react-component-processor.d.ts +10 -0
  117. package/dist/lib/react/react-component-processor.js +62 -0
  118. package/dist/lib/react/react-di-context.d.ts +21 -0
  119. package/dist/lib/react/react-di-context.js +55 -0
  120. package/dist/lib/react/react-module-factories.d.ts +6 -0
  121. package/dist/lib/react/react-module-factories.js +34 -0
  122. package/dist/lib/react/react-module.types.d.ts +183 -0
  123. package/dist/lib/react/react-module.types.js +1 -0
  124. package/dist/react.d.ts +4 -0
  125. package/dist/react.js +4 -0
  126. package/dist/tsconfig.tsbuildinfo +1 -0
  127. package/package.json +29 -3
package/README.md CHANGED
@@ -1,19 +1,25 @@
1
- # awilixify
1
+ <div align="center">
2
+ <img src="./logo.png" alt="awilixify logo" width="220" />
3
+ </div>
4
+
5
+ Transport-agnostic, type-safe, modular DI and CQRS framework on top of [Awilix](https://github.com/jeffijoe/awilix) that brings module architecture with powerful CQRS capabilities to Node.js applications and React 🚀 frontends.
2
6
 
3
7
  [![Build Status](https://github.com/wildstyles/awilixify/workflows/ci/badge.svg)](https://github.com/wildstyles/awilixify/actions)
4
8
  [![codecov](https://codecov.io/gh/wildstyles/awilixify/branch/main/graph/badge.svg)](https://codecov.io/gh/wildstyles/awilixify)
5
9
 
6
- 📚 Documentation: https://wildstyles.github.io/awilixify/
7
-
8
- A type-safe, modular DI and CQRS framework on top of [Awilix](https://github.com/jeffijoe/awilix) that brings NestJS-like module architecture with powerful CQRS capabilities to any Node.js application.
10
+ > [!WARNING]
11
+ > This project is in active development and is not production-ready yet.
9
12
 
10
- 🚀 **includes native ES decorators (TC39 Stage 3) for routing - no `reflect-metadata` or `experimentalDecorators` required!**
13
+ 📚 Documentation: https://wildstyles.github.io/awilixify/
11
14
 
12
15
  ## Features
13
16
 
14
17
  - **Type-Safe Module System** - Complete type safety for each provider in module
15
- - **HTTP Framework Agnostic** - Works with Express, Fastify, Hono, Koa, or any other framework
18
+ - **Transport Agnostic** - Works with Express, Fastify, Queues, Rabbit or any other tranport
19
+ - **Fullstack Module Model** - Reuse the same DI module mechanism in Node.js and React applications
16
20
  - **Powerful CQRS** - Type-safe query/command handlers with middleware pipeline, per-module mediators, and contract-based execution
21
+ - **Type-Level Middleware Composition** - Compose and inherit middleware with end-to-end type safety
22
+ - **No Experimental Decorators Required** - Uses native ES decorators (TC39 Stage 3) for routing without `reflect-metadata`
17
23
  - **NestJS-Inspired Architecture** - Familiar module/controller/provider patterns
18
24
  - **Less Import Boilerplate For Typing** - Define module dependencies once - reuse in all providers
19
25
  - **Lightweight** - Minimal overhead, built on proven Awilix foundation
@@ -0,0 +1,18 @@
1
+ export * from "./lib/decorators/decorator-state.js";
2
+ export type { ModuleScope } from "./lib/di/contexts/container-context-base.js";
3
+ export * from "./lib/di/contexts/di-context.js";
4
+ export * from "./lib/di/contexts/di-context-async.js";
5
+ export * from "./lib/di/modules/module.types.js";
6
+ export * from "./lib/di/modules/module-def.types.js";
7
+ export * from "./lib/di/modules/module-factories.js";
8
+ export * from "./lib/di/modules/module-overrides.js";
9
+ export * from "./lib/di/modules/module-ref.types.js";
10
+ export type { Controller, InitializerContext, InterceptContext, Interceptor, ProviderInit, } from "./lib/di/providers/provider.types.js";
11
+ export { Initializer } from "./lib/di/providers/provider.types.js";
12
+ export { isResultLike } from "./lib/di/type-guards.js";
13
+ export * from "./lib/mediator/contract.types.js";
14
+ export * from "./lib/mediator/global-middlewares.types.js";
15
+ export * from "./lib/mediator/handler.types.js";
16
+ export type { ExecutionContext, Middleware, MiddlewareContract, } from "./lib/mediator/middleware.types.js";
17
+ export * from "./lib/mediator/middleware.types.js";
18
+ export { Result } from "./lib/mediator/result.js";
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ export * from "./lib/decorators/decorator-state.js";
2
+ export * from "./lib/di/contexts/di-context.js";
3
+ export * from "./lib/di/contexts/di-context-async.js";
4
+ export * from "./lib/di/modules/module.types.js";
5
+ export * from "./lib/di/modules/module-def.types.js";
6
+ export * from "./lib/di/modules/module-factories.js";
7
+ export * from "./lib/di/modules/module-overrides.js";
8
+ export * from "./lib/di/modules/module-ref.types.js";
9
+ export { Initializer } from "./lib/di/providers/provider.types.js";
10
+ export { isResultLike } from "./lib/di/type-guards.js";
11
+ export * from "./lib/mediator/contract.types.js";
12
+ export * from "./lib/mediator/global-middlewares.types.js";
13
+ export * from "./lib/mediator/handler.types.js";
14
+ export * from "./lib/mediator/middleware.types.js";
15
+ export { Result } from "./lib/mediator/result.js";
@@ -0,0 +1,15 @@
1
+ import type { DecoratorState, DecoratorToken, MethodStateFrom, MethodUpdate, RootStateFrom, RootUpdate } from "./decorator-state.types.js";
2
+ export declare function createDecoratorStateUpdater<TInitializers extends {
3
+ method: () => unknown;
4
+ root?: () => unknown;
5
+ } = {
6
+ method: () => unknown;
7
+ }>(description: string, initializers: TInitializers): {
8
+ token: DecoratorToken<DecoratorState<MethodStateFrom<TInitializers>, RootStateFrom<TInitializers>>>;
9
+ update: {
10
+ (context: ClassDecoratorContext<any>, updater: RootUpdate<DecoratorState<MethodStateFrom<TInitializers>, RootStateFrom<TInitializers>>>): void;
11
+ (context: ClassMethodDecoratorContext<any, any>, updater: MethodUpdate<DecoratorState<MethodStateFrom<TInitializers>, RootStateFrom<TInitializers>>>): void;
12
+ };
13
+ };
14
+ export declare function resolveDecoratorState<TState extends DecoratorState<any, any>>(target: unknown, token: DecoratorToken<TState>): TState | null;
15
+ export declare function hasDecoratorMethodMetadata(target: unknown): boolean;
@@ -0,0 +1,72 @@
1
+ export function createDecoratorStateUpdater(description, initializers) {
2
+ const token = {
3
+ stateSymbol: Symbol(`DecoratorState:${description}`),
4
+ };
5
+ return {
6
+ token,
7
+ update: createUpdater(token, {
8
+ ...initializers,
9
+ root: initializers.root ?? (() => null),
10
+ }),
11
+ };
12
+ }
13
+ export function resolveDecoratorState(target, token) {
14
+ const metadataSymbol = (typeof Symbol !== "undefined" && Symbol.metadata) ||
15
+ Object.getOwnPropertySymbols(target).find((s) => s.toString() === "Symbol(Symbol.metadata)");
16
+ if (!metadataSymbol)
17
+ return null;
18
+ return (target[metadataSymbol]?.[token.stateSymbol] || null);
19
+ }
20
+ export function hasDecoratorMethodMetadata(target) {
21
+ return [target, target?.prototype].some((value) => hasOwnDecoratorMethodMetadata(value));
22
+ }
23
+ function hasOwnDecoratorMethodMetadata(target) {
24
+ if (target === null ||
25
+ (typeof target !== "object" && typeof target !== "function")) {
26
+ return false;
27
+ }
28
+ const metadataSymbol = (typeof Symbol !== "undefined" && Symbol.metadata) ||
29
+ Object.getOwnPropertySymbols(target).find((s) => s.toString() === "Symbol(Symbol.metadata)");
30
+ if (!metadataSymbol)
31
+ return false;
32
+ const metadata = target[metadataSymbol];
33
+ if (!metadata || typeof metadata !== "object")
34
+ return false;
35
+ return [
36
+ ...Object.getOwnPropertyNames(metadata).map((key) => metadata[key]),
37
+ ...Object.getOwnPropertySymbols(metadata).map((key) => metadata[key]),
38
+ ].some((state) => typeof state === "object" &&
39
+ state !== null &&
40
+ "methods" in state &&
41
+ state.methods instanceof Map &&
42
+ state.methods.size > 0);
43
+ }
44
+ function createUpdater(token, initializers) {
45
+ const initializeState = () => ({
46
+ root: initializers.root(),
47
+ methods: new Map(),
48
+ });
49
+ function update(context, updater) {
50
+ if (!context.metadata)
51
+ return;
52
+ const state = context.metadata[token.stateSymbol] || initializeState();
53
+ if (context.kind === "class") {
54
+ if (!("root" in updater))
55
+ return;
56
+ context.metadata[token.stateSymbol] = {
57
+ ...state,
58
+ root: updater.root(state.root),
59
+ };
60
+ return;
61
+ }
62
+ if (!("method" in updater))
63
+ return;
64
+ const nextMethods = new Map(state.methods);
65
+ nextMethods.set(context.name, updater.method(nextMethods.get(context.name) ?? initializers.method()));
66
+ context.metadata[token.stateSymbol] = {
67
+ ...state,
68
+ methods: nextMethods,
69
+ };
70
+ }
71
+ return update;
72
+ }
@@ -0,0 +1,35 @@
1
+ export type MethodName = string | symbol;
2
+ export type DecoratorState<TMethod, TRoot = null> = {
3
+ root: TRoot;
4
+ methods: Map<MethodName, TMethod>;
5
+ };
6
+ export type DecoratorMethodState<TState> = TState extends DecoratorState<infer TMethod, any> ? TMethod : never;
7
+ export type DecoratorRootState<TState> = TState extends DecoratorState<any, infer TRoot> ? TRoot : never;
8
+ export type StateInitializers<TState extends DecoratorState<any, any>> = {
9
+ method: () => DecoratorMethodState<TState>;
10
+ root: () => DecoratorRootState<TState>;
11
+ };
12
+ type StateUpdater<T> = (previous: T) => T;
13
+ export type RootUpdate<TState extends DecoratorState<any, any>> = {
14
+ root: StateUpdater<DecoratorRootState<TState>>;
15
+ };
16
+ export type MethodUpdate<TState extends DecoratorState<any, any>> = {
17
+ method: StateUpdater<DecoratorMethodState<TState>>;
18
+ };
19
+ export type StateUpdate<TState extends DecoratorState<any, any>> = RootUpdate<TState> | MethodUpdate<TState>;
20
+ export type DecoratorToken<TState extends DecoratorState<any, any>> = {
21
+ stateSymbol: symbol;
22
+ readonly state: TState;
23
+ };
24
+ export type MethodStateFrom<TInitializers> = TInitializers extends {
25
+ method: () => infer TMethod;
26
+ } ? TMethod : never;
27
+ export type RootStateFrom<TInitializers> = TInitializers extends {
28
+ root: () => infer TRoot;
29
+ } ? TRoot : null;
30
+ declare global {
31
+ interface SymbolConstructor {
32
+ readonly metadata: unique symbol;
33
+ }
34
+ }
35
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export type UnknownRecord = Record<PropertyKey, unknown>;
2
+ declare const emptyObjectSymbol: unique symbol;
3
+ export type EmptyObject = {
4
+ [emptyObjectSymbol]?: never;
5
+ };
6
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ import * as Awilix from "awilix";
2
+ import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
3
+ import { type LifecycleMethods, LifecycleProcessor } from "../processors/lifecycle-processor.js";
4
+ import { type OverrideOptions, OverridesProcessor } from "../processors/overrides-processor.js";
5
+ import { ProviderDependencySorter } from "../providers/provider-dependency-sorter.js";
6
+ import type { ProviderResolver } from "../providers/provider-resolver.js";
7
+ import { ModuleGraphEnsurer } from "./module-graph-ensurer.js";
8
+ interface ScopeContext {
9
+ hasScopeContext: () => boolean;
10
+ resolveFromScope: <T>(scope: Awilix.AwilixContainer, key: string | symbol) => T;
11
+ }
12
+ export interface ContainerContextOptions extends OverrideOptions {
13
+ containerOptions?: Awilix.ContainerOptions;
14
+ providerOptions?: Partial<Awilix.BuildResolverOptions<any>>;
15
+ globalModules?: readonly M[];
16
+ }
17
+ export interface ModuleScope<S extends Awilix.AwilixContainer = Awilix.AwilixContainer> extends LifecycleMethods {
18
+ name: string;
19
+ scope: S;
20
+ importedScopes: Map<string, ModuleScope>;
21
+ }
22
+ export type RegisteredModuleScope = {
23
+ module: M;
24
+ moduleScope: ModuleScope;
25
+ };
26
+ export declare abstract class ContainerContextBase<TOptions extends ContainerContextOptions = ContainerContextOptions> {
27
+ private readonly scopeContext?;
28
+ protected readonly forwardRefModules: WeakSet<M>;
29
+ protected readonly moduleScopeMap: WeakMap<M, Awilix.AwilixContainer<{}>>;
30
+ protected readonly moduleTreeMap: WeakMap<M, ModuleScope<Awilix.AwilixContainer<{}>>>;
31
+ protected readonly options: TOptions;
32
+ protected readonly sorter: ProviderDependencySorter;
33
+ protected readonly moduleGraphEnsurer: ModuleGraphEnsurer;
34
+ protected readonly lifecycleProcessor: LifecycleProcessor;
35
+ protected readonly overridesProcessor: OverridesProcessor<M>;
36
+ protected providerResolver: ProviderResolver;
37
+ protected globalModulesWithScope: RegisteredModuleScope[];
38
+ protected constructor(options: TOptions, scopeContext?: ScopeContext | undefined);
39
+ protected bootstrapModule(module: M): ModuleScope;
40
+ protected createContainer(module?: M): Awilix.AwilixContainer;
41
+ protected registerModuleWithScope(m: M, scope: Awilix.AwilixContainer, moduleChain: M[]): ModuleScope;
42
+ protected initializeGlobalModules(): void;
43
+ protected registerImportedFeatures(scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[]): void;
44
+ protected registerExportedProviders(scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[]): void;
45
+ protected getExportedProviderKeys(module: M): string[];
46
+ protected markModuleIfImportsUseForwardRef(m: M): void;
47
+ protected createModuleScope(name: string, scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[]): ModuleScope;
48
+ protected resolveImports(m: M): M[];
49
+ protected ensureAdditionalNameConflicts(_module: M, _resolvedImports: M[]): void;
50
+ protected beforeRegisterProviders(_module: M, _scope: Awilix.AwilixContainer, _importedModulesWithScope: RegisteredModuleScope[]): void;
51
+ protected afterRegisterProviders(_module: M, _scope: Awilix.AwilixContainer, _importedModulesWithScope: RegisteredModuleScope[]): void;
52
+ }
53
+ export {};
@@ -0,0 +1,194 @@
1
+ import * as Awilix from "awilix";
2
+ import * as ERRORS from "../errors.js";
3
+ import { LifecycleProcessor, } from "../processors/lifecycle-processor.js";
4
+ import { OverridesProcessor, } from "../processors/overrides-processor.js";
5
+ import { ProviderDependencySorter } from "../providers/provider-dependency-sorter.js";
6
+ import * as GUARGS from "../type-guards.js";
7
+ import { ModuleGraphEnsurer } from "./module-graph-ensurer.js";
8
+ export class ContainerContextBase {
9
+ scopeContext;
10
+ forwardRefModules = new WeakSet();
11
+ moduleScopeMap = new WeakMap();
12
+ moduleTreeMap = new WeakMap();
13
+ options;
14
+ sorter = new ProviderDependencySorter();
15
+ moduleGraphEnsurer = new ModuleGraphEnsurer();
16
+ lifecycleProcessor;
17
+ overridesProcessor;
18
+ providerResolver;
19
+ globalModulesWithScope = [];
20
+ constructor(options, scopeContext) {
21
+ this.scopeContext = scopeContext;
22
+ this.options = {
23
+ ...options,
24
+ containerOptions: {
25
+ strict: true,
26
+ injectionMode: Awilix.InjectionMode.CLASSIC,
27
+ ...options.containerOptions,
28
+ },
29
+ providerOptions: {
30
+ lifetime: Awilix.Lifetime.SINGLETON,
31
+ ...options.providerOptions,
32
+ },
33
+ };
34
+ this.overridesProcessor = new OverridesProcessor({
35
+ moduleOverrides: this.options.moduleOverrides,
36
+ });
37
+ this.lifecycleProcessor = new LifecycleProcessor(this.options.providerOptions || {});
38
+ }
39
+ bootstrapModule(module) {
40
+ this.initializeGlobalModules();
41
+ const moduleTree = this.registerModuleWithScope(module, this.createContainer(module), []);
42
+ this.overridesProcessor.ensureAllModuleOverridesApplied();
43
+ return moduleTree;
44
+ }
45
+ createContainer(module) {
46
+ const scope = Awilix.createContainer({
47
+ ...this.options.containerOptions,
48
+ ...module?.containerOptions,
49
+ });
50
+ this.lifecycleProcessor.trackScope(scope);
51
+ return scope;
52
+ }
53
+ registerModuleWithScope(m, scope, moduleChain) {
54
+ const existingTree = this.moduleTreeMap.get(m);
55
+ if (existingTree) {
56
+ return existingTree;
57
+ }
58
+ const imports = this.resolveImports(m);
59
+ const moduleWithOverrides = this.overridesProcessor.applyModuleOverrides(m);
60
+ this.moduleGraphEnsurer.ensureImportedModulesUniqueness({
61
+ module: moduleWithOverrides,
62
+ resolvedImports: imports,
63
+ globalModules: this.globalModulesWithScope.map((el) => el.module),
64
+ });
65
+ this.moduleGraphEnsurer.ensureNoProviderNameConflicts({
66
+ module: moduleWithOverrides,
67
+ resolvedImports: imports,
68
+ globalModules: this.globalModulesWithScope.map((el) => el.module),
69
+ getExportedProviderKeys: (module) => this.getExportedProviderKeys(module),
70
+ });
71
+ this.ensureAdditionalNameConflicts(moduleWithOverrides, imports);
72
+ this.markModuleIfImportsUseForwardRef(moduleWithOverrides);
73
+ const isCircular = moduleChain.includes(m);
74
+ if (isCircular) {
75
+ this.moduleGraphEnsurer.ensureCircularDependencyHasForwardRef({
76
+ module: m,
77
+ moduleChain,
78
+ forwardRefModules: this.forwardRefModules,
79
+ });
80
+ return this.createModuleScope(m.name, this.moduleScopeMap.get(m), []);
81
+ }
82
+ this.moduleScopeMap.set(m, scope);
83
+ const importedModulesWithScope = [
84
+ ...this.globalModulesWithScope,
85
+ ...imports.map((module) => {
86
+ const moduleTree = this.registerModuleWithScope(module, this.createContainer(module), [...moduleChain, m]);
87
+ return {
88
+ module: this.overridesProcessor.getModuleWithOverrides(module),
89
+ moduleScope: moduleTree,
90
+ };
91
+ }),
92
+ ];
93
+ this.registerImportedFeatures(scope, importedModulesWithScope);
94
+ const moduleForSorting = {
95
+ ...moduleWithOverrides,
96
+ imports: importedModulesWithScope.map((el) => el.module),
97
+ };
98
+ this.beforeRegisterProviders(moduleWithOverrides, scope, importedModulesWithScope);
99
+ for (const [key, provider] of Object.entries(this.sorter.sortByDependencies(moduleForSorting))) {
100
+ scope.register({
101
+ [key]: this.providerResolver.resolveProvider({
102
+ key,
103
+ provider,
104
+ resolutionScope: scope,
105
+ module: moduleWithOverrides,
106
+ }),
107
+ });
108
+ }
109
+ this.lifecycleProcessor.collectEagerProviders(moduleWithOverrides, scope);
110
+ this.afterRegisterProviders(moduleWithOverrides, scope, importedModulesWithScope);
111
+ const moduleTree = this.createModuleScope(m.name, scope, importedModulesWithScope);
112
+ this.moduleTreeMap.set(m, moduleTree);
113
+ return moduleTree;
114
+ }
115
+ initializeGlobalModules() {
116
+ const globalModules = this.options.globalModules || [];
117
+ const globalModuleImports = globalModules.flatMap((module) => this.resolveImports(module).map((importedModule) => ({
118
+ module,
119
+ importedModule,
120
+ })));
121
+ this.moduleGraphEnsurer.ensureGlobalModulesDoNotImportGlobalModules({
122
+ globalModules,
123
+ globalModuleImports,
124
+ });
125
+ this.globalModulesWithScope = [];
126
+ for (const module of globalModules) {
127
+ const moduleTree = this.registerModuleWithScope(module, this.createContainer(module), []);
128
+ this.globalModulesWithScope.push({
129
+ module: this.overridesProcessor.getModuleWithOverrides(module),
130
+ moduleScope: moduleTree,
131
+ });
132
+ }
133
+ }
134
+ registerImportedFeatures(scope, importedModulesWithScope) {
135
+ this.registerExportedProviders(scope, importedModulesWithScope);
136
+ }
137
+ registerExportedProviders(scope, importedModulesWithScope) {
138
+ for (const { module: importedModule, moduleScope: importedModuleScope, } of importedModulesWithScope) {
139
+ for (const key of this.getExportedProviderKeys(importedModule)) {
140
+ if (!importedModule.providers?.[key]) {
141
+ throw new ERRORS.InvalidProviderDefinitionError(importedModule.name, key);
142
+ }
143
+ scope.register({
144
+ [key]: Awilix.asFunction(() => {
145
+ const registration = importedModuleScope.scope.registrations[key];
146
+ return registration.lifetime === Awilix.Lifetime.SINGLETON
147
+ ? importedModuleScope.scope.resolve(key)
148
+ : this.scopeContext?.hasScopeContext()
149
+ ? this.scopeContext.resolveFromScope(importedModuleScope.scope, key)
150
+ : importedModuleScope.scope.resolve(key);
151
+ }, {
152
+ lifetime: Awilix.Lifetime.TRANSIENT,
153
+ isLeakSafe: true,
154
+ }),
155
+ });
156
+ }
157
+ }
158
+ }
159
+ getExportedProviderKeys(module) {
160
+ return module.exports ? [...module.exports] : [];
161
+ }
162
+ markModuleIfImportsUseForwardRef(m) {
163
+ if ((m.imports || []).some(GUARGS.isForwardRef)) {
164
+ this.forwardRefModules.add(m);
165
+ }
166
+ }
167
+ createModuleScope(name, scope, importedModulesWithScope) {
168
+ const importedScopes = importedModulesWithScope.reduce((acc, { moduleScope }) => {
169
+ acc.set(moduleScope.name, moduleScope);
170
+ return acc;
171
+ }, new Map());
172
+ return {
173
+ name,
174
+ scope,
175
+ importedScopes,
176
+ init: (options) => this.lifecycleProcessor.init(options),
177
+ dispose: () => this.lifecycleProcessor.dispose(),
178
+ };
179
+ }
180
+ resolveImports(m) {
181
+ return (m.imports || []).map((importItem) => {
182
+ const resolvedImport = GUARGS.isForwardRef(importItem)
183
+ ? importItem.resolve()
184
+ : importItem;
185
+ if (GUARGS.isPromiseLike(resolvedImport)) {
186
+ throw new ERRORS.AsyncModuleRequiresAsyncCreateError(m.name);
187
+ }
188
+ return resolvedImport;
189
+ });
190
+ }
191
+ ensureAdditionalNameConflicts(_module, _resolvedImports) { }
192
+ beforeRegisterProviders(_module, _scope, _importedModulesWithScope) { }
193
+ afterRegisterProviders(_module, _scope, _importedModulesWithScope) { }
194
+ }
@@ -0,0 +1,22 @@
1
+ import type { InternalModuleLike } from "../modules/runtime-module.types.js";
2
+ import type { AnyModuleOverride } from "./module-overrides.js";
3
+ import type { AnyProviderOverrides } from "./provider-overrides.types.js";
4
+ type OverrideOptions = {
5
+ providerOverrides?: AnyProviderOverrides;
6
+ moduleOverrides?: readonly AnyModuleOverride[];
7
+ };
8
+ export declare class ContextOverrides<M extends InternalModuleLike> {
9
+ private readonly options;
10
+ private readonly effectiveModuleMap;
11
+ private readonly appliedModuleOverrides;
12
+ private rootModule?;
13
+ constructor(options: OverrideOptions);
14
+ setRootModule(module: M): void;
15
+ applyModuleOverrides(module: M): M;
16
+ getEffectiveModule(module: M): M;
17
+ ensureAllModuleOverridesApplied(): void;
18
+ applyRootProviderOverrides(module: M, moduleForSorting: M): M;
19
+ private ensureModuleOverrideKeysExist;
20
+ private ensureFeatureOverrideKeysExist;
21
+ }
22
+ export {};
@@ -0,0 +1,93 @@
1
+ import * as ERRORS from "../errors.js";
2
+ export class ContextOverrides {
3
+ options;
4
+ effectiveModuleMap = new WeakMap();
5
+ appliedModuleOverrides = new WeakSet();
6
+ rootModule;
7
+ constructor(options) {
8
+ this.options = options;
9
+ }
10
+ setRootModule(module) {
11
+ this.rootModule = module;
12
+ }
13
+ applyModuleOverrides(module) {
14
+ const moduleOverride = this.options.moduleOverrides?.find((override) => override.module === module);
15
+ if (!moduleOverride) {
16
+ this.effectiveModuleMap.set(module, module);
17
+ return module;
18
+ }
19
+ this.ensureModuleOverrideKeysExist(module, moduleOverride);
20
+ this.appliedModuleOverrides.add(module);
21
+ const effectiveModule = {
22
+ ...module,
23
+ providers: {
24
+ ...module.providers,
25
+ ...moduleOverride.overrides.providers,
26
+ },
27
+ queryPreHandlers: {
28
+ ...module.queryPreHandlers,
29
+ ...moduleOverride.overrides.queryPreHandlers,
30
+ },
31
+ commandPreHandlers: {
32
+ ...module.commandPreHandlers,
33
+ ...moduleOverride.overrides.commandPreHandlers,
34
+ },
35
+ interceptors: {
36
+ ...module.interceptors,
37
+ ...moduleOverride.overrides.interceptors,
38
+ },
39
+ initializers: {
40
+ ...module.initializers,
41
+ ...moduleOverride.overrides.initializers,
42
+ },
43
+ };
44
+ this.effectiveModuleMap.set(module, effectiveModule);
45
+ return effectiveModule;
46
+ }
47
+ getEffectiveModule(module) {
48
+ return this.effectiveModuleMap.get(module) ?? module;
49
+ }
50
+ ensureAllModuleOverridesApplied() {
51
+ for (const override of this.options.moduleOverrides ?? []) {
52
+ if (!this.appliedModuleOverrides.has(override.module)) {
53
+ throw new ERRORS.ModuleOverrideTargetNotFoundError(override.module.name);
54
+ }
55
+ }
56
+ }
57
+ applyRootProviderOverrides(module, moduleForSorting) {
58
+ const overrides = this.options.providerOverrides;
59
+ if (module !== this.rootModule || !overrides) {
60
+ return moduleForSorting;
61
+ }
62
+ const providerKeys = new Set(Object.keys(module.providers || {}));
63
+ for (const key of Object.keys(overrides)) {
64
+ if (!providerKeys.has(key)) {
65
+ throw new ERRORS.ProviderOverrideNotFoundError(module.name, key);
66
+ }
67
+ }
68
+ return {
69
+ ...moduleForSorting,
70
+ providers: {
71
+ ...moduleForSorting.providers,
72
+ ...overrides,
73
+ },
74
+ };
75
+ }
76
+ ensureModuleOverrideKeysExist(module, moduleOverride) {
77
+ this.ensureFeatureOverrideKeysExist(module, "providers", moduleOverride.overrides.providers);
78
+ this.ensureFeatureOverrideKeysExist(module, "queryPreHandlers", moduleOverride.overrides.queryPreHandlers);
79
+ this.ensureFeatureOverrideKeysExist(module, "commandPreHandlers", moduleOverride.overrides.commandPreHandlers);
80
+ this.ensureFeatureOverrideKeysExist(module, "interceptors", moduleOverride.overrides.interceptors);
81
+ this.ensureFeatureOverrideKeysExist(module, "initializers", moduleOverride.overrides.initializers);
82
+ }
83
+ ensureFeatureOverrideKeysExist(module, featureKind, overrides) {
84
+ if (!overrides)
85
+ return;
86
+ const featureKeys = new Set(Object.keys(module[featureKind] || {}));
87
+ for (const key of Object.keys(overrides)) {
88
+ if (!featureKeys.has(key)) {
89
+ throw new ERRORS.ModuleFeatureOverrideNotFoundError(module.name, featureKind, key);
90
+ }
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,14 @@
1
+ import type { InternalModuleLike as M } from "../modules/runtime-module.types.js";
2
+ import type { ModuleScope } from "./container-context-base.js";
3
+ import type { DiContextOptions } from "./di-context-base.js";
4
+ import { DIContextBase } from "./di-context-base.js";
5
+ export declare class AsyncDIContext extends DIContextBase {
6
+ private readonly moduleTreePromiseMap;
7
+ private constructor();
8
+ static create(module: M | Promise<M>, options?: DiContextOptions): Promise<ModuleScope>;
9
+ private bootstrap;
10
+ private initializeGlobalModulesAsync;
11
+ private registerModuleWithScopeAsync;
12
+ private registerNewModuleWithScopeAsync;
13
+ private resolveImportsAsync;
14
+ }