@nextrush/core 3.0.7 → 4.0.0-beta.1
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/README.md +322 -493
- package/dist/index.d.ts +226 -182
- package/dist/index.js +501 -311
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { Middleware, Context,
|
|
2
|
-
export { ContentType, Context, ContextState, HttpMethod, HttpStatus, HttpStatusCode, Middleware, Next,
|
|
3
|
-
export { BadRequestError, ForbiddenError, HttpError, InternalServerError, NextRushError, NotFoundError, UnauthorizedError
|
|
1
|
+
import { Logger, ProxyTrust, Router, Container, Middleware, RouteEntry, Context, Extension, Next } from '@nextrush/types';
|
|
2
|
+
export { ContentType, Context, ContextState, Extension, ExtensionContext, ExtensionHost, HttpMethod, HttpStatus, HttpStatusCode, Logger, Middleware, Next, QueryParams, RouteEntry, RouteHandler, RouteParams, Router } from '@nextrush/types';
|
|
3
|
+
export { BadRequestError, ForbiddenError, HttpError, InternalServerError, NextRushError, NotFoundError, UnauthorizedError } from '@nextrush/errors';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @nextrush/core - Application Class
|
|
7
7
|
*
|
|
8
8
|
* The Application class is the main entry point for NextRush.
|
|
9
|
-
* It manages middleware registration and
|
|
9
|
+
* It manages middleware registration and the extension lifecycle.
|
|
10
|
+
*
|
|
11
|
+
* See docs/RFC/class-runtime/005-plugin-system.md for the extension model.
|
|
10
12
|
*
|
|
11
13
|
* @packageDocumentation
|
|
12
14
|
*/
|
|
@@ -16,13 +18,21 @@ export { BadRequestError, ForbiddenError, HttpError, InternalServerError, NextRu
|
|
|
16
18
|
*/
|
|
17
19
|
type ErrorHandler = (error: Error, ctx: Context) => void | Promise<void>;
|
|
18
20
|
/**
|
|
19
|
-
*
|
|
21
|
+
* Options for {@link Application.close}.
|
|
22
|
+
*
|
|
23
|
+
* @see RFC-022 (`docs/RFC/class-runtime/022-bounded-teardown-lifecycle.md`) / ADR-0012.
|
|
20
24
|
*/
|
|
21
|
-
interface
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
interface CloseOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Bound, in milliseconds, on total teardown time. Every teardown unit
|
|
28
|
+
* (extension `destroy()`) races against this budget independently — a
|
|
29
|
+
* unit that does not finish in time is reported as a {@link TeardownTimeoutError}
|
|
30
|
+
* in the returned array, and never blocks `close()` past the budget.
|
|
31
|
+
*
|
|
32
|
+
* @remarks Omitted = unbounded, identical to calling `close()` with no
|
|
33
|
+
* arguments today (`Promise.allSettled`, no timeout).
|
|
34
|
+
*/
|
|
35
|
+
timeout?: number;
|
|
26
36
|
}
|
|
27
37
|
/**
|
|
28
38
|
* Application options
|
|
@@ -34,37 +44,65 @@ interface ApplicationOptions {
|
|
|
34
44
|
*/
|
|
35
45
|
env?: 'development' | 'production' | 'test';
|
|
36
46
|
/**
|
|
37
|
-
*
|
|
47
|
+
* Proxy-trust specification for `ctx.ip` resolution (RFC-030, SEC-01).
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* `false` trusts nothing (the socket peer is always `ctx.ip`); a `number`
|
|
51
|
+
* trusts exactly that many reverse-proxy hops; a `string[]` of CIDR
|
|
52
|
+
* ranges/IPs trusts only a direct peer inside that set. `true` and `0`
|
|
53
|
+
* throw at construction — see {@link validateProxyTrust}.
|
|
54
|
+
*
|
|
38
55
|
* @default false
|
|
39
56
|
*/
|
|
40
|
-
proxy?:
|
|
57
|
+
proxy?: ProxyTrust;
|
|
41
58
|
/**
|
|
42
59
|
* Custom logger. Defaults to no-op (silent).
|
|
43
60
|
*
|
|
44
61
|
* @remarks
|
|
45
|
-
* Pass `console` for quick development logging
|
|
46
|
-
*
|
|
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.
|
|
62
|
+
* Pass `console` for quick development logging. For production, provide a
|
|
63
|
+
* structured logger (pino, winston, `@nextrush/logger`) implementing {@link Logger}.
|
|
55
64
|
*/
|
|
56
65
|
logger?: Logger;
|
|
66
|
+
/**
|
|
67
|
+
* A router the app owns. Route methods (`app.get`, `app.post`, …) delegate to
|
|
68
|
+
* it, and it is mounted last at `ready()`. The `nextrush` meta-package's
|
|
69
|
+
* `createApp` injects one automatically; pass it explicitly when using
|
|
70
|
+
* `@nextrush/core` directly.
|
|
71
|
+
*/
|
|
72
|
+
router?: Router;
|
|
73
|
+
/**
|
|
74
|
+
* A per-app DI container. Exposed to extensions via `ExtensionContext.container`
|
|
75
|
+
* and used by class-based registrars (e.g. `registerControllers`). Injected by
|
|
76
|
+
* `nextrush/class`; omitted for functional, DI-free apps.
|
|
77
|
+
*/
|
|
78
|
+
container?: Container;
|
|
57
79
|
}
|
|
58
80
|
/**
|
|
59
81
|
* Listener callback type
|
|
60
82
|
*/
|
|
61
83
|
type ListenCallback = () => void;
|
|
62
84
|
/**
|
|
63
|
-
* Routable interface - any object with routes() method
|
|
64
|
-
*
|
|
85
|
+
* Routable interface - any object with routes() method.
|
|
86
|
+
* Allows mounting Router instances without a circular dependency.
|
|
65
87
|
*/
|
|
66
88
|
interface Routable {
|
|
67
89
|
routes(): Middleware;
|
|
90
|
+
/**
|
|
91
|
+
* Test whether `path` falls under this router's mount prefix, using the
|
|
92
|
+
* SAME normalization the router itself matches with (case folding per its
|
|
93
|
+
* `caseSensitive` option, structural normalization) — never a raw
|
|
94
|
+
* `startsWith` comparison, which would apply a different rule than the
|
|
95
|
+
* router's own dispatch (RFC-029, SEC-02/SEC-15). Optional so a minimal
|
|
96
|
+
* `Routable` (e.g. a test double) still mounts; {@link createPrefixMount}
|
|
97
|
+
* falls back to a literal prefix test when this is absent.
|
|
98
|
+
*
|
|
99
|
+
* @param path - The full, still-query-stripped request path being tested.
|
|
100
|
+
* @param prefix - The normalized mount prefix (leading `/`, no trailing `/`).
|
|
101
|
+
* @returns The path's remainder past the prefix (e.g. `/users` for
|
|
102
|
+
* `/Admin/Users` mounted at `/admin`), or `undefined` if `path` is not
|
|
103
|
+
* under `prefix` per this router's own normalization.
|
|
104
|
+
*/
|
|
105
|
+
matchesMountPrefix?(path: string, prefix: string): string | undefined;
|
|
68
106
|
}
|
|
69
107
|
/**
|
|
70
108
|
* The Application class
|
|
@@ -77,195 +115,183 @@ interface Routable {
|
|
|
77
115
|
* ctx.json({ message: 'Hello World' });
|
|
78
116
|
* });
|
|
79
117
|
*
|
|
80
|
-
* //
|
|
81
|
-
*
|
|
118
|
+
* // Extensions (rare — long-lived services) are booted at ready(), which
|
|
119
|
+
* // adapters call automatically before start().
|
|
120
|
+
* app.extend(events());
|
|
121
|
+
*
|
|
122
|
+
* listen(app, { port: 8080 });
|
|
82
123
|
* ```
|
|
83
124
|
*/
|
|
84
125
|
declare class Application {
|
|
85
|
-
/**
|
|
86
|
-
* Middleware stack
|
|
87
|
-
*/
|
|
88
126
|
private readonly middlewareStack;
|
|
89
127
|
/**
|
|
90
|
-
*
|
|
128
|
+
* Boot-time security audit checks contributed by tagged middleware
|
|
129
|
+
* (`security-boundaries` capability, task 8.1). Collected as `use()`
|
|
130
|
+
* registers each middleware; run once by `_boot()`, production-only.
|
|
91
131
|
*/
|
|
92
|
-
private readonly
|
|
132
|
+
private readonly securityAudits;
|
|
133
|
+
/** Registered extensions, in registration order (setup runs at ready()) */
|
|
134
|
+
private readonly extensions;
|
|
135
|
+
/** Registered extension names — enforces uniqueness */
|
|
136
|
+
private readonly extensionNames;
|
|
93
137
|
/**
|
|
94
|
-
*
|
|
138
|
+
* Combined teardown-unit registration order: extension `destroy()`s and
|
|
139
|
+
* {@link onClose} hooks interleaved in the exact order they were registered,
|
|
140
|
+
* so `_shutdown()` can run the whole set in one reverse-of-registration pass
|
|
141
|
+
* (RFC-022 §7.3 — "teardown becomes a flat list of independently-isolated,
|
|
142
|
+
* budget-raced units"). Populated lazily by {@link extend} (for extensions
|
|
143
|
+
* declaring `destroy()`) and {@link onClose}.
|
|
95
144
|
*/
|
|
145
|
+
private readonly teardownUnits;
|
|
146
|
+
/** Whether {@link close} has started — {@link onClose} is a pre-shutdown-only registration point (RFC-022 §8.6). */
|
|
147
|
+
private _closeStarted;
|
|
148
|
+
/** Names decorated onto the app — enforces collision detection */
|
|
149
|
+
private readonly decorations;
|
|
96
150
|
private _errorHandler;
|
|
97
|
-
/**
|
|
98
|
-
* Pluggable logger
|
|
99
|
-
*/
|
|
100
151
|
readonly logger: Logger;
|
|
101
|
-
/**
|
|
102
|
-
* Application options
|
|
103
|
-
*/
|
|
104
152
|
readonly options: ApplicationOptions;
|
|
105
|
-
/**
|
|
106
|
-
* Whether the app is running
|
|
107
|
-
*/
|
|
153
|
+
/** Whether the app is running (server listening) */
|
|
108
154
|
private _isRunning;
|
|
155
|
+
/** Whether the app has been booted (extensions set up, config frozen) */
|
|
156
|
+
private _isReady;
|
|
157
|
+
/** Whether ready() mounted the app-owned router (so close() can undo it) */
|
|
158
|
+
private _routerMounted;
|
|
159
|
+
/** In-flight boot promise — memoized so concurrent ready() calls share one boot (H-1) */
|
|
160
|
+
private _readyPromise;
|
|
161
|
+
/** In-flight shutdown promise — memoized so concurrent close() calls share one (H-3) */
|
|
162
|
+
private _closePromise;
|
|
163
|
+
/** The app-owned router (optional). Route methods delegate to it. */
|
|
164
|
+
readonly router?: Router;
|
|
165
|
+
/** The app-owned DI container (optional). Exposed to extensions and registrars. */
|
|
166
|
+
readonly container?: Container;
|
|
109
167
|
constructor(options?: ApplicationOptions);
|
|
110
|
-
/**
|
|
111
|
-
* Check if running in production
|
|
112
|
-
*/
|
|
168
|
+
/** Check if running in production */
|
|
113
169
|
get isProduction(): boolean;
|
|
114
|
-
/**
|
|
115
|
-
* Check if app is running
|
|
116
|
-
*/
|
|
170
|
+
/** Check if app is running */
|
|
117
171
|
get isRunning(): boolean;
|
|
118
172
|
/**
|
|
119
|
-
*
|
|
173
|
+
* Whether a graceful shutdown is currently in progress — `true` from the
|
|
174
|
+
* moment {@link close} begins tearing down until it completes (F-12:
|
|
175
|
+
* shutdown observability, RFC-022). A readiness check or operator tooling
|
|
176
|
+
* can read this to reflect an in-progress drain.
|
|
120
177
|
*/
|
|
178
|
+
get isDraining(): boolean;
|
|
179
|
+
/** Check if app has been booted via ready() */
|
|
180
|
+
get isReady(): boolean;
|
|
181
|
+
/** Get middleware count */
|
|
121
182
|
get middlewareCount(): number;
|
|
183
|
+
/** Get registered extension count */
|
|
184
|
+
get extensionCount(): number;
|
|
122
185
|
/**
|
|
123
|
-
* Throws if the app is
|
|
124
|
-
* Prevents
|
|
186
|
+
* Throws if the app configuration is frozen (after ready() or start()).
|
|
187
|
+
* Prevents unsafe mutations once the app has booted or is serving traffic.
|
|
125
188
|
*/
|
|
126
|
-
private
|
|
189
|
+
private assertConfigurable;
|
|
127
190
|
/**
|
|
128
191
|
* Register middleware function(s)
|
|
129
192
|
*
|
|
130
|
-
* @param middleware - Middleware function
|
|
193
|
+
* @param middleware - Middleware function(s)
|
|
131
194
|
* @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
195
|
*/
|
|
145
196
|
use(...middleware: Middleware[]): this;
|
|
146
197
|
/**
|
|
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.
|
|
198
|
+
* Mount a router at a path prefix.
|
|
151
199
|
*
|
|
152
|
-
* @param path - Path prefix
|
|
200
|
+
* @param path - Path prefix (e.g. '/api/users')
|
|
153
201
|
* @param router - Router instance to mount
|
|
154
202
|
* @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
203
|
*/
|
|
176
204
|
route(path: string, router: Routable): this;
|
|
205
|
+
private requireRouter;
|
|
206
|
+
/** Register a GET route on the app-owned router. */
|
|
207
|
+
get(path: string, ...entries: RouteEntry[]): this;
|
|
208
|
+
/** Register a POST route on the app-owned router. */
|
|
209
|
+
post(path: string, ...entries: RouteEntry[]): this;
|
|
210
|
+
/** Register a PUT route on the app-owned router. */
|
|
211
|
+
put(path: string, ...entries: RouteEntry[]): this;
|
|
212
|
+
/** Register a PATCH route on the app-owned router. */
|
|
213
|
+
patch(path: string, ...entries: RouteEntry[]): this;
|
|
214
|
+
/** Register a DELETE route on the app-owned router. */
|
|
215
|
+
delete(path: string, ...entries: RouteEntry[]): this;
|
|
216
|
+
/** Register a HEAD route on the app-owned router. */
|
|
217
|
+
head(path: string, ...entries: RouteEntry[]): this;
|
|
177
218
|
/**
|
|
178
|
-
*
|
|
219
|
+
* Register a route for all HTTP methods on the app-owned router.
|
|
179
220
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
*
|
|
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
|
-
* ```
|
|
221
|
+
* @remarks
|
|
222
|
+
* There is intentionally no `app.options()` verb method — it would collide
|
|
223
|
+
* with the `app.options` configuration property. Register OPTIONS routes via
|
|
224
|
+
* `app.all()`, the router directly, or let CORS middleware handle preflight.
|
|
202
225
|
*/
|
|
203
|
-
|
|
226
|
+
all(path: string, ...entries: RouteEntry[]): this;
|
|
204
227
|
/**
|
|
205
|
-
* Set
|
|
228
|
+
* Set the application error handler. Replaces any previously set handler.
|
|
206
229
|
*
|
|
207
230
|
* @param handler - Error handler function
|
|
208
231
|
* @returns this for chaining
|
|
209
|
-
*
|
|
210
|
-
* @deprecated Use `setErrorHandler()` instead — `onError()` implies
|
|
211
|
-
* event subscription (additive), but this is a setter (replaces).
|
|
212
232
|
*/
|
|
213
|
-
|
|
233
|
+
setErrorHandler(handler: ErrorHandler): this;
|
|
214
234
|
/**
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* Handles both sync and async `install()` methods automatically.
|
|
218
|
-
* Returns `this` for sync plugins and `Promise<this>` for async ones.
|
|
235
|
+
* Register an extension. Queues it — `setup()` runs later, at `ready()`,
|
|
236
|
+
* in registration order. Synchronous and chainable.
|
|
219
237
|
*
|
|
220
|
-
* @param
|
|
221
|
-
*
|
|
238
|
+
* @param extension - Extension to register. If it declares a decorated
|
|
239
|
+
* shape via `Extension<TDecorated>`, the return type carries that shape —
|
|
240
|
+
* `app.extend(events<MyEvents>()).events` is statically known, no
|
|
241
|
+
* `declare module` augmentation required.
|
|
242
|
+
* @returns this, intersected with the extension's declared decorated shape
|
|
222
243
|
*
|
|
223
244
|
* @example
|
|
224
245
|
* ```typescript
|
|
225
|
-
*
|
|
226
|
-
* app.
|
|
227
|
-
*
|
|
228
|
-
* // Async plugin — just await it
|
|
229
|
-
* await app.plugin(databasePlugin({ uri: '...' }));
|
|
246
|
+
* const extended = app.extend(events<MyEvents>());
|
|
247
|
+
* await app.ready(); // adapters call this automatically — runs setup()/decorate()
|
|
248
|
+
* extended.events.emit('user:created', { id: '1' }); // available only AFTER ready()
|
|
230
249
|
* ```
|
|
231
250
|
*/
|
|
232
|
-
|
|
251
|
+
extend<TDecorated = Record<string, never>>(extension: Extension<TDecorated>): this & TDecorated;
|
|
233
252
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
* @returns Promise that resolves when plugin is installed
|
|
253
|
+
* Boot the application: run every registered extension's `setup()` once, in
|
|
254
|
+
* registration order, awaiting async setups. Idempotent — safe to call twice.
|
|
255
|
+
* Adapters call this automatically before `start()`.
|
|
238
256
|
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
257
|
+
* After `ready()` resolves, the configuration is frozen (`use`/`route`/`extend`
|
|
258
|
+
* throw).
|
|
241
259
|
*
|
|
242
|
-
* @
|
|
243
|
-
*
|
|
244
|
-
* await app.plugin(new DatabasePlugin({ connectionString: '...' }));
|
|
245
|
-
* ```
|
|
260
|
+
* @returns this
|
|
261
|
+
* @throws if an extension declares a `needs` dependency not yet registered
|
|
246
262
|
*/
|
|
247
|
-
|
|
263
|
+
ready(): Promise<this>;
|
|
248
264
|
/**
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
* @param name - Plugin name
|
|
252
|
-
* @returns Plugin instance or undefined
|
|
265
|
+
* Run the boot sequence once (extension setup + router mount). Guarded and
|
|
266
|
+
* memoized by {@link ready}.
|
|
253
267
|
*/
|
|
254
|
-
|
|
268
|
+
private _boot;
|
|
255
269
|
/**
|
|
256
|
-
*
|
|
270
|
+
* Run every registered middleware's boot-time security audit check
|
|
271
|
+
* (`security-boundaries` capability, task 8.1/8.2). `throw`-level verdicts
|
|
272
|
+
* fail boot immediately; `warn`-level verdicts log once each via the app
|
|
273
|
+
* logger and never block boot. Production-only — `_boot()` calls this
|
|
274
|
+
* conditionally so a dev/test app never pays the cost or sees the noise.
|
|
257
275
|
*/
|
|
258
|
-
|
|
276
|
+
private _runSecurityAudits;
|
|
259
277
|
/**
|
|
260
|
-
*
|
|
278
|
+
* Attach a value to the app under `name`. Extension-author primitive, invoked
|
|
279
|
+
* through {@link ExtensionContext.decorate} — there is intentionally no public
|
|
280
|
+
* `app.decorate()` (RFC §6.1). Throws on collision.
|
|
261
281
|
*
|
|
262
|
-
*
|
|
263
|
-
|
|
282
|
+
* @internal
|
|
283
|
+
*/
|
|
284
|
+
private decorate;
|
|
285
|
+
/**
|
|
286
|
+
* Whether a decoration already occupies `name`.
|
|
287
|
+
*/
|
|
288
|
+
hasDecorator(name: string): boolean;
|
|
289
|
+
/**
|
|
290
|
+
* Create the request handler callback.
|
|
264
291
|
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* handler that includes subsequent registrations.
|
|
292
|
+
* The middleware stack is snapshot at call time — call `ready()` before
|
|
293
|
+
* `callback()` so extension-registered middleware is included. Adapters do
|
|
294
|
+
* this automatically.
|
|
269
295
|
*
|
|
270
296
|
* @returns Request handler function
|
|
271
297
|
*/
|
|
@@ -275,46 +301,58 @@ declare class Application {
|
|
|
275
301
|
*/
|
|
276
302
|
private handleError;
|
|
277
303
|
/**
|
|
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.
|
|
304
|
+
* Default error handler — delegates to the shared error serializer so the
|
|
305
|
+
* default response matches `@nextrush/errors`' `errorHandler()` (audit C-1).
|
|
285
306
|
*/
|
|
286
307
|
private defaultErrorHandler;
|
|
287
308
|
/**
|
|
288
309
|
* Mark app as running and freeze configuration.
|
|
289
310
|
*
|
|
290
|
-
* Called by adapters when the server starts listening
|
|
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.
|
|
311
|
+
* Called by adapters when the server starts listening (after `ready()`).
|
|
295
312
|
*/
|
|
296
313
|
start(): void;
|
|
297
314
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
315
|
+
* Register a teardown hook for a resource outside the extension system
|
|
316
|
+
* (stateful middleware, a manually-attached service, …). Run during
|
|
317
|
+
* {@link close} under the SAME bounded/isolated guarantee as extension
|
|
318
|
+
* `destroy()` — one throwing/hanging hook never strands the others — in one
|
|
319
|
+
* combined reverse-of-registration order together with every `extend()`ed
|
|
320
|
+
* extension's `destroy()` (RFC-022 §8.1/§8.2).
|
|
321
|
+
*
|
|
322
|
+
* @param hook - Teardown callback. May be sync or async; a thrown/rejected
|
|
323
|
+
* hook is isolated and its error collected in {@link close}'s returned array.
|
|
302
324
|
*
|
|
303
|
-
* @
|
|
325
|
+
* @remarks Registration is pre-shutdown only: a hook registered after
|
|
326
|
+
* `close()` has already started is not run in that shutdown (RFC-022 §8.6).
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```typescript
|
|
330
|
+
* const store = new MemoryStore(options);
|
|
331
|
+
* app.onClose(() => store.shutdown());
|
|
332
|
+
* ```
|
|
304
333
|
*/
|
|
305
|
-
|
|
334
|
+
onClose(hook: () => void | Promise<void>): void;
|
|
335
|
+
/**
|
|
336
|
+
* Graceful shutdown. Destroys extensions in reverse registration order,
|
|
337
|
+
* each isolated from the others' failures — one failing/hanging `destroy()`
|
|
338
|
+
* never strands the rest (RFC-022 / ADR-0012).
|
|
339
|
+
*
|
|
340
|
+
* @param options - Optional teardown budget. Omitted = unbounded, byte-identical
|
|
341
|
+
* to today's behavior (`Promise.allSettled`, no timeout). When `timeout` is
|
|
342
|
+
* given, every teardown unit races against it independently; a unit that
|
|
343
|
+
* does not finish in time is reported as a {@link TeardownTimeoutError} in
|
|
344
|
+
* the returned array instead of blocking `close()` past the budget.
|
|
345
|
+
* @returns Array of errors from units that failed or timed out (empty on success)
|
|
346
|
+
*/
|
|
347
|
+
close(options?: CloseOptions): Promise<Error[]>;
|
|
348
|
+
/** Run the shutdown sequence once. Guarded and memoized by {@link close}. */
|
|
349
|
+
private _shutdown;
|
|
306
350
|
}
|
|
307
351
|
/**
|
|
308
352
|
* Create a new Application instance
|
|
309
353
|
*
|
|
310
354
|
* @param options - Application options
|
|
311
355
|
* @returns New Application instance
|
|
312
|
-
*
|
|
313
|
-
* @example
|
|
314
|
-
* ```typescript
|
|
315
|
-
* const app = createApp();
|
|
316
|
-
* const app = createApp({ env: 'production' });
|
|
317
|
-
* ```
|
|
318
356
|
*/
|
|
319
357
|
declare function createApp(options?: ApplicationOptions): Application;
|
|
320
358
|
|
|
@@ -337,8 +375,14 @@ type ComposedMiddleware = (ctx: Context, next?: Next) => Promise<void>;
|
|
|
337
375
|
interface ComposeOptions {
|
|
338
376
|
/**
|
|
339
377
|
* Warn when a middleware sends a response AND calls next().
|
|
340
|
-
*
|
|
341
|
-
* @
|
|
378
|
+
*
|
|
379
|
+
* @remarks
|
|
380
|
+
* Opt-in and defaults to `false` — `@nextrush/core` is a runtime-agnostic
|
|
381
|
+
* package and must not read `process.env` (global-rules §2, audit C-4). The
|
|
382
|
+
* `Application` enables this in non-production by passing the flag from its
|
|
383
|
+
* own `env` option.
|
|
384
|
+
*
|
|
385
|
+
* @default false
|
|
342
386
|
*/
|
|
343
387
|
warnDoubleResponse?: boolean;
|
|
344
388
|
}
|
|
@@ -385,4 +429,4 @@ declare function isMiddleware(fn: unknown): fn is Middleware;
|
|
|
385
429
|
*/
|
|
386
430
|
declare function flattenMiddleware(arr: (Middleware | Middleware[])[]): Middleware[];
|
|
387
431
|
|
|
388
|
-
export { Application, type ApplicationOptions, type ComposeOptions, type ComposedMiddleware, type ErrorHandler, type ListenCallback, type
|
|
432
|
+
export { Application, type ApplicationOptions, type ComposeOptions, type ComposedMiddleware, type ErrorHandler, type ListenCallback, type Routable, compose, createApp, flattenMiddleware, isMiddleware };
|