@mxweb/core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Provides a centralized configuration system similar to @nestjs/config.
4
4
  * @module config
5
5
  */
6
- import { ApplicationInject } from "./common";
6
+ import { ApplicationInject, InjectRegistry } from "./common";
7
7
  /**
8
8
  * Configuration management class that provides a centralized way to register
9
9
  * and access application configuration values.
@@ -58,20 +58,24 @@ export declare class Config implements ApplicationInject {
58
58
  /** Flag indicating if async providers have been built */
59
59
  private static asyncBuilt;
60
60
  /**
61
- * Creates and returns the singleton Config instance for injection into Application.
61
+ * Creates and returns a factory function for registering Config into Application.
62
+ * Uses the new InjectRegistry pattern for lazy initialization.
62
63
  *
63
- * @returns The singleton Config instance
64
+ * @template Name - The name type for the config inject (defaults to "config")
65
+ * @param name - The name to register the config under (defaults to "config")
66
+ * @returns A factory function that registers the Config singleton via InjectRegistry
64
67
  *
65
68
  * @example
66
69
  * ```ts
67
70
  * const app = Application.create({
68
- * injects: {
69
- * config: Config.forRoot(),
70
- * },
71
+ * injects: [
72
+ * Config.forRoot(), // Registers as "config"
73
+ * Config.forRoot("appConfig"), // Registers as "appConfig"
74
+ * ],
71
75
  * });
72
76
  * ```
73
77
  */
74
- static forRoot(): Config;
78
+ static forRoot<Name extends string = "config">(name?: Name): (registry: InjectRegistry) => void;
75
79
  /**
76
80
  * ApplicationInject lifecycle hook - called when the inject is initialized.
77
81
  * Builds all async providers to ensure configuration is ready.
@@ -144,8 +148,10 @@ export declare class Config implements ApplicationInject {
144
148
  * Automatically builds sync providers if not already built.
145
149
  *
146
150
  * @template T - The expected type of the configuration value
151
+ * @template D - The type of the default value (extends T)
147
152
  * @param key - The configuration key to retrieve
148
- * @returns The configuration value or undefined if not found
153
+ * @param defaultValue - Optional default value if key is not found
154
+ * @returns The configuration value, default value, or undefined if not found
149
155
  *
150
156
  * @remarks
151
157
  * This method only returns values from sync providers.
@@ -153,26 +159,32 @@ export declare class Config implements ApplicationInject {
153
159
  *
154
160
  * @example
155
161
  * ```ts
156
- * const port = Config.get<number>("port"); // 3000
157
- * const missing = Config.get("nonexistent"); // undefined
162
+ * const config = Config.forRoot();
163
+ * const port = config.get<number>("port"); // 3000
164
+ * const missing = config.get("nonexistent"); // undefined
165
+ * const withDefault = config.get<number>("timeout", 5000); // 5000 if not set
158
166
  * ```
159
167
  */
160
- static get<T = unknown>(key: string): T | undefined;
168
+ get<T = unknown, D extends T = T>(key: string, defaultValue?: D): D extends undefined ? T | undefined : T;
161
169
  /**
162
170
  * Retrieves a configuration value by key (asynchronous).
163
171
  * Automatically builds all providers (sync + async) if not already built.
164
172
  *
165
173
  * @template T - The expected type of the configuration value
174
+ * @template D - The type of the default value (extends T)
166
175
  * @param key - The configuration key to retrieve
167
- * @returns Promise resolving to the configuration value or undefined if not found
176
+ * @param defaultValue - Optional default value if key is not found
177
+ * @returns Promise resolving to the configuration value, default value, or undefined
168
178
  *
169
179
  * @example
170
180
  * ```ts
171
- * const secret = await Config.getAsync<string>("secretKey");
172
- * const remoteConfig = await Config.getAsync<RemoteConfig>("remoteConfig");
181
+ * const config = Config.forRoot();
182
+ * const secret = await config.getAsync<string>("secretKey");
183
+ * const remoteConfig = await config.getAsync<RemoteConfig>("remoteConfig");
184
+ * const withDefault = await config.getAsync<number>("retryCount", 3);
173
185
  * ```
174
186
  */
175
- static getAsync<T = unknown>(key: string): Promise<T | undefined>;
187
+ getAsync<T = unknown, D extends T = T>(key: string, defaultValue?: D): Promise<D extends undefined ? T | undefined : T>;
176
188
  /**
177
189
  * Retrieves a configuration value by key, throwing an error if not found (synchronous).
178
190
  *
@@ -183,11 +195,12 @@ export declare class Config implements ApplicationInject {
183
195
  *
184
196
  * @example
185
197
  * ```ts
186
- * const port = Config.getOrThrow<number>("port"); // 3000
187
- * const missing = Config.getOrThrow("nonexistent"); // throws Error
198
+ * const config = Config.forRoot();
199
+ * const port = config.getOrThrow<number>("port"); // 3000
200
+ * const missing = config.getOrThrow("nonexistent"); // throws Error
188
201
  * ```
189
202
  */
190
- static getOrThrow<T = unknown>(key: string): T;
203
+ getOrThrow<T = unknown>(key: string): T;
191
204
  /**
192
205
  * Retrieves a configuration value by key, throwing an error if not found (asynchronous).
193
206
  *
@@ -198,10 +211,11 @@ export declare class Config implements ApplicationInject {
198
211
  *
199
212
  * @example
200
213
  * ```ts
201
- * const secret = await Config.getAsyncOrThrow<string>("secretKey");
214
+ * const config = Config.forRoot();
215
+ * const secret = await config.getAsyncOrThrow<string>("secretKey");
202
216
  * ```
203
217
  */
204
- static getAsyncOrThrow<T = unknown>(key: string): Promise<T>;
218
+ getAsyncOrThrow<T = unknown>(key: string): Promise<T>;
205
219
  /**
206
220
  * Checks if a configuration key exists (registered or already built).
207
221
  *
@@ -210,12 +224,13 @@ export declare class Config implements ApplicationInject {
210
224
  *
211
225
  * @example
212
226
  * ```ts
213
- * if (Config.has("featureFlag")) {
227
+ * const config = Config.forRoot();
228
+ * if (config.has("featureFlag")) {
214
229
  * // Feature is configured
215
230
  * }
216
231
  * ```
217
232
  */
218
- static has(key: string): boolean;
233
+ has(key: string): boolean;
219
234
  /**
220
235
  * Returns a copy of all built configuration values.
221
236
  *
@@ -227,14 +242,15 @@ export declare class Config implements ApplicationInject {
227
242
  *
228
243
  * @example
229
244
  * ```ts
230
- * await Config.getAsync("anyKey"); // Ensure all are built
231
- * const allConfig = Config.getAll();
245
+ * const config = Config.forRoot();
246
+ * await config.getAsync("anyKey"); // Ensure all are built
247
+ * const allConfig = config.getAll();
232
248
  * for (const [key, value] of allConfig) {
233
249
  * console.log(`${key}: ${value}`);
234
250
  * }
235
251
  * ```
236
252
  */
237
- static getAll(): Map<string, unknown>;
253
+ getAll(): Map<string, unknown>;
238
254
  /**
239
255
  * Resets all configuration state.
240
256
  * Primarily used for testing to ensure clean state between tests.
@@ -250,9 +266,10 @@ export declare class Config implements ApplicationInject {
250
266
  * ```ts
251
267
  * // In test setup/teardown
252
268
  * beforeEach(() => {
253
- * Config.reset();
269
+ * const config = Config.forRoot();
270
+ * config.reset();
254
271
  * });
255
272
  * ```
256
273
  */
257
- static reset(): void;
274
+ reset(): void;
258
275
  }
package/dist/config.js CHANGED
@@ -1 +1 @@
1
- "use strict";class t{static forRoot(){return t.instance||(t.instance=new t),t.instance}async onInit(){await t.buildAsync()}static register(s,r){return t.providers.set(s,r),t}static registerAsync(s,r){return t.asyncProviders.set(s,r),t}static build(){if(!t.built){for(const[s,r]of t.providers)t.store.has(s)||t.store.set(s,r());t.built=!0}}static async buildAsync(){if(t.build(),!t.asyncBuilt){for(const[s,r]of t.asyncProviders)t.store.has(s)||t.store.set(s,await r());t.asyncBuilt=!0}}static get(s){return t.build(),t.store.get(s)}static async getAsync(s){return await t.buildAsync(),t.store.get(s)}static getOrThrow(s){if(t.build(),!t.store.has(s))throw new Error(`[Config] Config key "${s}" not found`);return t.store.get(s)}static async getAsyncOrThrow(s){if(await t.buildAsync(),!t.store.has(s))throw new Error(`[Config] Config key "${s}" not found`);return t.store.get(s)}static has(s){return t.store.has(s)||t.providers.has(s)||t.asyncProviders.has(s)}static getAll(){return new Map(t.store)}static reset(){t.instance=null,t.store.clear(),t.providers.clear(),t.asyncProviders.clear(),t.built=!1,t.asyncBuilt=!1}}t.instance=null,t.store=new Map,t.providers=new Map,t.asyncProviders=new Map,t.built=!1,t.asyncBuilt=!1,exports.Config=t;
1
+ "use strict";class t{static forRoot(r="config"){return s=>{s.set(r,()=>(t.instance||(t.instance=new t),t.instance))}}async onInit(){await t.buildAsync()}static register(r,s){return t.providers.set(r,s),t}static registerAsync(r,s){return t.asyncProviders.set(r,s),t}static build(){if(!t.built){for(const[r,s]of t.providers)t.store.has(r)||t.store.set(r,s());t.built=!0}}static async buildAsync(){if(t.build(),!t.asyncBuilt){for(const[r,s]of t.asyncProviders)t.store.has(r)||t.store.set(r,await s());t.asyncBuilt=!0}}get(r,s){return t.build(),t.store.get(r)??s}async getAsync(r,s){return await t.buildAsync(),t.store.get(r)??s}getOrThrow(r){if(t.build(),!t.store.has(r))throw new Error(`[Config] Config key "${r}" not found`);return t.store.get(r)}async getAsyncOrThrow(r){if(await t.buildAsync(),!t.store.has(r))throw new Error(`[Config] Config key "${r}" not found`);return t.store.get(r)}has(r){return t.store.has(r)||t.providers.has(r)||t.asyncProviders.has(r)}getAll(){return new Map(t.store)}reset(){t.instance=null,t.store.clear(),t.providers.clear(),t.asyncProviders.clear(),t.built=!1,t.asyncBuilt=!1}}t.instance=null,t.store=new Map,t.providers=new Map,t.asyncProviders=new Map,t.built=!1,t.asyncBuilt=!1,exports.Config=t;
package/dist/config.mjs CHANGED
@@ -1 +1 @@
1
- class t{static forRoot(){return t.instance||(t.instance=new t),t.instance}async onInit(){await t.buildAsync()}static register(s,r){return t.providers.set(s,r),t}static registerAsync(s,r){return t.asyncProviders.set(s,r),t}static build(){if(!t.built){for(const[s,r]of t.providers)t.store.has(s)||t.store.set(s,r());t.built=!0}}static async buildAsync(){if(t.build(),!t.asyncBuilt){for(const[s,r]of t.asyncProviders)t.store.has(s)||t.store.set(s,await r());t.asyncBuilt=!0}}static get(s){return t.build(),t.store.get(s)}static async getAsync(s){return await t.buildAsync(),t.store.get(s)}static getOrThrow(s){if(t.build(),!t.store.has(s))throw new Error(`[Config] Config key "${s}" not found`);return t.store.get(s)}static async getAsyncOrThrow(s){if(await t.buildAsync(),!t.store.has(s))throw new Error(`[Config] Config key "${s}" not found`);return t.store.get(s)}static has(s){return t.store.has(s)||t.providers.has(s)||t.asyncProviders.has(s)}static getAll(){return new Map(t.store)}static reset(){t.instance=null,t.store.clear(),t.providers.clear(),t.asyncProviders.clear(),t.built=!1,t.asyncBuilt=!1}}t.instance=null,t.store=new Map,t.providers=new Map,t.asyncProviders=new Map,t.built=!1,t.asyncBuilt=!1;export{t as Config};
1
+ class r{static forRoot(t="config"){return s=>{s.set(t,()=>(r.instance||(r.instance=new r),r.instance))}}async onInit(){await r.buildAsync()}static register(t,s){return r.providers.set(t,s),r}static registerAsync(t,s){return r.asyncProviders.set(t,s),r}static build(){if(!r.built){for(const[t,s]of r.providers)r.store.has(t)||r.store.set(t,s());r.built=!0}}static async buildAsync(){if(r.build(),!r.asyncBuilt){for(const[t,s]of r.asyncProviders)r.store.has(t)||r.store.set(t,await s());r.asyncBuilt=!0}}get(t,s){return r.build(),r.store.get(t)??s}async getAsync(t,s){return await r.buildAsync(),r.store.get(t)??s}getOrThrow(t){if(r.build(),!r.store.has(t))throw new Error(`[Config] Config key "${t}" not found`);return r.store.get(t)}async getAsyncOrThrow(t){if(await r.buildAsync(),!r.store.has(t))throw new Error(`[Config] Config key "${t}" not found`);return r.store.get(t)}has(t){return r.store.has(t)||r.providers.has(t)||r.asyncProviders.has(t)}getAll(){return new Map(r.store)}reset(){r.instance=null,r.store.clear(),r.providers.clear(),r.asyncProviders.clear(),r.built=!1,r.asyncBuilt=!1}}r.instance=null,r.store=new Map,r.providers=new Map,r.asyncProviders=new Map,r.built=!1,r.asyncBuilt=!1;export{r as Config};
@@ -277,21 +277,37 @@ export declare function FormData(): Promise<globalThis.FormData>;
277
277
  */
278
278
  export declare function Text(): Promise<string>;
279
279
  /**
280
- * Retrieves a feature-local inject by name.
280
+ * Retrieves a feature-local inject by name (async with lazy initialization).
281
281
  *
282
282
  * @template T - Expected type of the inject (must extend FeatureInject)
283
283
  * @param name - The name of the inject to retrieve
284
- * @returns The inject instance or undefined if not found
284
+ * @returns Promise resolving to the inject instance or undefined if not found
285
285
  *
286
286
  * @example
287
287
  * ```ts
288
- * findAll() {
289
- * const repository = Inject<ProductRepository>("productRepository");
288
+ * async findAll() {
289
+ * const repository = await Inject<ProductRepository>("productRepository");
290
290
  * return repository?.findAll();
291
291
  * }
292
292
  * ```
293
293
  */
294
- export declare function Inject<T extends FeatureInject = FeatureInject>(name: string): T | undefined;
294
+ export declare function Inject<T extends FeatureInject = FeatureInject>(name: string): Promise<T | undefined>;
295
+ /**
296
+ * Retrieves a feature-local inject by name (sync, must be already initialized).
297
+ *
298
+ * @template T - Expected type of the inject (must extend FeatureInject)
299
+ * @param name - The name of the inject to retrieve
300
+ * @returns The inject instance or undefined if not found/initialized
301
+ *
302
+ * @example
303
+ * ```ts
304
+ * formatProduct() {
305
+ * const formatter = InjectSync<Formatter>("formatter");
306
+ * return formatter?.format(this.product);
307
+ * }
308
+ * ```
309
+ */
310
+ export declare function InjectSync<T extends FeatureInject = FeatureInject>(name: string): T | undefined;
295
311
  /**
296
312
  * Retrieves route metadata by key.
297
313
  * Use with `SetMetadata()` to pass data to handlers/guards.
package/dist/decorator.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("./context.js");exports.Body=function(){return e.executeContext.switchHttp().json()},exports.FormData=function(){return e.executeContext.switchHttp().formData()},exports.Header=function(t){return e.executeContext.switchHttp().headers()[t.toLowerCase()]},exports.Headers=function(){return e.executeContext.switchHttp().headers()},exports.Inject=function(t){return e.executeContext.getLocalInject(t)},exports.Metadata=function(t){return e.executeContext.getMetadata(t)},exports.Param=function(t){return e.executeContext.switchHttp().params()[t]},exports.Params=function(){return e.executeContext.switchHttp().params()},exports.Query=function(){return e.executeContext.switchHttp().query()},exports.QueryParam=function(t){return e.executeContext.switchHttp().query()[t]},exports.Request=function(){return e.executeContext.switchHttp().getRequest()},exports.SetMetadata=function(e,t){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map([[e,t]])}},exports.Text=function(){return e.executeContext.switchHttp().text()},exports.UseFilters=function(...e){return{guards:new Set,filters:new Set(e),interceptors:new Set,pipes:new Set,metadata:new Map}},exports.UseGuards=function(...e){return{guards:new Set(e),filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map}},exports.UseInterceptors=function(...e){return{guards:new Set,filters:new Set,interceptors:new Set(e),pipes:new Set,metadata:new Map}},exports.UsePipes=function(...e){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set(e),metadata:new Map}},exports.applyDecorators=function(...e){const t=new Set,r=new Set,n=new Set,s=new Set,a=new Map;return e.forEach(e=>{e.guards.forEach(e=>t.add(e)),e.filters.forEach(e=>r.add(e)),e.interceptors.forEach(e=>n.add(e)),e.pipes.forEach(e=>s.add(e)),e.metadata.forEach((e,t)=>a.set(t,e))}),{guards:t,filters:r,interceptors:n,pipes:s,metadata:a}},exports.createDecorator=function(t){return(...r)=>t(e.executeContext,r)};
1
+ "use strict";var e=require("./context.js");exports.Body=function(){return e.executeContext.switchHttp().json()},exports.FormData=function(){return e.executeContext.switchHttp().formData()},exports.Header=function(t){return e.executeContext.switchHttp().headers()[t.toLowerCase()]},exports.Headers=function(){return e.executeContext.switchHttp().headers()},exports.Inject=function(t){return e.executeContext.getLocalInject(t)},exports.InjectSync=function(t){return e.executeContext.getLocalInjectSync(t)},exports.Metadata=function(t){return e.executeContext.getMetadata(t)},exports.Param=function(t){return e.executeContext.switchHttp().params()[t]},exports.Params=function(){return e.executeContext.switchHttp().params()},exports.Query=function(){return e.executeContext.switchHttp().query()},exports.QueryParam=function(t){return e.executeContext.switchHttp().query()[t]},exports.Request=function(){return e.executeContext.switchHttp().getRequest()},exports.SetMetadata=function(e,t){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map([[e,t]])}},exports.Text=function(){return e.executeContext.switchHttp().text()},exports.UseFilters=function(...e){return{guards:new Set,filters:new Set(e),interceptors:new Set,pipes:new Set,metadata:new Map}},exports.UseGuards=function(...e){return{guards:new Set(e),filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map}},exports.UseInterceptors=function(...e){return{guards:new Set,filters:new Set,interceptors:new Set(e),pipes:new Set,metadata:new Map}},exports.UsePipes=function(...e){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set(e),metadata:new Map}},exports.applyDecorators=function(...e){const t=new Set,r=new Set,n=new Set,o=new Set,s=new Map;return e.forEach(e=>{e.guards.forEach(e=>t.add(e)),e.filters.forEach(e=>r.add(e)),e.interceptors.forEach(e=>n.add(e)),e.pipes.forEach(e=>o.add(e)),e.metadata.forEach((e,t)=>s.set(t,e))}),{guards:t,filters:r,interceptors:n,pipes:o,metadata:s}},exports.createDecorator=function(t){return(...r)=>t(e.executeContext,r)};
@@ -1 +1 @@
1
- import{executeContext as t}from"./context.mjs";function e(t,e){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map([[t,e]])}}function n(...t){return{guards:new Set(t),filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map}}function r(...t){return{guards:new Set,filters:new Set(t),interceptors:new Set,pipes:new Set,metadata:new Map}}function a(...t){return{guards:new Set,filters:new Set,interceptors:new Set(t),pipes:new Set,metadata:new Map}}function i(...t){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set(t),metadata:new Map}}function s(...t){const e=new Set,n=new Set,r=new Set,a=new Set,i=new Map;return t.forEach(t=>{t.guards.forEach(t=>e.add(t)),t.filters.forEach(t=>n.add(t)),t.interceptors.forEach(t=>r.add(t)),t.pipes.forEach(t=>a.add(t)),t.metadata.forEach((t,e)=>i.set(e,t))}),{guards:e,filters:n,interceptors:r,pipes:a,metadata:i}}function u(){return t.switchHttp().json()}function c(){return t.switchHttp().query()}function o(){return t.switchHttp().params()}function p(){return t.switchHttp().headers()}function w(e){return t.switchHttp().params()[e]}function f(e){return t.switchHttp().headers()[e.toLowerCase()]}function d(e){return t.switchHttp().query()[e]}function S(){return t.switchHttp().getRequest()}function h(){return t.switchHttp().formData()}function m(){return t.switchHttp().text()}function g(e){return t.getLocalInject(e)}function H(e){return t.getMetadata(e)}function l(e){return(...n)=>e(t,n)}export{u as Body,h as FormData,f as Header,p as Headers,g as Inject,H as Metadata,w as Param,o as Params,c as Query,d as QueryParam,S as Request,e as SetMetadata,m as Text,r as UseFilters,n as UseGuards,a as UseInterceptors,i as UsePipes,s as applyDecorators,l as createDecorator};
1
+ import{executeContext as t}from"./context.mjs";function e(t,e){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map([[t,e]])}}function n(...t){return{guards:new Set(t),filters:new Set,interceptors:new Set,pipes:new Set,metadata:new Map}}function r(...t){return{guards:new Set,filters:new Set(t),interceptors:new Set,pipes:new Set,metadata:new Map}}function a(...t){return{guards:new Set,filters:new Set,interceptors:new Set(t),pipes:new Set,metadata:new Map}}function i(...t){return{guards:new Set,filters:new Set,interceptors:new Set,pipes:new Set(t),metadata:new Map}}function c(...t){const e=new Set,n=new Set,r=new Set,a=new Set,i=new Map;return t.forEach(t=>{t.guards.forEach(t=>e.add(t)),t.filters.forEach(t=>n.add(t)),t.interceptors.forEach(t=>r.add(t)),t.pipes.forEach(t=>a.add(t)),t.metadata.forEach((t,e)=>i.set(e,t))}),{guards:e,filters:n,interceptors:r,pipes:a,metadata:i}}function u(){return t.switchHttp().json()}function s(){return t.switchHttp().query()}function o(){return t.switchHttp().params()}function p(){return t.switchHttp().headers()}function w(e){return t.switchHttp().params()[e]}function f(e){return t.switchHttp().headers()[e.toLowerCase()]}function d(e){return t.switchHttp().query()[e]}function S(){return t.switchHttp().getRequest()}function h(){return t.switchHttp().formData()}function m(){return t.switchHttp().text()}function g(e){return t.getLocalInject(e)}function H(e){return t.getLocalInjectSync(e)}function l(e){return t.getMetadata(e)}function M(e){return(...n)=>e(t,n)}export{u as Body,h as FormData,f as Header,p as Headers,g as Inject,H as InjectSync,l as Metadata,w as Param,o as Params,s as Query,d as QueryParam,S as Request,e as SetMetadata,m as Text,r as UseFilters,n as UseGuards,a as UseInterceptors,i as UsePipes,c as applyDecorators,M as createDecorator};
package/dist/execute.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  import { NextRequest } from "next/server";
12
12
  import { ServerResponse } from "./response";
13
13
  import { Feature } from "./feature";
14
- import { ApplicationInject, CallHandler, FeatureInject, Pipe, RouteMethod, RouteNextHandler } from "./common";
14
+ import { ApplicationInject, CallHandler, FeatureInject, InjectEntry, InjectInstanceFactory, InjectRegistry, Pipe, RouteMethod, RouteNextHandler } from "./common";
15
15
  /**
16
16
  * Container for route-level metadata, guards, filters, interceptors, and pipes.
17
17
  * Created from decorator results and attached to each route.
@@ -112,6 +112,7 @@ export interface RequestContext {
112
112
  * - Uses Node.js AsyncLocalStorage to maintain request scope across async operations
113
113
  * - Manages both request-scoped context and global application injects
114
114
  * - Provides HTTP helpers similar to NestJS's ExecutionContext
115
+ * - Supports lazy initialization of injects via InjectRegistry
115
116
  *
116
117
  * @example
117
118
  * ```ts
@@ -119,8 +120,8 @@ export interface RequestContext {
119
120
  * const params = this.context.switchHttp().params();
120
121
  * const body = await this.context.switchHttp().json<CreateDto>();
121
122
  *
122
- * // Access global injects
123
- * const db = this.context.getInject<Database>("db");
123
+ * // Access global injects (async for lazy initialization)
124
+ * const db = await this.context.getInject<Database>("db");
124
125
  *
125
126
  * // Access feature-local injects
126
127
  * const repo = this.context.getLocalInject<Repository>("productRepo");
@@ -131,8 +132,13 @@ export declare class ExecuteContext {
131
132
  private static _instance;
132
133
  /** AsyncLocalStorage for request-scoped context */
133
134
  private storage;
134
- /** Map of global application injects */
135
+ /**
136
+ * Global injections - stores inject entries with factory and lazy instance.
137
+ * Each entry contains a factory function and optionally an initialized instance.
138
+ */
135
139
  private _injections;
140
+ /** Reference to registry for lazy initialization */
141
+ private _registry;
136
142
  /**
137
143
  * Private constructor to enforce singleton pattern.
138
144
  * @private
@@ -146,40 +152,71 @@ export declare class ExecuteContext {
146
152
  */
147
153
  static get instance(): ExecuteContext;
148
154
  /**
149
- * Returns the map of global application injects.
150
- * Injects are set by Application.loadInjects() during initialization.
155
+ * Sets the registry reference for lazy initialization.
156
+ * Called by Application during inject registration.
151
157
  *
152
- * @returns Map of inject name to instance
158
+ * @param registry - The InjectRegistry instance
153
159
  */
154
- get injections(): Map<string, ApplicationInject>;
160
+ setRegistry(registry: InjectRegistry): void;
155
161
  /**
156
- * Registers a global inject by name.
162
+ * Returns the map of global application inject entries.
163
+ * Entries contain factories and optionally initialized instances.
157
164
  *
165
+ * @returns Map of inject name to InjectEntry
166
+ */
167
+ get injections(): Map<string, InjectEntry>;
168
+ /**
169
+ * Registers an inject factory by name (lazy - instance not yet created).
170
+ *
171
+ * @template T - The type of the inject instance
158
172
  * @param name - The name to register the inject under
159
- * @param instance - The inject instance
173
+ * @param factory - Factory function that creates the inject instance
174
+ */
175
+ setInject<T extends ApplicationInject = ApplicationInject>(name: string, factory: InjectInstanceFactory<T>): void;
176
+ /**
177
+ * Retrieves a global inject by name with lazy initialization.
178
+ * If the inject hasn't been initialized yet, calls the factory to create it.
179
+ *
180
+ * @template T - Expected type of the inject (must extend ApplicationInject)
181
+ * @param name - The name of the inject to retrieve
182
+ * @returns Promise resolving to the inject instance or undefined if not found
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const db = await context.getInject<DatabaseConnection>("db");
187
+ * const config = await context.getInject<Config>("config");
188
+ * ```
160
189
  */
161
- setInject(name: string, instance: ApplicationInject): void;
190
+ getInject<T extends ApplicationInject = ApplicationInject>(name: string): Promise<T | undefined>;
162
191
  /**
163
- * Retrieves a global inject by name.
192
+ * Retrieves a global inject synchronously (only if already initialized).
193
+ * Returns undefined if the inject hasn't been initialized yet.
164
194
  *
165
195
  * @template T - Expected type of the inject (must extend ApplicationInject)
166
196
  * @param name - The name of the inject to retrieve
167
- * @returns The inject instance or undefined if not found
197
+ * @returns The inject instance or undefined if not found/not initialized
168
198
  *
169
199
  * @example
170
200
  * ```ts
171
- * const db = context.getInject<DatabaseConnection>("db");
172
- * const config = context.getInject<Config>("config");
201
+ * // Only returns if already initialized
202
+ * const config = context.getInjectSync<Config>("config");
173
203
  * ```
174
204
  */
175
- getInject<T extends ApplicationInject = ApplicationInject>(name: string): T | undefined;
205
+ getInjectSync<T extends ApplicationInject = ApplicationInject>(name: string): T | undefined;
176
206
  /**
177
- * Checks if a global inject exists by name.
207
+ * Checks if a global inject factory exists by name.
178
208
  *
179
209
  * @param name - The inject name to check
180
- * @returns true if the inject exists, false otherwise
210
+ * @returns true if the inject factory exists, false otherwise
181
211
  */
182
212
  hasInject(name: string): boolean;
213
+ /**
214
+ * Checks if a global inject has been initialized.
215
+ *
216
+ * @param name - The inject name to check
217
+ * @returns true if the inject instance exists, false otherwise
218
+ */
219
+ isInjectInitialized(name: string): boolean;
183
220
  /**
184
221
  * Clears all global injects.
185
222
  * Primarily used for testing to ensure clean state between tests.
@@ -304,20 +341,35 @@ export declare class ExecuteContext {
304
341
  */
305
342
  getFeature(): Feature | undefined;
306
343
  /**
307
- * Retrieves a feature-local inject by name.
344
+ * Retrieves a feature-local inject by name with lazy initialization.
308
345
  * Falls back to global injects if not found in the feature.
309
346
  *
310
347
  * @template T - Expected type of the inject (must extend FeatureInject)
311
348
  * @param name - The name of the inject to retrieve
312
- * @returns The inject instance or undefined if not found
349
+ * @returns Promise resolving to the inject instance or undefined if not found
313
350
  *
314
351
  * @example
315
352
  * ```ts
316
353
  * // First checks feature injects, then global injects
317
- * const repo = context.getLocalInject<ProductRepository>("productRepo");
354
+ * const repo = await context.getLocalInject<ProductRepository>("productRepo");
355
+ * ```
356
+ */
357
+ getLocalInject<T extends FeatureInject>(name: string): Promise<T | undefined>;
358
+ /**
359
+ * Retrieves a feature-local inject synchronously (only if already initialized).
360
+ * Falls back to global injects if not found in the feature.
361
+ *
362
+ * @template T - Expected type of the inject (must extend FeatureInject)
363
+ * @param name - The name of the inject to retrieve
364
+ * @returns The inject instance or undefined if not found/not initialized
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * // Only returns if already initialized
369
+ * const repo = context.getLocalInjectSync<ProductRepository>("productRepo");
318
370
  * ```
319
371
  */
320
- getLocalInject<T extends FeatureInject>(name: string): T | undefined;
372
+ getLocalInjectSync<T extends FeatureInject>(name: string): T | undefined;
321
373
  }
322
374
  /**
323
375
  * Interface for guard classes that determine if a request should proceed.
package/dist/execute.js CHANGED
@@ -1 +1 @@
1
- "use strict";var t=require("async_hooks");class e{constructor(){this.storage=new t.AsyncLocalStorage,this._injections=new Map}static get instance(){return e._instance||(e._instance=new e),e._instance}get injections(){return this._injections}setInject(t,e){this._injections.set(t,e)}getInject(t){return this._injections.get(t)}hasInject(t){return this._injections.has(t)}clearInjections(){this._injections.clear()}run(t,e){return this.storage.run(t,e)}getContext(){return this.storage.getStore()}getContextOrThrow(){const t=this.storage.getStore();if(!t)throw new Error("[ExecuteContext] No context available. Make sure you're inside a request handler.");return t}switchHttp(){const t=this.getContextOrThrow();return{getRequest:()=>t.req,getResponse:()=>t.res,getMethod:()=>t.method,getPath:()=>t.path,params:()=>t.params,wildcards:()=>t.wildcards,query:()=>Object.fromEntries(t.req.nextUrl.searchParams),headers:()=>Object.fromEntries(t.req.headers),body:()=>t.req.body,json:()=>t.req.json(),text:()=>t.req.text(),formData:()=>t.req.formData(),blob:()=>t.req.blob(),arrayBuffer:()=>t.req.arrayBuffer()}}getReflect(){return this.getContext()?.reflect}getMetadata(t){return this.getContext()?.reflect.getMetadata(t)}getFeature(){return this.getContext()?.feature}getLocalInject(t){const e=this.getContext()?.feature;return e?.hasInject(t)?e.getInject(t):this._injections.get(t)}}e._instance=null,exports.ExecuteContext=e,exports.Reflect=class{constructor(t,e,r,s,n){this.metadata=t,this.guards=e,this.filters=r,this.interceptors=s,this.pipes=n}getGuards(){return this.guards}getFilters(){return this.filters}getInterceptors(){return this.interceptors}getPipes(){return this.pipes}getMetadata(t){return this.metadata.get(t)}getAllMetadata(){return this.metadata}};
1
+ "use strict";var t=require("async_hooks");class e{constructor(){this.storage=new t.AsyncLocalStorage,this._injections=new Map,this._registry=null}static get instance(){return e._instance||(e._instance=new e),e._instance}setRegistry(t){this._registry=t}get injections(){return this._injections}setInject(t,e){this._injections.set(t,{factory:e})}async getInject(t){const e=this._injections.get(t);if(e){if(!e.instance){if(!this._registry)throw new Error(`[ExecuteContext] Registry not set. Cannot initialize inject '${t}'.`);e.instance=await e.factory(this._registry),"function"==typeof e.instance.onInit&&await e.instance.onInit()}return e.instance}}getInjectSync(t){const e=this._injections.get(t);return e?.instance}hasInject(t){return this._injections.has(t)}isInjectInitialized(t){const e=this._injections.get(t);return!!e?.instance}clearInjections(){this._injections.clear()}run(t,e){return this.storage.run(t,e)}getContext(){return this.storage.getStore()}getContextOrThrow(){const t=this.storage.getStore();if(!t)throw new Error("[ExecuteContext] No context available. Make sure you're inside a request handler.");return t}switchHttp(){const t=this.getContextOrThrow();return{getRequest:()=>t.req,getResponse:()=>t.res,getMethod:()=>t.method,getPath:()=>t.path,params:()=>t.params,wildcards:()=>t.wildcards,query:()=>Object.fromEntries(t.req.nextUrl.searchParams),headers:()=>Object.fromEntries(t.req.headers),body:()=>t.req.body,json:()=>t.req.json(),text:()=>t.req.text(),formData:()=>t.req.formData(),blob:()=>t.req.blob(),arrayBuffer:()=>t.req.arrayBuffer()}}getReflect(){return this.getContext()?.reflect}getMetadata(t){return this.getContext()?.reflect.getMetadata(t)}getFeature(){return this.getContext()?.feature}async getLocalInject(t){const e=this.getContext()?.feature;return e?.hasInject(t)?e.getInject(t):this.getInject(t)}getLocalInjectSync(t){const e=this.getContext()?.feature;return e?.hasInject(t)?e.getInjectSync(t):this.getInjectSync(t)}}e._instance=null,exports.ExecuteContext=e,exports.Reflect=class{constructor(t,e,r,n,s){this.metadata=t,this.guards=e,this.filters=r,this.interceptors=n,this.pipes=s}getGuards(){return this.guards}getFilters(){return this.filters}getInterceptors(){return this.interceptors}getPipes(){return this.pipes}getMetadata(t){return this.metadata.get(t)}getAllMetadata(){return this.metadata}};
package/dist/execute.mjs CHANGED
@@ -1 +1 @@
1
- import{AsyncLocalStorage as t}from"async_hooks";class e{constructor(t,e,r,s,n){this.metadata=t,this.guards=e,this.filters=r,this.interceptors=s,this.pipes=n}getGuards(){return this.guards}getFilters(){return this.filters}getInterceptors(){return this.interceptors}getPipes(){return this.pipes}getMetadata(t){return this.metadata.get(t)}getAllMetadata(){return this.metadata}}class r{constructor(){this.storage=new t,this._injections=new Map}static get instance(){return r._instance||(r._instance=new r),r._instance}get injections(){return this._injections}setInject(t,e){this._injections.set(t,e)}getInject(t){return this._injections.get(t)}hasInject(t){return this._injections.has(t)}clearInjections(){this._injections.clear()}run(t,e){return this.storage.run(t,e)}getContext(){return this.storage.getStore()}getContextOrThrow(){const t=this.storage.getStore();if(!t)throw new Error("[ExecuteContext] No context available. Make sure you're inside a request handler.");return t}switchHttp(){const t=this.getContextOrThrow();return{getRequest:()=>t.req,getResponse:()=>t.res,getMethod:()=>t.method,getPath:()=>t.path,params:()=>t.params,wildcards:()=>t.wildcards,query:()=>Object.fromEntries(t.req.nextUrl.searchParams),headers:()=>Object.fromEntries(t.req.headers),body:()=>t.req.body,json:()=>t.req.json(),text:()=>t.req.text(),formData:()=>t.req.formData(),blob:()=>t.req.blob(),arrayBuffer:()=>t.req.arrayBuffer()}}getReflect(){return this.getContext()?.reflect}getMetadata(t){return this.getContext()?.reflect.getMetadata(t)}getFeature(){return this.getContext()?.feature}getLocalInject(t){const e=this.getContext()?.feature;return e?.hasInject(t)?e.getInject(t):this._injections.get(t)}}r._instance=null;export{r as ExecuteContext,e as Reflect};
1
+ import{AsyncLocalStorage as t}from"async_hooks";class e{constructor(t,e,n,r,s){this.metadata=t,this.guards=e,this.filters=n,this.interceptors=r,this.pipes=s}getGuards(){return this.guards}getFilters(){return this.filters}getInterceptors(){return this.interceptors}getPipes(){return this.pipes}getMetadata(t){return this.metadata.get(t)}getAllMetadata(){return this.metadata}}class n{constructor(){this.storage=new t,this._injections=new Map,this._registry=null}static get instance(){return n._instance||(n._instance=new n),n._instance}setRegistry(t){this._registry=t}get injections(){return this._injections}setInject(t,e){this._injections.set(t,{factory:e})}async getInject(t){const e=this._injections.get(t);if(e){if(!e.instance){if(!this._registry)throw new Error(`[ExecuteContext] Registry not set. Cannot initialize inject '${t}'.`);e.instance=await e.factory(this._registry),"function"==typeof e.instance.onInit&&await e.instance.onInit()}return e.instance}}getInjectSync(t){const e=this._injections.get(t);return e?.instance}hasInject(t){return this._injections.has(t)}isInjectInitialized(t){const e=this._injections.get(t);return!!e?.instance}clearInjections(){this._injections.clear()}run(t,e){return this.storage.run(t,e)}getContext(){return this.storage.getStore()}getContextOrThrow(){const t=this.storage.getStore();if(!t)throw new Error("[ExecuteContext] No context available. Make sure you're inside a request handler.");return t}switchHttp(){const t=this.getContextOrThrow();return{getRequest:()=>t.req,getResponse:()=>t.res,getMethod:()=>t.method,getPath:()=>t.path,params:()=>t.params,wildcards:()=>t.wildcards,query:()=>Object.fromEntries(t.req.nextUrl.searchParams),headers:()=>Object.fromEntries(t.req.headers),body:()=>t.req.body,json:()=>t.req.json(),text:()=>t.req.text(),formData:()=>t.req.formData(),blob:()=>t.req.blob(),arrayBuffer:()=>t.req.arrayBuffer()}}getReflect(){return this.getContext()?.reflect}getMetadata(t){return this.getContext()?.reflect.getMetadata(t)}getFeature(){return this.getContext()?.feature}async getLocalInject(t){const e=this.getContext()?.feature;return e?.hasInject(t)?e.getInject(t):this.getInject(t)}getLocalInjectSync(t){const e=this.getContext()?.feature;return e?.hasInject(t)?e.getInjectSync(t):this.getInjectSync(t)}}n._instance=null;export{n as ExecuteContext,e as Reflect};
package/dist/feature.d.ts CHANGED
@@ -10,12 +10,12 @@
10
10
  import { ControllerConstructor } from "./controller";
11
11
  import { RouteMatched, Router } from "./router";
12
12
  import { FeatureHooks, FeatureHooksOptions } from "./hooks";
13
- import { FeatureInject, RouteMethod } from "./common";
13
+ import { FeatureInject, FeatureInjectFactory, RouteMethod } from "./common";
14
14
  /**
15
15
  * Type for feature-specific dependency injection configuration.
16
- * Maps inject names to their instances.
16
+ * Array of factory functions that register injects.
17
17
  */
18
- export type FeatureInjects = Record<string, FeatureInject>;
18
+ export type FeatureInjects = FeatureInjectFactory[];
19
19
  /**
20
20
  * Type for feature imports configuration.
21
21
  * Imports are executed once when the feature loads for side effects
@@ -71,10 +71,10 @@ export interface FeatureInitialize extends FeatureHooksOptions {
71
71
  imports?: FeatureImports;
72
72
  /**
73
73
  * Feature-specific injects (local to this feature).
74
- * Accessible via `ctx.getLocalInject()` or `Inject()` decorator.
75
- * Can be a static object, function, or async function.
74
+ * Array of factory functions that register injects.
75
+ * Accessible via `feature.getInject()` or `Inject()` decorator.
76
76
  */
77
- injects?: FeatureInjects | (() => FeatureInjects) | (() => Promise<FeatureInjects>);
77
+ injects?: FeatureInjects;
78
78
  }
79
79
  /**
80
80
  * Simplified interface for feature registration.
@@ -118,9 +118,11 @@ export interface FeatureRegister {
118
118
  * Route.delete("/products/:id", "remove"),
119
119
  * ),
120
120
  * imports: [Connection.forFeature([ProductEntity])],
121
- * injects: {
122
- * productRepo: new ProductRepository(),
123
- * },
121
+ * injects: [
122
+ * (registry) => {
123
+ * registry.set("productRepo", () => new ProductRepository());
124
+ * },
125
+ * ],
124
126
  * onStart: () => {
125
127
  * console.log("Product feature initialized");
126
128
  * },
@@ -138,10 +140,12 @@ export declare class Feature {
138
140
  private hooks;
139
141
  /** Cached controller instance (lazy instantiated) */
140
142
  private controller;
141
- /** Map of feature-local injects */
143
+ /** Map of feature-local inject entries (factory + instance) */
142
144
  private injects;
143
- /** Flag indicating if injects have been loaded */
144
- private injectsLoaded;
145
+ /** Feature inject registry */
146
+ private registry;
147
+ /** Flag indicating if inject factories have been registered */
148
+ private factoriesRegistered;
145
149
  /** Flag indicating if imports have been loaded */
146
150
  private importsLoaded;
147
151
  /**
@@ -152,6 +156,11 @@ export declare class Feature {
152
156
  * @param router - The router instance
153
157
  */
154
158
  private constructor();
159
+ /**
160
+ * Creates the inject registry for this feature.
161
+ * Only exposes get/set to prevent accidental removal.
162
+ */
163
+ private createInjectRegistry;
155
164
  /**
156
165
  * Factory method to create a new Feature instance.
157
166
  *
@@ -184,37 +193,54 @@ export declare class Feature {
184
193
  * This method is idempotent - subsequent calls have no effect.
185
194
  *
186
195
  * @remarks
187
- * Calls the `onFeature()` lifecycle hook on each inject after loading.
196
+ * Only registers factories - instances are created lazily on first get().
188
197
  */
189
198
  loadInjects(): Promise<void>;
190
199
  /**
191
200
  * Destroys all feature-specific injects.
192
- * Calls the `onFeatureDestroy()` lifecycle hook on each inject.
201
+ * Calls the `onFeatureDestroy()` lifecycle hook on each initialized inject.
193
202
  *
194
203
  * @remarks
195
204
  * Called during application shutdown via Application.registerShutdown().
205
+ * Only destroys injects that have been initialized (instance exists).
196
206
  */
197
207
  destroyInjects(): Promise<void>;
198
208
  /**
199
- * Retrieves a feature-specific inject by name.
209
+ * Retrieves a feature-specific inject by name (async - lazy initialization).
210
+ * If instance doesn't exist, calls factory to create it and runs onFeature().
200
211
  *
201
212
  * @template T - Expected type of the inject (must extend FeatureInject)
202
213
  * @param name - The name of the inject to retrieve
203
- * @returns The inject instance or undefined if not found
214
+ * @returns Promise resolving to the inject instance or undefined if not found
204
215
  *
205
216
  * @example
206
217
  * ```ts
207
- * const repo = feature.getInject<ProductRepository>("productRepo");
218
+ * const repo = await feature.getInject<ProductRepository>("productRepo");
208
219
  * ```
209
220
  */
210
- getInject<T extends FeatureInject>(name: string): T | undefined;
221
+ getInject<T extends FeatureInject>(name: string): Promise<T | undefined>;
222
+ /**
223
+ * Retrieves a feature-specific inject synchronously (only if already initialized).
224
+ *
225
+ * @template T - Expected type of the inject (must extend FeatureInject)
226
+ * @param name - The name of the inject to retrieve
227
+ * @returns The inject instance or undefined if not found/not initialized
228
+ */
229
+ getInjectSync<T extends FeatureInject>(name: string): T | undefined;
211
230
  /**
212
- * Checks if a feature-specific inject exists by name.
231
+ * Checks if a feature-specific inject factory is registered by name.
213
232
  *
214
233
  * @param name - The inject name to check
215
- * @returns true if the inject exists, false otherwise
234
+ * @returns true if the inject factory is registered, false otherwise
216
235
  */
217
236
  hasInject(name: string): boolean;
237
+ /**
238
+ * Checks if a feature-specific inject has been initialized.
239
+ *
240
+ * @param name - The inject name to check
241
+ * @returns true if the inject instance exists, false otherwise
242
+ */
243
+ isInjectInitialized(name: string): boolean;
218
244
  /**
219
245
  * Returns the controller instance for this feature.
220
246
  * Lazily instantiates the controller on first access.
package/dist/feature.js CHANGED
@@ -1 +1 @@
1
- "use strict";var t=require("./hooks.js");class e{constructor(e,o,s){this.options=e,this.ControllerContructor=o,this.router=s,this.routeMatched=null,this.controller=null,this.injects=new Map,this.injectsLoaded=!1,this.importsLoaded=!1,this.hooks=new t.FeatureHooks(this.options)}static create(t){return new e(t,t.controller,t.router)}async loadImports(){if(this.importsLoaded)return;this.importsLoaded=!0;const{imports:t}=this.options;if(!t)return;"function"==typeof t&&await t()}async loadInjects(){if(await this.loadImports(),this.injectsLoaded)return;this.injectsLoaded=!0;const{injects:t}=this.options;if(!t)return;const e="function"==typeof t?await t():t;for(const[t,o]of Object.entries(e))this.injects.set(t,o),o.onFeature&&await o.onFeature()}async destroyInjects(){for(const t of this.injects.values())t.onFeatureDestroy&&await t.onFeatureDestroy();this.injects.clear(),this.injectsLoaded=!1}getInject(t){return this.injects.get(t)}hasInject(t){return this.injects.has(t)}getController(){if(!this.controller){const t=this.ControllerContructor;this.controller=new t}return this.controller}getHooks(){return this.hooks}matchRoute(t,e){return this.routeMatched=this.router.match(t,e),this.routeMatched}}exports.Feature=e;
1
+ "use strict";var t=require("./hooks.js");class e{constructor(e,s,i){this.options=e,this.ControllerContructor=s,this.router=i,this.routeMatched=null,this.controller=null,this.injects=new Map,this.factoriesRegistered=!1,this.importsLoaded=!1,this.hooks=new t.FeatureHooks(this.options),this.registry=this.createInjectRegistry()}createInjectRegistry(){return{get:t=>this.getInject(t),set:(t,e)=>{this.injects.set(t,{factory:e})}}}static create(t){return new e(t,t.controller,t.router)}async loadImports(){if(this.importsLoaded)return;this.importsLoaded=!0;const{imports:t}=this.options;if(!t)return;"function"==typeof t&&await t()}async loadInjects(){if(await this.loadImports(),this.factoriesRegistered)return;this.factoriesRegistered=!0;const{injects:t}=this.options;if(t&&t.length)for(const e of t)await e(this.registry)}async destroyInjects(){for(const[t,e]of this.injects)if(e.instance&&e.instance.onFeatureDestroy)try{await e.instance.onFeatureDestroy()}catch(t){}this.injects.clear(),this.factoriesRegistered=!1}async getInject(t){const e=this.injects.get(t);if(e)return e.instance||(e.instance=await e.factory(this.registry),"function"==typeof e.instance.onFeature&&await e.instance.onFeature()),e.instance}getInjectSync(t){const e=this.injects.get(t);return e?.instance}hasInject(t){return this.injects.has(t)}isInjectInitialized(t){const e=this.injects.get(t);return!!e?.instance}getController(){if(!this.controller){const t=this.ControllerContructor;this.controller=new t}return this.controller}getHooks(){return this.hooks}matchRoute(t,e){return this.routeMatched=this.router.match(t,e),this.routeMatched}}exports.Feature=e;
package/dist/feature.mjs CHANGED
@@ -1 +1 @@
1
- import{FeatureHooks as t}from"./hooks.mjs";class o{constructor(o,e,s){this.options=o,this.ControllerContructor=e,this.router=s,this.routeMatched=null,this.controller=null,this.injects=new Map,this.injectsLoaded=!1,this.importsLoaded=!1,this.hooks=new t(this.options)}static create(t){return new o(t,t.controller,t.router)}async loadImports(){if(this.importsLoaded)return;this.importsLoaded=!0;const{imports:t}=this.options;if(!t)return;"function"==typeof t&&await t()}async loadInjects(){if(await this.loadImports(),this.injectsLoaded)return;this.injectsLoaded=!0;const{injects:t}=this.options;if(!t)return;const o="function"==typeof t?await t():t;for(const[t,e]of Object.entries(o))this.injects.set(t,e),e.onFeature&&await e.onFeature()}async destroyInjects(){for(const t of this.injects.values())t.onFeatureDestroy&&await t.onFeatureDestroy();this.injects.clear(),this.injectsLoaded=!1}getInject(t){return this.injects.get(t)}hasInject(t){return this.injects.has(t)}getController(){if(!this.controller){const t=this.ControllerContructor;this.controller=new t}return this.controller}getHooks(){return this.hooks}matchRoute(t,o){return this.routeMatched=this.router.match(t,o),this.routeMatched}}export{o as Feature};
1
+ import{FeatureHooks as t}from"./hooks.mjs";class e{constructor(e,s,i){this.options=e,this.ControllerContructor=s,this.router=i,this.routeMatched=null,this.controller=null,this.injects=new Map,this.factoriesRegistered=!1,this.importsLoaded=!1,this.hooks=new t(this.options),this.registry=this.createInjectRegistry()}createInjectRegistry(){return{get:t=>this.getInject(t),set:(t,e)=>{this.injects.set(t,{factory:e})}}}static create(t){return new e(t,t.controller,t.router)}async loadImports(){if(this.importsLoaded)return;this.importsLoaded=!0;const{imports:t}=this.options;if(!t)return;"function"==typeof t&&await t()}async loadInjects(){if(await this.loadImports(),this.factoriesRegistered)return;this.factoriesRegistered=!0;const{injects:t}=this.options;if(t&&t.length)for(const e of t)await e(this.registry)}async destroyInjects(){for(const[t,e]of this.injects)if(e.instance&&e.instance.onFeatureDestroy)try{await e.instance.onFeatureDestroy()}catch(t){}this.injects.clear(),this.factoriesRegistered=!1}async getInject(t){const e=this.injects.get(t);if(e)return e.instance||(e.instance=await e.factory(this.registry),"function"==typeof e.instance.onFeature&&await e.instance.onFeature()),e.instance}getInjectSync(t){const e=this.injects.get(t);return e?.instance}hasInject(t){return this.injects.has(t)}isInjectInitialized(t){const e=this.injects.get(t);return!!e?.instance}getController(){if(!this.controller){const t=this.ControllerContructor;this.controller=new t}return this.controller}getHooks(){return this.hooks}matchRoute(t,e){return this.routeMatched=this.router.match(t,e),this.routeMatched}}export{e as Feature};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var r=require("./application.js"),e=require("./common.js"),o=require("./config.js"),t=require("./controller.js"),s=require("./decorator.js"),a=require("./error.js"),p=require("./execute.js"),x=require("./feature.js"),i=require("./hooks.js"),u=require("./logger.js"),n=require("./response.js"),l=require("./route.js"),c=require("./router.js"),E=require("./service.js");exports.Application=r.Application,exports.InjectionRegistry=e.InjectionRegistry,Object.defineProperty(exports,"RouteMethod",{enumerable:!0,get:function(){return e.RouteMethod}}),exports.Config=o.Config,exports.Controller=t.Controller,exports.controller=t.controller,exports.Body=s.Body,exports.FormData=s.FormData,exports.Header=s.Header,exports.Headers=s.Headers,exports.Inject=s.Inject,exports.Metadata=s.Metadata,exports.Param=s.Param,exports.Params=s.Params,exports.Query=s.Query,exports.QueryParam=s.QueryParam,exports.Request=s.Request,exports.SetMetadata=s.SetMetadata,exports.Text=s.Text,exports.UseFilters=s.UseFilters,exports.UseGuards=s.UseGuards,exports.UseInterceptors=s.UseInterceptors,exports.UsePipes=s.UsePipes,exports.applyDecorators=s.applyDecorators,exports.createDecorator=s.createDecorator,exports.BadGatewayError=a.BadGatewayError,exports.BadRequestError=a.BadRequestError,exports.ConflictError=a.ConflictError,exports.ForbiddenError=a.ForbiddenError,exports.GatewayTimeoutError=a.GatewayTimeoutError,exports.GoneError=a.GoneError,exports.HttpError=a.HttpError,exports.InternalServerError=a.InternalServerError,exports.MethodNotAllowedError=a.MethodNotAllowedError,exports.NotAcceptableError=a.NotAcceptableError,exports.NotFoundError=a.NotFoundError,exports.NotImplementedError=a.NotImplementedError,exports.PayloadTooLargeError=a.PayloadTooLargeError,exports.RequestTimeoutError=a.RequestTimeoutError,exports.ServiceUnavailableError=a.ServiceUnavailableError,exports.TooManyRequestsError=a.TooManyRequestsError,exports.UnauthorizedError=a.UnauthorizedError,exports.UnprocessableEntityError=a.UnprocessableEntityError,exports.UnsupportedMediaTypeError=a.UnsupportedMediaTypeError,exports.ValidateError=a.ValidateError,exports.ExecuteContext=p.ExecuteContext,exports.Reflect=p.Reflect,exports.Feature=x.Feature,exports.ApplicationHooks=i.ApplicationHooks,exports.FeatureHooks=i.FeatureHooks,exports.RequestHooks=i.RequestHooks,exports.Logger=u.Logger,exports.logger=u.logger,exports.ServerResponse=n.ServerResponse,exports.Route=l.Route,exports.Router=c.Router,exports.Service=E.Service,exports.service=E.service;
1
+ "use strict";var r=require("./application.js"),e=require("./common.js"),o=require("./config.js"),t=require("./controller.js"),s=require("./decorator.js"),a=require("./error.js"),p=require("./execute.js"),x=require("./feature.js"),i=require("./hooks.js"),n=require("./logger.js"),u=require("./response.js"),c=require("./route.js"),l=require("./router.js"),E=require("./service.js");exports.Application=r.Application,exports.InjectionRegistry=e.InjectionRegistry,Object.defineProperty(exports,"RouteMethod",{enumerable:!0,get:function(){return e.RouteMethod}}),exports.Config=o.Config,exports.Controller=t.Controller,exports.controller=t.controller,exports.Body=s.Body,exports.FormData=s.FormData,exports.Header=s.Header,exports.Headers=s.Headers,exports.Inject=s.Inject,exports.InjectSync=s.InjectSync,exports.Metadata=s.Metadata,exports.Param=s.Param,exports.Params=s.Params,exports.Query=s.Query,exports.QueryParam=s.QueryParam,exports.Request=s.Request,exports.SetMetadata=s.SetMetadata,exports.Text=s.Text,exports.UseFilters=s.UseFilters,exports.UseGuards=s.UseGuards,exports.UseInterceptors=s.UseInterceptors,exports.UsePipes=s.UsePipes,exports.applyDecorators=s.applyDecorators,exports.createDecorator=s.createDecorator,exports.BadGatewayError=a.BadGatewayError,exports.BadRequestError=a.BadRequestError,exports.ConflictError=a.ConflictError,exports.ForbiddenError=a.ForbiddenError,exports.GatewayTimeoutError=a.GatewayTimeoutError,exports.GoneError=a.GoneError,exports.HttpError=a.HttpError,exports.InternalServerError=a.InternalServerError,exports.MethodNotAllowedError=a.MethodNotAllowedError,exports.NotAcceptableError=a.NotAcceptableError,exports.NotFoundError=a.NotFoundError,exports.NotImplementedError=a.NotImplementedError,exports.PayloadTooLargeError=a.PayloadTooLargeError,exports.RequestTimeoutError=a.RequestTimeoutError,exports.ServiceUnavailableError=a.ServiceUnavailableError,exports.TooManyRequestsError=a.TooManyRequestsError,exports.UnauthorizedError=a.UnauthorizedError,exports.UnprocessableEntityError=a.UnprocessableEntityError,exports.UnsupportedMediaTypeError=a.UnsupportedMediaTypeError,exports.ValidateError=a.ValidateError,exports.ExecuteContext=p.ExecuteContext,exports.Reflect=p.Reflect,exports.Feature=x.Feature,exports.ApplicationHooks=i.ApplicationHooks,exports.FeatureHooks=i.FeatureHooks,exports.RequestHooks=i.RequestHooks,exports.Logger=n.Logger,exports.logger=n.logger,exports.ServerResponse=u.ServerResponse,exports.Route=c.Route,exports.Router=l.Router,exports.Service=E.Service,exports.service=E.service;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export{Application}from"./application.mjs";export{InjectionRegistry,RouteMethod}from"./common.mjs";export{Config}from"./config.mjs";export{Controller,controller}from"./controller.mjs";export{Body,FormData,Header,Headers,Inject,Metadata,Param,Params,Query,QueryParam,Request,SetMetadata,Text,UseFilters,UseGuards,UseInterceptors,UsePipes,applyDecorators,createDecorator}from"./decorator.mjs";export{BadGatewayError,BadRequestError,ConflictError,ForbiddenError,GatewayTimeoutError,GoneError,HttpError,InternalServerError,MethodNotAllowedError,NotAcceptableError,NotFoundError,NotImplementedError,PayloadTooLargeError,RequestTimeoutError,ServiceUnavailableError,TooManyRequestsError,UnauthorizedError,UnprocessableEntityError,UnsupportedMediaTypeError,ValidateError}from"./error.mjs";export{ExecuteContext,Reflect}from"./execute.mjs";export{Feature}from"./feature.mjs";export{ApplicationHooks,FeatureHooks,RequestHooks}from"./hooks.mjs";export{Logger,logger}from"./logger.mjs";export{ServerResponse}from"./response.mjs";export{Route}from"./route.mjs";export{Router}from"./router.mjs";export{Service,service}from"./service.mjs";
1
+ export{Application}from"./application.mjs";export{InjectionRegistry,RouteMethod}from"./common.mjs";export{Config}from"./config.mjs";export{Controller,controller}from"./controller.mjs";export{Body,FormData,Header,Headers,Inject,InjectSync,Metadata,Param,Params,Query,QueryParam,Request,SetMetadata,Text,UseFilters,UseGuards,UseInterceptors,UsePipes,applyDecorators,createDecorator}from"./decorator.mjs";export{BadGatewayError,BadRequestError,ConflictError,ForbiddenError,GatewayTimeoutError,GoneError,HttpError,InternalServerError,MethodNotAllowedError,NotAcceptableError,NotFoundError,NotImplementedError,PayloadTooLargeError,RequestTimeoutError,ServiceUnavailableError,TooManyRequestsError,UnauthorizedError,UnprocessableEntityError,UnsupportedMediaTypeError,ValidateError}from"./error.mjs";export{ExecuteContext,Reflect}from"./execute.mjs";export{Feature}from"./feature.mjs";export{ApplicationHooks,FeatureHooks,RequestHooks}from"./hooks.mjs";export{Logger,logger}from"./logger.mjs";export{ServerResponse}from"./response.mjs";export{Route}from"./route.mjs";export{Router}from"./router.mjs";export{Service,service}from"./service.mjs";