@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,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Feature module for organizing application functionality.
|
|
3
|
+
*
|
|
4
|
+
* Features are the primary way to organize code in @mxweb/core.
|
|
5
|
+
* Each feature encapsulates a controller, router, and optional imports/injects.
|
|
6
|
+
* Similar to NestJS modules but optimized for Next.js App Router.
|
|
7
|
+
*
|
|
8
|
+
* @module feature
|
|
9
|
+
*/
|
|
10
|
+
import { ControllerConstructor } from "./controller";
|
|
11
|
+
import { RouteMatched, Router } from "./router";
|
|
12
|
+
import { FeatureHooks, FeatureHooksOptions } from "./hooks";
|
|
13
|
+
import { FeatureInject, RouteMethod } from "./common";
|
|
14
|
+
/**
|
|
15
|
+
* Type for feature-specific dependency injection configuration.
|
|
16
|
+
* Maps inject names to their instances.
|
|
17
|
+
*/
|
|
18
|
+
export type FeatureInjects = Record<string, FeatureInject>;
|
|
19
|
+
/**
|
|
20
|
+
* Type for feature imports configuration.
|
|
21
|
+
* Imports are executed once when the feature loads for side effects
|
|
22
|
+
* (e.g., registering entities, migrations).
|
|
23
|
+
*
|
|
24
|
+
* Can be:
|
|
25
|
+
* - A static array of imports
|
|
26
|
+
* - A function returning an array
|
|
27
|
+
* - An async function returning an array
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* // Static array
|
|
32
|
+
* imports: [Connection.forFeature([ProductEntity])]
|
|
33
|
+
*
|
|
34
|
+
* // Async function
|
|
35
|
+
* imports: async () => [
|
|
36
|
+
* await Connection.forFeature([ProductEntity]),
|
|
37
|
+
* Migration.forFeature([CreateProductTable]),
|
|
38
|
+
* ]
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export type FeatureImports = unknown[] | (() => unknown[]) | (() => Promise<unknown[]>);
|
|
42
|
+
/**
|
|
43
|
+
* Configuration options for creating a Feature.
|
|
44
|
+
* Extends FeatureHooksOptions for lifecycle hooks.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const options: FeatureInitialize = {
|
|
49
|
+
* controller: ProductController,
|
|
50
|
+
* router: Router.register(
|
|
51
|
+
* Route.get("/products", "findAll"),
|
|
52
|
+
* Route.post("/products", "create"),
|
|
53
|
+
* ),
|
|
54
|
+
* imports: [Connection.forFeature([ProductEntity])],
|
|
55
|
+
* injects: { productRepo: new ProductRepository() },
|
|
56
|
+
* onStart: () => console.log("Product feature started"),
|
|
57
|
+
* onRequest: (ctx) => console.log("Product feature request"),
|
|
58
|
+
* };
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export interface FeatureInitialize extends FeatureHooksOptions {
|
|
62
|
+
/** The controller class that handles requests for this feature */
|
|
63
|
+
controller: ControllerConstructor<any>;
|
|
64
|
+
/** Router with registered routes for this feature */
|
|
65
|
+
router: Router;
|
|
66
|
+
/**
|
|
67
|
+
* Imports executed once when the feature loads.
|
|
68
|
+
* Used for side effects like registering entities or migrations.
|
|
69
|
+
* The return values are not stored.
|
|
70
|
+
*/
|
|
71
|
+
imports?: FeatureImports;
|
|
72
|
+
/**
|
|
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.
|
|
76
|
+
*/
|
|
77
|
+
injects?: FeatureInjects | (() => FeatureInjects) | (() => Promise<FeatureInjects>);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Simplified interface for feature registration.
|
|
81
|
+
* Contains only the required controller and router.
|
|
82
|
+
*/
|
|
83
|
+
export interface FeatureRegister {
|
|
84
|
+
/** The controller class */
|
|
85
|
+
controller: ControllerConstructor<any>;
|
|
86
|
+
/** Router with routes */
|
|
87
|
+
router: Router;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Feature class representing a module of functionality.
|
|
91
|
+
*
|
|
92
|
+
* Features are the building blocks of an @mxweb/core application.
|
|
93
|
+
* Each feature contains:
|
|
94
|
+
* - A controller for handling requests
|
|
95
|
+
* - A router with route definitions
|
|
96
|
+
* - Optional imports for side effects (entities, migrations)
|
|
97
|
+
* - Optional injects for feature-local dependencies
|
|
98
|
+
* - Lifecycle hooks (onStart, onRequest, onResponse)
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* Features are registered with the Application using `Application.register()`.
|
|
102
|
+
* They are lazy-loaded on first request matching their routes.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* // product.feature.ts
|
|
107
|
+
* import { Application, Feature, Route, Router } from "@mxweb/core";
|
|
108
|
+
* import { ProductController } from "./product.controller";
|
|
109
|
+
*
|
|
110
|
+
* Application.register(
|
|
111
|
+
* Feature.create({
|
|
112
|
+
* controller: ProductController,
|
|
113
|
+
* router: Router.register(
|
|
114
|
+
* Route.get("/products", "findAll"),
|
|
115
|
+
* Route.get("/products/:id", "findById"),
|
|
116
|
+
* Route.post("/products", "create"),
|
|
117
|
+
* Route.put("/products/:id", "update"),
|
|
118
|
+
* Route.delete("/products/:id", "remove"),
|
|
119
|
+
* ),
|
|
120
|
+
* imports: [Connection.forFeature([ProductEntity])],
|
|
121
|
+
* injects: {
|
|
122
|
+
* productRepo: new ProductRepository(),
|
|
123
|
+
* },
|
|
124
|
+
* onStart: () => {
|
|
125
|
+
* console.log("Product feature initialized");
|
|
126
|
+
* },
|
|
127
|
+
* })
|
|
128
|
+
* );
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export declare class Feature {
|
|
132
|
+
private readonly options;
|
|
133
|
+
private readonly ControllerContructor;
|
|
134
|
+
private readonly router;
|
|
135
|
+
/** The last matched route for this feature */
|
|
136
|
+
private routeMatched;
|
|
137
|
+
/** Feature hooks manager */
|
|
138
|
+
private hooks;
|
|
139
|
+
/** Cached controller instance (lazy instantiated) */
|
|
140
|
+
private controller;
|
|
141
|
+
/** Map of feature-local injects */
|
|
142
|
+
private injects;
|
|
143
|
+
/** Flag indicating if injects have been loaded */
|
|
144
|
+
private injectsLoaded;
|
|
145
|
+
/** Flag indicating if imports have been loaded */
|
|
146
|
+
private importsLoaded;
|
|
147
|
+
/**
|
|
148
|
+
* Private constructor - use Feature.create() to instantiate.
|
|
149
|
+
*
|
|
150
|
+
* @param options - Feature configuration options
|
|
151
|
+
* @param ControllerContructor - The controller class constructor
|
|
152
|
+
* @param router - The router instance
|
|
153
|
+
*/
|
|
154
|
+
private constructor();
|
|
155
|
+
/**
|
|
156
|
+
* Factory method to create a new Feature instance.
|
|
157
|
+
*
|
|
158
|
+
* @param options - Feature configuration options
|
|
159
|
+
* @returns A new Feature instance
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* const feature = Feature.create({
|
|
164
|
+
* controller: ProductController,
|
|
165
|
+
* router: Router.register(
|
|
166
|
+
* Route.get("/products", "findAll"),
|
|
167
|
+
* ),
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
static create(options: FeatureInitialize): Feature;
|
|
172
|
+
/**
|
|
173
|
+
* Loads feature imports (side effects only, no storage).
|
|
174
|
+
* This method is idempotent - subsequent calls have no effect.
|
|
175
|
+
*
|
|
176
|
+
* @remarks
|
|
177
|
+
* Imports are used to register entities, migrations, or other side effects.
|
|
178
|
+
* The resolved values are not stored - only the side effects matter.
|
|
179
|
+
*/
|
|
180
|
+
loadImports(): Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Loads feature-specific injects.
|
|
183
|
+
* Also loads imports first if not already loaded.
|
|
184
|
+
* This method is idempotent - subsequent calls have no effect.
|
|
185
|
+
*
|
|
186
|
+
* @remarks
|
|
187
|
+
* Calls the `onFeature()` lifecycle hook on each inject after loading.
|
|
188
|
+
*/
|
|
189
|
+
loadInjects(): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Destroys all feature-specific injects.
|
|
192
|
+
* Calls the `onFeatureDestroy()` lifecycle hook on each inject.
|
|
193
|
+
*
|
|
194
|
+
* @remarks
|
|
195
|
+
* Called during application shutdown via Application.registerShutdown().
|
|
196
|
+
*/
|
|
197
|
+
destroyInjects(): Promise<void>;
|
|
198
|
+
/**
|
|
199
|
+
* Retrieves a feature-specific inject by name.
|
|
200
|
+
*
|
|
201
|
+
* @template T - Expected type of the inject (must extend FeatureInject)
|
|
202
|
+
* @param name - The name of the inject to retrieve
|
|
203
|
+
* @returns The inject instance or undefined if not found
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* const repo = feature.getInject<ProductRepository>("productRepo");
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
getInject<T extends FeatureInject>(name: string): T | undefined;
|
|
211
|
+
/**
|
|
212
|
+
* Checks if a feature-specific inject exists by name.
|
|
213
|
+
*
|
|
214
|
+
* @param name - The inject name to check
|
|
215
|
+
* @returns true if the inject exists, false otherwise
|
|
216
|
+
*/
|
|
217
|
+
hasInject(name: string): boolean;
|
|
218
|
+
/**
|
|
219
|
+
* Returns the controller instance for this feature.
|
|
220
|
+
* Lazily instantiates the controller on first access.
|
|
221
|
+
*
|
|
222
|
+
* @returns The controller instance
|
|
223
|
+
*/
|
|
224
|
+
getController(): any;
|
|
225
|
+
/**
|
|
226
|
+
* Returns the feature hooks manager.
|
|
227
|
+
*
|
|
228
|
+
* @returns The FeatureHooks instance
|
|
229
|
+
*/
|
|
230
|
+
getHooks(): FeatureHooks;
|
|
231
|
+
/**
|
|
232
|
+
* Attempts to match a request against this feature's routes.
|
|
233
|
+
*
|
|
234
|
+
* @param method - The HTTP method of the request
|
|
235
|
+
* @param path - The request path to match
|
|
236
|
+
* @returns The matched route info or null if no match
|
|
237
|
+
*/
|
|
238
|
+
matchRoute(method: RouteMethod, path: string): RouteMatched | null;
|
|
239
|
+
}
|
package/dist/feature.js
ADDED
|
@@ -0,0 +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;
|
package/dist/feature.mjs
ADDED
|
@@ -0,0 +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};
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Lifecycle hooks for Application and Feature levels.
|
|
3
|
+
*
|
|
4
|
+
* This module provides hook interfaces and managers for executing code at
|
|
5
|
+
* specific points in the application and request lifecycle:
|
|
6
|
+
* - `onStart`: Called once during initialization
|
|
7
|
+
* - `onRequest`: Called on every request before handling
|
|
8
|
+
* - `onResponse`: Called on every request after handling
|
|
9
|
+
*
|
|
10
|
+
* @module hooks
|
|
11
|
+
*/
|
|
12
|
+
import { NextRequest } from "next/server";
|
|
13
|
+
import { RouteMethod } from "./common";
|
|
14
|
+
import type { RequestContext } from "./execute";
|
|
15
|
+
/**
|
|
16
|
+
* Configuration options for Application-level lifecycle hooks.
|
|
17
|
+
*
|
|
18
|
+
* Application hooks run at the global level and have access to different
|
|
19
|
+
* context depending on the hook:
|
|
20
|
+
* - `onStart`: No context (runs once at initialization)
|
|
21
|
+
* - `onRequest`: Raw request only (before route matching)
|
|
22
|
+
* - `onResponse`: Full request context (after handling)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const app = Application.create({
|
|
27
|
+
* onStart: () => {
|
|
28
|
+
* console.log("Application started");
|
|
29
|
+
* },
|
|
30
|
+
* onRequest: (req, method) => {
|
|
31
|
+
* console.log(`${method} ${req.url}`);
|
|
32
|
+
* },
|
|
33
|
+
* onResponse: (context) => {
|
|
34
|
+
* console.log(`Response for ${context.path}`);
|
|
35
|
+
* },
|
|
36
|
+
* });
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export interface ApplicationHooksOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Called ONCE when the application is initialized.
|
|
42
|
+
* No request context is available at this point.
|
|
43
|
+
* Use for one-time setup, logging, or initialization tasks.
|
|
44
|
+
*/
|
|
45
|
+
onStart?(): void | Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Called on every request BEFORE route matching.
|
|
48
|
+
* No full context is available - only the raw request and method.
|
|
49
|
+
* Use for early request logging, global rate limiting, etc.
|
|
50
|
+
*
|
|
51
|
+
* @param req - The incoming Next.js request
|
|
52
|
+
* @param method - The HTTP method of the request
|
|
53
|
+
*/
|
|
54
|
+
onRequest?(req: NextRequest, method: RouteMethod): void | Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Called on every request AFTER the route handler completes.
|
|
57
|
+
* Full request context is available.
|
|
58
|
+
* Use for response logging, cleanup, metrics collection, etc.
|
|
59
|
+
*
|
|
60
|
+
* @param context - The request context containing request, response, params, etc.
|
|
61
|
+
*/
|
|
62
|
+
onResponse?(context: RequestContext): void | Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Configuration options for Feature-level lifecycle hooks.
|
|
66
|
+
*
|
|
67
|
+
* Feature hooks run at the feature/module level and have access to
|
|
68
|
+
* the full request context (unlike Application's onRequest).
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* Feature.create({
|
|
73
|
+
* controller: ProductController,
|
|
74
|
+
* router: productRouter,
|
|
75
|
+
* onStart: () => {
|
|
76
|
+
* console.log("Product feature initialized");
|
|
77
|
+
* },
|
|
78
|
+
* onRequest: (context) => {
|
|
79
|
+
* console.log(`Product request: ${context.method} ${context.path}`);
|
|
80
|
+
* },
|
|
81
|
+
* onResponse: (context) => {
|
|
82
|
+
* console.log(`Product response sent`);
|
|
83
|
+
* },
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export interface FeatureHooksOptions {
|
|
88
|
+
/**
|
|
89
|
+
* Called ONCE when the feature is initialized.
|
|
90
|
+
* No request context is available at this point.
|
|
91
|
+
* Use for feature-specific setup or logging.
|
|
92
|
+
*/
|
|
93
|
+
onStart?(): void | Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Called on every request to this feature BEFORE the route handler.
|
|
96
|
+
* Full request context is available (after route matching).
|
|
97
|
+
* Use for feature-specific request logging, validation, etc.
|
|
98
|
+
*
|
|
99
|
+
* @param context - The request context for the current request
|
|
100
|
+
*/
|
|
101
|
+
onRequest?(context: RequestContext): void | Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Called on every request to this feature AFTER the route handler.
|
|
104
|
+
* Full request context is available.
|
|
105
|
+
* Use for feature-specific response logging, cleanup, etc.
|
|
106
|
+
*
|
|
107
|
+
* @param context - The request context for the current request
|
|
108
|
+
*/
|
|
109
|
+
onResponse?(context: RequestContext): void | Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Manager class for Application-level hooks.
|
|
113
|
+
* Created during Application.create() and executes onStart immediately.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const hooks = new ApplicationHooks({
|
|
118
|
+
* onStart: () => console.log("Started"),
|
|
119
|
+
* onRequest: (req, method) => console.log(`${method} request`),
|
|
120
|
+
* });
|
|
121
|
+
* // onStart is called immediately in constructor
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export declare class ApplicationHooks {
|
|
125
|
+
private readonly options;
|
|
126
|
+
/**
|
|
127
|
+
* Creates a new ApplicationHooks instance.
|
|
128
|
+
* Immediately executes the onStart hook if provided.
|
|
129
|
+
*
|
|
130
|
+
* @param options - The hook configuration options
|
|
131
|
+
*/
|
|
132
|
+
constructor(options: ApplicationHooksOptions);
|
|
133
|
+
/**
|
|
134
|
+
* Returns the hook options.
|
|
135
|
+
* @returns The ApplicationHooksOptions object
|
|
136
|
+
*/
|
|
137
|
+
getOptions(): ApplicationHooksOptions;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Manager class for Feature-level hooks.
|
|
141
|
+
* Created during Feature.create() and executes onStart immediately.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* const hooks = new FeatureHooks({
|
|
146
|
+
* onStart: () => console.log("Feature started"),
|
|
147
|
+
* onRequest: (ctx) => console.log(`Request to ${ctx.path}`),
|
|
148
|
+
* });
|
|
149
|
+
* // onStart is called immediately in constructor
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare class FeatureHooks {
|
|
153
|
+
private readonly options;
|
|
154
|
+
/**
|
|
155
|
+
* Creates a new FeatureHooks instance.
|
|
156
|
+
* Immediately executes the onStart hook if provided.
|
|
157
|
+
*
|
|
158
|
+
* @param options - The hook configuration options
|
|
159
|
+
*/
|
|
160
|
+
constructor(options: FeatureHooksOptions);
|
|
161
|
+
/**
|
|
162
|
+
* Returns the hook options.
|
|
163
|
+
* @returns The FeatureHooksOptions object
|
|
164
|
+
*/
|
|
165
|
+
getOptions(): FeatureHooksOptions;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Per-request hook execution manager.
|
|
169
|
+
*
|
|
170
|
+
* Each request creates a new RequestHooks instance to track which hooks
|
|
171
|
+
* have been called, ensuring each hook runs at most once per request.
|
|
172
|
+
*
|
|
173
|
+
* @remarks
|
|
174
|
+
* This class manages the execution order:
|
|
175
|
+
* 1. Application onRequest (before route matching)
|
|
176
|
+
* 2. Feature onRequest (after route matching, before handler)
|
|
177
|
+
* 3. Handler execution
|
|
178
|
+
* 4. Feature onResponse (after handler)
|
|
179
|
+
* 5. Application onResponse (after all)
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```ts
|
|
183
|
+
* // Created internally by Application for each request
|
|
184
|
+
* const requestHooks = new RequestHooks(applicationHooks);
|
|
185
|
+
*
|
|
186
|
+
* // Set feature hooks after route matching
|
|
187
|
+
* requestHooks.setFeatureHooks(matchedFeature.getHooks());
|
|
188
|
+
*
|
|
189
|
+
* // Execute hooks at appropriate times
|
|
190
|
+
* await requestHooks.appRequest(req, method);
|
|
191
|
+
* await requestHooks.featureRequest(context);
|
|
192
|
+
* // ... handle request ...
|
|
193
|
+
* await requestHooks.featureResponse(context);
|
|
194
|
+
* await requestHooks.appResponse(context);
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export declare class RequestHooks {
|
|
198
|
+
private readonly appHooks;
|
|
199
|
+
private featureHooks;
|
|
200
|
+
/** Flag to ensure appRequest is only called once */
|
|
201
|
+
private appRequestCalled;
|
|
202
|
+
/** Flag to ensure appResponse is only called once */
|
|
203
|
+
private appResponseCalled;
|
|
204
|
+
/** Flag to ensure featureRequest is only called once */
|
|
205
|
+
private featureRequestCalled;
|
|
206
|
+
/** Flag to ensure featureResponse is only called once */
|
|
207
|
+
private featureResponseCalled;
|
|
208
|
+
/**
|
|
209
|
+
* Creates a new RequestHooks instance.
|
|
210
|
+
*
|
|
211
|
+
* @param appHooks - The application-level hooks manager
|
|
212
|
+
* @param featureHooks - Optional feature-level hooks manager (set later via setFeatureHooks)
|
|
213
|
+
*/
|
|
214
|
+
constructor(appHooks: ApplicationHooks, featureHooks?: FeatureHooks | null);
|
|
215
|
+
/**
|
|
216
|
+
* Sets the feature hooks after route matching.
|
|
217
|
+
* Called when the matching feature is determined.
|
|
218
|
+
*
|
|
219
|
+
* @param hooks - The FeatureHooks instance from the matched feature
|
|
220
|
+
*/
|
|
221
|
+
setFeatureHooks(hooks: FeatureHooks): void;
|
|
222
|
+
/**
|
|
223
|
+
* Executes the Application onRequest hook.
|
|
224
|
+
* Called before route matching. Only runs once per request.
|
|
225
|
+
*
|
|
226
|
+
* @param req - The incoming Next.js request
|
|
227
|
+
* @param method - The HTTP method
|
|
228
|
+
*/
|
|
229
|
+
appRequest(req: NextRequest, method: RouteMethod): Promise<void>;
|
|
230
|
+
/**
|
|
231
|
+
* Executes the Application onResponse hook.
|
|
232
|
+
* Called after dispatch and feature hooks. Only runs once per request.
|
|
233
|
+
*
|
|
234
|
+
* @param context - The request context
|
|
235
|
+
*/
|
|
236
|
+
appResponse(context: RequestContext): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* Executes the Feature onRequest hook.
|
|
239
|
+
* Called after route matching, before handler. Only runs once per request.
|
|
240
|
+
*
|
|
241
|
+
* @param context - The request context
|
|
242
|
+
*/
|
|
243
|
+
featureRequest(context: RequestContext): Promise<void>;
|
|
244
|
+
/**
|
|
245
|
+
* Executes the Feature onResponse hook.
|
|
246
|
+
* Called after handler, before app onResponse. Only runs once per request.
|
|
247
|
+
*
|
|
248
|
+
* @param context - The request context
|
|
249
|
+
*/
|
|
250
|
+
featureResponse(context: RequestContext): Promise<void>;
|
|
251
|
+
}
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";exports.ApplicationHooks=class{constructor(e){this.options=e,this.options.onStart?.()}getOptions(){return this.options}},exports.FeatureHooks=class{constructor(e){this.options=e,this.options.onStart?.()}getOptions(){return this.options}},exports.RequestHooks=class{constructor(e,s=null){this.appHooks=e,this.featureHooks=s,this.appRequestCalled=!1,this.appResponseCalled=!1,this.featureRequestCalled=!1,this.featureResponseCalled=!1}setFeatureHooks(e){this.featureHooks=e}async appRequest(e,s){if(!this.appRequestCalled)return this.appRequestCalled=!0,await(this.appHooks.getOptions().onRequest?.(e,s))}async appResponse(e){if(!this.appResponseCalled)return this.appResponseCalled=!0,await(this.appHooks.getOptions().onResponse?.(e))}async featureRequest(e){if(!this.featureRequestCalled&&this.featureHooks)return this.featureRequestCalled=!0,await(this.featureHooks.getOptions().onRequest?.(e))}async featureResponse(e){if(!this.featureResponseCalled&&this.featureHooks)return this.featureResponseCalled=!0,await(this.featureHooks.getOptions().onResponse?.(e))}};
|
package/dist/hooks.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class e{constructor(e){this.options=e,this.options.onStart?.()}getOptions(){return this.options}}class s{constructor(e){this.options=e,this.options.onStart?.()}getOptions(){return this.options}}class t{constructor(e,s=null){this.appHooks=e,this.featureHooks=s,this.appRequestCalled=!1,this.appResponseCalled=!1,this.featureRequestCalled=!1,this.featureResponseCalled=!1}setFeatureHooks(e){this.featureHooks=e}async appRequest(e,s){if(!this.appRequestCalled)return this.appRequestCalled=!0,await(this.appHooks.getOptions().onRequest?.(e,s))}async appResponse(e){if(!this.appResponseCalled)return this.appResponseCalled=!0,await(this.appHooks.getOptions().onResponse?.(e))}async featureRequest(e){if(!this.featureRequestCalled&&this.featureHooks)return this.featureRequestCalled=!0,await(this.featureHooks.getOptions().onRequest?.(e))}async featureResponse(e){if(!this.featureResponseCalled&&this.featureHooks)return this.featureResponseCalled=!0,await(this.featureHooks.getOptions().onResponse?.(e))}}export{e as ApplicationHooks,s as FeatureHooks,t as RequestHooks};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./application";
|
|
2
|
+
export * from "./common";
|
|
3
|
+
export * from "./config";
|
|
4
|
+
export * from "./controller";
|
|
5
|
+
export * from "./decorator";
|
|
6
|
+
export * from "./error";
|
|
7
|
+
export * from "./execute";
|
|
8
|
+
export * from "./feature";
|
|
9
|
+
export * from "./hooks";
|
|
10
|
+
export * from "./logger";
|
|
11
|
+
export * from "./response";
|
|
12
|
+
export * from "./route";
|
|
13
|
+
export * from "./router";
|
|
14
|
+
export * from "./service";
|
package/dist/index.js
ADDED
|
@@ -0,0 +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;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +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";
|