@orkestrel/middleware 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1339 @@
1
+ import { ConnectionInfo } from '@orkestrel/server';
2
+ import { CookieOptions } from '@orkestrel/server';
3
+ import { Encoding } from '@orkestrel/server';
4
+ import { MiddlewareContext } from '@orkestrel/server';
5
+ import { MiddlewareHandler } from '@orkestrel/server';
6
+ import { TokenSecret } from '@orkestrel/server';
7
+
8
+ /**
9
+ * Options for `createBearer` — bearer-token authentication.
10
+ *
11
+ * @param options - See fields below
12
+ * @remarks
13
+ * - `secret` — the {@link TokenSecret} `verifyToken` checks the extracted
14
+ * token against (rotation-aware).
15
+ * - `header` — the header the token is read from; defaults to
16
+ * {@link DEFAULT_BEARER_HEADER}.
17
+ * - `scheme` — the scheme prefix stripped before verification (case-
18
+ * insensitive); defaults to {@link DEFAULT_BEARER_SCHEME}. An empty string
19
+ * means the whole header value is the raw token.
20
+ */
21
+ export declare interface BearerOptions {
22
+ readonly secret: TokenSecret;
23
+ readonly header?: string;
24
+ readonly scheme?: string;
25
+ }
26
+
27
+ /**
28
+ * The bearer-authentication state slice `createBearer` stashes on
29
+ * `context.state` once a token verifies.
30
+ *
31
+ * @remarks
32
+ * `token` is optional-mutable: absent until `createBearer` runs, then
33
+ * written in place — the pattern every stateful battery's slice follows so a
34
+ * consumer intersects only the slices it mounts into its own `TState`.
35
+ */
36
+ export declare interface BearerState {
37
+ token?: string;
38
+ }
39
+
40
+ /**
41
+ * Options for `createBoundary` — the outermost error-rendering battery.
42
+ *
43
+ * @param options - See fields below
44
+ * @remarks
45
+ * - `expose` — when `true`, a non-`HTTPError` throw's `error.message` is
46
+ * surfaced in the 500 body instead of a generic message. Defaults to
47
+ * `false` (nothing leaks).
48
+ * - `report` — an optional fire-and-forget sink invoked with every caught
49
+ * error; its own throw is swallowed and can never alter the response.
50
+ */
51
+ export declare interface BoundaryOptions {
52
+ readonly expose?: boolean;
53
+ readonly report?: (error: unknown) => void;
54
+ }
55
+
56
+ /**
57
+ * A parsed client-info fact for {@link ClientInfo} — a leaf shaping helper
58
+ * `createForwarded` uses to build its stashed slice.
59
+ *
60
+ * @param ip - The resolved client IP, if any
61
+ * @returns The {@link ClientInfo} slice value
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * buildClientInfo('203.0.113.7') // { ip: '203.0.113.7' }
66
+ * ```
67
+ */
68
+ export declare function buildClientInfo(ip: string | undefined): ClientInfo;
69
+
70
+ /**
71
+ * Build the draft `RateLimit` structured header field (ruling I) — emitted
72
+ * only when `createLimiter`'s `policy` option is `true`.
73
+ *
74
+ * @param remaining - The requests still admitted this window
75
+ * @param resetAt - The window reset instant (same clock unit as `now`)
76
+ * @param now - The current instant
77
+ * @returns The `RateLimit` header value
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * buildRateLimitField(4, 1_500, 1_000) // '"default";r=4;t=1'
82
+ * ```
83
+ */
84
+ export declare function buildRateLimitField(remaining: number, resetAt: number, now: number): string;
85
+
86
+ /**
87
+ * Build the draft `RateLimit-Policy` structured header field (ruling I) —
88
+ * emitted only when `createLimiter`'s `policy` option is `true`.
89
+ *
90
+ * @param max - The window's admitted request count
91
+ * @param window - The window length in milliseconds
92
+ * @returns The `RateLimit-Policy` header value
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * buildRateLimitPolicyField(10, 60_000) // '"default";q=10;w=60'
97
+ * ```
98
+ */
99
+ export declare function buildRateLimitPolicyField(max: number, window: number): string;
100
+
101
+ /**
102
+ * Build the `Retry-After` header value — whole seconds until a window reset,
103
+ * floored at a minimum of `1` (ruling I).
104
+ *
105
+ * @param resetAt - The window reset instant (same clock unit as `now`)
106
+ * @param now - The current instant
107
+ * @returns The `Retry-After` value in whole seconds, minimum `1`
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * buildRetryAfter(1_500, 1_000) // '1'
112
+ * ```
113
+ */
114
+ export declare function buildRetryAfter(resetAt: number, now: number): string;
115
+
116
+ /**
117
+ * The resolved client connection facts `createForwarded` stashes.
118
+ *
119
+ * @remarks
120
+ * `ip` is the first untrusted address walking `X-Forwarded-For` /
121
+ * `Forwarded` right-to-left past the configured trusted hops, falling back
122
+ * to the socket peer when no proxy hop qualifies.
123
+ */
124
+ export declare interface ClientInfo {
125
+ readonly ip?: string;
126
+ }
127
+
128
+ /**
129
+ * The client-facts state slice `createForwarded` stashes.
130
+ */
131
+ export declare interface ClientState {
132
+ client?: ClientInfo;
133
+ }
134
+
135
+ /**
136
+ * Options for `createCompression` — response-body compression.
137
+ *
138
+ * @param options - See fields below
139
+ * @remarks
140
+ * - `threshold` — the minimum buffered body size (bytes) worth compressing;
141
+ * defaults to {@link DEFAULT_COMPRESSION_THRESHOLD}.
142
+ * - `encodings` — the codings offered, in preference order, intersected at
143
+ * CONSTRUCTION with what the runtime's `CompressionStream` actually
144
+ * supports; defaults to {@link DEFAULT_COMPRESSION_ENCODINGS}.
145
+ * - `filter` — an optional per-response opt-out predicate (the BREACH
146
+ * posture escape hatch); a response the predicate declines is never
147
+ * buffered or compressed. Defaults to always allowing.
148
+ */
149
+ export declare interface CompressionOptions {
150
+ readonly threshold?: number;
151
+ readonly encodings?: readonly Encoding[];
152
+ readonly filter?: (request: Request, response: Response) => boolean;
153
+ }
154
+
155
+ /**
156
+ * The shared negotiate → skip → threshold → compress → header-set skeleton
157
+ * both faces' `createCompression` batteries compose — response-body
158
+ * compression over a caller-supplied set of feature-detected codings.
159
+ *
160
+ * @remarks
161
+ * Decision order: {@link isBufferingIneligible} → `options.filter` → stamp
162
+ * `Vary: Accept-Encoding` (every negotiation-eligible response carries it,
163
+ * even when a later skip declines to compress) → `negotiateEncoding` over
164
+ * `options.encodings` → {@link isCompressionNegotiated} → `isCompressibleType`
165
+ * on `Content-Type` → a fast skip when the response already carries a
166
+ * numeric `Content-Length` BELOW `options.threshold` (avoids buffering a
167
+ * body known too small to be worth compressing) → buffer via
168
+ * `response.arrayBuffer()` → a threshold passthrough when the buffered size
169
+ * is still below `options.threshold` → `options.compress` → set
170
+ * `Content-Encoding` and a fresh `Content-Length` via {@link rebuildResponse}.
171
+ * Returns `response` unchanged (aside from the `Vary` stamp) on any skip.
172
+ *
173
+ * @param request - The inbound `Request` (read for `Accept-Encoding`)
174
+ * @param context - The `MiddlewareContext` (read for `context.method`)
175
+ * @param response - The downstream `Response` to consider compressing
176
+ * @param options - The threshold, optional filter, offered encodings, and the runtime's `compress` primitive
177
+ * @returns The original `response` when skipped, or a new compressed `Response`
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * await compressResponse(request, context, response, {
182
+ * threshold: 1024,
183
+ * encodings: ['gzip'],
184
+ * compress: async (bytes, encoding) => gzip(bytes),
185
+ * })
186
+ * ```
187
+ */
188
+ export declare function compressResponse(request: Request, context: MiddlewareContext<unknown>, response: Response, options: {
189
+ readonly threshold: number;
190
+ readonly filter?: (request: Request, response: Response) => boolean;
191
+ readonly encodings: readonly Encoding[];
192
+ readonly compress: (bytes: Uint8Array<ArrayBuffer>, encoding: Exclude<Encoding, 'identity'>) => Promise<Uint8Array<ArrayBuffer>>;
193
+ }): Promise<Response>;
194
+
195
+ /**
196
+ * The connection-facts state slice `createLimiter`'s default key derivation
197
+ * falls back to when neither {@link BearerState} nor {@link ClientState} is
198
+ * present — the raw socket peer surfaced on `context.state` by the server's
199
+ * `state` option.
200
+ */
201
+ export declare interface ConnectionState {
202
+ readonly connection?: ConnectionInfo;
203
+ }
204
+
205
+ /**
206
+ * Options for `createCookieTransport` — the signed-cookie {@link SessionTransport}.
207
+ *
208
+ * @param options - See fields below
209
+ * @remarks
210
+ * - `name` — the cookie name; defaults to {@link DEFAULT_SESSION_COOKIE}.
211
+ * - `secret` — the {@link TokenSecret} the session id is signed with (`signToken`).
212
+ * - `cookie` — extra {@link CookieOptions} attributes; `Max-Age` is derived
213
+ * from `SessionOptions.ttl` unless overridden here.
214
+ */
215
+ export declare interface CookieTransportOptions {
216
+ readonly name?: string;
217
+ readonly secret: TokenSecret;
218
+ readonly cookie?: CookieOptions;
219
+ }
220
+
221
+ /**
222
+ * Options for `createCors` — Cross-Origin Resource Sharing.
223
+ *
224
+ * @param options - See fields below
225
+ * @remarks
226
+ * - `origin` — the allowed origin(s): `'*'` (default), a single origin
227
+ * string, or an allow-list `readonly string[]` (reflects the request
228
+ * `Origin` when it matches, and merges `Vary: Origin`). The literal
229
+ * `Origin: null` is never reflected even when `'null'` is allow-listed.
230
+ * - `methods` — the methods advertised on a preflight; defaults to {@link DEFAULT_CORS_METHODS}.
231
+ * - `headers` — the headers advertised on a preflight; defaults to {@link DEFAULT_CORS_HEADERS}.
232
+ */
233
+ export declare interface CorsOptions {
234
+ readonly origin?: string | readonly string[];
235
+ readonly methods?: readonly string[];
236
+ readonly headers?: readonly string[];
237
+ }
238
+
239
+ /**
240
+ * Bearer-token authentication battery.
241
+ *
242
+ * @typeParam TState - The consumer's opaque per-request state type, must carry {@link BearerState}
243
+ * @param options - See {@link BearerOptions}
244
+ * @returns A `MiddlewareHandler<TState>`
245
+ * @throws {TypeError} When any option is malformed
246
+ * @throws {HTTPError} `401` when the token is missing, invalid, or expired
247
+ *
248
+ * @example
249
+ * ```ts
250
+ * const bearer = createBearer({ secret: 'shh' })
251
+ * ```
252
+ */
253
+ export declare function createBearer<TState extends BearerState>(options: BearerOptions): MiddlewareHandler<TState>;
254
+
255
+ /**
256
+ * The body-driving battery — eagerly awaits the cached `context.body()` so
257
+ * its throws (or a malformed-JSON `undefined`) surface before the handler runs.
258
+ *
259
+ * @typeParam TState - The consumer's opaque per-request state type
260
+ * @returns A `MiddlewareHandler<TState>`
261
+ * @throws {HTTPError} `400` when the request declares `application/json` and the body resolves `undefined`
262
+ *
263
+ * @remarks
264
+ * The shipped `MiddlewareContext.body()` is a parameterless, server-owned
265
+ * cache (`ServerOptions.limit` governs its size cap) — this battery carries
266
+ * no `limit`/`decompression` options (a deliberate break from the deleted old
267
+ * `createBodyParser` surface, which configured them itself).
268
+ *
269
+ * @example
270
+ * ```ts
271
+ * const body = createBody()
272
+ * ```
273
+ */
274
+ export declare function createBody<TState>(): MiddlewareHandler<TState>;
275
+
276
+ /**
277
+ * The outermost error-rendering battery — catches a downstream throw and
278
+ * renders it as a `Response`.
279
+ *
280
+ * @typeParam TState - The consumer's opaque per-request state type
281
+ * @param options - See {@link BoundaryOptions}
282
+ * @returns A `MiddlewareHandler<TState>`
283
+ * @throws {TypeError} When `options.expose` or `options.report` is malformed
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * const boundary = createBoundary({ expose: false })
288
+ * ```
289
+ */
290
+ export declare function createBoundary<TState>(options?: BoundaryOptions): MiddlewareHandler<TState>;
291
+
292
+ /**
293
+ * Response-body compression — negotiates and compresses a buffered response
294
+ * body over the runtime's feature-detected `CompressionStream` codings.
295
+ *
296
+ * @typeParam TState - The consumer's opaque per-request state type
297
+ * @param options - See {@link CompressionOptions}
298
+ * @returns A `MiddlewareHandler<TState>`
299
+ * @throws {TypeError} When `options.threshold` or `options.filter` is malformed
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * const compression = createCompression({ threshold: 1024 })
304
+ * ```
305
+ */
306
+ export declare function createCompression<TState>(options?: CompressionOptions): MiddlewareHandler<TState>;
307
+
308
+ /**
309
+ * Create a signed-cookie {@link SessionTransport} — the session id travels as
310
+ * a `signToken`-signed cookie value.
311
+ *
312
+ * @param options - See {@link CookieTransportOptions}
313
+ * @returns A {@link SessionTransport}
314
+ * @throws {TypeError} When `options.secret` or `options.name` is malformed
315
+ *
316
+ * @example
317
+ * ```ts
318
+ * const transport = createCookieTransport({ secret: 'shh' })
319
+ * ```
320
+ */
321
+ export declare function createCookieTransport(options: CookieTransportOptions): SessionTransport;
322
+
323
+ /**
324
+ * Cross-Origin Resource Sharing battery.
325
+ *
326
+ * @typeParam TState - The consumer's opaque per-request state type
327
+ * @param options - See {@link CorsOptions}
328
+ * @returns A `MiddlewareHandler<TState>`
329
+ * @throws {TypeError} When any option is malformed
330
+ *
331
+ * @example
332
+ * ```ts
333
+ * const cors = createCors({ origin: ['https://app.example'] })
334
+ * ```
335
+ */
336
+ export declare function createCors<TState>(options?: CorsOptions): MiddlewareHandler<TState>;
337
+
338
+ /**
339
+ * Session-bound double-submit CSRF protection battery.
340
+ *
341
+ * @typeParam TState - The consumer's opaque per-request state type, must carry {@link CSRFState}, {@link SessionState}, and {@link ConnectionState}
342
+ * @param options - See {@link CSRFOptions}
343
+ * @returns A `MiddlewareHandler<TState>`
344
+ * @throws {TypeError} When any option is malformed
345
+ * @throws {HTTPError} `403` when the submitted token is missing, mismatched, or bound to a different session
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * const csrf = createCSRF({ secret: 'shh' })
350
+ * ```
351
+ */
352
+ export declare function createCSRF<TState extends CSRFState & SessionState & ConnectionState>(options: CSRFOptions): MiddlewareHandler<TState>;
353
+
354
+ /**
355
+ * The application-level per-request deadline battery.
356
+ *
357
+ * @typeParam TState - The consumer's opaque per-request state type
358
+ * @param options - See {@link DeadlineOptions}
359
+ * @returns A `MiddlewareHandler<TState>`
360
+ * @throws {TypeError} When `options.ms` or `options.status` is malformed
361
+ *
362
+ * @remarks
363
+ * MUST sit OUTSIDE `createBody` in the chain — it reconstructs the inbound
364
+ * `Request` (to link its `signal` to the deadline `signal`), which throws if
365
+ * the body was already consumed upstream (e.g. by `createBody`'s cached read).
366
+ *
367
+ * @example
368
+ * ```ts
369
+ * const deadline = createDeadline({ ms: 5_000 })
370
+ * ```
371
+ */
372
+ export declare function createDeadline<TState>(options: DeadlineOptions): MiddlewareHandler<TState>;
373
+
374
+ /**
375
+ * Dynamic response `ETag` + conditional GET battery.
376
+ *
377
+ * @typeParam TState - The consumer's opaque per-request state type
378
+ * @param options - See {@link ETagOptions}
379
+ * @returns A `MiddlewareHandler<TState>`
380
+ * @throws {TypeError} When `options.weak` is not a boolean
381
+ *
382
+ * @example
383
+ * ```ts
384
+ * const etag = createETag({ weak: true })
385
+ * ```
386
+ */
387
+ export declare function createETag<TState>(options?: ETagOptions): MiddlewareHandler<TState>;
388
+
389
+ /**
390
+ * The trusted-proxy client-IP resolver battery.
391
+ *
392
+ * @typeParam TState - The consumer's opaque per-request state type, must carry {@link ClientState} and {@link ConnectionState}
393
+ * @param options - See {@link ForwardedOptions}
394
+ * @returns A `MiddlewareHandler<TState>`
395
+ * @throws {TypeError} When neither or both of `proxies`/`trusted` are provided, or either is malformed
396
+ *
397
+ * @example
398
+ * ```ts
399
+ * const forwarded = createForwarded({ proxies: 1 })
400
+ * ```
401
+ */
402
+ export declare function createForwarded<TState extends ClientState & ConnectionState>(options: ForwardedOptions): MiddlewareHandler<TState>;
403
+
404
+ /**
405
+ * Create a bare-header {@link SessionTransport} — the session id travels
406
+ * verbatim in a request/response header.
407
+ *
408
+ * @param options - See {@link HeaderTransportOptions}
409
+ * @returns A {@link SessionTransport}
410
+ * @throws {TypeError} When `options.header` is malformed
411
+ *
412
+ * @example
413
+ * ```ts
414
+ * const transport = createHeaderTransport()
415
+ * ```
416
+ */
417
+ export declare function createHeaderTransport(options?: HeaderTransportOptions): SessionTransport;
418
+
419
+ /**
420
+ * Fixed-window rate-limiting battery.
421
+ *
422
+ * @typeParam TState - The consumer's opaque per-request state type, must carry {@link BearerState}, {@link ClientState}, and {@link ConnectionState}
423
+ * @param options - See {@link LimiterOptions}
424
+ * @returns A `MiddlewareHandler<TState>`
425
+ * @throws {TypeError} When any option is malformed
426
+ *
427
+ * @example
428
+ * ```ts
429
+ * const limiter = createLimiter({ max: 100, window: 60_000 })
430
+ * ```
431
+ */
432
+ export declare function createLimiter<TState extends BearerState & ClientState & ConnectionState>(options: LimiterOptions<TState>): MiddlewareHandler<TState>;
433
+
434
+ /**
435
+ * Create the default in-process {@link SessionStoreInterface} — a `Map`-backed
436
+ * store enforcing an idle timeout and an absolute lifetime.
437
+ *
438
+ * @typeParam S - The session data payload type
439
+ * @param options - See {@link MemorySessionStoreOptions}
440
+ * @returns A {@link SessionStoreInterface}
441
+ * @throws {TypeError} When `options.ttl` or `options.lifetime` is malformed
442
+ *
443
+ * @remarks
444
+ * The {@link Session} entity is the `create` option's default value factory
445
+ * for `createSession` and deliberately ships WITHOUT its own `create*`
446
+ * factory — the name `createSession` belongs to the battery, not this class.
447
+ *
448
+ * @example
449
+ * ```ts
450
+ * const store = createMemorySessionStore({ ttl: 60_000 })
451
+ * ```
452
+ */
453
+ export declare function createMemorySessionStore<S>(options?: MemorySessionStoreOptions): SessionStoreInterface<S>;
454
+
455
+ /**
456
+ * Security-headers + request-identifier battery.
457
+ *
458
+ * @typeParam TState - The consumer's opaque per-request state type, must carry {@link IdentifierState}
459
+ * @param options - See {@link SecurityOptions}
460
+ * @returns A `MiddlewareHandler<TState>`
461
+ * @throws {TypeError} When any option is malformed
462
+ *
463
+ * @example
464
+ * ```ts
465
+ * const security = createSecurity({ hsts: true })
466
+ * ```
467
+ */
468
+ export declare function createSecurity<TState extends IdentifierState>(options?: SecurityOptions): MiddlewareHandler<TState>;
469
+
470
+ /**
471
+ * The generic session battery — resolves, mints, and persists a session
472
+ * across the request, with a mid-handler `regenerate`/`destroy` control handle.
473
+ *
474
+ * @typeParam S - The session entity type the store persists (must implement {@link SessionInterface})
475
+ * @typeParam TState - The consumer's opaque per-request state type, must carry {@link SessionState} and {@link ConnectionState}
476
+ * @param options - See {@link SessionOptions}
477
+ * @returns A `MiddlewareHandler<TState>`
478
+ * @throws {TypeError} When any option is malformed
479
+ * @throws {HTTPError} `404` when `require` is set and no session resolves or mints
480
+ *
481
+ * @example
482
+ * ```ts
483
+ * const session = createSession({ transport: createHeaderTransport() })
484
+ * ```
485
+ */
486
+ export declare function createSession<S extends SessionInterface = SessionInterface, TState extends SessionState & ConnectionState = SessionState & ConnectionState>(options: SessionOptions<S, TState>): MiddlewareHandler<TState>;
487
+
488
+ /**
489
+ * The access-log/timing seam — records one {@link TelemetryEntry} per request
490
+ * after the response settles.
491
+ *
492
+ * @typeParam TState - The consumer's opaque per-request state type
493
+ * @param options - See {@link TelemetryOptions}
494
+ * @returns A `MiddlewareHandler<TState>`
495
+ * @throws {TypeError} When `options.record` is not a function
496
+ *
497
+ * @example
498
+ * ```ts
499
+ * const telemetry = createTelemetry({ record: (entry) => console.log(entry) })
500
+ * ```
501
+ */
502
+ export declare function createTelemetry<TState>(options: TelemetryOptions): MiddlewareHandler<TState>;
503
+
504
+ /**
505
+ * Options for `createCSRF` — session-bound double-submit CSRF protection.
506
+ *
507
+ * @param options - See fields below
508
+ * @remarks
509
+ * - `secret` — the {@link TokenSecret} the CSRF token is signed with.
510
+ * - `cookie` — the signed-cookie name; defaults to {@link DEFAULT_CSRF_COOKIE}.
511
+ * - `header` — the header a mutating request submits its token in; defaults
512
+ * to {@link DEFAULT_CSRF_HEADER}.
513
+ * - `field` — the body field a mutating request may submit its token in
514
+ * instead of the header (requires `createBody` ahead for form posts);
515
+ * defaults to {@link DEFAULT_CSRF_FIELD}.
516
+ * - `safe` — the methods that mint instead of verify; defaults to
517
+ * {@link DEFAULT_CSRF_SAFE_METHODS}.
518
+ */
519
+ export declare interface CSRFOptions {
520
+ readonly secret: TokenSecret;
521
+ readonly cookie?: string;
522
+ readonly header?: string;
523
+ readonly field?: string;
524
+ readonly safe?: readonly string[];
525
+ }
526
+
527
+ /**
528
+ * The CSRF state slice `createCSRF` stashes — the raw token a safe-method
529
+ * response exposes for a subsequent mutating request to submit back.
530
+ */
531
+ export declare interface CSRFState {
532
+ csrf?: string;
533
+ }
534
+
535
+ /**
536
+ * Options for `createDeadline` — the application-level per-request deadline.
537
+ *
538
+ * @param options - See fields below
539
+ * @remarks
540
+ * - `ms` — the deadline in milliseconds, armed via `@orkestrel/timeout` and
541
+ * linked to the request's `signal` via `@orkestrel/abort`'s `linkSignal`.
542
+ * - `status` — the response status returned when the deadline fires before
543
+ * the downstream chain settles; defaults to {@link DEFAULT_DEADLINE_STATUS}.
544
+ */
545
+ export declare interface DeadlineOptions {
546
+ readonly ms: number;
547
+ readonly status?: number;
548
+ }
549
+
550
+ /** Default header `createBearer` reads the token from. */
551
+ export declare const DEFAULT_BEARER_HEADER = "authorization";
552
+
553
+ /** Default scheme prefix `createBearer` strips before verification. */
554
+ export declare const DEFAULT_BEARER_SCHEME = "Bearer";
555
+
556
+ /** Default `Origin-Agent-Cluster` value `createSecurity` sets. */
557
+ export declare const DEFAULT_CLUSTER = "?1";
558
+
559
+ /** Value `createSecurity` sets for `Cross-Origin-Embedder-Policy` when `coep: true`. */
560
+ export declare const DEFAULT_COEP = "require-corp";
561
+
562
+ /**
563
+ * Default content-codings `createCompression` offers, in preference order —
564
+ * intersected at construction with what the runtime's `CompressionStream`
565
+ * actually supports.
566
+ *
567
+ * @remarks
568
+ * The shipped `@orkestrel/server` peer's {@link Encoding} union is
569
+ * `'gzip' | 'deflate' | 'identity'` — it does not include `'br'` (see the
570
+ * deviation recorded against this constant in the build report). This
571
+ * default therefore offers every non-`identity` coding the peer's type
572
+ * admits; a node-face brotli variant, if one ships, extends this list there.
573
+ */
574
+ export declare const DEFAULT_COMPRESSION_ENCODINGS: readonly Encoding[];
575
+
576
+ /** Default minimum buffered body size (bytes) `createCompression` will compress. */
577
+ export declare const DEFAULT_COMPRESSION_THRESHOLD = 1024;
578
+
579
+ /** Default `Cross-Origin-Opener-Policy` value `createSecurity` sets. */
580
+ export declare const DEFAULT_COOP = "same-origin";
581
+
582
+ /** Default `Cross-Origin-Resource-Policy` value `createSecurity` sets. */
583
+ export declare const DEFAULT_CORP = "same-origin";
584
+
585
+ /** Default headers `createCors` advertises on a preflight response. */
586
+ export declare const DEFAULT_CORS_HEADERS: readonly string[];
587
+
588
+ /** Default methods `createCors` advertises on a preflight response. */
589
+ export declare const DEFAULT_CORS_METHODS: readonly string[];
590
+
591
+ /**
592
+ * Default `Content-Security-Policy` value `createSecurity` sets — a custom
593
+ * `csp` option REPLACES this wholesale, never merges.
594
+ */
595
+ export declare const DEFAULT_CSP = "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self'";
596
+
597
+ /** Default signed-cookie name `createCSRF` writes the CSRF token under. */
598
+ export declare const DEFAULT_CSRF_COOKIE = "csrf";
599
+
600
+ /** Default body field `createCSRF` falls back to reading a mutating request's submitted token from. */
601
+ export declare const DEFAULT_CSRF_FIELD = "_csrf";
602
+
603
+ /** Default header `createCSRF` reads a mutating request's submitted token from. */
604
+ export declare const DEFAULT_CSRF_HEADER = "x-csrf-token";
605
+
606
+ /** Default methods `createCSRF` treats as safe (mint instead of verify). */
607
+ export declare const DEFAULT_CSRF_SAFE_METHODS: readonly string[];
608
+
609
+ /** Default response status `createDeadline` returns when its deadline fires first. */
610
+ export declare const DEFAULT_DEADLINE_STATUS = 503;
611
+
612
+ /** Default `X-Frame-Options` value `createSecurity` sets. */
613
+ export declare const DEFAULT_FRAME_OPTIONS = "DENY";
614
+
615
+ /** Value `createSecurity` sets for `Strict-Transport-Security` when `hsts: true`. */
616
+ export declare const DEFAULT_HSTS = "max-age=31536000; includeSubDomains";
617
+
618
+ /** Default header `createSecurity` mints/echoes a request identifier into. */
619
+ export declare const DEFAULT_IDENTIFIER_HEADER = "x-request-id";
620
+
621
+ /** Default maximum number of distinct rate-limit keys `createLimiter` tracks before LRU eviction. */
622
+ export declare const DEFAULT_LIMITER_CAPACITY = 10000;
623
+
624
+ /** Default 429 body message `createLimiter` sends when a key is over budget. */
625
+ export declare const DEFAULT_LIMITER_MESSAGE = "rate limit exceeded";
626
+
627
+ /** Default `Permissions-Policy` value `createSecurity` sets. */
628
+ export declare const DEFAULT_PERMISSIONS_POLICY = "camera=(), microphone=(), geolocation=()";
629
+
630
+ /** Default `Referrer-Policy` value `createSecurity` sets. */
631
+ export declare const DEFAULT_REFERRER_POLICY = "strict-origin-when-cross-origin";
632
+
633
+ /** Default maximum number of distinct session ids `createMemorySessionStore` tracks before LRU (by last write) eviction. */
634
+ export declare const DEFAULT_SESSION_CAPACITY = 10000;
635
+
636
+ /** Default cookie name `createCookieTransport` writes the signed session id under. */
637
+ export declare const DEFAULT_SESSION_COOKIE = "session";
638
+
639
+ /** Default header `createHeaderTransport` carries the session id in. */
640
+ export declare const DEFAULT_SESSION_HEADER = "session-id";
641
+
642
+ /**
643
+ * Feature-detect which of `candidates` the runtime's `CompressionStream`
644
+ * actually supports — `createCompression`'s construction-time intersection
645
+ * (ruling J).
646
+ *
647
+ * @remarks
648
+ * Probes each candidate with `new CompressionStream(candidate)` inside a
649
+ * `try`/`catch`; a coding the runtime rejects is dropped silently. `identity`
650
+ * is never probed (it has no `CompressionStream` coding and is always
651
+ * implicitly acceptable to negotiation).
652
+ *
653
+ * @param candidates - The codings to probe, in preference order
654
+ * @returns The subset of `candidates` the runtime's `CompressionStream` supports, in order
655
+ *
656
+ * @example
657
+ * ```ts
658
+ * detectEncodings(['gzip', 'deflate']) // ['gzip', 'deflate'] on a runtime with both
659
+ * ```
660
+ */
661
+ export declare function detectEncodings(candidates: readonly Encoding[]): readonly Encoding[];
662
+
663
+ /**
664
+ * Constant-time string equality — `createCSRF`'s double-submit token
665
+ * comparison, avoiding a timing oracle on the submitted-vs-cookie match.
666
+ *
667
+ * @remarks
668
+ * Length-guarded XOR-accumulate over char codes: a length mismatch short
669
+ * circuits (safe — the lengths of two independently-generated tokens are
670
+ * not a useful timing signal), but once lengths match every character is
671
+ * compared with no early return, so a per-character mismatch never affects
672
+ * how long the comparison takes.
673
+ *
674
+ * @param a - The first string
675
+ * @param b - The second string
676
+ * @returns `true` when `a` and `b` are exactly equal
677
+ *
678
+ * @example
679
+ * ```ts
680
+ * equalsConstantTime('abc', 'abc') // true
681
+ * equalsConstantTime('abc', 'abd') // false
682
+ * ```
683
+ */
684
+ export declare function equalsConstantTime(a: string, b: string): boolean;
685
+
686
+ /**
687
+ * Options for `createETag` — dynamic response ETag + conditional GET.
688
+ *
689
+ * @param options - See fields below
690
+ * @remarks
691
+ * - `weak` — mint a weak `W/"…"` ETag (default `true`) or a strong `"…"` one
692
+ * (`false`).
693
+ */
694
+ export declare interface ETagOptions {
695
+ readonly weak?: boolean;
696
+ }
697
+
698
+ /**
699
+ * Options for `createForwarded` — the trusted-proxy client-IP resolver.
700
+ *
701
+ * @param options - See fields below
702
+ * @remarks
703
+ * Construction requires EXACTLY ONE of the two forms (a `TypeError` guards
704
+ * both-set and neither-set):
705
+ * - `proxies` — trust exactly this many hops from the right of
706
+ * `X-Forwarded-For` / `Forwarded`.
707
+ * - `trusted` — trust every hop matching one of these CIDR entries.
708
+ */
709
+ export declare type ForwardedOptions = {
710
+ readonly proxies: number;
711
+ } | {
712
+ readonly trusted: readonly string[];
713
+ };
714
+
715
+ /**
716
+ * Options for `createHeaderTransport` — the bare-header {@link SessionTransport}.
717
+ *
718
+ * @param options - See fields below
719
+ * @remarks
720
+ * - `header` — the header carrying the session id; defaults to
721
+ * {@link DEFAULT_SESSION_HEADER}.
722
+ */
723
+ export declare interface HeaderTransportOptions {
724
+ readonly header?: string;
725
+ }
726
+
727
+ /**
728
+ * The request-identifier state slice `createSecurity` stashes when its
729
+ * `identifier` option is enabled.
730
+ */
731
+ export declare interface IdentifierState {
732
+ identifier?: string;
733
+ }
734
+
735
+ /**
736
+ * Whether a response is eligible for the compression/ETag buffering pipeline
737
+ * (ruling J) — the shared cheap-skip predicate both batteries apply before
738
+ * ever touching `response.arrayBuffer()`.
739
+ *
740
+ * @remarks
741
+ * Skips a `HEAD` request, a `204`/`304` or otherwise bodyless response, an
742
+ * `event-stream` response (SSE — buffering would hang the connection), and a
743
+ * response that already carries the header the caller is about to set
744
+ * (`skipHeader`, e.g. `Content-Encoding` for compression, `ETag` for the
745
+ * ETag battery).
746
+ *
747
+ * @param method - The request's HTTP method
748
+ * @param response - The candidate response
749
+ * @param skipHeader - The response header whose presence means "already handled"
750
+ * @returns `true` when the response should be left untouched
751
+ *
752
+ * @example
753
+ * ```ts
754
+ * isBufferingIneligible('GET', new Response(null, { status: 204 }), 'content-encoding') // true
755
+ * ```
756
+ */
757
+ export declare function isBufferingIneligible(method: string, response: Response, skipHeader: string): boolean;
758
+
759
+ /**
760
+ * Whether a negotiated `Accept-Encoding` outcome is worth acting on —
761
+ * `createCompression`'s negotiation-eligibility half of ruling J's skip list.
762
+ *
763
+ * @param encoding - The negotiated coding, or `undefined` when negotiation failed
764
+ * @returns `true` when `encoding` names an actionable, non-`identity` coding
765
+ *
766
+ * @example
767
+ * ```ts
768
+ * isCompressionNegotiated('gzip') // true
769
+ * isCompressionNegotiated(undefined) // false
770
+ * ```
771
+ */
772
+ export declare function isCompressionNegotiated(encoding: Encoding | undefined): encoding is Exclude<Encoding, 'identity'>;
773
+
774
+ /**
775
+ * Determine whether a value implements {@link MultipartBody} — a total
776
+ * structural guard (§14): `files` keyed by field name to arrays of
777
+ * {@link MultipartFile}, and a `fields` string record.
778
+ *
779
+ * @param value - The candidate value
780
+ * @returns `true` when `value` is shaped like a {@link MultipartBody}
781
+ *
782
+ * @example
783
+ * ```ts
784
+ * isMultipartBody({ files: {}, fields: { name: 'a' } }) // true
785
+ * ```
786
+ */
787
+ export declare function isMultipartBody(value: unknown): value is MultipartBody;
788
+
789
+ /**
790
+ * Determine whether a value is one staged {@link MultipartFile} record — a
791
+ * total structural guard (§14) checking every required field's shape.
792
+ *
793
+ * @param value - The candidate value
794
+ * @returns `true` when `value` is shaped like a {@link MultipartFile}
795
+ */
796
+ export declare function isMultipartFile(value: unknown): value is MultipartFile;
797
+
798
+ /**
799
+ * Determine whether a request is a CORS PREFLIGHT — an `OPTIONS` request
800
+ * carrying an `Access-Control-Request-Method` header.
801
+ *
802
+ * @param method - The request's HTTP method
803
+ * @param headers - The request's `Headers`
804
+ * @returns `true` when the request is a CORS preflight `createCors` must answer
805
+ *
806
+ * @example
807
+ * ```ts
808
+ * isPreflight('OPTIONS', new Headers({ 'access-control-request-method': 'POST' })) // true
809
+ * ```
810
+ */
811
+ export declare function isPreflight(method: string, headers: Headers): boolean;
812
+
813
+ /**
814
+ * Determine whether a value implements {@link SessionInterface} — a total
815
+ * structural guard (§14): an `id` string plus a `data` `Map`.
816
+ *
817
+ * @param value - The candidate value
818
+ * @returns `true` when `value` is shaped like a {@link SessionInterface}
819
+ *
820
+ * @example
821
+ * ```ts
822
+ * isSession({ id: 'a', data: new Map() }) // true
823
+ * ```
824
+ */
825
+ export declare function isSession(value: unknown): value is SessionInterface;
826
+
827
+ /**
828
+ * Determine whether a value implements {@link SessionControlInterface} — a
829
+ * total structural guard (§14): callable `regenerate` and `destroy`.
830
+ *
831
+ * @param value - The candidate value
832
+ * @returns `true` when `value` is shaped like a {@link SessionControlInterface}
833
+ *
834
+ * @example
835
+ * ```ts
836
+ * isSessionControl({ regenerate() {}, destroy() {} }) // true
837
+ * ```
838
+ */
839
+ export declare function isSessionControl(value: unknown): value is SessionControlInterface;
840
+
841
+ /**
842
+ * Options for `createLimiter` — fixed-window rate limiting.
843
+ *
844
+ * @typeParam TState - The consumer's opaque per-request state type `key` reads
845
+ * @param options - See fields below
846
+ * @remarks
847
+ * - `max` — the number of requests admitted per key per `window`.
848
+ * - `window` — the window length in milliseconds.
849
+ * - `capacity` — the maximum number of distinct keys tracked before the
850
+ * least-recently-used key is evicted (true LRU — every access, not just
851
+ * insertion, refreshes recency); defaults to {@link DEFAULT_LIMITER_CAPACITY}.
852
+ * - `key` — derives the bucket key from the request; defaults to the
853
+ * bearer-token-then-client-IP idiom (see the battery's guide).
854
+ * - `message` — the 429 body message; defaults to {@link DEFAULT_LIMITER_MESSAGE}.
855
+ * - `clock` — the injected time source for all window math; defaults to `Date.now`.
856
+ * - `policy` — when `true`, also emits the draft `RateLimit`/`RateLimit-Policy`
857
+ * structured header fields; defaults to `false`. `Retry-After` always ships.
858
+ * - `evict` — invoked with a bucket's key when it is evicted for capacity;
859
+ * its own throw is swallowed and can never fail the request. It is a
860
+ * notification sink only — it must never call back into the limiter
861
+ * (no re-entrant reads/writes); mutations during eviction are unsupported.
862
+ */
863
+ export declare interface LimiterOptions<TState = unknown> {
864
+ readonly max: number;
865
+ readonly window: number;
866
+ readonly capacity?: number;
867
+ readonly key?: (context: MiddlewareContext<TState>) => string;
868
+ readonly message?: string;
869
+ readonly clock?: () => number;
870
+ readonly policy?: boolean;
871
+ readonly evict?: (key: string) => void;
872
+ }
873
+
874
+ /**
875
+ * Whether a candidate address is a bare (non-CIDR) trusted-hop match — an
876
+ * exact string match, or a simple prefix-CIDR match for IPv4 (`/8`–`/32`).
877
+ * An IPv6 entry matches by exact string only — there is no IPv6 CIDR
878
+ * support.
879
+ *
880
+ * @remarks
881
+ * Supports exact addresses and dotted-decimal IPv4 CIDR (`10.0.0.0/8`
882
+ * through `/32`) verbatim. An IPv6 entry is matched by exact string only
883
+ * (no CIDR expansion) — documented as the supported subset; `createForwarded`
884
+ * never claims full CIDR generality beyond IPv4.
885
+ *
886
+ * @remarks
887
+ * An IPv6 `trusted` roster entry is compared as an EXACT string — it must be
888
+ * supplied in canonical form (no zero-compression normalization, no case
889
+ * folding) by the caller; this function performs no IPv6 normalization of
890
+ * its own.
891
+ *
892
+ * @param address - The candidate hop address
893
+ * @param entry - One `trusted` roster entry — an exact address or an IPv4 CIDR
894
+ * @returns `true` when `address` is covered by `entry`
895
+ *
896
+ * @example
897
+ * ```ts
898
+ * matchesTrustedEntry('10.1.2.3', '10.0.0.0/8') // true
899
+ * matchesTrustedEntry('192.168.1.1', '10.0.0.0/8') // false
900
+ * ```
901
+ */
902
+ export declare function matchesTrustedEntry(address: string, entry: string): boolean;
903
+
904
+ /**
905
+ * The default in-process {@link SessionStoreInterface} — a `Map`-backed store
906
+ * enforcing both an idle timeout and an absolute lifetime, with lazy
907
+ * (read-time) eviction, a bounded capacity, and no background timers.
908
+ *
909
+ * @typeParam S - The session data payload type
910
+ *
911
+ * @remarks
912
+ * `get` evicts a session whose idle time (`now - lastSeen >= ttl`) or
913
+ * absolute lifetime (`now - createdAt >= lifetime`) has elapsed — the
914
+ * lifetime check fires EVEN IF the session was continuously touched, since
915
+ * `createdAt` is stamped once at the first `set` and preserved across every
916
+ * later re-`set` of the same id. A live read touches `lastSeen`. `delete` of
917
+ * an absent id is a no-op.
918
+ *
919
+ * Capacity is enforced as least-recently-used **by last write**: `set`
920
+ * refreshes an id's recency (deleting then re-inserting so the Map's
921
+ * iteration tail is the most-recently-written id). Inserting a brand-new id
922
+ * once the store is at `capacity` first prunes expired entries; if the store
923
+ * is still full, the least-recently-written id (the Map's head) is evicted.
924
+ * `options.evict` — when provided — is invoked (throw-isolated) with the id
925
+ * on every eviction the store's own policy performs (a capacity eviction or
926
+ * an expired-entry prune), but never for an explicit `delete`.
927
+ *
928
+ * @example
929
+ * ```ts
930
+ * const store = new MemorySessionStore({ ttl: 60_000, lifetime: 3_600_000 })
931
+ * await store.set('abc', { userId: 'u_1' }, Date.now())
932
+ * ```
933
+ */
934
+ export declare class MemorySessionStore<S> implements SessionStoreInterface<S> {
935
+ #private;
936
+ constructor(options?: MemorySessionStoreOptions);
937
+ get(id: string, now: number): Promise<S | undefined>;
938
+ set(id: string, session: S, now: number): Promise<void>;
939
+ delete(id: string): Promise<void>;
940
+ }
941
+
942
+ /**
943
+ * Options for `createMemorySessionStore` — the default in-process {@link SessionStoreInterface}.
944
+ *
945
+ * @param options - See fields below
946
+ * @remarks
947
+ * - `ttl` — the idle timeout in milliseconds (lazy eviction on `get`).
948
+ * - `lifetime` — the absolute lifetime in milliseconds from first `set`
949
+ * (evicts even a continuously-touched session).
950
+ * - `capacity` — the maximum number of distinct session ids tracked before
951
+ * the least-recently-written id is evicted (LRU by last write — every
952
+ * `set` refreshes an id's recency); defaults to {@link DEFAULT_SESSION_CAPACITY}.
953
+ * - `evict` — invoked with a session id when it is evicted by the store's
954
+ * own policy (a capacity eviction or an expired-entry prune) — never for
955
+ * an explicit `delete`. Its own throw is swallowed. It is a notification
956
+ * sink only — it must never call back into the store (no re-entrant
957
+ * `get`/`set`); mutations during eviction are unsupported.
958
+ */
959
+ export declare interface MemorySessionStoreOptions {
960
+ readonly ttl?: number;
961
+ readonly lifetime?: number;
962
+ readonly capacity?: number;
963
+ readonly evict?: (id: string) => void;
964
+ }
965
+
966
+ /**
967
+ * The parsed multipart request body `createMultipart` stashes — files keyed
968
+ * by their field name, plus every plain text field.
969
+ */
970
+ export declare interface MultipartBody {
971
+ readonly files: Readonly<Record<string, readonly MultipartFile[]>>;
972
+ readonly fields: Readonly<Record<string, string>>;
973
+ }
974
+
975
+ /**
976
+ * One staged multipart upload's public record — the shape the node-face
977
+ * `createMultipart` battery (`@orkestrel/middleware/server`) produces per
978
+ * uploaded file.
979
+ *
980
+ * @remarks
981
+ * Declared here rather than in the node-bound server surface so the
982
+ * fetch/string-pure {@link MultipartState} slice — referenced by any
983
+ * environment narrowing `context.state` — never depends on the node face.
984
+ * The server's concrete `UploadedFileInterface` is structurally compatible
985
+ * with this shape.
986
+ */
987
+ export declare interface MultipartFile {
988
+ readonly field: string;
989
+ readonly name: string;
990
+ readonly size: number;
991
+ readonly mime: string;
992
+ readonly validated: boolean;
993
+ readonly status: string;
994
+ readonly path: string;
995
+ }
996
+
997
+ /**
998
+ * The multipart state slice `createMultipart` stashes.
999
+ *
1000
+ * @remarks
1001
+ * Present only once `createMultipart` has fully parsed a multipart request.
1002
+ * After it runs, `context.body()` must not be called for that request — the
1003
+ * multipart battery consumes `request.body` as a stream, so the seam's
1004
+ * cached body has nothing left to read.
1005
+ */
1006
+ export declare interface MultipartState {
1007
+ multipart?: MultipartBody;
1008
+ }
1009
+
1010
+ /**
1011
+ * Rebuild a `Response` around a replacement body while preserving its
1012
+ * status/statusText — the buffered-response reconstruction shared by the
1013
+ * compression and ETag batteries after they have consumed
1014
+ * `response.arrayBuffer()`.
1015
+ *
1016
+ * @param body - The replacement body (already-buffered bytes, or `null`)
1017
+ * @param response - The original response whose status/statusText/headers are preserved
1018
+ * @param headers - The headers to apply; defaults to a fresh copy of `response.headers`
1019
+ * @returns A new `Response` carrying `body` with `response`'s status/statusText
1020
+ *
1021
+ * @example
1022
+ * ```ts
1023
+ * rebuildResponse(bytes, response) // same status/statusText, response's headers copied
1024
+ * rebuildResponse(bytes, response, headers) // explicit replacement headers
1025
+ * ```
1026
+ */
1027
+ export declare function rebuildResponse(body: ConstructorParameters<typeof Response>[0], response: Response, headers?: ConstructorParameters<typeof Headers>[0]): Response;
1028
+
1029
+ /**
1030
+ * Walk `X-Forwarded-For` right-to-left and resolve the first UNTRUSTED hop
1031
+ * address — `createForwarded`'s core algorithm.
1032
+ *
1033
+ * @remarks
1034
+ * Parses `X-Forwarded-For` only. With `proxies` set, trusts exactly that
1035
+ * many hops counted from the right (the closest to this server) and returns
1036
+ * the next one left of them; with `trusted` set, trusts every CONSECUTIVE
1037
+ * hop from the right that matches one of the roster
1038
+ * ({@link matchesTrustedEntry}) and returns the first hop that does not. If
1039
+ * the rightmost hop (the immediate sender) does not match the roster, the
1040
+ * whole header is untrustworthy and this returns `undefined` rather than
1041
+ * returning any client-supplied hop value. When every hop is trusted, or the
1042
+ * header is absent/empty, returns `undefined` (the caller falls back to the
1043
+ * socket peer).
1044
+ *
1045
+ * @param header - The raw `X-Forwarded-For` header value (comma-separated hops), if present
1046
+ * @param trust - Either a trusted hop COUNT or a `trusted` CIDR/exact roster
1047
+ * @returns The first untrusted hop address, or `undefined` when none qualifies
1048
+ *
1049
+ * @example
1050
+ * ```ts
1051
+ * resolveForwardedFor('203.0.113.7, 10.0.0.1', { proxies: 1 }) // '203.0.113.7'
1052
+ * ```
1053
+ */
1054
+ export declare function resolveForwardedFor(header: string | undefined, trust: {
1055
+ readonly proxies: number;
1056
+ } | {
1057
+ readonly trusted: readonly string[];
1058
+ }): string | undefined;
1059
+
1060
+ /**
1061
+ * Derive `createLimiter`'s default rate-limit bucket key from a request's
1062
+ * resolved identity facts.
1063
+ *
1064
+ * @remarks
1065
+ * Prefers a verified bearer token ({@link BearerState.token}) as
1066
+ * `token:<value>`; else a resolved client IP ({@link ClientState.client.ip},
1067
+ * set when `createForwarded` is mounted) or the raw socket peer
1068
+ * ({@link ConnectionState.connection.ip}) collapsed via `clientRateKey`
1069
+ * (IPv6 to its `/64` network) as `ip:<key>`; else the literal `ip:unknown`.
1070
+ * Never reads `X-Forwarded-For` itself — that trust decision belongs solely
1071
+ * to `createForwarded`.
1072
+ *
1073
+ * @param state - The slices `createLimiter`'s default key may read
1074
+ * @returns The bucket key for the request
1075
+ *
1076
+ * @example
1077
+ * ```ts
1078
+ * resolveKey({ token: 'abc' }) // 'token:abc'
1079
+ * resolveKey({ client: { ip: '2001:db8::1' } }) // 'ip:2001:db8:0:0::/64'
1080
+ * ```
1081
+ */
1082
+ export declare function resolveKey(state: BearerState & ClientState & ConnectionState): string;
1083
+
1084
+ /**
1085
+ * Resolve an opt-in, value-bearing security header — `string | boolean`
1086
+ * (default OFF, `true` uses the secure default), the shape `createSecurity`'s
1087
+ * `coep`/`hsts` options use, distinct from the plain value-or-`false` shape
1088
+ * `resolveSecurityHeader` (the peer substrate) handles.
1089
+ *
1090
+ * @param value - The option value — a `string` override, `true` for the secure default, or `false`/`undefined` to omit
1091
+ * @param fallback - The secure-default value used when `value` is `true`
1092
+ * @returns The header value to set, or `undefined` to omit the header
1093
+ *
1094
+ * @example
1095
+ * ```ts
1096
+ * resolveOptInHeader(true, 'require-corp') // 'require-corp'
1097
+ * resolveOptInHeader(undefined, 'require-corp') // undefined — omitted
1098
+ * ```
1099
+ */
1100
+ export declare function resolveOptInHeader(value: string | boolean | undefined, fallback: string): string | undefined;
1101
+
1102
+ /**
1103
+ * `createSecurity`'s `identifier` sub-option — request-id minting/echo
1104
+ * policy, or `false` to disable the feature entirely.
1105
+ *
1106
+ * @remarks
1107
+ * - `trust` — when `true`, an incoming `X-Request-ID` that passes {@link
1108
+ * import('@orkestrel/server').isValidRequestId} is echoed back instead of
1109
+ * replaced by a fresh mint. Defaults to `false` (always mint).
1110
+ */
1111
+ export declare type SecurityIdentifierOptions = {
1112
+ readonly trust?: boolean;
1113
+ } | false;
1114
+
1115
+ /**
1116
+ * Options for `createSecurity` — the security-headers + request-id battery.
1117
+ *
1118
+ * @param options - See fields below
1119
+ * @remarks
1120
+ * Every header option is `string | false` (a custom value replaces the
1121
+ * default wholesale, `false` omits the header) unless noted; unset uses the
1122
+ * documented default. `X-Content-Type-Options: nosniff` is unconditional and
1123
+ * has no option.
1124
+ * - `frame` — `X-Frame-Options`; `'DENY' | 'SAMEORIGIN' | false`, default `'DENY'`.
1125
+ * - `csp` — `Content-Security-Policy`; default {@link DEFAULT_CSP}.
1126
+ * - `referrer` — `Referrer-Policy`; default {@link DEFAULT_REFERRER_POLICY}.
1127
+ * - `permissions` — `Permissions-Policy`; default {@link DEFAULT_PERMISSIONS_POLICY}.
1128
+ * - `coop` — `Cross-Origin-Opener-Policy`; default {@link DEFAULT_COOP}.
1129
+ * - `corp` — `Cross-Origin-Resource-Policy`; default {@link DEFAULT_CORP}.
1130
+ * - `cluster` — `Origin-Agent-Cluster`; default {@link DEFAULT_CLUSTER}.
1131
+ * - `coep` — `Cross-Origin-Embedder-Policy`; `string | boolean`, OFF by
1132
+ * default (opt-in, breaks cross-origin subresources); `true` → {@link DEFAULT_COEP}.
1133
+ * - `hsts` — `Strict-Transport-Security`; `string | boolean`, OFF by default
1134
+ * (opt-in, destructive if misconfigured); `true` → {@link DEFAULT_HSTS}.
1135
+ * - `identifier` — {@link SecurityIdentifierOptions}; ON by default (mints
1136
+ * and stashes {@link IdentifierState}).
1137
+ */
1138
+ export declare interface SecurityOptions {
1139
+ readonly frame?: 'DENY' | 'SAMEORIGIN' | false;
1140
+ readonly csp?: string | false;
1141
+ readonly referrer?: string | false;
1142
+ readonly permissions?: string | false;
1143
+ readonly coop?: string | false;
1144
+ readonly corp?: string | false;
1145
+ readonly cluster?: string | false;
1146
+ readonly coep?: string | boolean;
1147
+ readonly hsts?: string | boolean;
1148
+ readonly identifier?: SecurityIdentifierOptions;
1149
+ }
1150
+
1151
+ /**
1152
+ * A server-managed session's default entity — the `create` option's default
1153
+ * value factory for `createSession` (ruling G: `Session` ships WITHOUT a
1154
+ * `createSession` factory of its own, since that name belongs to the
1155
+ * battery).
1156
+ *
1157
+ * @remarks
1158
+ * `data` is a live, mutable `Map` a handler reads/writes directly;
1159
+ * `createSession` persists it to the configured store on the way out.
1160
+ *
1161
+ * @example
1162
+ * ```ts
1163
+ * const session = new Session('abc123')
1164
+ * session.data.set('userId', 'u_1')
1165
+ * ```
1166
+ */
1167
+ export declare class Session implements SessionInterface {
1168
+ readonly id: string;
1169
+ readonly data: Map<string, unknown>;
1170
+ constructor(id: string);
1171
+ }
1172
+
1173
+ /**
1174
+ * The mid-handler control handle `createSession` stashes alongside the
1175
+ * session itself — the OWASP anti-fixation / logout primitives.
1176
+ *
1177
+ * @remarks
1178
+ * `regenerate` and `destroy` record intent SYNCHRONOUSLY when called; the
1179
+ * store I/O and transport write happen after the handler's `next()` returns
1180
+ * (`destroy` supersedes a prior `regenerate`). `regenerate` mints a new id,
1181
+ * carries the session's `data` over, and invalidates the old id.
1182
+ */
1183
+ export declare interface SessionControlInterface {
1184
+ regenerate(): void;
1185
+ destroy(): void;
1186
+ }
1187
+
1188
+ /**
1189
+ * A server-managed session's public surface — an id and its mutable data bag.
1190
+ *
1191
+ * @remarks
1192
+ * `data` is a live `Map` a handler reads/writes directly; `createSession`
1193
+ * persists it to the configured {@link SessionStoreInterface} on the way out.
1194
+ */
1195
+ export declare interface SessionInterface {
1196
+ readonly id: string;
1197
+ readonly data: Map<string, unknown>;
1198
+ }
1199
+
1200
+ /**
1201
+ * Options for `createSession` — the generic session battery.
1202
+ *
1203
+ * @typeParam S - The session data payload type `create` produces
1204
+ * @typeParam TState - The consumer's opaque per-request state type `mint` reads
1205
+ * @param options - See fields below
1206
+ * @remarks
1207
+ * - `transport` — the {@link SessionTransport} (`createCookieTransport(...)`,
1208
+ * `createHeaderTransport(...)`, or a custom one).
1209
+ * - `store` — the {@link SessionStoreInterface}; defaults to
1210
+ * `createMemorySessionStore({ ttl, lifetime, capacity, evict })`.
1211
+ * - `ttl` — the idle timeout in milliseconds.
1212
+ * - `lifetime` — the absolute session lifetime in milliseconds from mint.
1213
+ * - `capacity` — the maximum number of distinct session ids the DEFAULT
1214
+ * memory store tracks before LRU eviction; ignored when `store` is
1215
+ * provided. Defaults to {@link DEFAULT_SESSION_CAPACITY}.
1216
+ * - `evict` — invoked with a session id evicted by the DEFAULT memory
1217
+ * store's own policy; ignored when `store` is provided. It is a
1218
+ * notification sink only — it must never call back into the store
1219
+ * (no re-entrant `get`/`set`); mutations during eviction are unsupported.
1220
+ * - `create` — builds a fresh session's public entity from a minted id;
1221
+ * defaults to `new Session(id)`.
1222
+ * - `mint` — decides whether to auto-mint a session when none resolves;
1223
+ * defaults to always minting (auto-session).
1224
+ * - `require` — when `true`, a request that resolves no session and does not
1225
+ * mint one renders a 404 instead of proceeding sessionless. Defaults to `false`.
1226
+ * - `ends` — when `true`, a `DELETE` request carrying a valid session id
1227
+ * deletes the session and short-circuits with `204`. Defaults to `false`.
1228
+ * - `clock` — the injected time source fed to the store; defaults to `Date.now`.
1229
+ */
1230
+ export declare interface SessionOptions<S, TState = unknown> {
1231
+ readonly transport: SessionTransport;
1232
+ readonly store?: SessionStoreInterface<S>;
1233
+ readonly ttl?: number;
1234
+ readonly lifetime?: number;
1235
+ readonly capacity?: number;
1236
+ readonly evict?: (id: string) => void;
1237
+ readonly create?: (id: string) => S;
1238
+ readonly mint?: (context: MiddlewareContext<TState>) => boolean | Promise<boolean>;
1239
+ readonly require?: boolean;
1240
+ readonly ends?: boolean;
1241
+ readonly clock?: () => number;
1242
+ }
1243
+
1244
+ /**
1245
+ * The session state slice `createSession` stashes.
1246
+ *
1247
+ * @remarks
1248
+ * `session` is present whenever a request resolves or mints a session;
1249
+ * `control` is present whenever `session` is (the handle to act on it).
1250
+ */
1251
+ export declare interface SessionState {
1252
+ session?: SessionInterface;
1253
+ control?: SessionControlInterface;
1254
+ }
1255
+
1256
+ /**
1257
+ * The pluggable session persistence seam `createSession`'s `store` option
1258
+ * implements — a point-access store (AGENTS §5) keyed by session id.
1259
+ *
1260
+ * @typeParam S - The session data payload type
1261
+ * @remarks
1262
+ * Every primitive is async and takes a trailing `now` clock reading (the
1263
+ * same seam `createSession`'s `clock` option feeds) so a store can apply its
1264
+ * own idle/absolute expiry against the caller's injected time rather than
1265
+ * its own wall clock. `delete` of an absent id is a no-op, never throws.
1266
+ */
1267
+ export declare interface SessionStoreInterface<S> {
1268
+ get(id: string, now: number): Promise<S | undefined>;
1269
+ set(id: string, session: S, now: number): Promise<void>;
1270
+ delete(id: string): Promise<void>;
1271
+ }
1272
+
1273
+ /**
1274
+ * The transport seam `createSession`'s `transport` option implements — how a
1275
+ * session id travels to and from the client (a signed cookie, a header, …).
1276
+ *
1277
+ * @remarks
1278
+ * `read` is total (a malformed/tampered credential resolves `undefined`,
1279
+ * never throws). `write` and `clear` mutate the RETURNED `Response` on the
1280
+ * way out — the returning onion makes "before send" automatic. `write` is
1281
+ * called only when a session is freshly minted or regenerated; `clear` is
1282
+ * called on `destroy()`. `write`'s `encrypted` flag is the request's resolved
1283
+ * transport security (derived from `context.url.protocol`) so a cookie
1284
+ * transport can resolve its own `Secure` attribute via `resolveSecure`
1285
+ * without re-deriving connection facts itself.
1286
+ */
1287
+ export declare interface SessionTransport {
1288
+ read(request: Request): string | undefined | Promise<string | undefined>;
1289
+ write(response: Response, id: string, encrypted: boolean): void | Promise<void>;
1290
+ clear(response: Response): void;
1291
+ }
1292
+
1293
+ /**
1294
+ * One access-log-style entry `createTelemetry` records after a response
1295
+ * settles — the access-log/timing seam's payload shape.
1296
+ *
1297
+ * @remarks
1298
+ * - `method` — the request's HTTP verb.
1299
+ * - `pathname` — the request URL's pathname.
1300
+ * - `status` — the response's final status (the boundary-mapped status when
1301
+ * a downstream throw was rendered by `createBoundary`).
1302
+ * - `duration` — the wall-clock time in milliseconds the whole onion took
1303
+ * beneath `createTelemetry`.
1304
+ */
1305
+ export declare interface TelemetryEntry {
1306
+ readonly method: string;
1307
+ readonly pathname: string;
1308
+ readonly status: number;
1309
+ readonly duration: number;
1310
+ }
1311
+
1312
+ /**
1313
+ * Options for `createTelemetry` — the request timing/access-log seam.
1314
+ *
1315
+ * @param options - See fields below
1316
+ * @remarks
1317
+ * - `record` — invoked once per request with the settled {@link
1318
+ * TelemetryEntry}; its own throw is swallowed so a broken sink can never
1319
+ * fail the response.
1320
+ */
1321
+ export declare interface TelemetryOptions {
1322
+ readonly record: (entry: TelemetryEntry) => void;
1323
+ }
1324
+
1325
+ /**
1326
+ * Copy every entry of one session's `data` into another — the regenerate
1327
+ * data-carry `createSession`'s `control.regenerate()` applies (ruling D).
1328
+ *
1329
+ * @param from - The source session whose `data` is copied
1330
+ * @param to - The destination session `data` is copied into
1331
+ *
1332
+ * @example
1333
+ * ```ts
1334
+ * transferSessionData(oldSession, newSession)
1335
+ * ```
1336
+ */
1337
+ export declare function transferSessionData(from: SessionInterface, to: SessionInterface): void;
1338
+
1339
+ export { }