@nexus-ioc/core 0.6.1 → 0.7.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 (222) hide show
  1. package/README.md +731 -1
  2. package/dist/cjs/browser.js +2 -2
  3. package/dist/cjs/browser.js.map +1 -1
  4. package/dist/cjs/core/child-module.js +32 -0
  5. package/dist/cjs/core/child-module.js.map +1 -0
  6. package/dist/cjs/core/graph/analyze-lazy-module.js +54 -0
  7. package/dist/cjs/core/graph/analyze-lazy-module.js.map +1 -0
  8. package/dist/cjs/core/graph/analyze-module.js +11 -0
  9. package/dist/cjs/core/graph/analyze-module.js.map +1 -1
  10. package/dist/cjs/core/graph/module-graph.js +685 -70
  11. package/dist/cjs/core/graph/module-graph.js.map +1 -1
  12. package/dist/cjs/core/injection/injection-context.js +29 -0
  13. package/dist/cjs/core/injection/injection-context.js.map +1 -0
  14. package/dist/cjs/core/lazy-module-loader.js +41 -0
  15. package/dist/cjs/core/lazy-module-loader.js.map +1 -0
  16. package/dist/cjs/core/module-ref.js +84 -0
  17. package/dist/cjs/core/module-ref.js.map +1 -0
  18. package/dist/cjs/core/modules/container.js +305 -17
  19. package/dist/cjs/core/modules/container.js.map +1 -1
  20. package/dist/cjs/core/modules/module-container-factory.js +2 -2
  21. package/dist/cjs/core/modules/module-container-factory.js.map +1 -1
  22. package/dist/cjs/core/modules/module-container.js +54 -16
  23. package/dist/cjs/core/modules/module-container.js.map +1 -1
  24. package/dist/cjs/core/modules/module-token-factory.js.map +1 -1
  25. package/dist/cjs/core/modules/modules-container.js +43 -3
  26. package/dist/cjs/core/modules/modules-container.js.map +1 -1
  27. package/dist/cjs/core/nexus-applications.browser.js +57 -15
  28. package/dist/cjs/core/nexus-applications.browser.js.map +1 -1
  29. package/dist/cjs/core/nexus-applications.js +440 -82
  30. package/dist/cjs/core/nexus-applications.js.map +1 -1
  31. package/dist/cjs/core/nexus-applications.server.js +57 -15
  32. package/dist/cjs/core/nexus-applications.server.js.map +1 -1
  33. package/dist/cjs/core/resolver/providers-container.js.map +1 -1
  34. package/dist/cjs/core/resolver/resolution-context.js +62 -0
  35. package/dist/cjs/core/resolver/resolution-context.js.map +1 -0
  36. package/dist/cjs/core/resolver/resolver.js +523 -99
  37. package/dist/cjs/core/resolver/resolver.js.map +1 -1
  38. package/dist/cjs/decorators/inject.js +6 -3
  39. package/dist/cjs/decorators/inject.js.map +1 -1
  40. package/dist/cjs/decorators/injectable.js +0 -7
  41. package/dist/cjs/decorators/injectable.js.map +1 -1
  42. package/dist/cjs/decorators/{nsModule.js → module.js} +9 -7
  43. package/dist/cjs/decorators/module.js.map +1 -0
  44. package/dist/cjs/errors/bootstrap-error.js +47 -0
  45. package/dist/cjs/errors/bootstrap-error.js.map +1 -0
  46. package/dist/cjs/errors/child-errors.js +21 -0
  47. package/dist/cjs/errors/child-errors.js.map +1 -0
  48. package/dist/cjs/errors/index.js +24 -0
  49. package/dist/cjs/errors/index.js.map +1 -0
  50. package/dist/cjs/errors/injection-errors.js +25 -0
  51. package/dist/cjs/errors/injection-errors.js.map +1 -0
  52. package/dist/cjs/errors/lazy-module-errors.js +26 -0
  53. package/dist/cjs/errors/lazy-module-errors.js.map +1 -0
  54. package/dist/cjs/errors/provider-errors.js +95 -0
  55. package/dist/cjs/errors/provider-errors.js.map +1 -0
  56. package/dist/cjs/index.js +30 -6
  57. package/dist/cjs/index.js.map +1 -1
  58. package/dist/cjs/interfaces/index.js +1 -0
  59. package/dist/cjs/interfaces/index.js.map +1 -1
  60. package/dist/cjs/interfaces/modules/index.js +1 -0
  61. package/dist/cjs/interfaces/modules/index.js.map +1 -1
  62. package/dist/cjs/interfaces/modules/module-graph.interface.js +2 -0
  63. package/dist/cjs/interfaces/modules/module-graph.interface.js.map +1 -1
  64. package/dist/cjs/interfaces/modules/parent-link.interface.js +3 -0
  65. package/dist/cjs/interfaces/modules/parent-link.interface.js.map +1 -0
  66. package/dist/cjs/interfaces/on-module-destroy.interface.js +3 -0
  67. package/dist/cjs/interfaces/on-module-destroy.interface.js.map +1 -0
  68. package/dist/cjs/interfaces/scope.interface.js +2 -55
  69. package/dist/cjs/interfaces/scope.interface.js.map +1 -1
  70. package/dist/cjs/interfaces/validate-module-keys.js +2 -0
  71. package/dist/cjs/interfaces/validate-module-keys.js.map +1 -1
  72. package/dist/cjs/internal.js +9 -0
  73. package/dist/cjs/internal.js.map +1 -0
  74. package/dist/cjs/server.js +2 -2
  75. package/dist/cjs/server.js.map +1 -1
  76. package/dist/cjs/utils/forward-ref.js +14 -0
  77. package/dist/cjs/utils/forward-ref.js.map +1 -0
  78. package/dist/cjs/utils/helpers.js +14 -4
  79. package/dist/cjs/utils/helpers.js.map +1 -1
  80. package/dist/cjs/utils/lazy-module.js +33 -0
  81. package/dist/cjs/utils/lazy-module.js.map +1 -0
  82. package/dist/esm/browser.js +1 -1
  83. package/dist/esm/browser.js.map +1 -1
  84. package/dist/esm/core/child-module.js +29 -0
  85. package/dist/esm/core/child-module.js.map +1 -0
  86. package/dist/esm/core/graph/analyze-lazy-module.js +50 -0
  87. package/dist/esm/core/graph/analyze-lazy-module.js.map +1 -0
  88. package/dist/esm/core/graph/analyze-module.js +11 -0
  89. package/dist/esm/core/graph/analyze-module.js.map +1 -1
  90. package/dist/esm/core/graph/module-graph.js +686 -71
  91. package/dist/esm/core/graph/module-graph.js.map +1 -1
  92. package/dist/esm/core/injection/injection-context.js +25 -0
  93. package/dist/esm/core/injection/injection-context.js.map +1 -0
  94. package/dist/esm/core/lazy-module-loader.js +36 -0
  95. package/dist/esm/core/lazy-module-loader.js.map +1 -0
  96. package/dist/esm/core/module-ref.js +80 -0
  97. package/dist/esm/core/module-ref.js.map +1 -0
  98. package/dist/esm/core/modules/container.js +305 -17
  99. package/dist/esm/core/modules/container.js.map +1 -1
  100. package/dist/esm/core/modules/module-container-factory.js +2 -2
  101. package/dist/esm/core/modules/module-container-factory.js.map +1 -1
  102. package/dist/esm/core/modules/module-container.js +55 -17
  103. package/dist/esm/core/modules/module-container.js.map +1 -1
  104. package/dist/esm/core/modules/module-token-factory.js.map +1 -1
  105. package/dist/esm/core/modules/modules-container.js +43 -3
  106. package/dist/esm/core/modules/modules-container.js.map +1 -1
  107. package/dist/esm/core/nexus-applications.browser.js +55 -13
  108. package/dist/esm/core/nexus-applications.browser.js.map +1 -1
  109. package/dist/esm/core/nexus-applications.js +439 -81
  110. package/dist/esm/core/nexus-applications.js.map +1 -1
  111. package/dist/esm/core/nexus-applications.server.js +55 -13
  112. package/dist/esm/core/nexus-applications.server.js.map +1 -1
  113. package/dist/esm/core/resolver/providers-container.js.map +1 -1
  114. package/dist/esm/core/resolver/resolution-context.js +58 -0
  115. package/dist/esm/core/resolver/resolution-context.js.map +1 -0
  116. package/dist/esm/core/resolver/resolver.js +524 -100
  117. package/dist/esm/core/resolver/resolver.js.map +1 -1
  118. package/dist/esm/decorators/inject.js +6 -3
  119. package/dist/esm/decorators/inject.js.map +1 -1
  120. package/dist/esm/decorators/injectable.js +0 -7
  121. package/dist/esm/decorators/injectable.js.map +1 -1
  122. package/dist/esm/decorators/{nsModule.js → module.js} +8 -6
  123. package/dist/esm/decorators/module.js.map +1 -0
  124. package/dist/esm/errors/bootstrap-error.js +42 -0
  125. package/dist/esm/errors/bootstrap-error.js.map +1 -0
  126. package/dist/esm/errors/child-errors.js +17 -0
  127. package/dist/esm/errors/child-errors.js.map +1 -0
  128. package/dist/esm/errors/index.js +6 -0
  129. package/dist/esm/errors/index.js.map +1 -0
  130. package/dist/esm/errors/injection-errors.js +20 -0
  131. package/dist/esm/errors/injection-errors.js.map +1 -0
  132. package/dist/esm/errors/lazy-module-errors.js +21 -0
  133. package/dist/esm/errors/lazy-module-errors.js.map +1 -0
  134. package/dist/esm/errors/provider-errors.js +84 -0
  135. package/dist/esm/errors/provider-errors.js.map +1 -0
  136. package/dist/esm/index.js +9 -4
  137. package/dist/esm/index.js.map +1 -1
  138. package/dist/esm/interfaces/index.js +1 -0
  139. package/dist/esm/interfaces/index.js.map +1 -1
  140. package/dist/esm/interfaces/modules/index.js +1 -0
  141. package/dist/esm/interfaces/modules/index.js.map +1 -1
  142. package/dist/esm/interfaces/modules/module-graph.interface.js +2 -0
  143. package/dist/esm/interfaces/modules/module-graph.interface.js.map +1 -1
  144. package/dist/esm/interfaces/modules/parent-link.interface.js +2 -0
  145. package/dist/esm/interfaces/modules/parent-link.interface.js.map +1 -0
  146. package/dist/esm/interfaces/on-module-destroy.interface.js +2 -0
  147. package/dist/esm/interfaces/on-module-destroy.interface.js.map +1 -0
  148. package/dist/esm/interfaces/scope.interface.js +1 -55
  149. package/dist/esm/interfaces/scope.interface.js.map +1 -1
  150. package/dist/esm/interfaces/validate-module-keys.js +2 -0
  151. package/dist/esm/interfaces/validate-module-keys.js.map +1 -1
  152. package/dist/esm/internal.js +3 -0
  153. package/dist/esm/internal.js.map +1 -0
  154. package/dist/esm/server.js +1 -1
  155. package/dist/esm/server.js.map +1 -1
  156. package/dist/esm/utils/forward-ref.js +10 -0
  157. package/dist/esm/utils/forward-ref.js.map +1 -0
  158. package/dist/esm/utils/helpers.js +14 -4
  159. package/dist/esm/utils/helpers.js.map +1 -1
  160. package/dist/esm/utils/lazy-module.js +29 -0
  161. package/dist/esm/utils/lazy-module.js.map +1 -0
  162. package/dist/types/browser.d.ts +1 -1
  163. package/dist/types/core/child-module.d.ts +8 -0
  164. package/dist/types/core/graph/analyze-lazy-module.d.ts +28 -0
  165. package/dist/types/core/graph/analyze-module.d.ts +4 -2
  166. package/dist/types/core/graph/analyze-provider.d.ts +4 -4
  167. package/dist/types/core/graph/module-graph.d.ts +200 -7
  168. package/dist/types/core/graph/providers/analyze-class-provider.d.ts +1 -1
  169. package/dist/types/core/graph/providers/analyze-factory-provider.d.ts +2 -2
  170. package/dist/types/core/graph/providers/analyze-value-provider.d.ts +1 -1
  171. package/dist/types/core/injection/injection-context.d.ts +29 -0
  172. package/dist/types/core/lazy-module-loader.d.ts +17 -0
  173. package/dist/types/core/module-ref.d.ts +34 -0
  174. package/dist/types/core/modules/container.d.ts +134 -18
  175. package/dist/types/core/modules/module-container-factory.d.ts +3 -3
  176. package/dist/types/core/modules/module-container.d.ts +44 -5
  177. package/dist/types/core/modules/module-token-factory.d.ts +2 -2
  178. package/dist/types/core/modules/modules-container.d.ts +23 -4
  179. package/dist/types/core/nexus-applications.browser.d.ts +30 -8
  180. package/dist/types/core/nexus-applications.d.ts +219 -55
  181. package/dist/types/core/nexus-applications.server.d.ts +30 -8
  182. package/dist/types/core/resolver/providers-container.d.ts +2 -2
  183. package/dist/types/core/resolver/resolution-context.d.ts +22 -0
  184. package/dist/types/core/resolver/resolver.d.ts +122 -4
  185. package/dist/types/decorators/inject.d.ts +9 -5
  186. package/dist/types/decorators/injectable.d.ts +0 -7
  187. package/dist/types/decorators/{nsModule.d.ts → module.d.ts} +6 -5
  188. package/dist/types/errors/bootstrap-error.d.ts +6 -0
  189. package/dist/types/errors/child-errors.d.ts +10 -0
  190. package/dist/types/errors/index.d.ts +5 -0
  191. package/dist/types/errors/injection-errors.d.ts +11 -0
  192. package/dist/types/errors/lazy-module-errors.d.ts +12 -0
  193. package/dist/types/errors/provider-errors.d.ts +47 -0
  194. package/dist/types/index.d.ts +13 -4
  195. package/dist/types/interfaces/abstract.interface.d.ts +1 -3
  196. package/dist/types/interfaces/dynamic-module.interface.d.ts +7 -5
  197. package/dist/types/interfaces/index.d.ts +1 -0
  198. package/dist/types/interfaces/injection-token.interface.d.ts +1 -3
  199. package/dist/types/interfaces/module-metadata.interface.d.ts +12 -4
  200. package/dist/types/interfaces/module-types.interface.d.ts +21 -24
  201. package/dist/types/interfaces/modules/container.interface.d.ts +10 -4
  202. package/dist/types/interfaces/modules/index.d.ts +1 -0
  203. package/dist/types/interfaces/modules/module-container-factory.interface.d.ts +2 -2
  204. package/dist/types/interfaces/modules/module-graph.interface.d.ts +85 -12
  205. package/dist/types/interfaces/modules/module-token-factory.interface.d.ts +2 -2
  206. package/dist/types/interfaces/modules/modules-container.interface.d.ts +5 -4
  207. package/dist/types/interfaces/modules/parent-link.interface.d.ts +12 -0
  208. package/dist/types/interfaces/nexus-application.interface.d.ts +49 -6
  209. package/dist/types/interfaces/on-module-destroy.interface.d.ts +3 -0
  210. package/dist/types/interfaces/plugins/scanner-plugin.interface.d.ts +1 -1
  211. package/dist/types/interfaces/scope.interface.d.ts +1 -54
  212. package/dist/types/interfaces/validate-module-keys.d.ts +1 -0
  213. package/dist/types/internal.d.ts +3 -0
  214. package/dist/types/server.d.ts +1 -1
  215. package/dist/types/utils/forward-ref.d.ts +5 -0
  216. package/dist/types/utils/helpers.d.ts +8 -8
  217. package/dist/types/utils/lazy-module.d.ts +20 -0
  218. package/package.json +23 -7
  219. package/dist/cjs/decorators/nsModule.js.map +0 -1
  220. package/dist/esm/decorators/nsModule.js.map +0 -1
  221. package/dist/tsconfig.cjs.tsbuildinfo +0 -1
  222. package/dist/tsconfig.esm.tsbuildinfo +0 -1
@@ -1,30 +1,56 @@
1
- import { type HashUtilInterface, type InjectionToken, type Module, type NexusApplicationInterface, type ScannerPluginInterface } from "../interfaces";
1
+ import { type BootstrapOptions, type CreateChildOptions, type DynamicModule, type GetOptions, type HashUtilInterface, type LazyModule, type NexusApplicationInterface, type ProviderToken, type ScannerPluginInterface, type Type, type UnloadResult } from "../interfaces";
2
+ import { ModuleRef } from "./module-ref";
2
3
  /**
3
- * NexusApplications is the main application class that provides a high-level
4
+ * NexusApplication is the main application class that provides a high-level
4
5
  * API for creating and managing IoC containers.
5
6
  *
6
7
  * This class wraps the Container and provides additional features:
7
8
  * - Automatic singleton initialization
8
9
  * - Scanner plugin support for custom metadata processing
9
- * - Parent-child container hierarchies
10
- * - Async/sync container modes
10
+ * - Child containers for modules declared in `@Module({ children })`
11
+ * - Lazy/eager container modes
11
12
  *
12
13
  * @example
13
14
  * ```typescript
14
- * const app = NexusApplications.create(AppModule);
15
+ * const app = NexusApplication.create(AppModule);
15
16
  * await app.bootstrap();
16
- * const service = await app.get(MyService);
17
+ * const service = app.get(MyService);
17
18
  * ```
18
19
  */
19
- export declare class NexusApplications implements NexusApplicationInterface {
20
+ export declare class NexusApplication implements NexusApplicationInterface {
20
21
  private readonly rootModule;
21
- private hashUtil;
22
+ private readonly options?;
23
+ private readonly hashUtil;
22
24
  private isAsyncContainer;
25
+ /** Built in the constructor, once `hashUtil` honours `options.hashFn`. */
23
26
  private readonly container;
24
27
  private readonly scannerPlugins;
25
- private _parentContainer;
28
+ private closePromise;
29
+ /** The parent chain; set only for children made by `createChild()`. */
30
+ private readonly link;
31
+ /** Removes this child from its parent's `liveChildren` once closed. */
32
+ private readonly onClosed;
26
33
  /**
27
- * Creates a new NexusApplications instance.
34
+ * Token, in the parent graph, of the module that declares this child in
35
+ * `@Module({ children })`; the parent closes the child when an unload
36
+ * destroys that module.
37
+ */
38
+ private readonly declaredIn;
39
+ /**
40
+ * Children created by `createChild()` and not closed yet, in creation
41
+ * order. The only reference the parent keeps to a child.
42
+ */
43
+ private readonly liveChildren;
44
+ /**
45
+ * Lazy child code, per lazy ref id, with the token of the declaring
46
+ * module; a failed load is not cached, and an unload that destroys the
47
+ * declaring module drops the entry.
48
+ */
49
+ private readonly loadedChildren;
50
+ private readonly pendingLoads;
51
+ private readonly lazyModuleLoader;
52
+ /**
53
+ * Creates a new NexusApplication instance.
28
54
  *
29
55
  * @param rootModule - The root module of the application
30
56
  * @param options - Optional configuration
@@ -32,24 +58,77 @@ export declare class NexusApplications implements NexusApplicationInterface {
32
58
  */
33
59
  private constructor();
34
60
  /**
35
- * Creates a new NexusApplications instance.
61
+ * Creates a new NexusApplication instance.
36
62
  *
37
63
  * This is the main entry point for creating an application.
38
64
  *
39
65
  * @param rootModule - The root module of the application
40
66
  * @param options - Optional configuration
41
67
  * @param options.hashFn - Custom hash function for module identification
42
- * @returns A new NexusApplications instance
68
+ * @returns A new NexusApplication instance
43
69
  *
44
70
  * @example
45
71
  * ```typescript
46
- * const app = NexusApplications.create(AppModule);
72
+ * const app = NexusApplication.create(AppModule);
47
73
  * await app.bootstrap();
48
74
  * ```
49
75
  */
50
- static create(rootModule: Module, options?: {
76
+ static create(rootModule: Type, options?: {
51
77
  hashFn: new () => HashUtilInterface;
52
- }): NexusApplications;
78
+ }): NexusApplication;
79
+ /**
80
+ * Creates a not-yet-bootstrapped child application. Private: the only
81
+ * public way to get a child is `createChild()`.
82
+ */
83
+ private static createAsChild;
84
+ /**
85
+ * Creates a child application for a module declared in
86
+ * `@Module({ children })` somewhere in this application's graph. The
87
+ * child is returned bootstrapped, with its singletons created.
88
+ *
89
+ * - `Type` matches a declared class; `DynamicModule` matches by its
90
+ * `.module`; a `LazyModule` matches a declared ref by identity, and its
91
+ * loader runs once per ref (a failed load is retried next time).
92
+ * - `options.providers` are appended to the child root module's providers.
93
+ * - The child's `get()`/`resolve()` look in the child first, then at what
94
+ * the declaring module sees in this application, then up this
95
+ * application's own parent chain.
96
+ *
97
+ * @throws {ContainerNotCompiledError} If this application is not bootstrapped
98
+ * @throws {ContainerClosedError} If this application is closed or closing
99
+ * @throws {ChildModuleNotDeclaredError} If no module declares `child`, or
100
+ * (`reason: "unloaded"`) the lazy module declaring it was unloaded while
101
+ * the child was being created; the child is closed then
102
+ * @throws {LazyModuleLoadError} If a lazy child's loader fails or returns a non-module
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * @Module({ children: [ProfileModule] })
107
+ * class AppModule {}
108
+ *
109
+ * const app = await NexusApplication.create(AppModule).bootstrap();
110
+ * const profile = await app.createChild(ProfileModule, {
111
+ * providers: [{ provide: PROFILE_ID, useValue: "p1" }],
112
+ * });
113
+ * ```
114
+ */
115
+ createChild(child: Type | DynamicModule | LazyModule, options?: CreateChildOptions): Promise<NexusApplication>;
116
+ /** Runs a lazy child's loader once per ref; a failure is not cached. */
117
+ private loadChildModule;
118
+ private runChildLoader;
119
+ /**
120
+ * The link a child declared in `declaredIn` uses: what that module sees
121
+ * in this application, then this application's own parent chain. It
122
+ * never caches instances, only which tokens the declaring module sees,
123
+ * so a `canProvide` followed by `get` walks the imports once per token
124
+ * (until a load or unload changes the graph) instead of twice per call.
125
+ * Once this application closes, `canProvide` still answers from the
126
+ * graph, so `get`/`resolve` of a token the child would have taken from
127
+ * here throw `ContainerClosedError` (even with `optional`) instead of
128
+ * quietly reporting it missing.
129
+ */
130
+ private linkFor;
131
+ private requireLink;
53
132
  /**
54
133
  * Bootstraps the application by initializing the container and all providers.
55
134
  *
@@ -63,12 +142,63 @@ export declare class NexusApplications implements NexusApplicationInterface {
63
142
  *
64
143
  * @example
65
144
  * ```typescript
66
- * const app = NexusApplications.create(AppModule);
145
+ * const app = NexusApplication.create(AppModule);
67
146
  * await app.bootstrap();
68
147
  * // Application is now ready to use
69
148
  * ```
70
149
  */
71
- bootstrap(): Promise<this>;
150
+ bootstrap(options?: BootstrapOptions): Promise<this>;
151
+ /**
152
+ * Pre-instantiates the singleton providers named by `tokens`, unless the
153
+ * application is running in lazy mode.
154
+ */
155
+ private warmUpSingletons;
156
+ /**
157
+ * Closes the application and cleans up resources.
158
+ *
159
+ * - The closed flag is set synchronously: from this call on, `get`,
160
+ * `resolve` and `load` throw `ContainerClosedError`.
161
+ * - Waits for in-flight lazy loads, then runs on the compile queue so it
162
+ * never interleaves with `load`/`unload`.
163
+ * - Calls every `onModuleDestroy` in reverse creation order, even if some
164
+ * throw; failures are collected into a single `AggregateError`.
165
+ * - Idempotent: later calls return the same promise.
166
+ * - A child application removes itself from its parent's live children
167
+ * once closed.
168
+ *
169
+ * @returns A promise that resolves when the application is closed
170
+ * @throws {AggregateError} If one or more `onModuleDestroy` hooks failed
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const app = await NexusApplication.create(AppModule).bootstrap();
175
+ * await app.close();
176
+ * ```
177
+ */
178
+ close(): Promise<void>;
179
+ /**
180
+ * Closes the live children (newest first, one at a time), then this
181
+ * application. Every failure, a child's or its own, ends up in one
182
+ * `AggregateError`, flattened so a child's `AggregateError` contributes
183
+ * its errors rather than nesting.
184
+ */
185
+ private closeChildrenThenSelf;
186
+ /**
187
+ * Waits for in-flight `load()` calls (including their singleton warm-up,
188
+ * which bypasses the closed guard) so nothing is instantiated after the
189
+ * destroy pass, then tears the container down.
190
+ */
191
+ private drainAndClose;
192
+ /**
193
+ * Unload hook (see `Container.onUnloading`): closes the live children
194
+ * declared by a module the unload destroys, newest first, and forgets
195
+ * the lazy child code those modules declared.
196
+ */
197
+ private closeChildrenDeclaredIn;
198
+ /** True once `close()` has been called (the app may still be closing). */
199
+ get isClosed(): boolean;
200
+ private assertOpen;
201
+ private assertUsable;
72
202
  /**
73
203
  * Adds one or more scanner plugins to the application.
74
204
  *
@@ -81,7 +211,7 @@ export declare class NexusApplications implements NexusApplicationInterface {
81
211
  *
82
212
  * @example
83
213
  * ```typescript
84
- * const app = NexusApplications.create(AppModule)
214
+ * const app = NexusApplication.create(AppModule)
85
215
  * .addScannerPlugin(new CustomScanner())
86
216
  * .addScannerPlugin([new Scanner1(), new Scanner2()]);
87
217
  * await app.bootstrap();
@@ -89,72 +219,106 @@ export declare class NexusApplications implements NexusApplicationInterface {
89
219
  */
90
220
  addScannerPlugin(scanner: ScannerPluginInterface | ScannerPluginInterface[]): this;
91
221
  /**
92
- * Resolves and returns an instance of a provider by its injection token.
222
+ * Synchronously returns an already-created singleton provider.
93
223
  *
94
- * If the provider is not found in this container, it will attempt to
95
- * resolve it from the parent container (if set).
224
+ * If the token is not a provider of this application and this is a child
225
+ * (see `createChild()`), the parent chain is asked. A token found locally
226
+ * is always answered locally, never by the parent.
96
227
  *
97
- * @template T - The type of the provider to resolve
98
- * @param token - The injection token (class, string, or symbol)
99
- * @returns A promise that resolves to the provider instance, or undefined if not found
228
+ * @template T - The type of the provider
229
+ * @param token - The provider token: class, InjectionToken, string or symbol
230
+ * @param options - `optional: true` returns undefined instead of throwing when no provider exists
231
+ * @throws {ContainerNotCompiledError} If called before bootstrap()
232
+ * @throws {ProviderNotFoundError} If no provider has this token (unless optional)
233
+ * @throws {ProviderScopeError} If the provider is Transient; use resolve()
234
+ * @throws {ProviderNotInstantiatedError} If the singleton is not created yet (lazy mode); use resolve()
100
235
  *
101
236
  * @example
102
237
  * ```typescript
103
- * const app = await NexusApplications.create(AppModule).bootstrap();
104
- * const userService = await app.get(UserService);
105
- * const config = await app.get('CONFIG');
238
+ * const app = await NexusApplication.create(AppModule).bootstrap();
239
+ * const userService = app.get(UserService);
240
+ * const config = app.get('CONFIG', { optional: true });
106
241
  * ```
107
242
  */
108
- get<T>(token: InjectionToken): Promise<T | undefined>;
243
+ get<T>(token: ProviderToken<T>): T;
244
+ get<T>(token: ProviderToken<T>, options: {
245
+ optional: true;
246
+ }): T | undefined;
247
+ get<T>(token: ProviderToken<T>, options: {
248
+ optional?: false;
249
+ }): T;
250
+ get<T>(token: ProviderToken<T>, options: GetOptions): T | undefined;
109
251
  /**
110
- * Gets all errors that occurred during graph compilation.
252
+ * Resolves a provider asynchronously, creating it according to its scope
253
+ * (Transient providers are created per call). A child application falls
254
+ * back to its parent chain when the token is not a provider of its own.
111
255
  *
112
- * @returns An array of graph errors
256
+ * @param token - The provider token: class, InjectionToken, string or symbol
257
+ * @param options - `optional: true` returns undefined instead of rejecting when no provider exists
258
+ * @throws {ContainerNotCompiledError} If called before bootstrap()
259
+ * @throws {ProviderNotFoundError} If no provider has this token (unless optional)
113
260
  *
114
261
  * @example
115
262
  * ```typescript
116
- * const app = await NexusApplications.create(AppModule).bootstrap();
117
- * if (app.errors.length > 0) {
118
- * console.error('Application errors:', app.errors);
119
- * }
263
+ * const handler = await app.resolve(RequestHandler);
120
264
  * ```
121
265
  */
122
- get errors(): import("@nexus-ioc/shared").GraphError[];
266
+ resolve<T>(token: ProviderToken<T>): Promise<T>;
267
+ resolve<T>(token: ProviderToken<T>, options: {
268
+ optional: true;
269
+ }): Promise<T | undefined>;
270
+ resolve<T>(token: ProviderToken<T>, options: {
271
+ optional?: false;
272
+ }): Promise<T>;
273
+ resolve<T>(token: ProviderToken<T>, options: GetOptions): Promise<T | undefined>;
123
274
  /**
124
- * Enables async mode for the container.
275
+ * Loads a lazy module declared with `lazy()` into this application's
276
+ * container and returns a handle to it. Repeated calls for the same ref
277
+ * return the same providers; the loader runs once.
125
278
  *
126
- * In async mode, singleton providers are NOT pre-instantiated during
127
- * bootstrap. They will be created lazily on first access via get().
128
- * This can improve startup time for large applications.
279
+ * @throws {LazyModuleLoadError} if the loader fails or returns a non-module
280
+ * @throws {LazyModuleGraphError} if the module's dependency graph is invalid
281
+ */
282
+ load(lazyModule: LazyModule): Promise<ModuleRef>;
283
+ private loadAndWarmUp;
284
+ /**
285
+ * Unloads a lazy module previously returned by `load()` (directly or via
286
+ * `LazyModuleLoader`): destroys every singleton and module nothing else
287
+ * still needs. A no-op if `ref` is already unloaded.
288
+ */
289
+ unload(ref: ModuleRef): Promise<UnloadResult>;
290
+ /**
291
+ * Gets all errors that occurred during graph compilation.
129
292
  *
130
- * @returns This instance for method chaining
293
+ * @returns An array of graph errors
131
294
  *
132
295
  * @example
133
296
  * ```typescript
134
- * const app = NexusApplications.create(AppModule)
135
- * .async();
136
- * await app.bootstrap(); // Singletons are NOT created yet
137
- * const service = await app.get(MyService); // Created on first access
297
+ * const app = await NexusApplication.create(AppModule).bootstrap();
298
+ * if (app.errors.length > 0) {
299
+ * console.error('Application errors:', app.errors);
300
+ * }
138
301
  * ```
139
302
  */
140
- async(): this;
303
+ get errors(): import("@nexus-ioc/shared").GraphError[];
141
304
  /**
142
- * Sets a parent container for this application.
305
+ * Enables lazy mode for the container.
306
+ *
307
+ * In lazy mode, singleton providers are NOT pre-instantiated during
308
+ * bootstrap. They will be created lazily on first access via resolve();
309
+ * get() throws ProviderNotInstantiatedError until then.
143
310
  *
144
- * When a provider is not found in this container, it will be looked up
145
- * in the parent container. This enables hierarchical container structures.
311
+ * @deprecated Use lazy modules (lazy()/load()) instead; in this mode get() throws ProviderNotInstantiatedError until resolve() is called.
146
312
  *
147
- * @param parentContainer - The parent container
148
313
  * @returns This instance for method chaining
149
314
  *
150
315
  * @example
151
316
  * ```typescript
152
- * const parentApp = await NexusApplications.create(ParentModule).bootstrap();
153
- * const childApp = await NexusApplications.create(ChildModule)
154
- * .setParent(parentApp)
155
- * .bootstrap();
156
- * // childApp can access providers from parentApp
317
+ * const app = NexusApplication.create(AppModule)
318
+ * .lazy();
319
+ * await app.bootstrap(); // Singletons are NOT created yet
320
+ * const service = await app.resolve(MyService); // Created on first access
157
321
  * ```
158
322
  */
159
- setParent(parentContainer: NexusApplicationInterface): this;
323
+ lazy(): this;
160
324
  }
@@ -1,21 +1,43 @@
1
- import type { InjectionToken, Module, NexusApplicationInterface, ScannerPluginInterface } from "../interfaces";
1
+ import type { CreateChildOptions, DynamicModule, GetOptions, LazyModule, NexusApplicationInterface, ProviderToken, ScannerPluginInterface, Type, UnloadResult } from "../interfaces";
2
+ import { ModuleRef } from "./module-ref";
2
3
  /**
3
4
  * @deprecated
4
5
  * It will be removed in version 1.0.0.
5
- * these classes work the same way. For the new behavior, use @NexusApplications
6
+ * these classes work the same way. For the new behavior, use @NexusApplication
6
7
  */
7
- export declare class NexusApplicationsServer implements NexusApplicationInterface {
8
+ export declare class NexusApplicationServer implements NexusApplicationInterface {
8
9
  private readonly rootModule;
9
10
  private readonly hashUtil;
10
11
  private readonly container;
11
12
  private readonly scannerPlugins;
12
- private _parentContainer;
13
+ private closePromise;
13
14
  private constructor();
14
- static create(rootModule: Module): NexusApplicationsServer;
15
+ static create(rootModule: Type): NexusApplicationServer;
15
16
  bootstrap(): Promise<this>;
16
17
  addScannerPlugin(scanner: ScannerPluginInterface | ScannerPluginInterface[]): this;
17
- get<T>(token: InjectionToken): Promise<T | undefined>;
18
+ get<T>(token: ProviderToken<T>): T;
19
+ get<T>(token: ProviderToken<T>, options: {
20
+ optional: true;
21
+ }): T | undefined;
22
+ get<T>(token: ProviderToken<T>, options: {
23
+ optional?: false;
24
+ }): T;
25
+ get<T>(token: ProviderToken<T>, options: GetOptions): T | undefined;
26
+ resolve<T>(token: ProviderToken<T>): Promise<T>;
27
+ resolve<T>(token: ProviderToken<T>, options: {
28
+ optional: true;
29
+ }): Promise<T | undefined>;
30
+ resolve<T>(token: ProviderToken<T>, options: {
31
+ optional?: false;
32
+ }): Promise<T>;
33
+ resolve<T>(token: ProviderToken<T>, options: GetOptions): Promise<T | undefined>;
18
34
  get errors(): import("@nexus-ioc/shared").GraphError[];
19
- async(): this;
20
- setParent(parentContainer: NexusApplicationInterface): this;
35
+ load(lazyModule: LazyModule): Promise<ModuleRef>;
36
+ unload(ref: ModuleRef): Promise<UnloadResult>;
37
+ lazy(): this;
38
+ close(): Promise<void>;
39
+ get isClosed(): boolean;
40
+ private assertOpen;
41
+ private assertUsable;
42
+ createChild(_child: Type | DynamicModule | LazyModule, _options?: CreateChildOptions): Promise<NexusApplicationInterface>;
21
43
  }
@@ -1,3 +1,3 @@
1
- import type { InjectionToken } from "../../interfaces";
2
- export declare class ProvidersContainer extends Map<InjectionToken, any> {
1
+ import type { ProviderToken } from "../../interfaces";
2
+ export declare class ProvidersContainer extends Map<ProviderToken, any> {
3
3
  }
@@ -0,0 +1,22 @@
1
+ import type { ProviderToken } from "../../interfaces";
2
+ export declare class ResolutionContext {
3
+ /** Tokens currently being constructed in this tree, outermost first. */
4
+ readonly path: ProviderToken[];
5
+ /** onModuleInit promises started during synchronous creation. */
6
+ readonly pendingInits: Promise<unknown>[];
7
+ enter(token: ProviderToken): void;
8
+ leave(token: ProviderToken): void;
9
+ isConstructing(token: ProviderToken): boolean;
10
+ /**
11
+ * Queues an init promise. A no-op rejection handler is attached right
12
+ * away so a failure is never reported as an unhandled rejection before
13
+ * drainPendingInits() collects it; the original promise still rejects.
14
+ */
15
+ addPendingInit(promise: Promise<unknown>): void;
16
+ /**
17
+ * Waits for every pending init (allSettled semantics), including ones
18
+ * added while draining, clears the list, then rethrows the first failure
19
+ * in queue order.
20
+ */
21
+ drainPendingInits(): Promise<void>;
22
+ }
@@ -1,10 +1,128 @@
1
- import { type InjectionToken, type ModuleGraphInterface } from "../../interfaces";
2
- import { ProvidersContainer } from "./providers-container";
1
+ import { type ModuleGraphInterface, type ParentLink, type ProviderToken } from "../../interfaces";
2
+ import type { AnalyzeProvider } from "../graph/analyze-provider";
3
+ import { type InjectOptions } from "../injection/injection-context";
4
+ import { ResolutionContext } from "./resolution-context";
3
5
  export declare class Resolver {
4
6
  private readonly graph;
7
+ private readonly link;
5
8
  private readonly providersContainer;
6
- constructor(graph: ModuleGraphInterface);
7
- resolveProvider<T>(token: InjectionToken, resolveCache?: ProvidersContainer, isCircularDependency?: boolean): Promise<T | undefined>;
9
+ private readonly initializationOrder;
10
+ /** `lateBoundVisible` results, valid while the graph version matches. */
11
+ private readonly lateBoundMemo;
12
+ /**
13
+ * Singletons created by inject() whose onModuleInit (or the wait on
14
+ * inits queued before them) has not settled yet. Other resolution trees
15
+ * that hit such a cached singleton wait on this promise, so they never
16
+ * see it half-initialised or keep it after a failed init evicted it.
17
+ */
18
+ private readonly inFlightInits;
19
+ /**
20
+ * Singletons that resolveProvider is creating (construction through
21
+ * onModuleInit), not yet in the cache. Concurrent callers await the same
22
+ * promise, so each singleton is created once. An entry is removed when
23
+ * its creation settles: after the commit on success, so a token is always
24
+ * in the cache or here; on failure, so the next resolve retries.
25
+ */
26
+ private readonly inFlightCreations;
27
+ /**
28
+ * Set once close() starts. From then on nothing new is created or
29
+ * cached: creations still in flight are destroyed when they finish
30
+ * (close() does not wait for them, see commitCreation), and inject()
31
+ * in a resolution tree that outlived close() throws instead of creating.
32
+ */
33
+ private closed;
34
+ /**
35
+ * @param link - The parent chain of a child container. Edges marked
36
+ * `external` resolve through it; their results are never cached here.
37
+ */
38
+ constructor(graph: ModuleGraphInterface, link?: ParentLink | null);
39
+ /**
40
+ * The link that satisfies an external edge. The graph marks an edge
41
+ * external only when a link can provide its target, so a missing link
42
+ * is an internal error, reported as not found rather than `undefined`.
43
+ */
44
+ private linkFor;
45
+ /** Cached singleton lookup; never creates. Uses has() so falsy values count. */
46
+ getInstantiated(token: ProviderToken): {
47
+ found: true;
48
+ instance: unknown;
49
+ } | {
50
+ found: false;
51
+ };
52
+ /**
53
+ * Marks the resolver closed without destroying anything; used when the
54
+ * container was closed before this resolver existed.
55
+ */
56
+ markClosed(): void;
57
+ close(): Promise<void>;
58
+ /**
59
+ * Destroys exactly the given singletons: `onModuleDestroy` in reverse
60
+ * initialization order, then removed from the cache and from
61
+ * `initializationOrder`. A token that was never instantiated (never
62
+ * resolved, or `Transient`/non-singleton scope) is silently skipped.
63
+ * Like `close()`, every hook runs even if some throw, the cleanup always
64
+ * completes, and the failures are thrown afterwards as one
65
+ * `AggregateError`.
66
+ */
67
+ destroy(tokens: ProviderToken[]): Promise<void>;
68
+ resolveProvider<T>(token: ProviderToken, ctx?: ResolutionContext, isCircularDependency?: boolean): Promise<T | undefined>;
69
+ /**
70
+ * Caches what `creation` produced, unless the creation went stale while
71
+ * it ran: close() or destroy() (an unload) dropped its in-flight entry.
72
+ * A stale instance is never cached. Its onModuleDestroy is called (best
73
+ * effort: a failure there is ignored, since the caller already gets the
74
+ * rejection below and nothing else holds the instance), and the caller
75
+ * gets ContainerClosedError after a close, ProviderUnloadedError after
76
+ * an unload.
77
+ */
78
+ private commitCreation;
79
+ /**
80
+ * Caching rules shared by the async and sync paths: Singletons go into the
81
+ * global cache and the destroy order. Nothing else is cached.
82
+ */
83
+ private commitInstance;
84
+ /** Undoes commitInstance for `instance`, if it is still the cached one. */
85
+ private evictInstance;
8
86
  private createInstance;
87
+ private createInstanceInContext;
88
+ /**
89
+ * inject() entry point: resolves `token` synchronously for `requester`.
90
+ * The token must be visible from the requester's module, the same rule
91
+ * as `@Inject`.
92
+ */
93
+ resolveSync(token: ProviderToken, ctx: ResolutionContext, requester: AnalyzeProvider, options: InjectOptions): unknown;
94
+ /**
95
+ * Synchronous counterpart of resolveProvider for a provider node whose
96
+ * reachability was already established (visibility check or graph edge).
97
+ */
98
+ private resolveProviderSync;
99
+ /** Resolves a static @Inject edge of `requester` on the synchronous path. */
100
+ private resolveEdgeSync;
101
+ /**
102
+ * Synchronous mirror of createInstance + resolveProvider caching, used
103
+ * when inject() reaches a provider that does not exist yet.
104
+ */
105
+ private createInstanceSync;
106
+ /** Runs a factory; factories must be synchronous. */
107
+ private callFactory;
108
+ /** Registers `init` as the in-flight init of a just-committed singleton. */
109
+ private trackInFlightInit;
110
+ /**
111
+ * Calls onModuleInit synchronously. A synchronous throw is wrapped and
112
+ * rethrown; an async result is returned with its rejection wrapped.
113
+ */
114
+ private callInitSync;
115
+ private wrapInitError;
116
+ private contextFor;
117
+ /**
118
+ * Whether a late-bound edge's target may be injected into `requester`:
119
+ * it exists now and is visible from the requester's module. The graph
120
+ * records the referrer (keeping the target's module alive) under the
121
+ * same rule, so injection and unload bookkeeping agree.
122
+ */
123
+ private lateBoundVisible;
124
+ private constructorEdges;
125
+ private propertyEdges;
126
+ private injectPropertyDependenciesSync;
9
127
  private injectPropertyDependencies;
10
128
  }
@@ -1,24 +1,28 @@
1
1
  import "reflect-metadata";
2
- import { type Type } from "../interfaces";
2
+ import { type ProviderToken } from "../interfaces";
3
+ import type { ForwardRef } from "../utils/forward-ref";
3
4
  /**
4
5
  * Explicitly specifies the injection token for a constructor parameter or property.
5
6
  *
6
7
  * This decorator is used when:
7
- * - You need to inject a provider by a string or symbol token
8
+ * - You need to inject a provider by an InjectionToken, string or symbol token
8
9
  * - TypeScript's reflection cannot determine the type (e.g., interfaces, circular dependencies)
9
10
  * - You want to inject a different implementation than the declared type
10
11
  *
11
- * @param token - The injection token (class, string, or symbol)
12
+ * @param token - The provider token: class, InjectionToken, string or symbol, or a `forwardRef()`
12
13
  * @returns A decorator that can be applied to constructor parameters or properties
13
14
  * @throws {Error} If the token is undefined (often due to circular dependencies)
14
15
  *
15
16
  * @example
16
17
  * ```typescript
18
+ * // InjectionToken: a typed token for a value that has no class
19
+ * const DATABASE_CONFIG = new InjectionToken<DatabaseConfig>('DATABASE_CONFIG');
20
+ *
17
21
  * // Constructor parameter injection
18
22
  * @Injectable()
19
23
  * class UserService {
20
24
  * constructor(
21
- * @Inject('DATABASE_CONFIG') private config: DatabaseConfig,
25
+ * @Inject(DATABASE_CONFIG) private config: DatabaseConfig,
22
26
  * @Inject(Logger) private logger: Logger
23
27
  * ) {}
24
28
  * }
@@ -39,4 +43,4 @@ import { type Type } from "../interfaces";
39
43
  * }
40
44
  * ```
41
45
  */
42
- export declare function Inject(token: Type | symbol | string): PropertyDecorator & ParameterDecorator;
46
+ export declare function Inject(token: ProviderToken | ForwardRef): PropertyDecorator & ParameterDecorator;
@@ -9,7 +9,6 @@ import type { InjectableOptions } from "../interfaces";
9
9
  * @param options - Configuration options for the injectable
10
10
  * @param options.scope - The lifecycle scope of the provider:
11
11
  * - `Scope.Singleton` (default): One instance shared across the entire application
12
- * - `Scope.Request`: New instance for each container.get() call
13
12
  * - `Scope.Transient`: New instance every time, even within the same dependency tree
14
13
  * @returns A class decorator
15
14
  *
@@ -21,12 +20,6 @@ import type { InjectableOptions } from "../interfaces";
21
20
  * constructor(private db: Database) {}
22
21
  * }
23
22
  *
24
- * // Request scope
25
- * @Injectable({ scope: Scope.Request })
26
- * class RequestContext {
27
- * requestId = Math.random();
28
- * }
29
- *
30
23
  * // Transient scope
31
24
  * @Injectable({ scope: Scope.Transient })
32
25
  * class Logger {