@mxweb/core 1.0.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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/application.d.ts +402 -0
- package/dist/application.js +1 -0
- package/dist/application.mjs +1 -0
- package/dist/common.d.ts +323 -0
- package/dist/common.js +1 -0
- package/dist/common.mjs +1 -0
- package/dist/config.d.ts +258 -0
- package/dist/config.js +1 -0
- package/dist/config.mjs +1 -0
- package/dist/context.d.ts +48 -0
- package/dist/context.js +1 -0
- package/dist/context.mjs +1 -0
- package/dist/controller.d.ts +238 -0
- package/dist/controller.js +1 -0
- package/dist/controller.mjs +1 -0
- package/dist/decorator.d.ts +349 -0
- package/dist/decorator.js +1 -0
- package/dist/decorator.mjs +1 -0
- package/dist/error.d.ts +301 -0
- package/dist/error.js +1 -0
- package/dist/error.mjs +1 -0
- package/dist/execute.d.ts +469 -0
- package/dist/execute.js +1 -0
- package/dist/execute.mjs +1 -0
- package/dist/feature.d.ts +239 -0
- package/dist/feature.js +1 -0
- package/dist/feature.mjs +1 -0
- package/dist/hooks.d.ts +251 -0
- package/dist/hooks.js +1 -0
- package/dist/hooks.mjs +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/logger.d.ts +360 -0
- package/dist/logger.js +1 -0
- package/dist/logger.mjs +1 -0
- package/dist/response.d.ts +665 -0
- package/dist/response.js +1 -0
- package/dist/response.mjs +1 -0
- package/dist/route.d.ts +298 -0
- package/dist/route.js +1 -0
- package/dist/route.mjs +1 -0
- package/dist/router.d.ts +205 -0
- package/dist/router.js +1 -0
- package/dist/router.mjs +1 -0
- package/dist/service.d.ts +261 -0
- package/dist/service.js +1 -0
- package/dist/service.mjs +1 -0
- package/package.json +168 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Execution context and request-scoped state management.
|
|
3
|
+
*
|
|
4
|
+
* This module provides:
|
|
5
|
+
* - {@link ExecuteContext}: Request-scoped context using AsyncLocalStorage
|
|
6
|
+
* - {@link Reflect}: Route metadata and decorator access
|
|
7
|
+
* - Guard, Filter, Interceptor interfaces for request pipeline
|
|
8
|
+
*
|
|
9
|
+
* @module execute
|
|
10
|
+
*/
|
|
11
|
+
import { NextRequest } from "next/server";
|
|
12
|
+
import { ServerResponse } from "./response";
|
|
13
|
+
import { Feature } from "./feature";
|
|
14
|
+
import { ApplicationInject, CallHandler, FeatureInject, Pipe, RouteMethod, RouteNextHandler } from "./common";
|
|
15
|
+
/**
|
|
16
|
+
* Container for route-level metadata, guards, filters, interceptors, and pipes.
|
|
17
|
+
* Created from decorator results and attached to each route.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* // Access in a guard or interceptor
|
|
22
|
+
* const roles = context.getReflect()?.getMetadata<string[]>("roles");
|
|
23
|
+
* const guards = context.getReflect()?.getGuards();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class Reflect {
|
|
27
|
+
private readonly metadata;
|
|
28
|
+
private readonly guards;
|
|
29
|
+
private readonly filters;
|
|
30
|
+
private readonly interceptors;
|
|
31
|
+
private readonly pipes;
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new Reflect instance with the specified metadata and decorators.
|
|
34
|
+
*
|
|
35
|
+
* @param metadata - Map of metadata key-value pairs from SetMetadata
|
|
36
|
+
* @param guards - Set of guard classes from UseGuards
|
|
37
|
+
* @param filters - Set of filter classes from UseFilters
|
|
38
|
+
* @param interceptors - Set of interceptor classes from UseInterceptors
|
|
39
|
+
* @param pipes - Set of pipe classes from UsePipes
|
|
40
|
+
*/
|
|
41
|
+
constructor(metadata: Map<string, unknown>, guards: Set<Guard>, filters: Set<Filter>, interceptors: Set<Interceptor>, pipes: Set<Pipe>);
|
|
42
|
+
/**
|
|
43
|
+
* Returns the set of guard classes attached to this route.
|
|
44
|
+
* @returns Set of guard class constructors
|
|
45
|
+
*/
|
|
46
|
+
getGuards(): Set<Guard>;
|
|
47
|
+
/**
|
|
48
|
+
* Returns the set of exception filter classes attached to this route.
|
|
49
|
+
* @returns Set of filter class constructors
|
|
50
|
+
*/
|
|
51
|
+
getFilters(): Set<Filter<unknown>>;
|
|
52
|
+
/**
|
|
53
|
+
* Returns the set of interceptor classes attached to this route.
|
|
54
|
+
* @returns Set of interceptor class constructors
|
|
55
|
+
*/
|
|
56
|
+
getInterceptors(): Set<Interceptor<unknown>>;
|
|
57
|
+
/**
|
|
58
|
+
* Returns the set of pipe classes attached to this route.
|
|
59
|
+
* @returns Set of pipe class constructors
|
|
60
|
+
*/
|
|
61
|
+
getPipes(): Set<Pipe>;
|
|
62
|
+
/**
|
|
63
|
+
* Retrieves a metadata value by key.
|
|
64
|
+
*
|
|
65
|
+
* @template T - Expected type of the metadata value
|
|
66
|
+
* @param key - The metadata key to retrieve
|
|
67
|
+
* @returns The metadata value or undefined if not found
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const roles = reflect.getMetadata<string[]>("roles");
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
getMetadata<T = unknown>(key: string): T | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Returns all metadata as a Map.
|
|
77
|
+
* @returns Map of all metadata key-value pairs
|
|
78
|
+
*/
|
|
79
|
+
getAllMetadata(): Map<string, unknown>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Context object containing all request-related data.
|
|
83
|
+
* Created for each request and available throughout the request lifecycle.
|
|
84
|
+
*/
|
|
85
|
+
export interface RequestContext {
|
|
86
|
+
/** The incoming Next.js request */
|
|
87
|
+
req: NextRequest;
|
|
88
|
+
/** The response builder */
|
|
89
|
+
res: ServerResponse;
|
|
90
|
+
/** HTTP method of the request */
|
|
91
|
+
method: RouteMethod;
|
|
92
|
+
/** The matched path (without base API path) */
|
|
93
|
+
path: string;
|
|
94
|
+
/** Route parameters extracted from the path */
|
|
95
|
+
params: Record<string, string>;
|
|
96
|
+
/** Wildcard segments from the path */
|
|
97
|
+
wildcards: string[];
|
|
98
|
+
/** Route metadata and decorators */
|
|
99
|
+
reflect: Reflect;
|
|
100
|
+
/** The feature that matched this request */
|
|
101
|
+
feature: Feature;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Request-scoped execution context using AsyncLocalStorage.
|
|
105
|
+
*
|
|
106
|
+
* This class provides access to request data and global injects from anywhere
|
|
107
|
+
* in the application without explicitly passing context through function parameters.
|
|
108
|
+
*
|
|
109
|
+
* Uses the singleton pattern - access via {@link ExecuteContext.instance}.
|
|
110
|
+
*
|
|
111
|
+
* @remarks
|
|
112
|
+
* - Uses Node.js AsyncLocalStorage to maintain request scope across async operations
|
|
113
|
+
* - Manages both request-scoped context and global application injects
|
|
114
|
+
* - Provides HTTP helpers similar to NestJS's ExecutionContext
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* // In a service (accessed via executeContext singleton)
|
|
119
|
+
* const params = this.context.switchHttp().params();
|
|
120
|
+
* const body = await this.context.switchHttp().json<CreateDto>();
|
|
121
|
+
*
|
|
122
|
+
* // Access global injects
|
|
123
|
+
* const db = this.context.getInject<Database>("db");
|
|
124
|
+
*
|
|
125
|
+
* // Access feature-local injects
|
|
126
|
+
* const repo = this.context.getLocalInject<Repository>("productRepo");
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export declare class ExecuteContext {
|
|
130
|
+
/** Singleton instance */
|
|
131
|
+
private static _instance;
|
|
132
|
+
/** AsyncLocalStorage for request-scoped context */
|
|
133
|
+
private storage;
|
|
134
|
+
/** Map of global application injects */
|
|
135
|
+
private _injections;
|
|
136
|
+
/**
|
|
137
|
+
* Private constructor to enforce singleton pattern.
|
|
138
|
+
* @private
|
|
139
|
+
*/
|
|
140
|
+
private constructor();
|
|
141
|
+
/**
|
|
142
|
+
* Returns the singleton ExecuteContext instance.
|
|
143
|
+
* Creates the instance on first access.
|
|
144
|
+
*
|
|
145
|
+
* @returns The singleton ExecuteContext instance
|
|
146
|
+
*/
|
|
147
|
+
static get instance(): ExecuteContext;
|
|
148
|
+
/**
|
|
149
|
+
* Returns the map of global application injects.
|
|
150
|
+
* Injects are set by Application.loadInjects() during initialization.
|
|
151
|
+
*
|
|
152
|
+
* @returns Map of inject name to instance
|
|
153
|
+
*/
|
|
154
|
+
get injections(): Map<string, ApplicationInject>;
|
|
155
|
+
/**
|
|
156
|
+
* Registers a global inject by name.
|
|
157
|
+
*
|
|
158
|
+
* @param name - The name to register the inject under
|
|
159
|
+
* @param instance - The inject instance
|
|
160
|
+
*/
|
|
161
|
+
setInject(name: string, instance: ApplicationInject): void;
|
|
162
|
+
/**
|
|
163
|
+
* Retrieves a global inject by name.
|
|
164
|
+
*
|
|
165
|
+
* @template T - Expected type of the inject (must extend ApplicationInject)
|
|
166
|
+
* @param name - The name of the inject to retrieve
|
|
167
|
+
* @returns The inject instance or undefined if not found
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* const db = context.getInject<DatabaseConnection>("db");
|
|
172
|
+
* const config = context.getInject<Config>("config");
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
getInject<T extends ApplicationInject = ApplicationInject>(name: string): T | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* Checks if a global inject exists by name.
|
|
178
|
+
*
|
|
179
|
+
* @param name - The inject name to check
|
|
180
|
+
* @returns true if the inject exists, false otherwise
|
|
181
|
+
*/
|
|
182
|
+
hasInject(name: string): boolean;
|
|
183
|
+
/**
|
|
184
|
+
* Clears all global injects.
|
|
185
|
+
* Primarily used for testing to ensure clean state between tests.
|
|
186
|
+
*/
|
|
187
|
+
clearInjections(): void;
|
|
188
|
+
/**
|
|
189
|
+
* Runs a callback within the scope of a request context.
|
|
190
|
+
* All code executed within the callback can access the context
|
|
191
|
+
* via getContext() or switchHttp().
|
|
192
|
+
*
|
|
193
|
+
* @template T - Return type of the callback
|
|
194
|
+
* @param context - The request context to make available
|
|
195
|
+
* @param callback - The callback to execute within the context scope
|
|
196
|
+
* @returns The result of the callback (sync or async)
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* await executeContext.run(requestContext, async () => {
|
|
201
|
+
* // context is available here
|
|
202
|
+
* const ctx = executeContext.getContext();
|
|
203
|
+
* return await handler();
|
|
204
|
+
* });
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
run<T>(context: RequestContext, callback: () => T | Promise<T>): T | Promise<T>;
|
|
208
|
+
/**
|
|
209
|
+
* Retrieves the current request context.
|
|
210
|
+
* Returns undefined if called outside of a request scope.
|
|
211
|
+
*
|
|
212
|
+
* @returns The current RequestContext or undefined
|
|
213
|
+
*/
|
|
214
|
+
getContext(): RequestContext | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* Retrieves the current request context or throws an error.
|
|
217
|
+
* Use this when you expect to always be within a request scope.
|
|
218
|
+
*
|
|
219
|
+
* @returns The current RequestContext
|
|
220
|
+
* @throws {Error} If called outside of a request scope
|
|
221
|
+
*/
|
|
222
|
+
getContextOrThrow(): RequestContext;
|
|
223
|
+
/**
|
|
224
|
+
* Returns an object with helper methods for accessing HTTP request data.
|
|
225
|
+
* Similar to NestJS's switchToHttp() but as a function factory.
|
|
226
|
+
*
|
|
227
|
+
* @returns Object with HTTP helper methods
|
|
228
|
+
* @throws {Error} If called outside of a request scope
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```ts
|
|
232
|
+
* const http = context.switchHttp();
|
|
233
|
+
*
|
|
234
|
+
* // Access request/response
|
|
235
|
+
* const request = http.getRequest();
|
|
236
|
+
* const response = http.getResponse();
|
|
237
|
+
*
|
|
238
|
+
* // Access route info
|
|
239
|
+
* const method = http.getMethod();
|
|
240
|
+
* const path = http.getPath();
|
|
241
|
+
* const params = http.params();
|
|
242
|
+
*
|
|
243
|
+
* // Access request data
|
|
244
|
+
* const query = http.query();
|
|
245
|
+
* const headers = http.headers();
|
|
246
|
+
* const body = await http.json<MyDto>();
|
|
247
|
+
* const formData = await http.formData();
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
switchHttp(): {
|
|
251
|
+
/** Returns the Next.js request object */
|
|
252
|
+
getRequest: () => NextRequest;
|
|
253
|
+
/** Returns the ServerResponse builder */
|
|
254
|
+
getResponse: () => ServerResponse;
|
|
255
|
+
/** Returns the HTTP method */
|
|
256
|
+
getMethod: () => RouteMethod;
|
|
257
|
+
/** Returns the matched path */
|
|
258
|
+
getPath: () => string;
|
|
259
|
+
/** Returns route parameters */
|
|
260
|
+
params: () => Record<string, string>;
|
|
261
|
+
/** Returns wildcard segments */
|
|
262
|
+
wildcards: () => string[];
|
|
263
|
+
/** Returns query parameters as object */
|
|
264
|
+
query: () => {
|
|
265
|
+
[k: string]: string;
|
|
266
|
+
};
|
|
267
|
+
/** Returns headers as object */
|
|
268
|
+
headers: () => {
|
|
269
|
+
[k: string]: string;
|
|
270
|
+
};
|
|
271
|
+
/** Returns the raw body ReadableStream */
|
|
272
|
+
body: () => ReadableStream<Uint8Array<ArrayBuffer>> | null;
|
|
273
|
+
/** Parses and returns the JSON body */
|
|
274
|
+
json: <T = unknown>() => Promise<T>;
|
|
275
|
+
/** Returns the body as text */
|
|
276
|
+
text: () => Promise<string>;
|
|
277
|
+
/** Parses and returns FormData */
|
|
278
|
+
formData: () => Promise<FormData>;
|
|
279
|
+
/** Returns the body as Blob */
|
|
280
|
+
blob: () => Promise<Blob>;
|
|
281
|
+
/** Returns the body as ArrayBuffer */
|
|
282
|
+
arrayBuffer: () => Promise<ArrayBuffer>;
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* Returns the Reflect instance for the current route.
|
|
286
|
+
* Contains metadata and decorator information.
|
|
287
|
+
*
|
|
288
|
+
* @returns The Reflect instance or undefined if no context
|
|
289
|
+
*/
|
|
290
|
+
getReflect(): Reflect | undefined;
|
|
291
|
+
/**
|
|
292
|
+
* Retrieves route metadata by key.
|
|
293
|
+
* Shorthand for getReflect()?.getMetadata().
|
|
294
|
+
*
|
|
295
|
+
* @template T - Expected type of the metadata value
|
|
296
|
+
* @param key - The metadata key to retrieve
|
|
297
|
+
* @returns The metadata value or undefined
|
|
298
|
+
*/
|
|
299
|
+
getMetadata<T>(key: string): T | undefined;
|
|
300
|
+
/**
|
|
301
|
+
* Returns the Feature that matched the current request.
|
|
302
|
+
*
|
|
303
|
+
* @returns The Feature instance or undefined if no context
|
|
304
|
+
*/
|
|
305
|
+
getFeature(): Feature | undefined;
|
|
306
|
+
/**
|
|
307
|
+
* Retrieves a feature-local inject by name.
|
|
308
|
+
* Falls back to global injects if not found in the feature.
|
|
309
|
+
*
|
|
310
|
+
* @template T - Expected type of the inject (must extend FeatureInject)
|
|
311
|
+
* @param name - The name of the inject to retrieve
|
|
312
|
+
* @returns The inject instance or undefined if not found
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* // First checks feature injects, then global injects
|
|
317
|
+
* const repo = context.getLocalInject<ProductRepository>("productRepo");
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
getLocalInject<T extends FeatureInject>(name: string): T | undefined;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Interface for guard classes that determine if a request should proceed.
|
|
324
|
+
* Guards are used for authorization, authentication, and access control.
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```ts
|
|
328
|
+
* class AuthGuard implements CanActivate {
|
|
329
|
+
* canActivate(context: ExecuteContext): boolean {
|
|
330
|
+
* const token = context.switchHttp().headers()["authorization"];
|
|
331
|
+
* return !!token && isValidToken(token);
|
|
332
|
+
* }
|
|
333
|
+
* }
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
336
|
+
export interface CanActivate {
|
|
337
|
+
/**
|
|
338
|
+
* Determines if the request should be allowed to proceed.
|
|
339
|
+
*
|
|
340
|
+
* @param context - The execution context for the current request
|
|
341
|
+
* @returns true to allow, false to deny (results in 403 Forbidden)
|
|
342
|
+
*/
|
|
343
|
+
canActivate(context: ExecuteContext): boolean | Promise<boolean>;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Constructor type for guard classes.
|
|
347
|
+
*/
|
|
348
|
+
export type Guard = new (...args: unknown[]) => CanActivate;
|
|
349
|
+
/**
|
|
350
|
+
* Function type for route action handlers (inline handlers).
|
|
351
|
+
*
|
|
352
|
+
* RouteHandler is used when defining routes with inline functions instead of
|
|
353
|
+
* controller method names. The handler receives the ExecuteContext and returns
|
|
354
|
+
* data that will be serialized as the JSON response.
|
|
355
|
+
*
|
|
356
|
+
* @template Data - The type of data returned by the handler
|
|
357
|
+
* @param context - The ExecuteContext providing access to request, response, params, etc.
|
|
358
|
+
* @returns Data to be serialized as JSON response, or a Promise resolving to data
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* // Inline handler in route definition
|
|
363
|
+
* Route.get("/health", async (context) => {
|
|
364
|
+
* return context.response.success({ status: "ok", timestamp: Date.now() });
|
|
365
|
+
* });
|
|
366
|
+
*
|
|
367
|
+
* // With typed response
|
|
368
|
+
* const handler: RouteHandler<{ message: string }> = (ctx) => {
|
|
369
|
+
* return { message: "Hello World" };
|
|
370
|
+
* };
|
|
371
|
+
* Route.get("/hello", handler);
|
|
372
|
+
* ```
|
|
373
|
+
*/
|
|
374
|
+
export type RouteHandler<Data = unknown> = (context: ExecuteContext) => Data;
|
|
375
|
+
/**
|
|
376
|
+
* Function type for route middlewares.
|
|
377
|
+
* Middlewares can perform actions before the handler and must call next() to continue.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```ts
|
|
381
|
+
* const loggingMiddleware: RouteMiddleware = (context, next) => {
|
|
382
|
+
* console.log(`Request: ${context.switchHttp().getMethod()} ${context.switchHttp().getPath()}`);
|
|
383
|
+
* next();
|
|
384
|
+
* };
|
|
385
|
+
* ```
|
|
386
|
+
*/
|
|
387
|
+
export type RouteMiddleware = (context: ExecuteContext, next: RouteNextHandler) => void | Promise<void>;
|
|
388
|
+
/**
|
|
389
|
+
* Interface for exception filter classes that handle errors.
|
|
390
|
+
* Filters can transform exceptions into custom responses.
|
|
391
|
+
*
|
|
392
|
+
* @template Response - The type of response the filter returns
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* class HttpExceptionFilter implements ExceptionFilter<Response> {
|
|
397
|
+
* catch(exception: unknown, context: ExecuteContext): Response {
|
|
398
|
+
* if (exception instanceof HttpError) {
|
|
399
|
+
* return new Response(JSON.stringify({ error: exception.message }), {
|
|
400
|
+
* status: exception.statusCode,
|
|
401
|
+
* });
|
|
402
|
+
* }
|
|
403
|
+
* throw exception; // Re-throw if not handled
|
|
404
|
+
* }
|
|
405
|
+
* }
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
export interface ExceptionFilter<Response = unknown> {
|
|
409
|
+
/**
|
|
410
|
+
* Handles an exception and optionally returns a response.
|
|
411
|
+
*
|
|
412
|
+
* @param exception - The thrown exception
|
|
413
|
+
* @param context - The execution context for the current request
|
|
414
|
+
* @returns A response to send, or re-throw to pass to next filter
|
|
415
|
+
*/
|
|
416
|
+
catch(exception: unknown, context: ExecuteContext): Response | Promise<Response>;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Constructor type for exception filter classes.
|
|
420
|
+
*
|
|
421
|
+
* @template Response - The type of response the filter returns
|
|
422
|
+
*/
|
|
423
|
+
export type Filter<Response = unknown> = new (...args: unknown[]) => ExceptionFilter<Response>;
|
|
424
|
+
/**
|
|
425
|
+
* Interface for interceptor classes that wrap handler execution.
|
|
426
|
+
* Interceptors can transform requests/responses, add caching, logging, etc.
|
|
427
|
+
*
|
|
428
|
+
* @template T - The type of the handler result
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```ts
|
|
432
|
+
* class LoggingInterceptor implements InterceptorHandler {
|
|
433
|
+
* async intercept(context: ExecuteContext, next: CallHandler): Promise<unknown> {
|
|
434
|
+
* const start = Date.now();
|
|
435
|
+
* const result = await next();
|
|
436
|
+
* console.log(`Request took ${Date.now() - start}ms`);
|
|
437
|
+
* return result;
|
|
438
|
+
* }
|
|
439
|
+
* }
|
|
440
|
+
*
|
|
441
|
+
* class CacheInterceptor implements InterceptorHandler {
|
|
442
|
+
* async intercept(context: ExecuteContext, next: CallHandler): Promise<unknown> {
|
|
443
|
+
* const key = getCacheKey(context);
|
|
444
|
+
* const cached = await cache.get(key);
|
|
445
|
+
* if (cached) return cached;
|
|
446
|
+
*
|
|
447
|
+
* const result = await next();
|
|
448
|
+
* await cache.set(key, result);
|
|
449
|
+
* return result;
|
|
450
|
+
* }
|
|
451
|
+
* }
|
|
452
|
+
* ```
|
|
453
|
+
*/
|
|
454
|
+
export interface InterceptorHandler<T = unknown> {
|
|
455
|
+
/**
|
|
456
|
+
* Intercepts the handler execution.
|
|
457
|
+
*
|
|
458
|
+
* @param context - The execution context for the current request
|
|
459
|
+
* @param next - Function to call the next interceptor or handler
|
|
460
|
+
* @returns The (possibly transformed) result
|
|
461
|
+
*/
|
|
462
|
+
intercept(context: ExecuteContext, next: CallHandler<T>): Promise<T>;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Constructor type for interceptor classes.
|
|
466
|
+
*
|
|
467
|
+
* @template T - The type of the handler result
|
|
468
|
+
*/
|
|
469
|
+
export type Interceptor<T = unknown> = new (...args: unknown[]) => InterceptorHandler<T>;
|
package/dist/execute.js
ADDED
|
@@ -0,0 +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}};
|
package/dist/execute.mjs
ADDED
|
@@ -0,0 +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};
|