import type { HttpContractConfig, InferHeaderSchemaOutput, InferOutput, StandardSchema } from "../contracts/index.js"; import type { AnyPorts } from "../ports/index.js"; import type { TrustedProxyConfig, TrustedRequestInfo } from "./trusted-proxy.js"; /** * Framework-neutral request shape consumed by Beignet server adapters. * * Platform adapters should convert their native request into this shape before * passing it to `server.api(...)` or a single route handler. */ export interface HttpRequestLike { /** * HTTP method as received from the platform. */ method: string; /** * Absolute request URL. */ url: string; /** * Request headers. */ headers: Headers; /** * Abort signal for the request lifecycle when the platform exposes one. * * Streaming handlers should pass this to resources that must close when * the client disconnects. Adapters without cancellation support may omit * it. */ signal?: AbortSignal; /** * The platform request when an adapter has one available. * * Use this as an escape hatch for platform-specific APIs. Prefer the * framework-agnostic methods below when possible. */ raw?: Request; /** * Parse the request body as JSON. */ json(): Promise; /** * Parse the request body as text. */ text(): Promise; /** * Parse the request body as an array buffer when the platform supports it. */ arrayBuffer?(): Promise; /** * Parse the request body as a Blob when the platform supports it. */ blob?(): Promise; /** * Parse the request body as form data when the platform supports it. */ formData?(): Promise; /** * Clone the request when the platform supports replaying the body. */ clone?(): HttpRequestLike; } /** * Header values accepted by a framework-neutral Beignet response. * * Use an array when the field must be emitted more than once, such as * `Set-Cookie`. Adapters append every array item as a separate field value. */ export type HttpResponseHeaderValue = string | readonly string[]; /** * Framework-neutral response headers. */ export type HttpResponseHeaders = Record; /** * Framework-neutral response object returned by route handlers and hooks. */ export interface HttpResponseLike { /** * HTTP status code. */ status: number; /** * Response headers. Array values are emitted as repeated header fields. */ headers?: HttpResponseHeaders; /** * JSON-serializable body or an adapter-specific body value. */ body?: unknown; } /** * Response accepted by Beignet handlers. * * Use `HttpResponseLike` for framework-neutral responses. Return a native * `Response` only when the current adapter can pass it through unchanged. */ export type HttpResponse = HttpResponseLike | Response; /** * Framework-neutral Beignet API handler consumed by HTTP adapters. */ export type HttpAdapterApiHandler = (req: HttpRequestLike) => Promise; /** * Native handler shape produced by an HTTP adapter. */ export type HttpAdapterHandler = (req: NativeRequest) => Promise; /** * Contract implemented by packages that adapt Beignet's framework-neutral * server runtime to a platform HTTP API. * * Core owns request parsing, hooks, route matching, validation, error mapping, * response ownership, and provider lifecycle. Adapters own only the conversion * between the platform request/response types and Beignet's `HttpRequestLike` * / `HttpResponse` boundary. */ export interface HttpAdapter { /** * Human-readable adapter name for diagnostics and documentation. */ name: string; /** * Convert a platform request into Beignet's framework-neutral request shape. */ toRequestLike(req: NativeRequest): HttpRequestLike; /** * Convert a Beignet response into the platform response type. */ toNativeResponse(res: HttpResponse): NativeResponse | Promise; /** * Wrap a Beignet API handler in the platform's native handler shape. */ createHandler(handler: HttpAdapterApiHandler): HttpAdapterHandler; } type InferSchemaOrFallback = T extends StandardSchema ? InferOutput : Fallback; /** * Infer the handler path parameter type for a contract. */ export type InferPath = InferSchemaOrFallback>; /** * Infer the handler query parameter type for a contract. */ export type InferQuery = InferSchemaOrFallback>; /** * Infer the handler request body type for a contract. */ export type InferBody = InferSchemaOrFallback; /** * Infer the merged request header type for a contract. */ export type InferHeaders = InferHeaderSchemaOutput> extends undefined ? Record : InferHeaderSchemaOutput>; /** * Arguments passed to a route handler after request parsing and validation. */ export interface HandlerArgs { /** * Framework-neutral request. */ req: HttpRequestLike; /** * Application context assembled by the server context blueprint. */ ctx: Ctx; /** * Matched contract config. */ contract: C; /** * Parsed path parameters. */ path: InferPath; /** * Parsed query parameters. */ query: InferQuery; /** * Parsed request headers. */ headers: InferHeaders; /** * Parsed request body. */ body: InferBody; } /** * Route handler function for a contract. */ export type Handler = (args: HandlerArgs) => Promise | HttpResponse; /** * Value or promise of that value. */ export type MaybePromise = T | Promise; /** * Arguments passed to a route-scoped hook after request parsing and context * creation. */ export type RouteHookArgs = HandlerArgs; /** * Hook that runs only for the route or route group where it is attached. * * Route hooks are for scoped policy and context enrichment such as * authentication, tenant resolution, feature gates, and idempotency. They add * fields to the handler context instead of replacing the app context. * * Hook additions must not include `gate`: the server re-attaches the gate * declared by the context blueprint after every hook, so identity changes are * picked up automatically. */ export interface RouteHook> { /** * Optional name used in diagnostics and devtools. */ name?: string; /** * Resolve additional context for this route or throw to stop handling. */ resolve: (args: RouteHookArgs) => MaybePromise; } type AddedCtxFromHook = Hook extends RouteHook ? AddedCtx : unknown; type UnionToIntersection = (Union extends unknown ? (value: Union) => void : never) extends (value: infer Intersection) => void ? Intersection : never; /** * Intersection of the context fields added by a route hook list. */ export type AddedCtxFromHooks = Hooks extends readonly [] ? unknown : UnionToIntersection>; /** * Hook that runs after a route is matched but before request parsing and * context creation. * * Returning a response short-circuits the rest of the request pipeline. */ export type OnRequestHook = (args: { req: HttpRequestLike; requestInfo: TrustedRequestInfo; ports: Ports; contract: C; params: Record; }) => MaybePromise; /** * Result from a `beforeHandle` hook. * * Returning a plain response short-circuits the handler. Returning an object can * replace the context, short-circuit with a response, or do both. */ export type BeforeHandleResult = undefined | HttpResponse | { ctx?: Ctx; response?: HttpResponse; }; /** * Hook that runs after request parsing/context creation and before the handler. */ export type BeforeHandleHook = (args: { req: HttpRequestLike; requestInfo: TrustedRequestInfo; ctx: Ctx; contract: C; path: InferPath; query: InferQuery; headers: InferHeaders; body: InferBody; }) => MaybePromise>; /** * Hook that runs before the response is returned. * * Return a response to replace or decorate the outgoing response. Hooks run in * declaration order. For native web `Response` results the hook receives a * headers-only view and only header changes are applied. */ export type BeforeSendHook = (args: { req: HttpRequestLike; requestInfo: TrustedRequestInfo; ctx?: Ctx; contract: C; path?: InferPath; query?: InferQuery; headers?: InferHeaders; body?: InferBody; response: HttpResponseLike; error?: unknown; /** * True when the route returned a native web Response. The response argument * is a headers-only view ({ status, headers }); the body is not readable and * returned body/status changes are ignored. Header changes are merged onto * the native Response. */ native?: boolean; }) => MaybePromise; /** * Per-stage timing breakdown of one request, in milliseconds. * * Stages are measured around the pipeline phases in execution order: * `onRequest` hooks, request parsing/validation, context creation, route * hooks plus `beforeHandle` hooks, the route handler, and response * preparation (`beforeSend`, response validation, and finalizers). Stages * that did not run for a request — parsing on raw routes, the handler after * a hook short-circuit — report `0`. The stages do not sum exactly to the * request `durationMs`; routing and bookkeeping live in the gaps. */ export type RequestStageTimings = { onRequestMs: number; parseMs: number; contextMs: number; beforeHandleMs: number; handlerMs: number; sendMs: number; }; /** * Hook that runs after the response has been prepared. * * This is for logging and observability. Errors thrown by `afterSend` hooks are * ignored by the server pipeline. */ export type AfterSendHook = (args: { req: HttpRequestLike; requestInfo: TrustedRequestInfo; ctx?: Ctx; contract: C; path?: InferPath; query?: InferQuery; headers?: InferHeaders; body?: InferBody; response: HttpResponseLike; error?: unknown; durationMs: number; /** * Per-stage timing breakdown of this request. */ stages: RequestStageTimings; }) => MaybePromise; /** * Hook notified when the framework catches an error while handling a request. */ export type ServerCaughtErrorHook = (args: { err: unknown; req: HttpRequestLike; requestInfo?: TrustedRequestInfo; ctx?: Ctx; contract: C; path?: InferPath; query?: InferQuery; headers?: InferHeaders; body?: InferBody; }) => MaybePromise; /** * Hook that may map an unexpected error to a custom response. * * Return `undefined` to let the server's default unhandled-error mapper create * the response. */ export type ServerUnhandledErrorMapper = (args: { err: unknown; req: HttpRequestLike; requestInfo?: TrustedRequestInfo; ctx?: Ctx; contract: C; path?: InferPath; query?: InferQuery; headers?: InferHeaders; body?: InferBody; }) => MaybePromise; /** * Server lifecycle hook collection. * * Hooks run in the order they are registered within each server-hook phase. * `onRequest` can short-circuit before context creation; route hooks resolve * route-scoped context before server `beforeHandle`; `beforeHandle` can replace * context or short-circuit; `beforeSend` can replace the outgoing response, and * route-owned replacements are contract-validated before send; `afterSend` * observes the final response. */ export interface ServerHook { /** * Optional name used in diagnostics and devtools. */ name?: string; /** * Validates the hook configuration against the registered contracts. * * Invoked once at startup, right after `createServer(...)` collects the * contracts from the `routes` option and before provider setup. Throw to * fail startup instead of degrading silently at request time. Contracts * registered later through `server.route(...)` are not seen here, so hooks * that need full coverage should keep a runtime check as a backstop. */ validate?: (args: { contracts: readonly HttpContractConfig[]; /** * Server-level trusted-proxy policy. Request phases receive its resolved * value as `requestInfo`. */ trustedProxy?: TrustedProxyConfig; }) => void; /** * Runs after route matching and before body/query/header parsing. */ onRequest?: OnRequestHook; /** * Runs after request parsing, context creation, and route hook resolution. */ beforeHandle?: BeforeHandleHook; /** * Runs before the response is returned. Native web `Response` results get a * headers-only view with `native: true`. */ beforeSend?: BeforeSendHook; /** * Observes the final response after send preparation. */ afterSend?: AfterSendHook; /** * Observes framework-caught errors. */ onCaughtError?: ServerCaughtErrorHook; /** * Maps unexpected errors to responses. */ mapUnhandledError?: ServerUnhandledErrorMapper; } /** * Compiled route entry used by server internals and adapter helpers. */ export type ResolvedRoute<_Ctx, C extends HttpContractConfig> = { /** * Contract config for the route. */ contract: C; /** * Handler that receives the raw request and optional path params. */ handler: (req: HttpRequestLike, params?: Record) => Promise; /** * Test whether the route matches an incoming method and pathname. */ match: (method: string, pathname: string) => { matched: true; } | { matched: false; }; }; export {}; //# sourceMappingURL=http.d.ts.map