@wooksjs/event-http
Version:
@wooksjs/event-http
769 lines (747 loc) • 32.9 kB
TypeScript
import * as _wooksjs_event_core from '@wooksjs/event-core';
import { EventContext, Logger, EventContextOptions, EventKindSeeds } from '@wooksjs/event-core';
export { EventContext, EventContextOptions, useLogger, useRouteParams } from '@wooksjs/event-core';
import * as http from 'http';
import http__default, { IncomingHttpHeaders, IncomingMessage, ServerResponse, Server } from 'http';
import { Buffer } from 'buffer';
import { URLSearchParams } from 'url';
import * as wooks from 'wooks';
import { TWooksHandler, TWooksOptions, WooksAdapterBase, Wooks, WooksUpgradeHandler } from 'wooks';
import { TConsoleBase } from '@prostojs/logger';
import { ListenOptions } from 'net';
import { Duplex } from 'stream';
/**
* Provides access to parsed request cookies.
* @example
* ```ts
* const { getCookie, raw } = useCookies()
* const sessionId = getCookie('session_id')
* ```
*/
declare const useCookies: _wooksjs_event_core.WookComposable<{
raw: string | undefined;
getCookie: (name: string) => string | null;
}>;
/** Short names for common Accept MIME types. */
type KnownAcceptType = 'json' | 'html' | 'xml' | 'text';
/** Provides helpers to check the request's Accept header for supported MIME types. */
declare const useAccept: _wooksjs_event_core.WookComposable<{
accept: string | undefined;
has: (type: KnownAcceptType | (string & {})) => boolean;
}>;
/** Short names for common Authorization schemes. */
type KnownAuthType = 'basic' | 'bearer';
/**
* Provides parsed access to the Authorization header (type, credentials, Basic decoding).
* @example
* ```ts
* const { is, credentials, basicCredentials } = useAuthorization()
* if (is('bearer')) { const token = credentials() }
* ```
*/
declare const useAuthorization: _wooksjs_event_core.WookComposable<{
authorization: string | undefined;
type: () => string | null;
credentials: () => string | null;
is: (type: KnownAuthType | (string & {})) => boolean;
basicCredentials: () => {
username: string;
password: string;
} | null;
}>;
/**
* Returns the incoming request headers.
* @example
* ```ts
* const { host, authorization } = useHeaders()
* ```
*/
declare function useHeaders(ctx?: EventContext): IncomingHttpHeaders;
/** Default safety limits for request body reading (size, ratio, timeout). */
declare const DEFAULT_LIMITS: {
readonly maxCompressed: number;
readonly maxInflated: number;
readonly maxRatio: 100;
readonly readTimeoutMs: 10000;
};
/** @internal Exported for test pre-seeding via `ctx.set(rawBodySlot, ...)`. */
declare const rawBodySlot: _wooksjs_event_core.Cached<Promise<Buffer<ArrayBufferLike>>>;
/**
* Provides access to the incoming HTTP request (method, url, headers, body, IP).
* @example
* ```ts
* const { method, url, raw, rawBody, getIp } = useRequest()
* const body = await rawBody()
* ```
*/
declare const useRequest: _wooksjs_event_core.WookComposable<{
raw: http.IncomingMessage;
url: string | undefined;
method: string | undefined;
headers: http.IncomingHttpHeaders;
rawBody: () => Promise<Buffer<ArrayBufferLike>>;
reqId: () => string;
getIp: (options?: {
trustProxy: boolean;
}) => string;
getIpList: () => {
remoteIp: string;
forwarded: string[];
};
isCompressed: () => boolean;
getMaxCompressed: () => number;
setMaxCompressed: (limit: number) => void;
getReadTimeoutMs: () => number;
setReadTimeoutMs: (limit: number) => void;
getMaxInflated: () => number;
setMaxInflated: (limit: number) => void;
getMaxRatio: () => number;
setMaxRatio: (limit: number) => void;
}>;
/** Maps numeric HTTP status codes to their human-readable descriptions. */
declare const httpStatusCodes: {
100: string;
101: string;
102: string;
103: string;
200: string;
201: string;
202: string;
203: string;
204: string;
205: string;
206: string;
207: string;
208: string;
226: string;
300: string;
301: string;
302: string;
303: string;
304: string;
305: string;
306: string;
307: string;
308: string;
400: string;
401: string;
402: string;
403: string;
404: string;
405: string;
406: string;
407: string;
408: string;
409: string;
410: string;
411: string;
412: string;
413: string;
414: string;
415: string;
416: string;
417: string;
418: string;
421: string;
422: string;
423: string;
424: string;
425: string;
426: string;
428: string;
429: string;
431: string;
451: string;
500: string;
501: string;
502: string;
503: string;
504: string;
505: string;
506: string;
507: string;
508: string;
510: string;
511: string;
};
/** Enum of all standard HTTP status codes (100–511). */
declare enum EHttpStatusCode {
Continue = 100,
SwitchingProtocols = 101,
Processing = 102,
EarlyHints = 103,
OK = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
IMUsed = 226,
MultipleChoices = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
SwitchProxy = 306,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
URITooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImATeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HTTPVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511
}
/** Union of HTTP 4xx client error status codes. */
type THttpBadRequestCodes = 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451;
/** Union of HTTP 5xx server error status codes. */
type THttpServerErrorCodes = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511;
/** Union of all HTTP error status codes (4xx + 5xx). */
type THttpErrorCodes = THttpBadRequestCodes | THttpServerErrorCodes;
/** Represents an HTTP error with a status code and optional structured body. */
declare class HttpError<T extends TWooksErrorBody = TWooksErrorBody> extends Error {
protected code: THttpErrorCodes;
protected _body: string | T;
name: string;
constructor(code?: THttpErrorCodes, _body?: string | T);
get body(): TWooksErrorBodyExt;
}
/** Base shape for an HTTP error response body. */
interface TWooksErrorBody {
message: string;
statusCode: EHttpStatusCode;
error?: string;
}
/** Extended error body that always includes the error description string. */
interface TWooksErrorBodyExt extends TWooksErrorBody {
error: string;
}
type TTimeUnit = 'ms' | 's' | 'm' | 'h' | 'd' | 'w' | 'M' | 'Y';
type TTimeSingleString = `${number}${TTimeUnit}`;
type TTimeMultiString = `${TTimeSingleString}${TTimeSingleString | ''}${TTimeSingleString | ''}${TTimeSingleString | ''}`;
/** Raw HTTP event data attached to the event context. */
interface THttpEventData {
req: IncomingMessage;
res: ServerResponse;
requestLimits?: TRequestLimits;
}
/** Data for a pending outgoing `Set-Cookie` header (name is stored as the key in `HttpResponse._cookies`). */
interface TSetCookieData {
value: string;
attrs: TCookieAttributesInput;
}
/** Partial cookie attributes — all fields are optional. */
type TCookieAttributesInput = Partial<TCookieAttributes>;
/** Full set of attributes for a `Set-Cookie` header (RFC 6265 §4.1). */
interface TCookieAttributes {
/** Cookie expiration date. */
expires: Date | string | number;
/** Max age in seconds, or a time string (e.g. `'1h'`). */
maxAge: number | TTimeMultiString;
/** Cookie domain. */
domain: string;
/** Cookie path. */
path: string;
/** Secure flag — cookie only sent over HTTPS. */
secure: boolean;
/** HttpOnly flag — cookie not accessible via JavaScript. */
httpOnly: boolean;
/** SameSite policy. */
sameSite: boolean | 'Lax' | 'None' | 'Strict';
}
/** App-level request body limits (all optional, defaults apply when omitted). */
interface TRequestLimits {
/** Max compressed body size in bytes (default: 1 MB). */
maxCompressed?: number;
/** Max inflated (decompressed) body size in bytes (default: 10 MB). */
maxInflated?: number;
/** Max compression ratio, e.g. 100 means 100× expansion (default: 100). */
maxRatio?: number;
/** Body read timeout in milliseconds (default: 10 000). */
readTimeoutMs?: number;
/** Internal flag: true when this object is a per-request clone (copy-on-write). */
perRequest?: boolean;
}
/** Cache-Control directive object (RFC 7234 §5.2.2). All fields are optional. */
interface TCacheControl {
mustRevalidate?: boolean;
noCache?: boolean | string;
noStore?: boolean;
noTransform?: boolean;
public?: boolean;
private?: boolean | string;
proxyRevalidate?: boolean;
/** Max age in seconds, or a time string (e.g. `'3h 30m'`). */
maxAge?: number | TTimeMultiString;
/** Shared cache max age in seconds, or a time string. */
sMaxage?: number | TTimeMultiString;
}
/** Renders a `TCacheControl` object into a `Cache-Control` header string. */
declare function renderCacheControl(data: TCacheControl): string;
/**
* Manages response status, headers, cookies, cache control, and body for an HTTP request.
*
* All header mutations are accumulated in memory and flushed in a single `writeHead()` call
* when `send()` is invoked. Setter methods are chainable.
*
* @example
* ```ts
* const response = useResponse()
* response.setStatus(200).setHeader('x-custom', 'value')
* response.setCookie('session', 'abc', { httpOnly: true })
* ```
*/
declare class HttpResponse {
protected readonly _res: ServerResponse;
protected readonly _req: IncomingMessage;
protected readonly _logger: Logger;
protected readonly _captureMode: boolean;
/**
* @param _res - The underlying Node.js `ServerResponse`.
* @param _req - The underlying Node.js `IncomingMessage`.
* @param _logger - Logger instance for error reporting.
* @param defaultHeaders - Optional headers to pre-populate on this response (e.g. from `securityHeaders()`).
*/
constructor(_res: ServerResponse, _req: IncomingMessage, _logger: Logger, defaultHeaders?: Record<string, string | string[]>, _captureMode?: boolean);
protected _status: EHttpStatusCode;
protected _body: unknown;
protected _headers: Record<string, string | string[]>;
protected _cookies: Record<string, TSetCookieData>;
protected _rawCookies: string[];
protected _hasCookies: boolean;
protected _responded: boolean;
/** The HTTP status code. If not set, it is inferred automatically when `send()` is called. */
get status(): EHttpStatusCode;
set status(value: EHttpStatusCode);
/** Sets the HTTP status code (chainable). */
setStatus(value: EHttpStatusCode): this;
/** The response body. Automatically serialized by `send()` (objects → JSON, strings → text). */
get body(): unknown;
set body(value: unknown);
/** Sets the response body (chainable). */
setBody(value: unknown): this;
/** Sets a single response header (chainable). Arrays produce multi-value headers. */
setHeader(name: string, value: string | number | string[]): this;
/** Batch-sets multiple response headers from a record (chainable). Existing keys are overwritten. */
setHeaders(headers: Record<string, string | string[]>): this;
/** Returns the value of a response header, or `undefined` if not set. */
getHeader(name: string): string | string[] | undefined;
/** Removes a response header (chainable). */
removeHeader(name: string): this;
/** Returns a read-only snapshot of all response headers. */
headers(): Readonly<Record<string, string | string[]>>;
/** Sets the `Content-Type` response header (chainable). */
setContentType(value: string): this;
/** Returns the current `Content-Type` header value. */
getContentType(): string | string[] | undefined;
/** Sets the `Access-Control-Allow-Origin` header (chainable). Defaults to `'*'`. */
enableCors(origin?: string): this;
/** Sets an outgoing `Set-Cookie` header with optional attributes (chainable). */
setCookie(name: string, value: string, attrs?: Partial<TCookieAttributes>): this;
/** Returns a previously set cookie's data, or `undefined` if not set. */
getCookie(name: string): TSetCookieData | undefined;
/** Removes a cookie from the outgoing set list (chainable). */
removeCookie(name: string): this;
/** Removes all outgoing cookies (chainable). */
clearCookies(): this;
/** Appends a raw `Set-Cookie` header string (chainable). Use when you need full control over the cookie format. */
setCookieRaw(rawValue: string): this;
/**
* Renders all buffered cookies (named via `setCookie()`, then raw via `setCookieRaw()`)
* as `Set-Cookie` header strings, without responding.
*
* Non-destructive: the buffers stay intact, so a later `send()` still emits the same
* cookies — callers that drain cookies onto the wire themselves should not also send
* through this wrapper. Cookies placed directly into headers (via `setHeader('set-cookie', …)`
* or default headers) are not included.
*/
getSetCookieStrings(): string[];
/** Sets the `Cache-Control` header from a directive object (chainable). */
setCacheControl(data: TCacheControl): this;
/** Sets the `Age` header in seconds (chainable). Accepts a number or time string (e.g. `'2h 15m'`). */
setAge(value: number | TTimeMultiString): this;
/** Sets the `Expires` header (chainable). Accepts a `Date`, date string, or timestamp. */
setExpires(value: Date | string | number): this;
/** Sets or clears the `Pragma: no-cache` header (chainable). */
setPragmaNoCache(value?: boolean): this;
/**
* Returns the underlying Node.js `ServerResponse`.
* @param passthrough - If `true`, the framework still manages the response lifecycle. If `false` (default), the response is marked as "responded" and the framework will not touch it.
*/
getRawRes(passthrough?: boolean): ServerResponse;
/** Whether the response has already been sent (or the underlying stream is no longer writable). */
get responded(): boolean;
/**
* Builds a Web Standard `Response` from the accumulated response state
* (status, headers, cookies, body) without writing to the underlying `ServerResponse`.
*
* Used by `WooksHttp.fetch()` for programmatic invocation.
*/
toWebResponse(): Response;
private _buildWebHeaders;
/**
* Merges headers from a handler-returned fetch `Response` into the buffered headers.
* Explicitly buffered headers win. `set-cookie` is appended in array form so multiple
* cookies survive (`Headers` iteration would otherwise keep only the first).
*/
protected mergeFetchResponseHeaders(fetchResponse: Response): void;
protected renderBody(): string | Uint8Array;
protected renderError(data: TWooksErrorBodyExt, _ctx: EventContext): void;
/** Renders and sends an HTTP error response. Called automatically by the framework when a handler throws an `HttpError`. */
sendError(error: HttpError, ctx: EventContext): void | Promise<void>;
/**
* Finalizes and sends the response.
*
* Flushes all accumulated headers (including cookies) in a single `writeHead()` call,
* then writes the body. Supports `Readable` streams, `fetch` `Response` objects, and regular values.
*
* @throws Error if the response was already sent.
*/
send(): void | Promise<void>;
private finalizeCookies;
private autoStatus;
private sendStream;
private sendFetchResponse;
private sendRegular;
}
/** Converts a Record of headers to a Web Standard `Headers` object. */
declare function recordToWebHeaders(record: Record<string, string | string[]>): Headers;
/**
* Returns the HttpResponse instance for the current request.
* All response operations (status, headers, cookies, cache control, sending)
* are methods on the returned object.
*
* @example
* ```ts
* const response = useResponse()
* response.status = 200
* response.setHeader('x-custom', 'value')
* response.setCookie('session', 'abc', { httpOnly: true })
* ```
*/
declare function useResponse(ctx?: EventContext): HttpResponse;
/**
* Extended `URLSearchParams` with safe JSON conversion.
*
* Rejects prototype-pollution keys (`__proto__`, `constructor`, `prototype`) and duplicate non-array keys.
* Array parameters are detected by a trailing `[]` in the key name (e.g. `tags[]=a&tags[]=b`).
*/
declare class WooksURLSearchParams extends URLSearchParams {
/** Converts query parameters to a plain object. Array params (keys ending with `[]`) become `string[]`. */
toJson<T = unknown>(): T;
}
/**
* Provides access to URL search (query) parameters from the request.
* @example
* ```ts
* const { params, toJson } = useUrlParams()
* const page = params().get('page')
* ```
*/
declare const useUrlParams: _wooksjs_event_core.WookComposable<{
raw: () => string;
params: () => WooksURLSearchParams;
toJson: () => unknown;
}>;
/** Event kind definition for HTTP requests. Provides typed context slots for `req`, `response`, and `requestLimits`. */
declare const httpKind: _wooksjs_event_core.EventKind<{
req: _wooksjs_event_core.SlotMarker<IncomingMessage>;
response: _wooksjs_event_core.SlotMarker<HttpResponse | undefined>;
requestLimits: _wooksjs_event_core.SlotMarker<TRequestLimits | undefined>;
}>;
/** Creates an HTTP event context and runs `fn` inside it. */
declare function createHttpContext<R>(options: EventContextOptions, seeds: EventKindSeeds<typeof httpKind>, fn: () => R): R;
/** Returns the current HTTP event context. */
declare function useHttpContext(ctx?: EventContext): EventContext;
/**
* Default `HttpResponse` subclass used by `createHttpApp`.
*
* Overrides error rendering to produce content-negotiated responses (JSON, HTML, or plain text)
* based on the request's `Accept` header. HTML error pages include SVG icons and framework branding.
*/
declare class WooksHttpResponse extends HttpResponse {
/** Registers framework metadata (name, version, link, logo) used in HTML error pages. */
static registerFramework(opts: {
version: string;
poweredBy: string;
link: string;
image: string;
}): void;
protected renderError(data: TWooksErrorBodyExt, ctx: EventContext): void;
}
/**
* Identity headers forwarded from the calling HTTP context during programmatic `fetch()`
* when no `forwardHeaders` option is configured.
*
* The `forwardHeaders` option REPLACES this list. To extend it instead, spread the constant:
* ```ts
* createHttpApp({ forwardHeaders: [...DEFAULT_FORWARD_HEADERS, 'cloudfront-viewer-address'] })
* ```
*/
declare const DEFAULT_FORWARD_HEADERS: readonly string[];
/** Configuration options for the WooksHttp adapter. */
interface TWooksHttpOptions {
logger?: TConsoleBase;
onNotFound?: TWooksHandler;
router?: TWooksOptions['router'];
/** Default request body limits applied to every request (overridable per-request via `useRequest()`). */
requestLimits?: Omit<TRequestLimits, 'perRequest'>;
/** Custom HttpResponse subclass. Defaults to WooksHttpResponse (HTML/JSON/text error rendering). */
responseClass?: typeof WooksHttpResponse;
/** Default headers applied to every response. Use `securityHeaders()` for recommended security headers. */
defaultHeaders?: Record<string, string | string[]>;
/**
* Headers forwarded from the calling HTTP context during programmatic `fetch()`.
* REPLACES the default list entirely — to add headers while keeping the defaults,
* spread the exported constant: `[...DEFAULT_FORWARD_HEADERS, 'my-header']`.
* Set to `false` to disable forwarding entirely.
* @default DEFAULT_FORWARD_HEADERS — ['authorization', 'cookie', 'accept-language', 'x-forwarded-for', 'x-request-id']
*/
forwardHeaders?: string[] | false;
}
/** HTTP adapter for Wooks that provides route registration, server lifecycle, and request handling. */
declare class WooksHttp extends WooksAdapterBase {
protected opts?: TWooksHttpOptions | undefined;
protected logger: TConsoleBase;
protected ResponseClass: typeof WooksHttpResponse;
protected eventContextOptions: EventContextOptions;
constructor(opts?: TWooksHttpOptions | undefined, wooks?: Wooks | WooksAdapterBase);
/** Registers a handler for all HTTP methods on the given path. */
all<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers a GET route handler. */
get<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers a POST route handler. */
post<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers a PUT route handler. */
put<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers a PATCH route handler. */
patch<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers a DELETE route handler. */
delete<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers a HEAD route handler. */
head<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers an OPTIONS route handler. */
options<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
/** Registers an UPGRADE route handler for WebSocket upgrade requests. */
upgrade<ResType = unknown, ParamsType = Record<string, string | string[]>>(path: string, handler: TWooksHandler<ResType>): wooks.TProstoRouterPathHandle<ParamsType>;
private wsHandler?;
/** Register a WebSocket upgrade handler that implements the WooksUpgradeHandler contract. */
ws(handler: WooksUpgradeHandler): void;
protected server?: Server;
/**
* Starts the http(s) server.
*
* Use this only if you rely on Wooks server.
*/
listen(port?: number, hostname?: string, backlog?: number, listeningListener?: () => void): Promise<void>;
listen(port?: number, hostname?: string, listeningListener?: () => void): Promise<void>;
listen(port?: number, backlog?: number, listeningListener?: () => void): Promise<void>;
listen(port?: number, listeningListener?: () => void): Promise<void>;
listen(path: string, backlog?: number, listeningListener?: () => void): Promise<void>;
listen(path: string, listeningListener?: () => void): Promise<void>;
listen(options: ListenOptions, listeningListener?: () => void): Promise<void>;
listen(handle: unknown, backlog?: number, listeningListener?: () => void): Promise<void>;
listen(handle: unknown, listeningListener?: () => void): Promise<void>;
/**
* Stops the server if it was attached or passed via argument
* @param server
*/
close(server?: Server): Promise<unknown>;
/**
* Returns http(s) server that was attached to Wooks
*
* See attachServer method docs
* @returns Server
*/
getServer(): http__default.Server<typeof http__default.IncomingMessage, typeof http__default.ServerResponse> | undefined;
/**
* Attaches http(s) server instance
* to Wooks.
*
* Use it only if you want to `close` method to stop the server.
* @param server Server
*/
attachServer(server?: Server): void;
protected respond(data: unknown, response: HttpResponse, ctx: EventContext): void | Promise<void>;
/**
* Returns server callback function
* that can be passed to any node server:
* ```js
* import { createHttpApp } from '@wooksjs/event-http'
* import http from 'http'
*
* const app = createHttpApp()
* const server = http.createServer(app.getServerCb())
* server.listen(3000)
* ```
*/
getServerCb(onNoMatch?: (req: IncomingMessage, res: ServerResponse) => void): (req: IncomingMessage, res: ServerResponse) => void;
/**
* Returns upgrade callback function for the HTTP server's 'upgrade' event.
* Creates an HTTP context, seeds it with upgrade data, and routes as method 'UPGRADE'.
*/
getUpgradeCb(): (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
protected processUpgradeHandlers(handlers: TWooksHandler[], ctx: EventContext, socket: Duplex): void | Promise<unknown>;
/** Runs handlers and attaches a `.catch()` for async results to avoid unhandled rejections. */
private processAndCatch;
protected processHandlers(handlers: TWooksHandler[], ctx: EventContext, response: HttpResponse): void | Promise<unknown>;
private processAsyncResult;
/**
* Programmatic route invocation using the Web Standard fetch API.
* Goes through the full dispatch pipeline: context creation, route matching,
* handler execution, response finalization.
*
* When called from within an existing HTTP context (e.g. during SSR),
* identity headers (authorization, cookie) are automatically forwarded
* from the calling request unless already present on the given Request.
*
* @param request - A Web Standard Request object.
* @returns A Web Standard Response, or `null` if no route matched (and no `onNotFound` handler is set).
*/
fetch(request: Request): Promise<Response | null>;
/**
* Convenience wrapper for programmatic route invocation.
* Accepts a URL string (relative paths auto-prefixed with `http://localhost`),
* URL object, or Request, plus optional `RequestInit`.
*
* @param input - URL string, URL object, or Request.
* @param init - Optional RequestInit (method, headers, body, etc.).
* @returns A Web Standard Response.
*/
request(input: string | URL | Request, init?: RequestInit): Promise<Response | null>;
/**
* Runs `fn` inside an HTTP event context seeded from a real `(req, res)` pair,
* WITHOUT route dispatch. Composables that read request state (`useRequest`,
* `useHeaders`, `useCookies`, `useAuthorization`) work; route-scoped state is empty.
* Nested `fetch()` calls made during `fn` see this context as their caller,
* so `forwardHeaders` and parent `Set-Cookie` propagation apply.
*
* Never writes to `res` — the caller owns the wire. The response wrapper is
* created in capture mode, so even a stray `response.send()` inside `fn` only
* finalizes state without touching the socket. Buffered response state
* (e.g. `Set-Cookie` collected from nested fetches) can be applied by the
* caller via the returned wrapper:
* ```ts
* const { result: html, response } = await http.withHttpContext(req, res, () => render(url))
* for (const cookie of response.getSetCookieStrings()) {
* res.appendHeader('Set-Cookie', cookie)
* }
* ```
*/
withHttpContext<T>(req: IncomingMessage, res: ServerResponse, fn: () => T): Promise<{
result: Awaited<T>;
response: HttpResponse;
}>;
}
/**
* Creates a new WooksHttp application instance.
* @example
* ```ts
* const app = createHttpApp()
* app.get('/hello', () => 'Hello World!')
* app.listen(3000)
* ```
*/
declare function createHttpApp(opts?: TWooksHttpOptions, wooks?: Wooks | WooksAdapterBase): WooksHttp;
/**
* Configuration for `securityHeaders()`. Each option accepts a `string` (override value),
* `false` (disable), or `undefined` (use default). `strictTransportSecurity` has no default (opt-in only).
*/
interface SecurityHeadersOptions {
/** `Content-Security-Policy` header. Default: `"default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'"`. */
contentSecurityPolicy?: string | false;
/** `Cross-Origin-Opener-Policy` header. Default: `'same-origin'`. */
crossOriginOpenerPolicy?: string | false;
/** `Cross-Origin-Resource-Policy` header. Default: `'same-origin'`. */
crossOriginResourcePolicy?: string | false;
/** `Referrer-Policy` header. Default: `'no-referrer'`. */
referrerPolicy?: string | false;
/** `Strict-Transport-Security` header. No default (opt-in only — HSTS is dangerous if not on HTTPS). */
strictTransportSecurity?: string | false;
/** `X-Content-Type-Options` header. Default: `'nosniff'`. */
xContentTypeOptions?: string | false;
/** `X-Frame-Options` header. Default: `'SAMEORIGIN'`. */
xFrameOptions?: string | false;
}
/**
* Returns a record of recommended HTTP security headers.
*
* Each option accepts a `string` (override value) or `false` (disable).
* Omitting an option uses the default value.
*
* `strictTransportSecurity` is opt-in only (no default) — HSTS is dangerous if not on HTTPS.
*/
declare function securityHeaders(opts?: SecurityHeadersOptions): Record<string, string>;
/** Options for creating a test HTTP event context. */
interface TTestHttpContext {
/** Pre-set route parameters (e.g. `{ id: '42' }`). */
params?: Record<string, string | string[]>;
/** Request URL (e.g. `/api/users?page=1`). */
url: string;
/** Request headers. */
headers?: Record<string, string>;
/** HTTP method (default: `'GET'`). */
method?: string;
/** Custom request body limits. */
requestLimits?: TRequestLimits;
/** Pre-seed the raw body for body-parsing tests. */
rawBody?: string | Buffer;
/** Default headers to pre-populate on the response (e.g. from `securityHeaders()`). */
defaultHeaders?: Record<string, string | string[]>;
}
/**
* Creates a fully initialized HTTP event context for testing.
*
* Sets up an `EventContext` with a fake `IncomingMessage`, `HttpResponse`, route params,
* and optional pre-seeded body. Returns a runner function that executes callbacks inside the context scope.
*
* @example
* ```ts
* const run = prepareTestHttpContext({ url: '/users/42', params: { id: '42' } })
* run(() => {
* const { params } = useRouteParams()
* expect(params.id).toBe('42')
* })
* ```
*/
declare function prepareTestHttpContext(options: TTestHttpContext): <T>(cb: (...a: any[]) => T) => T;
export { DEFAULT_FORWARD_HEADERS, DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpResponse, WooksHttp, WooksHttpResponse, WooksURLSearchParams, createHttpApp, createHttpContext, httpKind, httpStatusCodes, prepareTestHttpContext, rawBodySlot, recordToWebHeaders, renderCacheControl, securityHeaders, useAccept, useAuthorization, useCookies, useHeaders, useHttpContext, useRequest, useResponse, useUrlParams };
export type { KnownAcceptType, KnownAuthType, SecurityHeadersOptions, TCacheControl, TCookieAttributes, TCookieAttributesInput, THttpEventData, TRequestLimits, TSetCookieData, TTestHttpContext, TWooksErrorBody, TWooksErrorBodyExt, TWooksHttpOptions };