@mxweb/core 1.0.2 → 1.2.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.
package/dist/execute.d.ts CHANGED
@@ -8,10 +8,225 @@
8
8
  *
9
9
  * @module execute
10
10
  */
11
- import { NextRequest } from "next/server";
12
11
  import { ServerResponse } from "./response";
13
- import { Feature } from "./feature";
14
- import { ApplicationInject, CallHandler, FeatureInject, InjectEntry, InjectInstanceFactory, InjectRegistry, Pipe, RouteMethod, RouteNextHandler } from "./common";
12
+ import { ApplicationInject, FeatureContext, Filter, Guard, InjectEntry, InjectInstanceFactory, InjectRegistry, Interceptor, Pipe, RouteMethod, RouteNextHandler } from "./common";
13
+ /**
14
+ * Core request interface defining the minimal contract for HTTP requests.
15
+ * This abstraction allows @mxweb/core to work with any request implementation
16
+ * (Next.js, Express, Fastify, etc.) as long as it conforms to this interface.
17
+ *
18
+ * @remarks
19
+ * This interface is designed to be compatible with multiple frameworks:
20
+ * - **Next.js**: Uses `nextUrl` for query params
21
+ * - **Express/Fastify**: Uses `url` (string) and `query` (parsed object)
22
+ * - **Fetch API**: Uses `url` (URL object)
23
+ *
24
+ * The framework adapter should populate the appropriate properties.
25
+ * `switchHttp().query()` will use `nextUrl.searchParams` → `url.searchParams` → `query` fallback.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * // Next.js Request is compatible with CoreRequest (uses nextUrl)
30
+ * const coreReq: CoreRequest = nextRequest;
31
+ *
32
+ * // Express Request adapter
33
+ * const expressReq: CoreRequest = {
34
+ * url: "/api/users?page=1",
35
+ * query: { page: "1" },
36
+ * headers: new Headers(req.headers),
37
+ * body: null,
38
+ * json: async () => req.body,
39
+ * text: async () => JSON.stringify(req.body),
40
+ * formData: async () => new FormData(),
41
+ * blob: async () => new Blob(),
42
+ * arrayBuffer: async () => new ArrayBuffer(0),
43
+ * };
44
+ *
45
+ * // Fetch Request adapter
46
+ * const fetchReq: CoreRequest = {
47
+ * url: new URL("https://example.com/api/users?page=1"),
48
+ * headers: request.headers,
49
+ * body: request.body,
50
+ * json: () => request.json(),
51
+ * text: () => request.text(),
52
+ * formData: () => request.formData(),
53
+ * blob: () => request.blob(),
54
+ * arrayBuffer: () => request.arrayBuffer(),
55
+ * };
56
+ * ```
57
+ */
58
+ export interface CoreRequest {
59
+ /**
60
+ * The NextURL of the request (Next.js specific).
61
+ * Used for extracting query parameters in Next.js applications.
62
+ * Takes priority over `url` when available.
63
+ */
64
+ readonly nextUrl?: URL | {
65
+ readonly searchParams: URLSearchParams;
66
+ };
67
+ /**
68
+ * The URL of the request.
69
+ * Can be:
70
+ * - URL object (Fetch API, custom implementations)
71
+ * - string (Express, Fastify - just the path with query string)
72
+ */
73
+ readonly url?: URL | string;
74
+ /**
75
+ * Pre-parsed query parameters object (Express/Fastify style).
76
+ * Used as fallback when `nextUrl` and `url` are not available or don't have searchParams.
77
+ */
78
+ readonly query?: Record<string, string | string[] | undefined>;
79
+ /**
80
+ * The HTTP headers of the request.
81
+ * Must be iterable (for use with Object.fromEntries).
82
+ */
83
+ readonly headers: Headers;
84
+ /**
85
+ * The body of the request as a ReadableStream, or null if no body.
86
+ */
87
+ readonly body: ReadableStream<Uint8Array> | null;
88
+ /**
89
+ * Parses the request body as JSON.
90
+ * @returns Promise resolving to the parsed JSON value
91
+ */
92
+ json(): Promise<unknown>;
93
+ /**
94
+ * Returns the request body as text.
95
+ * @returns Promise resolving to the body text
96
+ */
97
+ text(): Promise<string>;
98
+ /**
99
+ * Parses the request body as FormData.
100
+ * @returns Promise resolving to the FormData
101
+ */
102
+ formData(): Promise<FormData>;
103
+ /**
104
+ * Returns the request body as a Blob.
105
+ * @returns Promise resolving to the Blob
106
+ */
107
+ blob(): Promise<Blob>;
108
+ /**
109
+ * Returns the request body as an ArrayBuffer.
110
+ * @returns Promise resolving to the ArrayBuffer
111
+ */
112
+ arrayBuffer(): Promise<ArrayBuffer>;
113
+ }
114
+ /**
115
+ * Unified search params class that works with multiple input sources.
116
+ * Provides a consistent API for accessing query parameters regardless of the framework.
117
+ *
118
+ * @remarks
119
+ * This class abstracts the differences between:
120
+ * - URLSearchParams (Fetch API, Next.js)
121
+ * - Query object (Express, Fastify)
122
+ * - Query string (raw URL parsing)
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * // From URLSearchParams
127
+ * const params = new CoreSearchParams(new URLSearchParams("page=1&limit=10"));
128
+ *
129
+ * // From object (Express style)
130
+ * const params = new CoreSearchParams({ page: "1", limit: "10" });
131
+ *
132
+ * // From query string
133
+ * const params = new CoreSearchParams("page=1&limit=10");
134
+ *
135
+ * // Usage
136
+ * params.get("page"); // "1"
137
+ * params.getNumber("page"); // 1
138
+ * params.getAll("tags"); // ["a", "b"]
139
+ * params.toObject(); // { page: "1", limit: "10" }
140
+ * ```
141
+ */
142
+ export declare class CoreSearchParams {
143
+ private readonly params;
144
+ /**
145
+ * Creates a new CoreSearchParams instance.
146
+ *
147
+ * @param source - The source of query parameters:
148
+ * - URLSearchParams: Used directly
149
+ * - Record<string, string | string[] | undefined>: Object with query values
150
+ * - string: Query string (with or without leading "?")
151
+ * - undefined/null: Empty params
152
+ */
153
+ constructor(source?: URLSearchParams | Record<string, string | string[] | undefined> | string | null);
154
+ /**
155
+ * Gets the first value for a parameter.
156
+ * @param name - Parameter name
157
+ * @returns The value or null if not found
158
+ */
159
+ get(name: string): string | null;
160
+ /**
161
+ * Gets all values for a parameter.
162
+ * @param name - Parameter name
163
+ * @returns Array of values (empty if not found)
164
+ */
165
+ getAll(name: string): string[];
166
+ /**
167
+ * Checks if a parameter exists.
168
+ * @param name - Parameter name
169
+ * @returns true if the parameter exists
170
+ */
171
+ has(name: string): boolean;
172
+ /**
173
+ * Gets a parameter as a number.
174
+ * @param name - Parameter name
175
+ * @param defaultValue - Default value if not found or not a valid number
176
+ * @returns The parsed number or default value
177
+ */
178
+ getNumber(name: string, defaultValue?: number): number | undefined;
179
+ /**
180
+ * Gets a parameter as a boolean.
181
+ * Treats "true", "1", "yes" as true; "false", "0", "no" as false.
182
+ * @param name - Parameter name
183
+ * @param defaultValue - Default value if not found
184
+ * @returns The parsed boolean or default value
185
+ */
186
+ getBoolean(name: string, defaultValue?: boolean): boolean | undefined;
187
+ /**
188
+ * Returns an iterator of all parameter names.
189
+ */
190
+ keys(): IterableIterator<string>;
191
+ /**
192
+ * Returns an iterator of all parameter values.
193
+ */
194
+ values(): IterableIterator<string>;
195
+ /**
196
+ * Returns an iterator of all [name, value] pairs.
197
+ */
198
+ entries(): IterableIterator<[string, string]>;
199
+ /**
200
+ * Executes a callback for each parameter.
201
+ */
202
+ forEach(callback: (value: string, key: string, parent: URLSearchParams) => void): void;
203
+ /**
204
+ * Converts to a plain object (first value only for each key).
205
+ * @returns Object with string values
206
+ */
207
+ toObject(): Record<string, string>;
208
+ /**
209
+ * Converts to a plain object (all values as arrays).
210
+ * @returns Object with string array values
211
+ */
212
+ toObjectAll(): Record<string, string[]>;
213
+ /**
214
+ * Returns the underlying URLSearchParams.
215
+ */
216
+ toURLSearchParams(): URLSearchParams;
217
+ /**
218
+ * Converts to query string (without leading "?").
219
+ */
220
+ toString(): string;
221
+ /**
222
+ * Returns the number of parameters (counting duplicates).
223
+ */
224
+ get size(): number;
225
+ /**
226
+ * Makes the class iterable.
227
+ */
228
+ [Symbol.iterator](): IterableIterator<[string, string]>;
229
+ }
15
230
  /**
16
231
  * Container for route-level metadata, guards, filters, interceptors, and pipes.
17
232
  * Created from decorator results and attached to each route.
@@ -48,12 +263,12 @@ export declare class Reflect {
48
263
  * Returns the set of exception filter classes attached to this route.
49
264
  * @returns Set of filter class constructors
50
265
  */
51
- getFilters(): Set<Filter<unknown>>;
266
+ getFilters(): Set<Filter>;
52
267
  /**
53
268
  * Returns the set of interceptor classes attached to this route.
54
269
  * @returns Set of interceptor class constructors
55
270
  */
56
- getInterceptors(): Set<Interceptor<unknown>>;
271
+ getInterceptors(): Set<Interceptor>;
57
272
  /**
58
273
  * Returns the set of pipe classes attached to this route.
59
274
  * @returns Set of pipe class constructors
@@ -83,8 +298,8 @@ export declare class Reflect {
83
298
  * Created for each request and available throughout the request lifecycle.
84
299
  */
85
300
  export interface RequestContext {
86
- /** The incoming Next.js request */
87
- req: NextRequest;
301
+ /** The incoming HTTP request (CoreRequest-compatible) */
302
+ req: CoreRequest;
88
303
  /** The response builder */
89
304
  res: ServerResponse;
90
305
  /** HTTP method of the request */
@@ -98,7 +313,7 @@ export interface RequestContext {
98
313
  /** Route metadata and decorators */
99
314
  reflect: Reflect;
100
315
  /** The feature that matched this request */
101
- feature: Feature;
316
+ feature: FeatureContext;
102
317
  }
103
318
  /**
104
319
  * Request-scoped execution context using AsyncLocalStorage.
@@ -176,25 +391,31 @@ export declare class ExecuteContext {
176
391
  /**
177
392
  * Retrieves a global inject by name with lazy initialization.
178
393
  * If the inject hasn't been initialized yet, calls the factory to create it.
394
+ * Returns the result of switch() if available, otherwise the raw instance.
179
395
  *
180
- * @template T - Expected type of the inject (must extend ApplicationInject)
396
+ * @template T - Expected return type (from switch() or the inject itself)
181
397
  * @param name - The name of the inject to retrieve
182
- * @returns Promise resolving to the inject instance or undefined if not found
398
+ * @returns Promise resolving to the switched value or undefined if not found
183
399
  *
184
400
  * @example
185
401
  * ```ts
186
- * const db = await context.getInject<DatabaseConnection>("db");
402
+ * // If inject implements switch(), returns the switched value
403
+ * const db = await context.getInject<DatabaseClient>("db");
404
+ * const users = await db.query("SELECT * FROM users");
405
+ *
406
+ * // If inject doesn't implement switch(), returns the inject instance
187
407
  * const config = await context.getInject<Config>("config");
188
408
  * ```
189
409
  */
190
- getInject<T extends ApplicationInject = ApplicationInject>(name: string): Promise<T | undefined>;
410
+ getInject<T = unknown>(name: string): Promise<T | undefined>;
191
411
  /**
192
412
  * Retrieves a global inject synchronously (only if already initialized).
193
413
  * Returns undefined if the inject hasn't been initialized yet.
414
+ * Returns the result of switch() if available, otherwise the raw instance.
194
415
  *
195
- * @template T - Expected type of the inject (must extend ApplicationInject)
416
+ * @template T - Expected return type (from switch() or the inject itself)
196
417
  * @param name - The name of the inject to retrieve
197
- * @returns The inject instance or undefined if not found/not initialized
418
+ * @returns The switched value or undefined if not found/not initialized
198
419
  *
199
420
  * @example
200
421
  * ```ts
@@ -202,7 +423,7 @@ export declare class ExecuteContext {
202
423
  * const config = context.getInjectSync<Config>("config");
203
424
  * ```
204
425
  */
205
- getInjectSync<T extends ApplicationInject = ApplicationInject>(name: string): T | undefined;
426
+ getInjectSync<T = unknown>(name: string): T | undefined;
206
427
  /**
207
428
  * Checks if a global inject factory exists by name.
208
429
  *
@@ -285,8 +506,8 @@ export declare class ExecuteContext {
285
506
  * ```
286
507
  */
287
508
  switchHttp(): {
288
- /** Returns the Next.js request object */
289
- getRequest: () => NextRequest;
509
+ /** Returns the CoreRequest object, optionally cast to a specific type */
510
+ getRequest: <T extends CoreRequest = CoreRequest>() => T;
290
511
  /** Returns the ServerResponse builder */
291
512
  getResponse: () => ServerResponse;
292
513
  /** Returns the HTTP method */
@@ -297,16 +518,16 @@ export declare class ExecuteContext {
297
518
  params: () => Record<string, string>;
298
519
  /** Returns wildcard segments */
299
520
  wildcards: () => string[];
300
- /** Returns query parameters as object */
301
- query: () => {
302
- [k: string]: string;
303
- };
521
+ /** Returns CoreSearchParams instance for query parameter access */
522
+ searchParams: () => CoreSearchParams;
523
+ /** Returns query parameters as plain object (first value only) */
524
+ query: () => Record<string, string>;
304
525
  /** Returns headers as object */
305
526
  headers: () => {
306
527
  [k: string]: string;
307
528
  };
308
529
  /** Returns the raw body ReadableStream */
309
- body: () => ReadableStream<Uint8Array<ArrayBuffer>> | null;
530
+ body: () => ReadableStream<Uint8Array<ArrayBufferLike>> | null;
310
531
  /** Parses and returns the JSON body */
311
532
  json: <T = unknown>() => Promise<T>;
312
533
  /** Returns the body as text */
@@ -339,14 +560,15 @@ export declare class ExecuteContext {
339
560
  *
340
561
  * @returns The Feature instance or undefined if no context
341
562
  */
342
- getFeature(): Feature | undefined;
563
+ getFeature<Feature extends FeatureContext>(): Feature | undefined;
343
564
  /**
344
565
  * Retrieves a feature-local inject by name with lazy initialization.
345
566
  * Falls back to global injects if not found in the feature.
567
+ * Returns the result of switch() if available, otherwise the raw instance.
346
568
  *
347
- * @template T - Expected type of the inject (must extend FeatureInject)
569
+ * @template T - Expected return type (from switch() or the inject itself)
348
570
  * @param name - The name of the inject to retrieve
349
- * @returns Promise resolving to the inject instance or undefined if not found
571
+ * @returns Promise resolving to the switched value or undefined if not found
350
572
  *
351
573
  * @example
352
574
  * ```ts
@@ -354,14 +576,15 @@ export declare class ExecuteContext {
354
576
  * const repo = await context.getLocalInject<ProductRepository>("productRepo");
355
577
  * ```
356
578
  */
357
- getLocalInject<T extends FeatureInject>(name: string): Promise<T | undefined>;
579
+ getLocalInject<T = unknown>(name: string): Promise<T | undefined>;
358
580
  /**
359
581
  * Retrieves a feature-local inject synchronously (only if already initialized).
360
582
  * Falls back to global injects if not found in the feature.
583
+ * Returns the result of switch() if available, otherwise the raw instance.
361
584
  *
362
- * @template T - Expected type of the inject (must extend FeatureInject)
585
+ * @template T - Expected return type (from switch() or the inject itself)
363
586
  * @param name - The name of the inject to retrieve
364
- * @returns The inject instance or undefined if not found/not initialized
587
+ * @returns The switched value or undefined if not found/not initialized
365
588
  *
366
589
  * @example
367
590
  * ```ts
@@ -369,35 +592,52 @@ export declare class ExecuteContext {
369
592
  * const repo = context.getLocalInjectSync<ProductRepository>("productRepo");
370
593
  * ```
371
594
  */
372
- getLocalInjectSync<T extends FeatureInject>(name: string): T | undefined;
373
- }
374
- /**
375
- * Interface for guard classes that determine if a request should proceed.
376
- * Guards are used for authorization, authentication, and access control.
377
- *
378
- * @example
379
- * ```ts
380
- * class AuthGuard implements CanActivate {
381
- * canActivate(context: ExecuteContext): boolean {
382
- * const token = context.switchHttp().headers()["authorization"];
383
- * return !!token && isValidToken(token);
384
- * }
385
- * }
386
- * ```
387
- */
388
- export interface CanActivate {
595
+ getLocalInjectSync<T = unknown>(name: string): T | undefined;
596
+ /**
597
+ * Retrieves an inject by name and calls its switch() method.
598
+ * Searches in feature injects first (priority), then falls back to global injects.
599
+ *
600
+ * @template T - Expected return type of the switch() method
601
+ * @param name - The name of the inject to switch to
602
+ * @returns Promise resolving to the result of the inject's switch() method
603
+ * @throws {Error} If the inject is not found or doesn't have a switch() method
604
+ *
605
+ * @example
606
+ * ```ts
607
+ * // In a controller or service
608
+ * const db = await this.context.switch<DatabaseClient>("db");
609
+ * const users = await db.query("SELECT * FROM users");
610
+ *
611
+ * // The inject must implement switch():
612
+ * class Connection implements ApplicationInject {
613
+ * switch<T = DatabaseClient>(): T {
614
+ * return this.client as T;
615
+ * }
616
+ * }
617
+ * ```
618
+ */
619
+ switch<T = unknown>(name: string): Promise<T>;
389
620
  /**
390
- * Determines if the request should be allowed to proceed.
621
+ * Retrieves an inject by name and calls its switch() method (synchronous version).
622
+ * Only works if the inject has already been initialized.
623
+ * Searches in feature injects first (priority), then falls back to global injects.
624
+ *
625
+ * @template T - Expected return type of the switch() method
626
+ * @param name - The name of the inject to switch to
627
+ * @returns The result of the inject's switch() method, or undefined if not initialized
628
+ * @throws {Error} If the inject exists but doesn't have a switch() method
391
629
  *
392
- * @param context - The execution context for the current request
393
- * @returns true to allow, false to deny (results in 403 Forbidden)
630
+ * @example
631
+ * ```ts
632
+ * // Only use when you're sure the inject is already initialized
633
+ * const db = this.context.switchSync<DatabaseClient>("db");
634
+ * if (db) {
635
+ * const users = await db.query("SELECT * FROM users");
636
+ * }
637
+ * ```
394
638
  */
395
- canActivate(context: ExecuteContext): boolean | Promise<boolean>;
639
+ switchSync<T = unknown>(name: string): T | undefined;
396
640
  }
397
- /**
398
- * Constructor type for guard classes.
399
- */
400
- export type Guard = new (...args: unknown[]) => CanActivate;
401
641
  /**
402
642
  * Function type for route action handlers (inline handlers).
403
643
  *
@@ -437,85 +677,3 @@ export type RouteHandler<Data = unknown> = (context: ExecuteContext) => Data;
437
677
  * ```
438
678
  */
439
679
  export type RouteMiddleware = (context: ExecuteContext, next: RouteNextHandler) => void | Promise<void>;
440
- /**
441
- * Interface for exception filter classes that handle errors.
442
- * Filters can transform exceptions into custom responses.
443
- *
444
- * @template Response - The type of response the filter returns
445
- *
446
- * @example
447
- * ```ts
448
- * class HttpExceptionFilter implements ExceptionFilter<Response> {
449
- * catch(exception: unknown, context: ExecuteContext): Response {
450
- * if (exception instanceof HttpError) {
451
- * return new Response(JSON.stringify({ error: exception.message }), {
452
- * status: exception.statusCode,
453
- * });
454
- * }
455
- * throw exception; // Re-throw if not handled
456
- * }
457
- * }
458
- * ```
459
- */
460
- export interface ExceptionFilter<Response = unknown> {
461
- /**
462
- * Handles an exception and optionally returns a response.
463
- *
464
- * @param exception - The thrown exception
465
- * @param context - The execution context for the current request
466
- * @returns A response to send, or re-throw to pass to next filter
467
- */
468
- catch(exception: unknown, context: ExecuteContext): Response | Promise<Response>;
469
- }
470
- /**
471
- * Constructor type for exception filter classes.
472
- *
473
- * @template Response - The type of response the filter returns
474
- */
475
- export type Filter<Response = unknown> = new (...args: unknown[]) => ExceptionFilter<Response>;
476
- /**
477
- * Interface for interceptor classes that wrap handler execution.
478
- * Interceptors can transform requests/responses, add caching, logging, etc.
479
- *
480
- * @template T - The type of the handler result
481
- *
482
- * @example
483
- * ```ts
484
- * class LoggingInterceptor implements InterceptorHandler {
485
- * async intercept(context: ExecuteContext, next: CallHandler): Promise<unknown> {
486
- * const start = Date.now();
487
- * const result = await next();
488
- * console.log(`Request took ${Date.now() - start}ms`);
489
- * return result;
490
- * }
491
- * }
492
- *
493
- * class CacheInterceptor implements InterceptorHandler {
494
- * async intercept(context: ExecuteContext, next: CallHandler): Promise<unknown> {
495
- * const key = getCacheKey(context);
496
- * const cached = await cache.get(key);
497
- * if (cached) return cached;
498
- *
499
- * const result = await next();
500
- * await cache.set(key, result);
501
- * return result;
502
- * }
503
- * }
504
- * ```
505
- */
506
- export interface InterceptorHandler<T = unknown> {
507
- /**
508
- * Intercepts the handler execution.
509
- *
510
- * @param context - The execution context for the current request
511
- * @param next - Function to call the next interceptor or handler
512
- * @returns The (possibly transformed) result
513
- */
514
- intercept(context: ExecuteContext, next: CallHandler<T>): Promise<T>;
515
- }
516
- /**
517
- * Constructor type for interceptor classes.
518
- *
519
- * @template T - The type of the handler result
520
- */
521
- export type Interceptor<T = unknown> = new (...args: unknown[]) => InterceptorHandler<T>;
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,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}};
1
+ "use strict";var t=require("async_hooks");class e{constructor(t){if(t)if(t instanceof URLSearchParams)this.params=t;else if("string"==typeof t){const e=t.startsWith("?")?t.slice(1):t;this.params=new URLSearchParams(e)}else{this.params=new URLSearchParams;for(const[e,r]of Object.entries(t))if(void 0!==r)if(Array.isArray(r))for(const t of r)this.params.append(e,t);else this.params.set(e,r)}else this.params=new URLSearchParams}get(t){return this.params.get(t)}getAll(t){return this.params.getAll(t)}has(t){return this.params.has(t)}getNumber(t,e){const r=this.params.get(t);if(null===r)return e;const n=Number(r);return isNaN(n)?e:n}getBoolean(t,e){const r=this.params.get(t);if(null===r)return e;const n=r.toLowerCase();return!!["true","1","yes"].includes(n)||!["false","0","no"].includes(n)&&e}keys(){return this.params.keys()}values(){return this.params.values()}entries(){return this.params.entries()}forEach(t){this.params.forEach(t)}toObject(){const t={};for(const e of this.params.keys())t[e]=this.params.get(e);return t}toObjectAll(){const t={};for(const e of this.params.keys())t[e]||(t[e]=this.params.getAll(e));return t}toURLSearchParams(){return this.params}toString(){return this.params.toString()}get size(){let t=0;return this.params.forEach(()=>t++),t}[Symbol.iterator](){return this.params.entries()}}class r{constructor(){this.storage=new t.AsyncLocalStorage,this._injections=new Map,this._registry=null}static get instance(){return r._instance||(r._instance=new r),r._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"function"==typeof e.instance.switch?e.instance.switch():e.instance}}getInjectSync(t){const e=this._injections.get(t);if(e?.instance)return"function"==typeof e.instance.switch?e.instance.switch():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();let r=null;const n=()=>(r||(r=(()=>{if(t.req.nextUrl){const r=(t.req.nextUrl,URL,t.req.nextUrl.searchParams);return new e(r)}if(t.req.url instanceof URL)return new e(t.req.url.searchParams);if("string"==typeof t.req.url&&t.req.url.includes("?")){const r=t.req.url.split("?")[1];return new e(r)}return t.req.query?new e(t.req.query):new e})()),r);return{getRequest:()=>t.req,getResponse:()=>t.res,getMethod:()=>t.method,getPath:()=>t.path,params:()=>t.params,wildcards:()=>t.wildcards,searchParams:n,query:()=>n().toObject(),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;if(e?.hasInject(t)){const r=await e.getInject(t);if(!r)return;return"function"==typeof r.switch?r.switch():r}return this.getInject(t)}getLocalInjectSync(t){const e=this.getContext()?.feature;if(e?.hasInject(t)){const r=e.getInjectSync(t);if(!r)return;return"function"==typeof r.switch?r.switch():r}return this.getInjectSync(t)}async switch(t){const e=this.getContext()?.feature;if(e?.hasInject(t)){return await e.getInject(t)}const r=this._injections.get(t);if(!r)throw new Error(`[ExecuteContext] Inject '${t}' not found.`);if(!r.instance){if(!this._registry)throw new Error(`[ExecuteContext] Registry not set. Cannot initialize inject '${t}'.`);r.instance=await r.factory(this._registry),"function"==typeof r.instance.onInit&&await r.instance.onInit()}if("function"!=typeof r.instance.switch)throw new Error(`[ExecuteContext] Inject '${t}' does not implement switch() method.`);return r.instance.switch()}switchSync(t){const e=this.getContext()?.feature;let r;if(r=e?.hasInject(t)?e.getInjectSync(t):this.getInjectSync(t),r){if("function"!=typeof r.switch)throw new Error(`[ExecuteContext] Inject '${t}' does not implement switch() method.`);return r.switch()}}}r._instance=null,exports.CoreSearchParams=e,exports.ExecuteContext=r,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,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};
1
+ import{AsyncLocalStorage as t}from"async_hooks";class e{constructor(t){if(t)if(t instanceof URLSearchParams)this.params=t;else if("string"==typeof t){const e=t.startsWith("?")?t.slice(1):t;this.params=new URLSearchParams(e)}else{this.params=new URLSearchParams;for(const[e,r]of Object.entries(t))if(void 0!==r)if(Array.isArray(r))for(const t of r)this.params.append(e,t);else this.params.set(e,r)}else this.params=new URLSearchParams}get(t){return this.params.get(t)}getAll(t){return this.params.getAll(t)}has(t){return this.params.has(t)}getNumber(t,e){const r=this.params.get(t);if(null===r)return e;const n=Number(r);return isNaN(n)?e:n}getBoolean(t,e){const r=this.params.get(t);if(null===r)return e;const n=r.toLowerCase();return!!["true","1","yes"].includes(n)||!["false","0","no"].includes(n)&&e}keys(){return this.params.keys()}values(){return this.params.values()}entries(){return this.params.entries()}forEach(t){this.params.forEach(t)}toObject(){const t={};for(const e of this.params.keys())t[e]=this.params.get(e);return t}toObjectAll(){const t={};for(const e of this.params.keys())t[e]||(t[e]=this.params.getAll(e));return t}toURLSearchParams(){return this.params}toString(){return this.params.toString()}get size(){let t=0;return this.params.forEach(()=>t++),t}[Symbol.iterator](){return this.params.entries()}}class r{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}}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"function"==typeof e.instance.switch?e.instance.switch():e.instance}}getInjectSync(t){const e=this._injections.get(t);if(e?.instance)return"function"==typeof e.instance.switch?e.instance.switch():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();let r=null;const n=()=>(r||(r=(()=>{if(t.req.nextUrl){const r=(t.req.nextUrl,URL,t.req.nextUrl.searchParams);return new e(r)}if(t.req.url instanceof URL)return new e(t.req.url.searchParams);if("string"==typeof t.req.url&&t.req.url.includes("?")){const r=t.req.url.split("?")[1];return new e(r)}return t.req.query?new e(t.req.query):new e})()),r);return{getRequest:()=>t.req,getResponse:()=>t.res,getMethod:()=>t.method,getPath:()=>t.path,params:()=>t.params,wildcards:()=>t.wildcards,searchParams:n,query:()=>n().toObject(),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;if(e?.hasInject(t)){const r=await e.getInject(t);if(!r)return;return"function"==typeof r.switch?r.switch():r}return this.getInject(t)}getLocalInjectSync(t){const e=this.getContext()?.feature;if(e?.hasInject(t)){const r=e.getInjectSync(t);if(!r)return;return"function"==typeof r.switch?r.switch():r}return this.getInjectSync(t)}async switch(t){const e=this.getContext()?.feature;if(e?.hasInject(t)){return await e.getInject(t)}const r=this._injections.get(t);if(!r)throw new Error(`[ExecuteContext] Inject '${t}' not found.`);if(!r.instance){if(!this._registry)throw new Error(`[ExecuteContext] Registry not set. Cannot initialize inject '${t}'.`);r.instance=await r.factory(this._registry),"function"==typeof r.instance.onInit&&await r.instance.onInit()}if("function"!=typeof r.instance.switch)throw new Error(`[ExecuteContext] Inject '${t}' does not implement switch() method.`);return r.instance.switch()}switchSync(t){const e=this.getContext()?.feature;let r;if(r=e?.hasInject(t)?e.getInjectSync(t):this.getInjectSync(t),r){if("function"!=typeof r.switch)throw new Error(`[ExecuteContext] Inject '${t}' does not implement switch() method.`);return r.switch()}}}n._instance=null;export{e as CoreSearchParams,n as ExecuteContext,r as Reflect};