@orkestrel/router 0.0.1 → 0.0.3

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.
@@ -1,445 +0,0 @@
1
- import type { EmitterErrorHandler, EmitterHooks, EmitterInterface } from '@orkestrel/emitter';
2
- /**
3
- * The identifier START characters an identifier-grammar param name may
4
- * begin with — mirrors the runtime classifier's `[A-Za-z_]` head class
5
- * (`classifySegment` / `compilePath`, `helpers.ts`).
6
- */
7
- export type IdentifierStartChar = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '_';
8
- /**
9
- * The identifier CONTINUATION characters after the first — mirrors the
10
- * runtime classifier's `[A-Za-z0-9_]*` tail class.
11
- */
12
- export type IdentifierChar = IdentifierStartChar | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
13
- export type TakeIdentifierTail<S extends string, Acc extends string> = S extends `${infer Head}${infer Tail}` ? Head extends IdentifierChar ? TakeIdentifierTail<Tail, `${Acc}${Head}`> : Acc : Acc;
14
- export type IdentifierHead<S extends string> = S extends `${infer Head}${infer Tail}` ? Head extends IdentifierStartChar ? TakeIdentifierTail<Tail, Head> : '' : '';
15
- export type SegmentParam<Segment extends string> = Segment extends `:${infer Rest}` ? IdentifierHead<Rest> extends infer Name extends string ? Name extends '' ? unknown : {
16
- readonly [K in Name]: string;
17
- } : unknown : Segment extends `*${infer Rest}` ? IdentifierHead<Rest> extends infer Name extends string ? Name extends '' ? unknown : {
18
- readonly [K in Name]: string;
19
- } : unknown : unknown;
20
- /**
21
- * Recursive, unflattened param extraction for {@link PathParams} — walks a
22
- * path pattern segment by segment (split on `/`), extracting each segment's
23
- * {@link SegmentParam} contribution and intersecting the rest.
24
- *
25
- * @typeParam Path - The path pattern literal being decomposed
26
- *
27
- * @remarks
28
- * Splits `Path` at its first `/` into `Segment` + `Rest`, intersects
29
- * `SegmentParam<Segment>` with the recursive walk of `Rest`, and — once no
30
- * further `/` remains — resolves the final segment's own `SegmentParam`
31
- * directly. `SegmentParam` mirrors the runtime `classifySegment` grammar
32
- * exactly: a `:name` HEAD (identifier-char run, stopping at the first
33
- * non-identifier char) captures a param; a segment whose `:` is not at the
34
- * segment START (`a:b`) contributes nothing (the classification fix, §4); a
35
- * final `*name` wildcard captures the rest-of-path param the same way. A
36
- * fully parameterless `Path` resolves to `unknown` here (the intersection
37
- * identity every non-capturing segment contributes) — {@link PathParams}
38
- * flattens that down to a clean empty record. This type is exported so
39
- * {@link PathParams} (which flattens it into a clean mapped type for IDE
40
- * hovers) has a documented, testable recursive step; consumers reach for the
41
- * flattened {@link PathParams} form, never this raw recursion.
42
- */
43
- export type PathParamsRaw<Path extends string> = string extends Path ? Readonly<Record<string, string>> : Path extends `${infer Segment}/${infer Rest}` ? SegmentParam<Segment> & PathParamsRaw<Rest> : SegmentParam<Path>;
44
- /**
45
- * Extracts `{ name: string }` param records from a path pattern at the type
46
- * level — the typed half of the path grammar (§4).
47
- *
48
- * @typeParam Path - A route path pattern literal (`/users/:id/posts/:slug`,
49
- * `/files/*rest`, or a parameterless literal path)
50
- *
51
- * @remarks
52
- * A `:name` segment contributes `{ name: string }`; a trailing `*name`
53
- * wildcard (the grammar's only allowed wildcard position) contributes
54
- * `{ name: string }` capturing the rest of the path; a parameterless pattern
55
- * resolves to an empty record. Built over {@link PathParamsRaw} and flattened
56
- * through an identity-mapped type so editor hovers show the resolved shape
57
- * (`{ id: string; slug: string }`) rather than an unresolved intersection.
58
- *
59
- * @example
60
- * ```ts
61
- * type A = PathParams<'/users/:id/posts/:slug'> // { readonly id: string; readonly slug: string }
62
- * type B = PathParams<'/files/*rest'> // { readonly rest: string }
63
- * type C = PathParams<'/health'> // Record<string, never>
64
- * ```
65
- */
66
- export type PathParams<Path extends string> = {
67
- readonly [K in keyof PathParamsRaw<Path>]: PathParamsRaw<Path>[K];
68
- };
69
- /**
70
- * A compiled route path — the anchored regex plus its ordered param names.
71
- *
72
- * @remarks
73
- * The once-per-path compile output of `compilePath` (U1 `helpers.ts`):
74
- * `regex` is anchored (`^…$`) and matches the WHOLE pathname (with an
75
- * optional trailing slash, §4), and `params` lists each captured segment's
76
- * name (`:name` or the final `*name`) in order, so a `regex.exec` result's
77
- * capture groups line up with `params` positionally (the walk `matchPath`
78
- * performs). Plain data — no behavior.
79
- */
80
- export interface CompiledPath {
81
- readonly regex: RegExp;
82
- readonly params: readonly string[];
83
- }
84
- /**
85
- * One registered route in a {@link RouterInterface} — the `path` pattern plus
86
- * the opaque `meta` payload to return on a match, with an optional `name`.
87
- *
88
- * @typeParam Meta - The payload to carry on a match (opaque to the engine —
89
- * a route handler + method on the `Dispatcher`, a component/loader
90
- * reference on the `Navigator`)
91
- *
92
- * @remarks
93
- * - `path` — the `/`-prefixed route path pattern (`/users/:id`); compiled
94
- * once at registration.
95
- * - `meta` — the opaque payload returned (as {@link RouterMatch.meta}) when
96
- * this entry is the most-specific match. The engine never inspects it —
97
- * the consumer's {@link AnswerHandler} predicate (the override seam)
98
- * decides eligibility from it.
99
- * - `name` — an optional route identifier, carried through onto a match for
100
- * consumers that build named links or debug output.
101
- */
102
- export interface RouteEntry<Meta> {
103
- readonly path: string;
104
- readonly meta: Meta;
105
- readonly name?: string;
106
- }
107
- /**
108
- * One matched route — the winning entry's PATTERN, decoded params, `meta`
109
- * payload, and optional `name`.
110
- *
111
- * @typeParam Meta - The payload the winning entry carries
112
- *
113
- * @remarks
114
- * What {@link RouterInterface.match} returns on a hit (`undefined` on a
115
- * miss). `path` is the winning entry's REGISTERED PATTERN (not the concrete
116
- * pathname that was matched) — useful for consumers that need to know which
117
- * route fired. `params` is a frozen `name → value` record (empty for a
118
- * parameterless path), each value URL-decoded with a malformed `%` escape
119
- * tolerated as a literal (§4, never throws). Plain data — no behavior.
120
- */
121
- export interface RouterMatch<Meta> {
122
- readonly path: string;
123
- readonly params: Readonly<Record<string, string>>;
124
- readonly meta: Meta;
125
- readonly name?: string;
126
- }
127
- /**
128
- * The native-override seam — a predicate deciding whether an entry's `meta`
129
- * ANSWERS a given `match` call, beyond path matching.
130
- *
131
- * @typeParam Meta - The entry payload the predicate reads
132
- *
133
- * @remarks
134
- * The single seam the philosophy's "one engine, native overrides" principle
135
- * hangs on: the `Dispatcher` passes a method-check (`(record) => record.method
136
- * === requestMethod`), the `Navigator` omits the predicate entirely (every
137
- * path match always answers). Passed per-call to {@link RouterInterface.match};
138
- * when omitted, every entry whose path matches is eligible. Total — it never
139
- * throws (a consumer keeps it pure, per AGENTS §14 guard totality).
140
- */
141
- export type AnswerHandler<Meta> = (meta: Meta) => boolean;
142
- /**
143
- * Options for `createRouter` — an optional initial entry set, the case-
144
- * sensitivity toggle, and the dedup identity function.
145
- *
146
- * @typeParam Meta - The entry payload type
147
- *
148
- * @remarks
149
- * - `entries` — the initial `{ path, meta, name? }` entries to register (each
150
- * path compiled once), equivalent to a bare `createRouter()` followed by
151
- * `add(entries)`. Omitted ⇒ an empty router.
152
- * - `sensitive` — case-sensitive path matching (default `true`, §4). Set
153
- * `false` to fold case during matching (`/Users` matches `/users`);
154
- * registered patterns are never case-folded in storage, only in matching.
155
- * - `key` — an optional dedup identity function computed per entry
156
- * (`RouteEntry<Meta> → string`). When provided, registering an entry whose
157
- * key already exists REPLACES the prior entry in place (last write wins,
158
- * no engine rebuild) instead of adding a second candidate. Omitted ⇒ every
159
- * registered entry is kept, even duplicate paths.
160
- */
161
- export interface RouterOptions<Meta> {
162
- readonly entries?: readonly RouteEntry<Meta>[];
163
- readonly sensitive?: boolean;
164
- readonly key?: (entry: RouteEntry<Meta>) => string;
165
- }
166
- /**
167
- * The path-matching + registry engine contract (the §4.5 behavioral-interface
168
- * role for the one-class-per-file `Router`). Registers `{ path, meta, name? }`
169
- * entries (compiling each path once) and resolves a concrete pathname to the
170
- * MOST SPECIFIC matching entry — a literal segment beats a param beats a
171
- * wildcard at the earliest differing segment, registration-order-independent
172
- * (§4). The shared engine both the `Navigator` (browser) and the `Dispatcher`
173
- * (core, method-dimensioned) compose.
174
- *
175
- * @typeParam Meta - The opaque payload each entry carries and a match returns
176
- *
177
- * @remarks
178
- * - `count` — the number of registered entries.
179
- * - `add(entry)` / `add(entries)` — register ONE / MANY entries (§9.2 batch);
180
- * each path is compiled once here. When constructed with a `key` option,
181
- * an entry whose key already exists replaces the prior one in place;
182
- * otherwise every entry is kept, even duplicate paths.
183
- * - `match(pathname, answers?)` — the MOST-SPECIFIC matching entry as a
184
- * {@link RouterMatch} (its winning `path`, decoded `params`, `meta`, and
185
- * `name`), or `undefined`. The optional {@link AnswerHandler} predicate
186
- * filters candidates by `meta` first; omitted ⇒ every path match is
187
- * eligible.
188
- * - `entries()` — ALL registered entries in registration order.
189
- * - `entries(pathname)` — only entries whose path matches `pathname` (the
190
- * §9 plural accessor's filtered form; backs a consumer's allow/405 set).
191
- * - `group(prefix)` — a {@link GroupInterface} scoped under `prefix`; entries
192
- * added through the group are registered on this same router with `prefix`
193
- * prepended to each path.
194
- * - `clear()` — drop every entry (§10), leaving the router reusable.
195
- */
196
- export interface RouterInterface<Meta> {
197
- readonly count: number;
198
- add(entry: RouteEntry<Meta>): void;
199
- add(entries: readonly RouteEntry<Meta>[]): void;
200
- match(pathname: string, answers?: AnswerHandler<Meta>): RouterMatch<Meta> | undefined;
201
- entries(): readonly RouteEntry<Meta>[];
202
- entries(pathname: string): readonly RouteEntry<Meta>[];
203
- group(prefix: string): GroupInterface<Meta>;
204
- clear(): void;
205
- }
206
- /**
207
- * A prefix-scoped registration handle over a {@link RouterInterface} — pure
208
- * string composition (§4.2.2), no independent state or storage.
209
- *
210
- * @typeParam Meta - The entry payload type, matching the owning router
211
- *
212
- * @remarks
213
- * - `prefix` — the path prefix this group prepends to every entry it
214
- * registers (and to every nested group's own prefix).
215
- * - `add(entry)` / `add(entries)` — register ONE / MANY entries on the
216
- * OWNING router, each entry's `path` composed as `prefix + entry.path`
217
- * (§9.2 batch, mirroring {@link RouterInterface.add}).
218
- * - `group(prefix)` — a nested group whose prefix is `this.prefix + prefix`;
219
- * nesting composes prefixes left to right with no depth limit.
220
- */
221
- export interface GroupInterface<Meta> {
222
- readonly prefix: string;
223
- add(entry: RouteEntry<Meta>): void;
224
- add(entries: readonly RouteEntry<Meta>[]): void;
225
- group(prefix: string): GroupInterface<Meta>;
226
- }
227
- /**
228
- * The seven HTTP methods a {@link DispatcherInterface} dimensions dispatch
229
- * over — the value-level counterpart is {@link import('./constants.js').METHODS}.
230
- *
231
- * @remarks
232
- * `HEAD` is a valid explicit registration even though a `GET` route already
233
- * auto-answers `HEAD` (§5.1 dispatch semantics) — an explicit `HEAD` handler
234
- * always takes precedence over the derived one.
235
- */
236
- export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
237
- /**
238
- * The ambient context a {@link RouteHandler} receives alongside the raw
239
- * `Request` — decoded params, the winning pattern, the parsed URL, and the
240
- * consumer's opaque per-request state.
241
- *
242
- * @typeParam Path - The route path pattern the handler was registered under
243
- * (drives the typed shape of `params` via {@link PathParams})
244
- * @typeParam TState - The consumer's opaque per-request state type
245
- *
246
- * @remarks
247
- * - `params` — the decoded param record, typed from `Path` via
248
- * {@link PathParams} (empty for a parameterless path).
249
- * - `pattern` — the winning REGISTERED pattern (matches
250
- * {@link RouterMatch.path}), useful for logging/metrics.
251
- * - `url` — the request URL, already parsed once by the dispatcher.
252
- * - `state` — the consumer's per-request payload (logger, session, DI bag),
253
- * threaded opaquely through `handle()` — the router never inspects it.
254
- */
255
- export interface RouteContext<Path extends string = string, TState = undefined> {
256
- readonly params: PathParams<Path>;
257
- readonly pattern: string;
258
- readonly url: URL;
259
- readonly state: TState;
260
- }
261
- /**
262
- * A route handler — receives the raw fetch `Request` plus its typed
263
- * {@link RouteContext} and returns (or resolves) a fetch `Response`.
264
- *
265
- * @typeParam Path - The route path pattern the handler is registered under
266
- * @typeParam TState - The consumer's opaque per-request state type
267
- *
268
- * @remarks
269
- * A handler throw propagates to the caller of `dispatcher.handle` — the
270
- * dispatcher never invents an error boundary; mapping throws to responses is
271
- * the consuming server's policy (§5.1).
272
- */
273
- export type RouteHandler<Path extends string = string, TState = undefined> = (request: Request, context: RouteContext<Path, TState>) => Response | Promise<Response>;
274
- /**
275
- * One route registration input for {@link DispatcherInterface.add} — the
276
- * method-dimensioned counterpart of {@link RouteEntry}.
277
- *
278
- * @typeParam Path - The route path pattern literal (drives the typed
279
- * `handler`'s `context.params` via {@link PathParams})
280
- * @typeParam TState - The consumer's opaque per-request state type
281
- *
282
- * @remarks
283
- * - `method` — the HTTP method this route answers.
284
- * - `path` — the `/`-prefixed route path pattern.
285
- * - `handler` — the {@link RouteHandler} invoked on a match.
286
- * - `name` — an optional route identifier, carried through onto a
287
- * {@link RouterMatch}.
288
- */
289
- export interface RouteInput<Path extends string = string, TState = undefined> {
290
- readonly method: Method;
291
- readonly path: Path;
292
- readonly handler: RouteHandler<Path, TState>;
293
- readonly name?: string;
294
- }
295
- /**
296
- * The `meta` payload a {@link DispatcherInterface} stores in its underlying
297
- * `Router` — what {@link RouterInterface.match} returns as
298
- * {@link RouterMatch.meta} on a dispatch hit.
299
- *
300
- * @typeParam TState - The consumer's opaque per-request state type
301
- *
302
- * @remarks
303
- * The handler is typed over `string` (not the original literal `Path`) at
304
- * storage — path-specific param typing is recovered at the call site through
305
- * {@link RouteInput}'s generic `Path`, not preserved in the stored record.
306
- */
307
- export interface RouteRecord<TState> {
308
- readonly method: Method;
309
- readonly handler: RouteHandler<string, TState>;
310
- readonly name?: string;
311
- }
312
- /**
313
- * The outcome of {@link DispatcherInterface.match} — a discriminated union
314
- * over the three dispatch tiers: a full hit, a path-matches-but-method-
315
- * doesn't (405 territory), or nothing matched at all (404 territory).
316
- *
317
- * @typeParam TState - The consumer's opaque per-request state type
318
- *
319
- * @remarks
320
- * - `'matched'` — carries the winning {@link RouterMatch} (its `meta` is a
321
- * {@link RouteRecord}).
322
- * - `'unmethoded'` — the pathname matched at least one entry but none for
323
- * the requested method; `allow` is the derived `Allow` method set (from
324
- * `router.entries(pathname)`).
325
- * - `'unmatched'` — no registered pattern matches the pathname at all.
326
- */
327
- export type DispatchResult<TState> = {
328
- readonly status: 'matched';
329
- readonly match: RouterMatch<RouteRecord<TState>>;
330
- } | {
331
- readonly status: 'unmethoded';
332
- readonly allow: readonly Method[];
333
- } | {
334
- readonly status: 'unmatched';
335
- };
336
- /**
337
- * The `Dispatcher`'s event map (AGENTS §13) — the two dispatch-outcome
338
- * signals a consumer can observe alongside the return value of `handle`.
339
- *
340
- * @remarks
341
- * - `match` — emitted on every dispatch that resolves to a handler
342
- * (including the auto-`HEAD`/auto-`OPTIONS` derived cases): the request
343
- * `method` and the winning `pattern`.
344
- * - `miss` — emitted on every non-matching dispatch: the RAW request
345
- * `method` (a plain `string`, not narrowed to {@link Method} — an unknown
346
- * verb like `PURGE` is observable here exactly as sent, never coerced),
347
- * the raw `pathname`, and which tier missed (`'unmatched'` — nothing
348
- * matched the path at all; `'unmethoded'` — the path matched but not the
349
- * method, including an unknown verb against a path with other registered
350
- * methods).
351
- */
352
- export type DispatcherEventMap = {
353
- readonly match: readonly [method: Method, pattern: string];
354
- readonly miss: readonly [method: string, pathname: string, reason: 'unmatched' | 'unmethoded'];
355
- };
356
- /**
357
- * Options for `createDispatcher` — initial routes, case sensitivity, the two
358
- * default-responder overrides, and the AGENTS §13 emitter wiring.
359
- *
360
- * @typeParam TState - The consumer's opaque per-request state type
361
- *
362
- * @remarks
363
- * - `routes` — the initial route inputs to register, equivalent to a bare
364
- * `createDispatcher()` followed by `add(routes)`. Omitted ⇒ no routes.
365
- * - `sensitive` — forwarded to the underlying `Router` (default `true`, §4).
366
- * - `unmatched` — the responder invoked when nothing matches the pathname at
367
- * all (default: a `404` `Response`).
368
- * - `unmethoded` — the responder invoked when the pathname matches but not
369
- * the method, given the derived `Allow` set (default: a `405` `Response`
370
- * with an `Allow` header).
371
- * - `on` — initial `DispatcherEventMap` listeners (AGENTS §8/§13).
372
- * - `error` — the emitter's own listener-error handler (AGENTS §13),
373
- * forwarded alongside `on`.
374
- */
375
- export interface DispatcherOptions<TState> {
376
- readonly routes?: readonly RouteInput<string, TState>[];
377
- readonly sensitive?: boolean;
378
- readonly unmatched?: (request: Request) => Response | Promise<Response>;
379
- readonly unmethoded?: (request: Request, allow: readonly Method[]) => Response | Promise<Response>;
380
- readonly on?: EmitterHooks<DispatcherEventMap>;
381
- readonly error?: EmitterErrorHandler;
382
- }
383
- /**
384
- * The fetch-standard, method-dimensioned dispatch entity contract (the §4.5
385
- * behavioral-interface role for the one-class-per-file `Dispatcher`). Layers
386
- * HTTP method dispatch and web-standard `Request`/`Response` handling over a
387
- * single internal `Router<RouteRecord<TState>>`.
388
- *
389
- * @typeParam TState - The consumer's opaque per-request state type, threaded
390
- * into every {@link RouteContext} (default `undefined` for stateless use)
391
- *
392
- * @remarks
393
- * - `router` — the underlying registry, exposed READONLY for introspection
394
- * (the same object `add`/`group`/`match` operate on).
395
- * - `emitter` — the AGENTS §13 observable surface for {@link DispatcherEventMap}.
396
- * - `add(input)` / `add(inputs)` — register ONE / MANY {@link RouteInput}s
397
- * (§9.2 batch); throws `TypeError` on a malformed registration (a
398
- * non-`/`-prefixed path, a non-function handler, or a method outside
399
- * {@link import('./constants.js').METHODS}) — the construction/registration
400
- * boundary guard (§14); `match`/`handle` hot paths carry zero guards.
401
- * - `group(prefix)` — a {@link DispatchGroupInterface} scoped under `prefix`.
402
- * - `match(method, pathname)` — the raw {@link DispatchResult} for a method +
403
- * pathname pair, with no `Request`/`Response` involvement — the pure
404
- * decision `handle` builds its response from.
405
- * - `handle(request, state)` — the full dispatch: parses `request.url`,
406
- * calls `match`, and either invokes the winning handler (auto-stripping
407
- * the body for a derived `HEAD`, auto-answering a derived `OPTIONS` with
408
- * the `Allow` set), or invokes the `unmatched`/`unmethoded` responder.
409
- * Emits `match`/`miss` accordingly. A handler throw propagates uncaught.
410
- * - `destroy()` — tears down the `#emitter` (AGENTS §13); the underlying
411
- * router is left registered (not cleared) so introspection remains valid
412
- * after destroy.
413
- */
414
- export interface DispatcherInterface<TState = undefined> {
415
- readonly router: RouterInterface<RouteRecord<TState>>;
416
- readonly emitter: EmitterInterface<DispatcherEventMap>;
417
- add<Path extends string>(input: RouteInput<Path, TState>): void;
418
- add(inputs: readonly RouteInput<string, TState>[]): void;
419
- group(prefix: string): DispatchGroupInterface<TState>;
420
- match(method: Method, pathname: string): DispatchResult<TState>;
421
- handle(request: Request, state: TState): Promise<Response>;
422
- destroy(): void;
423
- }
424
- /**
425
- * A prefix-scoped registration handle over a {@link DispatcherInterface} —
426
- * the method-dimensioned counterpart of {@link GroupInterface}.
427
- *
428
- * @typeParam TState - The consumer's opaque per-request state type, matching
429
- * the owning dispatcher
430
- *
431
- * @remarks
432
- * - `prefix` — the path prefix this group prepends to every route it
433
- * registers (and to every nested group's own prefix).
434
- * - `add(input)` / `add(inputs)` — register ONE / MANY {@link RouteInput}s on
435
- * the OWNING dispatcher, each input's `path` composed as
436
- * `prefix + input.path` (§9.2 batch, mirroring
437
- * {@link DispatcherInterface.add}).
438
- * - `group(prefix)` — a nested group whose prefix is `this.prefix + prefix`.
439
- */
440
- export interface DispatchGroupInterface<TState> {
441
- readonly prefix: string;
442
- add<Path extends string>(input: RouteInput<Path, TState>): void;
443
- add(inputs: readonly RouteInput<string, TState>[]): void;
444
- group(prefix: string): DispatchGroupInterface<TState>;
445
- }
@@ -1,31 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from 'node:http';
2
- /**
3
- * Options for `buildRequest` — how to derive the built `Request`'s origin.
4
- *
5
- * @remarks
6
- * - `origin` — an explicit scheme + host to build the request URL against
7
- * (`https://api.example.com`). Omitted ⇒ derived from the connection: the
8
- * socket's `encrypted` presence picks `https`/`http`, and the `Host`
9
- * header supplies the host (absent `Host` ⇒ `localhost`).
10
- */
11
- export interface RequestOptions {
12
- readonly origin?: string;
13
- }
14
- /**
15
- * A `node:http` request handler — the function `createListener` returns,
16
- * matching `http.createServer`'s handler signature.
17
- *
18
- * @remarks
19
- * Invoked once per incoming message with the raw `IncomingMessage`/
20
- * `ServerResponse` pair; never returns a value (writes the response as a
21
- * side effect).
22
- */
23
- export type ListenerFunction = (request: IncomingMessage, response: ServerResponse) => void;
24
- /**
25
- * Derives a consumer's opaque per-request `TState` from the raw
26
- * `IncomingMessage` — the `state` argument `createListener` threads into
27
- * `dispatcher.handle`.
28
- *
29
- * @typeParam TState - The consumer's opaque per-request state type
30
- */
31
- export type StateFunction<TState> = (message: IncomingMessage) => TState;