@znight/http 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapter-6qC95ViO.d.mts → adapter-Dh3UF0ot.d.mts} +2 -2
- package/dist/compiler.d.mts +1 -1
- package/dist/express.d.mts +1 -1
- package/dist/express.mjs +1 -1
- package/dist/fastify.d.mts +1 -1
- package/dist/fastify.mjs +1 -1
- package/dist/hono.d.mts +1 -1
- package/dist/hono.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{node-npGnu7IW.mjs → node-DVEO_lrR.mjs} +2 -2
- package/dist/{node-npGnu7IW.mjs.map → node-DVEO_lrR.mjs.map} +1 -1
- package/dist/node.d.mts +1 -1
- package/dist/node.mjs +1 -1
- package/dist/{upgrade-io-dTMDDmBi.mjs → upgrade-io-CdQG7pZg.mjs} +2 -2
- package/dist/{upgrade-io-dTMDDmBi.mjs.map → upgrade-io-CdQG7pZg.mjs.map} +1 -1
- package/package.json +4 -4
- package/src/decorators.ts +1 -1
|
@@ -1206,7 +1206,7 @@ declare function UploadedFiles(options: UploadedFilesOptions): ParameterMarker;
|
|
|
1206
1206
|
* @param size static: bytes (`10_485_760`) or a size with a unit (`'10mb'`, `'512kb'`; `kb` = 1024 bytes).
|
|
1207
1207
|
*/
|
|
1208
1208
|
declare function BodyLimit(_size: ByteSize): ClassMarker & MethodMarker;
|
|
1209
|
-
/** Injects the native request of the adapter (escape hatch
|
|
1209
|
+
/** Injects the native request of the adapter (escape hatch). */
|
|
1210
1210
|
declare function Req(): ParameterMarker;
|
|
1211
1211
|
/**
|
|
1212
1212
|
* Injects the native response of the adapter (escape hatch; the compiler warns). The handler then
|
|
@@ -2160,4 +2160,4 @@ interface HttpAdapter {
|
|
|
2160
2160
|
readonly upgrades?: AdapterUpgrades;
|
|
2161
2161
|
}
|
|
2162
2162
|
export { BodyLimit as $, InferSchemaOutput as $n, ContentDispositionType as $t, ExceptionMapperRef as A, ConflictException as An, Validate as At, HstsOptions as B, NotFoundException as Bn, HttpInterceptorClass as Bt, PluginHttpUpgradesContext as C, ByteSize as Cn, RouteMetaEntry as Ct, PluginHttpRoutes as D, parseQuery as Dn, UploadedFiles as Dt, UpgradeHandlerOptions as E, QueryRecord as En, UploadedFile as Et, HttpRouteSummary as F, HttpErrorBody as Fn, ExceptionMapperClass as Ft, ParseSseOptions as G, UnauthorizedException as Gn, isHttpResponse as Gt, TrustProxy as H, PayloadTooLargeException as Hn, HttpResponseInit as Ht, HttpSseOptions as I, HttpException as In, ExceptionMapperResult as It, parseSseStream as J, ValidationException as Jn, SseEvent as Jt, SseItem as K, UnprocessableEntityException as Kn, StreamSource as Kt, InterceptorRef as L, HttpExceptionOptions as Ln, GuardClass as Lt, HttpCookieOptions as M, GatewayTimeoutException as Mn, CallHandler as Mt, HttpPlugin as N, GoneException as Nn, CanActivate as Nt, PluginHttpRoutesContext as O, BadGatewayException as On, UseGuard as Ot, HttpPluginOptions as P, HeaderValue as Pn, ExceptionMapper as Pt, Body as Q, InferSchemaInput as Qn, ByteRange as Qt, TrailingSlashPolicy as R, InternalServerErrorException as Rn, GuardEnforcement as Rt, PluginHttpUpgrades as S, uploads as Sn, RouteMetaCarrier as St, PluginUpgrades as T, parseByteSize as Tn, Sse as Tt, InjectSseResponse as U, ServiceUnavailableException as Un, RedirectStatus as Ut, SecurityHeadersOptions as V, NotImplementedException as Vn, HttpResponse as Vt, InjectSseWaitOptions as W, TooManyRequestsException as Wn, StreamResponseOptions as Wt, CorsOrigin as X, isHttpException as Xn, SseSource as Xt, CorsOptions as Y, ValidationIssueDetail as Yn, SseOptions as Yt, All as Z, toIssueDetail as Zn, encodeSseEvent as Zt, BunUpgrade as _, RequestId as _n, serializeClearCookie as _r, Res as _t, AdapterRoute as a, HttpMetadata as an, StandardSchemaV1Props as ar, Get as at, NodeUpgrade as b, UploadedFilesOptions as bn, RouteDecoratorInfo as bt, HttpServerAddress as c, HttpParamSource as cn, StandardSchemaV1Types as cr, Headers as ct, InjectStreamOptions as d, HttpSseDefinition as dn, CookieDefaults as dr, Param as dt, FileBody as en, StandardSchemaV1 as er, Controller as et, InjectStreamRequest as f, HttpUploadDefinition as fn, CookieOptions as fr, Patch as ft, BunSocketHandlers as g, RequestAbortedError as gn, parseSetCookie as gr, Req as gt, AdapterUpgrades as h, RequestAbortKind as hn, parseCookieHeader as hr, Query as ht, AdapterRequest as i, HttpControllerDefinition as in, StandardSchemaV1PathSegment as ir, Delete as it, GuardRef as j, ForbiddenException as jn, createRouteDecorator as jt, PluginRoute as k, BadRequestException as kn, UseInterceptor as kt, InjectRequest as l, HttpRouteDefinition as ln, isStandardSchema as lr, HttpCode as lt, ReplyBody as m, HttpRouteInfo as mn, SetCookieInfo as mr, Put as mt, AdapterHandler as n, contentDisposition as nn, StandardSchemaV1Issue as nr, Cookie as nt, FallbackHandler as o, HttpMethod as on, StandardSchemaV1Result as or, Head as ot, InjectStreamResponse as p, HttpContext as pn, ResponseCookie as pr, Post as pt, SseMessage as q, UnsupportedMediaTypeException as qn, SseBody as qt, AdapterReply as r, parseRange as rn, StandardSchemaV1Options as rr, Ctx as rt, HttpAdapter as s, HttpParamDefinition as sn, StandardSchemaV1SuccessResult as sr, Header as st, AdapterCloseOptions as t, FileResponseOptions as tn, StandardSchemaV1FailureResult as tr, ControllerOptions as tt, InjectResponse as u, HttpRouteGroupDefinition as un, ClearCookieOptions as ur, Options as ut, MemoryUpgrade as v, UploadLimits as vn, serializeCookie as vr, RouteDecorator as vt, PluginUpgradeRoute as w, formatByteSize as wn, SignedCookie as wt, PendingUpgrade as x, Uploads as xn, RouteDecoratorOptions as xt, NativeUpgrade as y, UploadedFileOptions as yn, RouteDecoratorArgs as yt, EnforcementMode as z, MethodNotAllowedException as zn, HttpInterceptor as zt };
|
|
2163
|
-
//# sourceMappingURL=adapter-
|
|
2163
|
+
//# sourceMappingURL=adapter-Dh3UF0ot.d.mts.map
|
package/dist/compiler.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cn as HttpParamSource, on as HttpMethod } from "./adapter-
|
|
1
|
+
import { cn as HttpParamSource, on as HttpMethod } from "./adapter-Dh3UF0ot.mjs";
|
|
2
2
|
import { AnalyzeContext, ClassInfo, ClassRef, CompilerExtension, Location, MethodInfo, StaticValue, ValidateContext, ValueRef } from "@znight/compiler";
|
|
3
3
|
/** Primitive coercions (`coerce.<kind>`). */
|
|
4
4
|
type ScalarCoercion = "string" | "number" | "integer" | "boolean" | "bigint" | "date";
|
package/dist/express.d.mts
CHANGED
package/dist/express.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as closeServer, Q as bufferInjectStream, V as ConnectionTracker, W as nodeAdapterRequest, X as writeNodeFailure, Z as writeNodeReply, lt as serverAddress, r as NodeUpgrades, tt as injectNodeStream } from "./upgrade-io-
|
|
1
|
+
import { H as closeServer, Q as bufferInjectStream, V as ConnectionTracker, W as nodeAdapterRequest, X as writeNodeFailure, Z as writeNodeReply, lt as serverAddress, r as NodeUpgrades, tt as injectNodeStream } from "./upgrade-io-CdQG7pZg.mjs";
|
|
2
2
|
import { toRegExpSource } from "./path.mjs";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
import express from "express";
|
package/dist/fastify.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as HttpAdapter } from "./adapter-
|
|
1
|
+
import { s as HttpAdapter } from "./adapter-Dh3UF0ot.mjs";
|
|
2
2
|
import { FastifyInstance, FastifyServerOptions } from "fastify";
|
|
3
3
|
/** Options of {@link fastifyAdapter}. */
|
|
4
4
|
export interface FastifyAdapterOptions {
|
package/dist/fastify.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ct as discardStream, G as nodeBodyStream, J as readNodeBody, K as normalizeNodeHeaders, Q as bufferInjectStream, U as isEncrypted, V as ConnectionTracker, Y as withNativeCookies, Z as writeNodeReply, at as lightStreamResponse, it as lightInjectOptions, lt as serverAddress, q as onResponseAbort, r as NodeUpgrades } from "./upgrade-io-
|
|
1
|
+
import { Ct as discardStream, G as nodeBodyStream, J as readNodeBody, K as normalizeNodeHeaders, Q as bufferInjectStream, U as isEncrypted, V as ConnectionTracker, Y as withNativeCookies, Z as writeNodeReply, at as lightStreamResponse, it as lightInjectOptions, lt as serverAddress, q as onResponseAbort, r as NodeUpgrades } from "./upgrade-io-CdQG7pZg.mjs";
|
|
2
2
|
import { toFastifyPath } from "./path.mjs";
|
|
3
3
|
import { Readable } from "node:stream";
|
|
4
4
|
import { tracingChannel } from "node:diagnostics_channel";
|
package/dist/hono.d.mts
CHANGED
package/dist/hono.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as exceedsDeclaredLength, Ct as discardStream, G as nodeBodyStream, H as closeServer, J as readNodeBody, Q as bufferInjectStream, V as ConnectionTracker, a as refusalResponse, ct as readWebStream, et as injectFetchStream, i as bunWebSocketOption, kt as BadRequestException, lt as serverAddress, q as onResponseAbort, r as NodeUpgrades, st as payloadTooLarge, t as FetchUpgradeRequest, u as isWebSocketUpgrade, ut as webBodyStream } from "./upgrade-io-
|
|
1
|
+
import { $ as exceedsDeclaredLength, Ct as discardStream, G as nodeBodyStream, H as closeServer, J as readNodeBody, Q as bufferInjectStream, V as ConnectionTracker, a as refusalResponse, ct as readWebStream, et as injectFetchStream, i as bunWebSocketOption, kt as BadRequestException, lt as serverAddress, q as onResponseAbort, r as NodeUpgrades, st as payloadTooLarge, t as FetchUpgradeRequest, u as isWebSocketUpgrade, ut as webBodyStream } from "./upgrade-io-CdQG7pZg.mjs";
|
|
2
2
|
import { toHonoPath } from "./path.mjs";
|
|
3
3
|
import { i as isBun } from "./utils-DIWdzVht.mjs";
|
|
4
4
|
import { Hono } from "hono";
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as BodyLimit, $n as InferSchemaOutput, $t as ContentDispositionType, A as ExceptionMapperRef, An as ConflictException, At as Validate, B as HstsOptions, Bn as NotFoundException, Bt as HttpInterceptorClass, C as PluginHttpUpgradesContext, Cn as ByteSize, Ct as RouteMetaEntry, D as PluginHttpRoutes, Dn as parseQuery, Dt as UploadedFiles, E as UpgradeHandlerOptions, En as QueryRecord, Et as UploadedFile, F as HttpRouteSummary, Fn as HttpErrorBody, Ft as ExceptionMapperClass, G as ParseSseOptions, Gn as UnauthorizedException, Gt as isHttpResponse, H as TrustProxy, Hn as PayloadTooLargeException, Ht as HttpResponseInit, I as HttpSseOptions, In as HttpException, It as ExceptionMapperResult, J as parseSseStream, Jn as ValidationException, Jt as SseEvent, K as SseItem, Kn as UnprocessableEntityException, Kt as StreamSource, L as InterceptorRef, Ln as HttpExceptionOptions, Lt as GuardClass, M as HttpCookieOptions, Mn as GatewayTimeoutException, Mt as CallHandler, N as HttpPlugin, Nn as GoneException, Nt as CanActivate, O as PluginHttpRoutesContext, On as BadGatewayException, Ot as UseGuard, P as HttpPluginOptions, Pn as HeaderValue, Pt as ExceptionMapper, Q as Body, Qn as InferSchemaInput, Qt as ByteRange, R as TrailingSlashPolicy, Rn as InternalServerErrorException, Rt as GuardEnforcement, S as PluginHttpUpgrades, Sn as uploads, St as RouteMetaCarrier, T as PluginUpgrades, Tn as parseByteSize, Tt as Sse, U as InjectSseResponse, Un as ServiceUnavailableException, Ut as RedirectStatus, V as SecurityHeadersOptions, Vn as NotImplementedException, Vt as HttpResponse, W as InjectSseWaitOptions, Wn as TooManyRequestsException, Wt as StreamResponseOptions, X as CorsOrigin, Xn as isHttpException, Xt as SseSource, Y as CorsOptions, Yn as ValidationIssueDetail, Yt as SseOptions, Z as All, Zn as toIssueDetail, Zt as encodeSseEvent, _ as BunUpgrade, _n as RequestId, _r as serializeClearCookie, _t as Res, a as AdapterRoute, an as HttpMetadata, ar as StandardSchemaV1Props, at as Get, b as NodeUpgrade, bn as UploadedFilesOptions, bt as RouteDecoratorInfo, c as HttpServerAddress, cn as HttpParamSource, cr as StandardSchemaV1Types, ct as Headers, d as InjectStreamOptions, dn as HttpSseDefinition, dr as CookieDefaults, dt as Param, en as FileBody, er as StandardSchemaV1, et as Controller, f as InjectStreamRequest, fn as HttpUploadDefinition, fr as CookieOptions, ft as Patch, g as BunSocketHandlers, gn as RequestAbortedError, gr as parseSetCookie, gt as Req, h as AdapterUpgrades, hn as RequestAbortKind, hr as parseCookieHeader, ht as Query, i as AdapterRequest, in as HttpControllerDefinition, ir as StandardSchemaV1PathSegment, it as Delete, j as GuardRef, jn as ForbiddenException, jt as createRouteDecorator, k as PluginRoute, kn as BadRequestException, kt as UseInterceptor, l as InjectRequest, ln as HttpRouteDefinition, lr as isStandardSchema, lt as HttpCode, m as ReplyBody, mn as HttpRouteInfo, mr as SetCookieInfo, mt as Put, n as AdapterHandler, nn as contentDisposition, nr as StandardSchemaV1Issue, nt as Cookie, o as FallbackHandler, on as HttpMethod, or as StandardSchemaV1Result, ot as Head, p as InjectStreamResponse, pn as HttpContext, pr as ResponseCookie, pt as Post, q as SseMessage, qn as UnsupportedMediaTypeException, qt as SseBody, r as AdapterReply, rn as parseRange, rr as StandardSchemaV1Options, rt as Ctx, s as HttpAdapter, sn as HttpParamDefinition, sr as StandardSchemaV1SuccessResult, st as Header, t as AdapterCloseOptions, tn as FileResponseOptions, tr as StandardSchemaV1FailureResult, tt as ControllerOptions, u as InjectResponse, un as HttpRouteGroupDefinition, ur as ClearCookieOptions, ut as Options, v as MemoryUpgrade, vn as UploadLimits, vr as serializeCookie, vt as RouteDecorator, w as PluginUpgradeRoute, wn as formatByteSize, wt as SignedCookie, x as PendingUpgrade, xn as Uploads, xt as RouteDecoratorOptions, y as NativeUpgrade, yn as UploadedFileOptions, yt as RouteDecoratorArgs, z as EnforcementMode, zn as MethodNotAllowedException, zt as HttpInterceptor } from "./adapter-
|
|
1
|
+
import { $ as BodyLimit, $n as InferSchemaOutput, $t as ContentDispositionType, A as ExceptionMapperRef, An as ConflictException, At as Validate, B as HstsOptions, Bn as NotFoundException, Bt as HttpInterceptorClass, C as PluginHttpUpgradesContext, Cn as ByteSize, Ct as RouteMetaEntry, D as PluginHttpRoutes, Dn as parseQuery, Dt as UploadedFiles, E as UpgradeHandlerOptions, En as QueryRecord, Et as UploadedFile, F as HttpRouteSummary, Fn as HttpErrorBody, Ft as ExceptionMapperClass, G as ParseSseOptions, Gn as UnauthorizedException, Gt as isHttpResponse, H as TrustProxy, Hn as PayloadTooLargeException, Ht as HttpResponseInit, I as HttpSseOptions, In as HttpException, It as ExceptionMapperResult, J as parseSseStream, Jn as ValidationException, Jt as SseEvent, K as SseItem, Kn as UnprocessableEntityException, Kt as StreamSource, L as InterceptorRef, Ln as HttpExceptionOptions, Lt as GuardClass, M as HttpCookieOptions, Mn as GatewayTimeoutException, Mt as CallHandler, N as HttpPlugin, Nn as GoneException, Nt as CanActivate, O as PluginHttpRoutesContext, On as BadGatewayException, Ot as UseGuard, P as HttpPluginOptions, Pn as HeaderValue, Pt as ExceptionMapper, Q as Body, Qn as InferSchemaInput, Qt as ByteRange, R as TrailingSlashPolicy, Rn as InternalServerErrorException, Rt as GuardEnforcement, S as PluginHttpUpgrades, Sn as uploads, St as RouteMetaCarrier, T as PluginUpgrades, Tn as parseByteSize, Tt as Sse, U as InjectSseResponse, Un as ServiceUnavailableException, Ut as RedirectStatus, V as SecurityHeadersOptions, Vn as NotImplementedException, Vt as HttpResponse, W as InjectSseWaitOptions, Wn as TooManyRequestsException, Wt as StreamResponseOptions, X as CorsOrigin, Xn as isHttpException, Xt as SseSource, Y as CorsOptions, Yn as ValidationIssueDetail, Yt as SseOptions, Z as All, Zn as toIssueDetail, Zt as encodeSseEvent, _ as BunUpgrade, _n as RequestId, _r as serializeClearCookie, _t as Res, a as AdapterRoute, an as HttpMetadata, ar as StandardSchemaV1Props, at as Get, b as NodeUpgrade, bn as UploadedFilesOptions, bt as RouteDecoratorInfo, c as HttpServerAddress, cn as HttpParamSource, cr as StandardSchemaV1Types, ct as Headers, d as InjectStreamOptions, dn as HttpSseDefinition, dr as CookieDefaults, dt as Param, en as FileBody, er as StandardSchemaV1, et as Controller, f as InjectStreamRequest, fn as HttpUploadDefinition, fr as CookieOptions, ft as Patch, g as BunSocketHandlers, gn as RequestAbortedError, gr as parseSetCookie, gt as Req, h as AdapterUpgrades, hn as RequestAbortKind, hr as parseCookieHeader, ht as Query, i as AdapterRequest, in as HttpControllerDefinition, ir as StandardSchemaV1PathSegment, it as Delete, j as GuardRef, jn as ForbiddenException, jt as createRouteDecorator, k as PluginRoute, kn as BadRequestException, kt as UseInterceptor, l as InjectRequest, ln as HttpRouteDefinition, lr as isStandardSchema, lt as HttpCode, m as ReplyBody, mn as HttpRouteInfo, mr as SetCookieInfo, mt as Put, n as AdapterHandler, nn as contentDisposition, nr as StandardSchemaV1Issue, nt as Cookie, o as FallbackHandler, on as HttpMethod, or as StandardSchemaV1Result, ot as Head, p as InjectStreamResponse, pn as HttpContext, pr as ResponseCookie, pt as Post, q as SseMessage, qn as UnsupportedMediaTypeException, qt as SseBody, r as AdapterReply, rn as parseRange, rr as StandardSchemaV1Options, rt as Ctx, s as HttpAdapter, sn as HttpParamDefinition, sr as StandardSchemaV1SuccessResult, st as Header, t as AdapterCloseOptions, tn as FileResponseOptions, tr as StandardSchemaV1FailureResult, tt as ControllerOptions, u as InjectResponse, un as HttpRouteGroupDefinition, ur as ClearCookieOptions, ut as Options, v as MemoryUpgrade, vn as UploadLimits, vr as serializeCookie, vt as RouteDecorator, w as PluginUpgradeRoute, wn as formatByteSize, wt as SignedCookie, x as PendingUpgrade, xn as Uploads, xt as RouteDecoratorOptions, y as NativeUpgrade, yn as UploadedFileOptions, yt as RouteDecoratorArgs, z as EnforcementMode, zn as MethodNotAllowedException, zt as HttpInterceptor } from "./adapter-Dh3UF0ot.mjs";
|
|
2
2
|
import { NodeAdapter, NodeAdapterOptions, nodeAdapter } from "./node.mjs";
|
|
3
3
|
import { TypedToken } from "@znight/core";
|
|
4
4
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as RouteTable, t as nodeAdapter } from "./node-
|
|
2
|
-
import { A as Req, At as ConflictException, B as isGroupOf, Bt as ServiceUnavailableException, C as HttpCode, Ct as discardStream, D as Post, Dt as trackStream, E as Patch, Et as toByteStream, F as UploadedFiles, Ft as InternalServerErrorException, Gt as ValidationException, Ht as UnauthorizedException, I as UseGuard, It as MethodNotAllowedException, Jt as toIssueDetail, Kt as isHttpException, L as UseInterceptor, Lt as NotFoundException, M as SignedCookie, Mt as GatewayTimeoutException, N as Sse, Nt as GoneException, O as Put, Ot as BadGatewayException, P as UploadedFile, Pt as HttpException, R as Validate, Rt as NotImplementedException, S as Headers, St as captureContext, T as Param, Tt as isStreamSource, Ut as UnprocessableEntityException, Vt as TooManyRequestsException, Wt as UnsupportedMediaTypeException, Xt as isValidStatus, Yt as isBodylessStatus, Zt as statusText, _ as Delete, _t as parseCookieHeader, b as Head, bt as serializeCookie, c as checkHandshake, d as All, dt as DEFAULT_COOKIE_OPTIONS, f as Body, ft as checkCookie, g as Ctx, gt as isCookieName, h as Cookie, ht as givenCookieKey, j as Res, jt as ForbiddenException, k as Query, kt as BadRequestException, l as collectPluginUpgrades, m as Controller, mt as encodeCookieValue, n as MemoryUpgradeRequest, nt as injectResponse, o as replyBytes, ot as normalizeInject, p as BodyLimit, pt as decodeCookieValue, qt as issue, rt as isEventStreamType, s as PendingUpgradeState, v as GROUP_NAME, vt as parseSetCookie, w as Options, wt as isByteStream, x as Header, xt as serializeResponseCookie, y as Get, yt as serializeClearCookie, z as createRouteDecorator, zt as PayloadTooLargeException } from "./upgrade-io-
|
|
1
|
+
import { n as RouteTable, t as nodeAdapter } from "./node-DVEO_lrR.mjs";
|
|
2
|
+
import { A as Req, At as ConflictException, B as isGroupOf, Bt as ServiceUnavailableException, C as HttpCode, Ct as discardStream, D as Post, Dt as trackStream, E as Patch, Et as toByteStream, F as UploadedFiles, Ft as InternalServerErrorException, Gt as ValidationException, Ht as UnauthorizedException, I as UseGuard, It as MethodNotAllowedException, Jt as toIssueDetail, Kt as isHttpException, L as UseInterceptor, Lt as NotFoundException, M as SignedCookie, Mt as GatewayTimeoutException, N as Sse, Nt as GoneException, O as Put, Ot as BadGatewayException, P as UploadedFile, Pt as HttpException, R as Validate, Rt as NotImplementedException, S as Headers, St as captureContext, T as Param, Tt as isStreamSource, Ut as UnprocessableEntityException, Vt as TooManyRequestsException, Wt as UnsupportedMediaTypeException, Xt as isValidStatus, Yt as isBodylessStatus, Zt as statusText, _ as Delete, _t as parseCookieHeader, b as Head, bt as serializeCookie, c as checkHandshake, d as All, dt as DEFAULT_COOKIE_OPTIONS, f as Body, ft as checkCookie, g as Ctx, gt as isCookieName, h as Cookie, ht as givenCookieKey, j as Res, jt as ForbiddenException, k as Query, kt as BadRequestException, l as collectPluginUpgrades, m as Controller, mt as encodeCookieValue, n as MemoryUpgradeRequest, nt as injectResponse, o as replyBytes, ot as normalizeInject, p as BodyLimit, pt as decodeCookieValue, qt as issue, rt as isEventStreamType, s as PendingUpgradeState, v as GROUP_NAME, vt as parseSetCookie, w as Options, wt as isByteStream, x as Header, xt as serializeResponseCookie, y as Get, yt as serializeClearCookie, z as createRouteDecorator, zt as PayloadTooLargeException } from "./upgrade-io-CdQG7pZg.mjs";
|
|
3
3
|
import { RoutePathError, compareRoutePaths, compareStrings, decodePathValue, joinPaths, matchRoutePath, normalizePath, parseRoutePath } from "./path.mjs";
|
|
4
4
|
import { a as isMediaTypePattern, i as contentTypeFor, n as parseByteSize, o as matchesMediaType, r as OCTET_STREAM, s as mediaTypeEssence, t as formatByteSize } from "./size-D8rsQcV0.mjs";
|
|
5
5
|
import { a as isThenable, i as isBun, n as errorMessage, r as fastRecord, t as emptyRecord } from "./utils-DIWdzVht.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as closeServer, Q as bufferInjectStream, V as ConnectionTracker, W as nodeAdapterRequest, X as writeNodeFailure, Z as writeNodeReply, lt as serverAddress, r as NodeUpgrades, tt as injectNodeStream } from "./upgrade-io-
|
|
1
|
+
import { H as closeServer, Q as bufferInjectStream, V as ConnectionTracker, W as nodeAdapterRequest, X as writeNodeFailure, Z as writeNodeReply, lt as serverAddress, r as NodeUpgrades, tt as injectNodeStream } from "./upgrade-io-CdQG7pZg.mjs";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
3
|
// src/router.ts
|
|
4
4
|
function createNode() {
|
|
@@ -184,4 +184,4 @@ var NodeHttpAdapter = class {
|
|
|
184
184
|
};
|
|
185
185
|
export { RouteTable as n, nodeAdapter as t };
|
|
186
186
|
|
|
187
|
-
//# sourceMappingURL=node-
|
|
187
|
+
//# sourceMappingURL=node-DVEO_lrR.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-npGnu7IW.mjs","names":[],"sources":["../src/router.ts","../src/adapters/node.ts"],"sourcesContent":["import type { RoutePath } from './path.ts'\n\ninterface RouteNode<T> {\n statics: Map<string, RouteNode<T>> | undefined\n param: RouteNode<T> | undefined\n /** Values of routes ending with a wildcard at this position, by method. */\n wildcard: Map<string, T> | undefined\n /** Values of routes ending at this node, by method. */\n values: Map<string, T> | undefined\n}\n\nfunction createNode<T>(): RouteNode<T> {\n return { statics: undefined, param: undefined, wildcard: undefined, values: undefined }\n}\n\n/**\n * A segment trie mapping `(method, route path)` to values. Lookups prefer static segments over\n * parameters over the wildcard, with backtracking (the same semantics as find-my-way), and are\n * case-sensitive on the raw request path. Used by the built-in Node adapter for routing and by the\n * plugin to tell `404 Not Found` from `405 Method Not Allowed`.\n */\nexport class RouteTable<T> {\n readonly #root: RouteNode<T> = createNode()\n #size = 0\n\n /** Number of `(method, route)` entries. */\n get size(): number {\n return this.#size\n }\n\n /**\n * Adds a value for `method` (upper case) and `route`.\n *\n * @returns the value already registered for the same method and shape, in which case nothing is\n * added.\n */\n add(method: string, route: RoutePath, value: T): T | undefined {\n let node = this.#root\n for (const segment of route.segments) {\n if (segment.kind === 'static') {\n node.statics ??= new Map()\n let child = node.statics.get(segment.value)\n if (child === undefined) {\n child = createNode()\n node.statics.set(segment.value, child)\n }\n node = child\n } else if (segment.kind === 'param') {\n node.param ??= createNode()\n node = node.param\n } else {\n node.wildcard ??= new Map()\n return this.#set(node.wildcard, method, value)\n }\n }\n node.values ??= new Map()\n return this.#set(node.values, method, value)\n }\n\n #set(map: Map<string, T>, method: string, value: T): T | undefined {\n const existing = map.get(method)\n if (existing !== undefined) return existing\n map.set(method, value)\n this.#size++\n return undefined\n }\n\n /** The value of the most specific route matching `method` and the raw `path` (no query string). */\n find(method: string, path: string): T | undefined {\n if (path.charCodeAt(0) !== 47 /* / */) return undefined\n if (path === '/') return this.#root.values?.get(method) ?? this.#root.wildcard?.get(method)\n return search(this.#root, path.split('/'), 1, method)\n }\n\n /** Methods of every route matching the raw `path`, sorted. */\n allowedMethods(path: string): string[] {\n const methods = new Set<string>()\n if (path.charCodeAt(0) === 47 /* / */) {\n if (path === '/') {\n addKeys(methods, this.#root.values)\n addKeys(methods, this.#root.wildcard)\n } else {\n collect(this.#root, path.split('/'), 1, methods)\n }\n }\n return [...methods].sort()\n }\n}\n\nfunction search<T>(node: RouteNode<T>, segments: readonly string[], index: number, method: string): T | undefined {\n if (index === segments.length) return node.values?.get(method)\n const segment = segments[index] as string\n const child = node.statics?.get(segment)\n if (child !== undefined) {\n const found = search(child, segments, index + 1, method)\n if (found !== undefined) return found\n }\n if (segment !== '' && node.param !== undefined) {\n const found = search(node.param, segments, index + 1, method)\n if (found !== undefined) return found\n }\n return node.wildcard?.get(method)\n}\n\nfunction collect<T>(node: RouteNode<T>, segments: readonly string[], index: number, methods: Set<string>): void {\n if (index === segments.length) {\n addKeys(methods, node.values)\n return\n }\n const segment = segments[index] as string\n const child = node.statics?.get(segment)\n if (child !== undefined) collect(child, segments, index + 1, methods)\n if (segment !== '' && node.param !== undefined) collect(node.param, segments, index + 1, methods)\n addKeys(methods, node.wildcard)\n}\n\nfunction addKeys(target: Set<string>, source: Map<string, unknown> | undefined): void {\n if (source !== undefined) for (const key of source.keys()) target.add(key)\n}\n","/**\n * `@znight/http/node`: the built-in, zero-dependency adapter on `node:http` (default adapter of\n * `HttpPlugin`). Works on Node.js and Bun. `inject()` uses the optional peer `light-my-request`.\n */\nimport type {\n AdapterCloseOptions,\n AdapterHandler,\n AdapterRoute,\n FallbackHandler,\n HttpAdapter,\n HttpServerAddress,\n InjectRequest,\n InjectResponse,\n InjectStreamRequest,\n InjectStreamResponse,\n} from '../adapter.ts'\n\nimport { createServer, type IncomingMessage, type Server, type ServerOptions, type ServerResponse } from 'node:http'\n\nimport { RouteTable } from '../router.ts'\nimport { ConnectionTracker, closeServer, nodeAdapterRequest, writeNodeFailure, writeNodeReply } from './node-io.ts'\nimport { bufferInjectStream, injectNodeStream, serverAddress } from './shared.ts'\nimport { NodeUpgrades } from './upgrade-io.ts'\n\n/** Options of {@link nodeAdapter}. */\nexport interface NodeAdapterOptions {\n /** Options of `http.createServer()` (timeouts, `maxHeaderSize`...). Ignored with {@link server}. */\n readonly serverOptions?: ServerOptions\n /**\n * An existing server (e.g. `https.createServer({ key, cert })`). The adapter adds its `request`\n * listener on `listen()` and closes the server on shutdown.\n */\n readonly server?: Server\n}\n\n/** The built-in Node.js adapter. */\nexport interface NodeAdapter extends HttpAdapter {\n readonly name: 'node'\n /** Request listener serving the routes, to mount the application in a server you manage. */\n readonly handler: (request: IncomingMessage, response: ServerResponse) => void\n /** The server, once listening (or the one given in the options). */\n readonly server: Server | undefined\n}\n\n/**\n * Creates the built-in `node:http` adapter: a segment-trie router (static > `:param` > `*`, with\n * backtracking), zero dependencies.\n *\n * ```ts\n * HttpPlugin.configure({ adapter: nodeAdapter({ serverOptions: { requestTimeout: 30_000 } }) })\n * ```\n */\nexport function nodeAdapter(options: NodeAdapterOptions = {}): NodeAdapter {\n return new NodeHttpAdapter(options)\n}\n\nclass NodeHttpAdapter implements NodeAdapter {\n readonly name = 'node' as const\n /** WebSocket upgrades (RFC 0003), routed by the server of {@link listen}. */\n readonly upgrades: NodeUpgrades = new NodeUpgrades()\n readonly #routes = new RouteTable<AdapterHandler>()\n readonly #options: NodeAdapterOptions\n #fallback: FallbackHandler | undefined\n #server: Server | undefined\n #tracker: ConnectionTracker | undefined\n #closing: Promise<void> | undefined\n\n constructor(options: NodeAdapterOptions) {\n this.#options = options\n this.#server = options.server\n }\n\n get server(): Server | undefined {\n return this.#server\n }\n\n registerRoute(route: AdapterRoute): void {\n if (this.#routes.add(route.method, route.path, route.handler) !== undefined) {\n throw new Error(`Duplicate route ${route.method} ${route.path.path}`)\n }\n }\n\n setFallbackHandler(handler: FallbackHandler): void {\n this.#fallback = handler\n }\n\n readonly handler = (request: IncomingMessage, response: ServerResponse): void => {\n // the listening server's connections (a request of another server is ignored)\n this.#tracker?.track(request, response)\n const url = request.url ?? '/'\n const query = url.indexOf('?')\n const handler = this.#routes.find(request.method ?? 'GET', query === -1 ? url : url.slice(0, query))\n const adapterRequest = nodeAdapterRequest(request, response)\n let reply: ReturnType<AdapterHandler>\n if (handler !== undefined) reply = handler(adapterRequest)\n else if (this.#fallback === undefined) {\n writeNodeFailure(response)\n return\n } else reply = this.#fallback(adapterRequest)\n reply.then(\n result => writeNodeReply(response, result),\n () => writeNodeFailure(response),\n )\n }\n\n async listen(port: number, host: string): Promise<HttpServerAddress> {\n const server = this.#server ?? createServer(this.#options.serverOptions ?? {})\n this.#server = server\n // `handler` counts the requests\n this.#tracker ??= new ConnectionTracker(server, { requests: false })\n this.#closing = undefined\n if (!server.listeners('request').includes(this.handler)) server.on('request', this.handler)\n this.upgrades.attach(server)\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error): void => reject(error)\n server.once('error', onError)\n server.listen(port, host, () => {\n server.off('error', onError)\n resolve()\n })\n })\n const address = server.address()\n if (address === null || typeof address === 'string') return serverAddress(host, port)\n return serverAddress(address.address, address.port, address.family)\n }\n\n close(options: AdapterCloseOptions = {}): Promise<void> {\n const server = this.#server\n const tracker = this.#tracker\n if (server === undefined || tracker === undefined) return Promise.resolve()\n this.#closing = closeServer(server, tracker, this.#closing, options.force === true)\n return this.#closing\n }\n\n inject(request: InjectRequest): Promise<InjectResponse> {\n return bufferInjectStream(stream => this.injectStream(stream), request)\n }\n\n injectStream(request: InjectStreamRequest): Promise<InjectStreamResponse> {\n return injectNodeStream('node', this.handler as (req: never, res: never) => void, request)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node-DVEO_lrR.mjs","names":[],"sources":["../src/router.ts","../src/adapters/node.ts"],"sourcesContent":["import type { RoutePath } from './path.ts'\n\ninterface RouteNode<T> {\n statics: Map<string, RouteNode<T>> | undefined\n param: RouteNode<T> | undefined\n /** Values of routes ending with a wildcard at this position, by method. */\n wildcard: Map<string, T> | undefined\n /** Values of routes ending at this node, by method. */\n values: Map<string, T> | undefined\n}\n\nfunction createNode<T>(): RouteNode<T> {\n return { statics: undefined, param: undefined, wildcard: undefined, values: undefined }\n}\n\n/**\n * A segment trie mapping `(method, route path)` to values. Lookups prefer static segments over\n * parameters over the wildcard, with backtracking (the same semantics as find-my-way), and are\n * case-sensitive on the raw request path. Used by the built-in Node adapter for routing and by the\n * plugin to tell `404 Not Found` from `405 Method Not Allowed`.\n */\nexport class RouteTable<T> {\n readonly #root: RouteNode<T> = createNode()\n #size = 0\n\n /** Number of `(method, route)` entries. */\n get size(): number {\n return this.#size\n }\n\n /**\n * Adds a value for `method` (upper case) and `route`.\n *\n * @returns the value already registered for the same method and shape, in which case nothing is\n * added.\n */\n add(method: string, route: RoutePath, value: T): T | undefined {\n let node = this.#root\n for (const segment of route.segments) {\n if (segment.kind === 'static') {\n node.statics ??= new Map()\n let child = node.statics.get(segment.value)\n if (child === undefined) {\n child = createNode()\n node.statics.set(segment.value, child)\n }\n node = child\n } else if (segment.kind === 'param') {\n node.param ??= createNode()\n node = node.param\n } else {\n node.wildcard ??= new Map()\n return this.#set(node.wildcard, method, value)\n }\n }\n node.values ??= new Map()\n return this.#set(node.values, method, value)\n }\n\n #set(map: Map<string, T>, method: string, value: T): T | undefined {\n const existing = map.get(method)\n if (existing !== undefined) return existing\n map.set(method, value)\n this.#size++\n return undefined\n }\n\n /** The value of the most specific route matching `method` and the raw `path` (no query string). */\n find(method: string, path: string): T | undefined {\n if (path.charCodeAt(0) !== 47 /* / */) return undefined\n if (path === '/') return this.#root.values?.get(method) ?? this.#root.wildcard?.get(method)\n return search(this.#root, path.split('/'), 1, method)\n }\n\n /** Methods of every route matching the raw `path`, sorted. */\n allowedMethods(path: string): string[] {\n const methods = new Set<string>()\n if (path.charCodeAt(0) === 47 /* / */) {\n if (path === '/') {\n addKeys(methods, this.#root.values)\n addKeys(methods, this.#root.wildcard)\n } else {\n collect(this.#root, path.split('/'), 1, methods)\n }\n }\n return [...methods].sort()\n }\n}\n\nfunction search<T>(node: RouteNode<T>, segments: readonly string[], index: number, method: string): T | undefined {\n if (index === segments.length) return node.values?.get(method)\n const segment = segments[index] as string\n const child = node.statics?.get(segment)\n if (child !== undefined) {\n const found = search(child, segments, index + 1, method)\n if (found !== undefined) return found\n }\n if (segment !== '' && node.param !== undefined) {\n const found = search(node.param, segments, index + 1, method)\n if (found !== undefined) return found\n }\n return node.wildcard?.get(method)\n}\n\nfunction collect<T>(node: RouteNode<T>, segments: readonly string[], index: number, methods: Set<string>): void {\n if (index === segments.length) {\n addKeys(methods, node.values)\n return\n }\n const segment = segments[index] as string\n const child = node.statics?.get(segment)\n if (child !== undefined) collect(child, segments, index + 1, methods)\n if (segment !== '' && node.param !== undefined) collect(node.param, segments, index + 1, methods)\n addKeys(methods, node.wildcard)\n}\n\nfunction addKeys(target: Set<string>, source: Map<string, unknown> | undefined): void {\n if (source !== undefined) for (const key of source.keys()) target.add(key)\n}\n","/**\n * `@znight/http/node`: the built-in, zero-dependency adapter on `node:http` (default adapter of\n * `HttpPlugin`). Works on Node.js and Bun. `inject()` uses the optional peer `light-my-request`.\n */\nimport type {\n AdapterCloseOptions,\n AdapterHandler,\n AdapterRoute,\n FallbackHandler,\n HttpAdapter,\n HttpServerAddress,\n InjectRequest,\n InjectResponse,\n InjectStreamRequest,\n InjectStreamResponse,\n} from '../adapter.ts'\n\nimport { createServer, type IncomingMessage, type Server, type ServerOptions, type ServerResponse } from 'node:http'\n\nimport { RouteTable } from '../router.ts'\nimport { ConnectionTracker, closeServer, nodeAdapterRequest, writeNodeFailure, writeNodeReply } from './node-io.ts'\nimport { bufferInjectStream, injectNodeStream, serverAddress } from './shared.ts'\nimport { NodeUpgrades } from './upgrade-io.ts'\n\n/** Options of {@link nodeAdapter}. */\nexport interface NodeAdapterOptions {\n /** Options of `http.createServer()` (timeouts, `maxHeaderSize`...). Ignored with {@link server}. */\n readonly serverOptions?: ServerOptions\n /**\n * An existing server (e.g. `https.createServer({ key, cert })`). The adapter adds its `request`\n * listener on `listen()` and closes the server on shutdown.\n */\n readonly server?: Server\n}\n\n/** The built-in Node.js adapter. */\nexport interface NodeAdapter extends HttpAdapter {\n readonly name: 'node'\n /** Request listener serving the routes, to mount the application in a server you manage. */\n readonly handler: (request: IncomingMessage, response: ServerResponse) => void\n /** The server, once listening (or the one given in the options). */\n readonly server: Server | undefined\n}\n\n/**\n * Creates the built-in `node:http` adapter: a segment-trie router (static > `:param` > `*`, with\n * backtracking), zero dependencies.\n *\n * ```ts\n * HttpPlugin.configure({ adapter: nodeAdapter({ serverOptions: { requestTimeout: 30_000 } }) })\n * ```\n */\nexport function nodeAdapter(options: NodeAdapterOptions = {}): NodeAdapter {\n return new NodeHttpAdapter(options)\n}\n\nclass NodeHttpAdapter implements NodeAdapter {\n readonly name = 'node' as const\n /** WebSocket upgrades (RFC 0003), routed by the server of {@link listen}. */\n readonly upgrades: NodeUpgrades = new NodeUpgrades()\n readonly #routes = new RouteTable<AdapterHandler>()\n readonly #options: NodeAdapterOptions\n #fallback: FallbackHandler | undefined\n #server: Server | undefined\n #tracker: ConnectionTracker | undefined\n #closing: Promise<void> | undefined\n\n constructor(options: NodeAdapterOptions) {\n this.#options = options\n this.#server = options.server\n }\n\n get server(): Server | undefined {\n return this.#server\n }\n\n registerRoute(route: AdapterRoute): void {\n if (this.#routes.add(route.method, route.path, route.handler) !== undefined) {\n throw new Error(`Duplicate route ${route.method} ${route.path.path}`)\n }\n }\n\n setFallbackHandler(handler: FallbackHandler): void {\n this.#fallback = handler\n }\n\n readonly handler = (request: IncomingMessage, response: ServerResponse): void => {\n // the listening server's connections (a request of another server is ignored)\n this.#tracker?.track(request, response)\n const url = request.url ?? '/'\n const query = url.indexOf('?')\n const handler = this.#routes.find(request.method ?? 'GET', query === -1 ? url : url.slice(0, query))\n const adapterRequest = nodeAdapterRequest(request, response)\n let reply: ReturnType<AdapterHandler>\n if (handler !== undefined) reply = handler(adapterRequest)\n else if (this.#fallback === undefined) {\n writeNodeFailure(response)\n return\n } else reply = this.#fallback(adapterRequest)\n reply.then(\n result => writeNodeReply(response, result),\n () => writeNodeFailure(response),\n )\n }\n\n async listen(port: number, host: string): Promise<HttpServerAddress> {\n const server = this.#server ?? createServer(this.#options.serverOptions ?? {})\n this.#server = server\n // `handler` counts the requests\n this.#tracker ??= new ConnectionTracker(server, { requests: false })\n this.#closing = undefined\n if (!server.listeners('request').includes(this.handler)) server.on('request', this.handler)\n this.upgrades.attach(server)\n await new Promise<void>((resolve, reject) => {\n const onError = (error: Error): void => reject(error)\n server.once('error', onError)\n server.listen(port, host, () => {\n server.off('error', onError)\n resolve()\n })\n })\n const address = server.address()\n if (address === null || typeof address === 'string') return serverAddress(host, port)\n return serverAddress(address.address, address.port, address.family)\n }\n\n close(options: AdapterCloseOptions = {}): Promise<void> {\n const server = this.#server\n const tracker = this.#tracker\n if (server === undefined || tracker === undefined) return Promise.resolve()\n this.#closing = closeServer(server, tracker, this.#closing, options.force === true)\n return this.#closing\n }\n\n inject(request: InjectRequest): Promise<InjectResponse> {\n return bufferInjectStream(stream => this.injectStream(stream), request)\n }\n\n injectStream(request: InjectStreamRequest): Promise<InjectStreamResponse> {\n return injectNodeStream('node', this.handler as (req: never, res: never) => void, request)\n }\n}\n"],"mappings":";;;AAWA,SAAS,aAA8B;CACrC,OAAO;EAAE,SAAS,KAAA;EAAW,OAAO,KAAA;EAAW,UAAU,KAAA;EAAW,QAAQ,KAAA;CAAU;AACxF;;;;;;;AAQA,IAAa,aAAb,MAA2B;CACzB,QAA+B,WAAW;CAC1C,QAAQ;;CAGR,IAAI,OAAe;EACjB,OAAO,KAAK;CACd;;;;;;;CAQA,IAAI,QAAgB,OAAkB,OAAyB;EAC7D,IAAI,OAAO,KAAK;EAChB,KAAK,MAAM,WAAW,MAAM,UAC1B,IAAI,QAAQ,SAAS,UAAU;GAC7B,KAAK,4BAAY,IAAI,IAAI;GACzB,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK;GAC1C,IAAI,UAAU,KAAA,GAAW;IACvB,QAAQ,WAAW;IACnB,KAAK,QAAQ,IAAI,QAAQ,OAAO,KAAK;GACvC;GACA,OAAO;EACT,OAAO,IAAI,QAAQ,SAAS,SAAS;GACnC,KAAK,UAAU,WAAW;GAC1B,OAAO,KAAK;EACd,OAAO;GACL,KAAK,6BAAa,IAAI,IAAI;GAC1B,OAAO,KAAK,KAAK,KAAK,UAAU,QAAQ,KAAK;EAC/C;EAEF,KAAK,2BAAW,IAAI,IAAI;EACxB,OAAO,KAAK,KAAK,KAAK,QAAQ,QAAQ,KAAK;CAC7C;CAEA,KAAK,KAAqB,QAAgB,OAAyB;EACjE,MAAM,WAAW,IAAI,IAAI,MAAM;EAC/B,IAAI,aAAa,KAAA,GAAW,OAAO;EACnC,IAAI,IAAI,QAAQ,KAAK;EACrB,KAAK;CAEP;;CAGA,KAAK,QAAgB,MAA6B;EAChD,IAAI,KAAK,WAAW,CAAC,MAAM,IAAY,OAAO,KAAA;EAC9C,IAAI,SAAS,KAAK,OAAO,KAAK,MAAM,QAAQ,IAAI,MAAM,KAAK,KAAK,MAAM,UAAU,IAAI,MAAM;EAC1F,OAAO,OAAO,KAAK,OAAO,KAAK,MAAM,GAAG,GAAG,GAAG,MAAM;CACtD;;CAGA,eAAe,MAAwB;EACrC,MAAM,0BAAU,IAAI,IAAY;EAChC,IAAI,KAAK,WAAW,CAAC,MAAM,IAAY;GACrC,IAAI,SAAS,KAAK;IAChB,QAAQ,SAAS,KAAK,MAAM,MAAM;IAClC,QAAQ,SAAS,KAAK,MAAM,QAAQ;GACtC,OACE,QAAQ,KAAK,OAAO,KAAK,MAAM,GAAG,GAAG,GAAG,OAAO;EAEnD;EACA,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK;CAC3B;AACF;AAEA,SAAS,OAAU,MAAoB,UAA6B,OAAe,QAA+B;CAChH,IAAI,UAAU,SAAS,QAAQ,OAAO,KAAK,QAAQ,IAAI,MAAM;CAC7D,MAAM,UAAU,SAAS;CACzB,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO;CACvC,IAAI,UAAU,KAAA,GAAW;EACvB,MAAM,QAAQ,OAAO,OAAO,UAAU,QAAQ,GAAG,MAAM;EACvD,IAAI,UAAU,KAAA,GAAW,OAAO;CAClC;CACA,IAAI,YAAY,MAAM,KAAK,UAAU,KAAA,GAAW;EAC9C,MAAM,QAAQ,OAAO,KAAK,OAAO,UAAU,QAAQ,GAAG,MAAM;EAC5D,IAAI,UAAU,KAAA,GAAW,OAAO;CAClC;CACA,OAAO,KAAK,UAAU,IAAI,MAAM;AAClC;AAEA,SAAS,QAAW,MAAoB,UAA6B,OAAe,SAA4B;CAC9G,IAAI,UAAU,SAAS,QAAQ;EAC7B,QAAQ,SAAS,KAAK,MAAM;EAC5B;CACF;CACA,MAAM,UAAU,SAAS;CACzB,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO;CACvC,IAAI,UAAU,KAAA,GAAW,QAAQ,OAAO,UAAU,QAAQ,GAAG,OAAO;CACpE,IAAI,YAAY,MAAM,KAAK,UAAU,KAAA,GAAW,QAAQ,KAAK,OAAO,UAAU,QAAQ,GAAG,OAAO;CAChG,QAAQ,SAAS,KAAK,QAAQ;AAChC;AAEA,SAAS,QAAQ,QAAqB,QAAgD;CACpF,IAAI,WAAW,KAAA,GAAW,KAAK,MAAM,OAAO,OAAO,KAAK,GAAG,OAAO,IAAI,GAAG;AAC3E;;;;;;;;;;AClEA,SAAgB,YAAY,UAA8B,CAAC,GAAgB;CACzE,OAAO,IAAI,gBAAgB,OAAO;AACpC;AAEA,IAAM,kBAAN,MAA6C;CAC3C,OAAgB;;CAEhB,WAAkC,IAAI,aAAa;CACnD,UAAmB,IAAI,WAA2B;CAClD;CACA;CACA;CACA;CACA;CAEA,YAAY,SAA6B;EACvC,KAAK,WAAW;EAChB,KAAK,UAAU,QAAQ;CACzB;CAEA,IAAI,SAA6B;EAC/B,OAAO,KAAK;CACd;CAEA,cAAc,OAA2B;EACvC,IAAI,KAAK,QAAQ,IAAI,MAAM,QAAQ,MAAM,MAAM,MAAM,OAAO,MAAM,KAAA,GAChE,MAAM,IAAI,MAAM,mBAAmB,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM;CAExE;CAEA,mBAAmB,SAAgC;EACjD,KAAK,YAAY;CACnB;CAEA,WAAoB,SAA0B,aAAmC;EAE/E,KAAK,UAAU,MAAM,SAAS,QAAQ;EACtC,MAAM,MAAM,QAAQ,OAAO;EAC3B,MAAM,QAAQ,IAAI,QAAQ,GAAG;EAC7B,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ,UAAU,OAAO,UAAU,KAAK,MAAM,IAAI,MAAM,GAAG,KAAK,CAAC;EACnG,MAAM,iBAAiB,mBAAmB,SAAS,QAAQ;EAC3D,IAAI;EACJ,IAAI,YAAY,KAAA,GAAW,QAAQ,QAAQ,cAAc;OACpD,IAAI,KAAK,cAAc,KAAA,GAAW;GACrC,iBAAiB,QAAQ;GACzB;EACF,OAAO,QAAQ,KAAK,UAAU,cAAc;EAC5C,MAAM,MACJ,WAAU,eAAe,UAAU,MAAM,SACnC,iBAAiB,QAAQ,CACjC;CACF;CAEA,MAAM,OAAO,MAAc,MAA0C;EACnE,MAAM,SAAS,KAAK,WAAW,aAAa,KAAK,SAAS,iBAAiB,CAAC,CAAC;EAC7E,KAAK,UAAU;EAEf,KAAK,aAAa,IAAI,kBAAkB,QAAQ,EAAE,UAAU,MAAM,CAAC;EACnE,KAAK,WAAW,KAAA;EAChB,IAAI,CAAC,OAAO,UAAU,SAAS,CAAC,CAAC,SAAS,KAAK,OAAO,GAAG,OAAO,GAAG,WAAW,KAAK,OAAO;EAC1F,KAAK,SAAS,OAAO,MAAM;EAC3B,MAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,MAAM,WAAW,UAAuB,OAAO,KAAK;GACpD,OAAO,KAAK,SAAS,OAAO;GAC5B,OAAO,OAAO,MAAM,YAAY;IAC9B,OAAO,IAAI,SAAS,OAAO;IAC3B,QAAQ;GACV,CAAC;EACH,CAAC;EACD,MAAM,UAAU,OAAO,QAAQ;EAC/B,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU,OAAO,cAAc,MAAM,IAAI;EACpF,OAAO,cAAc,QAAQ,SAAS,QAAQ,MAAM,QAAQ,MAAM;CACpE;CAEA,MAAM,UAA+B,CAAC,GAAkB;EACtD,MAAM,SAAS,KAAK;EACpB,MAAM,UAAU,KAAK;EACrB,IAAI,WAAW,KAAA,KAAa,YAAY,KAAA,GAAW,OAAO,QAAQ,QAAQ;EAC1E,KAAK,WAAW,YAAY,QAAQ,SAAS,KAAK,UAAU,QAAQ,UAAU,IAAI;EAClF,OAAO,KAAK;CACd;CAEA,OAAO,SAAiD;EACtD,OAAO,oBAAmB,WAAU,KAAK,aAAa,MAAM,GAAG,OAAO;CACxE;CAEA,aAAa,SAA6D;EACxE,OAAO,iBAAiB,QAAQ,KAAK,SAA6C,OAAO;CAC3F;AACF"}
|
package/dist/node.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as HttpAdapter } from "./adapter-
|
|
1
|
+
import { s as HttpAdapter } from "./adapter-Dh3UF0ot.mjs";
|
|
2
2
|
import { IncomingMessage, Server, ServerOptions, ServerResponse } from "node:http";
|
|
3
3
|
/** Options of {@link nodeAdapter}. */
|
|
4
4
|
export interface NodeAdapterOptions {
|
package/dist/node.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as nodeAdapter } from "./node-
|
|
1
|
+
export { t as nodeAdapter } from "./node-DVEO_lrR.mjs";
|
|
@@ -1773,7 +1773,7 @@ function UploadedFiles(_fieldOrOptions, _options) {
|
|
|
1773
1773
|
function BodyLimit(_size) {
|
|
1774
1774
|
return classOrMethodMarker;
|
|
1775
1775
|
}
|
|
1776
|
-
/** Injects the native request of the adapter (escape hatch
|
|
1776
|
+
/** Injects the native request of the adapter (escape hatch). */
|
|
1777
1777
|
function Req() {
|
|
1778
1778
|
return parameterMarker;
|
|
1779
1779
|
}
|
|
@@ -2226,4 +2226,4 @@ async function refusalResponse(reply) {
|
|
|
2226
2226
|
}
|
|
2227
2227
|
export { exceedsDeclaredLength as $, Req as A, ConflictException as At, isGroupOf as B, ServiceUnavailableException as Bt, HttpCode as C, discardStream as Ct, Post as D, trackStream as Dt, Patch as E, toByteStream as Et, UploadedFiles as F, InternalServerErrorException as Ft, nodeBodyStream as G, ValidationException as Gt, closeServer as H, UnauthorizedException as Ht, UseGuard as I, MethodNotAllowedException as It, readNodeBody as J, toIssueDetail as Jt, normalizeNodeHeaders as K, isHttpException as Kt, UseInterceptor as L, NotFoundException as Lt, SignedCookie as M, GatewayTimeoutException as Mt, Sse as N, GoneException as Nt, Put as O, BadGatewayException as Ot, UploadedFile as P, HttpException as Pt, bufferInjectStream as Q, Validate as R, NotImplementedException as Rt, Headers$1 as S, captureContext as St, Param as T, isStreamSource as Tt, isEncrypted as U, UnprocessableEntityException as Ut, ConnectionTracker as V, TooManyRequestsException as Vt, nodeAdapterRequest as W, UnsupportedMediaTypeException as Wt, writeNodeFailure as X, isValidStatus as Xt, withNativeCookies as Y, isBodylessStatus as Yt, writeNodeReply as Z, statusText as Zt, Delete as _, parseCookieHeader as _t, refusalResponse as a, lightStreamResponse as at, Head as b, serializeCookie as bt, checkHandshake as c, readWebStream as ct, All as d, DEFAULT_COOKIE_OPTIONS as dt, injectFetchStream as et, Body as f, checkCookie as ft, Ctx as g, isCookieName as gt, Cookie as h, givenCookieKey as ht, bunWebSocketOption as i, lightInjectOptions as it, Res as j, ForbiddenException as jt, Query as k, BadRequestException as kt, collectPluginUpgrades as l, serverAddress as lt, Controller as m, encodeCookieValue as mt, MemoryUpgradeRequest as n, injectResponse as nt, replyBytes as o, normalizeInject as ot, BodyLimit as p, decodeCookieValue as pt, onResponseAbort as q, issue as qt, NodeUpgrades as r, isEventStreamType as rt, PendingUpgradeState as s, payloadTooLarge as st, FetchUpgradeRequest as t, injectNodeStream as tt, isWebSocketUpgrade as u, webBodyStream as ut, GROUP_NAME as v, parseSetCookie as vt, Options as w, isByteStream as wt, Header as x, serializeResponseCookie as xt, Get as y, serializeClearCookie as yt, createRouteDecorator as z, PayloadTooLargeException as zt };
|
|
2228
2228
|
|
|
2229
|
-
//# sourceMappingURL=upgrade-io-
|
|
2229
|
+
//# sourceMappingURL=upgrade-io-CdQG7pZg.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upgrade-io-dTMDDmBi.mjs","names":["describe","invalid","Headers"],"sources":["../src/status.ts","../src/exceptions.ts","../src/stream.ts","../src/cookies.ts","../src/adapters/shared.ts","../src/adapters/node-io.ts","../src/decorators.ts","../src/upgrade.ts","../src/adapters/upgrade-io.ts"],"sourcesContent":["/** Standard reason phrases (RFC 9110 and common extensions), used in error bodies. */\nconst REASONS: Readonly<Record<number, string>> = {\n 100: 'Continue',\n 101: 'Switching Protocols',\n 102: 'Processing',\n 103: 'Early Hints',\n 200: 'OK',\n 201: 'Created',\n 202: 'Accepted',\n 203: 'Non-Authoritative Information',\n 204: 'No Content',\n 205: 'Reset Content',\n 206: 'Partial Content',\n 207: 'Multi-Status',\n 300: 'Multiple Choices',\n 301: 'Moved Permanently',\n 302: 'Found',\n 303: 'See Other',\n 304: 'Not Modified',\n 307: 'Temporary Redirect',\n 308: 'Permanent Redirect',\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 402: 'Payment Required',\n 403: 'Forbidden',\n 404: 'Not Found',\n 405: 'Method Not Allowed',\n 406: 'Not Acceptable',\n 407: 'Proxy Authentication Required',\n 408: 'Request Timeout',\n 409: 'Conflict',\n 410: 'Gone',\n 411: 'Length Required',\n 412: 'Precondition Failed',\n 413: 'Payload Too Large',\n 414: 'URI Too Long',\n 415: 'Unsupported Media Type',\n 416: 'Range Not Satisfiable',\n 417: 'Expectation Failed',\n 418: \"I'm a Teapot\",\n 421: 'Misdirected Request',\n 422: 'Unprocessable Entity',\n 423: 'Locked',\n 424: 'Failed Dependency',\n 425: 'Too Early',\n 426: 'Upgrade Required',\n 428: 'Precondition Required',\n 429: 'Too Many Requests',\n 431: 'Request Header Fields Too Large',\n 451: 'Unavailable For Legal Reasons',\n 500: 'Internal Server Error',\n 501: 'Not Implemented',\n 502: 'Bad Gateway',\n 503: 'Service Unavailable',\n 504: 'Gateway Timeout',\n 505: 'HTTP Version Not Supported',\n 507: 'Insufficient Storage',\n 508: 'Loop Detected',\n 511: 'Network Authentication Required',\n}\n\n/** Reason phrase of `status` (`404` → `Not Found`), or a generic one for unknown codes. */\nexport function statusText(status: number): string {\n const reason = REASONS[status]\n if (reason !== undefined) return reason\n if (status >= 500) return 'Server Error'\n return status >= 400 ? 'Client Error' : 'Unknown Status'\n}\n\n/** Whether `status` is an integer in the 100–599 range. */\nexport function isValidStatus(status: unknown): status is number {\n return typeof status === 'number' && Number.isInteger(status) && status >= 100 && status <= 599\n}\n\n/** Statuses whose responses never have a body. */\nexport function isBodylessStatus(status: number): boolean {\n return status === 204 || status === 304 || (status >= 100 && status < 200)\n}\n","import type { StandardSchemaV1Issue } from './standard-schema.ts'\n\nimport { isValidStatus, statusText } from './status.ts'\n\n/** Response header values: a single value or several (`set-cookie`). */\nexport type HeaderValue = string | readonly string[]\n\n/** Options of {@link HttpException}. */\nexport interface HttpExceptionOptions extends ErrorOptions {\n /** Headers added to the error response (`www-authenticate`, `retry-after`, `allow`...). */\n readonly headers?: Readonly<Record<string, HeaderValue>>\n}\n\n/** JSON body of an error response. */\nexport interface HttpErrorBody {\n readonly statusCode: number\n /** Reason phrase of the status (`Not Found`). */\n readonly error: string\n readonly message: string\n /** Structured details (validation issues...), omitted when absent. */\n readonly details?: unknown\n}\n\n/** One entry of the `details` of a validation error. */\nexport interface ValidationIssueDetail {\n /** Dotted path of the invalid value inside the validated input (`user.email`, `items.0`), `''` for the root. */\n readonly path: string\n readonly message: string\n}\n\nconst NO_HEADERS: Readonly<Record<string, HeaderValue>> = Object.freeze({})\n\n/**\n * An error carrying an HTTP status. Thrown from handlers, guards, interceptors or services, it is\n * rendered as `{ statusCode, error, message, details? }` with its status and headers.\n *\n * ```ts\n * throw new HttpException(409, 'Email already used', { field: 'email' })\n * throw new NotFoundException(`User ${id} not found`)\n * throw new UnauthorizedException('Token expired', undefined, { headers: { 'www-authenticate': 'Bearer' } })\n * ```\n *\n * Invalid statuses (not an integer in 100–599) become `500`.\n */\nexport class HttpException extends Error {\n /** HTTP status of the response. */\n readonly status: number\n /** Structured details rendered in the body (omitted when `undefined`). */\n readonly details: unknown\n /** Headers added to the response. */\n readonly headers: Readonly<Record<string, HeaderValue>>\n\n constructor(status: number, message?: string, details?: unknown, options: HttpExceptionOptions = {}) {\n const code = isValidStatus(status) ? status : 500\n super(message ?? statusText(code), options.cause === undefined ? undefined : { cause: options.cause })\n this.name = 'HttpException'\n this.status = code\n this.details = details\n this.headers = options.headers ?? NO_HEADERS\n }\n\n /** The `statusCode` field of the body (alias of {@link status}). */\n get statusCode(): number {\n return this.status\n }\n\n /** Body of the error response. Override it in a subclass to change the shape. */\n toBody(): HttpErrorBody {\n const body: { statusCode: number; error: string; message: string; details?: unknown } = {\n statusCode: this.status,\n error: statusText(this.status),\n message: this.message,\n }\n if (this.details !== undefined) body.details = this.details\n return body\n }\n}\n\n/** Whether `value` is an {@link HttpException} (also across duplicated package copies). */\nexport function isHttpException(value: unknown): value is HttpException {\n return (\n value instanceof HttpException ||\n (value instanceof Error &&\n typeof (value as { status?: unknown }).status === 'number' &&\n typeof (value as { toBody?: unknown }).toBody === 'function')\n )\n}\n\n/** 400 Bad Request. */\nexport class BadRequestException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(400, message, details, options)\n this.name = 'BadRequestException'\n }\n}\n\n/**\n * 400 Bad Request raised when an input fails its schema (`@Body(schema)`, `@Query(schema)`...).\n * `details` lists the issues as `{ path, message }`; the raw Standard Schema issues are kept in\n * {@link issues} for exception mappers.\n */\nexport class ValidationException extends BadRequestException {\n /** What was validated: `body`, `query`, `query \"page\"`, `param \"id\"`... */\n readonly location: string\n readonly issues: readonly StandardSchemaV1Issue[]\n\n constructor(location: string, issues: readonly StandardSchemaV1Issue[], options?: HttpExceptionOptions) {\n super(`Invalid ${location}`, issues.map(toIssueDetail), options)\n this.name = 'ValidationException'\n this.location = location\n this.issues = issues\n }\n}\n\n/**\n * The `details` of a 400 raised by the framework for one invalid input (a multipart field...): the\n * shape of the issues of {@link ValidationException}, documented by `@znight/openapi`.\n */\nexport function issue(path: string, message: string): readonly ValidationIssueDetail[] {\n return [{ path, message }]\n}\n\n/** Converts a Standard Schema issue to `{ path, message }` (`path` dotted, `''` for the root). */\nexport function toIssueDetail(issue: StandardSchemaV1Issue): ValidationIssueDetail {\n return { path: formatIssuePath(issue.path), message: issue.message }\n}\n\nfunction formatIssuePath(path: StandardSchemaV1Issue['path']): string {\n if (path === undefined || path.length === 0) return ''\n let result = ''\n for (const segment of path) {\n const key = typeof segment === 'object' && segment !== null ? segment.key : segment\n const text = typeof key === 'symbol' ? (key.description ?? 'symbol') : String(key)\n result = result === '' ? text : `${result}.${text}`\n }\n return result\n}\n\n/** 401 Unauthorized. */\nexport class UnauthorizedException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(401, message, details, options)\n this.name = 'UnauthorizedException'\n }\n}\n\n/** 403 Forbidden (also the response of a guard returning `false`). */\nexport class ForbiddenException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(403, message, details, options)\n this.name = 'ForbiddenException'\n }\n}\n\n/** 404 Not Found. */\nexport class NotFoundException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(404, message, details, options)\n this.name = 'NotFoundException'\n }\n}\n\n/** 405 Method Not Allowed (pass the `allow` header in `options.headers`). */\nexport class MethodNotAllowedException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(405, message, details, options)\n this.name = 'MethodNotAllowedException'\n }\n}\n\n/** 409 Conflict. */\nexport class ConflictException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(409, message, details, options)\n this.name = 'ConflictException'\n }\n}\n\n/** 410 Gone. */\nexport class GoneException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(410, message, details, options)\n this.name = 'GoneException'\n }\n}\n\n/** 413 Payload Too Large (request body above `bodyLimit`). */\nexport class PayloadTooLargeException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(413, message, details, options)\n this.name = 'PayloadTooLargeException'\n }\n}\n\n/** 415 Unsupported Media Type. */\nexport class UnsupportedMediaTypeException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(415, message, details, options)\n this.name = 'UnsupportedMediaTypeException'\n }\n}\n\n/** 422 Unprocessable Entity. */\nexport class UnprocessableEntityException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(422, message, details, options)\n this.name = 'UnprocessableEntityException'\n }\n}\n\n/** 429 Too Many Requests (pass `retry-after` in `options.headers`). */\nexport class TooManyRequestsException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(429, message, details, options)\n this.name = 'TooManyRequestsException'\n }\n}\n\n/** 500 Internal Server Error (its message is always sent, unlike unexpected errors). */\nexport class InternalServerErrorException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(500, message, details, options)\n this.name = 'InternalServerErrorException'\n }\n}\n\n/** 501 Not Implemented. */\nexport class NotImplementedException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(501, message, details, options)\n this.name = 'NotImplementedException'\n }\n}\n\n/** 502 Bad Gateway. */\nexport class BadGatewayException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(502, message, details, options)\n this.name = 'BadGatewayException'\n }\n}\n\n/** 503 Service Unavailable. */\nexport class ServiceUnavailableException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(503, message, details, options)\n this.name = 'ServiceUnavailableException'\n }\n}\n\n/** 504 Gateway Timeout. */\nexport class GatewayTimeoutException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(504, message, details, options)\n this.name = 'GatewayTimeoutException'\n }\n}\n","/**\n * Web stream helpers shared by the pipeline and the adapters (internal): conversion of handler\n * stream sources (`ReadableStream`, Node.js `Readable`, async iterables) to byte streams, tracking of\n * response streams (request scope lifetime) and small constructors.\n */\nimport { AsyncLocalStorage } from 'node:async_hooks'\n\n/**\n * A stream source accepted by `HttpResponse.stream()`: a Web `ReadableStream`, a Node.js `Readable`\n * or any async iterable (async generator...) of `Uint8Array` / `string` chunks (strings are encoded\n * as UTF-8).\n */\nexport type StreamSource = ReadableStream<Uint8Array | string> | AsyncIterable<Uint8Array | string>\n\n/** Runs a function in a captured async context (`AsyncLocalStorage.snapshot()`). */\nexport type ContextRunner = <R>(fn: () => R) => R\n\nconst ENCODER = new TextEncoder()\n\n/** The current async context, to run stream reads in it later (the request scope of a response). */\nexport function captureContext(): ContextRunner {\n const snapshot = (AsyncLocalStorage as { snapshot?: () => ContextRunner }).snapshot\n return typeof snapshot === 'function' ? snapshot() : run => run()\n}\n\n/** Whether `value` is a stream source (Web stream, Node.js readable or async iterable). */\nexport function isStreamSource(value: unknown): value is StreamSource {\n return (\n value instanceof ReadableStream ||\n (value !== null &&\n typeof value === 'object' &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function')\n )\n}\n\n/** Byte streams created by {@link toByteStream} (already normalised: not wrapped again). */\nconst BYTE_STREAMS = new WeakSet<ReadableStream<Uint8Array>>()\n\n/** Whether `stream` was created by {@link toByteStream}. */\nexport function isByteStream(stream: ReadableStream<unknown>): boolean {\n return BYTE_STREAMS.has(stream as ReadableStream<Uint8Array>)\n}\n\n/**\n * Converts a stream source to a pull-based byte stream: the source is read only when the consumer\n * reads (backpressure), strings are encoded as UTF-8, `ArrayBuffer`s and views are converted, empty\n * chunks are skipped and cancelling the stream cancels the source (`iterator.return()`, which\n * destroys a Node.js `Readable`; a `Readable` that was never read is destroyed directly).\n *\n * @throws TypeError (as a stream error) for chunks that are neither bytes nor strings.\n */\nexport function toByteStream(source: StreamSource): ReadableStream<Uint8Array> {\n let iterator: AsyncIterator<unknown> | undefined\n let reader: ChunkReader | undefined\n const next = (): Promise<IteratorResult<unknown>> => {\n if (source instanceof ReadableStream) {\n const current: ChunkReader = reader ?? source.getReader()\n reader = current\n return current.read() as Promise<IteratorResult<unknown>>\n }\n iterator ??= source[Symbol.asyncIterator]()\n return iterator.next()\n }\n const stream = new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n for (;;) {\n const result = await next()\n if (result.done === true) {\n controller.close()\n return\n }\n const chunk = toChunk(result.value)\n if (chunk.byteLength > 0) {\n controller.enqueue(chunk)\n return\n }\n }\n },\n async cancel(reason) {\n if (reader !== undefined) await reader.cancel(reason)\n else if (source instanceof ReadableStream) await source.cancel(reason)\n else if (iterator === undefined) {\n // never read: an async generator has nothing to clean up, a Node.js `Readable` holds its resource\n const destroyable = source as { destroy?: unknown }\n if (typeof destroyable.destroy === 'function') destroyable.destroy()\n } else await iterator.return?.(reason)\n },\n },\n { highWaterMark: 0 },\n )\n BYTE_STREAMS.add(stream)\n return stream\n}\n\n/** The part of a stream reader used here (Node.js and Bun declare different reader types). */\ninterface ChunkReader {\n read(): Promise<{ readonly done?: boolean; readonly value?: unknown }>\n cancel(reason?: unknown): Promise<void>\n}\n\nfunction toChunk(value: unknown): Uint8Array {\n if (value instanceof Uint8Array) return value\n if (typeof value === 'string') return ENCODER.encode(value)\n if (value instanceof ArrayBuffer) return new Uint8Array(value)\n if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n throw new TypeError(\n `Invalid stream chunk: expected a Uint8Array or a string, received ${value === null ? 'null' : typeof value}`,\n )\n}\n\n/** The part of a byte stream reader used by {@link trackStream}. */\ninterface ByteReader {\n read(): Promise<{ readonly done?: boolean; readonly value?: Uint8Array | undefined }>\n cancel(reason?: unknown): Promise<void>\n}\n\n/** A response stream whose completion is observed. */\nexport interface TrackedStream {\n readonly stream: ReadableStream<Uint8Array>\n /**\n * Resolves once the source was fully read (`undefined`), cancelled by the consumer (`undefined`:\n * client disconnected, HEAD...) or failed (the error). Never rejects.\n */\n readonly done: Promise<unknown>\n}\n\n/**\n * Wraps a response body so that the pipeline knows when it has been fully sent (or abandoned) and\n * reads the source in `run` (the async context of the request scope, so that stream producers can\n * use request-scoped providers). The wrapper is pull-based (no read-ahead): backpressure is the\n * consumer's. A `Blob` is read through `blob.stream()`, opened on the first read only. `onCancel`\n * runs when the consumer cancels the stream (the client left), before the source is cancelled.\n */\nexport function trackStream(\n body: ReadableStream<Uint8Array> | Blob,\n run: ContextRunner,\n onCancel?: () => void,\n): TrackedStream {\n let reader: ByteReader | undefined = body instanceof Blob ? undefined : body.getReader()\n let settle: (error: unknown) => void = () => undefined\n const done = new Promise<unknown>(resolve => {\n settle = resolve\n })\n let finished = false\n const finish = (error?: unknown): void => {\n if (finished) return\n finished = true\n settle(error)\n }\n const stream = new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n let result: Awaited<ReturnType<ByteReader['read']>>\n try {\n result = await run(() => {\n reader ??= (body as Blob).stream().getReader()\n return reader.read()\n })\n } catch (error) {\n finish(error)\n throw error\n }\n if (result.done === true) {\n controller.close()\n finish()\n return\n }\n controller.enqueue(result.value as Uint8Array)\n },\n async cancel(reason) {\n onCancel?.()\n try {\n const current = reader\n if (current !== undefined) await run(() => current.cancel(reason))\n } catch {\n // the source failed while being cancelled: nothing left to send anyway\n } finally {\n finish()\n }\n },\n },\n { highWaterMark: 0 },\n )\n return { stream, done }\n}\n\n/** A stream failing with `error` on first read. */\nexport function failedStream(error: unknown): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.error(error)\n },\n })\n}\n\n/** Cancels a stream, ignoring failures (unconsumed response bodies). */\nexport function discardStream(stream: ReadableStream<Uint8Array> | null | undefined): void {\n if (stream instanceof ReadableStream && !stream.locked) stream.cancel().catch(() => undefined)\n}\n","/**\n * Cookies (RFC 0006): parsing of the `cookie` request header, canonical value encoding, strict\n * `Set-Cookie` serialisation (RFC 6265bis: attribute validation, name prefixes, size limits),\n * `Set-Cookie` parsing (tests) and the response cookie jar.\n *\n * This module is import-free (pure functions): safe to import from anywhere, the compiler excepted\n * (it has its own token grammar).\n */\n\n/** Options of a cookie set on a response (`ctx.setCookie()`, `HttpResponse.withCookie()`). */\nexport interface CookieOptions {\n /** Lifetime in seconds (integer). `0` or less expires the cookie now. Default: session cookie. */\n readonly maxAge?: number\n /**\n * Absolute expiry (sent as an IMF-fixdate), in the years 1601 to 9999 (browsers ignore other\n * years). Browsers cap lifetimes at 400 days: prefer `maxAge` for long-lived cookies.\n */\n readonly expires?: Date\n /**\n * Domain (sub-domains included). Default: none, a host-only cookie. `null`: host-only even when\n * `cookies.defaults` sets a domain. `__Host-` cookies never take the default domain.\n */\n readonly domain?: string | null\n /** Default: `'/'`. */\n readonly path?: string\n /** Default: `true` (browsers only send it over HTTPS, `http://localhost` excepted). */\n readonly secure?: boolean\n /** Default: `true` (not readable from JavaScript). */\n readonly httpOnly?: boolean\n /** Default: `'lax'`. `'none'` requires `secure`. */\n readonly sameSite?: 'strict' | 'lax' | 'none'\n /** CHIPS partitioned cookie. Requires `secure`. Default: `false`. */\n readonly partitioned?: boolean\n /** Chromium `Priority`. Default: none. */\n readonly priority?: 'low' | 'medium' | 'high'\n /** Signs the value with the first secret of the plugin option `cookies.secrets`. Default: `false`. */\n readonly signed?: boolean\n}\n\n/** Plugin-wide defaults (`cookies.defaults`). Lifetime and signing are per cookie. */\nexport type CookieDefaults = Omit<CookieOptions, 'maxAge' | 'expires' | 'signed'>\n\n/** What identifies a cookie to clear (and keeps prefixed names valid). */\nexport type ClearCookieOptions = Pick<\n CookieOptions,\n 'domain' | 'path' | 'secure' | 'httpOnly' | 'sameSite' | 'partitioned'\n>\n\n/** A cookie to send, as given (defaults and signing are applied when the response is serialised). */\nexport interface ResponseCookie {\n readonly name: string\n /** `undefined`: a clearing cookie. */\n readonly value: string | undefined\n readonly options: CookieOptions\n}\n\n/** A parsed `Set-Cookie` line (see {@link parseSetCookie}). */\nexport interface SetCookieInfo {\n readonly name: string\n /** Decoded value (a signed cookie: `\"<value>.<signature>\"`, decoded). */\n readonly value: string\n /** The header line. */\n readonly raw: string\n readonly expires?: Date\n readonly maxAge?: number\n readonly domain?: string\n readonly path?: string\n readonly secure: boolean\n readonly httpOnly: boolean\n readonly sameSite?: 'strict' | 'lax' | 'none'\n readonly partitioned: boolean\n readonly priority?: 'low' | 'medium' | 'high'\n}\n\n/** The secure defaults: `Path=/; Secure; HttpOnly; SameSite=Lax`, host-only. */\nexport const DEFAULT_COOKIE_OPTIONS: Readonly<{\n path: string\n secure: boolean\n httpOnly: boolean\n sameSite: 'strict' | 'lax' | 'none'\n}> = Object.freeze({ path: '/', secure: true, httpOnly: true, sameSite: 'lax' })\n\n/** Largest `name=value` (bytes on the wire, after encoding and signing). */\nexport const MAX_COOKIE_SIZE = 4096\n/** Largest `Domain` / `Path` attribute value (bytes). */\nexport const MAX_COOKIE_ATTRIBUTE_SIZE = 1024\nconst MAX_DOMAIN_LENGTH = 253\nconst EPOCH = 'Thu, 01 Jan 1970 00:00:00 GMT'\n/** Years a cookie-date can carry (RFC 6265 §5.1.1; four digits in an IMF-fixdate). */\nconst MIN_EXPIRES_YEAR = 1601\nconst MAX_EXPIRES_YEAR = 9999\n\nconst OPTION_KEYS: ReadonlySet<string> = new Set([\n 'maxAge',\n 'expires',\n 'domain',\n 'path',\n 'secure',\n 'httpOnly',\n 'sameSite',\n 'partitioned',\n 'priority',\n 'signed',\n])\nconst SAME_SITE: Readonly<Record<string, string>> = { strict: 'Strict', lax: 'Lax', none: 'None' }\nconst PRIORITY: Readonly<Record<string, string>> = { low: 'Low', medium: 'Medium', high: 'High' }\n\n// -------------------------------------------------------------------------------------------------\n// Request cookies\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Parses a `cookie` request header into a prototype-less, frozen record (`__proto__` is just a\n * name). Pairs are split on `;` only (never `,`) and trimmed; a pair without `=` or with an empty\n * name is ignored; names are kept as sent (case-sensitive); a value wrapped in double quotes is\n * unquoted, and percent-decoded when it contains `%` (a malformed sequence keeps the raw value).\n * When a name repeats, the first occurrence wins (browsers send the most specific path first).\n * Linear time, never throws.\n */\nexport function parseCookieHeader(header: string | undefined): Readonly<Record<string, string>> {\n const result = Object.create(null) as Record<string, string>\n if (typeof header === 'string') {\n let start = 0\n const length = header.length\n // the next `=` at or after `start`, searched again only once passed: every character is scanned\n // at most twice, even for a header made of `;` without `=` (linear time)\n let equals = -1\n while (start < length) {\n let end = header.indexOf(';', start)\n if (end === -1) end = length\n if (equals < start) {\n equals = header.indexOf('=', start)\n if (equals === -1) equals = length\n }\n if (equals < end) {\n const name = trim(header, start, equals)\n if (name !== '' && !Object.hasOwn(result, name)) {\n result[name] = decodeCookieValue(unquote(trim(header, equals + 1, end)))\n }\n }\n start = end + 1\n }\n }\n return Object.freeze(result)\n}\n\n/** `text.slice(start, end)` without leading and trailing SP / HTAB. */\nfunction trim(text: string, start: number, end: number): string {\n let from = start\n let to = end\n while (from < to && isBlank(text.charCodeAt(from))) from++\n while (to > from && isBlank(text.charCodeAt(to - 1))) to--\n return text.slice(from, to)\n}\n\nfunction isBlank(code: number): boolean {\n return code === 0x20 || code === 0x09\n}\n\nfunction unquote(value: string): string {\n return value.length >= 2 && value.charCodeAt(0) === 0x22 && value.charCodeAt(value.length - 1) === 0x22\n ? value.slice(1, -1)\n : value\n}\n\n/**\n * Decodes a cookie value produced by {@link encodeCookieValue} (`decodeURIComponent` when it\n * contains `%`; a malformed sequence keeps the raw value). Never throws.\n */\nexport function decodeCookieValue(value: string): string {\n if (!value.includes('%')) return value\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\n/**\n * Encodes a cookie value canonically: the UTF-8 bytes outside RFC 6265 `cookie-octet` (space, `\"`,\n * `,`, `;`, `\\`, controls, non-ASCII) and `%` are percent-encoded (upper-case hex), so that\n * {@link decodeCookieValue} restores the value exactly (`a b;c` → `a%20b%3Bc`), and\n * `encode(decode(w)) === w` for every encoded `w`. Quotes are never emitted.\n *\n * @throws TypeError for a non-string or a string with lone surrogates (they cannot round-trip).\n */\nexport function encodeCookieValue(value: string): string {\n if (typeof value !== 'string') {\n throw new TypeError(`A cookie value must be a string (received ${describe(value)})`)\n }\n if (!value.isWellFormed()) {\n throw new TypeError('A cookie value must be a well-formed string (it contains a lone surrogate)')\n }\n let encoded = ''\n let plain = 0\n for (let index = 0; index < value.length; index++) {\n const code = value.charCodeAt(index)\n if (isCookieOctet(code)) continue\n encoded += value.slice(plain, index)\n if (code < 0x80) {\n encoded += `%${HEX[code] as string}`\n plain = index + 1\n } else {\n // a whole code point (a surrogate pair is two UTF-16 units): `encodeURIComponent` gives its UTF-8 bytes\n const point = value.codePointAt(index) as number\n const width = point > 0xffff ? 2 : 1\n encoded += encodeURIComponent(value.slice(index, index + width))\n index += width - 1\n plain = index + 1\n }\n }\n return plain === 0 ? value : encoded + value.slice(plain)\n}\n\nconst HEX: readonly string[] = Array.from({ length: 128 }, (_, code) =>\n code.toString(16).toUpperCase().padStart(2, '0'),\n)\n\n/** RFC 6265 `cookie-octet`, `%` excluded (the escape character). */\nfunction isCookieOctet(code: number): boolean {\n return (\n code === 0x21 ||\n (code >= 0x23 && code <= 0x2b && code !== 0x25) ||\n (code >= 0x2d && code <= 0x3a) ||\n (code >= 0x3c && code <= 0x5b) ||\n (code >= 0x5d && code <= 0x7e)\n )\n}\n\n/** Whether `name` is an RFC 9110 token (a cookie name Znight can set). */\nexport function isCookieName(name: unknown): name is string {\n if (typeof name !== 'string' || name === '') return false\n for (let index = 0; index < name.length; index++) {\n if (!isTokenChar(name.charCodeAt(index))) return false\n }\n return true\n}\n\nfunction isTokenChar(code: number): boolean {\n // ! # $ % & ' * + - . ^ _ ` | ~ DIGIT ALPHA\n return (\n (code >= 0x30 && code <= 0x39) ||\n (code >= 0x41 && code <= 0x5a) ||\n (code >= 0x61 && code <= 0x7a) ||\n code === 0x21 ||\n (code >= 0x23 && code <= 0x27) ||\n code === 0x2a ||\n code === 0x2b ||\n code === 0x2d ||\n code === 0x2e ||\n code === 0x5e ||\n code === 0x5f ||\n code === 0x60 ||\n code === 0x7c ||\n code === 0x7e\n )\n}\n\n// -------------------------------------------------------------------------------------------------\n// Response cookies\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Checks what a cookie says about itself, without plugin defaults: the name, the value type, the\n * options (types, `maxAge`, `expires`, `domain`, `path`) and the size before signing. Run by\n * `HttpResponse.withCookie()` / `withoutCookie()` at call time; the rules depending on the defaults\n * (prefixes, `SameSite=None` and `partitioned` with `secure`), signing and the final size are checked\n * when the response is serialised.\n *\n * @throws TypeError / RangeError naming the cookie.\n */\nexport function checkCookie(name: string, value: string | undefined, options: CookieOptions | undefined): void {\n checkName(name)\n const checked = checkOptions(name, options)\n if (value !== undefined) {\n const encoded = encodeValue(name, value)\n checkSize(name, encoded)\n }\n if (typeof checked.domain === 'string') normalizeDomain(name, checked.domain)\n if (checked.path !== undefined) checkPath(name, checked.path)\n}\n\n/** A cookie resolved with the defaults: its `Set-Cookie` line and its jar key. */\nexport interface SerializedCookie {\n /** `name` + domain + path: a later cookie with the same key replaces an earlier one. */\n readonly key: string\n readonly line: string\n}\n\n/**\n * Serialises a response cookie with `defaults` (merged under the options): every rule of RFC 0006\n * §4.3 is checked. `sign` turns the encoded value into its signed wire form (`signed: true`).\n *\n * @throws TypeError / RangeError naming the cookie.\n */\nexport function serializeResponseCookie(\n cookie: ResponseCookie,\n defaults: CookieDefaults,\n sign?: (name: string, encoded: string) => string,\n): SerializedCookie {\n const { name, value } = cookie\n checkName(name)\n const options = checkOptions(name, cookie.options)\n checkOptions(name, defaults, true)\n const attributes = resolveAttributes(name, { ...applicableDefaults(name, defaults), ...definedOnly(options) })\n let wire: string\n let maxAge: number | undefined\n let expires: string | undefined\n if (value === undefined) {\n wire = ''\n maxAge = 0\n expires = EPOCH\n } else {\n wire = encodeValue(name, value)\n if (options.signed === true) {\n if (sign === undefined) throw new TypeError(`Cannot sign the cookie \"${name}\": no signing key`)\n wire = sign(name, wire)\n }\n if (options.maxAge !== undefined) maxAge = Math.max(options.maxAge, 0)\n if (options.expires !== undefined) expires = options.expires.toUTCString()\n }\n checkSize(name, wire)\n let line = `${name}=${wire}`\n if (maxAge !== undefined) line += `; Max-Age=${maxAge}`\n if (expires !== undefined) line += `; Expires=${expires}`\n if (attributes.domain !== undefined) line += `; Domain=${attributes.domain}`\n line += `; Path=${attributes.path}`\n if (attributes.secure) line += '; Secure'\n if (attributes.httpOnly) line += '; HttpOnly'\n if (attributes.sameSite !== undefined) line += `; SameSite=${SAME_SITE[attributes.sameSite] as string}`\n if (attributes.partitioned) line += '; Partitioned'\n if (attributes.priority !== undefined && value !== undefined) {\n line += `; Priority=${PRIORITY[attributes.priority] as string}`\n }\n return { key: cookieKey(name, attributes.domain, attributes.path), line }\n}\n\n/**\n * The `Set-Cookie` line of a cookie with the secure defaults\n * (`Path=/; Secure; HttpOnly; SameSite=Lax`, overridable per cookie), in the order\n * `name=value; Max-Age; Expires; Domain; Path; Secure; HttpOnly; SameSite; Partitioned; Priority`.\n * The value is percent-encoded (see {@link encodeCookieValue}). Signing (`signed: true`) needs the\n * secrets of the plugin: use `ctx.setCookie()` or `HttpPlugin.signCookie()`.\n *\n * ```ts\n * serializeCookie('theme', 'dark', { maxAge: 86_400, httpOnly: false })\n * // theme=dark; Max-Age=86400; Path=/; Secure; SameSite=Lax\n * ```\n *\n * @throws TypeError for an invalid name, value or attribute, a `SameSite=None` or partitioned cookie\n * without `Secure`, a broken `__Secure-` / `__Host-` / `__Http-` / `__Host-Http-` prefix rule.\n * @throws RangeError when `name=value` exceeds 4096 bytes, or `Domain` / `Path` 1024 bytes.\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n return serializeResponseCookie({ name, value, options }, DEFAULT_COOKIE_OPTIONS).line\n}\n\n/**\n * The `Set-Cookie` line clearing a cookie: `name=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT`\n * plus `Domain`, `Path`, `Secure`, `HttpOnly`, `SameSite` and `Partitioned` (secure defaults merged\n * with `options`), so that a prefixed cookie is cleared with valid attributes.\n */\nexport function serializeClearCookie(name: string, options: ClearCookieOptions = {}): string {\n return serializeResponseCookie({ name, value: undefined, options }, DEFAULT_COOKIE_OPTIONS).line\n}\n\n/** The jar key of a cookie (RFC 6265: a cookie is identified by its name, domain and path). */\nexport function cookieKey(name: string, domain: string | undefined, path: string): string {\n return `${name}\\u0000${domain ?? ''}\\u0000${path}`\n}\n\ninterface Attributes {\n readonly domain: string | undefined\n readonly path: string\n readonly secure: boolean\n readonly httpOnly: boolean\n readonly sameSite: 'strict' | 'lax' | 'none' | undefined\n readonly partitioned: boolean\n readonly priority: 'low' | 'medium' | 'high' | undefined\n}\n\n/**\n * The defaults a cookie takes: all of them, but a `__Host-` cookie (host-only, `Path=/` by\n * definition) never takes a default domain or path. Its own options are still checked.\n */\nfunction applicableDefaults(name: string, defaults: CookieDefaults): CookieDefaults {\n if (!name.toLowerCase().startsWith('__host-')) return defaults\n const { domain: _domain, path: _path, ...rest } = defaults\n return rest\n}\n\n/** Attributes after the defaults, checked against the cross-attribute and prefix rules. */\nfunction resolveAttributes(name: string, options: CookieOptions): Attributes {\n // `null`: host-only, whatever the defaults\n const domain = typeof options.domain === 'string' ? normalizeDomain(name, options.domain) : undefined\n const path = options.path ?? '/'\n checkPath(name, path)\n const attributes: Attributes = {\n domain,\n path,\n secure: options.secure === true,\n httpOnly: options.httpOnly === true,\n sameSite: options.sameSite,\n partitioned: options.partitioned === true,\n priority: options.priority,\n }\n if (attributes.sameSite === 'none' && !attributes.secure) {\n throw invalid(name, 'SameSite=None requires secure: true (browsers reject it otherwise)')\n }\n if (attributes.partitioned && !attributes.secure) {\n throw invalid(name, 'partitioned cookies require secure: true')\n }\n checkPrefix(name, attributes)\n return attributes\n}\n\n/** `__Secure-`, `__Host-`, `__Http-`, `__Host-Http-` (case-insensitive, like browsers). */\nfunction checkPrefix(name: string, attributes: Attributes): void {\n const lower = name.toLowerCase()\n const host = lower.startsWith('__host-')\n const http = lower.startsWith('__http-') || lower.startsWith('__host-http-')\n if (!host && !http && !lower.startsWith('__secure-')) return\n const prefix = prefixName(host, http)\n if (!attributes.secure) throw invalid(name, `the ${prefix} prefix requires secure: true`)\n if (http && !attributes.httpOnly) throw invalid(name, `the ${prefix} prefix requires httpOnly: true`)\n if (host) {\n if (attributes.domain !== undefined) throw invalid(name, `the ${prefix} prefix forbids a domain`)\n if (attributes.path !== '/') throw invalid(name, `the ${prefix} prefix requires path: '/'`)\n }\n}\n\nfunction checkName(name: string): void {\n if (!isCookieName(name)) {\n throw new TypeError(\n `Invalid cookie name ${describe(name)}: expected a token (letters, digits and ! # $ % & ' * + - . ^ _ \\` | ~)`,\n )\n }\n}\n\nfunction encodeValue(name: string, value: string): string {\n if (typeof value !== 'string') throw invalid(name, `the value must be a string (received ${describe(value)})`)\n if (!value.isWellFormed()) throw invalid(name, 'the value contains a lone surrogate')\n return encodeCookieValue(value)\n}\n\nfunction checkSize(name: string, wire: string): void {\n const size = byteLength(name) + 1 + wire.length // the wire value is ASCII\n if (size > MAX_COOKIE_SIZE) {\n throw new RangeError(\n `Invalid cookie \"${name}\": name=value is ${size} bytes on the wire, above the limit of ${MAX_COOKIE_SIZE} (browsers drop it)`,\n )\n }\n}\n\n/** Checks the type of every option (and rejects unknown keys); returns the options. */\nfunction checkOptions(name: string, options: CookieOptions | undefined, defaults = false): CookieOptions {\n if (options === undefined) return {}\n const what = defaults ? 'cookies.defaults' : 'options'\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n throw invalid(name, `${what} must be an object (received ${describe(options)})`)\n }\n for (const key of Object.keys(options)) {\n if (!OPTION_KEYS.has(key)) throw invalid(name, `unknown option \"${key}\"`)\n }\n const { maxAge, expires, domain, path, secure, httpOnly, sameSite, partitioned, priority, signed } = options\n if (maxAge !== undefined && !(typeof maxAge === 'number' && Number.isSafeInteger(maxAge))) {\n throw invalid(name, `maxAge must be an integer number of seconds (received ${describe(maxAge)})`)\n }\n if (expires !== undefined && !(expires instanceof Date && !Number.isNaN(expires.getTime()))) {\n throw invalid(name, `expires must be a valid Date (received ${describe(expires)})`)\n }\n if (expires !== undefined) {\n const year = expires.getUTCFullYear()\n if (year < MIN_EXPIRES_YEAR || year > MAX_EXPIRES_YEAR) {\n throw invalid(\n name,\n `expires must be in the years ${MIN_EXPIRES_YEAR} to ${MAX_EXPIRES_YEAR} (received ${expires.toISOString()}): browsers ignore other dates; use maxAge for a long lifetime (browsers cap it at 400 days)`,\n )\n }\n }\n if (domain !== undefined && domain !== null && typeof domain !== 'string') {\n throw invalid(name, `domain must be a string or null (received ${describe(domain)})`)\n }\n if (path !== undefined && typeof path !== 'string') {\n throw invalid(name, `path must be a string (received ${describe(path)})`)\n }\n for (const [key, flag] of [\n ['secure', secure],\n ['httpOnly', httpOnly],\n ['partitioned', partitioned],\n ['signed', signed],\n ] as const) {\n if (flag !== undefined && typeof flag !== 'boolean') {\n throw invalid(name, `${key} must be a boolean (received ${describe(flag)})`)\n }\n }\n if (sameSite !== undefined && !Object.hasOwn(SAME_SITE, sameSite)) {\n throw invalid(name, `sameSite must be 'strict', 'lax' or 'none' (received ${describe(sameSite)})`)\n }\n if (priority !== undefined && !Object.hasOwn(PRIORITY, priority)) {\n throw invalid(name, `priority must be 'low', 'medium' or 'high' (received ${describe(priority)})`)\n }\n return options\n}\n\n/** Lower-cased, one leading `.` removed; an ASCII host name of at most 253 characters. */\nfunction normalizeDomain(name: string, domain: string): string {\n const normalized = (domain.startsWith('.') ? domain.slice(1) : domain).toLowerCase()\n if (normalized.length > MAX_COOKIE_ATTRIBUTE_SIZE) {\n throw new RangeError(`Invalid cookie \"${name}\": the domain exceeds ${MAX_COOKIE_ATTRIBUTE_SIZE} bytes`)\n }\n if (!isHostName(normalized)) {\n throw invalid(\n name,\n `invalid domain ${describe(domain)}: expected an ASCII host name (letters, digits, -, dot-separated labels; IDNs in punycode)`,\n )\n }\n return normalized\n}\n\nfunction isHostName(domain: string): boolean {\n if (domain === '' || domain.length > MAX_DOMAIN_LENGTH) return false\n let label = 0\n for (let index = 0; index < domain.length; index++) {\n const code = domain.charCodeAt(index)\n if (code === 0x2e) {\n if (label === 0) return false\n label = 0\n continue\n }\n const valid = (code >= 0x30 && code <= 0x39) || (code >= 0x61 && code <= 0x7a) || code === 0x2d\n if (!valid) return false\n label++\n }\n return label > 0\n}\n\n/** Starts with `/`, `%x20-7E` except `;`, at most 1024 bytes. */\nfunction checkPath(name: string, path: string): void {\n if (path.length > MAX_COOKIE_ATTRIBUTE_SIZE) {\n throw new RangeError(`Invalid cookie \"${name}\": the path exceeds ${MAX_COOKIE_ATTRIBUTE_SIZE} bytes`)\n }\n let valid = path.startsWith('/')\n for (let index = 0; valid && index < path.length; index++) {\n const code = path.charCodeAt(index)\n valid = code >= 0x20 && code <= 0x7e && code !== 0x3b\n }\n if (!valid) {\n throw invalid(name, `invalid path ${describe(path)}: expected \"/...\" made of visible ASCII characters without \";\"`)\n }\n}\n\n/** The options without `undefined` values (they would erase defaults when spread). */\nfunction definedOnly(options: CookieOptions): CookieOptions {\n const result: Record<string, unknown> = {}\n for (const key of Object.keys(options)) {\n const value = (options as Record<string, unknown>)[key]\n if (value !== undefined) result[key] = value\n }\n return result as CookieOptions\n}\n\n// -------------------------------------------------------------------------------------------------\n// Set-Cookie parsing\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Parses a `Set-Cookie` line (attribute names are case-insensitive; the value is decoded like a\n * request cookie). Used by `inject()` to fill `response.cookies`.\n *\n * @throws TypeError when the line has no `name=value` pair.\n */\nexport function parseSetCookie(line: string): SetCookieInfo {\n const parts = String(line).split(';')\n const pair = parts[0] as string\n const equals = pair.indexOf('=')\n const name = equals === -1 ? '' : trim(pair, 0, equals)\n if (name === '') throw new TypeError(`Invalid Set-Cookie line ${describe(line)}: missing name=value`)\n const info: {\n -readonly [K in keyof SetCookieInfo]: SetCookieInfo[K]\n } = {\n name,\n value: decodeCookieValue(unquote(trim(pair, equals + 1, pair.length))),\n raw: line,\n secure: false,\n httpOnly: false,\n partitioned: false,\n }\n for (const part of parts.slice(1)) {\n const separator = part.indexOf('=')\n const key = trim(part, 0, separator === -1 ? part.length : separator).toLowerCase()\n const value = separator === -1 ? '' : trim(part, separator + 1, part.length)\n switch (key) {\n case 'max-age': {\n const seconds = /^-?\\d+$/.test(value) ? Number(value) : Number.NaN\n if (Number.isSafeInteger(seconds)) info.maxAge = seconds\n break\n }\n case 'expires': {\n const date = new Date(value)\n if (!Number.isNaN(date.getTime())) info.expires = date\n break\n }\n case 'domain':\n if (value !== '') info.domain = (value.startsWith('.') ? value.slice(1) : value).toLowerCase()\n break\n case 'path':\n if (value.startsWith('/')) info.path = value\n break\n case 'secure':\n info.secure = true\n break\n case 'httponly':\n info.httpOnly = true\n break\n case 'partitioned':\n info.partitioned = true\n break\n case 'samesite': {\n const sameSite = value.toLowerCase()\n if (sameSite === 'strict' || sameSite === 'lax' || sameSite === 'none') info.sameSite = sameSite\n break\n }\n case 'priority': {\n const priority = value.toLowerCase()\n if (priority === 'low' || priority === 'medium' || priority === 'high') info.priority = priority\n break\n }\n default:\n break\n }\n }\n return Object.freeze(info)\n}\n\n/** The `set-cookie` lines of a response parsed by name (the last one wins), prototype-less and frozen. */\nexport function parseSetCookies(\n lines: readonly string[] | string | undefined,\n): Readonly<Record<string, SetCookieInfo>> {\n const result = Object.create(null) as Record<string, SetCookieInfo>\n const list = typeof lines === 'string' ? [lines] : (lines ?? [])\n for (const line of list) {\n try {\n const info = parseSetCookie(line)\n result[info.name] = info\n } catch {\n // not a cookie line: ignored\n }\n }\n return Object.freeze(result)\n}\n\n// -------------------------------------------------------------------------------------------------\n// Jar\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Cookies of a response in insertion order, keyed by name, domain and path: a later cookie with\n * the same key replaces the earlier one in place (set then clear gives one clearing cookie).\n */\nexport class CookieJar<T> {\n readonly #entries = new Map<string, T>()\n\n /** Adds or replaces (in place) the entry of `key`. */\n set(key: string, entry: T): void {\n this.#entries.set(key, entry)\n }\n\n get size(): number {\n return this.#entries.size\n }\n\n values(): T[] {\n return [...this.#entries.values()]\n }\n\n entries(): [string, T][] {\n return [...this.#entries.entries()]\n }\n}\n\n/**\n * The jar key of a cookie as given (`HttpResponse.withCookie()`, before the defaults are known):\n * an absent domain or path is keyed as \"default\", a `null` domain as host-only.\n */\nexport function givenCookieKey(name: string, options: CookieOptions): string {\n const given = options.domain\n let domain: string\n if (given === undefined) domain = '\\u0001'\n else if (given === null) domain = ''\n else domain = (given.startsWith('.') ? given.slice(1) : given).toLowerCase()\n return `${name}\\u0000${domain}\\u0000${options.path ?? '\\u0001'}`\n}\n\n// -------------------------------------------------------------------------------------------------\n// Helpers\n// -------------------------------------------------------------------------------------------------\n\nfunction prefixName(host: boolean, http: boolean): string {\n if (host) return http ? '__Host-Http-' : '__Host-'\n return http ? '__Http-' : '__Secure-'\n}\n\nfunction invalid(name: string, reason: string): TypeError {\n return new TypeError(`Invalid cookie \"${name}\": ${reason}`)\n}\n\nfunction byteLength(text: string): number {\n let size = 0\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index)\n if (code < 0x80) size += 1\n else if (code < 0x800 || (code >= 0xd800 && code <= 0xdfff))\n size += 2 // a surrogate pair: 4 bytes\n else size += 3\n }\n return size\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.length > 64 ? `${value.slice(0, 64)}…` : value)\n if (value instanceof Date) return 'an invalid Date'\n if (value === null) return 'null'\n if (typeof value === 'object') return 'an object'\n return typeof value === 'bigint' ? `${value}n` : String(value)\n}\n","/** Helpers shared by the adapters (internal). */\nimport type { Readable } from 'node:stream'\nimport type {\n HttpServerAddress,\n InjectRequest,\n InjectResponse,\n InjectStreamRequest,\n InjectStreamResponse,\n} from '../adapter.ts'\n\nimport { encodeCookieValue, parseSetCookies } from '../cookies.ts'\nimport { BadRequestException, PayloadTooLargeException } from '../exceptions.ts'\nimport { failedStream } from '../stream.ts'\n\n/** An inject request normalised for the underlying tools. */\nexport interface NormalizedInject {\n readonly method: string\n readonly url: string\n readonly headers: Record<string, string>\n readonly payload: string | Uint8Array | undefined\n}\n\n/**\n * Applies the defaults of {@link InjectRequest}: query merged in the URL, cookies appended to the\n * `cookie` header (encoded values joined with `; `), body encoding and content type (`FormData` →\n * `multipart/form-data`, `Blob` → its type).\n */\nexport async function normalizeInject(request: InjectRequest): Promise<NormalizedInject> {\n if (request === null || typeof request !== 'object') throw new TypeError('inject() expects a request object')\n if (typeof request.url !== 'string' || !request.url.startsWith('/')) {\n throw new TypeError(`inject() expects a url starting with \"/\" (received ${JSON.stringify(request.url)})`)\n }\n const method = (request.method ?? 'GET').toUpperCase()\n let url = request.url\n if (request.query !== undefined) {\n const search = new URLSearchParams()\n for (const [key, value] of Object.entries(request.query)) {\n if (typeof value === 'string') search.append(key, value)\n else for (const item of value) search.append(key, item)\n }\n const query = search.toString()\n if (query !== '') url += `${url.includes('?') ? '&' : '?'}${query}`\n }\n const headers: Record<string, string> = {}\n for (const [name, value] of Object.entries(request.headers ?? {})) headers[name.toLowerCase()] = value\n if (request.signedCookies !== undefined) {\n throw new TypeError('inject(): signedCookies are signed by HttpPlugin.inject() (adapters only accept cookies)')\n }\n const cookie = cookieHeader(request.cookies)\n if (cookie !== '') headers['cookie'] = headers['cookie'] === undefined ? cookie : `${headers['cookie']}; ${cookie}`\n const body = request.body\n let payload: string | Uint8Array | undefined\n if (body === undefined) {\n payload = undefined\n } else if (typeof body === 'string') {\n payload = body\n headers['content-type'] ??= 'text/plain; charset=utf-8'\n } else if (body instanceof Uint8Array || body instanceof ArrayBuffer) {\n payload = body instanceof Uint8Array ? body : new Uint8Array(body)\n headers['content-type'] ??= 'application/octet-stream'\n } else if (body instanceof FormData) {\n // the Fetch API encodes forms (the boundary of the generated content type must be used)\n const encoded = new Response(body)\n // read the generated content type (with its boundary) before consuming the body (Bun sets it lazily)\n const type = encoded.headers.get('content-type')\n payload = new Uint8Array(await encoded.arrayBuffer())\n headers['content-type'] = type ?? encoded.headers.get('content-type') ?? 'multipart/form-data'\n } else if (body instanceof Blob) {\n payload = new Uint8Array(await body.arrayBuffer())\n headers['content-type'] ??= body.type === '' ? 'application/octet-stream' : body.type\n } else {\n payload = JSON.stringify(body)\n headers['content-type'] ??= 'application/json'\n }\n return { method, url, headers, payload }\n}\n\n/** The `cookie` header of inject cookies: `name=encoded` pairs joined with `; `. */\nfunction cookieHeader(cookies: Readonly<Record<string, string>> | undefined): string {\n if (cookies === undefined) return ''\n if (cookies === null || typeof cookies !== 'object') throw new TypeError('inject(): cookies must be an object')\n const pairs: string[] = []\n for (const name of Object.keys(cookies)) {\n if (!isRequestCookieName(name)) {\n throw new TypeError(\n `inject(): invalid cookie name ${JSON.stringify(name)} (empty, or with \";\", \"=\", spaces or controls)`,\n )\n }\n const value = cookies[name]\n if (typeof value !== 'string') throw new TypeError(`inject(): the value of the cookie \"${name}\" must be a string`)\n pairs.push(`${name}=${encodeCookieValue(value)}`)\n }\n return pairs.join('; ')\n}\n\n/** A name a `cookie` header can carry: no `;`, `=`, whitespace or controls, Latin-1. */\nfunction isRequestCookieName(name: string): boolean {\n if (name === '') return false\n for (let index = 0; index < name.length; index++) {\n const code = name.charCodeAt(index)\n if (code <= 0x20 || code === 0x3b || code === 0x3d || code === 0x7f || code > 0xff) return false\n }\n return true\n}\n\nconst DECODER = new TextDecoder()\n\n/**\n * Normalises response headers: lower-case names, repeated values joined with `, `, except\n * `set-cookie` (one entry per cookie: an `Expires` attribute contains `, `).\n */\nexport function injectHeaders(\n headers: Readonly<Record<string, string | number | readonly string[] | undefined>>,\n): Record<string, string | string[]> {\n const normalized: Record<string, string | string[]> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (value === undefined) continue\n const key = name.toLowerCase()\n if (key === 'set-cookie') normalized[key] = typeof value === 'object' ? [...value] : [String(value)]\n else normalized[key] = typeof value === 'object' ? value.join(', ') : String(value)\n }\n return normalized\n}\n\n/** Builds an {@link InjectResponse} (headers normalised by {@link injectHeaders}, cookies parsed). */\nexport function injectResponse(\n status: number,\n headers: Readonly<Record<string, string | number | readonly string[] | undefined>>,\n bytes: Uint8Array,\n): InjectResponse {\n const normalized = injectHeaders(headers)\n const body = DECODER.decode(bytes)\n return {\n status,\n headers: normalized,\n body,\n bytes,\n cookies: parseSetCookies(normalized['set-cookie']),\n json: <T = unknown>(): T => JSON.parse(body) as T,\n }\n}\n\n/** Whether a `content-type` is `text/event-stream`. */\nexport function isEventStreamType(contentType: string | readonly string[] | undefined): boolean {\n if (typeof contentType !== 'string') return false\n const semicolon = contentType.indexOf(';')\n return (semicolon === -1 ? contentType : contentType.slice(0, semicolon)).trim().toLowerCase() === 'text/event-stream'\n}\n\n/**\n * `inject()` on top of `injectStream()`: reads the body to its end, except for an event stream\n * (which would never end): its body is cancelled (the server sees a disconnect) and the call\n * rejects with a hint.\n */\nexport async function bufferInjectStream(\n injectStream: (request: InjectStreamRequest) => Promise<InjectStreamResponse>,\n request: InjectRequest,\n): Promise<InjectResponse> {\n const response = await injectStream(request)\n const method = (request.method ?? 'GET').toUpperCase()\n if (method !== 'HEAD' && isEventStreamType(response.headers['content-type'])) {\n await response.body.cancel().catch(() => undefined)\n throw new TypeError(\n `inject(): ${method} ${request.url} answered an event stream (text/event-stream): use injectSse() or injectStream()`,\n )\n }\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let size = 0\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n size += value.byteLength\n chunks.push(value)\n }\n const bytes = concat(chunks, size)\n const body = DECODER.decode(bytes)\n return {\n status: response.status,\n headers: response.headers,\n body,\n bytes,\n cookies: response.cookies,\n json: <T = unknown>(): T => JSON.parse(body) as T,\n }\n}\n\n/** Builds an {@link InjectStreamResponse}. */\nexport function injectStreamResponse(\n status: number,\n headers: Readonly<Record<string, string | number | readonly string[] | undefined>>,\n body: ReadableStream<Uint8Array>,\n): InjectStreamResponse {\n const normalized = injectHeaders(headers)\n return { status, headers: normalized, cookies: parseSetCookies(normalized['set-cookie']), body }\n}\n\n/** Builds an {@link HttpServerAddress} from a bound address. */\nexport function serverAddress(address: string, port: number, family?: string | number): HttpServerAddress {\n const ipv6 = family === 'IPv6' || family === 6 || address.includes(':')\n let client = address\n if (address === '0.0.0.0') client = '127.0.0.1'\n else if (address === '::') client = '::1'\n const url = `http://${client.includes(':') ? `[${client}]` : client}:${port}`\n return Object.freeze({\n host: address,\n port,\n family: ipv6 ? 'IPv6' : 'IPv4',\n url,\n toString: () => url,\n })\n}\n\n/** The 413 error of a body above `limit` bytes. */\nexport function payloadTooLarge(limit: number): PayloadTooLargeException {\n return new PayloadTooLargeException(`Request body exceeds the limit of ${limit} bytes`, undefined, {\n headers: { connection: 'close' },\n })\n}\n\n/** Rejects early when `content-length` announces more than `limit` bytes. */\nexport function exceedsDeclaredLength(contentLength: string | undefined, limit: number): boolean {\n if (contentLength === undefined) return false\n const length = Number(contentLength)\n return Number.isFinite(length) && length > limit\n}\n\n/** Bytes read (and discarded) from an abandoned Web request body before it is cancelled. */\nconst MAX_DISCARD_BYTES = 64 * 1024 * 1024\n\n/**\n * The body of a Web request as a pull-based stream enforcing `limit` (see\n * `AdapterRequest.streamBody`). `body` is only read when needed (a Node.js-backed request body\n * starts buffering once accessed). On overflow or cancellation the rest of the body is read and\n * discarded in the background (up to 64 MiB, then cancelled), so the server can write the response\n * and keep the connection usable instead of resetting it.\n */\nexport function webBodyStream(\n body: () => ReadableStream<Uint8Array> | null,\n limit: number,\n contentLength: string | undefined,\n): ReadableStream<Uint8Array> {\n if (exceedsDeclaredLength(contentLength, limit)) return failedStream(payloadTooLarge(limit))\n const source = body()\n if (source === null) return new ReadableStream<Uint8Array>({ start: controller => controller.close() })\n const reader = source.getReader()\n let size = 0\n let abandoned = false\n const abandon = (): void => {\n if (abandoned) return\n abandoned = true\n discardReader(reader)\n }\n return new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n let result: Awaited<ReturnType<typeof reader.read>>\n try {\n result = await reader.read()\n } catch (error) {\n abandoned = true\n throw new BadRequestException('Failed to read the request body', undefined, { cause: error })\n }\n if (result.done) {\n abandoned = true\n controller.close()\n return\n }\n size += result.value.byteLength\n if (size > limit) {\n abandon()\n throw payloadTooLarge(limit)\n }\n controller.enqueue(result.value)\n },\n cancel: abandon,\n },\n { highWaterMark: 0 },\n )\n}\n\n/** The part of a stream reader used to discard a body. */\ninterface BodyReader {\n read(): Promise<{ readonly done: boolean; readonly value?: Uint8Array | undefined }>\n cancel(): Promise<void>\n}\n\n/** Reads and drops the rest of a request body in the background, cancelling it past 64 MiB. */\nfunction discardReader(reader: BodyReader): void {\n let discarded = 0\n const next = (): void => {\n reader.read().then(\n result => {\n if (result.done) return\n discarded += result.value?.byteLength ?? 0\n if (discarded > MAX_DISCARD_BYTES) reader.cancel().catch(() => undefined)\n else next()\n },\n () => undefined,\n )\n }\n next()\n}\n\n/** Reads a Web request body fully, enforcing `limit` (see {@link webBodyStream}). */\nexport async function readWebStream(\n body: () => ReadableStream<Uint8Array> | null,\n limit: number,\n contentLength: string | undefined,\n): Promise<Uint8Array> {\n const reader = webBodyStream(body, limit, contentLength).getReader()\n const chunks: Uint8Array[] = []\n let size = 0\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n size += value.byteLength\n chunks.push(value)\n }\n return concat(chunks, size)\n}\n\n/** Concatenates chunks (no copy for a single chunk). */\nexport function concat(chunks: readonly Uint8Array[], size: number): Uint8Array {\n if (chunks.length === 0) return new Uint8Array(0)\n if (chunks.length === 1) return chunks[0] as Uint8Array\n const result = new Uint8Array(size)\n let offset = 0\n for (const chunk of chunks) {\n result.set(chunk, offset)\n offset += chunk.byteLength\n }\n return result\n}\n\n/** The light-my-request response of a streaming inject (`payloadAsStream: true`). */\ninterface LightStreamResponse {\n readonly statusCode: number\n readonly headers: Record<string, string | number | string[] | undefined>\n stream(): Readable\n readonly raw: { readonly res: { destroy(error?: Error): void } }\n}\n\n/** Minimal typing of `light-my-request` (optional peer dependency). */\nexport interface LightMyRequest {\n inject(dispatch: (req: never, res: never) => void, options: LightInjectOptions): PromiseLike<LightStreamResponse>\n}\n\n/** Options of a streaming light-my-request inject (also `fastify.inject()`). */\nexport interface LightInjectOptions {\n method: string\n url: string\n headers: Record<string, string>\n payload?: string | Buffer\n remoteAddress?: string\n payloadAsStream: true\n}\n\nlet lightMyRequest: Promise<LightMyRequest> | undefined\n\n/** Loads `light-my-request`, with an actionable error when it is not installed. */\nexport function loadLightMyRequest(adapter: string): Promise<LightMyRequest> {\n lightMyRequest ??= import('light-my-request').then(\n module => {\n const loaded = module as unknown as { default?: LightMyRequest } & LightMyRequest\n return loaded.default ?? loaded\n },\n (error: unknown) => {\n lightMyRequest = undefined\n throw new Error(\n `inject() with the ${adapter} adapter requires the optional peer dependency \"light-my-request\" ` +\n '(bun add -d light-my-request / npm i -D light-my-request)',\n { cause: error },\n )\n },\n )\n return lightMyRequest\n}\n\n/**\n * The light-my-request options of a normalised inject request (streaming mode). The signal is\n * handled by {@link lightStreamResponse} (light-my-request would destroy its fake request with an\n * unhandled error); an already aborted signal rejects at once, like `fetch()`.\n */\nexport async function lightInjectOptions(request: InjectStreamRequest): Promise<LightInjectOptions> {\n request.signal?.throwIfAborted()\n const normalized = await normalizeInject(request)\n return {\n method: normalized.method,\n url: normalized.url,\n headers: normalized.headers,\n remoteAddress: '127.0.0.1',\n payloadAsStream: true,\n ...(normalized.payload === undefined ? {} : { payload: toBuffer(normalized.payload) }),\n }\n}\n\n/** Runs a request through a Node.js request listener with `light-my-request`, streaming the body. */\nexport async function injectNodeStream(\n adapter: string,\n dispatch: (req: never, res: never) => void,\n request: InjectStreamRequest,\n): Promise<InjectStreamResponse> {\n const options = await lightInjectOptions(request)\n const { inject } = await loadLightMyRequest(adapter)\n return lightStreamResponse(await inject(dispatch, options), request.signal)\n}\n\n/**\n * An {@link InjectStreamResponse} of a light-my-request streaming response. Cancelling the body\n * (or aborting `signal`) destroys the server response: the server sees a client disconnect.\n */\nexport function lightStreamResponse(response: LightStreamResponse, signal?: AbortSignal): InjectStreamResponse {\n const readable = response.stream()\n const disconnect = (): void => {\n response.raw.res.destroy()\n readable.destroy()\n }\n let finished = false\n const body = new ReadableStream<Uint8Array>(\n {\n start(controller) {\n readable.on('data', (chunk: Buffer) => {\n if (finished) return\n controller.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength))\n if ((controller.desiredSize ?? 0) <= 0) readable.pause()\n })\n readable.once('end', () => {\n if (finished) return\n finished = true\n controller.close()\n })\n readable.once('error', error => {\n if (finished) return\n finished = true\n controller.error(error)\n })\n },\n pull() {\n if (readable.isPaused()) readable.resume()\n },\n cancel() {\n finished = true\n disconnect()\n },\n },\n { highWaterMark: 0 },\n )\n if (signal !== undefined) {\n if (signal.aborted) disconnect()\n else signal.addEventListener('abort', disconnect, { once: true })\n }\n return injectStreamResponse(response.statusCode, response.headers, body)\n}\n\n/** A `Buffer` view of bytes (tools such as light-my-request JSON-encode other objects). */\nexport function toBuffer(payload: string | Uint8Array): string | Buffer {\n return typeof payload === 'string' ? payload : Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)\n}\n\n/**\n * Runs a request through a Fetch handler (`(request: Request) => Promise<Response>`), streaming\n * the body. Cancelling the body (or aborting `signal`) aborts the request signal and cancels the\n * response body.\n */\nexport async function injectFetchStream(\n fetch: (request: Request) => Response | Promise<Response>,\n request: InjectStreamRequest,\n): Promise<InjectStreamResponse> {\n const signal = request.signal\n signal?.throwIfAborted()\n const normalized = await normalizeInject(request)\n const abort = new AbortController()\n signal?.addEventListener('abort', () => abort.abort(signal.reason), { once: true })\n const init: RequestInit = { method: normalized.method, headers: normalized.headers, signal: abort.signal }\n if (normalized.payload !== undefined && normalized.method !== 'GET' && normalized.method !== 'HEAD') {\n init.body = normalized.payload\n }\n const response = await fetch(new Request(`http://localhost${normalized.url}`, init))\n const headers: Record<string, string | readonly string[]> = {}\n for (const [name, value] of response.headers) if (name !== 'set-cookie') headers[name] = value\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers['set-cookie'] = cookies\n const source = response.body\n const reader = source?.getReader()\n const body = new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n if (reader === undefined) {\n controller.close()\n return\n }\n const result = await reader.read()\n if (result.done) controller.close()\n else controller.enqueue(result.value)\n },\n async cancel(reason) {\n abort.abort(reason)\n await reader?.cancel(reason).catch(() => undefined)\n },\n },\n { highWaterMark: 0 },\n )\n abort.signal.addEventListener('abort', () => reader?.cancel(abort.signal.reason).catch(() => undefined), {\n once: true,\n })\n return injectStreamResponse(response.status, headers, body)\n}\n","/** Node.js `IncomingMessage` / `ServerResponse` helpers shared by the Node and Express adapters (internal). */\nimport type { IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders, Server, ServerResponse } from 'node:http'\nimport type { Socket } from 'node:net'\nimport type { AdapterReply, AdapterRequest } from '../adapter.ts'\nimport type { HeaderValue } from '../exceptions.ts'\n\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\n\nimport { BadRequestException } from '../exceptions.ts'\nimport { discardStream, failedStream } from '../stream.ts'\nimport { concat, exceedsDeclaredLength, payloadTooLarge } from './shared.ts'\n\n/** Bytes buffered by a request body stream before the request is paused. */\nconst BODY_HIGH_WATER_MARK = 64 * 1024\n\n/** Request headers with array values (only `set-cookie` in Node.js) joined with `, `. */\nexport function normalizeNodeHeaders(headers: IncomingHttpHeaders): Record<string, string | undefined> {\n for (const name in headers) {\n if (typeof headers[name] !== 'string') return copyHeaders(headers)\n }\n return headers as Record<string, string | undefined>\n}\n\nfunction copyHeaders(headers: IncomingHttpHeaders): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {}\n for (const name in headers) {\n const value = headers[name]\n result[name] = Array.isArray(value) ? value.join(', ') : value\n }\n return result\n}\n\n/**\n * Whether the body was already read by someone else: an Express body parser (`express.json()`...)\n * marks the request with `_body`; otherwise a declared body that already ended.\n */\nfunction consumedElsewhere(request: IncomingMessage): boolean {\n if ((request as { _body?: unknown })._body === true) return true\n if (!request.readableEnded) return false\n const length = request.headers['content-length']\n return request.headers['transfer-encoding'] !== undefined || (length !== undefined && length.trim() !== '0')\n}\n\n/** The error of a body consumed before Znight read it (an empty body would be silently wrong). */\nfunction consumedError(): Error {\n return new Error(\n 'The request body was already read by a middleware (an Express body parser such as express.json()?): ' +\n 'Znight reads the bodies of its routes itself, do not register body parsers for them',\n )\n}\n\n/** Reads a Node.js request body, enforcing `limit` (on `content-length`, then while streaming). */\nexport function readNodeBody(request: IncomingMessage, limit: number): Promise<Uint8Array> {\n if (exceedsDeclaredLength(request.headers['content-length'], limit)) {\n request.resume()\n return Promise.reject(payloadTooLarge(limit))\n }\n // a read in progress (the adapters read a body once: not expected)\n const reading = (request as ReadingRequest)[BODY_READ]\n if (reading != null) return reading.promise\n if (consumedElsewhere(request)) return Promise.reject(consumedError())\n if (request.readableEnded) return Promise.resolve(new Uint8Array(0))\n if (request.destroyed) return Promise.reject(new BadRequestException('The request was aborted'))\n let resolve!: (bytes: Uint8Array) => void\n let reject!: (error: unknown) => void\n const promise = new Promise<Uint8Array>((onRead, onError) => {\n resolve = onRead\n reject = onError\n })\n ;(request as ReadingRequest)[BODY_READ] = { limit, chunks: [], size: 0, resolve, reject, promise }\n if (reading === undefined) {\n request.on('data', onBodyData)\n request.on('end', onBodyEnd)\n request.on('error', onBodyError)\n request.on('close', onBodyClose)\n }\n return promise\n}\n\n/**\n * The state of the body read by {@link readNodeBody}, on its request: `null` once it is over (the\n * listeners stay), `undefined` before.\n */\nconst BODY_READ = Symbol('znight.bodyRead')\n\ninterface BodyRead {\n readonly limit: number\n readonly chunks: Uint8Array[]\n size: number\n readonly resolve: (bytes: Uint8Array) => void\n readonly reject: (error: unknown) => void\n readonly promise: Promise<Uint8Array>\n}\n\ntype ReadingRequest = IncomingMessage & { [BODY_READ]?: BodyRead | null }\n\n// The listeners of readNodeBody: shared functions (`this` is the request), no closure per request.\n// They stay attached once the read is over (removing them costs a lot more than leaving them): they\n// then do nothing. Node.js emits `error` on a destroyed request only when it has listeners, so the\n// `error` listener left behind changes nothing either.\n\n/** Stops reading: returns the state of the read (`undefined` when it is already over). */\nfunction stopBodyRead(request: ReadingRequest): BodyRead | undefined {\n const read = request[BODY_READ]\n if (read == null) return undefined\n request[BODY_READ] = null\n return read\n}\n\nfunction onBodyData(this: ReadingRequest, chunk: Uint8Array | string): void {\n const read = this[BODY_READ]\n if (read == null) return\n const bytes = typeof chunk === 'string' ? Buffer.from(chunk) : chunk\n read.size += bytes.byteLength\n if (read.size > read.limit) {\n stopBodyRead(this)\n this.resume() // discard the rest; the 413 response closes the connection\n read.reject(payloadTooLarge(read.limit))\n return\n }\n read.chunks.push(bytes)\n}\n\nfunction onBodyEnd(this: ReadingRequest): void {\n const read = stopBodyRead(this)\n read?.resolve(concat(read.chunks, read.size))\n}\n\nfunction onBodyError(this: ReadingRequest, error: Error): void {\n stopBodyRead(this)?.reject(new BadRequestException('Failed to read the request body', undefined, { cause: error }))\n}\n\nfunction onBodyClose(this: ReadingRequest): void {\n if (this.complete) return\n stopBodyRead(this)?.reject(new BadRequestException('The request was aborted'))\n}\n\n/**\n * A Node.js request body as a Web stream (see `AdapterRequest.streamBody`): the request is paused\n * while the consumer does not read (backpressure); past `limit` bytes the stream errors with 413 and\n * the rest of the body is discarded (`request.resume()`), like when the consumer cancels the stream,\n * so the response can still be written (it carries `connection: close`).\n */\nexport function nodeBodyStream(request: IncomingMessage, limit: number): ReadableStream<Uint8Array> {\n if (exceedsDeclaredLength(request.headers['content-length'], limit)) {\n request.resume()\n return failedStream(payloadTooLarge(limit))\n }\n if (consumedElsewhere(request)) return failedStream(consumedError())\n if (request.readableEnded) return new ReadableStream<Uint8Array>({ start: controller => controller.close() })\n if (request.destroyed) return failedStream(new BadRequestException('The request was aborted'))\n let size = 0\n let cleanup = (): void => undefined\n return new ReadableStream<Uint8Array>(\n {\n start(controller) {\n const onData = (chunk: Uint8Array | string): void => {\n const bytes = typeof chunk === 'string' ? Buffer.from(chunk) : chunk\n size += bytes.byteLength\n if (size > limit) {\n cleanup()\n request.resume() // discard the rest; the 413 response closes the connection\n controller.error(payloadTooLarge(limit))\n return\n }\n controller.enqueue(bytes)\n if ((controller.desiredSize ?? 0) <= 0) request.pause()\n }\n const onEnd = (): void => {\n cleanup()\n controller.close()\n }\n const onError = (error: Error): void => {\n cleanup()\n controller.error(new BadRequestException('Failed to read the request body', undefined, { cause: error }))\n }\n const onClose = (): void => {\n if (request.complete) return\n cleanup()\n controller.error(new BadRequestException('The request was aborted'))\n }\n cleanup = (): void => {\n request.off('data', onData)\n request.off('end', onEnd)\n request.off('error', onError)\n request.off('close', onClose)\n }\n request.on('data', onData)\n request.on('end', onEnd)\n request.on('error', onError)\n request.on('close', onClose)\n },\n pull() {\n if (request.isPaused()) request.resume()\n },\n cancel() {\n cleanup()\n request.resume() // discard the rest of the body\n },\n },\n { highWaterMark: BODY_HIGH_WATER_MARK, size: (chunk: Uint8Array | undefined) => chunk?.byteLength ?? 0 },\n )\n}\n\n/** Options of {@link nodeAdapterRequest}. */\nexport interface NodeRequestOptions {\n /** Request target (default: `request.url`). */\n readonly url?: string\n /** `@Req()` value (default: the `IncomingMessage`). */\n readonly raw?: unknown\n /** `@Res()` value (default: the `ServerResponse`). */\n readonly rawResponse?: unknown\n readonly ip?: string | undefined\n}\n\n/** Wraps a Node.js request/response pair as an {@link AdapterRequest}. */\nexport function nodeAdapterRequest(\n request: IncomingMessage,\n response: ServerResponse,\n options: NodeRequestOptions = NO_OPTIONS,\n): AdapterRequest {\n return new NodeAdapterRequest(request, response, options)\n}\n\nconst NO_OPTIONS: NodeRequestOptions = Object.freeze({})\n\n/** A Node.js request/response pair as an {@link AdapterRequest} (a class: no closure per request). */\nclass NodeAdapterRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip: string | undefined\n readonly remoteAddress: string | undefined\n readonly encrypted: boolean\n readonly raw: unknown\n readonly rawResponse: unknown\n readonly #request: IncomingMessage\n readonly #response: ServerResponse\n #body: Promise<Uint8Array> | undefined\n\n constructor(request: IncomingMessage, response: ServerResponse, options: NodeRequestOptions) {\n const remoteAddress = request.socket?.remoteAddress\n this.method = request.method ?? 'GET'\n this.url = options.url ?? request.url ?? '/'\n this.headers = normalizeNodeHeaders(request.headers)\n this.ip = options.ip ?? remoteAddress\n this.remoteAddress = remoteAddress\n this.encrypted = isEncrypted(request)\n this.raw = options.raw ?? request\n this.rawResponse = options.rawResponse ?? response\n this.#request = request\n this.#response = response\n }\n\n readBody(limit: number): Promise<Uint8Array> {\n this.#body ??= readNodeBody(this.#request, limit)\n return this.#body\n }\n\n streamBody(limit: number): ReadableStream<Uint8Array> {\n return nodeBodyStream(this.#request, limit)\n }\n\n rawStatus(): number {\n return this.#response.statusCode\n }\n\n onAbort(listener: () => void): void {\n onResponseAbort(this.#response, listener)\n }\n}\n\n/**\n * Calls `listener` once when `response` closes before it was fully written (the client left): on\n * the next microtask when it is already destroyed, never after a complete response.\n */\nexport function onResponseAbort(response: ServerResponse, listener: () => void): void {\n if (response.writableFinished) return\n if (response.destroyed) {\n queueMicrotask(listener)\n return\n }\n response.once('close', () => {\n if (!response.writableFinished) listener()\n })\n}\n\n/** Whether the request came over TLS (`node:https`, `node:http2` secure servers). */\nexport function isEncrypted(request: IncomingMessage): boolean {\n return (request.socket as { readonly encrypted?: unknown } | undefined)?.encrypted === true\n}\n\n/**\n * Writes a reply to a `ServerResponse`, piping a stream body (a failing stream destroys the\n * response). Never throws.\n */\nexport function writeNodeReply(response: ServerResponse, reply: AdapterReply): void {\n if (reply.raw === true) {\n discardStream(reply.body instanceof ReadableStream ? reply.body : null)\n return\n }\n if (response.headersSent || response.destroyed) {\n discardStream(reply.body instanceof ReadableStream ? reply.body : null)\n if (!response.writableEnded && !response.destroyed) response.end()\n return\n }\n try {\n // one call (merged over headers set earlier with setHeader(), e.g. by Express middleware); the\n // cookies set earlier are kept before the reply's own (writeHead would replace them)\n const headers =\n reply.headers['set-cookie'] === undefined\n ? reply.headers\n : withNativeCookies(response.getHeader('set-cookie'), reply.headers)\n response.writeHead(reply.status, headers as OutgoingHttpHeaders)\n } catch {\n // invalid header name or value set by user code\n discardStream(reply.body instanceof ReadableStream ? reply.body : null)\n if (!response.headersSent) {\n for (const name of response.getHeaderNames()) response.removeHeader(name)\n response.statusCode = 500\n response.setHeader('content-type', 'application/json; charset=utf-8')\n response.end('{\"statusCode\":500,\"error\":\"Internal Server Error\"}')\n }\n return\n }\n const body = reply.body\n if (body === null) {\n response.end()\n return\n }\n // an event stream may stay quiet longer than a socket timeout (`server.timeout`, Bun's emulation)\n if (reply.eventStream === true && (response as { isLightMyRequest?: boolean }).isLightMyRequest !== true) {\n response.setTimeout(0)\n }\n if (body instanceof Uint8Array) {\n // a string is written with the headers at once (bytes take a second write)\n response.end(reply.text ?? body)\n return\n }\n const fail = (): void => {\n if (!response.destroyed) response.destroy()\n }\n try {\n const stream = body instanceof Blob ? body.stream() : body\n pipeline(Readable.fromWeb(stream as import('node:stream/web').ReadableStream), response).catch(fail)\n } catch {\n fail()\n }\n}\n\n/**\n * `headers` with the `set-cookie` lines already set on the native response (Express middleware\n * `res.cookie()`, Fastify hooks `reply.header('set-cookie', ...)`) before its own: `headers`\n * unchanged when either side has none.\n */\nexport function withNativeCookies(\n native: number | string | readonly string[] | undefined,\n headers: Readonly<Record<string, HeaderValue>>,\n): Readonly<Record<string, HeaderValue>> {\n const own = headers['set-cookie']\n if (own === undefined || native === undefined || typeof native === 'number') return headers\n const before = typeof native === 'string' ? [native] : native\n if (before.length === 0) return headers\n return { ...headers, 'set-cookie': [...before, ...(typeof own === 'string' ? [own] : own)] }\n}\n\n/** Last-resort 500 when a handler promise rejected (should not happen: the pipeline maps errors). */\nexport function writeNodeFailure(response: ServerResponse): void {\n if (response.headersSent) {\n if (!response.writableEnded) response.destroy()\n return\n }\n response.statusCode = 500\n response.setHeader('content-type', 'application/json; charset=utf-8')\n response.end('{\"statusCode\":500,\"error\":\"Internal Server Error\"}')\n}\n\n/** The tracker of a socket (see {@link ConnectionTracker}). */\nconst TRACKER = Symbol('znight.tracker')\n/** The number of requests in progress on a tracked socket. */\nconst ACTIVE = Symbol('znight.active')\n\ninterface TrackedSocket extends Socket {\n [TRACKER]?: ConnectionTracker\n [ACTIVE]?: number\n}\n\n/**\n * Tracks the connections of a `node:http` server to close them on shutdown: idle keep-alive\n * connections first (graceful), every connection when forced. `server.closeIdleConnections()` /\n * `closeAllConnections()` are not reliable on every runtime (Bun), so sockets are tracked here. The\n * count of requests in progress lives on the socket, and one shared `close` listener per response\n * decrements it (no closure, no map lookup per request).\n */\nexport class ConnectionTracker {\n readonly #sockets = new Set<TrackedSocket>()\n #closing = false\n\n /**\n * `requests: false` when the caller's own `request` listener calls {@link track} for every request\n * of the server (one listener less to call per request).\n */\n constructor(server: Server, options: { readonly requests?: boolean } = {}) {\n server.on('connection', (socket: TrackedSocket) => {\n socket[TRACKER] = this\n socket[ACTIVE] = 0\n this.#sockets.add(socket)\n socket.once('close', () => this.#sockets.delete(socket))\n })\n if (options.requests !== false) {\n server.on('request', (request: IncomingMessage, response: ServerResponse) => this.track(request, response))\n }\n }\n\n /** Counts a request in progress on its connection, until its response closes (other servers' requests are ignored). */\n track(request: IncomingMessage, response: ServerResponse): void {\n const socket = request.socket as TrackedSocket | null\n if (socket?.[TRACKER] !== this) return\n socket[ACTIVE] = (socket[ACTIVE] ?? 0) + 1\n response.on('close', ConnectionTracker.#onResponseClose)\n }\n\n /** A response closed (`this`): one request less on its socket, ended when idle while closing. */\n static readonly #onResponseClose = function (this: ServerResponse): void {\n // the socket of a finished response is detached: reach it through its request\n const socket = (this.req as IncomingMessage | undefined)?.socket as TrackedSocket | null | undefined\n const tracker = socket?.[TRACKER]\n if (socket == null || tracker === undefined) return\n const active = (socket[ACTIVE] ?? 1) - 1\n socket[ACTIVE] = active\n if (active === 0 && tracker.#closing) socket.end()\n }\n\n /** Ends idle connections now and the others once their requests completed. */\n closeIdle(): void {\n this.#closing = true\n for (const socket of this.#sockets) if (socket[ACTIVE] === 0) socket.end()\n }\n\n /** Destroys every connection. */\n destroyAll(): void {\n this.#closing = true\n for (const socket of this.#sockets) socket.destroy()\n }\n}\n\n/**\n * Marks a socket taken over by a WebSocket transport (RFC 0003) as busy: a graceful close of the\n * server leaves it to its transport, which closes it with a close frame; a forced close destroys it.\n */\nexport function markUpgraded(socket: object): void {\n ;(socket as TrackedSocket)[ACTIVE] = 1\n}\n\n/** Closes a `node:http` server: graceful (idle connections ended), then forced when asked. */\nexport function closeServer(\n server: Server,\n tracker: ConnectionTracker,\n closing: Promise<void> | undefined,\n force: boolean,\n): Promise<void> {\n const promise =\n closing ??\n new Promise<void>(resolve => {\n if (!server.listening) {\n resolve()\n return\n }\n server.close(() => resolve())\n server.closeIdleConnections?.()\n tracker.closeIdle()\n })\n if (force) {\n server.closeAllConnections?.()\n tracker.destroyAll()\n }\n return promise\n}\n","/**\n * Marker decorators of `@znight/http`. Like every Znight decorator they do nothing at runtime: the\n * compiler extension `@znight/http/compiler` reads them from the source code and generates the\n * routes (`metadata.extensions.http`). Arguments marked _static_ must be statically evaluable\n * (literals, `const` references); _value_ arguments (schemas, guards...) may also be references to\n * exported bindings. See docs/internals/architecture.md §4.6 and §5.\n */\nimport type { ClassMarker, MethodMarker, ParameterMarker, Scope } from '@znight/core'\nimport type { HttpContext } from './context.ts'\nimport type { GuardClass, HttpInterceptorClass } from './interfaces.ts'\nimport type { ByteSize } from './size.ts'\nimport type { SseOptions } from './sse.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport type { UploadedFileOptions, UploadedFilesOptions } from './uploads.ts'\n\nfunction marker(): void {\n // intentionally empty: decorators are compile-time markers\n}\n\nconst classMarker: ClassMarker = marker\nconst methodMarker: MethodMarker = marker\nconst parameterMarker: ParameterMarker = marker\nconst classOrMethodMarker: ClassMarker & MethodMarker = marker\n\n/** Options of {@link Controller} (static). */\nexport interface ControllerOptions {\n /** Base path of every route of the controller (`/users`). Default: `/`. */\n readonly path?: string\n /** Provider scope. Default: `singleton`; `request` creates one controller per request. */\n readonly scope?: Scope\n}\n\n/**\n * Declares a controller: a provider (singleton by default) whose decorated methods are routes.\n *\n * ```ts\n * @Controller('/users')\n * export class UserController {\n * constructor(private readonly users: UserService) {}\n *\n * @Get('/:id')\n * find(@Param('id') id: number) {\n * return this.users.findById(id)\n * }\n * }\n * ```\n *\n * @param pathOrOptions static: base path, or `{ path?, scope? }`.\n */\nexport function Controller(_pathOrOptions?: string | ControllerOptions): ClassMarker {\n return classMarker\n}\n\n/** `GET` route. `path` (static) is relative to the controller path; default: the controller path. */\nexport function Get(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `POST` route (default status 201). */\nexport function Post(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PUT` route. */\nexport function Put(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PATCH` route. */\nexport function Patch(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `DELETE` route. */\nexport function Delete(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `HEAD` route (`GET` routes already answer `HEAD` requests). */\nexport function Head(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `OPTIONS` route (paths without one answer `OPTIONS` with `204` and an `allow` header). */\nexport function Options(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** Route for GET, HEAD, POST, PUT, PATCH, DELETE and OPTIONS (methods without a dedicated route on the same path). */\nexport function All(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * A `GET` route serving an event stream (Server-Sent Events). The handler returns an\n * `AsyncIterable`, an `Iterable` or a `ReadableStream` of `SseEvent` (`{ data, event, id, retry,\n * comment }`), or an `HttpResponse` / exception for other outcomes (204 stops `EventSource`). The\n * plugin frames the events, sends heartbeats, stops the source when the client leaves (`ctx.signal`)\n * and closes the stream gracefully on shutdown.\n *\n * ```ts\n * @Sse('/:id/events', { retry: 5_000 })\n * async events(@Param('id') id: string, @Ctx() ctx: HttpContext): Promise<AsyncIterable<SseEvent<OrderEvent>>> {\n * if ((await this.orders.find(id)) === undefined) throw new NotFoundException() // pre-flight checks first\n * return this.hub.subscribe(id, { signal: ctx.signal })\n * }\n * ```\n *\n * Prefer an `async` method returning the source over an `async *` generator: the body of a\n * generator only runs once the 200 and the headers are sent.\n *\n * @param path static: route path (relative to the controller path).\n * @param options static: `{ heartbeat?, retry?, maxDuration? }` (see `SseOptions`).\n */\nexport function Sse(path?: string, options?: SseOptions): MethodMarker\nexport function Sse(options: SseOptions): MethodMarker\nexport function Sse(_pathOrOptions?: string | SseOptions, _options?: SseOptions): MethodMarker {\n return methodMarker\n}\n\n/**\n * Injects a route parameter, coerced to the parameter type (`string`, `number`, `boolean`,\n * `bigint`, `Date`, literal unions) or validated with `schema`. Without arguments: every parameter\n * (`Record<string, string>`).\n *\n * ```ts\n * @Get('/:id')\n * find(@Param('id') id: number) {}\n * ```\n *\n * @param name static: name of a `:param` of the route path.\n * @param schema value: a Standard Schema validating the raw string (its output is injected).\n */\nexport function Param(): ParameterMarker\nexport function Param(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Param(schema: StandardSchemaV1): ParameterMarker\nexport function Param(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a query parameter (coerced to the parameter type; `T[]` accepts repeated and single\n * values; optional when the parameter is optional or has a default) or, without name, the whole\n * query (`Record<string, string | string[]>`), typically validated with a schema.\n *\n * ```ts\n * list(@Query('page') page = 1, @Query('tag') tags: string[] = []) {}\n * search(@Query(SearchQuery) query: SearchQuery) {}\n * ```\n *\n * @param name static: query key.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Query(): ParameterMarker\nexport function Query(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Query(schema: StandardSchemaV1): ParameterMarker\nexport function Query(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request cookie (decoded, coerced to the parameter type like `@Headers`: `string`,\n * `number`, `boolean`, `bigint`, `Date`, literal unions, enums, branded primitives) or validated\n * with `schema`; without name, every cookie (`Record<string, string>`). An absent cookie answers 400\n * `Missing cookie \"name\"` unless the parameter is optional. Error messages never echo the value.\n *\n * ```ts\n * // a stale or forged value falls back instead of answering 400 until the cookie expires\n * export const Theme = z.enum(['light', 'dark']).catch('light')\n *\n * read(@Cookie('theme', Theme) theme: 'light' | 'dark', @Cookie('visits') visits = 0) {}\n * ```\n *\n * @param name static: cookie name (an RFC 9110 token).\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Cookie(): ParameterMarker\nexport function Cookie(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Cookie(schema: StandardSchemaV1): ParameterMarker\nexport function Cookie(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the **verified** value of a signed cookie (set with `{ signed: true }`, plugin option\n * `cookies.secrets`): absent, tampered or signed with a retired key, the cookie does not exist\n * (400 `Missing cookie \"name\"` unless the parameter is optional). Same coercion and schema rules as\n * {@link Cookie}. A route reading a signed cookie fails the boot when `cookies.secrets` is not set.\n *\n * @param name static: cookie name.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function SignedCookie(_name: string, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the parsed request body, validated with `schema` when given (the schema output is\n * injected: defaults, transforms, stripped keys). A non-primitive body without schema is reported\n * by the compiler (ZNIGHT017).\n *\n * @param schema value: a Standard Schema (Zod, Valibot, ArkType...).\n */\nexport function Body(_schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request header (case-insensitive `name`, coerced to the parameter type) or, without\n * name, every header (`Record<string, string | undefined>`).\n *\n * @param name static: header name.\n */\nexport function Headers(_name?: string): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a file of a `multipart/form-data` body as a standard `File` (`name`, `type`, `size`,\n * `arrayBuffer()`, `text()`, `stream()`), held in memory. The route parses multipart bodies before\n * its interceptors, enforcing the options while the body is read: a file above `maxSize` answers\n * 413, a refused type 415, a second file in the field or a file in an undeclared field 400, a\n * missing required file 400, a non-multipart body 415. `@Body()` receives the text fields.\n *\n * ```ts\n * @Post('/avatar')\n * upload(@UploadedFile('avatar', { maxSize: '2mb', mimeTypes: ['image/png', 'image/jpeg'] }) avatar: File) {}\n *\n * @Post('/attachment')\n * attach(@UploadedFile('file') file?: File) {} // optional: undefined when absent\n * ```\n *\n * `File.name` and `File.type` are sent by the client: never trust them (see the README, \"Files\").\n *\n * @param field static: the multipart field; omitted: the single file of the body, whatever its field.\n * @param options static: `{ required?, maxSize?, mimeTypes? }`.\n */\nexport function UploadedFile(field?: string, options?: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(options: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(\n _fieldOrOptions?: string | UploadedFileOptions,\n _options?: UploadedFileOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the files of a multipart field (`File[]`, in body order), or of every field without\n * `field`. Same rules as {@link UploadedFile}; above `maxFiles` files the request answers 413. An\n * optional parameter (`files?: File[]`, `required: false`) receives an empty array when no file is\n * sent.\n *\n * ```ts\n * @Post('/documents')\n * add(@UploadedFiles('documents', { maxFiles: 5, maxSize: '20mb', mimeTypes: ['application/pdf'] }) documents: File[]) {}\n * ```\n *\n * @param field static: the multipart field; omitted: the files of every field.\n * @param options static: `{ required?, maxSize?, maxFiles?, mimeTypes? }`.\n */\nexport function UploadedFiles(field?: string, options?: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(options: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(\n _fieldOrOptions?: string | UploadedFilesOptions,\n _options?: UploadedFilesOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the maximum request body size of a route, or of every route of a controller (the route wins),\n * over the plugin `bodyLimit` (and over the limit computed for upload routes). `Infinity` disables\n * the limit, e.g. for a route streaming its body with `ctx.bodyStream()`.\n *\n * ```ts\n * @Put('/files/:name')\n * @BodyLimit('5gb')\n * async store(@Param('name') name: string, @Ctx() ctx: HttpContext) {\n * await pipeline(Readable.fromWeb(ctx.bodyStream()), createWriteStream(join(DIR, safeName(name))))\n * }\n * ```\n *\n * @param size static: bytes (`10_485_760`) or a size with a unit (`'10mb'`, `'512kb'`; `kb` = 1024 bytes).\n */\nexport function BodyLimit(_size: ByteSize): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/** Injects the native request of the adapter (escape hatch; the compiler warns). */\nexport function Req(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the native response of the adapter (escape hatch; the compiler warns). The handler then\n * writes the response itself, and must have finished when its promise settles.\n */\nexport function Res(): ParameterMarker {\n return parameterMarker\n}\n\n/** Injects the {@link HttpContext} of the request. */\nexport function Ctx(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the status of successful responses (wins over `HttpResponse.status` and the defaults).\n *\n * @param status static: an integer between 100 and 599.\n */\nexport function HttpCode(_status: number): MethodMarker {\n return methodMarker\n}\n\n/**\n * Adds a header to successful responses. Repeat the decorator for several headers.\n *\n * @param name static: header name.\n * @param value static: header value.\n */\nexport function Header(_name: string, _value: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * Protects a controller (every route) or a route with guards (providers implementing\n * {@link CanActivate}). Order: global guards → controller guards → route guards, each list in\n * declaration order.\n *\n * @param guards value: guard classes.\n */\nexport function UseGuard(..._guards: [GuardClass, ...GuardClass[]]): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Wraps a controller (every route) or a route with interceptors (providers implementing\n * {@link HttpInterceptor}). Order: global → controller → route, the first one being the outermost.\n *\n * @param interceptors value: interceptor classes.\n */\nexport function UseInterceptor(\n ..._interceptors: [HttpInterceptorClass, ...HttpInterceptorClass[]]\n): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Validates the request body with `schema`: sugar for `@Body(schema)` on the body parameter (using\n * both is ZNIGHT005).\n *\n * @param schema value: a Standard Schema.\n */\nexport function Validate(_schema: StandardSchemaV1): MethodMarker {\n return methodMarker\n}\n\n/** Arguments of a route decorator: optional when `T` accepts `undefined` or is `true` (flag decorators). */\nexport type RouteDecoratorArgs<T> = [T] extends [true] ? [value?: T] : undefined extends T ? [value?: T] : [value: T]\n\n/** Options of {@link createRouteDecorator} (static). */\nexport interface RouteDecoratorOptions {\n /**\n * Decision group. Decorators of a group are alternatives: one per controller or route, and the\n * route's decision replaces the controller's. Default: the key (the decorator is its own group).\n * A letter followed by letters, digits, `_`, `.` or `-`.\n */\n readonly group?: string\n /**\n * Every route must carry a decision of the group: ZNIGHT023 at build time when a route has none,\n * and at boot when no guard of its chain enforces it (see {@link GuardClass}). All the decorators\n * of a group must agree. Default `false`.\n */\n readonly required?: boolean\n}\n\n/** The data part of a route decorator: what guards list in `static enforces`. */\nexport interface RouteDecoratorInfo {\n /** Key of the value in `route.meta`. */\n readonly key: string\n /** Decision group (`options.group ?? key`). */\n readonly group: string\n /** Every route must carry a decision of the group. */\n readonly required: boolean\n}\n\n/**\n * A route metadata entry given as data rather than as a decorator: the `meta` of plugin routes\n * (`[Public.meta()]`). Built by {@link RouteDecorator.meta}.\n */\nexport interface RouteMetaEntry<T = unknown> {\n readonly key: string\n readonly value: T\n /** Decision group. Default: the key. */\n readonly group?: string\n /** Default `false`. */\n readonly required?: boolean\n}\n\n/**\n * Anything that carries effective route metadata: the {@link HttpContext} of a request, and the\n * contexts of other transports that reuse route decorators (a GraphQL resolver context, a WebSocket\n * gateway context). {@link RouteDecorator.get} reads `route.meta[key]`; nothing else is required.\n *\n * ```ts\n * const carrier: RouteMetaCarrier = { route: { meta: { roles: ['admin'] } } }\n * Roles.get(carrier) // ['admin']\n * ```\n */\nexport interface RouteMetaCarrier {\n /** The matched route (or field, or handler), `undefined` when there is none. */\n readonly route?: { readonly meta: Readonly<Record<string, unknown>> } | undefined\n}\n\n/** A user-defined route metadata decorator created with {@link createRouteDecorator}. */\nexport interface RouteDecorator<T> extends RouteDecoratorInfo {\n (...args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker\n /**\n * The value of the current route, if set. Reads the effective metadata: the route's decision of\n * a group wins over the controller's. Accepts any {@link RouteMetaCarrier}: an\n * {@link HttpContext}, or the context of another transport exposing `route.meta`.\n */\n get(ctx: RouteMetaCarrier): T | undefined\n /**\n * The same metadata as data (`{ key, value, group, required }`), for routes that are not compiled\n * controllers (plugin routes: `OpenApiPlugin.configure({ meta: [Public.meta()] })`). The value is\n * `true` when omitted, like `@Public()`.\n */\n meta(...args: RouteDecoratorArgs<T>): RouteMetaEntry<T>\n}\n\n/**\n * Grammar of an explicit decision group name (internal; the compiler extension has the same rule).\n * A decorator without `group` is its own group, named after its key: any non-empty key is valid.\n */\nexport const GROUP_NAME: RegExp = /^[A-Za-z][\\w.-]*$/\n\n/** `true` when `group` is a valid group of `key`: the key itself (the default) or a valid name. */\nexport function isGroupOf(group: unknown, key: string): group is string {\n return typeof group === 'string' && (group === key || GROUP_NAME.test(group))\n}\n\n/**\n * Creates a metadata decorator for controllers and routes. The compiler stores its argument\n * (`value`, statically evaluated or an exported reference; `true` when omitted) in\n * `meta[key]`, read by guards and interceptors through `ctx.route.meta` or `decorator.get(ctx)`.\n *\n * ```ts\n * export const Public = createRouteDecorator('public', { group: 'access', required: true })\n * export const Authenticated = createRouteDecorator('authenticated', { group: 'access', required: true })\n * export const Roles = createRouteDecorator<readonly string[]>('roles', { group: 'access', required: true })\n *\n * @Controller('/books')\n * @Roles(['reader']) // the decision of every route of the controller...\n * export class BookController {\n * @Get('/:id/cover')\n * @Public() // ...unless the route has its own decision of the group\n * cover() {}\n * }\n *\n * // in a guard\n * if (Public.get(ctx)) return true\n * const roles = Roles.get(ctx) ?? []\n * ```\n *\n * Decorators of one `group` are alternatives: two of them on the same class or method are\n * ZNIGHT005, and the route's decision replaces the controller's (without `group`, each decorator is\n * its own group: the route value wins over the controller value). With `required: true`, a route\n * without decision fails the build (ZNIGHT023).\n *\n * @param key static: unique metadata key.\n * @param options static: `{ group?, required? }`.\n */\nexport function createRouteDecorator<T = true>(key: string, options?: RouteDecoratorOptions): RouteDecorator<T> {\n if (typeof key !== 'string' || key === '') {\n throw new TypeError(`createRouteDecorator(): the key must be a non-empty string (received ${String(key)})`)\n }\n if (options !== undefined && (options === null || typeof options !== 'object')) {\n throw new TypeError(`createRouteDecorator('${key}'): options must be an object { group?, required? }`)\n }\n // the grammar applies to an explicit group only: without one, any key is its own group (as before groups)\n const group = options?.group ?? key\n if (!isGroupOf(group, key)) {\n throw new TypeError(\n `createRouteDecorator('${key}'): \"group\" must be a name made of letters, digits, _ . - starting with a letter (received ${String(group)})`,\n )\n }\n const required = options?.required ?? false\n if (typeof required !== 'boolean') {\n throw new TypeError(`createRouteDecorator('${key}'): \"required\" must be a boolean (received ${String(required)})`)\n }\n const decorator = (..._args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker => classOrMethodMarker\n return Object.assign(decorator, {\n key,\n group,\n required,\n get: (ctx: RouteMetaCarrier): T | undefined => ctx.route?.meta[key] as T | undefined,\n meta: (...args: RouteDecoratorArgs<T>): RouteMetaEntry<T> =>\n Object.freeze({ key, value: (args.length === 0 ? true : args[0]) as T, group, required }),\n })\n}\n","/**\n * Upgrade routes (RFC 0003 §8.2): WebSocket handshakes served by `HttpPlugin` on behalf of another\n * plugin (`@znight/websocket`). The handshake is an HTTP request: it runs through the pipeline\n * (`http:request` hook, request scope, global guards, the route's guards, exception mappers), then\n * the plugin's `accept` takes the connection. The request scope stays open until the connection\n * closes.\n *\n * Upgrade routes live in their own route table, consulted only for upgrade requests: they never\n * change the ordinary routing, and a page and its socket may share a path.\n */\nimport type { Token } from '@znight/core'\nimport type { AdapterReply, AdapterRequest } from './adapter.ts'\nimport type { HttpContext } from './context.ts'\nimport type { RouteMetaEntry } from './decorators.ts'\nimport type { HeaderValue } from './exceptions.ts'\nimport type { GuardRef } from './plugin.ts'\nimport type { NormalizedMetaEntry, PluginHttpRoutesContext } from './plugin-routes.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\n\nimport { isGroupOf } from './decorators.ts'\nimport { BadRequestException, HttpException } from './exceptions.ts'\nimport { joinPaths, normalizePath, parseRoutePath, type RoutePath, RoutePathError } from './path.ts'\n\n/**\n * The upgrade of a `node:http` server (`'upgrade'` event): every adapter built on `node:http`\n * (`node`, `express`, `fastify`, `hono` on Node.js), on Node.js and on Bun.\n */\nexport interface NodeUpgrade {\n readonly kind: 'node'\n /** The `IncomingMessage` of the handshake. */\n readonly request: unknown\n /** The `net.Socket` (a `Duplex`) of the connection. */\n readonly socket: unknown\n /** The first bytes after the handshake headers. */\n readonly head: Uint8Array\n}\n\n/** The upgrade of a `Bun.serve()` server (`honoAdapter()` on Bun). */\nexport interface BunUpgrade {\n readonly kind: 'bun'\n /** The Fetch `Request` of the handshake. */\n readonly request: Request\n /** The `Bun.serve()` server (`server.upgrade(request, { data, headers })`). */\n readonly server: unknown\n}\n\n/** An in-memory upgrade (`HttpPlugin.upgradeInMemory()`, tests): `peer` belongs to the caller. */\nexport interface MemoryUpgrade {\n readonly kind: 'memory'\n readonly peer: unknown\n}\n\n/** The native side of an upgrade request, completed by a transport. */\nexport type NativeUpgrade = NodeUpgrade | BunUpgrade | MemoryUpgrade\n\n/** What {@link PluginUpgradeRoute.accept} receives to complete the handshake. */\nexport interface PendingUpgrade {\n readonly native: NativeUpgrade\n /**\n * Headers of the `101` response: the headers and cookies the guards set on the context, the\n * request id and the security headers are not included (they are HTTP response headers); read\n * once, when the transport completes the handshake.\n */\n readonly headers: Readonly<Record<string, HeaderValue>>\n /**\n * The handshake timed out and was answered `408`: the transport must not complete it. Check it\n * after every `await`, right before completing the handshake.\n */\n readonly expired: boolean\n /**\n * Keeps the request scope (and the in-flight count of `HttpPlugin`) open until `closed`\n * settles: the connection lives in the scope of its handshake. Call it once, after the transport\n * completed the handshake.\n */\n hold(closed: Promise<unknown>): void\n}\n\n/**\n * A route answering upgrade requests (`GET` with `upgrade: websocket`), declared by another plugin\n * through {@link PluginHttpUpgrades.httpUpgrades}.\n */\nexport interface PluginUpgradeRoute {\n /** Path relative to the `HttpPlugin` prefix, with the route grammar (`/chat`, `/docs/:docId`). */\n readonly path: string\n /** Name of the route (the gateway), shown in `HttpPlugin.routes`, logs and errors. */\n readonly name: string\n /** `ctx.route.controller` during the handshake (the gateway token). Default: the plugin name. */\n readonly owner?: Token\n /** Route metadata (`ctx.route.meta`), one entry per group, checked at boot like plugin routes. */\n readonly meta?: readonly RouteMetaEntry[]\n /** Guards of the handshake (classes, instances or provider tokens), after the global guards. */\n readonly guards?: readonly (GuardRef | Token)[]\n /** Time the handshake gets before it is answered `408` (ms). Default: none. */\n readonly timeoutMs?: number\n /**\n * Cheap checks before the guards (origin, subprotocols, capacity), after the protocol checks of\n * RFC 6455. Throw an `HttpException` to refuse.\n */\n precheck?(ctx: HttpContext): void | Promise<void>\n /** After the guards: take the connection. Throw an `HttpException` to refuse. */\n accept(ctx: HttpContext, upgrade: PendingUpgrade): void | Promise<void>\n}\n\n/** What {@link PluginHttpUpgrades.httpUpgrades} returns. */\nexport interface PluginUpgrades {\n readonly routes: readonly PluginUpgradeRoute[]\n /**\n * Server-wide settings of the `websocket` option of `Bun.serve()` (`maxPayloadLength`,\n * `idleTimeout`, `backpressureLimit`, `sendPings`, `perMessageDeflate`...), used by adapters\n * serving with `Bun.serve()`. The handlers are set by `HttpPlugin`: they dispatch every event to\n * the `data` given to `server.upgrade()`, a {@link BunSocketHandlers}.\n */\n readonly bunWebSocket?: Readonly<Record<string, unknown>>\n}\n\n/** What {@link PluginHttpUpgrades.httpUpgrades} receives. */\nexport interface PluginHttpUpgradesContext extends PluginHttpRoutesContext {\n /** Name of the adapter (`node`, `fastify`...). */\n readonly adapter: string\n /**\n * The native upgrades the adapter produces (`node`: a `node:http` server, `bun`: `Bun.serve()`),\n * `undefined` when the adapter cannot upgrade connections.\n */\n readonly upgrades: 'node' | 'bun' | undefined\n}\n\n/**\n * Implemented, next to {@link PluginHttpRoutes}, by a plugin that accepts WebSocket connections\n * (`@znight/websocket`). `HttpPlugin` calls `httpUpgrades()` once in its `onBootstrap`, after\n * `httpRoutes()`, whatever the plugin order, and asks its adapter to route the matching upgrade\n * requests to the pipeline. `onHttpDrain()` is where the plugin closes its connections.\n */\nexport interface PluginHttpUpgrades {\n httpUpgrades(context: PluginHttpUpgradesContext): PluginUpgrades\n}\n\n/**\n * The `data` a transport gives to `server.upgrade()` on `Bun.serve()`: `HttpPlugin` dispatches\n * every event of the socket to it.\n */\nexport interface BunSocketHandlers {\n open(ws: unknown): void\n message(ws: unknown, message: string | Uint8Array): void\n close(ws: unknown, code: number, reason: string): void\n drain(ws: unknown): void\n pong?(ws: unknown): void\n}\n\n/** What `HttpPlugin` gives to {@link AdapterUpgrades.enable}. */\nexport interface UpgradeHandlerOptions {\n /** Whether an upgrade request to the raw `path` (no query string) is for Znight. */\n match(path: string): boolean\n /**\n * Runs the handshake through the pipeline. Resolves with the refusal to write (an HTTP response),\n * or `undefined` once the transport took the connection. Never rejects.\n */\n handle(request: AdapterRequest, native: NodeUpgrade | BunUpgrade): Promise<AdapterReply | undefined>\n /** The `websocket` option of `Bun.serve()` (settings and dispatching handlers), Bun adapters only. */\n readonly bunWebSocket: Readonly<Record<string, unknown>>\n}\n\n/** The optional upgrade capability of an adapter (RFC 0003 §8.2.3). */\nexport interface AdapterUpgrades {\n /** The native upgrades the adapter produces. */\n readonly kind: 'node' | 'bun'\n /** Called once, before `listen()`, when the application has upgrade routes. */\n enable(options: UpgradeHandlerOptions): void\n}\n\n/** A validated upgrade route (internal). */\nexport interface CollectedUpgradeRoute {\n readonly plugin: string\n readonly instance: object\n readonly path: RoutePath\n readonly relativePath: string\n readonly name: string\n readonly owner: Token\n readonly meta: readonly NormalizedMetaEntry[]\n readonly guards: readonly unknown[]\n readonly timeoutMs: number | undefined\n readonly precheck: ((ctx: HttpContext) => void | Promise<void>) | undefined\n readonly accept: (ctx: HttpContext, upgrade: PendingUpgrade) => void | Promise<void>\n}\n\n/** The upgrade routes of the plugins and the merged `Bun.serve()` settings (internal). */\nexport interface CollectedUpgrades {\n readonly routes: readonly CollectedUpgradeRoute[]\n readonly bunWebSocket: Readonly<Record<string, unknown>>\n}\n\n/** Calls `httpUpgrades()` on every other plugin implementing it, in plugin order, and validates the routes. */\nexport function collectPluginUpgrades(\n plugins: readonly object[],\n self: object,\n context: PluginHttpUpgradesContext,\n): CollectedUpgrades {\n const routes: CollectedUpgradeRoute[] = []\n const bunWebSocket: Record<string, unknown> = {}\n for (const plugin of plugins) {\n if (plugin === self) continue\n const provider = plugin as Partial<PluginHttpUpgrades> & { readonly name?: unknown }\n if (typeof provider.httpUpgrades !== 'function') continue\n const name = String(provider.name)\n const result: unknown = provider.httpUpgrades(context)\n const declared = (result as Partial<PluginUpgrades> | null | undefined)?.routes\n if (!Array.isArray(declared)) {\n throw invalid(name, `httpUpgrades() must return { routes: [...] } (received ${describe(result)})`)\n }\n for (const route of declared as unknown[]) routes.push(validateRoute(plugin, name, route, context.prefix))\n const settings = (result as PluginUpgrades).bunWebSocket\n if (settings !== undefined) Object.assign(bunWebSocket, settings)\n }\n return { routes, bunWebSocket }\n}\n\nfunction validateRoute(instance: object, plugin: string, value: unknown, prefix: string): CollectedUpgradeRoute {\n if (value === null || typeof value !== 'object') throw invalid(plugin, `invalid upgrade route ${describe(value)}`)\n const route = value as Partial<PluginUpgradeRoute>\n if (typeof route.name !== 'string' || route.name === '') {\n throw invalid(plugin, `the upgrade route ${String(route.path)} needs a name`)\n }\n const where = `${String(route.path)} (${route.name})`\n if (typeof route.path !== 'string') throw invalid(plugin, `the upgrade route ${where} has no path`)\n if (typeof route.accept !== 'function') throw invalid(plugin, `the upgrade route ${where} has no accept function`)\n if (route.precheck !== undefined && typeof route.precheck !== 'function') {\n throw invalid(plugin, `the precheck of the upgrade route ${where} must be a function`)\n }\n let path: RoutePath\n try {\n path = parseRoutePath(joinPaths(prefix, route.path))\n } catch (error) {\n if (!(error instanceof RoutePathError)) throw error\n throw invalid(plugin, `invalid path of the upgrade route ${where}: ${error.issue.message}`, error)\n }\n const meta = route.meta ?? []\n if (!Array.isArray(meta)) throw invalid(plugin, `the meta of the upgrade route ${where} must be an array of entries`)\n const entries = (meta as unknown[]).map(entry => metaEntry(plugin, where, entry))\n const guards = route.guards ?? []\n if (!Array.isArray(guards)) throw invalid(plugin, `the guards of the upgrade route ${where} must be an array`)\n const timeoutMs = route.timeoutMs\n if (timeoutMs !== undefined && !(typeof timeoutMs === 'number' && timeoutMs > 0)) {\n throw invalid(plugin, `invalid timeoutMs ${describe(timeoutMs)} of the upgrade route ${where}`)\n }\n return {\n plugin,\n instance,\n path,\n relativePath: normalizePath(route.path),\n name: route.name,\n owner: route.owner ?? plugin,\n meta: entries,\n guards,\n timeoutMs: timeoutMs === Number.POSITIVE_INFINITY ? undefined : timeoutMs,\n precheck: route.precheck?.bind(route),\n accept: route.accept.bind(route),\n }\n}\n\nfunction metaEntry(plugin: string, where: string, value: unknown): NormalizedMetaEntry {\n const entry = (value ?? {}) as Partial<RouteMetaEntry>\n if (value === null || typeof value !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n throw invalid(plugin, `invalid meta entry ${describe(value)} of the upgrade route ${where}`)\n }\n const group = entry.group ?? entry.key\n const required = entry.required ?? false\n if (!isGroupOf(group, entry.key) || typeof required !== 'boolean') {\n throw invalid(plugin, `invalid group of the meta entry \"${entry.key}\" of the upgrade route ${where}`)\n }\n return { key: entry.key, value: entry.value, group, required }\n}\n\nfunction invalid(plugin: string, reason: string, cause?: unknown): ZnightError {\n return new ZnightError(ErrorCode.InvalidRoute, `HttpPlugin: plugin \"${plugin}\": ${reason}`, {\n ...(cause === undefined ? {} : { cause }),\n })\n}\n\nfunction describe(value: unknown): string {\n try {\n return typeof value === 'function' ? 'a function' : (JSON.stringify(value) ?? String(value))\n } catch {\n return typeof value\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Handshake checks (RFC 6455 §4.2.1)\n// -------------------------------------------------------------------------------------------------\n\nconst KEY = /^[A-Za-z0-9+/]{22}==$/\n\n/** Whether a request asks for a WebSocket upgrade (`upgrade: websocket`, any case). */\nexport function isWebSocketUpgrade(headers: Readonly<Record<string, string | undefined>>): boolean {\n const upgrade = headers['upgrade']\n return upgrade !== undefined && upgrade.length === 9 && upgrade.toLowerCase() === 'websocket'\n}\n\n/**\n * The protocol checks of a handshake: `GET`, `sec-websocket-version: 13` (`426` with the supported\n * version otherwise) and a base64 16-byte `sec-websocket-key` (`400`).\n */\nexport function checkHandshake(ctx: HttpContext): void {\n if (ctx.method !== 'GET') throw new BadRequestException('A WebSocket handshake must be a GET request')\n if (ctx.headers['sec-websocket-version'] !== '13') {\n throw new HttpException(426, 'Unsupported WebSocket version', undefined, {\n headers: { 'sec-websocket-version': '13' },\n })\n }\n const key = ctx.headers['sec-websocket-key']\n if (key === undefined || !KEY.test(key.trim())) throw new BadRequestException('Invalid Sec-WebSocket-Key')\n}\n\n/** Internal: the pending upgrade of a handshake, created by the pipeline. */\nexport class PendingUpgradeState implements PendingUpgrade {\n readonly native: NativeUpgrade\n readonly #headers: () => Readonly<Record<string, HeaderValue>>\n /** The transport completed the handshake (`101`). */\n accepted = false\n /** The handshake timed out: the transport must not complete it. */\n expired = false\n held: Promise<unknown> | undefined\n\n constructor(native: NativeUpgrade, headers: () => Readonly<Record<string, HeaderValue>>) {\n this.native = native\n this.#headers = headers\n }\n\n get headers(): Readonly<Record<string, HeaderValue>> {\n return this.#headers()\n }\n\n hold(closed: Promise<unknown>): void {\n if (this.held !== undefined) throw new Error('PendingUpgrade.hold() can only be called once')\n this.accepted = true\n this.held = closed.then(\n () => undefined,\n () => undefined,\n )\n }\n}\n","/**\n * WebSocket upgrades on the adapters (RFC 0003 §8.2.3, internal): the upgrade capability of\n * `node:http` servers, the request of a handshake as an {@link AdapterRequest} (Node.js, Fetch,\n * in memory) and the raw HTTP refusal written on a socket.\n */\nimport type { IncomingMessage, Server } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport type { AdapterReply, AdapterRequest } from '../adapter.ts'\nimport type { HeaderValue } from '../exceptions.ts'\nimport type { AdapterUpgrades, BunSocketHandlers, UpgradeHandlerOptions } from '../upgrade.ts'\n\nimport { statusText } from '../status.ts'\nimport { isWebSocketUpgrade } from '../upgrade.ts'\nimport { markUpgraded, normalizeNodeHeaders } from './node-io.ts'\nimport { concat } from './shared.ts'\n\nconst EMPTY = new Uint8Array(0)\n\n/** A handshake has no body: Znight never reads one. */\nconst NO_BODY: Promise<Uint8Array> = Promise.resolve(EMPTY)\n\n/** The `IncomingMessage` of a `node:http` upgrade as an {@link AdapterRequest}. */\nclass NodeUpgradeRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip: string | undefined\n readonly remoteAddress: string | undefined\n readonly encrypted: boolean\n readonly raw: unknown\n readonly rawResponse: unknown\n\n constructor(request: IncomingMessage, socket: Duplex) {\n const peer = (socket as { readonly remoteAddress?: string }).remoteAddress ?? request.socket?.remoteAddress\n this.method = request.method ?? 'GET'\n this.url = request.url ?? '/'\n this.headers = normalizeNodeHeaders(request.headers)\n this.ip = peer\n this.remoteAddress = peer\n this.encrypted = (request.socket as { readonly encrypted?: unknown } | undefined)?.encrypted === true\n this.raw = request\n this.rawResponse = socket\n }\n\n readBody(): Promise<Uint8Array> {\n return NO_BODY\n }\n\n hasBody(): boolean {\n return false\n }\n}\n\n/** The Fetch `Request` of a `Bun.serve()` upgrade as an {@link AdapterRequest}. */\nexport class FetchUpgradeRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip: string | undefined\n readonly remoteAddress: string | undefined\n readonly encrypted: boolean\n readonly raw: Request\n readonly rawResponse: unknown = undefined\n\n constructor(request: Request, url: string, headers: Record<string, string>, address: string | undefined) {\n this.method = request.method\n this.url = url\n this.headers = headers\n this.ip = address\n this.remoteAddress = address\n this.encrypted = request.url.startsWith('https:')\n this.raw = request\n }\n\n readBody(): Promise<Uint8Array> {\n return NO_BODY\n }\n\n hasBody(): boolean {\n return false\n }\n}\n\n/** An in-memory handshake (`HttpPlugin.upgradeInMemory()`) as an {@link AdapterRequest}. */\nexport class MemoryUpgradeRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip = '127.0.0.1'\n readonly remoteAddress = '127.0.0.1'\n readonly encrypted = false\n readonly raw: unknown = undefined\n readonly rawResponse: unknown = undefined\n\n constructor(method: string, url: string, headers: Record<string, string>) {\n this.method = method\n this.url = url\n this.headers = headers\n }\n\n readBody(): Promise<Uint8Array> {\n return NO_BODY\n }\n\n hasBody(): boolean {\n return false\n }\n}\n\n/** The bytes of a reply body (refusals are small: read whole). */\nexport async function replyBytes(reply: AdapterReply): Promise<Uint8Array> {\n const body = reply.body\n if (body === null) return EMPTY\n if (body instanceof Uint8Array) return body\n if (body instanceof Blob) return new Uint8Array(await body.arrayBuffer())\n const chunks: Uint8Array[] = []\n let size = 0\n for await (const chunk of body as ReadableStream<Uint8Array>) {\n chunks.push(chunk)\n size += chunk.byteLength\n }\n return concat(chunks, size)\n}\n\n/** Whether a header value can be written on a raw socket (no CR/LF injection). */\nfunction safeHeader(value: string): boolean {\n return !/[\\r\\n]/.test(value)\n}\n\n/**\n * Writes a refused handshake as a raw HTTP/1.1 response on the upgrade socket, then ends it\n * (`connection: close`). Never throws.\n */\nexport async function writeRawRefusal(socket: Duplex, reply: AdapterReply): Promise<void> {\n try {\n const body = await replyBytes(reply)\n let head = `HTTP/1.1 ${reply.status} ${statusText(reply.status)}\\r\\n`\n const headers: Record<string, HeaderValue> = { ...reply.headers }\n headers['connection'] = 'close'\n headers['content-length'] = String(body.byteLength)\n for (const [name, value] of Object.entries(headers)) {\n for (const item of typeof value === 'string' ? [value] : value) {\n if (safeHeader(name) && safeHeader(item)) head += `${name}: ${item}\\r\\n`\n }\n }\n head += '\\r\\n'\n if (socket.destroyed) return\n socket.write(head)\n if (body.byteLength > 0) socket.write(body)\n socket.end()\n // a client that never closes its side: destroy after a short grace\n setTimeout(() => socket.destroy(), 1_000).unref?.()\n } catch {\n socket.destroy()\n }\n}\n\n/** The fallback reply when the pipeline failed (never expected). */\nconst FAILURE: AdapterReply = Object.freeze({ status: 500, headers: {}, body: null })\n\n/**\n * The upgrade capability of an adapter built on a `node:http` server (RFC 0003 §8.2.3): upgrade\n * requests of the gateway paths are routed to the pipeline through `shouldUpgradeCallback`\n * (composed with the server's own) and an `'upgrade'` listener; other upgrade requests are left to\n * the server (its own listeners, or ordinary requests).\n */\nexport class NodeUpgrades implements AdapterUpgrades {\n readonly kind = 'node' as const\n #options: UpgradeHandlerOptions | undefined\n readonly #attached = new WeakSet<Server>()\n\n /** Whether {@link enable} was called. */\n get enabled(): boolean {\n return this.#options !== undefined\n }\n\n enable(options: UpgradeHandlerOptions): void {\n this.#options = options\n }\n\n /** Routes the gateway upgrades of `server` to the pipeline (once per server; no-op when not enabled). */\n attach(server: Server): void {\n const options = this.#options\n if (options === undefined || this.#attached.has(server)) return\n this.#attached.add(server)\n const matches = (request: IncomingMessage): boolean => {\n if (!isWebSocketUpgrade(request.headers as Record<string, string | undefined>)) return false\n const url = request.url ?? '/'\n const query = url.indexOf('?')\n return options.match(query === -1 ? url : url.slice(0, query))\n }\n const target = server as Server & { shouldUpgradeCallback?: (request: IncomingMessage) => boolean }\n const previous = target.shouldUpgradeCallback\n const composable = typeof previous === 'function'\n const listener = (request: IncomingMessage, socket: Duplex, head: Uint8Array): void => {\n if (!matches(request)) {\n // without shouldUpgradeCallback (Node.js < 24.12), every upgrade reaches the listeners: answer\n // the ones nobody else handles\n if (!composable && server.listenerCount('upgrade') === 1) {\n void writeRawRefusal(socket, { status: 404, headers: {}, body: null })\n }\n return\n }\n socket.on('error', () => socket.destroy())\n markUpgraded(socket)\n const native = { kind: 'node', request, socket, head } as const\n options.handle(new NodeUpgradeRequest(request, socket), native).then(\n reply => {\n if (reply !== undefined) void writeRawRefusal(socket, reply)\n },\n () => void writeRawRefusal(socket, FAILURE),\n )\n }\n if (previous !== undefined) {\n target.shouldUpgradeCallback = function (this: Server, request: IncomingMessage): boolean {\n if (matches(request)) return true\n // the server's callback without Znight's listener (Node's default counts the listeners)\n const self = this ?? server\n const view = Object.create(self, {\n listenerCount: {\n value: (name: string | symbol): number => self.listenerCount(name) - (name === 'upgrade' ? 1 : 0),\n },\n }) as Server\n return previous.call(view, request) === true\n }\n }\n server.on('upgrade', listener)\n }\n}\n\n/**\n * The `websocket` option of `Bun.serve()`: the plugins' settings, and handlers dispatching every\n * event to the {@link BunSocketHandlers} given as `data` to `server.upgrade()`.\n */\nexport function bunWebSocketOption(settings: Readonly<Record<string, unknown>>): Readonly<Record<string, unknown>> {\n type Socket = { readonly data: BunSocketHandlers }\n return Object.freeze({\n ...settings,\n open: (ws: Socket): void => ws.data.open(ws),\n message: (ws: Socket, message: string | Uint8Array): void => ws.data.message(ws, message),\n close: (ws: Socket, code: number, reason: string): void => ws.data.close(ws, code, reason),\n drain: (ws: Socket): void => ws.data.drain(ws),\n pong: (ws: Socket): void => ws.data.pong?.(ws),\n })\n}\n\n/** Builds the `Response` of a refused `Bun.serve()` upgrade. */\nexport async function refusalResponse(reply: AdapterReply): Promise<Response> {\n const headers = new Headers()\n for (const [name, value] of Object.entries(reply.headers)) {\n for (const item of typeof value === 'string' ? [value] : value) headers.append(name, item)\n }\n const body = await replyBytes(reply)\n return new Response(body.byteLength === 0 ? null : body, { status: reply.status, headers })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"upgrade-io-CdQG7pZg.mjs","names":["describe","invalid","Headers"],"sources":["../src/status.ts","../src/exceptions.ts","../src/stream.ts","../src/cookies.ts","../src/adapters/shared.ts","../src/adapters/node-io.ts","../src/decorators.ts","../src/upgrade.ts","../src/adapters/upgrade-io.ts"],"sourcesContent":["/** Standard reason phrases (RFC 9110 and common extensions), used in error bodies. */\nconst REASONS: Readonly<Record<number, string>> = {\n 100: 'Continue',\n 101: 'Switching Protocols',\n 102: 'Processing',\n 103: 'Early Hints',\n 200: 'OK',\n 201: 'Created',\n 202: 'Accepted',\n 203: 'Non-Authoritative Information',\n 204: 'No Content',\n 205: 'Reset Content',\n 206: 'Partial Content',\n 207: 'Multi-Status',\n 300: 'Multiple Choices',\n 301: 'Moved Permanently',\n 302: 'Found',\n 303: 'See Other',\n 304: 'Not Modified',\n 307: 'Temporary Redirect',\n 308: 'Permanent Redirect',\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 402: 'Payment Required',\n 403: 'Forbidden',\n 404: 'Not Found',\n 405: 'Method Not Allowed',\n 406: 'Not Acceptable',\n 407: 'Proxy Authentication Required',\n 408: 'Request Timeout',\n 409: 'Conflict',\n 410: 'Gone',\n 411: 'Length Required',\n 412: 'Precondition Failed',\n 413: 'Payload Too Large',\n 414: 'URI Too Long',\n 415: 'Unsupported Media Type',\n 416: 'Range Not Satisfiable',\n 417: 'Expectation Failed',\n 418: \"I'm a Teapot\",\n 421: 'Misdirected Request',\n 422: 'Unprocessable Entity',\n 423: 'Locked',\n 424: 'Failed Dependency',\n 425: 'Too Early',\n 426: 'Upgrade Required',\n 428: 'Precondition Required',\n 429: 'Too Many Requests',\n 431: 'Request Header Fields Too Large',\n 451: 'Unavailable For Legal Reasons',\n 500: 'Internal Server Error',\n 501: 'Not Implemented',\n 502: 'Bad Gateway',\n 503: 'Service Unavailable',\n 504: 'Gateway Timeout',\n 505: 'HTTP Version Not Supported',\n 507: 'Insufficient Storage',\n 508: 'Loop Detected',\n 511: 'Network Authentication Required',\n}\n\n/** Reason phrase of `status` (`404` → `Not Found`), or a generic one for unknown codes. */\nexport function statusText(status: number): string {\n const reason = REASONS[status]\n if (reason !== undefined) return reason\n if (status >= 500) return 'Server Error'\n return status >= 400 ? 'Client Error' : 'Unknown Status'\n}\n\n/** Whether `status` is an integer in the 100–599 range. */\nexport function isValidStatus(status: unknown): status is number {\n return typeof status === 'number' && Number.isInteger(status) && status >= 100 && status <= 599\n}\n\n/** Statuses whose responses never have a body. */\nexport function isBodylessStatus(status: number): boolean {\n return status === 204 || status === 304 || (status >= 100 && status < 200)\n}\n","import type { StandardSchemaV1Issue } from './standard-schema.ts'\n\nimport { isValidStatus, statusText } from './status.ts'\n\n/** Response header values: a single value or several (`set-cookie`). */\nexport type HeaderValue = string | readonly string[]\n\n/** Options of {@link HttpException}. */\nexport interface HttpExceptionOptions extends ErrorOptions {\n /** Headers added to the error response (`www-authenticate`, `retry-after`, `allow`...). */\n readonly headers?: Readonly<Record<string, HeaderValue>>\n}\n\n/** JSON body of an error response. */\nexport interface HttpErrorBody {\n readonly statusCode: number\n /** Reason phrase of the status (`Not Found`). */\n readonly error: string\n readonly message: string\n /** Structured details (validation issues...), omitted when absent. */\n readonly details?: unknown\n}\n\n/** One entry of the `details` of a validation error. */\nexport interface ValidationIssueDetail {\n /** Dotted path of the invalid value inside the validated input (`user.email`, `items.0`), `''` for the root. */\n readonly path: string\n readonly message: string\n}\n\nconst NO_HEADERS: Readonly<Record<string, HeaderValue>> = Object.freeze({})\n\n/**\n * An error carrying an HTTP status. Thrown from handlers, guards, interceptors or services, it is\n * rendered as `{ statusCode, error, message, details? }` with its status and headers.\n *\n * ```ts\n * throw new HttpException(409, 'Email already used', { field: 'email' })\n * throw new NotFoundException(`User ${id} not found`)\n * throw new UnauthorizedException('Token expired', undefined, { headers: { 'www-authenticate': 'Bearer' } })\n * ```\n *\n * Invalid statuses (not an integer in 100–599) become `500`.\n */\nexport class HttpException extends Error {\n /** HTTP status of the response. */\n readonly status: number\n /** Structured details rendered in the body (omitted when `undefined`). */\n readonly details: unknown\n /** Headers added to the response. */\n readonly headers: Readonly<Record<string, HeaderValue>>\n\n constructor(status: number, message?: string, details?: unknown, options: HttpExceptionOptions = {}) {\n const code = isValidStatus(status) ? status : 500\n super(message ?? statusText(code), options.cause === undefined ? undefined : { cause: options.cause })\n this.name = 'HttpException'\n this.status = code\n this.details = details\n this.headers = options.headers ?? NO_HEADERS\n }\n\n /** The `statusCode` field of the body (alias of {@link status}). */\n get statusCode(): number {\n return this.status\n }\n\n /** Body of the error response. Override it in a subclass to change the shape. */\n toBody(): HttpErrorBody {\n const body: { statusCode: number; error: string; message: string; details?: unknown } = {\n statusCode: this.status,\n error: statusText(this.status),\n message: this.message,\n }\n if (this.details !== undefined) body.details = this.details\n return body\n }\n}\n\n/** Whether `value` is an {@link HttpException} (also across duplicated package copies). */\nexport function isHttpException(value: unknown): value is HttpException {\n return (\n value instanceof HttpException ||\n (value instanceof Error &&\n typeof (value as { status?: unknown }).status === 'number' &&\n typeof (value as { toBody?: unknown }).toBody === 'function')\n )\n}\n\n/** 400 Bad Request. */\nexport class BadRequestException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(400, message, details, options)\n this.name = 'BadRequestException'\n }\n}\n\n/**\n * 400 Bad Request raised when an input fails its schema (`@Body(schema)`, `@Query(schema)`...).\n * `details` lists the issues as `{ path, message }`; the raw Standard Schema issues are kept in\n * {@link issues} for exception mappers.\n */\nexport class ValidationException extends BadRequestException {\n /** What was validated: `body`, `query`, `query \"page\"`, `param \"id\"`... */\n readonly location: string\n readonly issues: readonly StandardSchemaV1Issue[]\n\n constructor(location: string, issues: readonly StandardSchemaV1Issue[], options?: HttpExceptionOptions) {\n super(`Invalid ${location}`, issues.map(toIssueDetail), options)\n this.name = 'ValidationException'\n this.location = location\n this.issues = issues\n }\n}\n\n/**\n * The `details` of a 400 raised by the framework for one invalid input (a multipart field...): the\n * shape of the issues of {@link ValidationException}, documented by `@znight/openapi`.\n */\nexport function issue(path: string, message: string): readonly ValidationIssueDetail[] {\n return [{ path, message }]\n}\n\n/** Converts a Standard Schema issue to `{ path, message }` (`path` dotted, `''` for the root). */\nexport function toIssueDetail(issue: StandardSchemaV1Issue): ValidationIssueDetail {\n return { path: formatIssuePath(issue.path), message: issue.message }\n}\n\nfunction formatIssuePath(path: StandardSchemaV1Issue['path']): string {\n if (path === undefined || path.length === 0) return ''\n let result = ''\n for (const segment of path) {\n const key = typeof segment === 'object' && segment !== null ? segment.key : segment\n const text = typeof key === 'symbol' ? (key.description ?? 'symbol') : String(key)\n result = result === '' ? text : `${result}.${text}`\n }\n return result\n}\n\n/** 401 Unauthorized. */\nexport class UnauthorizedException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(401, message, details, options)\n this.name = 'UnauthorizedException'\n }\n}\n\n/** 403 Forbidden (also the response of a guard returning `false`). */\nexport class ForbiddenException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(403, message, details, options)\n this.name = 'ForbiddenException'\n }\n}\n\n/** 404 Not Found. */\nexport class NotFoundException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(404, message, details, options)\n this.name = 'NotFoundException'\n }\n}\n\n/** 405 Method Not Allowed (pass the `allow` header in `options.headers`). */\nexport class MethodNotAllowedException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(405, message, details, options)\n this.name = 'MethodNotAllowedException'\n }\n}\n\n/** 409 Conflict. */\nexport class ConflictException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(409, message, details, options)\n this.name = 'ConflictException'\n }\n}\n\n/** 410 Gone. */\nexport class GoneException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(410, message, details, options)\n this.name = 'GoneException'\n }\n}\n\n/** 413 Payload Too Large (request body above `bodyLimit`). */\nexport class PayloadTooLargeException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(413, message, details, options)\n this.name = 'PayloadTooLargeException'\n }\n}\n\n/** 415 Unsupported Media Type. */\nexport class UnsupportedMediaTypeException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(415, message, details, options)\n this.name = 'UnsupportedMediaTypeException'\n }\n}\n\n/** 422 Unprocessable Entity. */\nexport class UnprocessableEntityException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(422, message, details, options)\n this.name = 'UnprocessableEntityException'\n }\n}\n\n/** 429 Too Many Requests (pass `retry-after` in `options.headers`). */\nexport class TooManyRequestsException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(429, message, details, options)\n this.name = 'TooManyRequestsException'\n }\n}\n\n/** 500 Internal Server Error (its message is always sent, unlike unexpected errors). */\nexport class InternalServerErrorException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(500, message, details, options)\n this.name = 'InternalServerErrorException'\n }\n}\n\n/** 501 Not Implemented. */\nexport class NotImplementedException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(501, message, details, options)\n this.name = 'NotImplementedException'\n }\n}\n\n/** 502 Bad Gateway. */\nexport class BadGatewayException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(502, message, details, options)\n this.name = 'BadGatewayException'\n }\n}\n\n/** 503 Service Unavailable. */\nexport class ServiceUnavailableException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(503, message, details, options)\n this.name = 'ServiceUnavailableException'\n }\n}\n\n/** 504 Gateway Timeout. */\nexport class GatewayTimeoutException extends HttpException {\n constructor(message?: string, details?: unknown, options?: HttpExceptionOptions) {\n super(504, message, details, options)\n this.name = 'GatewayTimeoutException'\n }\n}\n","/**\n * Web stream helpers shared by the pipeline and the adapters (internal): conversion of handler\n * stream sources (`ReadableStream`, Node.js `Readable`, async iterables) to byte streams, tracking of\n * response streams (request scope lifetime) and small constructors.\n */\nimport { AsyncLocalStorage } from 'node:async_hooks'\n\n/**\n * A stream source accepted by `HttpResponse.stream()`: a Web `ReadableStream`, a Node.js `Readable`\n * or any async iterable (async generator...) of `Uint8Array` / `string` chunks (strings are encoded\n * as UTF-8).\n */\nexport type StreamSource = ReadableStream<Uint8Array | string> | AsyncIterable<Uint8Array | string>\n\n/** Runs a function in a captured async context (`AsyncLocalStorage.snapshot()`). */\nexport type ContextRunner = <R>(fn: () => R) => R\n\nconst ENCODER = new TextEncoder()\n\n/** The current async context, to run stream reads in it later (the request scope of a response). */\nexport function captureContext(): ContextRunner {\n const snapshot = (AsyncLocalStorage as { snapshot?: () => ContextRunner }).snapshot\n return typeof snapshot === 'function' ? snapshot() : run => run()\n}\n\n/** Whether `value` is a stream source (Web stream, Node.js readable or async iterable). */\nexport function isStreamSource(value: unknown): value is StreamSource {\n return (\n value instanceof ReadableStream ||\n (value !== null &&\n typeof value === 'object' &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function')\n )\n}\n\n/** Byte streams created by {@link toByteStream} (already normalised: not wrapped again). */\nconst BYTE_STREAMS = new WeakSet<ReadableStream<Uint8Array>>()\n\n/** Whether `stream` was created by {@link toByteStream}. */\nexport function isByteStream(stream: ReadableStream<unknown>): boolean {\n return BYTE_STREAMS.has(stream as ReadableStream<Uint8Array>)\n}\n\n/**\n * Converts a stream source to a pull-based byte stream: the source is read only when the consumer\n * reads (backpressure), strings are encoded as UTF-8, `ArrayBuffer`s and views are converted, empty\n * chunks are skipped and cancelling the stream cancels the source (`iterator.return()`, which\n * destroys a Node.js `Readable`; a `Readable` that was never read is destroyed directly).\n *\n * @throws TypeError (as a stream error) for chunks that are neither bytes nor strings.\n */\nexport function toByteStream(source: StreamSource): ReadableStream<Uint8Array> {\n let iterator: AsyncIterator<unknown> | undefined\n let reader: ChunkReader | undefined\n const next = (): Promise<IteratorResult<unknown>> => {\n if (source instanceof ReadableStream) {\n const current: ChunkReader = reader ?? source.getReader()\n reader = current\n return current.read() as Promise<IteratorResult<unknown>>\n }\n iterator ??= source[Symbol.asyncIterator]()\n return iterator.next()\n }\n const stream = new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n for (;;) {\n const result = await next()\n if (result.done === true) {\n controller.close()\n return\n }\n const chunk = toChunk(result.value)\n if (chunk.byteLength > 0) {\n controller.enqueue(chunk)\n return\n }\n }\n },\n async cancel(reason) {\n if (reader !== undefined) await reader.cancel(reason)\n else if (source instanceof ReadableStream) await source.cancel(reason)\n else if (iterator === undefined) {\n // never read: an async generator has nothing to clean up, a Node.js `Readable` holds its resource\n const destroyable = source as { destroy?: unknown }\n if (typeof destroyable.destroy === 'function') destroyable.destroy()\n } else await iterator.return?.(reason)\n },\n },\n { highWaterMark: 0 },\n )\n BYTE_STREAMS.add(stream)\n return stream\n}\n\n/** The part of a stream reader used here (Node.js and Bun declare different reader types). */\ninterface ChunkReader {\n read(): Promise<{ readonly done?: boolean; readonly value?: unknown }>\n cancel(reason?: unknown): Promise<void>\n}\n\nfunction toChunk(value: unknown): Uint8Array {\n if (value instanceof Uint8Array) return value\n if (typeof value === 'string') return ENCODER.encode(value)\n if (value instanceof ArrayBuffer) return new Uint8Array(value)\n if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength)\n throw new TypeError(\n `Invalid stream chunk: expected a Uint8Array or a string, received ${value === null ? 'null' : typeof value}`,\n )\n}\n\n/** The part of a byte stream reader used by {@link trackStream}. */\ninterface ByteReader {\n read(): Promise<{ readonly done?: boolean; readonly value?: Uint8Array | undefined }>\n cancel(reason?: unknown): Promise<void>\n}\n\n/** A response stream whose completion is observed. */\nexport interface TrackedStream {\n readonly stream: ReadableStream<Uint8Array>\n /**\n * Resolves once the source was fully read (`undefined`), cancelled by the consumer (`undefined`:\n * client disconnected, HEAD...) or failed (the error). Never rejects.\n */\n readonly done: Promise<unknown>\n}\n\n/**\n * Wraps a response body so that the pipeline knows when it has been fully sent (or abandoned) and\n * reads the source in `run` (the async context of the request scope, so that stream producers can\n * use request-scoped providers). The wrapper is pull-based (no read-ahead): backpressure is the\n * consumer's. A `Blob` is read through `blob.stream()`, opened on the first read only. `onCancel`\n * runs when the consumer cancels the stream (the client left), before the source is cancelled.\n */\nexport function trackStream(\n body: ReadableStream<Uint8Array> | Blob,\n run: ContextRunner,\n onCancel?: () => void,\n): TrackedStream {\n let reader: ByteReader | undefined = body instanceof Blob ? undefined : body.getReader()\n let settle: (error: unknown) => void = () => undefined\n const done = new Promise<unknown>(resolve => {\n settle = resolve\n })\n let finished = false\n const finish = (error?: unknown): void => {\n if (finished) return\n finished = true\n settle(error)\n }\n const stream = new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n let result: Awaited<ReturnType<ByteReader['read']>>\n try {\n result = await run(() => {\n reader ??= (body as Blob).stream().getReader()\n return reader.read()\n })\n } catch (error) {\n finish(error)\n throw error\n }\n if (result.done === true) {\n controller.close()\n finish()\n return\n }\n controller.enqueue(result.value as Uint8Array)\n },\n async cancel(reason) {\n onCancel?.()\n try {\n const current = reader\n if (current !== undefined) await run(() => current.cancel(reason))\n } catch {\n // the source failed while being cancelled: nothing left to send anyway\n } finally {\n finish()\n }\n },\n },\n { highWaterMark: 0 },\n )\n return { stream, done }\n}\n\n/** A stream failing with `error` on first read. */\nexport function failedStream(error: unknown): ReadableStream<Uint8Array> {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controller.error(error)\n },\n })\n}\n\n/** Cancels a stream, ignoring failures (unconsumed response bodies). */\nexport function discardStream(stream: ReadableStream<Uint8Array> | null | undefined): void {\n if (stream instanceof ReadableStream && !stream.locked) stream.cancel().catch(() => undefined)\n}\n","/**\n * Cookies (RFC 0006): parsing of the `cookie` request header, canonical value encoding, strict\n * `Set-Cookie` serialisation (RFC 6265bis: attribute validation, name prefixes, size limits),\n * `Set-Cookie` parsing (tests) and the response cookie jar.\n *\n * This module is import-free (pure functions): safe to import from anywhere, the compiler excepted\n * (it has its own token grammar).\n */\n\n/** Options of a cookie set on a response (`ctx.setCookie()`, `HttpResponse.withCookie()`). */\nexport interface CookieOptions {\n /** Lifetime in seconds (integer). `0` or less expires the cookie now. Default: session cookie. */\n readonly maxAge?: number\n /**\n * Absolute expiry (sent as an IMF-fixdate), in the years 1601 to 9999 (browsers ignore other\n * years). Browsers cap lifetimes at 400 days: prefer `maxAge` for long-lived cookies.\n */\n readonly expires?: Date\n /**\n * Domain (sub-domains included). Default: none, a host-only cookie. `null`: host-only even when\n * `cookies.defaults` sets a domain. `__Host-` cookies never take the default domain.\n */\n readonly domain?: string | null\n /** Default: `'/'`. */\n readonly path?: string\n /** Default: `true` (browsers only send it over HTTPS, `http://localhost` excepted). */\n readonly secure?: boolean\n /** Default: `true` (not readable from JavaScript). */\n readonly httpOnly?: boolean\n /** Default: `'lax'`. `'none'` requires `secure`. */\n readonly sameSite?: 'strict' | 'lax' | 'none'\n /** CHIPS partitioned cookie. Requires `secure`. Default: `false`. */\n readonly partitioned?: boolean\n /** Chromium `Priority`. Default: none. */\n readonly priority?: 'low' | 'medium' | 'high'\n /** Signs the value with the first secret of the plugin option `cookies.secrets`. Default: `false`. */\n readonly signed?: boolean\n}\n\n/** Plugin-wide defaults (`cookies.defaults`). Lifetime and signing are per cookie. */\nexport type CookieDefaults = Omit<CookieOptions, 'maxAge' | 'expires' | 'signed'>\n\n/** What identifies a cookie to clear (and keeps prefixed names valid). */\nexport type ClearCookieOptions = Pick<\n CookieOptions,\n 'domain' | 'path' | 'secure' | 'httpOnly' | 'sameSite' | 'partitioned'\n>\n\n/** A cookie to send, as given (defaults and signing are applied when the response is serialised). */\nexport interface ResponseCookie {\n readonly name: string\n /** `undefined`: a clearing cookie. */\n readonly value: string | undefined\n readonly options: CookieOptions\n}\n\n/** A parsed `Set-Cookie` line (see {@link parseSetCookie}). */\nexport interface SetCookieInfo {\n readonly name: string\n /** Decoded value (a signed cookie: `\"<value>.<signature>\"`, decoded). */\n readonly value: string\n /** The header line. */\n readonly raw: string\n readonly expires?: Date\n readonly maxAge?: number\n readonly domain?: string\n readonly path?: string\n readonly secure: boolean\n readonly httpOnly: boolean\n readonly sameSite?: 'strict' | 'lax' | 'none'\n readonly partitioned: boolean\n readonly priority?: 'low' | 'medium' | 'high'\n}\n\n/** The secure defaults: `Path=/; Secure; HttpOnly; SameSite=Lax`, host-only. */\nexport const DEFAULT_COOKIE_OPTIONS: Readonly<{\n path: string\n secure: boolean\n httpOnly: boolean\n sameSite: 'strict' | 'lax' | 'none'\n}> = Object.freeze({ path: '/', secure: true, httpOnly: true, sameSite: 'lax' })\n\n/** Largest `name=value` (bytes on the wire, after encoding and signing). */\nexport const MAX_COOKIE_SIZE = 4096\n/** Largest `Domain` / `Path` attribute value (bytes). */\nexport const MAX_COOKIE_ATTRIBUTE_SIZE = 1024\nconst MAX_DOMAIN_LENGTH = 253\nconst EPOCH = 'Thu, 01 Jan 1970 00:00:00 GMT'\n/** Years a cookie-date can carry (RFC 6265 §5.1.1; four digits in an IMF-fixdate). */\nconst MIN_EXPIRES_YEAR = 1601\nconst MAX_EXPIRES_YEAR = 9999\n\nconst OPTION_KEYS: ReadonlySet<string> = new Set([\n 'maxAge',\n 'expires',\n 'domain',\n 'path',\n 'secure',\n 'httpOnly',\n 'sameSite',\n 'partitioned',\n 'priority',\n 'signed',\n])\nconst SAME_SITE: Readonly<Record<string, string>> = { strict: 'Strict', lax: 'Lax', none: 'None' }\nconst PRIORITY: Readonly<Record<string, string>> = { low: 'Low', medium: 'Medium', high: 'High' }\n\n// -------------------------------------------------------------------------------------------------\n// Request cookies\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Parses a `cookie` request header into a prototype-less, frozen record (`__proto__` is just a\n * name). Pairs are split on `;` only (never `,`) and trimmed; a pair without `=` or with an empty\n * name is ignored; names are kept as sent (case-sensitive); a value wrapped in double quotes is\n * unquoted, and percent-decoded when it contains `%` (a malformed sequence keeps the raw value).\n * When a name repeats, the first occurrence wins (browsers send the most specific path first).\n * Linear time, never throws.\n */\nexport function parseCookieHeader(header: string | undefined): Readonly<Record<string, string>> {\n const result = Object.create(null) as Record<string, string>\n if (typeof header === 'string') {\n let start = 0\n const length = header.length\n // the next `=` at or after `start`, searched again only once passed: every character is scanned\n // at most twice, even for a header made of `;` without `=` (linear time)\n let equals = -1\n while (start < length) {\n let end = header.indexOf(';', start)\n if (end === -1) end = length\n if (equals < start) {\n equals = header.indexOf('=', start)\n if (equals === -1) equals = length\n }\n if (equals < end) {\n const name = trim(header, start, equals)\n if (name !== '' && !Object.hasOwn(result, name)) {\n result[name] = decodeCookieValue(unquote(trim(header, equals + 1, end)))\n }\n }\n start = end + 1\n }\n }\n return Object.freeze(result)\n}\n\n/** `text.slice(start, end)` without leading and trailing SP / HTAB. */\nfunction trim(text: string, start: number, end: number): string {\n let from = start\n let to = end\n while (from < to && isBlank(text.charCodeAt(from))) from++\n while (to > from && isBlank(text.charCodeAt(to - 1))) to--\n return text.slice(from, to)\n}\n\nfunction isBlank(code: number): boolean {\n return code === 0x20 || code === 0x09\n}\n\nfunction unquote(value: string): string {\n return value.length >= 2 && value.charCodeAt(0) === 0x22 && value.charCodeAt(value.length - 1) === 0x22\n ? value.slice(1, -1)\n : value\n}\n\n/**\n * Decodes a cookie value produced by {@link encodeCookieValue} (`decodeURIComponent` when it\n * contains `%`; a malformed sequence keeps the raw value). Never throws.\n */\nexport function decodeCookieValue(value: string): string {\n if (!value.includes('%')) return value\n try {\n return decodeURIComponent(value)\n } catch {\n return value\n }\n}\n\n/**\n * Encodes a cookie value canonically: the UTF-8 bytes outside RFC 6265 `cookie-octet` (space, `\"`,\n * `,`, `;`, `\\`, controls, non-ASCII) and `%` are percent-encoded (upper-case hex), so that\n * {@link decodeCookieValue} restores the value exactly (`a b;c` → `a%20b%3Bc`), and\n * `encode(decode(w)) === w` for every encoded `w`. Quotes are never emitted.\n *\n * @throws TypeError for a non-string or a string with lone surrogates (they cannot round-trip).\n */\nexport function encodeCookieValue(value: string): string {\n if (typeof value !== 'string') {\n throw new TypeError(`A cookie value must be a string (received ${describe(value)})`)\n }\n if (!value.isWellFormed()) {\n throw new TypeError('A cookie value must be a well-formed string (it contains a lone surrogate)')\n }\n let encoded = ''\n let plain = 0\n for (let index = 0; index < value.length; index++) {\n const code = value.charCodeAt(index)\n if (isCookieOctet(code)) continue\n encoded += value.slice(plain, index)\n if (code < 0x80) {\n encoded += `%${HEX[code] as string}`\n plain = index + 1\n } else {\n // a whole code point (a surrogate pair is two UTF-16 units): `encodeURIComponent` gives its UTF-8 bytes\n const point = value.codePointAt(index) as number\n const width = point > 0xffff ? 2 : 1\n encoded += encodeURIComponent(value.slice(index, index + width))\n index += width - 1\n plain = index + 1\n }\n }\n return plain === 0 ? value : encoded + value.slice(plain)\n}\n\nconst HEX: readonly string[] = Array.from({ length: 128 }, (_, code) =>\n code.toString(16).toUpperCase().padStart(2, '0'),\n)\n\n/** RFC 6265 `cookie-octet`, `%` excluded (the escape character). */\nfunction isCookieOctet(code: number): boolean {\n return (\n code === 0x21 ||\n (code >= 0x23 && code <= 0x2b && code !== 0x25) ||\n (code >= 0x2d && code <= 0x3a) ||\n (code >= 0x3c && code <= 0x5b) ||\n (code >= 0x5d && code <= 0x7e)\n )\n}\n\n/** Whether `name` is an RFC 9110 token (a cookie name Znight can set). */\nexport function isCookieName(name: unknown): name is string {\n if (typeof name !== 'string' || name === '') return false\n for (let index = 0; index < name.length; index++) {\n if (!isTokenChar(name.charCodeAt(index))) return false\n }\n return true\n}\n\nfunction isTokenChar(code: number): boolean {\n // ! # $ % & ' * + - . ^ _ ` | ~ DIGIT ALPHA\n return (\n (code >= 0x30 && code <= 0x39) ||\n (code >= 0x41 && code <= 0x5a) ||\n (code >= 0x61 && code <= 0x7a) ||\n code === 0x21 ||\n (code >= 0x23 && code <= 0x27) ||\n code === 0x2a ||\n code === 0x2b ||\n code === 0x2d ||\n code === 0x2e ||\n code === 0x5e ||\n code === 0x5f ||\n code === 0x60 ||\n code === 0x7c ||\n code === 0x7e\n )\n}\n\n// -------------------------------------------------------------------------------------------------\n// Response cookies\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Checks what a cookie says about itself, without plugin defaults: the name, the value type, the\n * options (types, `maxAge`, `expires`, `domain`, `path`) and the size before signing. Run by\n * `HttpResponse.withCookie()` / `withoutCookie()` at call time; the rules depending on the defaults\n * (prefixes, `SameSite=None` and `partitioned` with `secure`), signing and the final size are checked\n * when the response is serialised.\n *\n * @throws TypeError / RangeError naming the cookie.\n */\nexport function checkCookie(name: string, value: string | undefined, options: CookieOptions | undefined): void {\n checkName(name)\n const checked = checkOptions(name, options)\n if (value !== undefined) {\n const encoded = encodeValue(name, value)\n checkSize(name, encoded)\n }\n if (typeof checked.domain === 'string') normalizeDomain(name, checked.domain)\n if (checked.path !== undefined) checkPath(name, checked.path)\n}\n\n/** A cookie resolved with the defaults: its `Set-Cookie` line and its jar key. */\nexport interface SerializedCookie {\n /** `name` + domain + path: a later cookie with the same key replaces an earlier one. */\n readonly key: string\n readonly line: string\n}\n\n/**\n * Serialises a response cookie with `defaults` (merged under the options): every rule of RFC 0006\n * §4.3 is checked. `sign` turns the encoded value into its signed wire form (`signed: true`).\n *\n * @throws TypeError / RangeError naming the cookie.\n */\nexport function serializeResponseCookie(\n cookie: ResponseCookie,\n defaults: CookieDefaults,\n sign?: (name: string, encoded: string) => string,\n): SerializedCookie {\n const { name, value } = cookie\n checkName(name)\n const options = checkOptions(name, cookie.options)\n checkOptions(name, defaults, true)\n const attributes = resolveAttributes(name, { ...applicableDefaults(name, defaults), ...definedOnly(options) })\n let wire: string\n let maxAge: number | undefined\n let expires: string | undefined\n if (value === undefined) {\n wire = ''\n maxAge = 0\n expires = EPOCH\n } else {\n wire = encodeValue(name, value)\n if (options.signed === true) {\n if (sign === undefined) throw new TypeError(`Cannot sign the cookie \"${name}\": no signing key`)\n wire = sign(name, wire)\n }\n if (options.maxAge !== undefined) maxAge = Math.max(options.maxAge, 0)\n if (options.expires !== undefined) expires = options.expires.toUTCString()\n }\n checkSize(name, wire)\n let line = `${name}=${wire}`\n if (maxAge !== undefined) line += `; Max-Age=${maxAge}`\n if (expires !== undefined) line += `; Expires=${expires}`\n if (attributes.domain !== undefined) line += `; Domain=${attributes.domain}`\n line += `; Path=${attributes.path}`\n if (attributes.secure) line += '; Secure'\n if (attributes.httpOnly) line += '; HttpOnly'\n if (attributes.sameSite !== undefined) line += `; SameSite=${SAME_SITE[attributes.sameSite] as string}`\n if (attributes.partitioned) line += '; Partitioned'\n if (attributes.priority !== undefined && value !== undefined) {\n line += `; Priority=${PRIORITY[attributes.priority] as string}`\n }\n return { key: cookieKey(name, attributes.domain, attributes.path), line }\n}\n\n/**\n * The `Set-Cookie` line of a cookie with the secure defaults\n * (`Path=/; Secure; HttpOnly; SameSite=Lax`, overridable per cookie), in the order\n * `name=value; Max-Age; Expires; Domain; Path; Secure; HttpOnly; SameSite; Partitioned; Priority`.\n * The value is percent-encoded (see {@link encodeCookieValue}). Signing (`signed: true`) needs the\n * secrets of the plugin: use `ctx.setCookie()` or `HttpPlugin.signCookie()`.\n *\n * ```ts\n * serializeCookie('theme', 'dark', { maxAge: 86_400, httpOnly: false })\n * // theme=dark; Max-Age=86400; Path=/; Secure; SameSite=Lax\n * ```\n *\n * @throws TypeError for an invalid name, value or attribute, a `SameSite=None` or partitioned cookie\n * without `Secure`, a broken `__Secure-` / `__Host-` / `__Http-` / `__Host-Http-` prefix rule.\n * @throws RangeError when `name=value` exceeds 4096 bytes, or `Domain` / `Path` 1024 bytes.\n */\nexport function serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n return serializeResponseCookie({ name, value, options }, DEFAULT_COOKIE_OPTIONS).line\n}\n\n/**\n * The `Set-Cookie` line clearing a cookie: `name=; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT`\n * plus `Domain`, `Path`, `Secure`, `HttpOnly`, `SameSite` and `Partitioned` (secure defaults merged\n * with `options`), so that a prefixed cookie is cleared with valid attributes.\n */\nexport function serializeClearCookie(name: string, options: ClearCookieOptions = {}): string {\n return serializeResponseCookie({ name, value: undefined, options }, DEFAULT_COOKIE_OPTIONS).line\n}\n\n/** The jar key of a cookie (RFC 6265: a cookie is identified by its name, domain and path). */\nexport function cookieKey(name: string, domain: string | undefined, path: string): string {\n return `${name}\\u0000${domain ?? ''}\\u0000${path}`\n}\n\ninterface Attributes {\n readonly domain: string | undefined\n readonly path: string\n readonly secure: boolean\n readonly httpOnly: boolean\n readonly sameSite: 'strict' | 'lax' | 'none' | undefined\n readonly partitioned: boolean\n readonly priority: 'low' | 'medium' | 'high' | undefined\n}\n\n/**\n * The defaults a cookie takes: all of them, but a `__Host-` cookie (host-only, `Path=/` by\n * definition) never takes a default domain or path. Its own options are still checked.\n */\nfunction applicableDefaults(name: string, defaults: CookieDefaults): CookieDefaults {\n if (!name.toLowerCase().startsWith('__host-')) return defaults\n const { domain: _domain, path: _path, ...rest } = defaults\n return rest\n}\n\n/** Attributes after the defaults, checked against the cross-attribute and prefix rules. */\nfunction resolveAttributes(name: string, options: CookieOptions): Attributes {\n // `null`: host-only, whatever the defaults\n const domain = typeof options.domain === 'string' ? normalizeDomain(name, options.domain) : undefined\n const path = options.path ?? '/'\n checkPath(name, path)\n const attributes: Attributes = {\n domain,\n path,\n secure: options.secure === true,\n httpOnly: options.httpOnly === true,\n sameSite: options.sameSite,\n partitioned: options.partitioned === true,\n priority: options.priority,\n }\n if (attributes.sameSite === 'none' && !attributes.secure) {\n throw invalid(name, 'SameSite=None requires secure: true (browsers reject it otherwise)')\n }\n if (attributes.partitioned && !attributes.secure) {\n throw invalid(name, 'partitioned cookies require secure: true')\n }\n checkPrefix(name, attributes)\n return attributes\n}\n\n/** `__Secure-`, `__Host-`, `__Http-`, `__Host-Http-` (case-insensitive, like browsers). */\nfunction checkPrefix(name: string, attributes: Attributes): void {\n const lower = name.toLowerCase()\n const host = lower.startsWith('__host-')\n const http = lower.startsWith('__http-') || lower.startsWith('__host-http-')\n if (!host && !http && !lower.startsWith('__secure-')) return\n const prefix = prefixName(host, http)\n if (!attributes.secure) throw invalid(name, `the ${prefix} prefix requires secure: true`)\n if (http && !attributes.httpOnly) throw invalid(name, `the ${prefix} prefix requires httpOnly: true`)\n if (host) {\n if (attributes.domain !== undefined) throw invalid(name, `the ${prefix} prefix forbids a domain`)\n if (attributes.path !== '/') throw invalid(name, `the ${prefix} prefix requires path: '/'`)\n }\n}\n\nfunction checkName(name: string): void {\n if (!isCookieName(name)) {\n throw new TypeError(\n `Invalid cookie name ${describe(name)}: expected a token (letters, digits and ! # $ % & ' * + - . ^ _ \\` | ~)`,\n )\n }\n}\n\nfunction encodeValue(name: string, value: string): string {\n if (typeof value !== 'string') throw invalid(name, `the value must be a string (received ${describe(value)})`)\n if (!value.isWellFormed()) throw invalid(name, 'the value contains a lone surrogate')\n return encodeCookieValue(value)\n}\n\nfunction checkSize(name: string, wire: string): void {\n const size = byteLength(name) + 1 + wire.length // the wire value is ASCII\n if (size > MAX_COOKIE_SIZE) {\n throw new RangeError(\n `Invalid cookie \"${name}\": name=value is ${size} bytes on the wire, above the limit of ${MAX_COOKIE_SIZE} (browsers drop it)`,\n )\n }\n}\n\n/** Checks the type of every option (and rejects unknown keys); returns the options. */\nfunction checkOptions(name: string, options: CookieOptions | undefined, defaults = false): CookieOptions {\n if (options === undefined) return {}\n const what = defaults ? 'cookies.defaults' : 'options'\n if (options === null || typeof options !== 'object' || Array.isArray(options)) {\n throw invalid(name, `${what} must be an object (received ${describe(options)})`)\n }\n for (const key of Object.keys(options)) {\n if (!OPTION_KEYS.has(key)) throw invalid(name, `unknown option \"${key}\"`)\n }\n const { maxAge, expires, domain, path, secure, httpOnly, sameSite, partitioned, priority, signed } = options\n if (maxAge !== undefined && !(typeof maxAge === 'number' && Number.isSafeInteger(maxAge))) {\n throw invalid(name, `maxAge must be an integer number of seconds (received ${describe(maxAge)})`)\n }\n if (expires !== undefined && !(expires instanceof Date && !Number.isNaN(expires.getTime()))) {\n throw invalid(name, `expires must be a valid Date (received ${describe(expires)})`)\n }\n if (expires !== undefined) {\n const year = expires.getUTCFullYear()\n if (year < MIN_EXPIRES_YEAR || year > MAX_EXPIRES_YEAR) {\n throw invalid(\n name,\n `expires must be in the years ${MIN_EXPIRES_YEAR} to ${MAX_EXPIRES_YEAR} (received ${expires.toISOString()}): browsers ignore other dates; use maxAge for a long lifetime (browsers cap it at 400 days)`,\n )\n }\n }\n if (domain !== undefined && domain !== null && typeof domain !== 'string') {\n throw invalid(name, `domain must be a string or null (received ${describe(domain)})`)\n }\n if (path !== undefined && typeof path !== 'string') {\n throw invalid(name, `path must be a string (received ${describe(path)})`)\n }\n for (const [key, flag] of [\n ['secure', secure],\n ['httpOnly', httpOnly],\n ['partitioned', partitioned],\n ['signed', signed],\n ] as const) {\n if (flag !== undefined && typeof flag !== 'boolean') {\n throw invalid(name, `${key} must be a boolean (received ${describe(flag)})`)\n }\n }\n if (sameSite !== undefined && !Object.hasOwn(SAME_SITE, sameSite)) {\n throw invalid(name, `sameSite must be 'strict', 'lax' or 'none' (received ${describe(sameSite)})`)\n }\n if (priority !== undefined && !Object.hasOwn(PRIORITY, priority)) {\n throw invalid(name, `priority must be 'low', 'medium' or 'high' (received ${describe(priority)})`)\n }\n return options\n}\n\n/** Lower-cased, one leading `.` removed; an ASCII host name of at most 253 characters. */\nfunction normalizeDomain(name: string, domain: string): string {\n const normalized = (domain.startsWith('.') ? domain.slice(1) : domain).toLowerCase()\n if (normalized.length > MAX_COOKIE_ATTRIBUTE_SIZE) {\n throw new RangeError(`Invalid cookie \"${name}\": the domain exceeds ${MAX_COOKIE_ATTRIBUTE_SIZE} bytes`)\n }\n if (!isHostName(normalized)) {\n throw invalid(\n name,\n `invalid domain ${describe(domain)}: expected an ASCII host name (letters, digits, -, dot-separated labels; IDNs in punycode)`,\n )\n }\n return normalized\n}\n\nfunction isHostName(domain: string): boolean {\n if (domain === '' || domain.length > MAX_DOMAIN_LENGTH) return false\n let label = 0\n for (let index = 0; index < domain.length; index++) {\n const code = domain.charCodeAt(index)\n if (code === 0x2e) {\n if (label === 0) return false\n label = 0\n continue\n }\n const valid = (code >= 0x30 && code <= 0x39) || (code >= 0x61 && code <= 0x7a) || code === 0x2d\n if (!valid) return false\n label++\n }\n return label > 0\n}\n\n/** Starts with `/`, `%x20-7E` except `;`, at most 1024 bytes. */\nfunction checkPath(name: string, path: string): void {\n if (path.length > MAX_COOKIE_ATTRIBUTE_SIZE) {\n throw new RangeError(`Invalid cookie \"${name}\": the path exceeds ${MAX_COOKIE_ATTRIBUTE_SIZE} bytes`)\n }\n let valid = path.startsWith('/')\n for (let index = 0; valid && index < path.length; index++) {\n const code = path.charCodeAt(index)\n valid = code >= 0x20 && code <= 0x7e && code !== 0x3b\n }\n if (!valid) {\n throw invalid(name, `invalid path ${describe(path)}: expected \"/...\" made of visible ASCII characters without \";\"`)\n }\n}\n\n/** The options without `undefined` values (they would erase defaults when spread). */\nfunction definedOnly(options: CookieOptions): CookieOptions {\n const result: Record<string, unknown> = {}\n for (const key of Object.keys(options)) {\n const value = (options as Record<string, unknown>)[key]\n if (value !== undefined) result[key] = value\n }\n return result as CookieOptions\n}\n\n// -------------------------------------------------------------------------------------------------\n// Set-Cookie parsing\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Parses a `Set-Cookie` line (attribute names are case-insensitive; the value is decoded like a\n * request cookie). Used by `inject()` to fill `response.cookies`.\n *\n * @throws TypeError when the line has no `name=value` pair.\n */\nexport function parseSetCookie(line: string): SetCookieInfo {\n const parts = String(line).split(';')\n const pair = parts[0] as string\n const equals = pair.indexOf('=')\n const name = equals === -1 ? '' : trim(pair, 0, equals)\n if (name === '') throw new TypeError(`Invalid Set-Cookie line ${describe(line)}: missing name=value`)\n const info: {\n -readonly [K in keyof SetCookieInfo]: SetCookieInfo[K]\n } = {\n name,\n value: decodeCookieValue(unquote(trim(pair, equals + 1, pair.length))),\n raw: line,\n secure: false,\n httpOnly: false,\n partitioned: false,\n }\n for (const part of parts.slice(1)) {\n const separator = part.indexOf('=')\n const key = trim(part, 0, separator === -1 ? part.length : separator).toLowerCase()\n const value = separator === -1 ? '' : trim(part, separator + 1, part.length)\n switch (key) {\n case 'max-age': {\n const seconds = /^-?\\d+$/.test(value) ? Number(value) : Number.NaN\n if (Number.isSafeInteger(seconds)) info.maxAge = seconds\n break\n }\n case 'expires': {\n const date = new Date(value)\n if (!Number.isNaN(date.getTime())) info.expires = date\n break\n }\n case 'domain':\n if (value !== '') info.domain = (value.startsWith('.') ? value.slice(1) : value).toLowerCase()\n break\n case 'path':\n if (value.startsWith('/')) info.path = value\n break\n case 'secure':\n info.secure = true\n break\n case 'httponly':\n info.httpOnly = true\n break\n case 'partitioned':\n info.partitioned = true\n break\n case 'samesite': {\n const sameSite = value.toLowerCase()\n if (sameSite === 'strict' || sameSite === 'lax' || sameSite === 'none') info.sameSite = sameSite\n break\n }\n case 'priority': {\n const priority = value.toLowerCase()\n if (priority === 'low' || priority === 'medium' || priority === 'high') info.priority = priority\n break\n }\n default:\n break\n }\n }\n return Object.freeze(info)\n}\n\n/** The `set-cookie` lines of a response parsed by name (the last one wins), prototype-less and frozen. */\nexport function parseSetCookies(\n lines: readonly string[] | string | undefined,\n): Readonly<Record<string, SetCookieInfo>> {\n const result = Object.create(null) as Record<string, SetCookieInfo>\n const list = typeof lines === 'string' ? [lines] : (lines ?? [])\n for (const line of list) {\n try {\n const info = parseSetCookie(line)\n result[info.name] = info\n } catch {\n // not a cookie line: ignored\n }\n }\n return Object.freeze(result)\n}\n\n// -------------------------------------------------------------------------------------------------\n// Jar\n// -------------------------------------------------------------------------------------------------\n\n/**\n * Cookies of a response in insertion order, keyed by name, domain and path: a later cookie with\n * the same key replaces the earlier one in place (set then clear gives one clearing cookie).\n */\nexport class CookieJar<T> {\n readonly #entries = new Map<string, T>()\n\n /** Adds or replaces (in place) the entry of `key`. */\n set(key: string, entry: T): void {\n this.#entries.set(key, entry)\n }\n\n get size(): number {\n return this.#entries.size\n }\n\n values(): T[] {\n return [...this.#entries.values()]\n }\n\n entries(): [string, T][] {\n return [...this.#entries.entries()]\n }\n}\n\n/**\n * The jar key of a cookie as given (`HttpResponse.withCookie()`, before the defaults are known):\n * an absent domain or path is keyed as \"default\", a `null` domain as host-only.\n */\nexport function givenCookieKey(name: string, options: CookieOptions): string {\n const given = options.domain\n let domain: string\n if (given === undefined) domain = '\\u0001'\n else if (given === null) domain = ''\n else domain = (given.startsWith('.') ? given.slice(1) : given).toLowerCase()\n return `${name}\\u0000${domain}\\u0000${options.path ?? '\\u0001'}`\n}\n\n// -------------------------------------------------------------------------------------------------\n// Helpers\n// -------------------------------------------------------------------------------------------------\n\nfunction prefixName(host: boolean, http: boolean): string {\n if (host) return http ? '__Host-Http-' : '__Host-'\n return http ? '__Http-' : '__Secure-'\n}\n\nfunction invalid(name: string, reason: string): TypeError {\n return new TypeError(`Invalid cookie \"${name}\": ${reason}`)\n}\n\nfunction byteLength(text: string): number {\n let size = 0\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index)\n if (code < 0x80) size += 1\n else if (code < 0x800 || (code >= 0xd800 && code <= 0xdfff))\n size += 2 // a surrogate pair: 4 bytes\n else size += 3\n }\n return size\n}\n\nfunction describe(value: unknown): string {\n if (typeof value === 'string') return JSON.stringify(value.length > 64 ? `${value.slice(0, 64)}…` : value)\n if (value instanceof Date) return 'an invalid Date'\n if (value === null) return 'null'\n if (typeof value === 'object') return 'an object'\n return typeof value === 'bigint' ? `${value}n` : String(value)\n}\n","/** Helpers shared by the adapters (internal). */\nimport type { Readable } from 'node:stream'\nimport type {\n HttpServerAddress,\n InjectRequest,\n InjectResponse,\n InjectStreamRequest,\n InjectStreamResponse,\n} from '../adapter.ts'\n\nimport { encodeCookieValue, parseSetCookies } from '../cookies.ts'\nimport { BadRequestException, PayloadTooLargeException } from '../exceptions.ts'\nimport { failedStream } from '../stream.ts'\n\n/** An inject request normalised for the underlying tools. */\nexport interface NormalizedInject {\n readonly method: string\n readonly url: string\n readonly headers: Record<string, string>\n readonly payload: string | Uint8Array | undefined\n}\n\n/**\n * Applies the defaults of {@link InjectRequest}: query merged in the URL, cookies appended to the\n * `cookie` header (encoded values joined with `; `), body encoding and content type (`FormData` →\n * `multipart/form-data`, `Blob` → its type).\n */\nexport async function normalizeInject(request: InjectRequest): Promise<NormalizedInject> {\n if (request === null || typeof request !== 'object') throw new TypeError('inject() expects a request object')\n if (typeof request.url !== 'string' || !request.url.startsWith('/')) {\n throw new TypeError(`inject() expects a url starting with \"/\" (received ${JSON.stringify(request.url)})`)\n }\n const method = (request.method ?? 'GET').toUpperCase()\n let url = request.url\n if (request.query !== undefined) {\n const search = new URLSearchParams()\n for (const [key, value] of Object.entries(request.query)) {\n if (typeof value === 'string') search.append(key, value)\n else for (const item of value) search.append(key, item)\n }\n const query = search.toString()\n if (query !== '') url += `${url.includes('?') ? '&' : '?'}${query}`\n }\n const headers: Record<string, string> = {}\n for (const [name, value] of Object.entries(request.headers ?? {})) headers[name.toLowerCase()] = value\n if (request.signedCookies !== undefined) {\n throw new TypeError('inject(): signedCookies are signed by HttpPlugin.inject() (adapters only accept cookies)')\n }\n const cookie = cookieHeader(request.cookies)\n if (cookie !== '') headers['cookie'] = headers['cookie'] === undefined ? cookie : `${headers['cookie']}; ${cookie}`\n const body = request.body\n let payload: string | Uint8Array | undefined\n if (body === undefined) {\n payload = undefined\n } else if (typeof body === 'string') {\n payload = body\n headers['content-type'] ??= 'text/plain; charset=utf-8'\n } else if (body instanceof Uint8Array || body instanceof ArrayBuffer) {\n payload = body instanceof Uint8Array ? body : new Uint8Array(body)\n headers['content-type'] ??= 'application/octet-stream'\n } else if (body instanceof FormData) {\n // the Fetch API encodes forms (the boundary of the generated content type must be used)\n const encoded = new Response(body)\n // read the generated content type (with its boundary) before consuming the body (Bun sets it lazily)\n const type = encoded.headers.get('content-type')\n payload = new Uint8Array(await encoded.arrayBuffer())\n headers['content-type'] = type ?? encoded.headers.get('content-type') ?? 'multipart/form-data'\n } else if (body instanceof Blob) {\n payload = new Uint8Array(await body.arrayBuffer())\n headers['content-type'] ??= body.type === '' ? 'application/octet-stream' : body.type\n } else {\n payload = JSON.stringify(body)\n headers['content-type'] ??= 'application/json'\n }\n return { method, url, headers, payload }\n}\n\n/** The `cookie` header of inject cookies: `name=encoded` pairs joined with `; `. */\nfunction cookieHeader(cookies: Readonly<Record<string, string>> | undefined): string {\n if (cookies === undefined) return ''\n if (cookies === null || typeof cookies !== 'object') throw new TypeError('inject(): cookies must be an object')\n const pairs: string[] = []\n for (const name of Object.keys(cookies)) {\n if (!isRequestCookieName(name)) {\n throw new TypeError(\n `inject(): invalid cookie name ${JSON.stringify(name)} (empty, or with \";\", \"=\", spaces or controls)`,\n )\n }\n const value = cookies[name]\n if (typeof value !== 'string') throw new TypeError(`inject(): the value of the cookie \"${name}\" must be a string`)\n pairs.push(`${name}=${encodeCookieValue(value)}`)\n }\n return pairs.join('; ')\n}\n\n/** A name a `cookie` header can carry: no `;`, `=`, whitespace or controls, Latin-1. */\nfunction isRequestCookieName(name: string): boolean {\n if (name === '') return false\n for (let index = 0; index < name.length; index++) {\n const code = name.charCodeAt(index)\n if (code <= 0x20 || code === 0x3b || code === 0x3d || code === 0x7f || code > 0xff) return false\n }\n return true\n}\n\nconst DECODER = new TextDecoder()\n\n/**\n * Normalises response headers: lower-case names, repeated values joined with `, `, except\n * `set-cookie` (one entry per cookie: an `Expires` attribute contains `, `).\n */\nexport function injectHeaders(\n headers: Readonly<Record<string, string | number | readonly string[] | undefined>>,\n): Record<string, string | string[]> {\n const normalized: Record<string, string | string[]> = {}\n for (const [name, value] of Object.entries(headers)) {\n if (value === undefined) continue\n const key = name.toLowerCase()\n if (key === 'set-cookie') normalized[key] = typeof value === 'object' ? [...value] : [String(value)]\n else normalized[key] = typeof value === 'object' ? value.join(', ') : String(value)\n }\n return normalized\n}\n\n/** Builds an {@link InjectResponse} (headers normalised by {@link injectHeaders}, cookies parsed). */\nexport function injectResponse(\n status: number,\n headers: Readonly<Record<string, string | number | readonly string[] | undefined>>,\n bytes: Uint8Array,\n): InjectResponse {\n const normalized = injectHeaders(headers)\n const body = DECODER.decode(bytes)\n return {\n status,\n headers: normalized,\n body,\n bytes,\n cookies: parseSetCookies(normalized['set-cookie']),\n json: <T = unknown>(): T => JSON.parse(body) as T,\n }\n}\n\n/** Whether a `content-type` is `text/event-stream`. */\nexport function isEventStreamType(contentType: string | readonly string[] | undefined): boolean {\n if (typeof contentType !== 'string') return false\n const semicolon = contentType.indexOf(';')\n return (semicolon === -1 ? contentType : contentType.slice(0, semicolon)).trim().toLowerCase() === 'text/event-stream'\n}\n\n/**\n * `inject()` on top of `injectStream()`: reads the body to its end, except for an event stream\n * (which would never end): its body is cancelled (the server sees a disconnect) and the call\n * rejects with a hint.\n */\nexport async function bufferInjectStream(\n injectStream: (request: InjectStreamRequest) => Promise<InjectStreamResponse>,\n request: InjectRequest,\n): Promise<InjectResponse> {\n const response = await injectStream(request)\n const method = (request.method ?? 'GET').toUpperCase()\n if (method !== 'HEAD' && isEventStreamType(response.headers['content-type'])) {\n await response.body.cancel().catch(() => undefined)\n throw new TypeError(\n `inject(): ${method} ${request.url} answered an event stream (text/event-stream): use injectSse() or injectStream()`,\n )\n }\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let size = 0\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n size += value.byteLength\n chunks.push(value)\n }\n const bytes = concat(chunks, size)\n const body = DECODER.decode(bytes)\n return {\n status: response.status,\n headers: response.headers,\n body,\n bytes,\n cookies: response.cookies,\n json: <T = unknown>(): T => JSON.parse(body) as T,\n }\n}\n\n/** Builds an {@link InjectStreamResponse}. */\nexport function injectStreamResponse(\n status: number,\n headers: Readonly<Record<string, string | number | readonly string[] | undefined>>,\n body: ReadableStream<Uint8Array>,\n): InjectStreamResponse {\n const normalized = injectHeaders(headers)\n return { status, headers: normalized, cookies: parseSetCookies(normalized['set-cookie']), body }\n}\n\n/** Builds an {@link HttpServerAddress} from a bound address. */\nexport function serverAddress(address: string, port: number, family?: string | number): HttpServerAddress {\n const ipv6 = family === 'IPv6' || family === 6 || address.includes(':')\n let client = address\n if (address === '0.0.0.0') client = '127.0.0.1'\n else if (address === '::') client = '::1'\n const url = `http://${client.includes(':') ? `[${client}]` : client}:${port}`\n return Object.freeze({\n host: address,\n port,\n family: ipv6 ? 'IPv6' : 'IPv4',\n url,\n toString: () => url,\n })\n}\n\n/** The 413 error of a body above `limit` bytes. */\nexport function payloadTooLarge(limit: number): PayloadTooLargeException {\n return new PayloadTooLargeException(`Request body exceeds the limit of ${limit} bytes`, undefined, {\n headers: { connection: 'close' },\n })\n}\n\n/** Rejects early when `content-length` announces more than `limit` bytes. */\nexport function exceedsDeclaredLength(contentLength: string | undefined, limit: number): boolean {\n if (contentLength === undefined) return false\n const length = Number(contentLength)\n return Number.isFinite(length) && length > limit\n}\n\n/** Bytes read (and discarded) from an abandoned Web request body before it is cancelled. */\nconst MAX_DISCARD_BYTES = 64 * 1024 * 1024\n\n/**\n * The body of a Web request as a pull-based stream enforcing `limit` (see\n * `AdapterRequest.streamBody`). `body` is only read when needed (a Node.js-backed request body\n * starts buffering once accessed). On overflow or cancellation the rest of the body is read and\n * discarded in the background (up to 64 MiB, then cancelled), so the server can write the response\n * and keep the connection usable instead of resetting it.\n */\nexport function webBodyStream(\n body: () => ReadableStream<Uint8Array> | null,\n limit: number,\n contentLength: string | undefined,\n): ReadableStream<Uint8Array> {\n if (exceedsDeclaredLength(contentLength, limit)) return failedStream(payloadTooLarge(limit))\n const source = body()\n if (source === null) return new ReadableStream<Uint8Array>({ start: controller => controller.close() })\n const reader = source.getReader()\n let size = 0\n let abandoned = false\n const abandon = (): void => {\n if (abandoned) return\n abandoned = true\n discardReader(reader)\n }\n return new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n let result: Awaited<ReturnType<typeof reader.read>>\n try {\n result = await reader.read()\n } catch (error) {\n abandoned = true\n throw new BadRequestException('Failed to read the request body', undefined, { cause: error })\n }\n if (result.done) {\n abandoned = true\n controller.close()\n return\n }\n size += result.value.byteLength\n if (size > limit) {\n abandon()\n throw payloadTooLarge(limit)\n }\n controller.enqueue(result.value)\n },\n cancel: abandon,\n },\n { highWaterMark: 0 },\n )\n}\n\n/** The part of a stream reader used to discard a body. */\ninterface BodyReader {\n read(): Promise<{ readonly done: boolean; readonly value?: Uint8Array | undefined }>\n cancel(): Promise<void>\n}\n\n/** Reads and drops the rest of a request body in the background, cancelling it past 64 MiB. */\nfunction discardReader(reader: BodyReader): void {\n let discarded = 0\n const next = (): void => {\n reader.read().then(\n result => {\n if (result.done) return\n discarded += result.value?.byteLength ?? 0\n if (discarded > MAX_DISCARD_BYTES) reader.cancel().catch(() => undefined)\n else next()\n },\n () => undefined,\n )\n }\n next()\n}\n\n/** Reads a Web request body fully, enforcing `limit` (see {@link webBodyStream}). */\nexport async function readWebStream(\n body: () => ReadableStream<Uint8Array> | null,\n limit: number,\n contentLength: string | undefined,\n): Promise<Uint8Array> {\n const reader = webBodyStream(body, limit, contentLength).getReader()\n const chunks: Uint8Array[] = []\n let size = 0\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n size += value.byteLength\n chunks.push(value)\n }\n return concat(chunks, size)\n}\n\n/** Concatenates chunks (no copy for a single chunk). */\nexport function concat(chunks: readonly Uint8Array[], size: number): Uint8Array {\n if (chunks.length === 0) return new Uint8Array(0)\n if (chunks.length === 1) return chunks[0] as Uint8Array\n const result = new Uint8Array(size)\n let offset = 0\n for (const chunk of chunks) {\n result.set(chunk, offset)\n offset += chunk.byteLength\n }\n return result\n}\n\n/** The light-my-request response of a streaming inject (`payloadAsStream: true`). */\ninterface LightStreamResponse {\n readonly statusCode: number\n readonly headers: Record<string, string | number | string[] | undefined>\n stream(): Readable\n readonly raw: { readonly res: { destroy(error?: Error): void } }\n}\n\n/** Minimal typing of `light-my-request` (optional peer dependency). */\nexport interface LightMyRequest {\n inject(dispatch: (req: never, res: never) => void, options: LightInjectOptions): PromiseLike<LightStreamResponse>\n}\n\n/** Options of a streaming light-my-request inject (also `fastify.inject()`). */\nexport interface LightInjectOptions {\n method: string\n url: string\n headers: Record<string, string>\n payload?: string | Buffer\n remoteAddress?: string\n payloadAsStream: true\n}\n\nlet lightMyRequest: Promise<LightMyRequest> | undefined\n\n/** Loads `light-my-request`, with an actionable error when it is not installed. */\nexport function loadLightMyRequest(adapter: string): Promise<LightMyRequest> {\n lightMyRequest ??= import('light-my-request').then(\n module => {\n const loaded = module as unknown as { default?: LightMyRequest } & LightMyRequest\n return loaded.default ?? loaded\n },\n (error: unknown) => {\n lightMyRequest = undefined\n throw new Error(\n `inject() with the ${adapter} adapter requires the optional peer dependency \"light-my-request\" ` +\n '(bun add -d light-my-request / npm i -D light-my-request)',\n { cause: error },\n )\n },\n )\n return lightMyRequest\n}\n\n/**\n * The light-my-request options of a normalised inject request (streaming mode). The signal is\n * handled by {@link lightStreamResponse} (light-my-request would destroy its fake request with an\n * unhandled error); an already aborted signal rejects at once, like `fetch()`.\n */\nexport async function lightInjectOptions(request: InjectStreamRequest): Promise<LightInjectOptions> {\n request.signal?.throwIfAborted()\n const normalized = await normalizeInject(request)\n return {\n method: normalized.method,\n url: normalized.url,\n headers: normalized.headers,\n remoteAddress: '127.0.0.1',\n payloadAsStream: true,\n ...(normalized.payload === undefined ? {} : { payload: toBuffer(normalized.payload) }),\n }\n}\n\n/** Runs a request through a Node.js request listener with `light-my-request`, streaming the body. */\nexport async function injectNodeStream(\n adapter: string,\n dispatch: (req: never, res: never) => void,\n request: InjectStreamRequest,\n): Promise<InjectStreamResponse> {\n const options = await lightInjectOptions(request)\n const { inject } = await loadLightMyRequest(adapter)\n return lightStreamResponse(await inject(dispatch, options), request.signal)\n}\n\n/**\n * An {@link InjectStreamResponse} of a light-my-request streaming response. Cancelling the body\n * (or aborting `signal`) destroys the server response: the server sees a client disconnect.\n */\nexport function lightStreamResponse(response: LightStreamResponse, signal?: AbortSignal): InjectStreamResponse {\n const readable = response.stream()\n const disconnect = (): void => {\n response.raw.res.destroy()\n readable.destroy()\n }\n let finished = false\n const body = new ReadableStream<Uint8Array>(\n {\n start(controller) {\n readable.on('data', (chunk: Buffer) => {\n if (finished) return\n controller.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength))\n if ((controller.desiredSize ?? 0) <= 0) readable.pause()\n })\n readable.once('end', () => {\n if (finished) return\n finished = true\n controller.close()\n })\n readable.once('error', error => {\n if (finished) return\n finished = true\n controller.error(error)\n })\n },\n pull() {\n if (readable.isPaused()) readable.resume()\n },\n cancel() {\n finished = true\n disconnect()\n },\n },\n { highWaterMark: 0 },\n )\n if (signal !== undefined) {\n if (signal.aborted) disconnect()\n else signal.addEventListener('abort', disconnect, { once: true })\n }\n return injectStreamResponse(response.statusCode, response.headers, body)\n}\n\n/** A `Buffer` view of bytes (tools such as light-my-request JSON-encode other objects). */\nexport function toBuffer(payload: string | Uint8Array): string | Buffer {\n return typeof payload === 'string' ? payload : Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)\n}\n\n/**\n * Runs a request through a Fetch handler (`(request: Request) => Promise<Response>`), streaming\n * the body. Cancelling the body (or aborting `signal`) aborts the request signal and cancels the\n * response body.\n */\nexport async function injectFetchStream(\n fetch: (request: Request) => Response | Promise<Response>,\n request: InjectStreamRequest,\n): Promise<InjectStreamResponse> {\n const signal = request.signal\n signal?.throwIfAborted()\n const normalized = await normalizeInject(request)\n const abort = new AbortController()\n signal?.addEventListener('abort', () => abort.abort(signal.reason), { once: true })\n const init: RequestInit = { method: normalized.method, headers: normalized.headers, signal: abort.signal }\n if (normalized.payload !== undefined && normalized.method !== 'GET' && normalized.method !== 'HEAD') {\n init.body = normalized.payload\n }\n const response = await fetch(new Request(`http://localhost${normalized.url}`, init))\n const headers: Record<string, string | readonly string[]> = {}\n for (const [name, value] of response.headers) if (name !== 'set-cookie') headers[name] = value\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers['set-cookie'] = cookies\n const source = response.body\n const reader = source?.getReader()\n const body = new ReadableStream<Uint8Array>(\n {\n async pull(controller) {\n if (reader === undefined) {\n controller.close()\n return\n }\n const result = await reader.read()\n if (result.done) controller.close()\n else controller.enqueue(result.value)\n },\n async cancel(reason) {\n abort.abort(reason)\n await reader?.cancel(reason).catch(() => undefined)\n },\n },\n { highWaterMark: 0 },\n )\n abort.signal.addEventListener('abort', () => reader?.cancel(abort.signal.reason).catch(() => undefined), {\n once: true,\n })\n return injectStreamResponse(response.status, headers, body)\n}\n","/** Node.js `IncomingMessage` / `ServerResponse` helpers shared by the Node and Express adapters (internal). */\nimport type { IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders, Server, ServerResponse } from 'node:http'\nimport type { Socket } from 'node:net'\nimport type { AdapterReply, AdapterRequest } from '../adapter.ts'\nimport type { HeaderValue } from '../exceptions.ts'\n\nimport { Readable } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\n\nimport { BadRequestException } from '../exceptions.ts'\nimport { discardStream, failedStream } from '../stream.ts'\nimport { concat, exceedsDeclaredLength, payloadTooLarge } from './shared.ts'\n\n/** Bytes buffered by a request body stream before the request is paused. */\nconst BODY_HIGH_WATER_MARK = 64 * 1024\n\n/** Request headers with array values (only `set-cookie` in Node.js) joined with `, `. */\nexport function normalizeNodeHeaders(headers: IncomingHttpHeaders): Record<string, string | undefined> {\n for (const name in headers) {\n if (typeof headers[name] !== 'string') return copyHeaders(headers)\n }\n return headers as Record<string, string | undefined>\n}\n\nfunction copyHeaders(headers: IncomingHttpHeaders): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {}\n for (const name in headers) {\n const value = headers[name]\n result[name] = Array.isArray(value) ? value.join(', ') : value\n }\n return result\n}\n\n/**\n * Whether the body was already read by someone else: an Express body parser (`express.json()`...)\n * marks the request with `_body`; otherwise a declared body that already ended.\n */\nfunction consumedElsewhere(request: IncomingMessage): boolean {\n if ((request as { _body?: unknown })._body === true) return true\n if (!request.readableEnded) return false\n const length = request.headers['content-length']\n return request.headers['transfer-encoding'] !== undefined || (length !== undefined && length.trim() !== '0')\n}\n\n/** The error of a body consumed before Znight read it (an empty body would be silently wrong). */\nfunction consumedError(): Error {\n return new Error(\n 'The request body was already read by a middleware (an Express body parser such as express.json()?): ' +\n 'Znight reads the bodies of its routes itself, do not register body parsers for them',\n )\n}\n\n/** Reads a Node.js request body, enforcing `limit` (on `content-length`, then while streaming). */\nexport function readNodeBody(request: IncomingMessage, limit: number): Promise<Uint8Array> {\n if (exceedsDeclaredLength(request.headers['content-length'], limit)) {\n request.resume()\n return Promise.reject(payloadTooLarge(limit))\n }\n // a read in progress (the adapters read a body once: not expected)\n const reading = (request as ReadingRequest)[BODY_READ]\n if (reading != null) return reading.promise\n if (consumedElsewhere(request)) return Promise.reject(consumedError())\n if (request.readableEnded) return Promise.resolve(new Uint8Array(0))\n if (request.destroyed) return Promise.reject(new BadRequestException('The request was aborted'))\n let resolve!: (bytes: Uint8Array) => void\n let reject!: (error: unknown) => void\n const promise = new Promise<Uint8Array>((onRead, onError) => {\n resolve = onRead\n reject = onError\n })\n ;(request as ReadingRequest)[BODY_READ] = { limit, chunks: [], size: 0, resolve, reject, promise }\n if (reading === undefined) {\n request.on('data', onBodyData)\n request.on('end', onBodyEnd)\n request.on('error', onBodyError)\n request.on('close', onBodyClose)\n }\n return promise\n}\n\n/**\n * The state of the body read by {@link readNodeBody}, on its request: `null` once it is over (the\n * listeners stay), `undefined` before.\n */\nconst BODY_READ = Symbol('znight.bodyRead')\n\ninterface BodyRead {\n readonly limit: number\n readonly chunks: Uint8Array[]\n size: number\n readonly resolve: (bytes: Uint8Array) => void\n readonly reject: (error: unknown) => void\n readonly promise: Promise<Uint8Array>\n}\n\ntype ReadingRequest = IncomingMessage & { [BODY_READ]?: BodyRead | null }\n\n// The listeners of readNodeBody: shared functions (`this` is the request), no closure per request.\n// They stay attached once the read is over (removing them costs a lot more than leaving them): they\n// then do nothing. Node.js emits `error` on a destroyed request only when it has listeners, so the\n// `error` listener left behind changes nothing either.\n\n/** Stops reading: returns the state of the read (`undefined` when it is already over). */\nfunction stopBodyRead(request: ReadingRequest): BodyRead | undefined {\n const read = request[BODY_READ]\n if (read == null) return undefined\n request[BODY_READ] = null\n return read\n}\n\nfunction onBodyData(this: ReadingRequest, chunk: Uint8Array | string): void {\n const read = this[BODY_READ]\n if (read == null) return\n const bytes = typeof chunk === 'string' ? Buffer.from(chunk) : chunk\n read.size += bytes.byteLength\n if (read.size > read.limit) {\n stopBodyRead(this)\n this.resume() // discard the rest; the 413 response closes the connection\n read.reject(payloadTooLarge(read.limit))\n return\n }\n read.chunks.push(bytes)\n}\n\nfunction onBodyEnd(this: ReadingRequest): void {\n const read = stopBodyRead(this)\n read?.resolve(concat(read.chunks, read.size))\n}\n\nfunction onBodyError(this: ReadingRequest, error: Error): void {\n stopBodyRead(this)?.reject(new BadRequestException('Failed to read the request body', undefined, { cause: error }))\n}\n\nfunction onBodyClose(this: ReadingRequest): void {\n if (this.complete) return\n stopBodyRead(this)?.reject(new BadRequestException('The request was aborted'))\n}\n\n/**\n * A Node.js request body as a Web stream (see `AdapterRequest.streamBody`): the request is paused\n * while the consumer does not read (backpressure); past `limit` bytes the stream errors with 413 and\n * the rest of the body is discarded (`request.resume()`), like when the consumer cancels the stream,\n * so the response can still be written (it carries `connection: close`).\n */\nexport function nodeBodyStream(request: IncomingMessage, limit: number): ReadableStream<Uint8Array> {\n if (exceedsDeclaredLength(request.headers['content-length'], limit)) {\n request.resume()\n return failedStream(payloadTooLarge(limit))\n }\n if (consumedElsewhere(request)) return failedStream(consumedError())\n if (request.readableEnded) return new ReadableStream<Uint8Array>({ start: controller => controller.close() })\n if (request.destroyed) return failedStream(new BadRequestException('The request was aborted'))\n let size = 0\n let cleanup = (): void => undefined\n return new ReadableStream<Uint8Array>(\n {\n start(controller) {\n const onData = (chunk: Uint8Array | string): void => {\n const bytes = typeof chunk === 'string' ? Buffer.from(chunk) : chunk\n size += bytes.byteLength\n if (size > limit) {\n cleanup()\n request.resume() // discard the rest; the 413 response closes the connection\n controller.error(payloadTooLarge(limit))\n return\n }\n controller.enqueue(bytes)\n if ((controller.desiredSize ?? 0) <= 0) request.pause()\n }\n const onEnd = (): void => {\n cleanup()\n controller.close()\n }\n const onError = (error: Error): void => {\n cleanup()\n controller.error(new BadRequestException('Failed to read the request body', undefined, { cause: error }))\n }\n const onClose = (): void => {\n if (request.complete) return\n cleanup()\n controller.error(new BadRequestException('The request was aborted'))\n }\n cleanup = (): void => {\n request.off('data', onData)\n request.off('end', onEnd)\n request.off('error', onError)\n request.off('close', onClose)\n }\n request.on('data', onData)\n request.on('end', onEnd)\n request.on('error', onError)\n request.on('close', onClose)\n },\n pull() {\n if (request.isPaused()) request.resume()\n },\n cancel() {\n cleanup()\n request.resume() // discard the rest of the body\n },\n },\n { highWaterMark: BODY_HIGH_WATER_MARK, size: (chunk: Uint8Array | undefined) => chunk?.byteLength ?? 0 },\n )\n}\n\n/** Options of {@link nodeAdapterRequest}. */\nexport interface NodeRequestOptions {\n /** Request target (default: `request.url`). */\n readonly url?: string\n /** `@Req()` value (default: the `IncomingMessage`). */\n readonly raw?: unknown\n /** `@Res()` value (default: the `ServerResponse`). */\n readonly rawResponse?: unknown\n readonly ip?: string | undefined\n}\n\n/** Wraps a Node.js request/response pair as an {@link AdapterRequest}. */\nexport function nodeAdapterRequest(\n request: IncomingMessage,\n response: ServerResponse,\n options: NodeRequestOptions = NO_OPTIONS,\n): AdapterRequest {\n return new NodeAdapterRequest(request, response, options)\n}\n\nconst NO_OPTIONS: NodeRequestOptions = Object.freeze({})\n\n/** A Node.js request/response pair as an {@link AdapterRequest} (a class: no closure per request). */\nclass NodeAdapterRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip: string | undefined\n readonly remoteAddress: string | undefined\n readonly encrypted: boolean\n readonly raw: unknown\n readonly rawResponse: unknown\n readonly #request: IncomingMessage\n readonly #response: ServerResponse\n #body: Promise<Uint8Array> | undefined\n\n constructor(request: IncomingMessage, response: ServerResponse, options: NodeRequestOptions) {\n const remoteAddress = request.socket?.remoteAddress\n this.method = request.method ?? 'GET'\n this.url = options.url ?? request.url ?? '/'\n this.headers = normalizeNodeHeaders(request.headers)\n this.ip = options.ip ?? remoteAddress\n this.remoteAddress = remoteAddress\n this.encrypted = isEncrypted(request)\n this.raw = options.raw ?? request\n this.rawResponse = options.rawResponse ?? response\n this.#request = request\n this.#response = response\n }\n\n readBody(limit: number): Promise<Uint8Array> {\n this.#body ??= readNodeBody(this.#request, limit)\n return this.#body\n }\n\n streamBody(limit: number): ReadableStream<Uint8Array> {\n return nodeBodyStream(this.#request, limit)\n }\n\n rawStatus(): number {\n return this.#response.statusCode\n }\n\n onAbort(listener: () => void): void {\n onResponseAbort(this.#response, listener)\n }\n}\n\n/**\n * Calls `listener` once when `response` closes before it was fully written (the client left): on\n * the next microtask when it is already destroyed, never after a complete response.\n */\nexport function onResponseAbort(response: ServerResponse, listener: () => void): void {\n if (response.writableFinished) return\n if (response.destroyed) {\n queueMicrotask(listener)\n return\n }\n response.once('close', () => {\n if (!response.writableFinished) listener()\n })\n}\n\n/** Whether the request came over TLS (`node:https`, `node:http2` secure servers). */\nexport function isEncrypted(request: IncomingMessage): boolean {\n return (request.socket as { readonly encrypted?: unknown } | undefined)?.encrypted === true\n}\n\n/**\n * Writes a reply to a `ServerResponse`, piping a stream body (a failing stream destroys the\n * response). Never throws.\n */\nexport function writeNodeReply(response: ServerResponse, reply: AdapterReply): void {\n if (reply.raw === true) {\n discardStream(reply.body instanceof ReadableStream ? reply.body : null)\n return\n }\n if (response.headersSent || response.destroyed) {\n discardStream(reply.body instanceof ReadableStream ? reply.body : null)\n if (!response.writableEnded && !response.destroyed) response.end()\n return\n }\n try {\n // one call (merged over headers set earlier with setHeader(), e.g. by Express middleware); the\n // cookies set earlier are kept before the reply's own (writeHead would replace them)\n const headers =\n reply.headers['set-cookie'] === undefined\n ? reply.headers\n : withNativeCookies(response.getHeader('set-cookie'), reply.headers)\n response.writeHead(reply.status, headers as OutgoingHttpHeaders)\n } catch {\n // invalid header name or value set by user code\n discardStream(reply.body instanceof ReadableStream ? reply.body : null)\n if (!response.headersSent) {\n for (const name of response.getHeaderNames()) response.removeHeader(name)\n response.statusCode = 500\n response.setHeader('content-type', 'application/json; charset=utf-8')\n response.end('{\"statusCode\":500,\"error\":\"Internal Server Error\"}')\n }\n return\n }\n const body = reply.body\n if (body === null) {\n response.end()\n return\n }\n // an event stream may stay quiet longer than a socket timeout (`server.timeout`, Bun's emulation)\n if (reply.eventStream === true && (response as { isLightMyRequest?: boolean }).isLightMyRequest !== true) {\n response.setTimeout(0)\n }\n if (body instanceof Uint8Array) {\n // a string is written with the headers at once (bytes take a second write)\n response.end(reply.text ?? body)\n return\n }\n const fail = (): void => {\n if (!response.destroyed) response.destroy()\n }\n try {\n const stream = body instanceof Blob ? body.stream() : body\n pipeline(Readable.fromWeb(stream as import('node:stream/web').ReadableStream), response).catch(fail)\n } catch {\n fail()\n }\n}\n\n/**\n * `headers` with the `set-cookie` lines already set on the native response (Express middleware\n * `res.cookie()`, Fastify hooks `reply.header('set-cookie', ...)`) before its own: `headers`\n * unchanged when either side has none.\n */\nexport function withNativeCookies(\n native: number | string | readonly string[] | undefined,\n headers: Readonly<Record<string, HeaderValue>>,\n): Readonly<Record<string, HeaderValue>> {\n const own = headers['set-cookie']\n if (own === undefined || native === undefined || typeof native === 'number') return headers\n const before = typeof native === 'string' ? [native] : native\n if (before.length === 0) return headers\n return { ...headers, 'set-cookie': [...before, ...(typeof own === 'string' ? [own] : own)] }\n}\n\n/** Last-resort 500 when a handler promise rejected (should not happen: the pipeline maps errors). */\nexport function writeNodeFailure(response: ServerResponse): void {\n if (response.headersSent) {\n if (!response.writableEnded) response.destroy()\n return\n }\n response.statusCode = 500\n response.setHeader('content-type', 'application/json; charset=utf-8')\n response.end('{\"statusCode\":500,\"error\":\"Internal Server Error\"}')\n}\n\n/** The tracker of a socket (see {@link ConnectionTracker}). */\nconst TRACKER = Symbol('znight.tracker')\n/** The number of requests in progress on a tracked socket. */\nconst ACTIVE = Symbol('znight.active')\n\ninterface TrackedSocket extends Socket {\n [TRACKER]?: ConnectionTracker\n [ACTIVE]?: number\n}\n\n/**\n * Tracks the connections of a `node:http` server to close them on shutdown: idle keep-alive\n * connections first (graceful), every connection when forced. `server.closeIdleConnections()` /\n * `closeAllConnections()` are not reliable on every runtime (Bun), so sockets are tracked here. The\n * count of requests in progress lives on the socket, and one shared `close` listener per response\n * decrements it (no closure, no map lookup per request).\n */\nexport class ConnectionTracker {\n readonly #sockets = new Set<TrackedSocket>()\n #closing = false\n\n /**\n * `requests: false` when the caller's own `request` listener calls {@link track} for every request\n * of the server (one listener less to call per request).\n */\n constructor(server: Server, options: { readonly requests?: boolean } = {}) {\n server.on('connection', (socket: TrackedSocket) => {\n socket[TRACKER] = this\n socket[ACTIVE] = 0\n this.#sockets.add(socket)\n socket.once('close', () => this.#sockets.delete(socket))\n })\n if (options.requests !== false) {\n server.on('request', (request: IncomingMessage, response: ServerResponse) => this.track(request, response))\n }\n }\n\n /** Counts a request in progress on its connection, until its response closes (other servers' requests are ignored). */\n track(request: IncomingMessage, response: ServerResponse): void {\n const socket = request.socket as TrackedSocket | null\n if (socket?.[TRACKER] !== this) return\n socket[ACTIVE] = (socket[ACTIVE] ?? 0) + 1\n response.on('close', ConnectionTracker.#onResponseClose)\n }\n\n /** A response closed (`this`): one request less on its socket, ended when idle while closing. */\n static readonly #onResponseClose = function (this: ServerResponse): void {\n // the socket of a finished response is detached: reach it through its request\n const socket = (this.req as IncomingMessage | undefined)?.socket as TrackedSocket | null | undefined\n const tracker = socket?.[TRACKER]\n if (socket == null || tracker === undefined) return\n const active = (socket[ACTIVE] ?? 1) - 1\n socket[ACTIVE] = active\n if (active === 0 && tracker.#closing) socket.end()\n }\n\n /** Ends idle connections now and the others once their requests completed. */\n closeIdle(): void {\n this.#closing = true\n for (const socket of this.#sockets) if (socket[ACTIVE] === 0) socket.end()\n }\n\n /** Destroys every connection. */\n destroyAll(): void {\n this.#closing = true\n for (const socket of this.#sockets) socket.destroy()\n }\n}\n\n/**\n * Marks a socket taken over by a WebSocket transport (RFC 0003) as busy: a graceful close of the\n * server leaves it to its transport, which closes it with a close frame; a forced close destroys it.\n */\nexport function markUpgraded(socket: object): void {\n ;(socket as TrackedSocket)[ACTIVE] = 1\n}\n\n/** Closes a `node:http` server: graceful (idle connections ended), then forced when asked. */\nexport function closeServer(\n server: Server,\n tracker: ConnectionTracker,\n closing: Promise<void> | undefined,\n force: boolean,\n): Promise<void> {\n const promise =\n closing ??\n new Promise<void>(resolve => {\n if (!server.listening) {\n resolve()\n return\n }\n server.close(() => resolve())\n server.closeIdleConnections?.()\n tracker.closeIdle()\n })\n if (force) {\n server.closeAllConnections?.()\n tracker.destroyAll()\n }\n return promise\n}\n","/**\n * Marker decorators of `@znight/http`. Like every Znight decorator they do nothing at runtime: the\n * compiler extension `@znight/http/compiler` reads them from the source code and generates the\n * routes (`metadata.extensions.http`). Arguments marked _static_ must be statically evaluable\n * (literals, `const` references); _value_ arguments (schemas, guards...) may also be references to\n * exported bindings. See docs/internals/architecture.md §4.6 and §5.\n */\nimport type { ClassMarker, MethodMarker, ParameterMarker, Scope } from '@znight/core'\nimport type { HttpContext } from './context.ts'\nimport type { GuardClass, HttpInterceptorClass } from './interfaces.ts'\nimport type { ByteSize } from './size.ts'\nimport type { SseOptions } from './sse.ts'\nimport type { StandardSchemaV1 } from './standard-schema.ts'\nimport type { UploadedFileOptions, UploadedFilesOptions } from './uploads.ts'\n\nfunction marker(): void {\n // intentionally empty: decorators are compile-time markers\n}\n\nconst classMarker: ClassMarker = marker\nconst methodMarker: MethodMarker = marker\nconst parameterMarker: ParameterMarker = marker\nconst classOrMethodMarker: ClassMarker & MethodMarker = marker\n\n/** Options of {@link Controller} (static). */\nexport interface ControllerOptions {\n /** Base path of every route of the controller (`/users`). Default: `/`. */\n readonly path?: string\n /** Provider scope. Default: `singleton`; `request` creates one controller per request. */\n readonly scope?: Scope\n}\n\n/**\n * Declares a controller: a provider (singleton by default) whose decorated methods are routes.\n *\n * ```ts\n * @Controller('/users')\n * export class UserController {\n * constructor(private readonly users: UserService) {}\n *\n * @Get('/:id')\n * find(@Param('id') id: number) {\n * return this.users.findById(id)\n * }\n * }\n * ```\n *\n * @param pathOrOptions static: base path, or `{ path?, scope? }`.\n */\nexport function Controller(_pathOrOptions?: string | ControllerOptions): ClassMarker {\n return classMarker\n}\n\n/** `GET` route. `path` (static) is relative to the controller path; default: the controller path. */\nexport function Get(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `POST` route (default status 201). */\nexport function Post(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PUT` route. */\nexport function Put(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `PATCH` route. */\nexport function Patch(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `DELETE` route. */\nexport function Delete(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `HEAD` route (`GET` routes already answer `HEAD` requests). */\nexport function Head(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** `OPTIONS` route (paths without one answer `OPTIONS` with `204` and an `allow` header). */\nexport function Options(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/** Route for GET, HEAD, POST, PUT, PATCH, DELETE and OPTIONS (methods without a dedicated route on the same path). */\nexport function All(_path?: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * A `GET` route serving an event stream (Server-Sent Events). The handler returns an\n * `AsyncIterable`, an `Iterable` or a `ReadableStream` of `SseEvent` (`{ data, event, id, retry,\n * comment }`), or an `HttpResponse` / exception for other outcomes (204 stops `EventSource`). The\n * plugin frames the events, sends heartbeats, stops the source when the client leaves (`ctx.signal`)\n * and closes the stream gracefully on shutdown.\n *\n * ```ts\n * @Sse('/:id/events', { retry: 5_000 })\n * async events(@Param('id') id: string, @Ctx() ctx: HttpContext): Promise<AsyncIterable<SseEvent<OrderEvent>>> {\n * if ((await this.orders.find(id)) === undefined) throw new NotFoundException() // pre-flight checks first\n * return this.hub.subscribe(id, { signal: ctx.signal })\n * }\n * ```\n *\n * Prefer an `async` method returning the source over an `async *` generator: the body of a\n * generator only runs once the 200 and the headers are sent.\n *\n * @param path static: route path (relative to the controller path).\n * @param options static: `{ heartbeat?, retry?, maxDuration? }` (see `SseOptions`).\n */\nexport function Sse(path?: string, options?: SseOptions): MethodMarker\nexport function Sse(options: SseOptions): MethodMarker\nexport function Sse(_pathOrOptions?: string | SseOptions, _options?: SseOptions): MethodMarker {\n return methodMarker\n}\n\n/**\n * Injects a route parameter, coerced to the parameter type (`string`, `number`, `boolean`,\n * `bigint`, `Date`, literal unions) or validated with `schema`. Without arguments: every parameter\n * (`Record<string, string>`).\n *\n * ```ts\n * @Get('/:id')\n * find(@Param('id') id: number) {}\n * ```\n *\n * @param name static: name of a `:param` of the route path.\n * @param schema value: a Standard Schema validating the raw string (its output is injected).\n */\nexport function Param(): ParameterMarker\nexport function Param(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Param(schema: StandardSchemaV1): ParameterMarker\nexport function Param(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a query parameter (coerced to the parameter type; `T[]` accepts repeated and single\n * values; optional when the parameter is optional or has a default) or, without name, the whole\n * query (`Record<string, string | string[]>`), typically validated with a schema.\n *\n * ```ts\n * list(@Query('page') page = 1, @Query('tag') tags: string[] = []) {}\n * search(@Query(SearchQuery) query: SearchQuery) {}\n * ```\n *\n * @param name static: query key.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Query(): ParameterMarker\nexport function Query(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Query(schema: StandardSchemaV1): ParameterMarker\nexport function Query(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request cookie (decoded, coerced to the parameter type like `@Headers`: `string`,\n * `number`, `boolean`, `bigint`, `Date`, literal unions, enums, branded primitives) or validated\n * with `schema`; without name, every cookie (`Record<string, string>`). An absent cookie answers 400\n * `Missing cookie \"name\"` unless the parameter is optional. Error messages never echo the value.\n *\n * ```ts\n * // a stale or forged value falls back instead of answering 400 until the cookie expires\n * export const Theme = z.enum(['light', 'dark']).catch('light')\n *\n * read(@Cookie('theme', Theme) theme: 'light' | 'dark', @Cookie('visits') visits = 0) {}\n * ```\n *\n * @param name static: cookie name (an RFC 9110 token).\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function Cookie(): ParameterMarker\nexport function Cookie(name: string, schema?: StandardSchemaV1): ParameterMarker\nexport function Cookie(schema: StandardSchemaV1): ParameterMarker\nexport function Cookie(_nameOrSchema?: string | StandardSchemaV1, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the **verified** value of a signed cookie (set with `{ signed: true }`, plugin option\n * `cookies.secrets`): absent, tampered or signed with a retired key, the cookie does not exist\n * (400 `Missing cookie \"name\"` unless the parameter is optional). Same coercion and schema rules as\n * {@link Cookie}. A route reading a signed cookie fails the boot when `cookies.secrets` is not set.\n *\n * @param name static: cookie name.\n * @param schema value: a Standard Schema (its output is injected).\n */\nexport function SignedCookie(_name: string, _schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the parsed request body, validated with `schema` when given (the schema output is\n * injected: defaults, transforms, stripped keys). A non-primitive body without schema is reported\n * by the compiler (ZNIGHT017).\n *\n * @param schema value: a Standard Schema (Zod, Valibot, ArkType...).\n */\nexport function Body(_schema?: StandardSchemaV1): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a request header (case-insensitive `name`, coerced to the parameter type) or, without\n * name, every header (`Record<string, string | undefined>`).\n *\n * @param name static: header name.\n */\nexport function Headers(_name?: string): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects a file of a `multipart/form-data` body as a standard `File` (`name`, `type`, `size`,\n * `arrayBuffer()`, `text()`, `stream()`), held in memory. The route parses multipart bodies before\n * its interceptors, enforcing the options while the body is read: a file above `maxSize` answers\n * 413, a refused type 415, a second file in the field or a file in an undeclared field 400, a\n * missing required file 400, a non-multipart body 415. `@Body()` receives the text fields.\n *\n * ```ts\n * @Post('/avatar')\n * upload(@UploadedFile('avatar', { maxSize: '2mb', mimeTypes: ['image/png', 'image/jpeg'] }) avatar: File) {}\n *\n * @Post('/attachment')\n * attach(@UploadedFile('file') file?: File) {} // optional: undefined when absent\n * ```\n *\n * `File.name` and `File.type` are sent by the client: never trust them (see the README, \"Files\").\n *\n * @param field static: the multipart field; omitted: the single file of the body, whatever its field.\n * @param options static: `{ required?, maxSize?, mimeTypes? }`.\n */\nexport function UploadedFile(field?: string, options?: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(options: UploadedFileOptions): ParameterMarker\nexport function UploadedFile(\n _fieldOrOptions?: string | UploadedFileOptions,\n _options?: UploadedFileOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the files of a multipart field (`File[]`, in body order), or of every field without\n * `field`. Same rules as {@link UploadedFile}; above `maxFiles` files the request answers 413. An\n * optional parameter (`files?: File[]`, `required: false`) receives an empty array when no file is\n * sent.\n *\n * ```ts\n * @Post('/documents')\n * add(@UploadedFiles('documents', { maxFiles: 5, maxSize: '20mb', mimeTypes: ['application/pdf'] }) documents: File[]) {}\n * ```\n *\n * @param field static: the multipart field; omitted: the files of every field.\n * @param options static: `{ required?, maxSize?, maxFiles?, mimeTypes? }`.\n */\nexport function UploadedFiles(field?: string, options?: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(options: UploadedFilesOptions): ParameterMarker\nexport function UploadedFiles(\n _fieldOrOptions?: string | UploadedFilesOptions,\n _options?: UploadedFilesOptions,\n): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the maximum request body size of a route, or of every route of a controller (the route wins),\n * over the plugin `bodyLimit` (and over the limit computed for upload routes). `Infinity` disables\n * the limit, e.g. for a route streaming its body with `ctx.bodyStream()`.\n *\n * ```ts\n * @Put('/files/:name')\n * @BodyLimit('5gb')\n * async store(@Param('name') name: string, @Ctx() ctx: HttpContext) {\n * await pipeline(Readable.fromWeb(ctx.bodyStream()), createWriteStream(join(DIR, safeName(name))))\n * }\n * ```\n *\n * @param size static: bytes (`10_485_760`) or a size with a unit (`'10mb'`, `'512kb'`; `kb` = 1024 bytes).\n */\nexport function BodyLimit(_size: ByteSize): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/** Injects the native request of the adapter (escape hatch). */\nexport function Req(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Injects the native response of the adapter (escape hatch; the compiler warns). The handler then\n * writes the response itself, and must have finished when its promise settles.\n */\nexport function Res(): ParameterMarker {\n return parameterMarker\n}\n\n/** Injects the {@link HttpContext} of the request. */\nexport function Ctx(): ParameterMarker {\n return parameterMarker\n}\n\n/**\n * Sets the status of successful responses (wins over `HttpResponse.status` and the defaults).\n *\n * @param status static: an integer between 100 and 599.\n */\nexport function HttpCode(_status: number): MethodMarker {\n return methodMarker\n}\n\n/**\n * Adds a header to successful responses. Repeat the decorator for several headers.\n *\n * @param name static: header name.\n * @param value static: header value.\n */\nexport function Header(_name: string, _value: string): MethodMarker {\n return methodMarker\n}\n\n/**\n * Protects a controller (every route) or a route with guards (providers implementing\n * {@link CanActivate}). Order: global guards → controller guards → route guards, each list in\n * declaration order.\n *\n * @param guards value: guard classes.\n */\nexport function UseGuard(..._guards: [GuardClass, ...GuardClass[]]): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Wraps a controller (every route) or a route with interceptors (providers implementing\n * {@link HttpInterceptor}). Order: global → controller → route, the first one being the outermost.\n *\n * @param interceptors value: interceptor classes.\n */\nexport function UseInterceptor(\n ..._interceptors: [HttpInterceptorClass, ...HttpInterceptorClass[]]\n): ClassMarker & MethodMarker {\n return classOrMethodMarker\n}\n\n/**\n * Validates the request body with `schema`: sugar for `@Body(schema)` on the body parameter (using\n * both is ZNIGHT005).\n *\n * @param schema value: a Standard Schema.\n */\nexport function Validate(_schema: StandardSchemaV1): MethodMarker {\n return methodMarker\n}\n\n/** Arguments of a route decorator: optional when `T` accepts `undefined` or is `true` (flag decorators). */\nexport type RouteDecoratorArgs<T> = [T] extends [true] ? [value?: T] : undefined extends T ? [value?: T] : [value: T]\n\n/** Options of {@link createRouteDecorator} (static). */\nexport interface RouteDecoratorOptions {\n /**\n * Decision group. Decorators of a group are alternatives: one per controller or route, and the\n * route's decision replaces the controller's. Default: the key (the decorator is its own group).\n * A letter followed by letters, digits, `_`, `.` or `-`.\n */\n readonly group?: string\n /**\n * Every route must carry a decision of the group: ZNIGHT023 at build time when a route has none,\n * and at boot when no guard of its chain enforces it (see {@link GuardClass}). All the decorators\n * of a group must agree. Default `false`.\n */\n readonly required?: boolean\n}\n\n/** The data part of a route decorator: what guards list in `static enforces`. */\nexport interface RouteDecoratorInfo {\n /** Key of the value in `route.meta`. */\n readonly key: string\n /** Decision group (`options.group ?? key`). */\n readonly group: string\n /** Every route must carry a decision of the group. */\n readonly required: boolean\n}\n\n/**\n * A route metadata entry given as data rather than as a decorator: the `meta` of plugin routes\n * (`[Public.meta()]`). Built by {@link RouteDecorator.meta}.\n */\nexport interface RouteMetaEntry<T = unknown> {\n readonly key: string\n readonly value: T\n /** Decision group. Default: the key. */\n readonly group?: string\n /** Default `false`. */\n readonly required?: boolean\n}\n\n/**\n * Anything that carries effective route metadata: the {@link HttpContext} of a request, and the\n * contexts of other transports that reuse route decorators (a GraphQL resolver context, a WebSocket\n * gateway context). {@link RouteDecorator.get} reads `route.meta[key]`; nothing else is required.\n *\n * ```ts\n * const carrier: RouteMetaCarrier = { route: { meta: { roles: ['admin'] } } }\n * Roles.get(carrier) // ['admin']\n * ```\n */\nexport interface RouteMetaCarrier {\n /** The matched route (or field, or handler), `undefined` when there is none. */\n readonly route?: { readonly meta: Readonly<Record<string, unknown>> } | undefined\n}\n\n/** A user-defined route metadata decorator created with {@link createRouteDecorator}. */\nexport interface RouteDecorator<T> extends RouteDecoratorInfo {\n (...args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker\n /**\n * The value of the current route, if set. Reads the effective metadata: the route's decision of\n * a group wins over the controller's. Accepts any {@link RouteMetaCarrier}: an\n * {@link HttpContext}, or the context of another transport exposing `route.meta`.\n */\n get(ctx: RouteMetaCarrier): T | undefined\n /**\n * The same metadata as data (`{ key, value, group, required }`), for routes that are not compiled\n * controllers (plugin routes: `OpenApiPlugin.configure({ meta: [Public.meta()] })`). The value is\n * `true` when omitted, like `@Public()`.\n */\n meta(...args: RouteDecoratorArgs<T>): RouteMetaEntry<T>\n}\n\n/**\n * Grammar of an explicit decision group name (internal; the compiler extension has the same rule).\n * A decorator without `group` is its own group, named after its key: any non-empty key is valid.\n */\nexport const GROUP_NAME: RegExp = /^[A-Za-z][\\w.-]*$/\n\n/** `true` when `group` is a valid group of `key`: the key itself (the default) or a valid name. */\nexport function isGroupOf(group: unknown, key: string): group is string {\n return typeof group === 'string' && (group === key || GROUP_NAME.test(group))\n}\n\n/**\n * Creates a metadata decorator for controllers and routes. The compiler stores its argument\n * (`value`, statically evaluated or an exported reference; `true` when omitted) in\n * `meta[key]`, read by guards and interceptors through `ctx.route.meta` or `decorator.get(ctx)`.\n *\n * ```ts\n * export const Public = createRouteDecorator('public', { group: 'access', required: true })\n * export const Authenticated = createRouteDecorator('authenticated', { group: 'access', required: true })\n * export const Roles = createRouteDecorator<readonly string[]>('roles', { group: 'access', required: true })\n *\n * @Controller('/books')\n * @Roles(['reader']) // the decision of every route of the controller...\n * export class BookController {\n * @Get('/:id/cover')\n * @Public() // ...unless the route has its own decision of the group\n * cover() {}\n * }\n *\n * // in a guard\n * if (Public.get(ctx)) return true\n * const roles = Roles.get(ctx) ?? []\n * ```\n *\n * Decorators of one `group` are alternatives: two of them on the same class or method are\n * ZNIGHT005, and the route's decision replaces the controller's (without `group`, each decorator is\n * its own group: the route value wins over the controller value). With `required: true`, a route\n * without decision fails the build (ZNIGHT023).\n *\n * @param key static: unique metadata key.\n * @param options static: `{ group?, required? }`.\n */\nexport function createRouteDecorator<T = true>(key: string, options?: RouteDecoratorOptions): RouteDecorator<T> {\n if (typeof key !== 'string' || key === '') {\n throw new TypeError(`createRouteDecorator(): the key must be a non-empty string (received ${String(key)})`)\n }\n if (options !== undefined && (options === null || typeof options !== 'object')) {\n throw new TypeError(`createRouteDecorator('${key}'): options must be an object { group?, required? }`)\n }\n // the grammar applies to an explicit group only: without one, any key is its own group (as before groups)\n const group = options?.group ?? key\n if (!isGroupOf(group, key)) {\n throw new TypeError(\n `createRouteDecorator('${key}'): \"group\" must be a name made of letters, digits, _ . - starting with a letter (received ${String(group)})`,\n )\n }\n const required = options?.required ?? false\n if (typeof required !== 'boolean') {\n throw new TypeError(`createRouteDecorator('${key}'): \"required\" must be a boolean (received ${String(required)})`)\n }\n const decorator = (..._args: RouteDecoratorArgs<T>): ClassMarker & MethodMarker => classOrMethodMarker\n return Object.assign(decorator, {\n key,\n group,\n required,\n get: (ctx: RouteMetaCarrier): T | undefined => ctx.route?.meta[key] as T | undefined,\n meta: (...args: RouteDecoratorArgs<T>): RouteMetaEntry<T> =>\n Object.freeze({ key, value: (args.length === 0 ? true : args[0]) as T, group, required }),\n })\n}\n","/**\n * Upgrade routes (RFC 0003 §8.2): WebSocket handshakes served by `HttpPlugin` on behalf of another\n * plugin (`@znight/websocket`). The handshake is an HTTP request: it runs through the pipeline\n * (`http:request` hook, request scope, global guards, the route's guards, exception mappers), then\n * the plugin's `accept` takes the connection. The request scope stays open until the connection\n * closes.\n *\n * Upgrade routes live in their own route table, consulted only for upgrade requests: they never\n * change the ordinary routing, and a page and its socket may share a path.\n */\nimport type { Token } from '@znight/core'\nimport type { AdapterReply, AdapterRequest } from './adapter.ts'\nimport type { HttpContext } from './context.ts'\nimport type { RouteMetaEntry } from './decorators.ts'\nimport type { HeaderValue } from './exceptions.ts'\nimport type { GuardRef } from './plugin.ts'\nimport type { NormalizedMetaEntry, PluginHttpRoutesContext } from './plugin-routes.ts'\n\nimport { ErrorCode, ZnightError } from '@znight/core'\n\nimport { isGroupOf } from './decorators.ts'\nimport { BadRequestException, HttpException } from './exceptions.ts'\nimport { joinPaths, normalizePath, parseRoutePath, type RoutePath, RoutePathError } from './path.ts'\n\n/**\n * The upgrade of a `node:http` server (`'upgrade'` event): every adapter built on `node:http`\n * (`node`, `express`, `fastify`, `hono` on Node.js), on Node.js and on Bun.\n */\nexport interface NodeUpgrade {\n readonly kind: 'node'\n /** The `IncomingMessage` of the handshake. */\n readonly request: unknown\n /** The `net.Socket` (a `Duplex`) of the connection. */\n readonly socket: unknown\n /** The first bytes after the handshake headers. */\n readonly head: Uint8Array\n}\n\n/** The upgrade of a `Bun.serve()` server (`honoAdapter()` on Bun). */\nexport interface BunUpgrade {\n readonly kind: 'bun'\n /** The Fetch `Request` of the handshake. */\n readonly request: Request\n /** The `Bun.serve()` server (`server.upgrade(request, { data, headers })`). */\n readonly server: unknown\n}\n\n/** An in-memory upgrade (`HttpPlugin.upgradeInMemory()`, tests): `peer` belongs to the caller. */\nexport interface MemoryUpgrade {\n readonly kind: 'memory'\n readonly peer: unknown\n}\n\n/** The native side of an upgrade request, completed by a transport. */\nexport type NativeUpgrade = NodeUpgrade | BunUpgrade | MemoryUpgrade\n\n/** What {@link PluginUpgradeRoute.accept} receives to complete the handshake. */\nexport interface PendingUpgrade {\n readonly native: NativeUpgrade\n /**\n * Headers of the `101` response: the headers and cookies the guards set on the context, the\n * request id and the security headers are not included (they are HTTP response headers); read\n * once, when the transport completes the handshake.\n */\n readonly headers: Readonly<Record<string, HeaderValue>>\n /**\n * The handshake timed out and was answered `408`: the transport must not complete it. Check it\n * after every `await`, right before completing the handshake.\n */\n readonly expired: boolean\n /**\n * Keeps the request scope (and the in-flight count of `HttpPlugin`) open until `closed`\n * settles: the connection lives in the scope of its handshake. Call it once, after the transport\n * completed the handshake.\n */\n hold(closed: Promise<unknown>): void\n}\n\n/**\n * A route answering upgrade requests (`GET` with `upgrade: websocket`), declared by another plugin\n * through {@link PluginHttpUpgrades.httpUpgrades}.\n */\nexport interface PluginUpgradeRoute {\n /** Path relative to the `HttpPlugin` prefix, with the route grammar (`/chat`, `/docs/:docId`). */\n readonly path: string\n /** Name of the route (the gateway), shown in `HttpPlugin.routes`, logs and errors. */\n readonly name: string\n /** `ctx.route.controller` during the handshake (the gateway token). Default: the plugin name. */\n readonly owner?: Token\n /** Route metadata (`ctx.route.meta`), one entry per group, checked at boot like plugin routes. */\n readonly meta?: readonly RouteMetaEntry[]\n /** Guards of the handshake (classes, instances or provider tokens), after the global guards. */\n readonly guards?: readonly (GuardRef | Token)[]\n /** Time the handshake gets before it is answered `408` (ms). Default: none. */\n readonly timeoutMs?: number\n /**\n * Cheap checks before the guards (origin, subprotocols, capacity), after the protocol checks of\n * RFC 6455. Throw an `HttpException` to refuse.\n */\n precheck?(ctx: HttpContext): void | Promise<void>\n /** After the guards: take the connection. Throw an `HttpException` to refuse. */\n accept(ctx: HttpContext, upgrade: PendingUpgrade): void | Promise<void>\n}\n\n/** What {@link PluginHttpUpgrades.httpUpgrades} returns. */\nexport interface PluginUpgrades {\n readonly routes: readonly PluginUpgradeRoute[]\n /**\n * Server-wide settings of the `websocket` option of `Bun.serve()` (`maxPayloadLength`,\n * `idleTimeout`, `backpressureLimit`, `sendPings`, `perMessageDeflate`...), used by adapters\n * serving with `Bun.serve()`. The handlers are set by `HttpPlugin`: they dispatch every event to\n * the `data` given to `server.upgrade()`, a {@link BunSocketHandlers}.\n */\n readonly bunWebSocket?: Readonly<Record<string, unknown>>\n}\n\n/** What {@link PluginHttpUpgrades.httpUpgrades} receives. */\nexport interface PluginHttpUpgradesContext extends PluginHttpRoutesContext {\n /** Name of the adapter (`node`, `fastify`...). */\n readonly adapter: string\n /**\n * The native upgrades the adapter produces (`node`: a `node:http` server, `bun`: `Bun.serve()`),\n * `undefined` when the adapter cannot upgrade connections.\n */\n readonly upgrades: 'node' | 'bun' | undefined\n}\n\n/**\n * Implemented, next to {@link PluginHttpRoutes}, by a plugin that accepts WebSocket connections\n * (`@znight/websocket`). `HttpPlugin` calls `httpUpgrades()` once in its `onBootstrap`, after\n * `httpRoutes()`, whatever the plugin order, and asks its adapter to route the matching upgrade\n * requests to the pipeline. `onHttpDrain()` is where the plugin closes its connections.\n */\nexport interface PluginHttpUpgrades {\n httpUpgrades(context: PluginHttpUpgradesContext): PluginUpgrades\n}\n\n/**\n * The `data` a transport gives to `server.upgrade()` on `Bun.serve()`: `HttpPlugin` dispatches\n * every event of the socket to it.\n */\nexport interface BunSocketHandlers {\n open(ws: unknown): void\n message(ws: unknown, message: string | Uint8Array): void\n close(ws: unknown, code: number, reason: string): void\n drain(ws: unknown): void\n pong?(ws: unknown): void\n}\n\n/** What `HttpPlugin` gives to {@link AdapterUpgrades.enable}. */\nexport interface UpgradeHandlerOptions {\n /** Whether an upgrade request to the raw `path` (no query string) is for Znight. */\n match(path: string): boolean\n /**\n * Runs the handshake through the pipeline. Resolves with the refusal to write (an HTTP response),\n * or `undefined` once the transport took the connection. Never rejects.\n */\n handle(request: AdapterRequest, native: NodeUpgrade | BunUpgrade): Promise<AdapterReply | undefined>\n /** The `websocket` option of `Bun.serve()` (settings and dispatching handlers), Bun adapters only. */\n readonly bunWebSocket: Readonly<Record<string, unknown>>\n}\n\n/** The optional upgrade capability of an adapter (RFC 0003 §8.2.3). */\nexport interface AdapterUpgrades {\n /** The native upgrades the adapter produces. */\n readonly kind: 'node' | 'bun'\n /** Called once, before `listen()`, when the application has upgrade routes. */\n enable(options: UpgradeHandlerOptions): void\n}\n\n/** A validated upgrade route (internal). */\nexport interface CollectedUpgradeRoute {\n readonly plugin: string\n readonly instance: object\n readonly path: RoutePath\n readonly relativePath: string\n readonly name: string\n readonly owner: Token\n readonly meta: readonly NormalizedMetaEntry[]\n readonly guards: readonly unknown[]\n readonly timeoutMs: number | undefined\n readonly precheck: ((ctx: HttpContext) => void | Promise<void>) | undefined\n readonly accept: (ctx: HttpContext, upgrade: PendingUpgrade) => void | Promise<void>\n}\n\n/** The upgrade routes of the plugins and the merged `Bun.serve()` settings (internal). */\nexport interface CollectedUpgrades {\n readonly routes: readonly CollectedUpgradeRoute[]\n readonly bunWebSocket: Readonly<Record<string, unknown>>\n}\n\n/** Calls `httpUpgrades()` on every other plugin implementing it, in plugin order, and validates the routes. */\nexport function collectPluginUpgrades(\n plugins: readonly object[],\n self: object,\n context: PluginHttpUpgradesContext,\n): CollectedUpgrades {\n const routes: CollectedUpgradeRoute[] = []\n const bunWebSocket: Record<string, unknown> = {}\n for (const plugin of plugins) {\n if (plugin === self) continue\n const provider = plugin as Partial<PluginHttpUpgrades> & { readonly name?: unknown }\n if (typeof provider.httpUpgrades !== 'function') continue\n const name = String(provider.name)\n const result: unknown = provider.httpUpgrades(context)\n const declared = (result as Partial<PluginUpgrades> | null | undefined)?.routes\n if (!Array.isArray(declared)) {\n throw invalid(name, `httpUpgrades() must return { routes: [...] } (received ${describe(result)})`)\n }\n for (const route of declared as unknown[]) routes.push(validateRoute(plugin, name, route, context.prefix))\n const settings = (result as PluginUpgrades).bunWebSocket\n if (settings !== undefined) Object.assign(bunWebSocket, settings)\n }\n return { routes, bunWebSocket }\n}\n\nfunction validateRoute(instance: object, plugin: string, value: unknown, prefix: string): CollectedUpgradeRoute {\n if (value === null || typeof value !== 'object') throw invalid(plugin, `invalid upgrade route ${describe(value)}`)\n const route = value as Partial<PluginUpgradeRoute>\n if (typeof route.name !== 'string' || route.name === '') {\n throw invalid(plugin, `the upgrade route ${String(route.path)} needs a name`)\n }\n const where = `${String(route.path)} (${route.name})`\n if (typeof route.path !== 'string') throw invalid(plugin, `the upgrade route ${where} has no path`)\n if (typeof route.accept !== 'function') throw invalid(plugin, `the upgrade route ${where} has no accept function`)\n if (route.precheck !== undefined && typeof route.precheck !== 'function') {\n throw invalid(plugin, `the precheck of the upgrade route ${where} must be a function`)\n }\n let path: RoutePath\n try {\n path = parseRoutePath(joinPaths(prefix, route.path))\n } catch (error) {\n if (!(error instanceof RoutePathError)) throw error\n throw invalid(plugin, `invalid path of the upgrade route ${where}: ${error.issue.message}`, error)\n }\n const meta = route.meta ?? []\n if (!Array.isArray(meta)) throw invalid(plugin, `the meta of the upgrade route ${where} must be an array of entries`)\n const entries = (meta as unknown[]).map(entry => metaEntry(plugin, where, entry))\n const guards = route.guards ?? []\n if (!Array.isArray(guards)) throw invalid(plugin, `the guards of the upgrade route ${where} must be an array`)\n const timeoutMs = route.timeoutMs\n if (timeoutMs !== undefined && !(typeof timeoutMs === 'number' && timeoutMs > 0)) {\n throw invalid(plugin, `invalid timeoutMs ${describe(timeoutMs)} of the upgrade route ${where}`)\n }\n return {\n plugin,\n instance,\n path,\n relativePath: normalizePath(route.path),\n name: route.name,\n owner: route.owner ?? plugin,\n meta: entries,\n guards,\n timeoutMs: timeoutMs === Number.POSITIVE_INFINITY ? undefined : timeoutMs,\n precheck: route.precheck?.bind(route),\n accept: route.accept.bind(route),\n }\n}\n\nfunction metaEntry(plugin: string, where: string, value: unknown): NormalizedMetaEntry {\n const entry = (value ?? {}) as Partial<RouteMetaEntry>\n if (value === null || typeof value !== 'object' || typeof entry.key !== 'string' || entry.key === '') {\n throw invalid(plugin, `invalid meta entry ${describe(value)} of the upgrade route ${where}`)\n }\n const group = entry.group ?? entry.key\n const required = entry.required ?? false\n if (!isGroupOf(group, entry.key) || typeof required !== 'boolean') {\n throw invalid(plugin, `invalid group of the meta entry \"${entry.key}\" of the upgrade route ${where}`)\n }\n return { key: entry.key, value: entry.value, group, required }\n}\n\nfunction invalid(plugin: string, reason: string, cause?: unknown): ZnightError {\n return new ZnightError(ErrorCode.InvalidRoute, `HttpPlugin: plugin \"${plugin}\": ${reason}`, {\n ...(cause === undefined ? {} : { cause }),\n })\n}\n\nfunction describe(value: unknown): string {\n try {\n return typeof value === 'function' ? 'a function' : (JSON.stringify(value) ?? String(value))\n } catch {\n return typeof value\n }\n}\n\n// -------------------------------------------------------------------------------------------------\n// Handshake checks (RFC 6455 §4.2.1)\n// -------------------------------------------------------------------------------------------------\n\nconst KEY = /^[A-Za-z0-9+/]{22}==$/\n\n/** Whether a request asks for a WebSocket upgrade (`upgrade: websocket`, any case). */\nexport function isWebSocketUpgrade(headers: Readonly<Record<string, string | undefined>>): boolean {\n const upgrade = headers['upgrade']\n return upgrade !== undefined && upgrade.length === 9 && upgrade.toLowerCase() === 'websocket'\n}\n\n/**\n * The protocol checks of a handshake: `GET`, `sec-websocket-version: 13` (`426` with the supported\n * version otherwise) and a base64 16-byte `sec-websocket-key` (`400`).\n */\nexport function checkHandshake(ctx: HttpContext): void {\n if (ctx.method !== 'GET') throw new BadRequestException('A WebSocket handshake must be a GET request')\n if (ctx.headers['sec-websocket-version'] !== '13') {\n throw new HttpException(426, 'Unsupported WebSocket version', undefined, {\n headers: { 'sec-websocket-version': '13' },\n })\n }\n const key = ctx.headers['sec-websocket-key']\n if (key === undefined || !KEY.test(key.trim())) throw new BadRequestException('Invalid Sec-WebSocket-Key')\n}\n\n/** Internal: the pending upgrade of a handshake, created by the pipeline. */\nexport class PendingUpgradeState implements PendingUpgrade {\n readonly native: NativeUpgrade\n readonly #headers: () => Readonly<Record<string, HeaderValue>>\n /** The transport completed the handshake (`101`). */\n accepted = false\n /** The handshake timed out: the transport must not complete it. */\n expired = false\n held: Promise<unknown> | undefined\n\n constructor(native: NativeUpgrade, headers: () => Readonly<Record<string, HeaderValue>>) {\n this.native = native\n this.#headers = headers\n }\n\n get headers(): Readonly<Record<string, HeaderValue>> {\n return this.#headers()\n }\n\n hold(closed: Promise<unknown>): void {\n if (this.held !== undefined) throw new Error('PendingUpgrade.hold() can only be called once')\n this.accepted = true\n this.held = closed.then(\n () => undefined,\n () => undefined,\n )\n }\n}\n","/**\n * WebSocket upgrades on the adapters (RFC 0003 §8.2.3, internal): the upgrade capability of\n * `node:http` servers, the request of a handshake as an {@link AdapterRequest} (Node.js, Fetch,\n * in memory) and the raw HTTP refusal written on a socket.\n */\nimport type { IncomingMessage, Server } from 'node:http'\nimport type { Duplex } from 'node:stream'\nimport type { AdapterReply, AdapterRequest } from '../adapter.ts'\nimport type { HeaderValue } from '../exceptions.ts'\nimport type { AdapterUpgrades, BunSocketHandlers, UpgradeHandlerOptions } from '../upgrade.ts'\n\nimport { statusText } from '../status.ts'\nimport { isWebSocketUpgrade } from '../upgrade.ts'\nimport { markUpgraded, normalizeNodeHeaders } from './node-io.ts'\nimport { concat } from './shared.ts'\n\nconst EMPTY = new Uint8Array(0)\n\n/** A handshake has no body: Znight never reads one. */\nconst NO_BODY: Promise<Uint8Array> = Promise.resolve(EMPTY)\n\n/** The `IncomingMessage` of a `node:http` upgrade as an {@link AdapterRequest}. */\nclass NodeUpgradeRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip: string | undefined\n readonly remoteAddress: string | undefined\n readonly encrypted: boolean\n readonly raw: unknown\n readonly rawResponse: unknown\n\n constructor(request: IncomingMessage, socket: Duplex) {\n const peer = (socket as { readonly remoteAddress?: string }).remoteAddress ?? request.socket?.remoteAddress\n this.method = request.method ?? 'GET'\n this.url = request.url ?? '/'\n this.headers = normalizeNodeHeaders(request.headers)\n this.ip = peer\n this.remoteAddress = peer\n this.encrypted = (request.socket as { readonly encrypted?: unknown } | undefined)?.encrypted === true\n this.raw = request\n this.rawResponse = socket\n }\n\n readBody(): Promise<Uint8Array> {\n return NO_BODY\n }\n\n hasBody(): boolean {\n return false\n }\n}\n\n/** The Fetch `Request` of a `Bun.serve()` upgrade as an {@link AdapterRequest}. */\nexport class FetchUpgradeRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip: string | undefined\n readonly remoteAddress: string | undefined\n readonly encrypted: boolean\n readonly raw: Request\n readonly rawResponse: unknown = undefined\n\n constructor(request: Request, url: string, headers: Record<string, string>, address: string | undefined) {\n this.method = request.method\n this.url = url\n this.headers = headers\n this.ip = address\n this.remoteAddress = address\n this.encrypted = request.url.startsWith('https:')\n this.raw = request\n }\n\n readBody(): Promise<Uint8Array> {\n return NO_BODY\n }\n\n hasBody(): boolean {\n return false\n }\n}\n\n/** An in-memory handshake (`HttpPlugin.upgradeInMemory()`) as an {@link AdapterRequest}. */\nexport class MemoryUpgradeRequest implements AdapterRequest {\n readonly method: string\n readonly url: string\n readonly headers: Readonly<Record<string, string | undefined>>\n readonly ip = '127.0.0.1'\n readonly remoteAddress = '127.0.0.1'\n readonly encrypted = false\n readonly raw: unknown = undefined\n readonly rawResponse: unknown = undefined\n\n constructor(method: string, url: string, headers: Record<string, string>) {\n this.method = method\n this.url = url\n this.headers = headers\n }\n\n readBody(): Promise<Uint8Array> {\n return NO_BODY\n }\n\n hasBody(): boolean {\n return false\n }\n}\n\n/** The bytes of a reply body (refusals are small: read whole). */\nexport async function replyBytes(reply: AdapterReply): Promise<Uint8Array> {\n const body = reply.body\n if (body === null) return EMPTY\n if (body instanceof Uint8Array) return body\n if (body instanceof Blob) return new Uint8Array(await body.arrayBuffer())\n const chunks: Uint8Array[] = []\n let size = 0\n for await (const chunk of body as ReadableStream<Uint8Array>) {\n chunks.push(chunk)\n size += chunk.byteLength\n }\n return concat(chunks, size)\n}\n\n/** Whether a header value can be written on a raw socket (no CR/LF injection). */\nfunction safeHeader(value: string): boolean {\n return !/[\\r\\n]/.test(value)\n}\n\n/**\n * Writes a refused handshake as a raw HTTP/1.1 response on the upgrade socket, then ends it\n * (`connection: close`). Never throws.\n */\nexport async function writeRawRefusal(socket: Duplex, reply: AdapterReply): Promise<void> {\n try {\n const body = await replyBytes(reply)\n let head = `HTTP/1.1 ${reply.status} ${statusText(reply.status)}\\r\\n`\n const headers: Record<string, HeaderValue> = { ...reply.headers }\n headers['connection'] = 'close'\n headers['content-length'] = String(body.byteLength)\n for (const [name, value] of Object.entries(headers)) {\n for (const item of typeof value === 'string' ? [value] : value) {\n if (safeHeader(name) && safeHeader(item)) head += `${name}: ${item}\\r\\n`\n }\n }\n head += '\\r\\n'\n if (socket.destroyed) return\n socket.write(head)\n if (body.byteLength > 0) socket.write(body)\n socket.end()\n // a client that never closes its side: destroy after a short grace\n setTimeout(() => socket.destroy(), 1_000).unref?.()\n } catch {\n socket.destroy()\n }\n}\n\n/** The fallback reply when the pipeline failed (never expected). */\nconst FAILURE: AdapterReply = Object.freeze({ status: 500, headers: {}, body: null })\n\n/**\n * The upgrade capability of an adapter built on a `node:http` server (RFC 0003 §8.2.3): upgrade\n * requests of the gateway paths are routed to the pipeline through `shouldUpgradeCallback`\n * (composed with the server's own) and an `'upgrade'` listener; other upgrade requests are left to\n * the server (its own listeners, or ordinary requests).\n */\nexport class NodeUpgrades implements AdapterUpgrades {\n readonly kind = 'node' as const\n #options: UpgradeHandlerOptions | undefined\n readonly #attached = new WeakSet<Server>()\n\n /** Whether {@link enable} was called. */\n get enabled(): boolean {\n return this.#options !== undefined\n }\n\n enable(options: UpgradeHandlerOptions): void {\n this.#options = options\n }\n\n /** Routes the gateway upgrades of `server` to the pipeline (once per server; no-op when not enabled). */\n attach(server: Server): void {\n const options = this.#options\n if (options === undefined || this.#attached.has(server)) return\n this.#attached.add(server)\n const matches = (request: IncomingMessage): boolean => {\n if (!isWebSocketUpgrade(request.headers as Record<string, string | undefined>)) return false\n const url = request.url ?? '/'\n const query = url.indexOf('?')\n return options.match(query === -1 ? url : url.slice(0, query))\n }\n const target = server as Server & { shouldUpgradeCallback?: (request: IncomingMessage) => boolean }\n const previous = target.shouldUpgradeCallback\n const composable = typeof previous === 'function'\n const listener = (request: IncomingMessage, socket: Duplex, head: Uint8Array): void => {\n if (!matches(request)) {\n // without shouldUpgradeCallback (Node.js < 24.12), every upgrade reaches the listeners: answer\n // the ones nobody else handles\n if (!composable && server.listenerCount('upgrade') === 1) {\n void writeRawRefusal(socket, { status: 404, headers: {}, body: null })\n }\n return\n }\n socket.on('error', () => socket.destroy())\n markUpgraded(socket)\n const native = { kind: 'node', request, socket, head } as const\n options.handle(new NodeUpgradeRequest(request, socket), native).then(\n reply => {\n if (reply !== undefined) void writeRawRefusal(socket, reply)\n },\n () => void writeRawRefusal(socket, FAILURE),\n )\n }\n if (previous !== undefined) {\n target.shouldUpgradeCallback = function (this: Server, request: IncomingMessage): boolean {\n if (matches(request)) return true\n // the server's callback without Znight's listener (Node's default counts the listeners)\n const self = this ?? server\n const view = Object.create(self, {\n listenerCount: {\n value: (name: string | symbol): number => self.listenerCount(name) - (name === 'upgrade' ? 1 : 0),\n },\n }) as Server\n return previous.call(view, request) === true\n }\n }\n server.on('upgrade', listener)\n }\n}\n\n/**\n * The `websocket` option of `Bun.serve()`: the plugins' settings, and handlers dispatching every\n * event to the {@link BunSocketHandlers} given as `data` to `server.upgrade()`.\n */\nexport function bunWebSocketOption(settings: Readonly<Record<string, unknown>>): Readonly<Record<string, unknown>> {\n type Socket = { readonly data: BunSocketHandlers }\n return Object.freeze({\n ...settings,\n open: (ws: Socket): void => ws.data.open(ws),\n message: (ws: Socket, message: string | Uint8Array): void => ws.data.message(ws, message),\n close: (ws: Socket, code: number, reason: string): void => ws.data.close(ws, code, reason),\n drain: (ws: Socket): void => ws.data.drain(ws),\n pong: (ws: Socket): void => ws.data.pong?.(ws),\n })\n}\n\n/** Builds the `Response` of a refused `Bun.serve()` upgrade. */\nexport async function refusalResponse(reply: AdapterReply): Promise<Response> {\n const headers = new Headers()\n for (const [name, value] of Object.entries(reply.headers)) {\n for (const item of typeof value === 'string' ? [value] : value) headers.append(name, item)\n }\n const body = await replyBytes(reply)\n return new Response(body.byteLength === 0 ? null : body, { status: reply.status, headers })\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@znight/http",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Znight HTTP plugin: controllers, routing, guards, interceptors, validation with Fastify, Express or Hono",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ugho STEPHAN",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"access": "public"
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
|
-
"@znight/core": "0.6.
|
|
82
|
+
"@znight/core": "0.6.1"
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
85
|
"@hono/node-server": "^2.1.5",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"fastify": "^5.12.7",
|
|
88
88
|
"hono": "^4.13.14",
|
|
89
89
|
"light-my-request": "^6.8.0",
|
|
90
|
-
"@znight/compiler": "^0.6.
|
|
90
|
+
"@znight/compiler": "^0.6.1"
|
|
91
91
|
},
|
|
92
92
|
"peerDependenciesMeta": {
|
|
93
93
|
"@hono/node-server": {
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"valibot": "1.5.0",
|
|
119
119
|
"zod": "4.6.7",
|
|
120
120
|
"light-my-request": "6.8.0",
|
|
121
|
-
"@znight/compiler": "0.6.
|
|
121
|
+
"@znight/compiler": "0.6.1"
|
|
122
122
|
},
|
|
123
123
|
"znight": {
|
|
124
124
|
"apiVersion": 1,
|
package/src/decorators.ts
CHANGED
|
@@ -286,7 +286,7 @@ export function BodyLimit(_size: ByteSize): ClassMarker & MethodMarker {
|
|
|
286
286
|
return classOrMethodMarker
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
/** Injects the native request of the adapter (escape hatch
|
|
289
|
+
/** Injects the native request of the adapter (escape hatch). */
|
|
290
290
|
export function Req(): ParameterMarker {
|
|
291
291
|
return parameterMarker
|
|
292
292
|
}
|