routup 5.1.1 → 6.0.0-beta.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/README.md +100 -41
- package/dist/bun.d.mts +3 -3
- package/dist/bun.mjs +4 -4
- package/dist/bun.mjs.map +1 -1
- package/dist/cloudflare.d.mts +3 -3
- package/dist/cloudflare.mjs +4 -4
- package/dist/cloudflare.mjs.map +1 -1
- package/dist/deno.d.mts +3 -3
- package/dist/deno.mjs +4 -4
- package/dist/deno.mjs.map +1 -1
- package/dist/generic.d.mts +3 -3
- package/dist/generic.mjs +4 -4
- package/dist/generic.mjs.map +1 -1
- package/dist/index-kxLRw2Wc.d.mts +1950 -0
- package/dist/node.d.mts +4 -4
- package/dist/node.mjs +6 -6
- package/dist/node.mjs.map +1 -1
- package/dist/service-worker.d.mts +3 -3
- package/dist/service-worker.mjs +4 -4
- package/dist/service-worker.mjs.map +1 -1
- package/dist/src-gmPicCWT.mjs +3032 -0
- package/dist/src-gmPicCWT.mjs.map +1 -0
- package/package.json +8 -6
- package/dist/index-CvJhS_a6.d.mts +0 -1128
- package/dist/src-DFLGrih4.mjs +0 -1921
- package/dist/src-DFLGrih4.mjs.map +0 -1
|
@@ -0,0 +1,1950 @@
|
|
|
1
|
+
import QuickLRU from "quick-lru";
|
|
2
|
+
import { FastURL, ServerRequest } from "srvx";
|
|
3
|
+
import { HTTPError, HTTPErrorInput, HTTPErrorInput as HTTPErrorInput$1 } from "@ebec/http";
|
|
4
|
+
import Negotiator from "negotiator";
|
|
5
|
+
import { Key, ParseOptions, PathToRegexpOptions } from "path-to-regexp";
|
|
6
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
7
|
+
|
|
8
|
+
//#region src/error/module.d.ts
|
|
9
|
+
declare const ErrorSymbol: unique symbol;
|
|
10
|
+
declare class AppError extends HTTPError {
|
|
11
|
+
constructor(input?: HTTPErrorInput$1);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/constants.d.ts
|
|
15
|
+
declare const MethodName: {
|
|
16
|
+
readonly GET: "GET";
|
|
17
|
+
readonly POST: "POST";
|
|
18
|
+
readonly PUT: "PUT";
|
|
19
|
+
readonly PATCH: "PATCH";
|
|
20
|
+
readonly DELETE: "DELETE";
|
|
21
|
+
readonly OPTIONS: "OPTIONS";
|
|
22
|
+
readonly HEAD: "HEAD";
|
|
23
|
+
};
|
|
24
|
+
type MethodName = typeof MethodName[keyof typeof MethodName];
|
|
25
|
+
/**
|
|
26
|
+
* `MethodName` plus the open-enum escape hatch for non-standard
|
|
27
|
+
* methods (`PROPFIND`, `MKCOL`, custom verbs). The `(string & {})`
|
|
28
|
+
* intersection is structurally identical to `string` but TypeScript
|
|
29
|
+
* doesn't collapse the union — so callers still get autocomplete
|
|
30
|
+
* for the canonical methods while remaining free to pass anything.
|
|
31
|
+
*/
|
|
32
|
+
type MethodNameLike = MethodName | (string & {});
|
|
33
|
+
declare const HeaderName: {
|
|
34
|
+
readonly ACCEPT: "accept";
|
|
35
|
+
readonly ACCEPT_CHARSET: "accept-charset";
|
|
36
|
+
readonly ACCEPT_ENCODING: "accept-encoding";
|
|
37
|
+
readonly ACCEPT_LANGUAGE: "accept-language";
|
|
38
|
+
readonly ACCEPT_RANGES: "accept-ranges";
|
|
39
|
+
readonly ALLOW: "allow";
|
|
40
|
+
readonly CACHE_CONTROL: "cache-control";
|
|
41
|
+
readonly CONTENT_DISPOSITION: "content-disposition";
|
|
42
|
+
readonly CONTENT_ENCODING: "content-encoding";
|
|
43
|
+
readonly CONTENT_LENGTH: "content-length";
|
|
44
|
+
readonly CONTENT_RANGE: "content-range";
|
|
45
|
+
readonly CONTENT_TYPE: "content-type";
|
|
46
|
+
readonly CONNECTION: "connection";
|
|
47
|
+
readonly COOKIE: "cookie";
|
|
48
|
+
readonly ETag: "etag";
|
|
49
|
+
readonly HOST: "host";
|
|
50
|
+
readonly IF_MODIFIED_SINCE: "if-modified-since";
|
|
51
|
+
readonly IF_NONE_MATCH: "if-none-match";
|
|
52
|
+
readonly LAST_MODIFIED: "last-modified";
|
|
53
|
+
readonly LOCATION: "location";
|
|
54
|
+
readonly RANGE: "range";
|
|
55
|
+
readonly RATE_LIMIT_LIMIT: "ratelimit-limit";
|
|
56
|
+
readonly RATE_LIMIT_REMAINING: "ratelimit-remaining";
|
|
57
|
+
readonly RATE_LIMIT_RESET: "ratelimit-reset";
|
|
58
|
+
readonly RETRY_AFTER: "retry-after";
|
|
59
|
+
readonly SET_COOKIE: "set-cookie";
|
|
60
|
+
readonly TRANSFER_ENCODING: "transfer-encoding";
|
|
61
|
+
readonly X_ACCEL_BUFFERING: "x-accel-buffering";
|
|
62
|
+
readonly X_FORWARDED_HOST: "x-forwarded-host";
|
|
63
|
+
readonly X_FORWARDED_FOR: "x-forwarded-for";
|
|
64
|
+
readonly X_FORWARDED_PROTO: "x-forwarded-proto";
|
|
65
|
+
};
|
|
66
|
+
type HeaderName = typeof HeaderName[keyof typeof HeaderName];
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/event/types.d.ts
|
|
69
|
+
type AppResponse = {
|
|
70
|
+
status: number;
|
|
71
|
+
headers: Headers;
|
|
72
|
+
};
|
|
73
|
+
type AppRequest = ServerRequest;
|
|
74
|
+
type NextFn = (error?: Error) => unknown | Promise<unknown>;
|
|
75
|
+
interface IAppEvent {
|
|
76
|
+
/**
|
|
77
|
+
* The srvx ServerRequest (extends Web Standard Request).
|
|
78
|
+
*/
|
|
79
|
+
readonly request: AppRequest;
|
|
80
|
+
/**
|
|
81
|
+
* Route parameters extracted from the URL path pattern. Values
|
|
82
|
+
* are `string` (or `undefined` for an optional param that
|
|
83
|
+
* didn't match) — both the trie router (`extractTrieParams`)
|
|
84
|
+
* and the linear router (path-to-regexp output) only ever
|
|
85
|
+
* produce string values.
|
|
86
|
+
*/
|
|
87
|
+
readonly params: Record<string, string | undefined>;
|
|
88
|
+
/**
|
|
89
|
+
* Current request path, adjusted relative to the mount point during router nesting.
|
|
90
|
+
*/
|
|
91
|
+
readonly path: string;
|
|
92
|
+
/**
|
|
93
|
+
* HTTP method (GET, POST, PUT, etc.). Typed as the canonical
|
|
94
|
+
* `MethodName` set with an open-enum escape hatch — non-
|
|
95
|
+
* standard methods (`PROPFIND`, custom verbs) still type-check
|
|
96
|
+
* while standard ones autocomplete.
|
|
97
|
+
*/
|
|
98
|
+
readonly method: MethodNameLike;
|
|
99
|
+
/**
|
|
100
|
+
* Accumulated mount path from nested routers.
|
|
101
|
+
*/
|
|
102
|
+
readonly mountPath: string;
|
|
103
|
+
/**
|
|
104
|
+
* Web Standard Headers from the request.
|
|
105
|
+
*/
|
|
106
|
+
readonly headers: Headers;
|
|
107
|
+
/**
|
|
108
|
+
* Lazily-parsed URL search parameters.
|
|
109
|
+
*
|
|
110
|
+
* For advanced query parsing (arrays, nesting), use `@routup/query`.
|
|
111
|
+
*/
|
|
112
|
+
readonly searchParams: URLSearchParams;
|
|
113
|
+
/**
|
|
114
|
+
* Response accumulator — set status/headers before returning a plain value.
|
|
115
|
+
*
|
|
116
|
+
* If the handler returns a `Response` object directly, these values are
|
|
117
|
+
* ignored. They only apply when returning plain values (string, object, etc.)
|
|
118
|
+
* that go through `toResponse()`.
|
|
119
|
+
*/
|
|
120
|
+
readonly response: AppResponse;
|
|
121
|
+
/**
|
|
122
|
+
* Per-request store for caching and plugin state.
|
|
123
|
+
*
|
|
124
|
+
* Use symbol keys (e.g., `Symbol.for('routup:body')`) to avoid collisions.
|
|
125
|
+
* Data is garbage collected with the event when the request completes.
|
|
126
|
+
*/
|
|
127
|
+
readonly store: Record<string | symbol, unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* Pre-resolved router options for the current dispatch context.
|
|
130
|
+
*
|
|
131
|
+
* Contains merged options from the router path stack with defaults applied.
|
|
132
|
+
*/
|
|
133
|
+
readonly appOptions: Readonly<AppOptions>;
|
|
134
|
+
/**
|
|
135
|
+
* Abort signal tied to the request lifecycle.
|
|
136
|
+
*
|
|
137
|
+
* When a `timeout` router option is set, this signal aborts after the
|
|
138
|
+
* specified duration. Handlers performing long I/O (fetch, streams, DB queries)
|
|
139
|
+
* can pass this signal to those operations for cooperative cancellation.
|
|
140
|
+
*/
|
|
141
|
+
readonly signal: AbortSignal;
|
|
142
|
+
/**
|
|
143
|
+
* Call the next handler in the pipeline (onion model).
|
|
144
|
+
*
|
|
145
|
+
* The result is cached — calling `next()` multiple times returns the same response.
|
|
146
|
+
* Returns the downstream `Response`, or `undefined` if no handler matched.
|
|
147
|
+
*/
|
|
148
|
+
next(error?: Error): Promise<Response | undefined>;
|
|
149
|
+
/**
|
|
150
|
+
* Whether `next()` has been invoked on this event.
|
|
151
|
+
*
|
|
152
|
+
* Used by the dispatch pipeline to disambiguate an `undefined` return value:
|
|
153
|
+
* a handler that returns `undefined` after calling `next()` is forwarding the
|
|
154
|
+
* downstream result; one that returns `undefined` without calling `next()` is
|
|
155
|
+
* unresolved and will wait on `signal` (timeout-bounded).
|
|
156
|
+
*/
|
|
157
|
+
readonly nextCalled: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* The cached promise returned by the first `next()` call on this event,
|
|
160
|
+
* or `undefined` if `next()` has not been invoked.
|
|
161
|
+
*/
|
|
162
|
+
readonly nextResult: Promise<Response | undefined> | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Returns a promise that resolves the first time `next()` is invoked on this event.
|
|
165
|
+
*
|
|
166
|
+
* If `next()` has already been called, the returned promise is already resolved.
|
|
167
|
+
* Used by the dispatch pipeline so a handler that returns `undefined` and later
|
|
168
|
+
* calls `next()` asynchronously (e.g. from a `setTimeout`) still propagates the
|
|
169
|
+
* downstream response instead of hanging until `signal` aborts.
|
|
170
|
+
*/
|
|
171
|
+
whenNextCalled(): Promise<void>;
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/event/module.d.ts
|
|
175
|
+
type AppEventCreateContext = {
|
|
176
|
+
request: AppRequest;
|
|
177
|
+
params: Record<string, string | undefined>;
|
|
178
|
+
path: string;
|
|
179
|
+
method: MethodNameLike;
|
|
180
|
+
mountPath: string;
|
|
181
|
+
headers: Headers;
|
|
182
|
+
searchParams: URLSearchParams;
|
|
183
|
+
response: AppResponse;
|
|
184
|
+
store: Record<string | symbol, unknown>;
|
|
185
|
+
signal: AbortSignal;
|
|
186
|
+
appOptions: Readonly<AppOptions>;
|
|
187
|
+
next: (event: IAppEvent, error?: Error) => Promise<Response | undefined>;
|
|
188
|
+
};
|
|
189
|
+
declare class AppEvent implements IAppEvent {
|
|
190
|
+
readonly request: AppRequest;
|
|
191
|
+
readonly params: Record<string, string | undefined>;
|
|
192
|
+
readonly path: string;
|
|
193
|
+
readonly method: MethodNameLike;
|
|
194
|
+
readonly mountPath: string;
|
|
195
|
+
readonly headers: Headers;
|
|
196
|
+
readonly searchParams: URLSearchParams;
|
|
197
|
+
readonly response: AppResponse;
|
|
198
|
+
readonly store: Record<string | symbol, unknown>;
|
|
199
|
+
readonly signal: AbortSignal;
|
|
200
|
+
readonly appOptions: Readonly<AppOptions>;
|
|
201
|
+
protected _context: AppEventCreateContext;
|
|
202
|
+
protected _nextCalled: boolean;
|
|
203
|
+
protected _nextResult: Promise<Response | undefined> | undefined;
|
|
204
|
+
protected _nextCalledDeferred: {
|
|
205
|
+
promise: Promise<void>;
|
|
206
|
+
resolve: () => void;
|
|
207
|
+
} | undefined;
|
|
208
|
+
constructor(context: AppEventCreateContext);
|
|
209
|
+
get nextCalled(): boolean;
|
|
210
|
+
get nextResult(): Promise<Response | undefined> | undefined;
|
|
211
|
+
whenNextCalled(): Promise<void>;
|
|
212
|
+
next(error?: Error): Promise<Response | undefined>;
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/dispatcher/types.d.ts
|
|
216
|
+
interface IDispatcherEvent {
|
|
217
|
+
/**
|
|
218
|
+
* The srvx ServerRequest (extends Web Standard Request).
|
|
219
|
+
*/
|
|
220
|
+
readonly request: AppRequest;
|
|
221
|
+
/**
|
|
222
|
+
* Route parameters extracted from the URL path pattern. Values
|
|
223
|
+
* are `string` (or `undefined` for an optional param that
|
|
224
|
+
* didn't match).
|
|
225
|
+
*/
|
|
226
|
+
params: Record<string, string | undefined>;
|
|
227
|
+
/**
|
|
228
|
+
* Current request path, adjusted relative to the mount point during router nesting.
|
|
229
|
+
*/
|
|
230
|
+
path: string;
|
|
231
|
+
/**
|
|
232
|
+
* HTTP method (GET, POST, PUT, etc.). See `IAppEvent.method`
|
|
233
|
+
* for the open-enum typing rationale.
|
|
234
|
+
*/
|
|
235
|
+
readonly method: MethodNameLike;
|
|
236
|
+
/**
|
|
237
|
+
* Accumulated mount path from nested routers.
|
|
238
|
+
*/
|
|
239
|
+
mountPath: string;
|
|
240
|
+
/**
|
|
241
|
+
* Response accumulator — set status/headers before returning a plain value.
|
|
242
|
+
*/
|
|
243
|
+
readonly response: AppResponse;
|
|
244
|
+
/**
|
|
245
|
+
* Whether a response has been produced.
|
|
246
|
+
*/
|
|
247
|
+
dispatched: boolean;
|
|
248
|
+
/**
|
|
249
|
+
* Error that occurred during dispatch, if any.
|
|
250
|
+
*/
|
|
251
|
+
error?: AppError;
|
|
252
|
+
/**
|
|
253
|
+
* Options of the App currently dispatching this event. Set on
|
|
254
|
+
* entry to `App.dispatch` and restored on exit so nested apps
|
|
255
|
+
* temporarily override the parent's view.
|
|
256
|
+
*/
|
|
257
|
+
appOptions: Readonly<AppOptions>;
|
|
258
|
+
/**
|
|
259
|
+
* `true` while at least one `App.dispatch` is on the call stack
|
|
260
|
+
* for this event. Used by `App.dispatch` to derive whether a
|
|
261
|
+
* given dispatch call is the root (the first one entered) or
|
|
262
|
+
* nested. Saved/restored across the call so nested dispatches
|
|
263
|
+
* leave the flag in the state their caller expects.
|
|
264
|
+
*/
|
|
265
|
+
isDispatching: boolean;
|
|
266
|
+
/**
|
|
267
|
+
* Abort signal for cooperative cancellation.
|
|
268
|
+
*
|
|
269
|
+
* When a `timeout` router option is set, this signal aborts after the
|
|
270
|
+
* specified duration. Handlers can pass it to fetch(), streams, or other
|
|
271
|
+
* AbortSignal-aware APIs.
|
|
272
|
+
*/
|
|
273
|
+
signal: AbortSignal;
|
|
274
|
+
/**
|
|
275
|
+
* Collected allowed methods for the current path (used for OPTIONS / 405 responses).
|
|
276
|
+
*/
|
|
277
|
+
methodsAllowed: Set<string>;
|
|
278
|
+
/**
|
|
279
|
+
* Set the continuation function for this event.
|
|
280
|
+
*
|
|
281
|
+
* Replaces the current continuation. The provided function receives
|
|
282
|
+
* an optional error and may return any value — it will be converted
|
|
283
|
+
* to a `Response` via `toResponse()`.
|
|
284
|
+
*
|
|
285
|
+
* Passing `undefined` clears the continuation function.
|
|
286
|
+
*/
|
|
287
|
+
setNext(fn?: NextFn): void;
|
|
288
|
+
/**
|
|
289
|
+
* Build a public AppEvent from the current dispatch state.
|
|
290
|
+
*
|
|
291
|
+
* Creates a lightweight snapshot with shared references (store, response, headers)
|
|
292
|
+
* and the current App's options. This is the event passed to handler functions.
|
|
293
|
+
*
|
|
294
|
+
* @param signal - Optional AbortSignal override. When provided, the built event
|
|
295
|
+
* uses this signal instead of the dispatcher event's own signal.
|
|
296
|
+
* Used by per-handler timeout to provide a handler-scoped signal.
|
|
297
|
+
*/
|
|
298
|
+
build(signal?: AbortSignal): IAppEvent;
|
|
299
|
+
}
|
|
300
|
+
interface IDispatcher {
|
|
301
|
+
dispatch(event: IDispatcherEvent): Promise<Response | undefined>;
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/dispatcher/module.d.ts
|
|
305
|
+
declare class DispatcherEvent implements IDispatcherEvent {
|
|
306
|
+
readonly request: AppRequest;
|
|
307
|
+
params: Record<string, string | undefined>;
|
|
308
|
+
path: string;
|
|
309
|
+
readonly method: MethodNameLike;
|
|
310
|
+
/**
|
|
311
|
+
* Collected allowed methods (for OPTIONS).
|
|
312
|
+
*/
|
|
313
|
+
methodsAllowed: Set<string>;
|
|
314
|
+
mountPath: string;
|
|
315
|
+
error?: AppError;
|
|
316
|
+
/**
|
|
317
|
+
* Options of the App currently dispatching this event. Set on
|
|
318
|
+
* entry to `App.dispatch` and restored on exit (so nested apps
|
|
319
|
+
* temporarily override). Initialized to `{}` so consumers
|
|
320
|
+
* reading before any dispatch get a valid (empty) shape.
|
|
321
|
+
*/
|
|
322
|
+
appOptions: Readonly<AppOptions>;
|
|
323
|
+
/**
|
|
324
|
+
* `true` while at least one `App.dispatch` is on the call stack
|
|
325
|
+
* for this event. `App.dispatch` reads this on entry to derive
|
|
326
|
+
* `isRoot` and writes it on entry/exit so nested calls see it
|
|
327
|
+
* already set.
|
|
328
|
+
*/
|
|
329
|
+
isDispatching: boolean;
|
|
330
|
+
protected _dispatched: boolean;
|
|
331
|
+
protected _response?: AppResponse;
|
|
332
|
+
protected _store?: Record<string | symbol, unknown>;
|
|
333
|
+
/**
|
|
334
|
+
* Cached parsed URL (avoids double-parsing).
|
|
335
|
+
*/
|
|
336
|
+
protected _url: InstanceType<typeof FastURL>;
|
|
337
|
+
/**
|
|
338
|
+
* Continuation function for middleware onion model.
|
|
339
|
+
*/
|
|
340
|
+
protected _next?: (event: IAppEvent, error?: Error) => Promise<Response | undefined>;
|
|
341
|
+
protected _signal?: AbortSignal;
|
|
342
|
+
protected _signalCleanup?: () => void;
|
|
343
|
+
/**
|
|
344
|
+
* Whether _next has already been called (guard against double-invocation).
|
|
345
|
+
*/
|
|
346
|
+
protected _nextCalled: boolean;
|
|
347
|
+
/**
|
|
348
|
+
* The cached result of the next handler.
|
|
349
|
+
*/
|
|
350
|
+
protected _nextResult?: Promise<Response | undefined>;
|
|
351
|
+
constructor(request: AppRequest);
|
|
352
|
+
get response(): AppResponse;
|
|
353
|
+
get signal(): AbortSignal;
|
|
354
|
+
set signal(value: AbortSignal);
|
|
355
|
+
get dispatched(): boolean;
|
|
356
|
+
set dispatched(value: boolean);
|
|
357
|
+
protected next(event: IAppEvent, error?: Error): Promise<Response | undefined>;
|
|
358
|
+
setNext(fn?: NextFn): void;
|
|
359
|
+
build(signal?: AbortSignal): AppEvent;
|
|
360
|
+
protected get store(): Record<string | symbol, unknown>;
|
|
361
|
+
}
|
|
362
|
+
//#endregion
|
|
363
|
+
//#region src/hook/constants.d.ts
|
|
364
|
+
declare const HookName: {
|
|
365
|
+
/**
|
|
366
|
+
* Fired at the start of `App.dispatch`, before the pipeline walk.
|
|
367
|
+
* Once per router per request.
|
|
368
|
+
*/
|
|
369
|
+
readonly START: "start";
|
|
370
|
+
/**
|
|
371
|
+
* Fired at the end of `App.dispatch`, after the pipeline walk
|
|
372
|
+
* (and OPTIONS auto-Allow synthesis) completes. Once per router per
|
|
373
|
+
* request.
|
|
374
|
+
*/
|
|
375
|
+
readonly END: "end";
|
|
376
|
+
readonly ERROR: "error";
|
|
377
|
+
readonly CHILD_MATCH: "childMatch";
|
|
378
|
+
readonly CHILD_DISPATCH_BEFORE: "childDispatchBefore";
|
|
379
|
+
readonly CHILD_DISPATCH_AFTER: "childDispatchAfter";
|
|
380
|
+
};
|
|
381
|
+
type HookName = typeof HookName[keyof typeof HookName];
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/hook/types.d.ts
|
|
384
|
+
type HookErrorListener = (event: IDispatcherEvent) => Promise<unknown> | unknown;
|
|
385
|
+
type HookDefaultListener = (event: IDispatcherEvent) => Promise<unknown> | unknown;
|
|
386
|
+
type HookListener = HookErrorListener | HookDefaultListener;
|
|
387
|
+
type HookUnsubscribeFn = () => void;
|
|
388
|
+
interface IHooks {
|
|
389
|
+
addListener(name: HookName, fn: HookListener, priority?: number): HookUnsubscribeFn;
|
|
390
|
+
removeListener(name: HookName): void;
|
|
391
|
+
removeListener(name: HookName, fn: HookListener): void;
|
|
392
|
+
removeListener(name: HookName, fn?: HookListener): void;
|
|
393
|
+
/**
|
|
394
|
+
* Returns true if at least one listener is registered for the given
|
|
395
|
+
* hook name. Used by the dispatch pipeline to skip the
|
|
396
|
+
* `await trigger(...)` microtask hop on the hot path when nothing
|
|
397
|
+
* is listening.
|
|
398
|
+
*/
|
|
399
|
+
hasListeners(name: HookName): boolean;
|
|
400
|
+
/**
|
|
401
|
+
* Returns true if at least one listener is registered across *any*
|
|
402
|
+
* hook name. Cheap (single boolean read). Useful as a coarse
|
|
403
|
+
* fast-path guard before any per-name `hasListeners(...)` lookup
|
|
404
|
+
* for apps that never register a hook — the common workload.
|
|
405
|
+
*/
|
|
406
|
+
hasAny(): boolean;
|
|
407
|
+
clone(): IHooks;
|
|
408
|
+
trigger(name: HookName, event: IDispatcherEvent): Promise<void>;
|
|
409
|
+
}
|
|
410
|
+
//#endregion
|
|
411
|
+
//#region src/handler/constants.d.ts
|
|
412
|
+
declare const HandlerType: {
|
|
413
|
+
readonly CORE: "core";
|
|
414
|
+
readonly ERROR: "error";
|
|
415
|
+
};
|
|
416
|
+
type HandlerType = typeof HandlerType[keyof typeof HandlerType];
|
|
417
|
+
declare const HandlerSymbol: unique symbol;
|
|
418
|
+
//#endregion
|
|
419
|
+
//#region src/path/type.d.ts
|
|
420
|
+
type PathMatcherOptions = PathToRegexpOptions & ParseOptions;
|
|
421
|
+
type PathMatcherExecResult = {
|
|
422
|
+
path: string;
|
|
423
|
+
params: Record<string, any>;
|
|
424
|
+
};
|
|
425
|
+
type Path = string;
|
|
426
|
+
interface IPathMatcher {
|
|
427
|
+
test(path: string): boolean;
|
|
428
|
+
exec(path: string): PathMatcherExecResult | undefined;
|
|
429
|
+
}
|
|
430
|
+
//#endregion
|
|
431
|
+
//#region src/path/matcher.d.ts
|
|
432
|
+
declare class PathMatcher implements IPathMatcher {
|
|
433
|
+
protected path: Path;
|
|
434
|
+
protected regexp: RegExp;
|
|
435
|
+
protected regexpKeys: Key[];
|
|
436
|
+
protected regexpOptions: PathMatcherOptions;
|
|
437
|
+
constructor(path: Path, options?: PathMatcherOptions);
|
|
438
|
+
test(path: string): boolean;
|
|
439
|
+
exec(path: string): PathMatcherExecResult | undefined;
|
|
440
|
+
}
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/path/utils.d.ts
|
|
443
|
+
declare function isPath(input: unknown): input is Path;
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region src/handler/types-base.d.ts
|
|
446
|
+
type HandlerBaseOptions = {
|
|
447
|
+
method?: Uppercase<MethodName> | Lowercase<MethodName>;
|
|
448
|
+
path?: Path;
|
|
449
|
+
/**
|
|
450
|
+
* Per-handler timeout in milliseconds.
|
|
451
|
+
*
|
|
452
|
+
* Overrides the router's `handlerTimeout` default. Whether this value
|
|
453
|
+
* can extend or only narrow the default is controlled by the router's
|
|
454
|
+
* `handlerTimeoutOverridable` option.
|
|
455
|
+
*/
|
|
456
|
+
timeout?: number;
|
|
457
|
+
onError?: HookErrorListener;
|
|
458
|
+
onBefore?: HookDefaultListener;
|
|
459
|
+
onAfter?: HookDefaultListener;
|
|
460
|
+
};
|
|
461
|
+
//#endregion
|
|
462
|
+
//#region src/handler/error/types.d.ts
|
|
463
|
+
type ErrorHandler = (error: AppError, event: IAppEvent) => unknown | Promise<unknown>;
|
|
464
|
+
type ErrorHandlerOptions = HandlerBaseOptions & {
|
|
465
|
+
type: typeof HandlerType.ERROR;
|
|
466
|
+
fn: ErrorHandler;
|
|
467
|
+
};
|
|
468
|
+
//#endregion
|
|
469
|
+
//#region src/handler/error/define.d.ts
|
|
470
|
+
/**
|
|
471
|
+
* Create an error handler.
|
|
472
|
+
*
|
|
473
|
+
* Error handlers receive errors thrown by preceding handlers in the pipeline.
|
|
474
|
+
*
|
|
475
|
+
* @param input - Handler function `(error, event) => value` or options object `{ fn, path? }`
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```typescript
|
|
479
|
+
* router.use(defineErrorHandler((error, event) => {
|
|
480
|
+
* return { message: error.message };
|
|
481
|
+
* }));
|
|
482
|
+
* ```
|
|
483
|
+
*/
|
|
484
|
+
declare function defineErrorHandler(input: Omit<ErrorHandlerOptions, 'type'>): Handler;
|
|
485
|
+
declare function defineErrorHandler(input: ErrorHandler): Handler;
|
|
486
|
+
//#endregion
|
|
487
|
+
//#region src/handler/types.d.ts
|
|
488
|
+
type HandlerOptions = CoreHandlerOptions | ErrorHandlerOptions;
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/handler/module.d.ts
|
|
491
|
+
declare class Handler implements IDispatcher {
|
|
492
|
+
protected config: HandlerOptions;
|
|
493
|
+
protected hooks: IHooks;
|
|
494
|
+
readonly method: MethodName | undefined;
|
|
495
|
+
constructor(handler: HandlerOptions);
|
|
496
|
+
get type(): "error" | "core";
|
|
497
|
+
get path(): string | undefined;
|
|
498
|
+
dispatch(event: IDispatcherEvent): Promise<Response | undefined>;
|
|
499
|
+
/**
|
|
500
|
+
* Resolve a handler's return value into the final value handed to `toResponse`.
|
|
501
|
+
*
|
|
502
|
+
* Contract:
|
|
503
|
+
* - non-undefined value → return as-is (becomes the response)
|
|
504
|
+
* - `undefined` + `event.next()` was called → forward downstream result
|
|
505
|
+
* - `undefined` + `event.next()` not yet called → wait until either `next()` is
|
|
506
|
+
* invoked (e.g. from an async callback) or `signal` aborts. A global or
|
|
507
|
+
* per-handler timeout aborts `signal` and surfaces as 408. With no timeout
|
|
508
|
+
* configured and no eventual `next()` call, the request hangs by design.
|
|
509
|
+
*/
|
|
510
|
+
protected resolveHandlerResult(invocation: unknown | Promise<unknown>, handlerEvent: IAppEvent): Promise<unknown>;
|
|
511
|
+
protected executeWithTimeout(fn: () => unknown | Promise<unknown>, effectiveTimeout: number | undefined, controller?: AbortController): Promise<unknown>;
|
|
512
|
+
protected resolveTimeout(appOptions: AppOptions): number | undefined;
|
|
513
|
+
protected mountHooks(): void;
|
|
514
|
+
}
|
|
515
|
+
//#endregion
|
|
516
|
+
//#region src/handler/core/types.d.ts
|
|
517
|
+
type CoreHandler = (event: IAppEvent) => unknown | Promise<unknown>;
|
|
518
|
+
type CoreHandlerOptions = HandlerBaseOptions & {
|
|
519
|
+
type: typeof HandlerType.CORE;
|
|
520
|
+
fn: CoreHandler;
|
|
521
|
+
};
|
|
522
|
+
//#endregion
|
|
523
|
+
//#region src/handler/core/define.d.ts
|
|
524
|
+
/**
|
|
525
|
+
* Create a request handler.
|
|
526
|
+
*
|
|
527
|
+
* @param input - Handler function `(event) => value` or options object `{ fn, path?, method? }`
|
|
528
|
+
*
|
|
529
|
+
* @example
|
|
530
|
+
* ```typescript
|
|
531
|
+
* // Shorthand — function only
|
|
532
|
+
* router.get('/', defineCoreHandler((event) => 'Hello'));
|
|
533
|
+
*
|
|
534
|
+
* // Verbose — with path and method
|
|
535
|
+
* router.use(defineCoreHandler({
|
|
536
|
+
* path: '/users/:id',
|
|
537
|
+
* method: 'GET',
|
|
538
|
+
* fn: (event) => ({ id: event.params.id }),
|
|
539
|
+
* }));
|
|
540
|
+
* ```
|
|
541
|
+
*/
|
|
542
|
+
declare function defineCoreHandler(input: Omit<CoreHandlerOptions, 'type'>): Handler;
|
|
543
|
+
declare function defineCoreHandler(input: CoreHandler): Handler;
|
|
544
|
+
//#endregion
|
|
545
|
+
//#region src/handler/adapters/node/types.d.ts
|
|
546
|
+
type NodeHandler = (req: IncomingMessage, res: ServerResponse) => unknown | Promise<unknown>;
|
|
547
|
+
type NodeMiddleware = (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => unknown | Promise<unknown>;
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/handler/adapters/node/define.d.ts
|
|
550
|
+
/**
|
|
551
|
+
* Wraps a Node.js `(req, res)` handler for use in the routup pipeline.
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```typescript
|
|
555
|
+
* import { fromNodeHandler } from 'routup/node';
|
|
556
|
+
*
|
|
557
|
+
* router.use(fromNodeHandler((req, res) => {
|
|
558
|
+
* res.end('Hello');
|
|
559
|
+
* }));
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
562
|
+
declare function fromNodeHandler(handler: NodeHandler): Handler;
|
|
563
|
+
/**
|
|
564
|
+
* Wraps a Node.js `(req, res, next)` middleware for use in the routup pipeline.
|
|
565
|
+
*
|
|
566
|
+
* @example
|
|
567
|
+
* ```typescript
|
|
568
|
+
* import cors from 'cors';
|
|
569
|
+
* import { fromNodeMiddleware } from 'routup/node';
|
|
570
|
+
*
|
|
571
|
+
* router.use(fromNodeMiddleware(cors()));
|
|
572
|
+
* ```
|
|
573
|
+
*/
|
|
574
|
+
declare function fromNodeMiddleware(handler: NodeMiddleware): Handler;
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/handler/adapters/web/types.d.ts
|
|
577
|
+
/**
|
|
578
|
+
* A plain function that follows the Web Fetch API signature.
|
|
579
|
+
* Compatible with any framework that exposes a fetch-style entry point.
|
|
580
|
+
*/
|
|
581
|
+
interface WebHandler {
|
|
582
|
+
(request: Request): Response | Promise<Response>;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* An object with a `fetch` method (e.g. another router, Hono app, etc.).
|
|
586
|
+
*/
|
|
587
|
+
interface WebHandlerProvider {
|
|
588
|
+
fetch(request: Request): Response | Promise<Response>;
|
|
589
|
+
}
|
|
590
|
+
//#endregion
|
|
591
|
+
//#region src/handler/adapters/web/define.d.ts
|
|
592
|
+
/**
|
|
593
|
+
* Create a handler from a Web Fetch API-compatible function or object.
|
|
594
|
+
*
|
|
595
|
+
* Wraps an external app (e.g. Hono, another App) so it can be mounted
|
|
596
|
+
* via `router.use()`. The original request is passed through as-is.
|
|
597
|
+
*
|
|
598
|
+
* @param input - Fetch function `(request) => Response` or object with a `fetch` method
|
|
599
|
+
*
|
|
600
|
+
* @experimental
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```ts
|
|
604
|
+
* // Mount an object with a fetch method
|
|
605
|
+
* router.use('/api', fromWebHandler(honoApp));
|
|
606
|
+
*
|
|
607
|
+
* // Mount a plain fetch function
|
|
608
|
+
* router.use('/proxy', fromWebHandler((req) => fetch(req)));
|
|
609
|
+
* ```
|
|
610
|
+
*/
|
|
611
|
+
declare function fromWebHandler(input: WebHandler): Handler;
|
|
612
|
+
declare function fromWebHandler(input: WebHandlerProvider): Handler;
|
|
613
|
+
//#endregion
|
|
614
|
+
//#region src/handler/adapters/web/is.d.ts
|
|
615
|
+
declare function isWebHandlerProvider(input: unknown): input is WebHandlerProvider;
|
|
616
|
+
declare function isWebHandler(input: unknown): input is WebHandler;
|
|
617
|
+
//#endregion
|
|
618
|
+
//#region src/handler/is.d.ts
|
|
619
|
+
declare function isHandlerOptions(input: unknown): input is HandlerOptions;
|
|
620
|
+
declare function isHandler(input: unknown): input is Handler;
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region src/handler/utils.d.ts
|
|
623
|
+
/**
|
|
624
|
+
* Match a request method against a handler's bound method.
|
|
625
|
+
*
|
|
626
|
+
* - When the handler has no method bound, matches every request method.
|
|
627
|
+
* - Otherwise matches when the request method is the same.
|
|
628
|
+
* - HEAD requests additionally match GET handlers.
|
|
629
|
+
*/
|
|
630
|
+
declare function matchHandlerMethod(handlerMethod: MethodName | undefined, requestMethod: MethodName): boolean;
|
|
631
|
+
//#endregion
|
|
632
|
+
//#region src/plugin/error/constants.d.ts
|
|
633
|
+
declare const PluginErrorCode: {
|
|
634
|
+
readonly PLUGIN: "PLUGIN";
|
|
635
|
+
readonly NOT_INSTALLED: "PLUGIN_NOT_INSTALLED";
|
|
636
|
+
readonly ALREADY_INSTALLED: "PLUGIN_ALREADY_INSTALLED";
|
|
637
|
+
readonly INSTALL: "PLUGIN_INSTALL";
|
|
638
|
+
};
|
|
639
|
+
type PluginErrorCode = typeof PluginErrorCode[keyof typeof PluginErrorCode];
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region src/plugin/error/module.d.ts
|
|
642
|
+
declare class PluginError extends AppError {
|
|
643
|
+
constructor(input?: HTTPErrorInput);
|
|
644
|
+
}
|
|
645
|
+
//#endregion
|
|
646
|
+
//#region src/plugin/error/is.d.ts
|
|
647
|
+
declare function isPluginError(input: unknown): input is PluginError;
|
|
648
|
+
//#endregion
|
|
649
|
+
//#region src/plugin/error/sub/already-installed.d.ts
|
|
650
|
+
declare class PluginAlreadyInstalledError extends PluginError {
|
|
651
|
+
readonly pluginName: string;
|
|
652
|
+
constructor(pluginName: string);
|
|
653
|
+
}
|
|
654
|
+
//#endregion
|
|
655
|
+
//#region src/plugin/error/sub/install.d.ts
|
|
656
|
+
declare class PluginInstallError extends PluginError {
|
|
657
|
+
readonly pluginName: string;
|
|
658
|
+
constructor(pluginName: string, cause?: Error);
|
|
659
|
+
}
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region src/plugin/error/sub/not-installed.d.ts
|
|
662
|
+
declare class PluginNotInstalledError extends PluginError {
|
|
663
|
+
readonly pluginName: string;
|
|
664
|
+
readonly helperName: string;
|
|
665
|
+
constructor(pluginName: string, helperName: string);
|
|
666
|
+
}
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/plugin/types.d.ts
|
|
669
|
+
type PluginInstallFn = (router: IApp) => any;
|
|
670
|
+
type Plugin = {
|
|
671
|
+
/**
|
|
672
|
+
* The name of the plugin.
|
|
673
|
+
*/
|
|
674
|
+
name: string;
|
|
675
|
+
/**
|
|
676
|
+
* The version of the plugin (semver).
|
|
677
|
+
*/
|
|
678
|
+
version?: string;
|
|
679
|
+
/**
|
|
680
|
+
* The installation function called on registration.
|
|
681
|
+
*/
|
|
682
|
+
install: PluginInstallFn;
|
|
683
|
+
};
|
|
684
|
+
type PluginInstallContext = {
|
|
685
|
+
/**
|
|
686
|
+
* By specifying a path, the plugin will be installed as a child router.
|
|
687
|
+
*/
|
|
688
|
+
path?: Path;
|
|
689
|
+
};
|
|
690
|
+
//#endregion
|
|
691
|
+
//#region src/plugin/is.d.ts
|
|
692
|
+
declare function isPlugin(input: unknown): input is Plugin;
|
|
693
|
+
//#endregion
|
|
694
|
+
//#region src/utils/etag/types.d.ts
|
|
695
|
+
type EtagOptions = {
|
|
696
|
+
/**
|
|
697
|
+
* Create a weak ETag?
|
|
698
|
+
* Output is prefixed with: /W
|
|
699
|
+
*/
|
|
700
|
+
weak?: boolean;
|
|
701
|
+
/**
|
|
702
|
+
* Threshold of bytes from which an etag is generated.
|
|
703
|
+
*
|
|
704
|
+
* default: undefined
|
|
705
|
+
*/
|
|
706
|
+
threshold?: number;
|
|
707
|
+
};
|
|
708
|
+
type EtagFn = (body: string, size?: number) => Promise<string | undefined>;
|
|
709
|
+
type EtagInput = boolean | null | EtagOptions | EtagFn;
|
|
710
|
+
//#endregion
|
|
711
|
+
//#region src/utils/trust-proxy/type.d.ts
|
|
712
|
+
type TrustProxyFn = (address: string, hop: number) => boolean;
|
|
713
|
+
type TrustProxyInput = boolean | number | string | string[] | TrustProxyFn;
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region src/app/constants.d.ts
|
|
716
|
+
declare const AppPipelineStep: {
|
|
717
|
+
readonly START: 0;
|
|
718
|
+
readonly LOOKUP: 1;
|
|
719
|
+
readonly CHILD_BEFORE: 2;
|
|
720
|
+
readonly CHILD_DISPATCH: 3;
|
|
721
|
+
readonly CHILD_AFTER: 4;
|
|
722
|
+
readonly FINISH: 5;
|
|
723
|
+
};
|
|
724
|
+
type AppPipelineStep = typeof AppPipelineStep[keyof typeof AppPipelineStep];
|
|
725
|
+
declare const RouteEntryType: {
|
|
726
|
+
readonly APP: "app";
|
|
727
|
+
readonly HANDLER: "handler";
|
|
728
|
+
};
|
|
729
|
+
type RouteEntryType = typeof RouteEntryType[keyof typeof RouteEntryType];
|
|
730
|
+
//#endregion
|
|
731
|
+
//#region src/cache/types.d.ts
|
|
732
|
+
/**
|
|
733
|
+
* Pluggable cache strategy used by `IRouter` implementations to
|
|
734
|
+
* memoize `lookup(path)` results by request path. The default
|
|
735
|
+
* implementation (`LruCache`) is a `quick-lru`-backed bounded LRU;
|
|
736
|
+
* users can supply their own `ICache` (e.g. wrapping `lru-cache` for
|
|
737
|
+
* TTL/size-based eviction) via `BaseRouterOptions.cache`, or pass
|
|
738
|
+
* `null` to disable caching.
|
|
739
|
+
*
|
|
740
|
+
* The cache is opaque about value type so the same `ICache`
|
|
741
|
+
* implementation can be reused for non-router caching needs.
|
|
742
|
+
*/
|
|
743
|
+
interface ICache<V> {
|
|
744
|
+
/**
|
|
745
|
+
* Return the cached value for `key`, or `undefined` when the key
|
|
746
|
+
* is absent (or has been evicted). Implementations should treat
|
|
747
|
+
* `undefined` as "no entry" — callers cannot store `undefined`.
|
|
748
|
+
* Other falsy values (`null`, `0`, `''`, `false`) are storable
|
|
749
|
+
* and must be returned unchanged on hit.
|
|
750
|
+
*/
|
|
751
|
+
get(key: string): V | undefined;
|
|
752
|
+
/**
|
|
753
|
+
* Store `value` under `key`. Bounded implementations (LRU, TTL,
|
|
754
|
+
* size-based) decide eviction at this point.
|
|
755
|
+
*/
|
|
756
|
+
set(key: string, value: V): void;
|
|
757
|
+
/**
|
|
758
|
+
* Remove a single entry. No-op when `key` is absent.
|
|
759
|
+
*/
|
|
760
|
+
delete(key: string): void;
|
|
761
|
+
/**
|
|
762
|
+
* Drop every entry. Routers call this from inside `add()` so a
|
|
763
|
+
* newly registered route can never be hidden by stale matches
|
|
764
|
+
* cached against an earlier route set.
|
|
765
|
+
*/
|
|
766
|
+
clear(): void;
|
|
767
|
+
/**
|
|
768
|
+
* Return a fresh, **empty** cache of the same shape — same class
|
|
769
|
+
* for leaf implementations. Used by `IRouter.clone()` so the
|
|
770
|
+
* clone preserves the configured cache family (size, eviction
|
|
771
|
+
* policy, …) without inheriting the parent's cached values.
|
|
772
|
+
* Mirrors `IRouter.clone()`.
|
|
773
|
+
*/
|
|
774
|
+
clone(): ICache<V>;
|
|
775
|
+
}
|
|
776
|
+
//#endregion
|
|
777
|
+
//#region src/cache/lru.d.ts
|
|
778
|
+
type LruCacheOptions = {
|
|
779
|
+
/**
|
|
780
|
+
* Maximum number of entries before the least-recently-used entry
|
|
781
|
+
* is evicted on `set`. Default: `1024`.
|
|
782
|
+
*/
|
|
783
|
+
maxSize?: number;
|
|
784
|
+
};
|
|
785
|
+
/**
|
|
786
|
+
* Default `ICache` implementation — a bounded LRU backed by
|
|
787
|
+
* [`quick-lru`](https://github.com/sindresorhus/quick-lru). Picked for
|
|
788
|
+
* its small footprint (~1kB), ESM-only build (matches routup), and
|
|
789
|
+
* stable API.
|
|
790
|
+
*
|
|
791
|
+
* For TTL, size-based eviction, or dispose hooks, write your own
|
|
792
|
+
* `ICache` (e.g. wrapping `lru-cache`) and pass it via the router's
|
|
793
|
+
* `BaseRouterOptions.cache` slot.
|
|
794
|
+
*/
|
|
795
|
+
declare class LruCache<V> implements ICache<V> {
|
|
796
|
+
protected options: LruCacheOptions;
|
|
797
|
+
protected inner: QuickLRU<string, V>;
|
|
798
|
+
constructor(options?: LruCacheOptions);
|
|
799
|
+
get(key: string): V | undefined;
|
|
800
|
+
set(key: string, value: V): void;
|
|
801
|
+
delete(key: string): void;
|
|
802
|
+
clear(): void;
|
|
803
|
+
clone(): ICache<V>;
|
|
804
|
+
}
|
|
805
|
+
//#endregion
|
|
806
|
+
//#region src/types.d.ts
|
|
807
|
+
/**
|
|
808
|
+
* Constraint on `IRouter<T>`'s data slot — routers store object-shaped
|
|
809
|
+
* per-route data (handlers, child apps, custom records). Primitives
|
|
810
|
+
* (`string`, `number`) aren't supported as route data; if you need to
|
|
811
|
+
* carry a primitive, wrap it in an object.
|
|
812
|
+
*/
|
|
813
|
+
type ObjectLiteral = Record<string, any>;
|
|
814
|
+
/**
|
|
815
|
+
* A registered route — what `IRouter.add` consumes. Only `path` and
|
|
816
|
+
* `method` are routing-relevant; `data` is opaque to the router and
|
|
817
|
+
* returned as-is on match. Apps store their own discrimination
|
|
818
|
+
* (e.g. handler-vs-nested-app) inside `data`.
|
|
819
|
+
*
|
|
820
|
+
* **Match-semantics convention:**
|
|
821
|
+
* - `method !== undefined` → router treats the entry as method-bound
|
|
822
|
+
* and matches the path **exactly**.
|
|
823
|
+
* - `method === undefined` → entry is method-agnostic (middleware /
|
|
824
|
+
* nested app) and matches by **prefix**.
|
|
825
|
+
*
|
|
826
|
+
* Custom `IRouter` implementations should honor this convention so
|
|
827
|
+
* apps can swap routers transparently.
|
|
828
|
+
*/
|
|
829
|
+
type Route<T extends ObjectLiteral = ObjectLiteral> = {
|
|
830
|
+
/**
|
|
831
|
+
* Mount path.
|
|
832
|
+
* - `undefined` means "no path" (route matches every request).
|
|
833
|
+
* - `'/'` behaves like "no path" for method-agnostic prefix routes
|
|
834
|
+
* (middleware / mount-less nested apps).
|
|
835
|
+
* - Method-bound `'/'` is treated as an exact root match
|
|
836
|
+
* (`app.get('/', …)` matches only the root).
|
|
837
|
+
*/
|
|
838
|
+
path?: Path;
|
|
839
|
+
/**
|
|
840
|
+
* Bound HTTP method. When set, the router treats this route as an
|
|
841
|
+
* exact match; when undefined, the route matches by prefix.
|
|
842
|
+
*/
|
|
843
|
+
method?: MethodName;
|
|
844
|
+
/**
|
|
845
|
+
* Opaque to the router. Returned via `RouteMatch.route.data` on
|
|
846
|
+
* match; consumers (typically `App`) decide what's inside.
|
|
847
|
+
*/
|
|
848
|
+
data: T;
|
|
849
|
+
};
|
|
850
|
+
/**
|
|
851
|
+
* A single matched route returned by `IRouter.lookup`. The dispatch
|
|
852
|
+
* loop consumes these instead of walking the raw routes — `params`
|
|
853
|
+
* are pre-extracted at lookup time so we don't re-run the matcher
|
|
854
|
+
* later, and `path` (when set) tells the loop how much of
|
|
855
|
+
* `event.path` to strip when recursing into a child app.
|
|
856
|
+
*/
|
|
857
|
+
type RouteMatch<T extends ObjectLiteral = ObjectLiteral> = {
|
|
858
|
+
route: Route<T>;
|
|
859
|
+
/**
|
|
860
|
+
* Registration index in the router. Used by the dispatch loop's
|
|
861
|
+
* `setNext` continuation ("resume from index + 1") and by
|
|
862
|
+
* `App.clone()` to re-register routes in their original order.
|
|
863
|
+
*/
|
|
864
|
+
index: number;
|
|
865
|
+
/**
|
|
866
|
+
* Path params extracted from the route's matcher. Values are
|
|
867
|
+
* `string` (or `undefined` for an optional param that didn't
|
|
868
|
+
* match). Empty object when the route has no path or no params.
|
|
869
|
+
*/
|
|
870
|
+
params: Record<string, string | undefined>;
|
|
871
|
+
/**
|
|
872
|
+
* For routes with a matcher: the path substring the matcher
|
|
873
|
+
* consumed. Used by `executePipelineStepChildDispatch` to strip
|
|
874
|
+
* the matched prefix off `event.path` before dispatching into a
|
|
875
|
+
* child app. Undefined for routes without a matcher.
|
|
876
|
+
*/
|
|
877
|
+
path?: string;
|
|
878
|
+
};
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region src/router/types.d.ts
|
|
881
|
+
/**
|
|
882
|
+
* Options shared by every built-in router. Custom `IRouter`
|
|
883
|
+
* implementations are encouraged to extend this so users can swap
|
|
884
|
+
* routers without rewiring caching.
|
|
885
|
+
*
|
|
886
|
+
* - `cache` (omitted): no caching — every `lookup()` runs the
|
|
887
|
+
* router's full match logic. This is the default.
|
|
888
|
+
* - `cache: <ICache>`: enable lookup memoization. Pass `LruCache`
|
|
889
|
+
* for the built-in bounded LRU, or your own `ICache` (e.g.
|
|
890
|
+
* wrapping `lru-cache` for TTL or size-based eviction).
|
|
891
|
+
*
|
|
892
|
+
* The router is responsible for invalidating its own cache whenever
|
|
893
|
+
* `add()` is called — registering a new route can change the match
|
|
894
|
+
* set for any cached path.
|
|
895
|
+
*/
|
|
896
|
+
type BaseRouterOptions<T extends ObjectLiteral = ObjectLiteral> = {
|
|
897
|
+
cache?: ICache<readonly RouteMatch<T>[]>;
|
|
898
|
+
};
|
|
899
|
+
/**
|
|
900
|
+
* Pluggable strategy for storing routes and answering "which entries
|
|
901
|
+
* match this path?". The default `LinearRouter` walks the stored
|
|
902
|
+
* entries linearly. Alternative implementations (radix tree,
|
|
903
|
+
* aggregated regex, …) can swap in via `AppContext.router` to
|
|
904
|
+
* skip the walk entirely on apps with many routes.
|
|
905
|
+
*
|
|
906
|
+
* The router operates on `Route<T>` where `T` is opaque data; the
|
|
907
|
+
* router never inspects `entry.data`. Only `entry.path` and
|
|
908
|
+
* `entry.method` are routing-relevant.
|
|
909
|
+
*
|
|
910
|
+
* **Match-semantics convention** (custom implementations must honor):
|
|
911
|
+
* - `entry.method !== undefined` → match the path **exactly** (the
|
|
912
|
+
* entry is method-bound, e.g. a verb-shortcut handler).
|
|
913
|
+
* - `entry.method === undefined` → match by **prefix** (middleware,
|
|
914
|
+
* nested apps).
|
|
915
|
+
*
|
|
916
|
+
* Method matching against the request method is kept at the dispatch-
|
|
917
|
+
* loop call site, not here, because method semantics differ between
|
|
918
|
+
* handler and nested-app entries (only handler entries are
|
|
919
|
+
* method-bound).
|
|
920
|
+
*/
|
|
921
|
+
interface IRouter<T extends ObjectLiteral = ObjectLiteral> {
|
|
922
|
+
/**
|
|
923
|
+
* Register a route. Entries are stored in registration order —
|
|
924
|
+
* the order they were passed to `App.use` / `.get` / `.post` /
|
|
925
|
+
* etc. — and lookup results preserve that order.
|
|
926
|
+
*/
|
|
927
|
+
add(route: Route<T>): void;
|
|
928
|
+
/**
|
|
929
|
+
* Return every entry that matches the given path, in registration
|
|
930
|
+
* order. The dispatch loop iterates this list; nested `setNext`
|
|
931
|
+
* re-entries resume from a later index in the same list.
|
|
932
|
+
*
|
|
933
|
+
* `method`, when provided, is the request HTTP method. Routers
|
|
934
|
+
* MAY use it to filter at lookup time (e.g. method-bucketed
|
|
935
|
+
* tries) — but the App's dispatch loop still runs its own
|
|
936
|
+
* method check on every returned match, so a router that
|
|
937
|
+
* ignores `method` and emits more candidates than necessary
|
|
938
|
+
* stays correct, just not optimally fast.
|
|
939
|
+
*
|
|
940
|
+
* When the request method is `OPTIONS` (auto-Allow surface) or
|
|
941
|
+
* `HEAD` (falls through to GET), method-aware routers should
|
|
942
|
+
* widen their emission to cover those cases — see the OPTIONS /
|
|
943
|
+
* HEAD handling notes on `TrieRouter` for the canonical
|
|
944
|
+
* implementation.
|
|
945
|
+
*/
|
|
946
|
+
lookup(path: string, method?: MethodNameLike): readonly RouteMatch<T>[];
|
|
947
|
+
/**
|
|
948
|
+
* Return a fresh, **empty** router of the same shape — same class
|
|
949
|
+
* for leaf implementations; composable wrappers should recursively
|
|
950
|
+
* clone their inner router. Used by `App.install()` and
|
|
951
|
+
* `App.clone()` so plugin sub-apps and cloned apps preserve the
|
|
952
|
+
* active router family instead of silently downgrading to
|
|
953
|
+
* `LinearRouter`.
|
|
954
|
+
*/
|
|
955
|
+
clone(): IRouter<T>;
|
|
956
|
+
}
|
|
957
|
+
//#endregion
|
|
958
|
+
//#region src/app/types.d.ts
|
|
959
|
+
type AppOptions = {
|
|
960
|
+
/**
|
|
961
|
+
* Global request timeout in milliseconds.
|
|
962
|
+
*
|
|
963
|
+
* Applies to the entire dispatch pipeline in `fetch()`. When exceeded,
|
|
964
|
+
* the request is aborted and a 408 response is returned. The AbortSignal
|
|
965
|
+
* on the event is also aborted for cooperative cancellation.
|
|
966
|
+
*/
|
|
967
|
+
timeout?: number;
|
|
968
|
+
/**
|
|
969
|
+
* Default per-handler timeout in milliseconds.
|
|
970
|
+
*
|
|
971
|
+
* Applies individually to each handler's `fn()` execution. Handlers can
|
|
972
|
+
* override this value via their own `timeout` option — see
|
|
973
|
+
* `handlerTimeoutOverridable` to control whether overrides can extend
|
|
974
|
+
* or only narrow this default.
|
|
975
|
+
*/
|
|
976
|
+
handlerTimeout?: number;
|
|
977
|
+
/**
|
|
978
|
+
* Whether handlers can extend the `handlerTimeout` default.
|
|
979
|
+
*
|
|
980
|
+
* When `false` (default), a handler's `timeout` is clamped to
|
|
981
|
+
* `Math.min(handlerTimeout, handler.timeout)`. When `true`, the
|
|
982
|
+
* handler's `timeout` fully replaces the router default.
|
|
983
|
+
*/
|
|
984
|
+
handlerTimeoutOverridable?: boolean;
|
|
985
|
+
/**
|
|
986
|
+
* Number of trailing labels in the request hostname that make up
|
|
987
|
+
* the registrable domain (e.g. `example.com` → 2). Subdomain
|
|
988
|
+
* helpers strip this many labels from the right before returning
|
|
989
|
+
* the subdomain portion.
|
|
990
|
+
*/
|
|
991
|
+
subdomainOffset?: number;
|
|
992
|
+
/**
|
|
993
|
+
* Maximum number of proxy IPs to walk when resolving the client
|
|
994
|
+
* IP from `X-Forwarded-For`. Caps how far back the chain is
|
|
995
|
+
* trusted, regardless of `trustProxy`.
|
|
996
|
+
*/
|
|
997
|
+
proxyIpMax?: number;
|
|
998
|
+
/**
|
|
999
|
+
* ETag generator, or `null` to disable ETag/304 entirely.
|
|
1000
|
+
*
|
|
1001
|
+
* - `undefined` (the default): consumers fall back to a
|
|
1002
|
+
* framework-provided `EtagFn`.
|
|
1003
|
+
* - `null`: explicit opt-out — the response pipeline branches
|
|
1004
|
+
* synchronously and skips the `await applyEtag(...)` microtask hop.
|
|
1005
|
+
* - `EtagFn`: the user's own generator.
|
|
1006
|
+
*/
|
|
1007
|
+
etag?: EtagFn | null;
|
|
1008
|
+
/**
|
|
1009
|
+
* Predicate that decides whether a given upstream address is a
|
|
1010
|
+
* trusted proxy when resolving the client IP / protocol /
|
|
1011
|
+
* hostname from forwarding headers.
|
|
1012
|
+
*/
|
|
1013
|
+
trustProxy?: TrustProxyFn;
|
|
1014
|
+
};
|
|
1015
|
+
/**
|
|
1016
|
+
* User-facing input variant of `AppOptions`.
|
|
1017
|
+
*
|
|
1018
|
+
* Accepts looser shapes for `etag` and `trustProxy` (string,
|
|
1019
|
+
* boolean, list-of-CIDRs, …) which `normalizeAppOptions` lowers to
|
|
1020
|
+
* the resolved `EtagFn | null` / `TrustProxyFn` shape stored on the
|
|
1021
|
+
* App.
|
|
1022
|
+
*/
|
|
1023
|
+
type AppOptionsInput = Omit<AppOptions, 'etag' | 'trustProxy'> & {
|
|
1024
|
+
/**
|
|
1025
|
+
* ETag input — accepts an `EtagFn`, `false`/`null` to disable,
|
|
1026
|
+
* or other shapes accepted by `buildEtagFn`. Normalized to
|
|
1027
|
+
* `EtagFn | null` on the App.
|
|
1028
|
+
*/
|
|
1029
|
+
etag?: EtagInput;
|
|
1030
|
+
/**
|
|
1031
|
+
* Trust-proxy input — accepts a predicate, a list of trusted
|
|
1032
|
+
* CIDRs, `'loopback'`, etc., as accepted by `buildTrustProxyFn`.
|
|
1033
|
+
* Normalized to `TrustProxyFn` on the App.
|
|
1034
|
+
*/
|
|
1035
|
+
trustProxy?: TrustProxyInput;
|
|
1036
|
+
};
|
|
1037
|
+
/**
|
|
1038
|
+
* Constructor input for `App`.
|
|
1039
|
+
*
|
|
1040
|
+
* Splits true runtime options (which propagate to mounted children
|
|
1041
|
+
* via mount-time inheritance) from App-local identity (`name`,
|
|
1042
|
+
* `path`) and constructor injectables (`hooks`, `plugins`,
|
|
1043
|
+
* `router`). Keeping these separate prevents identity from leaking
|
|
1044
|
+
* across the mount boundary — e.g. a parent's `path: '/api'` would
|
|
1045
|
+
* otherwise propagate into a child whose own `path` is unset and
|
|
1046
|
+
* silently double-prefix on registration.
|
|
1047
|
+
*/
|
|
1048
|
+
type AppContext = {
|
|
1049
|
+
/**
|
|
1050
|
+
* Optional label for the App instance.
|
|
1051
|
+
*/
|
|
1052
|
+
name?: string;
|
|
1053
|
+
/**
|
|
1054
|
+
* Registration-time path prefix for entries registered on this
|
|
1055
|
+
* App.
|
|
1056
|
+
*
|
|
1057
|
+
* When set, every entry registered via `use`, `get`, `post`, …
|
|
1058
|
+
* has this prefix prepended to its mount path.
|
|
1059
|
+
* `new App({ path: '/api' })` followed by `app.get('/users', h)`
|
|
1060
|
+
* is equivalent to `app.get('/api/users', h)` on an App without
|
|
1061
|
+
* a `path`.
|
|
1062
|
+
*
|
|
1063
|
+
* Path matching itself still happens inside the active `IRouter`
|
|
1064
|
+
* — this only affects how entries are registered, not how
|
|
1065
|
+
* lookup is performed. Local to this App; not propagated to
|
|
1066
|
+
* mounted children.
|
|
1067
|
+
*/
|
|
1068
|
+
path?: Path;
|
|
1069
|
+
/**
|
|
1070
|
+
* Runtime options that propagate to mounted children via
|
|
1071
|
+
* mount-time inheritance.
|
|
1072
|
+
*/
|
|
1073
|
+
options?: AppOptionsInput;
|
|
1074
|
+
/**
|
|
1075
|
+
* Lifecycle hook registry. Defaults to a fresh `Hooks` instance.
|
|
1076
|
+
* Pass an existing registry to share listeners across Apps (used
|
|
1077
|
+
* by `clone()` to seed the copy with the original's listeners).
|
|
1078
|
+
*/
|
|
1079
|
+
hooks?: IHooks;
|
|
1080
|
+
/**
|
|
1081
|
+
* Map of installed plugin name → version. Defaults to an empty
|
|
1082
|
+
* map. Used by `clone()` to carry the installed-plugin registry
|
|
1083
|
+
* over so duplicate installs are still rejected on the copy.
|
|
1084
|
+
*/
|
|
1085
|
+
plugins?: Map<string, string | undefined>;
|
|
1086
|
+
/**
|
|
1087
|
+
* Pluggable router (route table). Defaults to `LinearRouter` —
|
|
1088
|
+
* walks registered entries linearly per request. Swap in an
|
|
1089
|
+
* alternative (e.g. `TrieRouter`) on apps with many routes.
|
|
1090
|
+
*/
|
|
1091
|
+
router?: IRouter<RouteEntry>;
|
|
1092
|
+
};
|
|
1093
|
+
/**
|
|
1094
|
+
* App-internal data that gets stored as `Route.data` in the active
|
|
1095
|
+
* router. Tagged union — the discriminator `type` (HANDLER / APP)
|
|
1096
|
+
* tells the dispatch loop which branch of the union to read.
|
|
1097
|
+
*
|
|
1098
|
+
* `path` and `method` are not part of this type — they live on
|
|
1099
|
+
* `Route<RouteEntry>` itself (the router's routing-relevant fields),
|
|
1100
|
+
* and App resolves the handler's intrinsic method into `Route.method`
|
|
1101
|
+
* at registration time.
|
|
1102
|
+
*/
|
|
1103
|
+
type AppRouteEntry = {
|
|
1104
|
+
/**
|
|
1105
|
+
* Discriminator marking this entry as a mounted child App (vs a
|
|
1106
|
+
* leaf handler). The dispatch loop branches on this to recurse
|
|
1107
|
+
* via `IApp.dispatch` rather than invoking a handler `fn`.
|
|
1108
|
+
*/
|
|
1109
|
+
type: typeof RouteEntryType.APP;
|
|
1110
|
+
/**
|
|
1111
|
+
* The mounted child App. Path/method live on the wrapping
|
|
1112
|
+
* `Route<RouteEntry>`, not here.
|
|
1113
|
+
*/
|
|
1114
|
+
data: IApp;
|
|
1115
|
+
};
|
|
1116
|
+
/**
|
|
1117
|
+
* Leaf entry in the route table: a handler invoked directly by the
|
|
1118
|
+
* dispatch loop.
|
|
1119
|
+
*/
|
|
1120
|
+
type HandlerRouteEntry = {
|
|
1121
|
+
/**
|
|
1122
|
+
* Discriminator marking this entry as a leaf handler (vs a
|
|
1123
|
+
* mounted child App).
|
|
1124
|
+
*/
|
|
1125
|
+
type: typeof RouteEntryType.HANDLER;
|
|
1126
|
+
/**
|
|
1127
|
+
* The handler invoked when this entry matches. Path/method live
|
|
1128
|
+
* on the wrapping `Route<RouteEntry>`, not here.
|
|
1129
|
+
*/
|
|
1130
|
+
data: Handler;
|
|
1131
|
+
};
|
|
1132
|
+
/**
|
|
1133
|
+
* Tagged union of route-table entries. The active `IRouter` stores
|
|
1134
|
+
* one of these as `Route.data` per registered entry; the dispatch
|
|
1135
|
+
* loop reads `type` to choose the right branch.
|
|
1136
|
+
*/
|
|
1137
|
+
type RouteEntry = AppRouteEntry | HandlerRouteEntry;
|
|
1138
|
+
type AppPipelineContext = {
|
|
1139
|
+
/**
|
|
1140
|
+
* Current pipeline phase — drives the state machine in
|
|
1141
|
+
* `App.executePipelineStep`. Mutated as the loop advances.
|
|
1142
|
+
*/
|
|
1143
|
+
step: AppPipelineStep;
|
|
1144
|
+
/**
|
|
1145
|
+
* The dispatcher event being processed. Carries request, path,
|
|
1146
|
+
* params, and the response accumulator across pipeline steps.
|
|
1147
|
+
*/
|
|
1148
|
+
event: IDispatcherEvent;
|
|
1149
|
+
/**
|
|
1150
|
+
* `true` when this dispatch is the outermost App on the call
|
|
1151
|
+
* stack (the root). Captured in `App.dispatch` from the event's
|
|
1152
|
+
* pre-overwrite `appOptions` and used to gate root-only
|
|
1153
|
+
* behaviour like OPTIONS auto-Allow.
|
|
1154
|
+
*/
|
|
1155
|
+
isRoot: boolean;
|
|
1156
|
+
/**
|
|
1157
|
+
* Position within `matches`. Replaces the old "raw stack index" —
|
|
1158
|
+
* the dispatch loop now iterates the resolved-matches list rather
|
|
1159
|
+
* than the unfiltered registration order.
|
|
1160
|
+
*/
|
|
1161
|
+
matchIndex: number;
|
|
1162
|
+
/**
|
|
1163
|
+
* Resolved matches for the current `event.path`, populated on the
|
|
1164
|
+
* first LOOKUP entry and threaded through `setNext` recursion so
|
|
1165
|
+
* we don't re-run `IRouter.lookup` per cycle. Invalidated
|
|
1166
|
+
* automatically when `event.path` changes (a hook mutating the
|
|
1167
|
+
* path between entries triggers a refresh).
|
|
1168
|
+
*/
|
|
1169
|
+
matches?: readonly RouteMatch<RouteEntry>[];
|
|
1170
|
+
/**
|
|
1171
|
+
* The `event.path` that was used to compute `matches`. Stored so
|
|
1172
|
+
* we can detect a mid-walk path mutation and refresh the cache.
|
|
1173
|
+
*/
|
|
1174
|
+
matchesPath?: string;
|
|
1175
|
+
/**
|
|
1176
|
+
* The Response produced by the pipeline. Set by handlers (via
|
|
1177
|
+
* `toResponse`) or by terminal pipeline steps; returned from
|
|
1178
|
+
* `App.dispatch` once `FINISH` is reached.
|
|
1179
|
+
*/
|
|
1180
|
+
response?: Response;
|
|
1181
|
+
};
|
|
1182
|
+
interface IApp extends IDispatcher {
|
|
1183
|
+
/**
|
|
1184
|
+
* Optional label for the router instance.
|
|
1185
|
+
*/
|
|
1186
|
+
readonly name?: string;
|
|
1187
|
+
/**
|
|
1188
|
+
* Public entry point — processes a request through the pipeline
|
|
1189
|
+
* and returns a Response (with 404/500 fallbacks).
|
|
1190
|
+
*/
|
|
1191
|
+
fetch(request: AppRequest): Promise<Response>;
|
|
1192
|
+
/**
|
|
1193
|
+
* Return a new router that mirrors this one but owns independent
|
|
1194
|
+
* mountable state — fresh stack of shallow-copied entries (handlers and
|
|
1195
|
+
* child routers shared by reference), fresh `Hooks` seeded with the
|
|
1196
|
+
* current listeners, shallow copy of options, and a fresh plugins map.
|
|
1197
|
+
*
|
|
1198
|
+
* Intended for mounting the same logical router under multiple paths
|
|
1199
|
+
* without sharing mutable state across mount points.
|
|
1200
|
+
*/
|
|
1201
|
+
clone(): IApp;
|
|
1202
|
+
/**
|
|
1203
|
+
* Swap the active `IRouter`. Every previously-registered route
|
|
1204
|
+
* is replayed onto the new router so lookups stay correct. Any
|
|
1205
|
+
* cache the previous router carried is dropped along with it.
|
|
1206
|
+
*
|
|
1207
|
+
* Useful when the right router family is only known after
|
|
1208
|
+
* routes are registered (a SmartRouter-style decision), or for
|
|
1209
|
+
* comparing implementations mid-flight without rebuilding the
|
|
1210
|
+
* App.
|
|
1211
|
+
*/
|
|
1212
|
+
setRouter(router: IRouter<RouteEntry>): void;
|
|
1213
|
+
/**
|
|
1214
|
+
* Check if a plugin with the given name is installed on this router.
|
|
1215
|
+
*/
|
|
1216
|
+
hasPlugin(name: string): boolean;
|
|
1217
|
+
/**
|
|
1218
|
+
* Get the version of an installed plugin by name on this router,
|
|
1219
|
+
* or `undefined` if the plugin is not installed here.
|
|
1220
|
+
*/
|
|
1221
|
+
getPluginVersion(name: string): string | undefined;
|
|
1222
|
+
/**
|
|
1223
|
+
* Register a handler, router, or plugin.
|
|
1224
|
+
* When a path is provided, the item is mounted at that path.
|
|
1225
|
+
*/
|
|
1226
|
+
use(router: IApp): this;
|
|
1227
|
+
use(handler: Handler | HandlerOptions): this;
|
|
1228
|
+
use(plugin: Plugin): this;
|
|
1229
|
+
use(path: Path, router: IApp): this;
|
|
1230
|
+
use(path: Path, handler: Handler | HandlerOptions): this;
|
|
1231
|
+
use(path: Path, plugin: Plugin): this;
|
|
1232
|
+
/** Register GET handler(s). */
|
|
1233
|
+
get(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1234
|
+
get(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1235
|
+
/** Register POST handler(s). */
|
|
1236
|
+
post(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1237
|
+
post(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1238
|
+
/** Register PUT handler(s). */
|
|
1239
|
+
put(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1240
|
+
put(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1241
|
+
/** Register PATCH handler(s). */
|
|
1242
|
+
patch(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1243
|
+
patch(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1244
|
+
/** Register DELETE handler(s). */
|
|
1245
|
+
delete(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1246
|
+
delete(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1247
|
+
/** Register HEAD handler(s). */
|
|
1248
|
+
head(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1249
|
+
head(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1250
|
+
/** Register OPTIONS handler(s). */
|
|
1251
|
+
options(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1252
|
+
options(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1253
|
+
/**
|
|
1254
|
+
* Add a hook listener.
|
|
1255
|
+
*/
|
|
1256
|
+
on(name: typeof HookName.START | typeof HookName.END | typeof HookName.CHILD_DISPATCH_BEFORE | typeof HookName.CHILD_DISPATCH_AFTER, fn: HookDefaultListener): HookUnsubscribeFn;
|
|
1257
|
+
on(name: typeof HookName.CHILD_MATCH, fn: HookDefaultListener): HookUnsubscribeFn;
|
|
1258
|
+
on(name: typeof HookName.ERROR, fn: HookErrorListener): HookUnsubscribeFn;
|
|
1259
|
+
/**
|
|
1260
|
+
* Remove a specific or all hook listeners for the given hook name.
|
|
1261
|
+
*/
|
|
1262
|
+
off(name: HookName): this;
|
|
1263
|
+
off(name: HookName, fn: HookListener): this;
|
|
1264
|
+
}
|
|
1265
|
+
//#endregion
|
|
1266
|
+
//#region src/error/create.d.ts
|
|
1267
|
+
/**
|
|
1268
|
+
* Create an internal error object by
|
|
1269
|
+
* - an existing AppError (returned as-is)
|
|
1270
|
+
* - an HTTPError (wrapped into a AppError preserving status)
|
|
1271
|
+
* - an Error (wrapped preserving message and cause)
|
|
1272
|
+
* - an options object (status, message, etc.)
|
|
1273
|
+
* - a message string
|
|
1274
|
+
*
|
|
1275
|
+
* @param input
|
|
1276
|
+
*/
|
|
1277
|
+
declare function createError(input: HTTPErrorInput | unknown): AppError;
|
|
1278
|
+
//#endregion
|
|
1279
|
+
//#region src/error/is.d.ts
|
|
1280
|
+
declare function isError(input: unknown): input is AppError;
|
|
1281
|
+
//#endregion
|
|
1282
|
+
//#region src/response/helpers/cache.d.ts
|
|
1283
|
+
type ResponseCacheHeadersOptions = {
|
|
1284
|
+
maxAge?: number;
|
|
1285
|
+
modifiedTime?: string | Date;
|
|
1286
|
+
cacheControls?: string[];
|
|
1287
|
+
};
|
|
1288
|
+
declare function setResponseCacheHeaders(event: IAppEvent, options?: ResponseCacheHeadersOptions): void;
|
|
1289
|
+
//#endregion
|
|
1290
|
+
//#region src/response/helpers/event-stream/types.d.ts
|
|
1291
|
+
/**
|
|
1292
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format
|
|
1293
|
+
*/
|
|
1294
|
+
type EventStreamMessage = {
|
|
1295
|
+
/**
|
|
1296
|
+
* The event ID to set the EventSource object's last event ID value.
|
|
1297
|
+
*/
|
|
1298
|
+
id?: string;
|
|
1299
|
+
/**
|
|
1300
|
+
* The reconnection time.
|
|
1301
|
+
* If the connection to the server is lost, the browser will wait for the specified time before attempting to reconnect.
|
|
1302
|
+
* This must be an integer, specifying the reconnection time in milliseconds.
|
|
1303
|
+
*/
|
|
1304
|
+
retry?: number;
|
|
1305
|
+
/**
|
|
1306
|
+
* The data field for the message.
|
|
1307
|
+
*/
|
|
1308
|
+
data: string;
|
|
1309
|
+
/**
|
|
1310
|
+
* A string identifying the type of event described.
|
|
1311
|
+
*/
|
|
1312
|
+
event?: string;
|
|
1313
|
+
};
|
|
1314
|
+
type EventStreamListener<T = any> = (err: Error | null, data: T) => void | Promise<void>;
|
|
1315
|
+
//#endregion
|
|
1316
|
+
//#region src/response/helpers/event-stream/module.d.ts
|
|
1317
|
+
type EventStreamOptions = {
|
|
1318
|
+
maxMessageSize?: number;
|
|
1319
|
+
};
|
|
1320
|
+
type EventStreamHandle = {
|
|
1321
|
+
write(message: string | EventStreamMessage): boolean;
|
|
1322
|
+
end(): void;
|
|
1323
|
+
response: Response;
|
|
1324
|
+
};
|
|
1325
|
+
declare function createEventStream(event: IAppEvent, options?: EventStreamOptions): EventStreamHandle;
|
|
1326
|
+
//#endregion
|
|
1327
|
+
//#region src/response/helpers/event-stream/utils.d.ts
|
|
1328
|
+
declare function serializeEventStreamMessage(message: EventStreamMessage): string;
|
|
1329
|
+
//#endregion
|
|
1330
|
+
//#region src/response/helpers/header.d.ts
|
|
1331
|
+
declare function appendResponseHeader(event: IAppEvent, name: string, value: string | string[]): void;
|
|
1332
|
+
declare function appendResponseHeaderDirective(event: IAppEvent, name: string, value: string | string[]): void;
|
|
1333
|
+
//#endregion
|
|
1334
|
+
//#region src/response/helpers/header-disposition.d.ts
|
|
1335
|
+
declare function setResponseHeaderAttachment(event: IAppEvent, filename?: string): void;
|
|
1336
|
+
declare function setResponseHeaderInline(event: IAppEvent, filename?: string): void;
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region src/response/helpers/header-content-type.d.ts
|
|
1339
|
+
declare function setResponseHeaderContentType(event: IAppEvent, input: string, ifNotExists?: boolean): void;
|
|
1340
|
+
//#endregion
|
|
1341
|
+
//#region src/response/helpers/send-accepted.d.ts
|
|
1342
|
+
declare function sendAccepted(event: IAppEvent, data?: unknown): Promise<Response>;
|
|
1343
|
+
//#endregion
|
|
1344
|
+
//#region src/response/helpers/send-created.d.ts
|
|
1345
|
+
declare function sendCreated(event: IAppEvent, data?: unknown): Promise<Response>;
|
|
1346
|
+
//#endregion
|
|
1347
|
+
//#region src/response/helpers/send-file.d.ts
|
|
1348
|
+
type SendFileContentOptions = {
|
|
1349
|
+
end?: number;
|
|
1350
|
+
start?: number;
|
|
1351
|
+
};
|
|
1352
|
+
/**
|
|
1353
|
+
* File metadata used by {@link sendFile}. All fields are optional, but each
|
|
1354
|
+
* missing field disables related response features:
|
|
1355
|
+
*
|
|
1356
|
+
* - `size` — without it, range requests, `Accept-Ranges`, `Content-Length`,
|
|
1357
|
+
* `ETag`, and `Last-Modified` are all omitted (the response is sent
|
|
1358
|
+
* without HTTP-level caching or seekability).
|
|
1359
|
+
* - `mtime` — without it, `Last-Modified` is omitted and the `ETag` is not
|
|
1360
|
+
* emitted (`ETag` requires both `size` and `mtime`).
|
|
1361
|
+
* - `name` — falls back to `SendFileOptions.name` when set; if both are
|
|
1362
|
+
* missing, no `Content-Disposition` or extension-derived
|
|
1363
|
+
* `Content-Type` is set.
|
|
1364
|
+
*/
|
|
1365
|
+
type SendFileStats = {
|
|
1366
|
+
size?: number;
|
|
1367
|
+
mtime?: Date | number | string;
|
|
1368
|
+
name?: string;
|
|
1369
|
+
};
|
|
1370
|
+
type SendFileDisposition = 'attachment' | 'inline';
|
|
1371
|
+
type SendFileContent = ReadableStream | ArrayBuffer | Uint8Array;
|
|
1372
|
+
type SendFileOptions = {
|
|
1373
|
+
stats: (() => Promise<SendFileStats> | SendFileStats) | SendFileStats;
|
|
1374
|
+
content: (options: SendFileContentOptions) => Promise<SendFileContent> | SendFileContent;
|
|
1375
|
+
/**
|
|
1376
|
+
* @deprecated Use `disposition: 'attachment'` instead. Kept for backwards
|
|
1377
|
+
* compatibility — when `disposition` is set, it takes precedence.
|
|
1378
|
+
*/
|
|
1379
|
+
attachment?: boolean;
|
|
1380
|
+
disposition?: SendFileDisposition;
|
|
1381
|
+
name?: string;
|
|
1382
|
+
};
|
|
1383
|
+
declare function sendFile(event: IAppEvent, options: SendFileOptions): Promise<Response>;
|
|
1384
|
+
//#endregion
|
|
1385
|
+
//#region src/response/helpers/send-format.d.ts
|
|
1386
|
+
type ResponseFormatHandler = () => Response | unknown;
|
|
1387
|
+
type ResponseFormats = {
|
|
1388
|
+
default: ResponseFormatHandler;
|
|
1389
|
+
[key: string]: ResponseFormatHandler;
|
|
1390
|
+
};
|
|
1391
|
+
declare function sendFormat(event: IAppEvent, input: ResponseFormats): Response | unknown | undefined;
|
|
1392
|
+
//#endregion
|
|
1393
|
+
//#region src/response/helpers/send-redirect.d.ts
|
|
1394
|
+
declare function sendRedirect(event: IAppEvent, location: string, statusCode?: number): Response;
|
|
1395
|
+
//#endregion
|
|
1396
|
+
//#region src/response/helpers/send-stream.d.ts
|
|
1397
|
+
declare function sendStream(event: IAppEvent, stream: ReadableStream): Response;
|
|
1398
|
+
//#endregion
|
|
1399
|
+
//#region src/response/helpers/utils.d.ts
|
|
1400
|
+
declare function setResponseContentTypeByFileName(event: IAppEvent, fileName: string): void;
|
|
1401
|
+
//#endregion
|
|
1402
|
+
//#region src/response/to-response.d.ts
|
|
1403
|
+
/**
|
|
1404
|
+
* Convert a handler's return value into a Web `Response`.
|
|
1405
|
+
*
|
|
1406
|
+
* Returns synchronously for the common cases (string, JSON object,
|
|
1407
|
+
* binary, stream, blob) when ETag generation is disabled. Returns a
|
|
1408
|
+
* `Promise` when an ETag must be computed (the generator is async).
|
|
1409
|
+
*
|
|
1410
|
+
* Callers that want the async return uniformly can `await` the result
|
|
1411
|
+
* — `await` on a non-Promise still works but pays a microtask hop.
|
|
1412
|
+
* The App fast path branches on `instanceof Promise` to keep the
|
|
1413
|
+
* sync return truly sync.
|
|
1414
|
+
*/
|
|
1415
|
+
declare function toResponse(value: unknown, event: IAppEvent): Response | undefined | Promise<Response | undefined>;
|
|
1416
|
+
//#endregion
|
|
1417
|
+
//#region src/request/helpers/cache.d.ts
|
|
1418
|
+
declare function isRequestCacheable(event: IAppEvent, modifiedTime: string | Date): boolean;
|
|
1419
|
+
//#endregion
|
|
1420
|
+
//#region src/request/helpers/header.d.ts
|
|
1421
|
+
declare function getRequestHeader(event: IAppEvent, name: string): string | null;
|
|
1422
|
+
//#endregion
|
|
1423
|
+
//#region src/request/helpers/header-accept.d.ts
|
|
1424
|
+
declare function getRequestAcceptableContentTypes(event: IAppEvent): string[];
|
|
1425
|
+
declare function getRequestAcceptableContentType(event: IAppEvent, input?: string | string[]): string | undefined;
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region src/request/helpers/header-accept-charset.d.ts
|
|
1428
|
+
declare function getRequestAcceptableCharsets(event: IAppEvent): string[];
|
|
1429
|
+
declare function getRequestAcceptableCharset(event: IAppEvent, input: string | string[]): string | undefined;
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/request/helpers/header-accept-encoding.d.ts
|
|
1432
|
+
declare function getRequestAcceptableEncodings(event: IAppEvent): string[];
|
|
1433
|
+
declare function getRequestAcceptableEncoding(event: IAppEvent, input: string | string[]): string | undefined;
|
|
1434
|
+
//#endregion
|
|
1435
|
+
//#region src/request/helpers/header-accept-language.d.ts
|
|
1436
|
+
declare function getRequestAcceptableLanguages(event: IAppEvent): string[];
|
|
1437
|
+
declare function getRequestAcceptableLanguage(event: IAppEvent, input?: string | string[]): string | undefined;
|
|
1438
|
+
//#endregion
|
|
1439
|
+
//#region src/request/helpers/header-content-type.d.ts
|
|
1440
|
+
declare function matchRequestContentType(event: IAppEvent, contentType: string): boolean;
|
|
1441
|
+
//#endregion
|
|
1442
|
+
//#region src/request/helpers/hostname.d.ts
|
|
1443
|
+
type RequestHostNameOptions = {
|
|
1444
|
+
trustProxy?: TrustProxyInput;
|
|
1445
|
+
};
|
|
1446
|
+
declare function getRequestHostName(event: IAppEvent, options?: RequestHostNameOptions): string | undefined;
|
|
1447
|
+
//#endregion
|
|
1448
|
+
//#region src/request/helpers/ip.d.ts
|
|
1449
|
+
type RequestIpOptions = {
|
|
1450
|
+
trustProxy?: TrustProxyInput;
|
|
1451
|
+
};
|
|
1452
|
+
/**
|
|
1453
|
+
* Get the client IP address from the request.
|
|
1454
|
+
*
|
|
1455
|
+
* When `trustProxy` is configured, walks the `X-Forwarded-For` chain
|
|
1456
|
+
* and returns the rightmost untrusted address (the actual client IP).
|
|
1457
|
+
* Falls back to `event.request.ip` (the direct connection IP).
|
|
1458
|
+
*/
|
|
1459
|
+
declare function getRequestIP(event: IAppEvent, options?: RequestIpOptions): string | undefined;
|
|
1460
|
+
//#endregion
|
|
1461
|
+
//#region src/request/helpers/negotiator.d.ts
|
|
1462
|
+
declare function useRequestNegotiator(event: IAppEvent): Negotiator;
|
|
1463
|
+
//#endregion
|
|
1464
|
+
//#region src/request/helpers/protocol.d.ts
|
|
1465
|
+
type RequestProtocolOptions = {
|
|
1466
|
+
trustProxy?: TrustProxyInput;
|
|
1467
|
+
default?: string;
|
|
1468
|
+
};
|
|
1469
|
+
declare function getRequestProtocol(event: IAppEvent, options?: RequestProtocolOptions): string;
|
|
1470
|
+
//#endregion
|
|
1471
|
+
//#region src/router/linear/module.d.ts
|
|
1472
|
+
/**
|
|
1473
|
+
* Default router — walks registered routes linearly per request and
|
|
1474
|
+
* runs each route's mount-level matcher (built via `buildRoutePathMatcher`,
|
|
1475
|
+
* path-to-regexp-backed). Routes without a mount path (mount-less
|
|
1476
|
+
* middleware / nested apps registered via `.use(handler)`) match every
|
|
1477
|
+
* request directly — there is no per-route `matchPath()` fallback.
|
|
1478
|
+
*
|
|
1479
|
+
* Behaviour-preserving wrapper around the previous in-line stack walk
|
|
1480
|
+
* in `executePipelineStepLookup`. The matcher allocations live here
|
|
1481
|
+
* (not on the registered route), so routers using a different matching
|
|
1482
|
+
* strategy (radix tree, aggregated regex, …) can ignore this file
|
|
1483
|
+
* entirely.
|
|
1484
|
+
*
|
|
1485
|
+
* Optional per-router lookup cache: pass an `ICache` via
|
|
1486
|
+
* `BaseRouterOptions.cache` to skip the linear walk on repeated
|
|
1487
|
+
* requests for the same path. Default is no caching.
|
|
1488
|
+
*/
|
|
1489
|
+
declare class LinearRouter<T extends ObjectLiteral = ObjectLiteral> implements IRouter<T> {
|
|
1490
|
+
protected _routes: Route<T>[];
|
|
1491
|
+
protected _matchers: (IPathMatcher | undefined)[];
|
|
1492
|
+
protected cache?: ICache<readonly RouteMatch<T>[]>;
|
|
1493
|
+
constructor(options?: BaseRouterOptions<T>);
|
|
1494
|
+
add(route: Route<T>): void;
|
|
1495
|
+
lookup(path: string, _method?: MethodNameLike): readonly RouteMatch<T>[];
|
|
1496
|
+
clone(): IRouter<T>;
|
|
1497
|
+
}
|
|
1498
|
+
//#endregion
|
|
1499
|
+
//#region src/router/smart/module.d.ts
|
|
1500
|
+
type SmartRouterOptions<T extends ObjectLiteral = ObjectLiteral> = BaseRouterOptions<T> & {
|
|
1501
|
+
/**
|
|
1502
|
+
* Route count at or above which `SmartRouter` switches from
|
|
1503
|
+
* `LinearRouter` (faster at small N) to `TrieRouter` (faster
|
|
1504
|
+
* at large N). Default `30`.
|
|
1505
|
+
*/
|
|
1506
|
+
threshold?: number;
|
|
1507
|
+
};
|
|
1508
|
+
/**
|
|
1509
|
+
* Auto-selecting router. Accumulates registered routes in a pending
|
|
1510
|
+
* buffer; on the first `lookup()` call, picks `LinearRouter` or
|
|
1511
|
+
* `TrieRouter` based on the registered route count and replays the
|
|
1512
|
+
* pending list onto the chosen inner router. Every subsequent call
|
|
1513
|
+
* — `add`, `lookup`, `clone` — forwards to the inner.
|
|
1514
|
+
*
|
|
1515
|
+
* Use this when you don't want to commit to a router family up-front
|
|
1516
|
+
* (e.g. a library that registers a variable number of routes
|
|
1517
|
+
* depending on configuration). For known workloads, prefer the
|
|
1518
|
+
* concrete router — `SmartRouter` adds one indirection per call.
|
|
1519
|
+
*
|
|
1520
|
+
* Inspired by Hono's `SmartRouter` (which auto-selects across more
|
|
1521
|
+
* candidates including `RegExpRouter`); ours covers the only choice
|
|
1522
|
+
* that matters in routup today: linear-vs-trie at the registration-
|
|
1523
|
+
* size crossover.
|
|
1524
|
+
*/
|
|
1525
|
+
declare class SmartRouter<T extends ObjectLiteral = ObjectLiteral> implements IRouter<T> {
|
|
1526
|
+
protected inner?: IRouter<T>;
|
|
1527
|
+
protected pending: Route<T>[];
|
|
1528
|
+
protected readonly threshold: number;
|
|
1529
|
+
/**
|
|
1530
|
+
* Cache handed off to whichever inner router gets chosen. Stays
|
|
1531
|
+
* `undefined` if the user didn't configure one.
|
|
1532
|
+
*/
|
|
1533
|
+
protected readonly cache?: ICache<readonly RouteMatch<T>[]>;
|
|
1534
|
+
constructor(options?: SmartRouterOptions<T>);
|
|
1535
|
+
add(route: Route<T>): void;
|
|
1536
|
+
lookup(path: string, method?: string): readonly RouteMatch<T>[];
|
|
1537
|
+
clone(): IRouter<T>;
|
|
1538
|
+
/**
|
|
1539
|
+
* Pick the inner router based on the registered route count.
|
|
1540
|
+
* `LinearRouter` for tiny tables, `TrieRouter` past the
|
|
1541
|
+
* configured threshold.
|
|
1542
|
+
*
|
|
1543
|
+
* @protected
|
|
1544
|
+
*/
|
|
1545
|
+
protected choose(): IRouter<T>;
|
|
1546
|
+
}
|
|
1547
|
+
//#endregion
|
|
1548
|
+
//#region src/router/trie/types.d.ts
|
|
1549
|
+
/**
|
|
1550
|
+
* Tagged param-extraction instruction. Built at registration time
|
|
1551
|
+
* during `insertIntoTrie`; consumed at lookup time to build the
|
|
1552
|
+
* params object directly from the request's pre-split segments —
|
|
1553
|
+
* no regex execution per match.
|
|
1554
|
+
*
|
|
1555
|
+
* - `segment`: capture `segments[depth]` as `name`.
|
|
1556
|
+
* - `splat`: capture `segments[depth..]` joined with `/` as `name`.
|
|
1557
|
+
* `name` is `'*'` for the unnamed bare splat (`/files/*`).
|
|
1558
|
+
*/
|
|
1559
|
+
type ParamCapture = {
|
|
1560
|
+
kind: 'segment';
|
|
1561
|
+
depth: number;
|
|
1562
|
+
name: string;
|
|
1563
|
+
} | {
|
|
1564
|
+
kind: 'splat';
|
|
1565
|
+
depth: number;
|
|
1566
|
+
name: string;
|
|
1567
|
+
};
|
|
1568
|
+
/**
|
|
1569
|
+
* Per-variant route record stored at a trie leaf.
|
|
1570
|
+
*
|
|
1571
|
+
* `paramsIndexMap` populated for trie-walked variants so lookup can
|
|
1572
|
+
* extract params without running `matcher.exec`. `matcher` is only
|
|
1573
|
+
* populated for universal-bucket routes (registered paths the trie
|
|
1574
|
+
* parser couldn't handle — regex constraints, compound segments,
|
|
1575
|
+
* escapes — that fall back to path-to-regexp).
|
|
1576
|
+
*
|
|
1577
|
+
* `index` is shared across every variant produced from a single
|
|
1578
|
+
* `add()` call so the candidate list deduplicates naturally on
|
|
1579
|
+
* registration order.
|
|
1580
|
+
*/
|
|
1581
|
+
type IndexedRoute<T extends ObjectLiteral = ObjectLiteral> = {
|
|
1582
|
+
route: Route<T>;
|
|
1583
|
+
index: number;
|
|
1584
|
+
/**
|
|
1585
|
+
* Universal-bucket-only — populated for paths the trie parser
|
|
1586
|
+
* couldn't handle (regex constraints, compound segments, escapes).
|
|
1587
|
+
* The lookup loop runs `matcher.exec(path)` to confirm the match
|
|
1588
|
+
* and extract params, identical to `LinearRouter`.
|
|
1589
|
+
*/
|
|
1590
|
+
matcher?: IPathMatcher;
|
|
1591
|
+
/**
|
|
1592
|
+
* Trie-walked-only — populated for variants that came out of
|
|
1593
|
+
* `parsePath`. The lookup loop walks this list to build the
|
|
1594
|
+
* `params` object directly from request segments, no regex.
|
|
1595
|
+
*/
|
|
1596
|
+
paramsIndexMap?: ParamCapture[];
|
|
1597
|
+
/**
|
|
1598
|
+
* Trie-walked-only — how many request segments this variant
|
|
1599
|
+
* consumes when matched. Used to compute `match.path` (the
|
|
1600
|
+
* matched prefix) at lookup time without re-running a matcher.
|
|
1601
|
+
*
|
|
1602
|
+
* - Exact / prefix variants: `segments.length` (consume up to
|
|
1603
|
+
* the leaf).
|
|
1604
|
+
* - Splat variants: depth of the splat segment (it then absorbs
|
|
1605
|
+
* the rest — see `splatTerminated`).
|
|
1606
|
+
*/
|
|
1607
|
+
matchDepth?: number;
|
|
1608
|
+
/**
|
|
1609
|
+
* Trie-walked-only — `true` when this variant ends in a splat.
|
|
1610
|
+
* `match.path` is then computed from the *full* request length
|
|
1611
|
+
* (the splat absorbed every remaining segment), not from
|
|
1612
|
+
* `matchDepth` (which is only the depth of the splat node).
|
|
1613
|
+
*/
|
|
1614
|
+
splatTerminated?: boolean;
|
|
1615
|
+
};
|
|
1616
|
+
type Segment = {
|
|
1617
|
+
kind: 'static';
|
|
1618
|
+
value: string;
|
|
1619
|
+
} | {
|
|
1620
|
+
kind: 'param';
|
|
1621
|
+
name: string;
|
|
1622
|
+
} | {
|
|
1623
|
+
kind: 'splat';
|
|
1624
|
+
name: string;
|
|
1625
|
+
};
|
|
1626
|
+
/**
|
|
1627
|
+
* Method-keyed bucket of indexed routes. The empty-string key
|
|
1628
|
+
* (`''`) holds method-agnostic entries (handlers registered without
|
|
1629
|
+
* a method binding). Stored as a prototype-less object so user-
|
|
1630
|
+
* controlled method strings can't collide with `Object.prototype`
|
|
1631
|
+
* keys (`__proto__`, `hasOwnProperty`, …).
|
|
1632
|
+
*/
|
|
1633
|
+
type MethodBuckets<T extends ObjectLiteral = ObjectLiteral> = Record<string, IndexedRoute<T>[]>;
|
|
1634
|
+
type TrieNode<T extends ObjectLiteral = ObjectLiteral> = {
|
|
1635
|
+
staticChildren: Map<string, TrieNode<T>>;
|
|
1636
|
+
paramChild?: TrieNode<T>;
|
|
1637
|
+
/**
|
|
1638
|
+
* Entries whose path ends with a splat at this depth (`/files/*`,
|
|
1639
|
+
* `/foo/*name`, …). They match the current node and every deeper
|
|
1640
|
+
* request path. Bucketed by HTTP method (`''` = method-agnostic).
|
|
1641
|
+
*/
|
|
1642
|
+
splatRoutes: MethodBuckets<T>;
|
|
1643
|
+
/**
|
|
1644
|
+
* Exact-match routes whose path ends at this node — only matched
|
|
1645
|
+
* when the request path is fully consumed at this depth.
|
|
1646
|
+
* Bucketed by HTTP method (`''` = method-agnostic).
|
|
1647
|
+
*/
|
|
1648
|
+
exactRoutes: MethodBuckets<T>;
|
|
1649
|
+
/**
|
|
1650
|
+
* Prefix-match routes (middleware / nested apps) whose path ends
|
|
1651
|
+
* at this node — matched whenever this node is reached,
|
|
1652
|
+
* regardless of remaining depth. Not bucketed: middleware is
|
|
1653
|
+
* method-agnostic by design (the inner handler does its own
|
|
1654
|
+
* method discrimination).
|
|
1655
|
+
*/
|
|
1656
|
+
prefixRoutes: IndexedRoute<T>[];
|
|
1657
|
+
};
|
|
1658
|
+
//#endregion
|
|
1659
|
+
//#region src/router/trie/module.d.ts
|
|
1660
|
+
/**
|
|
1661
|
+
* Radix-trie router — registers routes into a per-segment tree at
|
|
1662
|
+
* `add()` time and walks the tree at `lookup()` to collect
|
|
1663
|
+
* candidates by structure rather than by linear scan.
|
|
1664
|
+
*
|
|
1665
|
+
* Inspired by Hono's `TrieRouter` and rou3. The trie handles
|
|
1666
|
+
* routup's path vocabulary directly via its own parser
|
|
1667
|
+
* (`./parser.ts`):
|
|
1668
|
+
*
|
|
1669
|
+
* - Static segments (`/users`)
|
|
1670
|
+
* - Named params (`:id`)
|
|
1671
|
+
* - Optional params (`:id?`) — expanded to two route variants at
|
|
1672
|
+
* registration (T2)
|
|
1673
|
+
* - Optional groups (`/users{/edit}`) — same expansion strategy
|
|
1674
|
+
* - Bare and named splats (`/files/*`, `/files/*rest`)
|
|
1675
|
+
*
|
|
1676
|
+
* Per-leaf storage is bucketed by HTTP method (T4) so lookup
|
|
1677
|
+
* narrows to the request method's bucket(s) instead of emitting
|
|
1678
|
+
* every entry at the leaf and letting the dispatcher's filter
|
|
1679
|
+
* discard mismatches.
|
|
1680
|
+
*
|
|
1681
|
+
* Param extraction is `paramsIndexMap`-driven (T3): a pre-built
|
|
1682
|
+
* `Array<{ depth, name }>` per variant lets `extractTrieParams`
|
|
1683
|
+
* read params straight from the request's pre-split segments — no
|
|
1684
|
+
* regex execution per match.
|
|
1685
|
+
*
|
|
1686
|
+
* Paths the trie parser doesn't handle (compound segments like
|
|
1687
|
+
* `/files/:n.ext`, escape sequences `\:`, regex constraints) and
|
|
1688
|
+
* empty/root paths fall through to the `universal` bucket. That
|
|
1689
|
+
* bucket still uses `path-to-regexp` via `buildRoutePathMatcher`,
|
|
1690
|
+
* so correctness is preserved.
|
|
1691
|
+
*
|
|
1692
|
+
* Pure-static-spine fast path (`shortCircuit`): when the request
|
|
1693
|
+
* walks a static spine with no param/splat/prefix siblings on any
|
|
1694
|
+
* traversed node, the leaf's `exactRoutes` (filtered to the request
|
|
1695
|
+
* method's buckets) is the full answer — no need to walk the param
|
|
1696
|
+
* branch or collect prefix candidates at intermediate nodes.
|
|
1697
|
+
*/
|
|
1698
|
+
declare class TrieRouter<T extends ObjectLiteral = ObjectLiteral> implements IRouter<T> {
|
|
1699
|
+
/**
|
|
1700
|
+
* Monotonic counter assigned as the registration `index` on each
|
|
1701
|
+
* route — the dispatch loop uses it to preserve registration
|
|
1702
|
+
* order across the candidate list. App owns the canonical
|
|
1703
|
+
* `Route<T>[]` list (Plan 019); the trie no longer keeps a
|
|
1704
|
+
* parallel copy.
|
|
1705
|
+
*/
|
|
1706
|
+
protected _routeCount: number;
|
|
1707
|
+
protected root: TrieNode<T>;
|
|
1708
|
+
/**
|
|
1709
|
+
* Routes that bypass the trie — registered with no path, with
|
|
1710
|
+
* the root path `/`, or with a path containing syntax the
|
|
1711
|
+
* parser doesn't recognise. Walked linearly on every lookup,
|
|
1712
|
+
* merged into the result in registration order.
|
|
1713
|
+
*/
|
|
1714
|
+
protected universal: IndexedRoute<T>[];
|
|
1715
|
+
protected cache?: ICache<readonly RouteMatch<T>[]>;
|
|
1716
|
+
constructor(options?: BaseRouterOptions<T>);
|
|
1717
|
+
add(route: Route<T>): void;
|
|
1718
|
+
lookup(path: string, method?: MethodNameLike): readonly RouteMatch<T>[];
|
|
1719
|
+
clone(): IRouter<T>;
|
|
1720
|
+
/**
|
|
1721
|
+
* T1: returns the pre-computed candidate list when the request's
|
|
1722
|
+
* static spine has no param sibling, no prefix routes, and no
|
|
1723
|
+
* splats along the way. The leaf node's `exactRoutes` (filtered
|
|
1724
|
+
* to the request method's buckets) is then the complete answer —
|
|
1725
|
+
* no need to walk the param branch or collect prefix/splat
|
|
1726
|
+
* candidates from intermediate nodes. When any branch is
|
|
1727
|
+
* encountered, returns `null` and the caller falls through to
|
|
1728
|
+
* the regular `walk`.
|
|
1729
|
+
*/
|
|
1730
|
+
protected shortCircuit(segments: string[], method: MethodNameLike | undefined): IndexedRoute<T>[] | null;
|
|
1731
|
+
protected parseRequestPath(path: string): string[];
|
|
1732
|
+
protected insertIntoTrie(segments: Segment[], route: Route<T>, index: number): void;
|
|
1733
|
+
protected walk(node: TrieNode<T>, segments: string[], depth: number, collected: IndexedRoute<T>[], method: MethodNameLike | undefined): void;
|
|
1734
|
+
protected isExactMatchRoute(route: Route<T>): boolean;
|
|
1735
|
+
/**
|
|
1736
|
+
* T5: copy params onto a prototype-less object so downstream
|
|
1737
|
+
* lookups skip prototype-chain traversal and avoid `__proto__` /
|
|
1738
|
+
* `hasOwnProperty` shadowing from user-controlled segment values.
|
|
1739
|
+
*/
|
|
1740
|
+
protected assignParams(source: Record<string, string | undefined>): Record<string, string | undefined>;
|
|
1741
|
+
}
|
|
1742
|
+
//#endregion
|
|
1743
|
+
//#region src/router/utils.d.ts
|
|
1744
|
+
/**
|
|
1745
|
+
* Build a path-to-regexp-backed `PathMatcher` for the route's mount
|
|
1746
|
+
* path, applying the exact-vs-prefix convention every router should
|
|
1747
|
+
* agree on:
|
|
1748
|
+
*
|
|
1749
|
+
* - `route.method !== undefined` → exact match (method-bound route)
|
|
1750
|
+
* - `route.method === undefined` → prefix match (middleware / nested
|
|
1751
|
+
* app)
|
|
1752
|
+
*
|
|
1753
|
+
* Returns `undefined` when the route has no mount path — middleware
|
|
1754
|
+
* registered without a path matches every request.
|
|
1755
|
+
*
|
|
1756
|
+
* Routers are free to ignore this helper and build their own match
|
|
1757
|
+
* mechanism (radix tree, single aggregated regex, etc.) — it's
|
|
1758
|
+
* provided as a convenience for routers that want path-to-regexp
|
|
1759
|
+
* semantics with minimal boilerplate.
|
|
1760
|
+
*/
|
|
1761
|
+
declare function buildRoutePathMatcher<T extends ObjectLiteral = ObjectLiteral>(route: Route<T>): IPathMatcher | undefined;
|
|
1762
|
+
//#endregion
|
|
1763
|
+
//#region src/app/module.d.ts
|
|
1764
|
+
declare class App implements IApp {
|
|
1765
|
+
/**
|
|
1766
|
+
* A label for the router instance.
|
|
1767
|
+
*/
|
|
1768
|
+
readonly name?: string;
|
|
1769
|
+
/**
|
|
1770
|
+
* Registration-time path prefix for entries registered on this
|
|
1771
|
+
* App. Local to this instance — never inherited from a parent.
|
|
1772
|
+
*
|
|
1773
|
+
* @protected
|
|
1774
|
+
*/
|
|
1775
|
+
protected _path?: Path;
|
|
1776
|
+
/**
|
|
1777
|
+
* Pluggable router (route table) — owns the "which entries match
|
|
1778
|
+
* this path?" lookup. Defaults to `LinearRouter` (walks entries
|
|
1779
|
+
* linearly per request); swap in via `AppContext.router`
|
|
1780
|
+
* for a radix/trie implementation on apps with many routes.
|
|
1781
|
+
*
|
|
1782
|
+
* @protected
|
|
1783
|
+
*/
|
|
1784
|
+
protected router: IRouter<RouteEntry>;
|
|
1785
|
+
/**
|
|
1786
|
+
* Lifecycle hook registry.
|
|
1787
|
+
*
|
|
1788
|
+
* @protected
|
|
1789
|
+
*/
|
|
1790
|
+
protected hooks: IHooks;
|
|
1791
|
+
/**
|
|
1792
|
+
* Normalized options for this App instance.
|
|
1793
|
+
*
|
|
1794
|
+
* Frozen on construction and on every `extendOptions` update —
|
|
1795
|
+
* once published to `event.appOptions` it is shared across all
|
|
1796
|
+
* requests, and a handler must not be able to mutate
|
|
1797
|
+
* router-global state. `extendOptions` therefore uses a
|
|
1798
|
+
* functional update (build a new object, freeze it, replace
|
|
1799
|
+
* the slot) rather than mutating in place.
|
|
1800
|
+
*/
|
|
1801
|
+
protected _options: Readonly<AppOptions>;
|
|
1802
|
+
/**
|
|
1803
|
+
* Registry of installed plugins (name → version) on this router.
|
|
1804
|
+
*
|
|
1805
|
+
* @protected
|
|
1806
|
+
*/
|
|
1807
|
+
protected plugins: Map<string, string | undefined>;
|
|
1808
|
+
/**
|
|
1809
|
+
* Every route registered on this App, in registration order.
|
|
1810
|
+
*
|
|
1811
|
+
* App owns the canonical list — the `IRouter` contract has no
|
|
1812
|
+
* `routes` field, so cascades / clones / `setRouter` replay
|
|
1813
|
+
* read from here instead of asking the router. Routes are
|
|
1814
|
+
* pushed alongside every `this.router.add()` via the `register`
|
|
1815
|
+
* helper.
|
|
1816
|
+
*
|
|
1817
|
+
* @protected
|
|
1818
|
+
*/
|
|
1819
|
+
protected _routes: Route<RouteEntry>[];
|
|
1820
|
+
constructor(input?: AppContext);
|
|
1821
|
+
/**
|
|
1822
|
+
* Register a route with the active router and record it on the
|
|
1823
|
+
* App so we can replay it onto a different router later (see
|
|
1824
|
+
* `setRouter`) and so cascades / clones have a source of truth
|
|
1825
|
+
* independent of the router instance.
|
|
1826
|
+
*
|
|
1827
|
+
* @protected
|
|
1828
|
+
*/
|
|
1829
|
+
protected register(route: Route<RouteEntry>): void;
|
|
1830
|
+
/**
|
|
1831
|
+
* Swap the active router. Replays every previously-registered
|
|
1832
|
+
* route onto the new router so lookups stay correct.
|
|
1833
|
+
*
|
|
1834
|
+
* Useful for picking a router after route shape is known (e.g.
|
|
1835
|
+
* a SmartRouter-style decision), or for testing alternatives
|
|
1836
|
+
* mid-flight without rebuilding the App. Any cache the previous
|
|
1837
|
+
* router carried is dropped along with it.
|
|
1838
|
+
*/
|
|
1839
|
+
setRouter(router: IRouter<RouteEntry>): void;
|
|
1840
|
+
/**
|
|
1841
|
+
* Public entry point — creates a DispatcherEvent from the request,
|
|
1842
|
+
* runs the pipeline, and returns a Response (with 404/500 fallbacks).
|
|
1843
|
+
*/
|
|
1844
|
+
fetch(request: AppRequest): Promise<Response>;
|
|
1845
|
+
protected buildFallbackResponse(request: AppRequest, event: IDispatcherEvent, status: number, message: string): Response;
|
|
1846
|
+
/**
|
|
1847
|
+
* Mount-time option inheritance — fill in any of this App's
|
|
1848
|
+
* unset option keys from the supplied parent options. Called by
|
|
1849
|
+
* `App.use(child)` after narrowing to `App` via `isAppInstance`.
|
|
1850
|
+
*
|
|
1851
|
+
* Public so callers don't need to reach into another App's
|
|
1852
|
+
* protected fields: the parent passes its options by value and
|
|
1853
|
+
* the child decides what to do with them.
|
|
1854
|
+
*
|
|
1855
|
+
* Shallow per-key merge. App-local concerns — `name`, `path`,
|
|
1856
|
+
* `hooks`, `plugins`, `router`, and the router's cache — are
|
|
1857
|
+
* deliberately not propagated; they sit on `AppContext`, not
|
|
1858
|
+
* inside `AppOptions`.
|
|
1859
|
+
*
|
|
1860
|
+
* Cascades to any Apps already mounted on this one — a deeper
|
|
1861
|
+
* grandchild gets the new keys too. Without this, mounting
|
|
1862
|
+
* grandchild → child → parent in that order would leave the
|
|
1863
|
+
* grandchild without parent's options (it adopted from child
|
|
1864
|
+
* before child had them).
|
|
1865
|
+
*
|
|
1866
|
+
* Late mutation of the parent's options after this call does NOT
|
|
1867
|
+
* propagate. `AppOptions` is configured at construction-and-mount;
|
|
1868
|
+
* later changes are not a supported workflow.
|
|
1869
|
+
*/
|
|
1870
|
+
extendOptions(incoming: Readonly<AppOptions>): void;
|
|
1871
|
+
protected executePipelineStep(context: AppPipelineContext): Promise<void>;
|
|
1872
|
+
protected executePipelineStepStart(context: AppPipelineContext): Promise<void>;
|
|
1873
|
+
protected executePipelineStepLookup(context: AppPipelineContext): Promise<void>;
|
|
1874
|
+
protected executePipelineStepChildBefore(context: AppPipelineContext): Promise<void>;
|
|
1875
|
+
protected executePipelineStepChildAfter(context: AppPipelineContext): Promise<void>;
|
|
1876
|
+
protected executePipelineStepChildDispatch(context: AppPipelineContext): Promise<void>;
|
|
1877
|
+
protected executePipelineStepFinish(context: AppPipelineContext): Promise<void>;
|
|
1878
|
+
dispatch(event: IDispatcherEvent): Promise<Response | undefined>;
|
|
1879
|
+
delete(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1880
|
+
delete(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1881
|
+
get(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1882
|
+
get(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1883
|
+
post(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1884
|
+
post(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1885
|
+
put(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1886
|
+
put(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1887
|
+
patch(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1888
|
+
patch(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1889
|
+
head(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1890
|
+
head(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1891
|
+
options(...handlers: (Handler | HandlerOptions)[]): this;
|
|
1892
|
+
options(path: Path, ...handlers: (Handler | HandlerOptions)[]): this;
|
|
1893
|
+
protected useForMethod(method: MethodName, ...input: (Path | Handler | HandlerOptions)[]): void;
|
|
1894
|
+
use(router: IApp): this;
|
|
1895
|
+
use(handler: Handler | HandlerOptions): this;
|
|
1896
|
+
use(plugin: Plugin): this;
|
|
1897
|
+
use(path: Path, router: IApp): this;
|
|
1898
|
+
use(path: Path, handler: Handler | HandlerOptions): this;
|
|
1899
|
+
use(path: Path, plugin: Plugin): this;
|
|
1900
|
+
/**
|
|
1901
|
+
* Check if a plugin with the given name is installed on this router.
|
|
1902
|
+
*/
|
|
1903
|
+
hasPlugin(name: string): boolean;
|
|
1904
|
+
/**
|
|
1905
|
+
* Get the version of an installed plugin by name on this router,
|
|
1906
|
+
* or `undefined` if the plugin is not installed here.
|
|
1907
|
+
*/
|
|
1908
|
+
getPluginVersion(name: string): string | undefined;
|
|
1909
|
+
protected install(plugin: Plugin, context?: PluginInstallContext): this;
|
|
1910
|
+
/**
|
|
1911
|
+
* Return a new `App` that mirrors this one but owns independent
|
|
1912
|
+
* mountable state.
|
|
1913
|
+
*
|
|
1914
|
+
* The new router has:
|
|
1915
|
+
* - a fresh `stack` array of shallow-copied entries (handlers and child
|
|
1916
|
+
* routers are shared by reference; only the wrapping entries are new)
|
|
1917
|
+
* - the same `pathMatcher` reference (it is stateless)
|
|
1918
|
+
* - a fresh `Hooks` instance seeded with the current listeners
|
|
1919
|
+
* - a shallow copy of `_options`
|
|
1920
|
+
* - a fresh `plugins` map with the same entries
|
|
1921
|
+
*
|
|
1922
|
+
* Use this when the same logical router needs to be mounted under
|
|
1923
|
+
* multiple paths — each mount can receive its own clone so subsequent
|
|
1924
|
+
* mutations on one mount do not bleed into the others.
|
|
1925
|
+
*/
|
|
1926
|
+
clone(): IApp;
|
|
1927
|
+
/**
|
|
1928
|
+
* Add a hook listener.
|
|
1929
|
+
*
|
|
1930
|
+
* @param name
|
|
1931
|
+
* @param fn
|
|
1932
|
+
* @param priority
|
|
1933
|
+
*/
|
|
1934
|
+
on(name: typeof HookName.START | typeof HookName.END | typeof HookName.CHILD_DISPATCH_BEFORE | typeof HookName.CHILD_DISPATCH_AFTER, fn: HookDefaultListener, priority?: number): HookUnsubscribeFn;
|
|
1935
|
+
on(name: typeof HookName.CHILD_MATCH, fn: HookDefaultListener, priority?: number): HookUnsubscribeFn;
|
|
1936
|
+
on(name: typeof HookName.ERROR, fn: HookErrorListener, priority?: number): HookUnsubscribeFn;
|
|
1937
|
+
/**
|
|
1938
|
+
* Remove single or all hook listeners.
|
|
1939
|
+
*
|
|
1940
|
+
* @param name
|
|
1941
|
+
*/
|
|
1942
|
+
off(name: HookName): this;
|
|
1943
|
+
off(name: HookName, fn: HookListener): this;
|
|
1944
|
+
}
|
|
1945
|
+
//#endregion
|
|
1946
|
+
//#region src/app/options.d.ts
|
|
1947
|
+
declare function normalizeAppOptions(input: AppOptionsInput): AppOptions;
|
|
1948
|
+
//#endregion
|
|
1949
|
+
export { createError as $, HandlerSymbol as $t, sendFormat as A, isWebHandlerProvider as At, setResponseHeaderAttachment as B, CoreHandlerOptions as Bt, getRequestAcceptableContentTypes as C, isPluginError as Ct, setResponseContentTypeByFileName as D, isHandler as Dt, toResponse as E, matchHandlerMethod as Et, SendFileStats as F, fromNodeMiddleware as Ft, EventStreamHandle as G, ErrorHandlerOptions as Gt, appendResponseHeader as H, HandlerOptions as Ht, sendFile as I, NodeHandler as It, EventStreamListener as J, PathMatcher as Jt, EventStreamOptions as K, HandlerBaseOptions as Kt, sendCreated as L, NodeMiddleware as Lt, SendFileContentOptions as M, WebHandler as Mt, SendFileDisposition as N, WebHandlerProvider as Nt, sendStream as O, isHandlerOptions as Ot, SendFileOptions as P, fromNodeHandler as Pt, isError as Q, PathMatcherOptions as Qt, sendAccepted as R, defineCoreHandler as Rt, getRequestAcceptableContentType as S, PluginAlreadyInstalledError as St, isRequestCacheable as T, PluginErrorCode as Tt, appendResponseHeaderDirective as U, defineErrorHandler as Ut, setResponseHeaderInline as V, Handler as Vt, serializeEventStreamMessage as W, ErrorHandler as Wt, ResponseCacheHeadersOptions as X, Path as Xt, EventStreamMessage as Y, IPathMatcher as Yt, setResponseCacheHeaders as Z, PathMatcherExecResult as Zt, getRequestAcceptableLanguages as _, Plugin as _t, SmartRouter as a, AppEventCreateContext as an, HandlerRouteEntry as at, getRequestAcceptableCharset as b, PluginNotInstalledError as bt, RequestProtocolOptions as c, IAppEvent as cn, BaseRouterOptions as ct, RequestIpOptions as d, MethodName as dn, Route as dt, HandlerType as en, AppContext as et, getRequestIP as f, MethodNameLike as fn, RouteMatch as ft, getRequestAcceptableLanguage as g, isPlugin as gt, matchRequestContentType as h, HTTPErrorInput$1 as hn, ICache as ht, TrieRouter as i, AppEvent as in, AppRouteEntry as it, SendFileContent as j, fromWebHandler as jt, sendRedirect as k, isWebHandler as kt, getRequestProtocol as l, NextFn as ln, IRouter as lt, getRequestHostName as m, ErrorSymbol as mn, LruCacheOptions as mt, App as n, IDispatcher as nn, AppOptionsInput as nt, SmartRouterOptions as o, AppRequest as on, IApp as ot, RequestHostNameOptions as p, AppError as pn, LruCache as pt, createEventStream as q, isPath as qt, buildRoutePathMatcher as r, IDispatcherEvent as rn, AppPipelineContext as rt, LinearRouter as s, AppResponse as sn, RouteEntry as st, normalizeAppOptions as t, DispatcherEvent as tn, AppOptions as tt, useRequestNegotiator as u, HeaderName as un, ObjectLiteral as ut, getRequestAcceptableEncoding as v, PluginInstallContext as vt, getRequestHeader as w, PluginError as wt, getRequestAcceptableCharsets as x, PluginInstallError as xt, getRequestAcceptableEncodings as y, PluginInstallFn as yt, setResponseHeaderContentType as z, CoreHandler as zt };
|
|
1950
|
+
//# sourceMappingURL=index-kxLRw2Wc.d.mts.map
|