awilixify 2.2.1 → 3.1.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 (119) hide show
  1. package/README.md +15 -6
  2. package/dist/index.d.ts +19 -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/devtools/devtools.types.d.ts +63 -0
  9. package/dist/lib/devtools/devtools.types.js +1 -0
  10. package/dist/lib/devtools/helpers.d.ts +2 -0
  11. package/dist/lib/devtools/helpers.js +18 -0
  12. package/dist/lib/devtools/index.d.ts +4 -0
  13. package/dist/lib/devtools/index.js +3 -0
  14. package/dist/lib/di/common.types.d.ts +6 -0
  15. package/dist/lib/di/common.types.js +1 -0
  16. package/dist/lib/di/contexts/container-context-base.d.ts +63 -0
  17. package/dist/lib/di/contexts/container-context-base.js +232 -0
  18. package/dist/lib/di/contexts/di-context-async.d.ts +14 -0
  19. package/dist/lib/di/contexts/di-context-async.js +118 -0
  20. package/dist/lib/di/contexts/di-context-base.d.ts +19 -0
  21. package/dist/lib/di/contexts/di-context-base.js +33 -0
  22. package/dist/lib/di/contexts/di-context.d.ts +7 -0
  23. package/dist/lib/di/contexts/di-context.js +9 -0
  24. package/dist/lib/di/contexts/module-graph-ensurer.d.ts +32 -0
  25. package/dist/lib/di/contexts/module-graph-ensurer.js +50 -0
  26. package/dist/lib/di/errors.d.ts +69 -0
  27. package/dist/lib/di/errors.js +154 -0
  28. package/dist/lib/di/modules/module-def.types.d.ts +117 -0
  29. package/dist/lib/di/modules/module-def.types.js +1 -0
  30. package/dist/lib/di/modules/module-factories.d.ts +16 -0
  31. package/dist/lib/di/modules/module-factories.js +54 -0
  32. package/dist/lib/di/modules/module-overrides.d.ts +70 -0
  33. package/dist/lib/di/modules/module-overrides.js +3 -0
  34. package/dist/lib/di/modules/module-ref.types.d.ts +13 -0
  35. package/dist/lib/di/modules/module-ref.types.js +1 -0
  36. package/dist/lib/di/modules/module.types.d.ts +178 -0
  37. package/dist/lib/di/modules/module.types.js +1 -0
  38. package/dist/lib/di/modules/runtime-module.types.d.ts +32 -0
  39. package/dist/lib/di/modules/runtime-module.types.js +1 -0
  40. package/dist/lib/di/processors/controller-processor.d.ts +13 -0
  41. package/dist/lib/di/processors/controller-processor.js +76 -0
  42. package/dist/lib/di/processors/handler-processor.d.ts +19 -0
  43. package/dist/lib/di/processors/handler-processor.js +103 -0
  44. package/dist/lib/di/processors/initializer-processor.d.ts +20 -0
  45. package/dist/lib/di/processors/initializer-processor.js +95 -0
  46. package/dist/lib/di/processors/interceptor-processor.d.ts +21 -0
  47. package/dist/lib/di/processors/interceptor-processor.js +117 -0
  48. package/dist/lib/di/processors/keyed-feature-registrar.d.ts +19 -0
  49. package/dist/lib/di/processors/keyed-feature-registrar.js +112 -0
  50. package/dist/lib/di/processors/lifecycle-processor.d.ts +37 -0
  51. package/dist/lib/di/processors/lifecycle-processor.js +175 -0
  52. package/dist/lib/di/processors/overrides-processor.d.ts +24 -0
  53. package/dist/lib/di/processors/overrides-processor.js +69 -0
  54. package/dist/lib/di/providers/provider-dependency-sorter.d.ts +9 -0
  55. package/dist/lib/di/providers/provider-dependency-sorter.js +76 -0
  56. package/dist/lib/di/providers/provider-resolver.d.ts +35 -0
  57. package/dist/lib/di/providers/provider-resolver.js +168 -0
  58. package/dist/lib/di/providers/provider.types.d.ts +1 -0
  59. package/dist/lib/di/providers/provider.types.js +1 -0
  60. package/dist/lib/di/providers/types/controller.types.d.ts +9 -0
  61. package/dist/lib/di/providers/types/controller.types.js +1 -0
  62. package/dist/lib/di/providers/types/decorator-context.types.d.ts +9 -0
  63. package/dist/lib/di/providers/types/decorator-context.types.js +1 -0
  64. package/dist/lib/di/providers/types/handler.types.d.ts +9 -0
  65. package/dist/lib/di/providers/types/handler.types.js +1 -0
  66. package/dist/lib/di/providers/types/index.d.ts +7 -0
  67. package/dist/lib/di/providers/types/index.js +7 -0
  68. package/dist/lib/di/providers/types/initializer.types.d.ts +16 -0
  69. package/dist/lib/di/providers/types/initializer.types.js +3 -0
  70. package/dist/lib/di/providers/types/interceptor.types.d.ts +18 -0
  71. package/dist/lib/di/providers/types/interceptor.types.js +1 -0
  72. package/dist/lib/di/providers/types/middleware.types.d.ts +10 -0
  73. package/dist/lib/di/providers/types/middleware.types.js +1 -0
  74. package/dist/lib/di/providers/types/provider.types.d.ts +26 -0
  75. package/dist/lib/di/providers/types/provider.types.js +1 -0
  76. package/dist/lib/di/request-scope-context.d.ts +5 -0
  77. package/dist/lib/di/request-scope-context.js +28 -0
  78. package/dist/lib/di/type-guards.d.ts +35 -0
  79. package/dist/lib/di/type-guards.js +84 -0
  80. package/dist/lib/http/decorators.d.ts +33 -0
  81. package/dist/lib/http/decorators.js +151 -0
  82. package/dist/lib/http/exceptions.d.ts +58 -0
  83. package/dist/lib/http/exceptions.js +71 -0
  84. package/dist/lib/http/http-verbs.d.ts +12 -0
  85. package/dist/lib/http/http-verbs.js +11 -0
  86. package/dist/lib/http/index.d.ts +3 -0
  87. package/dist/lib/http/index.js +3 -0
  88. package/dist/lib/http/openapi-builder.d.ts +27 -0
  89. package/dist/lib/http/openapi-builder.js +83 -0
  90. package/dist/lib/mediator/contract.types.d.ts +159 -0
  91. package/dist/lib/mediator/contract.types.js +1 -0
  92. package/dist/lib/mediator/errors.d.ts +15 -0
  93. package/dist/lib/mediator/errors.js +33 -0
  94. package/dist/lib/mediator/global-middlewares.types.d.ts +13 -0
  95. package/dist/lib/mediator/global-middlewares.types.js +1 -0
  96. package/dist/lib/mediator/handler.types.d.ts +16 -0
  97. package/dist/lib/mediator/handler.types.js +1 -0
  98. package/dist/lib/mediator/mediator.d.ts +24 -0
  99. package/dist/lib/mediator/mediator.js +134 -0
  100. package/dist/lib/mediator/mediator.types.d.ts +64 -0
  101. package/dist/lib/mediator/mediator.types.js +1 -0
  102. package/dist/lib/mediator/middleware.types.d.ts +41 -0
  103. package/dist/lib/mediator/middleware.types.js +1 -0
  104. package/dist/lib/mediator/result.d.ts +18 -0
  105. package/dist/lib/mediator/result.js +24 -0
  106. package/dist/lib/react/errors.d.ts +12 -0
  107. package/dist/lib/react/errors.js +24 -0
  108. package/dist/lib/react/index.d.ts +4 -0
  109. package/dist/lib/react/index.js +4 -0
  110. package/dist/lib/react/react-component-processor.d.ts +10 -0
  111. package/dist/lib/react/react-component-processor.js +62 -0
  112. package/dist/lib/react/react-di-context.d.ts +16 -0
  113. package/dist/lib/react/react-di-context.js +52 -0
  114. package/dist/lib/react/react-module-factories.d.ts +6 -0
  115. package/dist/lib/react/react-module-factories.js +34 -0
  116. package/dist/lib/react/react-module.types.d.ts +169 -0
  117. package/dist/lib/react/react-module.types.js +1 -0
  118. package/dist/tsconfig.tsbuildinfo +1 -0
  119. package/package.json +33 -3
@@ -0,0 +1,16 @@
1
+ import type { AnyContract } from "./contract.types.js";
2
+ import type { EmptyContext } from "./middleware.types.js";
3
+ export interface Handler<C extends AnyContract, K extends C["key"] = C["key"]> {
4
+ readonly contract: C;
5
+ executor: Executor<ExtractPayload<C, K>, ExtractResponse<C, K>, ExtractContractContext<C>>;
6
+ }
7
+ export type Executor<P = unknown, R = unknown, Ctx extends EmptyContext = EmptyContext> = (payload: P, context: Ctx) => Promise<R>;
8
+ type ExtractContractContext<C extends AnyContract> = C extends {
9
+ context: infer TContext extends Record<string, unknown>;
10
+ } ? TContext : EmptyContext;
11
+ type ExtractContractByKey<C extends AnyContract, K extends C["key"]> = Extract<C, {
12
+ key: K;
13
+ }>;
14
+ export type ExtractPayload<C extends AnyContract, K extends C["key"]> = ExtractContractByKey<C, K>["payload"];
15
+ export type ExtractResponse<C extends AnyContract, K extends C["key"]> = ExtractContractByKey<C, K>["response"];
16
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { DevtoolsProcessorRef } from "../devtools/devtools.types.js";
2
+ import type { AnyContract } from "./contract.types.js";
3
+ import type { Executor, ExtractPayload } from "./handler.types.js";
4
+ import type { ExecuteArgs, ExecuteResponse, ExecuteResponseByScenario, ExecuteRuntimeOptions, ExtractScenarioName } from "./mediator.types.js";
5
+ import type { MiddlewareResolverMap } from "./middleware.types.js";
6
+ export declare class Mediator<C extends AnyContract> {
7
+ private handlers;
8
+ private middlewareResolvers;
9
+ private handlerType;
10
+ private moduleName;
11
+ private devtoolsProcessorRef;
12
+ constructor(middlewareResolvers: MiddlewareResolverMap, moduleName: string, handlerType: string | undefined, devtoolsProcessorRef: DevtoolsProcessorRef);
13
+ register(key: string, executor: Executor): void;
14
+ execute<K extends C["key"], Name extends ExtractScenarioName<C, K>>(key: K, payload: ExtractPayload<C, K>, options: ExecuteRuntimeOptions<C, K> & {
15
+ scenario: Name;
16
+ }): Promise<ExecuteResponseByScenario<C, K, Name>>;
17
+ execute<K extends C["key"], TOptions extends ExecuteRuntimeOptions<C, K> = ExecuteRuntimeOptions<C, K>>(key: K, payload: ExtractPayload<C, K>, ...args: ExecuteArgs<C, K, TOptions>): Promise<ExecuteResponse<C, K>>;
18
+ private executeMiddlewares;
19
+ private processMiddlewareResult;
20
+ private resolveApplicableMiddlewares;
21
+ private ensureMiddlewareDependencies;
22
+ private mergeContext;
23
+ private isResult;
24
+ }
@@ -0,0 +1,134 @@
1
+ import { runInRequestScopeContext } from "../di/request-scope-context.js";
2
+ import * as errors from "./errors.js";
3
+ import { Result } from "./result.js";
4
+ export class Mediator {
5
+ handlers = new Map();
6
+ middlewareResolvers;
7
+ handlerType;
8
+ moduleName;
9
+ devtoolsProcessorRef;
10
+ constructor(middlewareResolvers, moduleName, handlerType = "handler", devtoolsProcessorRef) {
11
+ this.handlerType = handlerType;
12
+ this.moduleName = moduleName;
13
+ this.middlewareResolvers = middlewareResolvers;
14
+ this.devtoolsProcessorRef = devtoolsProcessorRef;
15
+ }
16
+ register(key, executor) {
17
+ const keyStr = String(key);
18
+ if (this.handlers.has(keyStr)) {
19
+ throw new errors.HandlerAlreadyRegisteredError(keyStr);
20
+ }
21
+ this.handlers.set(keyStr, executor);
22
+ }
23
+ async execute(key, payload, options) {
24
+ return runInRequestScopeContext(async () => {
25
+ const keyStr = String(key);
26
+ const executor = this.handlers.get(keyStr);
27
+ if (!executor) {
28
+ throw new errors.HandlerNotRegisteredError(keyStr, this.moduleName);
29
+ }
30
+ const { executionContext, includePreHandlerKeys, excludePreHandlerKeys } = options ?? {};
31
+ const applicableMiddlewares = this.resolveApplicableMiddlewares({
32
+ excludePreHandlerKeys,
33
+ includePreHandlerKeys,
34
+ });
35
+ const middlewareResult = await this.executeMiddlewares(applicableMiddlewares, payload, executionContext ?? {});
36
+ if (middlewareResult.type === "error") {
37
+ return middlewareResult.error;
38
+ }
39
+ const handlerResult = await executor(payload, middlewareResult.context);
40
+ if (middlewareResult.hasResultMiddleware) {
41
+ return (this.isResult(handlerResult)
42
+ ? handlerResult
43
+ : Result.ok(handlerResult));
44
+ }
45
+ return handlerResult;
46
+ });
47
+ }
48
+ async executeMiddlewares(middlewares, payload, executionContext) {
49
+ let context = {};
50
+ let hasResultMiddleware = false;
51
+ for (const [middlewareKey, middleware] of middlewares) {
52
+ const result = await (this.devtoolsProcessorRef.current?.tracer.recordSpan({
53
+ kind: "prehandler",
54
+ moduleName: this.moduleName,
55
+ providerKey: `${this.handlerType}:prehandler:${middlewareKey}`,
56
+ methodName: "execute",
57
+ args: [payload, context, executionContext],
58
+ callback: () => middleware.execute(payload, context, executionContext),
59
+ }) ?? middleware.execute(payload, context, executionContext));
60
+ if (this.isResult(result)) {
61
+ hasResultMiddleware = true;
62
+ }
63
+ const processed = this.processMiddlewareResult(result, context, middlewareKey);
64
+ if (processed.shouldShortCircuit) {
65
+ return { type: "error", error: processed.result };
66
+ }
67
+ context = processed.context;
68
+ }
69
+ return { type: "success", context, hasResultMiddleware };
70
+ }
71
+ processMiddlewareResult(result, currentContext, middlewareKey) {
72
+ if (this.isResult(result)) {
73
+ return result.ok
74
+ ? {
75
+ shouldShortCircuit: false,
76
+ context: this.mergeContext(currentContext, result.value, middlewareKey),
77
+ }
78
+ : { shouldShortCircuit: true, result };
79
+ }
80
+ return {
81
+ shouldShortCircuit: false,
82
+ context: this.mergeContext(currentContext, result, middlewareKey),
83
+ };
84
+ }
85
+ resolveApplicableMiddlewares(options) {
86
+ const { includePreHandlerKeys = [], excludePreHandlerKeys = [] } = options ?? {};
87
+ const filtered = Array.from(this.middlewareResolvers.entries()).filter(([key]) => {
88
+ if (excludePreHandlerKeys.includes(key)) {
89
+ return false;
90
+ }
91
+ if (includePreHandlerKeys.length > 0) {
92
+ return includePreHandlerKeys.includes(key);
93
+ }
94
+ return true;
95
+ });
96
+ const resolvedMiddlewares = filtered.map(([key, resolver]) => [key, resolver()]);
97
+ this.ensureMiddlewareDependencies(resolvedMiddlewares);
98
+ return resolvedMiddlewares;
99
+ }
100
+ ensureMiddlewareDependencies(middlewares) {
101
+ const processedKeys = [];
102
+ for (const [key, middleware] of middlewares) {
103
+ const requires = middleware.requires || [];
104
+ for (const requiredKey of requires) {
105
+ if (!processedKeys.includes(requiredKey)) {
106
+ throw new errors.MiddlewareRequiredError(key, requiredKey);
107
+ }
108
+ }
109
+ processedKeys.push(key);
110
+ }
111
+ }
112
+ mergeContext(currentContext, data, middlewareKey) {
113
+ if (data === undefined) {
114
+ return currentContext;
115
+ }
116
+ if (typeof data !== "object" || data === null) {
117
+ const returnedType = data === null ? "null" : typeof data;
118
+ throw new errors.InvalidMiddlewareReturnValueError(middlewareKey, returnedType);
119
+ }
120
+ const currentKeys = Object.keys(currentContext);
121
+ const newKeys = Object.keys(data);
122
+ const conflictingKeys = newKeys.filter((key) => currentKeys.includes(key));
123
+ if (conflictingKeys.length > 0) {
124
+ throw new errors.ContextKeyConflictError(middlewareKey, conflictingKeys);
125
+ }
126
+ return { ...currentContext, ...data };
127
+ }
128
+ isResult(value) {
129
+ return (typeof value === "object" &&
130
+ value !== null &&
131
+ "ok" in value &&
132
+ typeof value.ok === "boolean");
133
+ }
134
+ }
@@ -0,0 +1,64 @@
1
+ import type { AnyContract } from "./contract.types.js";
2
+ import type { ExecutionContext } from "./middleware.types.js";
3
+ export type ExtractScenarioName<C extends AnyContract, K extends C["key"]> = Extract<keyof ExtractContractScenarios<C, K>, string>;
4
+ export type ExecuteResponseByScenario<C extends AnyContract, K extends C["key"], Name extends ExtractScenarioName<C, K>> = ExtractScenarioReturnType<C, K, Name>;
5
+ export type ExecuteRuntimeOptions<C extends AnyContract, K extends C["key"]> = ExecutionContextOption & ExecuteOptions<C, K>;
6
+ export type ExecuteArgs<C extends AnyContract, K extends C["key"], TOptions extends ExecuteRuntimeOptions<C, K> = ExecuteRuntimeOptions<C, K>> = IsExecuteOptionsRequired<C, K> extends true ? [options: TOptions] : [options?: never];
7
+ export type ExecuteResponse<C extends AnyContract, K extends C["key"]> = ExtractContractReturnType<C, K>;
8
+ type ExtractContractScenarios<C extends AnyContract, K extends C["key"]> = Extract<C, {
9
+ key: K;
10
+ }> extends {
11
+ scenarios: infer S extends Record<string, unknown>;
12
+ } ? S : never;
13
+ type ExtractScenarioByName<C extends AnyContract, K extends C["key"], Name extends string> = Name extends keyof ExtractContractScenarios<C, K> ? ExtractContractScenarios<C, K>[Name] : never;
14
+ type ExtractScenarioConfig<C extends AnyContract, K extends C["key"], Name extends string> = ExtractScenarioByName<C, K, Name> extends {
15
+ config: infer Config;
16
+ } ? Config : never;
17
+ type ExtractScenarioReturnType<C extends AnyContract, K extends C["key"], Name extends string> = ExtractScenarioByName<C, K, Name> extends {
18
+ returnType: infer ReturnType;
19
+ } ? ReturnType : ExtractContractReturnType<C, K>;
20
+ type ExecuteNoScenarioOptions = {
21
+ scenario?: never;
22
+ includePreHandlerKeys?: never;
23
+ excludePreHandlerKeys?: never;
24
+ };
25
+ type ExecuteOptions<C extends AnyContract, K extends C["key"]> = [
26
+ ExtractContractScenarios<C, K>
27
+ ] extends [never] ? ExecuteNoScenarioOptions : ExecuteScenarioOptions<C, K>;
28
+ type ScenarioIncludeOption<C extends AnyContract, K extends C["key"], Name extends string> = ExtractScenarioConfig<C, K, Name> extends {
29
+ includePreHandlerKeys: infer Include extends readonly any[];
30
+ } ? {
31
+ includePreHandlerKeys: Include;
32
+ } : {
33
+ includePreHandlerKeys?: never;
34
+ };
35
+ type ScenarioExcludeOption<C extends AnyContract, K extends C["key"], Name extends string> = ExtractScenarioConfig<C, K, Name> extends {
36
+ excludePreHandlerKeys: infer Exclude extends readonly any[];
37
+ } ? {
38
+ excludePreHandlerKeys: Exclude;
39
+ } : {
40
+ excludePreHandlerKeys?: never;
41
+ };
42
+ type ExecuteScenarioOptions<C extends AnyContract, K extends C["key"]> = {
43
+ [Name in ExtractScenarioName<C, K>]: {
44
+ scenario: Name;
45
+ } & ScenarioIncludeOption<C, K, Name> & ScenarioExcludeOption<C, K, Name>;
46
+ }[ExtractScenarioName<C, K>];
47
+ type ExecutionContextOption = [keyof ExecutionContext] extends [never] ? {
48
+ executionContext?: never;
49
+ } : {
50
+ executionContext: ExecutionContext;
51
+ };
52
+ type HasScenarios<C extends AnyContract, K extends C["key"]> = [
53
+ ExtractContractScenarios<C, K>
54
+ ] extends [never] ? false : true;
55
+ type IsExecutionContextRequired = [keyof ExecutionContext] extends [never] ? false : true;
56
+ type IsExecuteOptionsRequired<C extends AnyContract, K extends C["key"]> = HasScenarios<C, K> extends true ? true : IsExecutionContextRequired;
57
+ type ExtractContractReturnType<C extends AnyContract, K extends C["key"]> = Extract<C, {
58
+ key: K;
59
+ }> extends {
60
+ returnType: infer ReturnType;
61
+ } ? ReturnType : Extract<C, {
62
+ key: K;
63
+ }>["response"];
64
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,41 @@
1
+ import type { Result } from "./result.js";
2
+ type EmptyObject = Record<never, never>;
3
+ export interface ExecutionContext {
4
+ }
5
+ export type EmptyContext = EmptyObject;
6
+ export type AnyMiddlewareContract = MiddlewareContract<string, unknown, any>;
7
+ export type AnyContext = Record<string, unknown>;
8
+ export type MiddlewareResolver = () => Middleware;
9
+ export type MiddlewareResolverMap = Map<string, () => Middleware>;
10
+ export type Middleware<C extends AnyMiddlewareContract = AnyMiddlewareContract> = MiddlewareRequires<C> & {
11
+ readonly contract: C;
12
+ execute: MiddlewareFn<ExtractContractContext<C>, ExtractMiddlewareReturnType<C>>;
13
+ };
14
+ export type ExtractMiddlewareContext<T> = [T] extends [Result<infer Data, any>] ? Data extends Record<string, unknown> ? Data : EmptyObject : T extends Record<string, unknown> ? T : EmptyObject;
15
+ export type MiddlewareContract<K extends string, ReturnType, RequiredContracts extends readonly AnyMiddlewareContract[] = readonly []> = {
16
+ key: K;
17
+ returnType: ReturnType;
18
+ requires: ExtractRequiredKeysTupleFromContracts<RequiredContracts>;
19
+ context: MergeContextFromContracts<RequiredContracts>;
20
+ executionContext: ExecutionContext;
21
+ };
22
+ type ExtractRequiredKeysTupleFromContracts<Contracts extends readonly AnyMiddlewareContract[]> = number extends Contracts["length"] ? readonly string[] : Contracts extends readonly [] ? readonly [] : Contracts extends readonly [infer First, ...infer Rest] ? First extends AnyMiddlewareContract ? Rest extends readonly AnyMiddlewareContract[] ? readonly [
23
+ First["key"],
24
+ ...ExtractRequiredKeysTupleFromContracts<Rest>
25
+ ] : readonly [First["key"]] : readonly [] : readonly [];
26
+ type MergeContextFromContracts<Contracts extends readonly AnyMiddlewareContract[]> = number extends Contracts["length"] ? AnyContext : Contracts extends readonly [] ? EmptyObject : Contracts extends readonly [infer First, ...infer Rest] ? First extends AnyMiddlewareContract ? Rest extends readonly AnyMiddlewareContract[] ? ExtractMiddlewareContext<First["returnType"]> & MergeContextFromContracts<Rest> : ExtractMiddlewareContext<First["returnType"]> : EmptyObject : EmptyObject;
27
+ type ExtractMiddlewareReturnType<C extends AnyMiddlewareContract> = C["returnType"];
28
+ type ExtractRequiredKeys<C extends AnyMiddlewareContract> = C["requires"][number];
29
+ type ExtractRequiredList<C extends AnyMiddlewareContract> = C["requires"];
30
+ type ExtractContractContext<C extends AnyMiddlewareContract> = C["context"];
31
+ type MiddlewareFn<RequiredContext extends AnyContext = EmptyContext, ReturnType = unknown> = (payload: unknown, context: RequiredContext, executionContext: ExecutionContext) => Promise<ReturnType>;
32
+ type MiddlewareRequires<C extends AnyMiddlewareContract> = [
33
+ ExtractRequiredKeys<C>
34
+ ] extends [never] ? {
35
+ readonly requires?: readonly [];
36
+ } : string extends ExtractRequiredKeys<C> ? {
37
+ readonly requires?: readonly string[];
38
+ } : {
39
+ readonly requires: ExtractRequiredList<C>;
40
+ };
41
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ export type Result<T, E> = Ok<T> | Err<E>;
2
+ declare class Ok<T> {
3
+ readonly value: T;
4
+ readonly ok: true;
5
+ readonly error: undefined;
6
+ constructor(value: T);
7
+ }
8
+ declare class Err<E> {
9
+ readonly error: E;
10
+ readonly ok: false;
11
+ readonly value: undefined;
12
+ constructor(error: E);
13
+ }
14
+ export declare const Result: {
15
+ ok<T>(value: T): Result<T, never>;
16
+ error<E>(error: E): Result<never, E>;
17
+ };
18
+ export {};
@@ -0,0 +1,24 @@
1
+ class Ok {
2
+ value;
3
+ ok = true;
4
+ error = undefined;
5
+ constructor(value) {
6
+ this.value = value;
7
+ }
8
+ }
9
+ class Err {
10
+ error;
11
+ ok = false;
12
+ value = undefined;
13
+ constructor(error) {
14
+ this.error = error;
15
+ }
16
+ }
17
+ export const Result = {
18
+ ok(value) {
19
+ return new Ok(value);
20
+ },
21
+ error(error) {
22
+ return new Err(error);
23
+ },
24
+ };
@@ -0,0 +1,12 @@
1
+ export declare class ComponentNameConflictError extends Error {
2
+ constructor(moduleName: string, conflictingKeys: string[]);
3
+ }
4
+ export declare class InvalidComponentExportError extends Error {
5
+ constructor(moduleName: string, componentKey: string);
6
+ }
7
+ export declare class ComponentDepsOverrideError extends Error {
8
+ constructor(componentKey: string);
9
+ }
10
+ export declare class ScopedProviderLifetimeError extends Error {
11
+ constructor(moduleName: string, providerKey: string);
12
+ }
@@ -0,0 +1,24 @@
1
+ export class ComponentNameConflictError extends Error {
2
+ constructor(moduleName, conflictingKeys) {
3
+ super(`Module "${moduleName}" has component name conflicts with providers or imported features: ${conflictingKeys.join(", ")}`);
4
+ this.name = "ComponentNameConflictError";
5
+ }
6
+ }
7
+ export class InvalidComponentExportError extends Error {
8
+ constructor(moduleName, componentKey) {
9
+ super(`Module "${moduleName}" exports component "${componentKey}", but that component is not declared by the module.`);
10
+ this.name = "InvalidComponentExportError";
11
+ }
12
+ }
13
+ export class ComponentDepsOverrideError extends Error {
14
+ constructor(componentKey) {
15
+ super(`Component "${componentKey}" received a "deps" prop. React component dependencies are injected by ReactDIContext and cannot be overridden from JSX.`);
16
+ this.name = "ComponentDepsOverrideError";
17
+ }
18
+ }
19
+ export class ScopedProviderLifetimeError extends Error {
20
+ constructor(moduleName, providerKey) {
21
+ super(`Provider "${providerKey}" in React module "${moduleName}" uses SCOPED lifetime. ReactDIContext supports SINGLETON and TRANSIENT providers only.`);
22
+ this.name = "ScopedProviderLifetimeError";
23
+ }
24
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./errors.js";
2
+ export * from "./react-di-context.js";
3
+ export * from "./react-module.types.js";
4
+ export * from "./react-module-factories.js";
@@ -0,0 +1,4 @@
1
+ export * from "./errors.js";
2
+ export * from "./react-di-context.js";
3
+ export * from "./react-module.types.js";
4
+ export * from "./react-module-factories.js";
@@ -0,0 +1,10 @@
1
+ import * as Awilix from "awilix";
2
+ import type { RegisteredModuleScope } from "../di/contexts/container-context-base.js";
3
+ import type { InternalModuleLike as M } from "../di/modules/runtime-module.types.js";
4
+ export declare class ReactComponentProcessor {
5
+ processComponents(m: M, scope: Awilix.AwilixContainer): void;
6
+ registerExportedComponents(scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[]): void;
7
+ getExportedComponentKeys(module: M): string[];
8
+ private wrapComponent;
9
+ private createDepsProxy;
10
+ }
@@ -0,0 +1,62 @@
1
+ import * as Awilix from "awilix";
2
+ import { createElement } from "react";
3
+ import * as ERRORS from "./errors.js";
4
+ export class ReactComponentProcessor {
5
+ processComponents(m, scope) {
6
+ if (!m.components)
7
+ return;
8
+ const componentKeys = Object.keys(m.components);
9
+ const conflicts = componentKeys.filter((key) => scope.registrations[key]);
10
+ if (conflicts.length > 0) {
11
+ throw new ERRORS.ComponentNameConflictError(m.name, conflicts);
12
+ }
13
+ for (const [key, component] of Object.entries(m.components)) {
14
+ scope.register({
15
+ [key]: Awilix.asValue(this.wrapComponent(key, component, scope)),
16
+ });
17
+ }
18
+ }
19
+ registerExportedComponents(scope, importedModulesWithScope) {
20
+ for (const { module, moduleScope } of importedModulesWithScope) {
21
+ for (const key of module.componentExports || []) {
22
+ if (!module.components?.[key]) {
23
+ throw new ERRORS.InvalidComponentExportError(module.name, key);
24
+ }
25
+ if (scope.registrations[key]) {
26
+ throw new ERRORS.ComponentNameConflictError(module.name, [key]);
27
+ }
28
+ scope.register({
29
+ [key]: Awilix.asFunction(() => moduleScope.scope.resolve(key), {
30
+ lifetime: Awilix.Lifetime.TRANSIENT,
31
+ isLeakSafe: true,
32
+ }),
33
+ });
34
+ }
35
+ }
36
+ }
37
+ getExportedComponentKeys(module) {
38
+ return module.componentExports ? [...module.componentExports] : [];
39
+ }
40
+ wrapComponent(key, component, scope) {
41
+ return (props = {}) => {
42
+ if (Object.hasOwn(props, "deps")) {
43
+ throw new ERRORS.ComponentDepsOverrideError(key);
44
+ }
45
+ return createElement(component, {
46
+ ...props,
47
+ deps: this.createDepsProxy(scope),
48
+ });
49
+ };
50
+ }
51
+ createDepsProxy(scope) {
52
+ return new Proxy({}, {
53
+ get: (_target, prop) => {
54
+ if (typeof prop !== "string")
55
+ return undefined;
56
+ if (!scope.registrations[prop])
57
+ return undefined;
58
+ return scope.resolve(prop);
59
+ },
60
+ });
61
+ }
62
+ }
@@ -0,0 +1,16 @@
1
+ import * as Awilix from "awilix";
2
+ import { ContainerContextBase, type ContainerContextOptions, type ModuleScope, type RegisteredModuleScope } from "../di/contexts/container-context-base.js";
3
+ import type { InternalModuleLike as M } from "../di/modules/runtime-module.types.js";
4
+ import type { NonScopedResolverOptions } from "./react-module.types.js";
5
+ type ReactContainerContextOptions = ContainerContextOptions<NonScopedResolverOptions<any>>;
6
+ export declare class ReactDIContext extends ContainerContextBase {
7
+ private readonly componentProcessor;
8
+ private constructor();
9
+ static create(module: M, options?: ReactContainerContextOptions): ModuleScope;
10
+ protected registerImportedFeatures(scope: Awilix.AwilixContainer, importedModulesWithScope: RegisteredModuleScope[]): void;
11
+ protected ensureAdditionalNameConflicts(m: M, resolvedImports: M[]): void;
12
+ protected beforeRegisterProviders(m: M): void;
13
+ protected afterRegisterProviders(m: M, scope: Awilix.AwilixContainer): void;
14
+ private hasScopedProviderLifetime;
15
+ }
16
+ export {};
@@ -0,0 +1,52 @@
1
+ import * as Awilix from "awilix";
2
+ import { ContainerContextBase, } from "../di/contexts/container-context-base.js";
3
+ import { ProviderResolver } from "../di/providers/provider-resolver.js";
4
+ import * as REACT_ERRORS from "./errors.js";
5
+ import { ReactComponentProcessor } from "./react-component-processor.js";
6
+ export class ReactDIContext extends ContainerContextBase {
7
+ componentProcessor = new ReactComponentProcessor();
8
+ constructor(options) {
9
+ super(options);
10
+ this.providerResolver = new ProviderResolver(undefined, this.options.providerOptions || {}, {});
11
+ }
12
+ static create(module, options) {
13
+ return new ReactDIContext(options ?? {}).bootstrapModule(module);
14
+ }
15
+ registerImportedFeatures(scope, importedModulesWithScope) {
16
+ this.registerExportedProviders(scope, importedModulesWithScope);
17
+ this.componentProcessor.registerExportedComponents(scope, importedModulesWithScope);
18
+ }
19
+ ensureAdditionalNameConflicts(m, resolvedImports) {
20
+ const componentKeys = Object.keys(m.components || {});
21
+ const providerConflicts = Object.keys(m.providers || {}).filter((key) => componentKeys.includes(key));
22
+ const importComponentConflicts = [
23
+ ...this.globalModulesWithScope.flatMap(({ module: globalModule }) => this.componentProcessor.getExportedComponentKeys(globalModule)),
24
+ ...resolvedImports.flatMap((importItem) => this.componentProcessor.getExportedComponentKeys(importItem)),
25
+ ].filter((key) => componentKeys.includes(key));
26
+ const conflicts = [...providerConflicts, ...importComponentConflicts];
27
+ if (conflicts.length > 0) {
28
+ throw new REACT_ERRORS.ComponentNameConflictError(m.name, conflicts);
29
+ }
30
+ }
31
+ beforeRegisterProviders(m) {
32
+ if (m.providerOptions?.lifetime === Awilix.Lifetime.SCOPED ||
33
+ this.options.providerOptions?.lifetime === Awilix.Lifetime.SCOPED) {
34
+ throw new REACT_ERRORS.ScopedProviderLifetimeError(m.name, "providerOptions");
35
+ }
36
+ for (const [key, provider] of Object.entries(m.providers || {})) {
37
+ if (this.hasScopedProviderLifetime(provider)) {
38
+ throw new REACT_ERRORS.ScopedProviderLifetimeError(m.name, key);
39
+ }
40
+ }
41
+ }
42
+ afterRegisterProviders(m, scope) {
43
+ this.componentProcessor.processComponents(m, scope);
44
+ }
45
+ hasScopedProviderLifetime(provider) {
46
+ return (typeof provider === "object" &&
47
+ provider !== null &&
48
+ ("useClass" in provider || "useFactory" in provider) &&
49
+ "lifetime" in provider &&
50
+ provider.lifetime === Awilix.Lifetime.SCOPED);
51
+ }
52
+ }
@@ -0,0 +1,6 @@
1
+ import type { Module, ModuleDefinition } from "./react-module.types.js";
2
+ export type ModuleOptions = {
3
+ hashNameFrom?: unknown;
4
+ hashLength?: number;
5
+ };
6
+ export declare function createModule<TDef extends ModuleDefinition>(module: Module<TDef>, options?: ModuleOptions): Module<TDef>;
@@ -0,0 +1,34 @@
1
+ export function createModule(module, options) {
2
+ if (options?.hashNameFrom === undefined) {
3
+ return module;
4
+ }
5
+ const hash = hashString(stableStringify(options.hashNameFrom)).slice(0, Math.max(4, options.hashLength ?? 8));
6
+ return {
7
+ ...module,
8
+ name: `${module.name}_${hash}`,
9
+ };
10
+ }
11
+ function hashString(value) {
12
+ let hash = 5381;
13
+ for (let index = 0; index < value.length; index += 1) {
14
+ hash = (hash * 33) ^ value.charCodeAt(index);
15
+ }
16
+ return (hash >>> 0).toString(16).padStart(8, "0");
17
+ }
18
+ function stableStringify(value) {
19
+ return JSON.stringify(sortRecursively(value));
20
+ }
21
+ function sortRecursively(value) {
22
+ if (Array.isArray(value)) {
23
+ return value.map(sortRecursively);
24
+ }
25
+ if (value && typeof value === "object") {
26
+ return Object.keys(value)
27
+ .sort()
28
+ .reduce((acc, key) => {
29
+ acc[key] = sortRecursively(value[key]);
30
+ return acc;
31
+ }, {});
32
+ }
33
+ return value;
34
+ }