@nextrush/core 3.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 +626 -0
- package/dist/index.d.ts +388 -0
- package/dist/index.js +534 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { Middleware, Context, Plugin, Next } from '@nextrush/types';
|
|
2
|
+
export { ContentType, Context, ContextState, HttpMethod, HttpStatus, HttpStatusCode, Middleware, Next, Plugin, PluginWithHooks, QueryParams, RouteHandler, RouteParams } from '@nextrush/types';
|
|
3
|
+
export { BadRequestError, ForbiddenError, HttpError, InternalServerError, NextRushError, NotFoundError, UnauthorizedError, createError as createHttpError } from '@nextrush/errors';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @nextrush/core - Application Class
|
|
7
|
+
*
|
|
8
|
+
* The Application class is the main entry point for NextRush.
|
|
9
|
+
* It manages middleware registration and plugin installation.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Error handler function type
|
|
16
|
+
*/
|
|
17
|
+
type ErrorHandler = (error: Error, ctx: Context) => void | Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Logger interface for pluggable logging
|
|
20
|
+
*/
|
|
21
|
+
interface Logger {
|
|
22
|
+
error(...args: unknown[]): void;
|
|
23
|
+
warn(...args: unknown[]): void;
|
|
24
|
+
info(...args: unknown[]): void;
|
|
25
|
+
debug(...args: unknown[]): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Application options
|
|
29
|
+
*/
|
|
30
|
+
interface ApplicationOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Environment mode
|
|
33
|
+
* @default 'development'
|
|
34
|
+
*/
|
|
35
|
+
env?: 'development' | 'production' | 'test';
|
|
36
|
+
/**
|
|
37
|
+
* Whether to use proxy headers (X-Forwarded-For, etc.)
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
proxy?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Custom logger. Defaults to no-op (silent).
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* Pass `console` for quick development logging:
|
|
46
|
+
* ```ts
|
|
47
|
+
* const app = createApp({ logger: console });
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* For production, provide a structured logger (e.g. pino, winston)
|
|
51
|
+
* that implements the {@link Logger} interface.
|
|
52
|
+
*
|
|
53
|
+
* Adapters and internal hooks use `app.logger` — configuring it here
|
|
54
|
+
* ensures consistent logging across the framework.
|
|
55
|
+
*/
|
|
56
|
+
logger?: Logger;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Listener callback type
|
|
60
|
+
*/
|
|
61
|
+
type ListenCallback = () => void;
|
|
62
|
+
/**
|
|
63
|
+
* Routable interface - any object with routes() method
|
|
64
|
+
* This allows mounting Router instances without circular dependency
|
|
65
|
+
*/
|
|
66
|
+
interface Routable {
|
|
67
|
+
routes(): Middleware;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The Application class
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const app = createApp();
|
|
75
|
+
*
|
|
76
|
+
* app.use(async (ctx) => {
|
|
77
|
+
* ctx.json({ message: 'Hello World' });
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* // Mount with an adapter
|
|
81
|
+
* listen(app, { port: 3000 });
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare class Application {
|
|
85
|
+
/**
|
|
86
|
+
* Middleware stack
|
|
87
|
+
*/
|
|
88
|
+
private readonly middlewareStack;
|
|
89
|
+
/**
|
|
90
|
+
* Installed plugins
|
|
91
|
+
*/
|
|
92
|
+
private readonly plugins;
|
|
93
|
+
/**
|
|
94
|
+
* Custom error handler
|
|
95
|
+
*/
|
|
96
|
+
private _errorHandler;
|
|
97
|
+
/**
|
|
98
|
+
* Pluggable logger
|
|
99
|
+
*/
|
|
100
|
+
readonly logger: Logger;
|
|
101
|
+
/**
|
|
102
|
+
* Application options
|
|
103
|
+
*/
|
|
104
|
+
readonly options: ApplicationOptions;
|
|
105
|
+
/**
|
|
106
|
+
* Whether the app is running
|
|
107
|
+
*/
|
|
108
|
+
private _isRunning;
|
|
109
|
+
constructor(options?: ApplicationOptions);
|
|
110
|
+
/**
|
|
111
|
+
* Check if running in production
|
|
112
|
+
*/
|
|
113
|
+
get isProduction(): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Check if app is running
|
|
116
|
+
*/
|
|
117
|
+
get isRunning(): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Get middleware count
|
|
120
|
+
*/
|
|
121
|
+
get middlewareCount(): number;
|
|
122
|
+
/**
|
|
123
|
+
* Throws if the app is already running.
|
|
124
|
+
* Prevents configuration mutations after start().
|
|
125
|
+
*/
|
|
126
|
+
private assertNotRunning;
|
|
127
|
+
/**
|
|
128
|
+
* Register middleware function(s)
|
|
129
|
+
*
|
|
130
|
+
* @param middleware - Middleware function or array of middleware
|
|
131
|
+
* @returns this for chaining
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* // Single middleware
|
|
136
|
+
* app.use(async (ctx) => {
|
|
137
|
+
* console.log(ctx.method, ctx.path);
|
|
138
|
+
* await ctx.next();
|
|
139
|
+
* });
|
|
140
|
+
*
|
|
141
|
+
* // Multiple middleware
|
|
142
|
+
* app.use(cors(), helmet(), json());
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
use(...middleware: Middleware[]): this;
|
|
146
|
+
/**
|
|
147
|
+
* Mount a router at a path prefix
|
|
148
|
+
*
|
|
149
|
+
* This is the Hono-style API for mounting routers directly on the app.
|
|
150
|
+
* The router's routes will only match requests that start with the given prefix.
|
|
151
|
+
*
|
|
152
|
+
* @param path - Path prefix for the router (e.g., '/api/users')
|
|
153
|
+
* @param router - Router instance to mount
|
|
154
|
+
* @returns this for chaining
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* // Create modular routers
|
|
159
|
+
* const users = createRouter();
|
|
160
|
+
* users.get('/', listUsers);
|
|
161
|
+
* users.get('/:id', getUser);
|
|
162
|
+
* users.post('/', createUser);
|
|
163
|
+
*
|
|
164
|
+
* const posts = createRouter();
|
|
165
|
+
* posts.get('/', listPosts);
|
|
166
|
+
* posts.get('/:id', getPost);
|
|
167
|
+
*
|
|
168
|
+
* // Mount directly on app - clean like Hono!
|
|
169
|
+
* const app = createApp();
|
|
170
|
+
* app.route('/api/users', users);
|
|
171
|
+
* app.route('/api/posts', posts);
|
|
172
|
+
*
|
|
173
|
+
* listen(app, 3000);
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
route(path: string, router: Routable): this;
|
|
177
|
+
/**
|
|
178
|
+
* Set the application error handler.
|
|
179
|
+
*
|
|
180
|
+
* Replaces any previously set handler. Only one error handler is active
|
|
181
|
+
* at a time. For additive error handling, compose logic within a single
|
|
182
|
+
* handler or use the `errorHandler()` middleware from `@nextrush/errors`.
|
|
183
|
+
*
|
|
184
|
+
* @param handler - Error handler function
|
|
185
|
+
* @returns this for chaining
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* app.setErrorHandler((error, ctx) => {
|
|
190
|
+
* console.error('Request failed:', error);
|
|
191
|
+
*
|
|
192
|
+
* if (error instanceof ValidationError) {
|
|
193
|
+
* ctx.status = 400;
|
|
194
|
+
* ctx.json({ error: error.message, details: error.details });
|
|
195
|
+
* return;
|
|
196
|
+
* }
|
|
197
|
+
*
|
|
198
|
+
* ctx.status = 500;
|
|
199
|
+
* ctx.json({ error: 'Internal Server Error' });
|
|
200
|
+
* });
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
setErrorHandler(handler: ErrorHandler): this;
|
|
204
|
+
/**
|
|
205
|
+
* Set custom error handler.
|
|
206
|
+
*
|
|
207
|
+
* @param handler - Error handler function
|
|
208
|
+
* @returns this for chaining
|
|
209
|
+
*
|
|
210
|
+
* @deprecated Use `setErrorHandler()` instead — `onError()` implies
|
|
211
|
+
* event subscription (additive), but this is a setter (replaces).
|
|
212
|
+
*/
|
|
213
|
+
onError(handler: ErrorHandler): this;
|
|
214
|
+
/**
|
|
215
|
+
* Install a plugin.
|
|
216
|
+
*
|
|
217
|
+
* Handles both sync and async `install()` methods automatically.
|
|
218
|
+
* Returns `this` for sync plugins and `Promise<this>` for async ones.
|
|
219
|
+
*
|
|
220
|
+
* @param plugin - Plugin to install
|
|
221
|
+
* @returns this (sync) or Promise<this> (async)
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* // Sync plugin
|
|
226
|
+
* app.plugin(loggerPlugin({ level: 'info' }));
|
|
227
|
+
*
|
|
228
|
+
* // Async plugin — just await it
|
|
229
|
+
* await app.plugin(databasePlugin({ uri: '...' }));
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
plugin(plugin: Plugin): this | Promise<this>;
|
|
233
|
+
/**
|
|
234
|
+
* Install a plugin asynchronously.
|
|
235
|
+
*
|
|
236
|
+
* @param plugin - Plugin to install
|
|
237
|
+
* @returns Promise that resolves when plugin is installed
|
|
238
|
+
*
|
|
239
|
+
* @deprecated Use `plugin()` instead — it handles both sync and async
|
|
240
|
+
* plugins automatically.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* await app.plugin(new DatabasePlugin({ connectionString: '...' }));
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
pluginAsync(plugin: Plugin): Promise<this>;
|
|
248
|
+
/**
|
|
249
|
+
* Get an installed plugin by name
|
|
250
|
+
*
|
|
251
|
+
* @param name - Plugin name
|
|
252
|
+
* @returns Plugin instance or undefined
|
|
253
|
+
*/
|
|
254
|
+
getPlugin<T extends Plugin>(name: string): T | undefined;
|
|
255
|
+
/**
|
|
256
|
+
* Check if a plugin is installed
|
|
257
|
+
*/
|
|
258
|
+
hasPlugin(name: string): boolean;
|
|
259
|
+
/**
|
|
260
|
+
* Create the request handler callback
|
|
261
|
+
*
|
|
262
|
+
* This is the function that adapters call to handle each request.
|
|
263
|
+
* It composes all middleware and returns a function that processes context.
|
|
264
|
+
*
|
|
265
|
+
* **Important:** The middleware stack is snapshot at call time.
|
|
266
|
+
* Middleware or plugins added after `callback()` will NOT take effect
|
|
267
|
+
* on the returned handler. Call `callback()` again to get a
|
|
268
|
+
* handler that includes subsequent registrations.
|
|
269
|
+
*
|
|
270
|
+
* @returns Request handler function
|
|
271
|
+
*/
|
|
272
|
+
callback(): (ctx: Context) => Promise<void>;
|
|
273
|
+
/**
|
|
274
|
+
* Handle errors - uses custom handler if set, otherwise default
|
|
275
|
+
*/
|
|
276
|
+
private handleError;
|
|
277
|
+
/**
|
|
278
|
+
* Default error handler
|
|
279
|
+
*
|
|
280
|
+
* Uses the `expose` flag on errors (set by HttpError/NextRushError)
|
|
281
|
+
* to decide whether to include the error message in the response.
|
|
282
|
+
* 4xx errors expose messages by default; 5xx errors never do.
|
|
283
|
+
* This prevents leaking internal details (paths, SQL, stack info)
|
|
284
|
+
* regardless of environment.
|
|
285
|
+
*/
|
|
286
|
+
private defaultErrorHandler;
|
|
287
|
+
/**
|
|
288
|
+
* Mark app as running and freeze configuration.
|
|
289
|
+
*
|
|
290
|
+
* Called by adapters when the server starts listening. After this call,
|
|
291
|
+
* `use()`, `route()`, `plugin()`, and `pluginAsync()` will throw.
|
|
292
|
+
* This prevents unsafe middleware mutations while requests are in flight.
|
|
293
|
+
*
|
|
294
|
+
* To re-enable registration (e.g. for testing), call `close()` first.
|
|
295
|
+
*/
|
|
296
|
+
start(): void;
|
|
297
|
+
/**
|
|
298
|
+
* Graceful shutdown
|
|
299
|
+
* Destroys all plugins that have a destroy method.
|
|
300
|
+
* Uses Promise.allSettled to ensure all plugins are destroyed
|
|
301
|
+
* even if some throw errors.
|
|
302
|
+
*
|
|
303
|
+
* @returns Array of errors from plugins that failed to destroy (empty on success)
|
|
304
|
+
*/
|
|
305
|
+
close(): Promise<Error[]>;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create a new Application instance
|
|
309
|
+
*
|
|
310
|
+
* @param options - Application options
|
|
311
|
+
* @returns New Application instance
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```typescript
|
|
315
|
+
* const app = createApp();
|
|
316
|
+
* const app = createApp({ env: 'production' });
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
declare function createApp(options?: ApplicationOptions): Application;
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @nextrush/core - Middleware Composition
|
|
323
|
+
*
|
|
324
|
+
* Koa-style middleware composition with async/await support.
|
|
325
|
+
* This is the heart of the middleware pipeline.
|
|
326
|
+
*
|
|
327
|
+
* @packageDocumentation
|
|
328
|
+
*/
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Composed middleware handler - can be called with just context
|
|
332
|
+
*/
|
|
333
|
+
type ComposedMiddleware = (ctx: Context, next?: Next) => Promise<void>;
|
|
334
|
+
/**
|
|
335
|
+
* Options for middleware composition
|
|
336
|
+
*/
|
|
337
|
+
interface ComposeOptions {
|
|
338
|
+
/**
|
|
339
|
+
* Warn when a middleware sends a response AND calls next().
|
|
340
|
+
* Enabled by default in non-production environments.
|
|
341
|
+
* @default process.env.NODE_ENV !== 'production'
|
|
342
|
+
*/
|
|
343
|
+
warnDoubleResponse?: boolean;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Compose multiple middleware functions into a single middleware.
|
|
347
|
+
*
|
|
348
|
+
* Executes middleware in order, each middleware can call `await next()`
|
|
349
|
+
* to pass control to the next middleware and wait for it to complete.
|
|
350
|
+
*
|
|
351
|
+
* @param middleware - Array of middleware functions to compose
|
|
352
|
+
* @param options - Composition options
|
|
353
|
+
* @returns Single composed middleware function
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* ```typescript
|
|
357
|
+
* const composed = compose([
|
|
358
|
+
* async (ctx, next) => {
|
|
359
|
+
* console.log('1 - before');
|
|
360
|
+
* await next();
|
|
361
|
+
* console.log('1 - after');
|
|
362
|
+
* },
|
|
363
|
+
* async (ctx, next) => {
|
|
364
|
+
* console.log('2 - before');
|
|
365
|
+
* await next();
|
|
366
|
+
* console.log('2 - after');
|
|
367
|
+
* },
|
|
368
|
+
* ]);
|
|
369
|
+
*
|
|
370
|
+
* // Output:
|
|
371
|
+
* // 1 - before
|
|
372
|
+
* // 2 - before
|
|
373
|
+
* // 2 - after
|
|
374
|
+
* // 1 - after
|
|
375
|
+
* ```
|
|
376
|
+
*/
|
|
377
|
+
declare function compose(middleware: Middleware[], options?: ComposeOptions): ComposedMiddleware;
|
|
378
|
+
/**
|
|
379
|
+
* Check if a function is a valid middleware
|
|
380
|
+
*/
|
|
381
|
+
declare function isMiddleware(fn: unknown): fn is Middleware;
|
|
382
|
+
/**
|
|
383
|
+
* Flatten nested middleware arrays with type validation.
|
|
384
|
+
* Uses bounded depth (10 levels) to prevent V8 deoptimization on deeply nested arrays.
|
|
385
|
+
*/
|
|
386
|
+
declare function flattenMiddleware(arr: (Middleware | Middleware[])[]): Middleware[];
|
|
387
|
+
|
|
388
|
+
export { Application, type ApplicationOptions, type ComposeOptions, type ComposedMiddleware, type ErrorHandler, type ListenCallback, type Logger, type Routable, compose, createApp, flattenMiddleware, isMiddleware };
|