@velajs/vela 1.10.0 → 1.13.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 (85) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/dist/application.d.ts +25 -0
  3. package/dist/application.js +103 -2
  4. package/dist/container/container.d.ts +46 -1
  5. package/dist/container/container.js +156 -13
  6. package/dist/container/disposable.js +1 -1
  7. package/dist/container/types.d.ts +27 -0
  8. package/dist/cors/cors.module.d.ts +5 -5
  9. package/dist/cors/cors.module.js +26 -25
  10. package/dist/discovery/discoverable.decorator.d.ts +38 -0
  11. package/dist/discovery/discoverable.decorator.js +42 -0
  12. package/dist/discovery/discovery.service.d.ts +102 -0
  13. package/dist/discovery/discovery.service.js +177 -0
  14. package/dist/discovery/index.d.ts +2 -0
  15. package/dist/discovery/index.js +2 -0
  16. package/dist/entrypoint/entrypoint.registry.d.ts +42 -0
  17. package/dist/entrypoint/entrypoint.registry.js +112 -0
  18. package/dist/entrypoint/entrypoint.types.d.ts +41 -0
  19. package/dist/entrypoint/entrypoint.types.js +3 -0
  20. package/dist/entrypoint/execution-context.d.ts +15 -0
  21. package/dist/entrypoint/execution-context.js +21 -0
  22. package/dist/entrypoint/execution-scope.d.ts +21 -0
  23. package/dist/entrypoint/execution-scope.js +28 -0
  24. package/dist/entrypoint/index.d.ts +4 -0
  25. package/dist/entrypoint/index.js +4 -0
  26. package/dist/event-emitter/event-emitter.module.js +1 -0
  27. package/dist/event-emitter/event-emitter.subscriber.d.ts +3 -3
  28. package/dist/event-emitter/event-emitter.subscriber.js +12 -29
  29. package/dist/factory/adapter.d.ts +36 -0
  30. package/dist/factory/adapter.js +18 -0
  31. package/dist/factory/bootstrap.js +14 -2
  32. package/dist/factory.d.ts +11 -1
  33. package/dist/factory.js +23 -2
  34. package/dist/http/handler-executor.js +22 -19
  35. package/dist/http/route-contributor.d.ts +68 -0
  36. package/dist/http/route-contributor.js +22 -0
  37. package/dist/http/route.manager.js +33 -19
  38. package/dist/i18n/i18n.module.js +9 -1
  39. package/dist/index.d.ts +12 -3
  40. package/dist/index.js +9 -2
  41. package/dist/internal.d.ts +0 -2
  42. package/dist/internal.js +0 -7
  43. package/dist/module/configurable-module.builder.d.ts +12 -0
  44. package/dist/module/configurable-module.builder.js +21 -114
  45. package/dist/module/decorators.js +4 -2
  46. package/dist/module/define-module.d.ts +112 -0
  47. package/dist/module/define-module.js +232 -0
  48. package/dist/module/index.d.ts +3 -1
  49. package/dist/module/index.js +3 -1
  50. package/dist/module/lazy-modules.d.ts +82 -0
  51. package/dist/module/lazy-modules.js +231 -0
  52. package/dist/module/lazy-provider.d.ts +65 -0
  53. package/dist/module/lazy-provider.js +111 -0
  54. package/dist/module/module-loader.d.ts +21 -0
  55. package/dist/module/module-loader.js +99 -24
  56. package/dist/openapi/document.js +16 -15
  57. package/dist/pipeline/component.manager.d.ts +15 -9
  58. package/dist/pipeline/component.manager.js +32 -46
  59. package/dist/pipeline/index.d.ts +2 -0
  60. package/dist/pipeline/index.js +1 -0
  61. package/dist/pipeline/pipeline-runner.d.ts +31 -0
  62. package/dist/pipeline/pipeline-runner.js +40 -0
  63. package/dist/registry/metadata.registry.d.ts +9 -3
  64. package/dist/registry/metadata.registry.js +55 -25
  65. package/dist/registry/types.d.ts +10 -0
  66. package/dist/schedule/schedule.module.d.ts +5 -0
  67. package/dist/schedule/schedule.module.js +21 -8
  68. package/dist/schedule/schedule.registry.d.ts +3 -3
  69. package/dist/schedule/schedule.registry.js +23 -44
  70. package/dist/schedule-node/schedule-node.module.d.ts +5 -0
  71. package/dist/schedule-node/schedule-node.module.js +20 -10
  72. package/dist/seeder/seeder.module.d.ts +8 -10
  73. package/dist/seeder/seeder.module.js +19 -15
  74. package/dist/websocket/index.d.ts +1 -1
  75. package/dist/websocket/index.js +1 -1
  76. package/dist/websocket/websocket.module.d.ts +20 -3
  77. package/dist/websocket/websocket.module.js +50 -39
  78. package/dist/websocket/websocket.tokens.d.ts +2 -1
  79. package/dist/websocket/websocket.tokens.js +3 -2
  80. package/dist/websocket/ws-dispatcher.d.ts +21 -9
  81. package/dist/websocket/ws-dispatcher.js +44 -38
  82. package/dist/websocket-node/register-gateways.js +3 -3
  83. package/package.json +1 -1
  84. package/dist/http/crud-bridge.d.ts +0 -90
  85. package/dist/http/crud-bridge.js +0 -25
@@ -16,7 +16,8 @@ export function Module(options = {}) {
16
16
  providers: options.providers,
17
17
  controllers: options.controllers,
18
18
  exports: options.exports,
19
- isGlobal: options.isGlobal
19
+ isGlobal: options.isGlobal,
20
+ lazy: options.lazy
20
21
  });
21
22
  };
22
23
  }
@@ -40,6 +41,7 @@ export function getModuleMetadata(target) {
40
41
  controllers: options.controllers ?? [],
41
42
  imports: options.imports ?? [],
42
43
  exports: options.exports ?? [],
43
- isGlobal: options.isGlobal === true
44
+ isGlobal: options.isGlobal === true,
45
+ lazy: options.lazy === true
44
46
  };
45
47
  }
@@ -0,0 +1,112 @@
1
+ import { InjectionToken, type ProviderOptions, type Token, type Type } from '../container/types';
2
+ import type { ComponentInstance, ModuleImport } from '../registry/types';
3
+ import type { ConfigurableModuleAsyncOptions, ConfigurableModuleExtras, ConfigurableModuleExtrasTransform, ConfigurableModuleHost } from './configurable-module.types';
4
+ /** The `global:` slot's component groups, lowered to `APP_*` registrations. */
5
+ export interface GlobalComponentSlot {
6
+ guards?: Array<Type | ComponentInstance>;
7
+ pipes?: Array<Type | ComponentInstance>;
8
+ interceptors?: Array<Type | ComponentInstance>;
9
+ filters?: Array<Type | ComponentInstance>;
10
+ middleware?: Array<Type | ComponentInstance>;
11
+ }
12
+ /** What a module instance contributes, computed from its call-time options. */
13
+ export interface ModuleContributions {
14
+ providers?: Array<Type | ProviderOptions>;
15
+ controllers?: Type[];
16
+ imports?: ModuleImport[];
17
+ exports?: Array<Type | InjectionToken>;
18
+ /**
19
+ * Standardized global-component registration — the one idiom replacing both
20
+ * the `@Module({ providers: [{ provide: APP_GUARD, useExisting: X }] })`
21
+ * pattern and the conditional-push-into-forRoot pattern. Class entries are
22
+ * registered as providers and wired via `useExisting`; instances via `useValue`.
23
+ */
24
+ global?: GlobalComponentSlot;
25
+ }
26
+ export interface ModuleSetupContext<Opts> {
27
+ /** The options token — derived providers do `inject: [OPTIONS]`. */
28
+ readonly OPTIONS: InjectionToken<Opts>;
29
+ /**
30
+ * Structural options known at call time. For `forRoot` this is the full
31
+ * bag; for `forRootAsync` it is only the structural fields passed alongside
32
+ * the factory (the DI-resolved options exist only at resolution time —
33
+ * read them through `OPTIONS`, never here).
34
+ */
35
+ readonly options: Partial<Opts>;
36
+ /** The instance key in effect (for deriving per-instance token names). */
37
+ readonly key: string;
38
+ }
39
+ export interface DefineModuleSpec<Opts, Extras extends ConfigurableModuleExtras = {
40
+ isGlobal?: boolean;
41
+ }, MethodKey extends string = 'forRoot', FactoryMethodKey extends string = 'create'> {
42
+ /** Names the generated base class, the minted options token, and diagnostics. */
43
+ name: string;
44
+ /**
45
+ * Reuse an existing options token instead of minting one — critical for
46
+ * migrations so the module's public token keeps its identity.
47
+ */
48
+ optionsToken?: InjectionToken<Opts>;
49
+ /**
50
+ * Structural contributions as a function of the call-time options. Runs at
51
+ * `forRoot`/`forRootAsync` call time, once per module instance.
52
+ */
53
+ setup?: (ctx: ModuleSetupContext<Opts>) => ModuleContributions;
54
+ /**
55
+ * Dedup key from the structural options. Defaults to `stableHash(options)`.
56
+ * Modules whose options carry stateful instances (drivers, registries)
57
+ * should derive from the stable identifying subset — or document that
58
+ * callers pass an explicit `key` for multi-instance setups.
59
+ */
60
+ key?: (options: Partial<Opts>) => string;
61
+ /** Call-site extras defaults (default `{ isGlobal: false }`). */
62
+ extras?: Extras;
63
+ /** Reshape the definition from resolved extras (default: `isGlobal` → `global: true`). */
64
+ transform?: ConfigurableModuleExtrasTransform<Extras>;
65
+ /** Rename the sync static (default `forRoot`); the async static becomes `<name>Async`. */
66
+ methodName?: MethodKey;
67
+ /** Method a `useClass`/`useExisting` options factory must implement (default `create`). */
68
+ factoryMethodName?: FactoryMethodKey;
69
+ /**
70
+ * Default every generated module instance to deferred (first-use)
71
+ * materialization. Call sites can also opt in per instance by passing
72
+ * `lazy: true` alongside the options (recognized like `isGlobal`).
73
+ * See MODULE_AUTHORING.md "Lazy modules".
74
+ */
75
+ lazy?: boolean;
76
+ }
77
+ /**
78
+ * The one blessed module-authoring engine. Generates `forRoot` AND
79
+ * `forRootAsync` statics with: `stableHash` key derivation (multi-instance
80
+ * dedup that survives HMR), typed `inject` tuple inference on the async
81
+ * factory, an `isGlobal` extra, and — the piece `ConfigurableModuleBuilder`
82
+ * could not express — providers/controllers/imports/exports/global components
83
+ * computed **as functions of the options**.
84
+ *
85
+ * ```ts
86
+ * const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = defineModule<CorsOptions>({
87
+ * name: 'Cors',
88
+ * setup: ({ OPTIONS }) => ({
89
+ * providers: [{
90
+ * provide: APP_MIDDLEWARE,
91
+ * useFactory: (o: CorsOptions) => buildCorsMiddleware(o),
92
+ * inject: [OPTIONS],
93
+ * }],
94
+ * exports: [OPTIONS],
95
+ * }),
96
+ * });
97
+ * export class CorsModule extends ConfigurableModuleClass {}
98
+ * ```
99
+ *
100
+ * `ConfigurableModuleBuilder` remains supported (NestJS parity) and is a thin
101
+ * adapter over this engine.
102
+ */
103
+ export declare function defineModule<Opts, Extras extends ConfigurableModuleExtras = {
104
+ isGlobal?: boolean;
105
+ }, MethodKey extends string = 'forRoot', FactoryMethodKey extends string = 'create'>(spec: DefineModuleSpec<Opts, Extras, MethodKey, FactoryMethodKey>): ConfigurableModuleHost<Opts, MethodKey, FactoryMethodKey, Extras>;
106
+ /**
107
+ * Lower `useFactory`/`useClass`/`useExisting` async options into provider
108
+ * registrations. Structural fields from the call site merge UNDER the resolved
109
+ * options (`{ ...structural, ...resolved }`) so sync-declared fields act as
110
+ * defaults and the factory stays authoritative.
111
+ */
112
+ export declare function buildAsyncOptionsProviders<Opts>(optionsToken: Token, factoryMethodName: string, async: Pick<ConfigurableModuleAsyncOptions<Opts>, 'inject' | 'useFactory' | 'useClass' | 'useExisting'>, structural?: Record<string, unknown>): Array<ProviderOptions>;
@@ -0,0 +1,232 @@
1
+ import { InjectionToken } from "../container/types.js";
2
+ import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_MIDDLEWARE, APP_PIPE } from "../pipeline/tokens.js";
3
+ import { stableHash } from "./stable-hash.js";
4
+ const DEFAULT_EXTRAS = {
5
+ isGlobal: false
6
+ };
7
+ const DEFAULT_TRANSFORM = (def, extras)=>extras.isGlobal ? {
8
+ ...def,
9
+ global: true
10
+ } : def;
11
+ const GLOBAL_SLOT_TOKENS = {
12
+ guards: APP_GUARD,
13
+ pipes: APP_PIPE,
14
+ interceptors: APP_INTERCEPTOR,
15
+ filters: APP_FILTER,
16
+ middleware: APP_MIDDLEWARE
17
+ };
18
+ /** Lower a `global:` slot to `APP_*` provider registrations. */ function lowerGlobalSlot(slot) {
19
+ const out = [];
20
+ for (const kind of Object.keys(GLOBAL_SLOT_TOKENS)){
21
+ for (const component of slot[kind] ?? []){
22
+ const token = GLOBAL_SLOT_TOKENS[kind];
23
+ if (typeof component === 'function') {
24
+ out.push(component, {
25
+ provide: token,
26
+ useExisting: component
27
+ });
28
+ } else {
29
+ out.push({
30
+ provide: token,
31
+ useValue: component
32
+ });
33
+ }
34
+ }
35
+ }
36
+ return out;
37
+ }
38
+ const ASYNC_OPTION_KEYS = new Set([
39
+ 'key',
40
+ 'imports',
41
+ 'inject',
42
+ 'useFactory',
43
+ 'useClass',
44
+ 'useExisting'
45
+ ]);
46
+ /**
47
+ * The one blessed module-authoring engine. Generates `forRoot` AND
48
+ * `forRootAsync` statics with: `stableHash` key derivation (multi-instance
49
+ * dedup that survives HMR), typed `inject` tuple inference on the async
50
+ * factory, an `isGlobal` extra, and — the piece `ConfigurableModuleBuilder`
51
+ * could not express — providers/controllers/imports/exports/global components
52
+ * computed **as functions of the options**.
53
+ *
54
+ * ```ts
55
+ * const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = defineModule<CorsOptions>({
56
+ * name: 'Cors',
57
+ * setup: ({ OPTIONS }) => ({
58
+ * providers: [{
59
+ * provide: APP_MIDDLEWARE,
60
+ * useFactory: (o: CorsOptions) => buildCorsMiddleware(o),
61
+ * inject: [OPTIONS],
62
+ * }],
63
+ * exports: [OPTIONS],
64
+ * }),
65
+ * });
66
+ * export class CorsModule extends ConfigurableModuleClass {}
67
+ * ```
68
+ *
69
+ * `ConfigurableModuleBuilder` remains supported (NestJS parity) and is a thin
70
+ * adapter over this engine.
71
+ */ export function defineModule(spec) {
72
+ const optionsToken = spec.optionsToken ?? new InjectionToken(`${spec.name}_MODULE_OPTIONS`);
73
+ const syncName = spec.methodName ?? 'forRoot';
74
+ const asyncName = `${syncName}Async`;
75
+ const factoryMethodName = spec.factoryMethodName ?? 'create';
76
+ const extrasDefaults = spec.extras ?? DEFAULT_EXTRAS;
77
+ const transform = spec.transform ?? DEFAULT_TRANSFORM;
78
+ const deriveKey = (explicit, structural)=>explicit ?? spec.key?.(structural) ?? stableHash(structural);
79
+ // Laziness is OR-composed: the spec defaults it, a call site can add it.
80
+ const applyLazy = (definition, callSiteLazy)=>spec.lazy === true || callSiteLazy === true ? {
81
+ ...definition,
82
+ lazy: true
83
+ } : definition;
84
+ const applyContributions = (definition, structural, key)=>{
85
+ if (!spec.setup) return definition;
86
+ const contributions = spec.setup({
87
+ OPTIONS: optionsToken,
88
+ options: structural,
89
+ key
90
+ });
91
+ const providers = [
92
+ ...definition.providers ?? [],
93
+ ...contributions.providers ?? [],
94
+ ...contributions.global ? lowerGlobalSlot(contributions.global) : []
95
+ ];
96
+ return {
97
+ ...definition,
98
+ providers,
99
+ controllers: [
100
+ ...definition.controllers ?? [],
101
+ ...contributions.controllers ?? []
102
+ ],
103
+ imports: [
104
+ ...definition.imports ?? [],
105
+ ...contributions.imports ?? []
106
+ ],
107
+ exports: [
108
+ ...definition.exports ?? [],
109
+ ...contributions.exports ?? []
110
+ ]
111
+ };
112
+ };
113
+ let GeneratedModuleClass = class GeneratedModuleClass {
114
+ };
115
+ Object.defineProperty(GeneratedModuleClass, 'name', {
116
+ value: `${spec.name}ModuleHost`
117
+ });
118
+ Object.defineProperty(GeneratedModuleClass, syncName, {
119
+ configurable: true,
120
+ writable: true,
121
+ enumerable: false,
122
+ value (options = {}) {
123
+ const { key: explicitKey, ...rest } = options;
124
+ const key = deriveKey(explicitKey, rest);
125
+ const definition = {
126
+ module: this,
127
+ key,
128
+ providers: [
129
+ {
130
+ provide: optionsToken,
131
+ useValue: rest
132
+ }
133
+ ]
134
+ };
135
+ return applyLazy(transform(applyContributions(definition, rest, key), {
136
+ ...extrasDefaults,
137
+ ...rest
138
+ }), rest.lazy);
139
+ }
140
+ });
141
+ Object.defineProperty(GeneratedModuleClass, asyncName, {
142
+ configurable: true,
143
+ writable: true,
144
+ enumerable: false,
145
+ value (options = {}) {
146
+ const bag = options;
147
+ const structural = {};
148
+ for (const [k, v] of Object.entries(bag)){
149
+ if (!ASYNC_OPTION_KEYS.has(k)) structural[k] = v;
150
+ }
151
+ const key = deriveKey(bag.key, // Async factories aren't structurally hashable in a useful way, so the
152
+ // default key hashes the async wiring + structural fields — same
153
+ // instance-identity semantics ConfigurableModuleBuilder always had.
154
+ spec.key ? structural : {
155
+ inject: bag.inject,
156
+ useFactory: bag.useFactory,
157
+ useClass: bag.useClass,
158
+ useExisting: bag.useExisting,
159
+ ...structural
160
+ });
161
+ const definition = {
162
+ module: this,
163
+ key,
164
+ imports: bag.imports ?? [],
165
+ providers: buildAsyncOptionsProviders(optionsToken, factoryMethodName, bag, structural)
166
+ };
167
+ return applyLazy(transform(applyContributions(definition, structural, key), {
168
+ ...extrasDefaults,
169
+ ...structural
170
+ }), structural.lazy);
171
+ }
172
+ });
173
+ return {
174
+ ConfigurableModuleClass: GeneratedModuleClass,
175
+ MODULE_OPTIONS_TOKEN: optionsToken,
176
+ // Type-only sentinels — never read at runtime.
177
+ OPTIONS_TYPE: undefined,
178
+ ASYNC_OPTIONS_TYPE: undefined
179
+ };
180
+ }
181
+ /**
182
+ * Lower `useFactory`/`useClass`/`useExisting` async options into provider
183
+ * registrations. Structural fields from the call site merge UNDER the resolved
184
+ * options (`{ ...structural, ...resolved }`) so sync-declared fields act as
185
+ * defaults and the factory stays authoritative.
186
+ */ export function buildAsyncOptionsProviders(optionsToken, factoryMethodName, async, structural = {}) {
187
+ const hasStructural = Object.keys(structural).length > 0;
188
+ const merge = (resolved)=>resolved instanceof Promise ? resolved.then((o)=>({
189
+ ...structural,
190
+ ...o
191
+ })) : {
192
+ ...structural,
193
+ ...resolved
194
+ };
195
+ if (async.useFactory) {
196
+ const factory = async.useFactory;
197
+ return [
198
+ {
199
+ provide: optionsToken,
200
+ // No structural fields → pass the caller's factory through untouched
201
+ // (function identity preserved; nothing to merge).
202
+ useFactory: hasStructural ? (...deps)=>merge(factory(...deps)) : factory,
203
+ inject: async.inject ?? []
204
+ }
205
+ ];
206
+ }
207
+ if (async.useClass) {
208
+ const factoryClass = async.useClass;
209
+ return [
210
+ factoryClass,
211
+ {
212
+ provide: optionsToken,
213
+ useFactory: (instance)=>merge(instance[factoryMethodName]()),
214
+ inject: [
215
+ factoryClass
216
+ ]
217
+ }
218
+ ];
219
+ }
220
+ if (async.useExisting) {
221
+ return [
222
+ {
223
+ provide: optionsToken,
224
+ useFactory: (instance)=>merge(instance[factoryMethodName]()),
225
+ inject: [
226
+ async.useExisting
227
+ ]
228
+ }
229
+ ];
230
+ }
231
+ throw new Error('Async module options require one of `useFactory`, `useClass`, or `useExisting`.');
232
+ }
@@ -1,6 +1,8 @@
1
1
  export { Global, Module, isModule, getModuleMetadata, defineDynamicModule, } from './decorators';
2
2
  export { stableHash } from './stable-hash';
3
- export { ConfigurableModuleBuilder, defineConfigurableModule, } from './configurable-module.builder';
3
+ export { ConfigurableModuleBuilder, defineConfigurableModule, moduleKey, } from './configurable-module.builder';
4
+ export { defineModule, buildAsyncOptionsProviders, type DefineModuleSpec, type GlobalComponentSlot, type ModuleContributions, type ModuleSetupContext, } from './define-module';
5
+ export { lazyProvider, moduleToken, provideGlobal, sideEffectModule, type LazyProviderSpec, } from './lazy-provider';
4
6
  export type { ConfigurableModuleAsyncOptions, ConfigurableModuleBuilderOptions, ConfigurableModuleClassType, ConfigurableModuleExtras, ConfigurableModuleExtrasTransform, ConfigurableModuleHost, ConfigurableModuleOptionsFactory, DefineConfigurableModuleSpec, } from './configurable-module.types';
5
7
  export { ModuleLoader } from './module-loader';
6
8
  export { MiddlewareBuilder } from './middleware';
@@ -1,5 +1,7 @@
1
1
  export { Global, Module, isModule, getModuleMetadata, defineDynamicModule } from "./decorators.js";
2
2
  export { stableHash } from "./stable-hash.js";
3
- export { ConfigurableModuleBuilder, defineConfigurableModule } from "./configurable-module.builder.js";
3
+ export { ConfigurableModuleBuilder, defineConfigurableModule, moduleKey } from "./configurable-module.builder.js";
4
+ export { defineModule, buildAsyncOptionsProviders } from "./define-module.js";
5
+ export { lazyProvider, moduleToken, provideGlobal, sideEffectModule } from "./lazy-provider.js";
4
6
  export { ModuleLoader } from "./module-loader.js";
5
7
  export { MiddlewareBuilder } from "./middleware.js";
@@ -0,0 +1,82 @@
1
+ import type { Container } from '../container/container';
2
+ import type { LazyResolutionHook, Token } from '../container/types';
3
+ /** One lazy module instance's deferral unit: its own tokens, in registration order. */
4
+ export interface LazyModuleGroup {
5
+ moduleId: string;
6
+ tokens: Token[];
7
+ /**
8
+ * A class provider's prototype declares `collectEntrypoints` — the module
9
+ * must be materialized before the entrypoint registry snapshot or its
10
+ * computed contributions would be silently absent.
11
+ */
12
+ hasEntrypointContributor: boolean;
13
+ }
14
+ /**
15
+ * Owns deferred-module state for one application: which module instances are
16
+ * still pending, which have been claimed by a container trigger, and how
17
+ * claimed groups get completed (construction + lifecycle-hook replay).
18
+ *
19
+ * Phases:
20
+ * - `'bootstrap'` (until the end of `callOnApplicationBootstrap`): completed
21
+ * groups are *absorbed* — their instances queue up for the application's
22
+ * normal hook phases, so a lazy module dragged in by an eager consumer gets
23
+ * today-identical semantics.
24
+ * - `'live'`: hooks replay at drain time (memoized, exactly once), then the
25
+ * instances are handed to the application for shutdown-hook symmetry.
26
+ *
27
+ * Sync/async duality: sync drains throw a descriptive error when a member
28
+ * factory or hook yields a thenable — lazy modules with async providers or
29
+ * hooks must be reached through an async seam (`materializeLazyModules()`,
30
+ * `resolveAsync`) or stay eager.
31
+ */
32
+ export declare class LazyModuleManager implements LazyResolutionHook {
33
+ private readonly container;
34
+ private readonly pending;
35
+ private readonly claimed;
36
+ private readonly absorbed;
37
+ private phase;
38
+ private draining;
39
+ private drainPromise?;
40
+ private onMaterialized?;
41
+ constructor(container: Container);
42
+ registerGroup(group: LazyModuleGroup): void;
43
+ /** Application sink for live-phase materializations (shutdown symmetry). */
44
+ setOnMaterialized(sink: (instances: unknown[]) => void): void;
45
+ setPhaseLive(): void;
46
+ isPending(moduleId: string): boolean;
47
+ /** Tokens whose owning modules are ALL still pending are deferred. */
48
+ hasPendingModules(): boolean;
49
+ claim(moduleId: string): void;
50
+ hasClaimed(): boolean;
51
+ /**
52
+ * A drain loop is running. The container consults this before its
53
+ * post-resolution drain: `constructGroupAsync` resolves members through
54
+ * `resolveAsync`, whose end-of-cascade check would otherwise re-enter and
55
+ * AWAIT the very drain promise it is executing inside — a self-referential
56
+ * await that never settles (with ≥2 claimed groups). Claims made while
57
+ * draining are picked up by the running loop instead.
58
+ */
59
+ isDraining(): boolean;
60
+ /** Instances constructed during the bootstrap phase, owed their hooks. */
61
+ takeAbsorbed(): unknown[];
62
+ drainSync(): void;
63
+ drainAsync(): Promise<void>;
64
+ /**
65
+ * Materialize every still-pending group whose providers compute entrypoints
66
+ * (`collectEntrypoints` on a class prototype). Called by the application
67
+ * right before the entrypoint-registry snapshot so computed contributions
68
+ * are never silently absent. The cost — those modules are effectively
69
+ * eager — is the documented price of contributing computed entrypoints.
70
+ */
71
+ materializeContributors(): Promise<void>;
72
+ /** Materialize everything still pending (warmup / tests / node runtimes). */
73
+ materializeAll(): Promise<void>;
74
+ private groupTokensToConstruct;
75
+ private constructGroupSync;
76
+ private constructGroupAsync;
77
+ /** Reversed batch = dependency-before-consumer (see drainSync comment). */
78
+ private orderBatch;
79
+ private finishBatchSync;
80
+ private finishBatchAsync;
81
+ private describeSyncFailure;
82
+ }