@btravstack/http-server / index
index
Classes
AuthenticatorUnavailable
Defined in: packages/http-server/src/auth.ts:31
Authentication cannot decide because its dependency is unavailable. Carries no credential details.
Extends
TaggedErrorInstance<"AuthenticatorUnavailable", { }>
Constructors
Constructor
new AuthenticatorUnavailable(args): AuthenticatorUnavailable;Defined in: node_modules/.pnpm/unthrown@5.12.1/node_modules/unthrown/dist/index.d.mts:2386
Parameters
| Parameter | Type |
|---|---|
args | void |
Returns
Inherited from
TaggedError("AuthenticatorUnavailable").constructor
Properties
CredentialRefused
Defined in: packages/http-server/src/auth.ts:28
A credential the caller presented was refused — a capability URL whose signature does not verify, or that has expired. Distinct from Unauthenticated because a login cannot help: the walk answers it as UnderScoped, 403, unless another requirement accepts the caller. Carries nothing, for Unauthenticated's reason.
Extends
TaggedErrorInstance<"CredentialRefused", { }>
Constructors
Constructor
new CredentialRefused(args): CredentialRefused;Defined in: node_modules/.pnpm/unthrown@5.12.1/node_modules/unthrown/dist/index.d.mts:2386
Parameters
| Parameter | Type |
|---|---|
args | void |
Returns
Inherited from
TaggedError("CredentialRefused").constructor
Properties
HttpChallenges
Defined in: packages/http-server/src/protected-resource.ts:56
The challenges a 401 carries, one member per composed surface. Protected resources also identify their metadata for typed Bearer scope refusals. httpServer contributes the empty member that keeps the set from being the empty dependency di refuses; an empty challenge is dropped, so a graph composing no protected resource sends no header.
A set port for CookieSchemes' reason: the runtime never sees what the root provides beside it, so the header is a fact about the graph.
Extends
PortInstance<"HttpChallenges", readonly ( |HttpChallenge|HttpRequestChallenge)[]> &object
Constructors
Constructor
new HttpChallenges(): HttpChallenges;Defined in: packages/di/dist/index.d.mts:29
Returns
Inherited from
Port.many("HttpChallenges")<HttpChallenge | HttpRequestChallenge>.constructor
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
[ID] | readonly | "HttpChallenges" | Port.many("HttpChallenges").[ID] | packages/di/dist/index.d.mts:11 |
[MANY] | readonly | true | Port.many("HttpChallenges").[MANY] | packages/di/dist/index.d.mts:30 |
[SERVICE] | readonly | readonly ( | HttpChallenge | HttpRequestChallenge)[] | Port.many("HttpChallenges").[SERVICE] | packages/di/dist/index.d.mts:12 |
many | static readonly | true | Port.many("HttpChallenges").many | packages/di/dist/index.d.mts:33 |
portId | static readonly | "HttpChallenges" | Port.many("HttpChallenges").portId | packages/di/dist/index.d.mts:32 |
HttpConfig
Defined in: packages/http-server/src/http-config.ts:10
What the transport is bound and configured with, as a service: the starter binds it from PORT (default 3000; 0 lets the OS pick), HOST (default 0.0.0.0), HTTP_BODY_LIMIT, HTTP_STREAM_BODY_LIMIT, HTTP_CORS_ORIGIN, HTTP_COMPRESSION, HTTP_HEADERS_TIMEOUT_MS and HTTP_REQUEST_TIMEOUT_MS, each pinned by the matching option, and anything else in the graph may read it.
Extends
PortInstance<"HttpConfig", {bodyLimit:number;compression:boolean;corsOrigin:string;headersTimeoutMs:number;hostname:string;port:number;requestTimeoutMs:number;streamBodyLimit:number; }>
Constructors
Constructor
new HttpConfig(): HttpConfig;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
Port("HttpConfig")<{ readonly port: number; readonly hostname: string; /** The largest request body a procedure reads, in bytes; `0` is unbounded. */ readonly bodyLimit: number; /** * The largest request body a route reads as a stream, in bytes; `0` is * unbounded. Counted while the body streams, never buffered. */ readonly streamBodyLimit: number; /** Comma-separated allowed origins, or `*`. Empty is "the deployment said nothing". */ readonly corsOrigin: string; readonly compression: boolean; /** * How long a client may take to send a request's headers, in ms; the listener * answers `408` past it. As configured: a value above `requestTimeoutMs` is held * to it by the listener, so the effective bound is the smaller of the two. */ readonly headersTimeoutMs: number; /** How long a client may take to send a whole request, headers and body, in ms; `408` past it. */ readonly requestTimeoutMs: number; }>.constructor
Properties
| Property | Modifier | Type | Description | Inherited from | Defined in |
|---|---|---|---|---|---|
[ID] | readonly | "HttpConfig" | - | Port("HttpConfig").[ID] | packages/di/dist/index.d.mts:11 |
[SERVICE] | readonly | object | - | Port("HttpConfig").[SERVICE] | packages/di/dist/index.d.mts:12 |
[SERVICE].bodyLimit | readonly | number | The largest request body a procedure reads, in bytes; 0 is unbounded. | - | packages/http-server/src/http-config.ts:14 |
[SERVICE].compression | readonly | boolean | - | - | packages/http-server/src/http-config.ts:22 |
[SERVICE].corsOrigin | readonly | string | Comma-separated allowed origins, or *. Empty is "the deployment said nothing". | - | packages/http-server/src/http-config.ts:21 |
[SERVICE].headersTimeoutMs | readonly | number | How long a client may take to send a request's headers, in ms; the listener answers 408 past it. As configured: a value above requestTimeoutMs is held to it by the listener, so the effective bound is the smaller of the two. | - | packages/http-server/src/http-config.ts:28 |
[SERVICE].hostname | readonly | string | - | - | packages/http-server/src/http-config.ts:12 |
[SERVICE].port | readonly | number | - | - | packages/http-server/src/http-config.ts:11 |
[SERVICE].requestTimeoutMs | readonly | number | How long a client may take to send a whole request, headers and body, in ms; 408 past it. | - | packages/http-server/src/http-config.ts:30 |
[SERVICE].streamBodyLimit | readonly | number | The largest request body a route reads as a stream, in bytes; 0 is unbounded. Counted while the body streams, never buffered. | - | packages/http-server/src/http-config.ts:19 |
portId | static readonly | "HttpConfig" | - | Port("HttpConfig").portId | packages/di/dist/index.d.mts:16 |
HttpHandler
Defined in: packages/http-server/src/handler.ts:56
The HTTP surface as a SET port: every protocol served in this process contributes one member, and the runtime routes each request to the one whose prefix matches longest.
A set port rather than the single function it used to be, because HTTP is one transport carrying several protocols — oRPC here, GraphQL and htmx fragments beside it — while a graph holds exactly one runtime. They cannot be three runtimes; they are three answerers under one.
The runtime reaches them through Runtime.resolves rather than through di, because a member contributed by a SIBLING module is not visible from inside this one: start gates that the composition root exports this port, and HttpModule adds it to exports so an application never lists it.
Extends
PortInstance<"HttpHandler", readonlyHttpAnswerer[]> &object
Constructors
Constructor
new HttpHandler(): HttpHandler;Defined in: packages/di/dist/index.d.mts:29
Returns
Inherited from
Port.many("HttpHandler")<HttpAnswerer>.constructor
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
[ID] | readonly | "HttpHandler" | Port.many("HttpHandler").[ID] | packages/di/dist/index.d.mts:11 |
[MANY] | readonly | true | Port.many("HttpHandler").[MANY] | packages/di/dist/index.d.mts:30 |
[SERVICE] | readonly | readonly HttpAnswerer[] | Port.many("HttpHandler").[SERVICE] | packages/di/dist/index.d.mts:12 |
many | static readonly | true | HttpChallenges.many | packages/di/dist/index.d.mts:33 |
portId | static readonly | "HttpHandler" | Port.many("HttpHandler").portId | packages/di/dist/index.d.mts:32 |
HttpRequestMetadata
Defined in: packages/http-server/src/request-metadata.ts:10
Non-authentication metadata pinned to one HTTP request unit. Headers are an immutable snapshot; the signal is the runtime's cancellation signal. Values are untrusted input: decoding and authorization remain application policy.
Extends
PortInstance<"HttpRequestMetadata", {headers:Readonly<Record<string,string| readonlystring[] |undefined>>;method:string|undefined;signal:AbortSignal;url:string|undefined; }>
Constructors
Constructor
new HttpRequestMetadata(): HttpRequestMetadata;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
Port("HttpRequestMetadata")<{ readonly headers: Readonly<Record<string, string | readonly string[] | undefined>>; readonly method: string | undefined; readonly url: string | undefined; readonly signal: AbortSignal; }>.constructor
Properties
| Property | Modifier | Type | Inherited from | Defined in |
|---|---|---|---|---|
[ID] | readonly | "HttpRequestMetadata" | Port("HttpRequestMetadata").[ID] | packages/di/dist/index.d.mts:11 |
[SERVICE] | readonly | object | Port("HttpRequestMetadata").[SERVICE] | packages/di/dist/index.d.mts:12 |
[SERVICE].headers | readonly | Readonly<Record<string, string | readonly string[] | undefined>> | - | packages/http-server/src/request-metadata.ts:11 |
[SERVICE].method | readonly | string | undefined | - | packages/http-server/src/request-metadata.ts:12 |
[SERVICE].signal | readonly | AbortSignal | - | packages/http-server/src/request-metadata.ts:14 |
[SERVICE].url | readonly | string | undefined | - | packages/http-server/src/request-metadata.ts:13 |
portId | static readonly | "HttpRequestMetadata" | Port("HttpRequestMetadata").portId | packages/di/dist/index.d.mts:16 |
HttpRuntime
Defined in: packages/http-server/src/http-runtime.ts:138
The runtime's port: what the starter provides, and what HttpModule and GraphqlModule export for start to boot.
It resolves HttpHandler, which is why a root exporting it is now part of start's gate: the answerers are contributed by sibling modules — oRPC here, a fragment or GraphQL answerer beside it — so they are not visible from inside this module and have to be read out of the application context.
Extends
RuntimePort<Runtime<typeofHttpHandler,HttpInfo>>
Constructors
Constructor
new HttpRuntime(): HttpRuntime;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
RuntimePort<Runtime<typeof HttpHandler, HttpInfo>>.constructor
Properties
ProtectedResource
Defined in: packages/http-server/src/protected-resource.ts:212
What protectedResource was configured with, once the boot has checked it.
Extends
PortInstance<"HttpProtectedResource", {authorizationServers: readonlystring[];metadata:string;resource:string; }>
Constructors
Constructor
new ProtectedResource(): ProtectedResource;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
Port("HttpProtectedResource")<{ /** The resource identifier: the `aud` its tokens are minted for (RFC 8707). */ readonly resource: string; readonly authorizationServers: readonly string[]; /** Where the metadata document is served, as a client is told to fetch it. */ readonly metadata: string; }>.constructor
Properties
| Property | Modifier | Type | Description | Inherited from | Defined in |
|---|---|---|---|---|---|
[ID] | readonly | "HttpProtectedResource" | - | Port("HttpProtectedResource").[ID] | packages/di/dist/index.d.mts:11 |
[SERVICE] | readonly | object | - | Port("HttpProtectedResource").[SERVICE] | packages/di/dist/index.d.mts:12 |
[SERVICE].authorizationServers | readonly | readonly string[] | - | - | packages/http-server/src/protected-resource.ts:215 |
[SERVICE].metadata | readonly | string | Where the metadata document is served, as a client is told to fetch it. | - | packages/http-server/src/protected-resource.ts:217 |
[SERVICE].resource | readonly | string | The resource identifier: the aud its tokens are minted for (RFC 8707). | - | packages/http-server/src/protected-resource.ts:214 |
portId | static readonly | "HttpProtectedResource" | - | Port("HttpProtectedResource").portId | packages/di/dist/index.d.mts:16 |
ProtectedResourcePerHost
Defined in: packages/http-server/src/protected-resource.ts:475
What protectedResourcePerHost was configured with, once the boot has checked it.
Extends
PortInstance<"HttpProtectedResourcePerHost", {authorizationServers: readonlystring[];path:string; }>
Constructors
Constructor
new ProtectedResourcePerHost(): ProtectedResourcePerHost;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
Port("HttpProtectedResourcePerHost")<{ /** The resource's path on every served host, as the URL parser spells it. */ readonly path: string; readonly authorizationServers: readonly string[]; }>.constructor
Properties
| Property | Modifier | Type | Description | Inherited from | Defined in |
|---|---|---|---|---|---|
[ID] | readonly | "HttpProtectedResourcePerHost" | - | Port("HttpProtectedResourcePerHost").[ID] | packages/di/dist/index.d.mts:11 |
[SERVICE] | readonly | object | - | Port("HttpProtectedResourcePerHost").[SERVICE] | packages/di/dist/index.d.mts:12 |
[SERVICE].authorizationServers | readonly | readonly string[] | - | - | packages/http-server/src/protected-resource.ts:478 |
[SERVICE].path | readonly | string | The resource's path on every served host, as the URL parser spells it. | - | packages/http-server/src/protected-resource.ts:477 |
portId | static readonly | "HttpProtectedResourcePerHost" | - | Port("HttpProtectedResourcePerHost").portId | packages/di/dist/index.d.mts:16 |
ServedHosts
Defined in: packages/http-server/src/protected-resource.ts:470
Whether this deployment serves a host — usually a domain a tenant verified, kept in the application's own data. Asked with the host as the URL parser spells it: lowercase, punycode, the scheme's default port dropped and any other port kept (tenant-a.example, localhost:3000), and the request unit's signal, aborted once the unit settles — a client that left included — so a query can be cancelled.
Extends
PortInstance<"HttpServedHosts", (host,signal) =>AsyncResult<boolean,never>>
Constructors
Constructor
new ServedHosts(): ServedHosts;Defined in: packages/di/dist/index.d.mts:15
Returns
Inherited from
Port("HttpServedHosts")<(host: string, signal: AbortSignal) => AsyncResult<boolean, never>>.constructor
Properties
Unauthenticated
Defined in: packages/http-server/src/auth.ts:19
A caller was refused. Carries nothing: the starter surfaces no reason — a rejected caller gets an UNAUTHORIZED and oRPC's default message — so a payload here would be write-only.
An authenticator that wants to record why reports it to Observers before returning this — jwtAuthenticator is the worked case, and note WHAT it records: a refusal its DEPENDENCY caused, never one the caller's credential caused. A line per refused credential is how a scanner writes an application's logs for it.
Extends
TaggedErrorInstance<"Unauthenticated", { }>
Constructors
Constructor
new Unauthenticated(args): Unauthenticated;Defined in: node_modules/.pnpm/unthrown@5.12.1/node_modules/unthrown/dist/index.d.mts:2386
Parameters
| Parameter | Type |
|---|---|
args | void |
Returns
Inherited from
TaggedError("Unauthenticated").constructor
Properties
UnderScoped
Defined in: packages/http-server/src/auth.ts:39
A credential was valid but lacks one or more scopes the endpoint declared, or a scheme refused a credential the caller presented (CredentialRefused). Distinct from Unauthenticated because the answers differ: an anonymous caller gets 401, a refused one 403.
Extends
TaggedErrorInstance<"UnderScoped", { }>
Constructors
Constructor
new UnderScoped(scopes?): UnderScoped;Defined in: packages/http-server/src/auth.ts:43
Parameters
| Parameter | Type |
|---|---|
scopes? | readonly string[] |
Returns
Overrides
TaggedError("UnderScoped").constructor
Properties
| Property | Modifier | Type | Description | Inherited from | Defined in |
|---|---|---|---|---|---|
_tag | readonly | "UnderScoped" | - | TaggedError("UnderScoped")._tag | node_modules/.pnpm/unthrown@5.12.1/node_modules/unthrown/dist/index.d.mts:2363 |
cause? | public | unknown | - | TaggedError("UnderScoped").cause | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es2022.error.d.ts:24 |
message | public | string | - | TaggedError("UnderScoped").message | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1075 |
name | public | string | - | TaggedError("UnderScoped").name | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1074 |
scopes | readonly | readonly string[] | undefined | One sufficient Bearer alternative, in declaration order; absent for other credentials. | - | packages/http-server/src/auth.ts:41 |
stack? | public | string | - | TaggedError("UnderScoped").stack | node_modules/.pnpm/typescript@6.0.3/node_modules/typescript/lib/lib.es5.d.ts:1076 |
Type Aliases
ApiKey
type ApiKey<P> = object;Defined in: packages/http-server/src/api-key.ts:16
One issued key, and what presenting it makes the caller.
scopes is the only place a scope is written: the scheme's vocabulary is the union of what its keys grant, inferred rather than declared a second time as a type argument. A vocabulary stated separately could name a scope no key grants, which passes ScopeGate and then refuses every caller with a permanent 403 — the failure that gate exists to catch, one layer up.
Type Parameters
| Type Parameter |
|---|
P |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
key | readonly | string | - | packages/http-server/src/api-key.ts:17 |
principal | readonly | P | - | packages/http-server/src/api-key.ts:18 |
scopes? | readonly | readonly string[] | What this key grants, checked against the endpoint's declared scopes by the existing 403 path. | packages/http-server/src/api-key.ts:20 |
ApiKeyOptions
type ApiKeyOptions<P, Keys> = object;Defined in: packages/http-server/src/api-key.ts:23
Type Parameters
| Type Parameter |
|---|
P |
Keys extends readonly ApiKey<P>[] |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
header? | readonly | string | Which header carries the key. Default x-api-key. | packages/http-server/src/api-key.ts:25 |
keys | readonly | Keys | - | packages/http-server/src/api-key.ts:26 |
Authenticator
type Authenticator<P, Scope, N, E> = object;Defined in: packages/http-server/src/auth.ts:205
What HttpAuthenticator hands back: a description defineHttp binds to a port once the scheme name is known, carrying its principal and scope types so the registry can be inferred rather than declared.
Type Parameters
| Type Parameter | Default type |
|---|---|
P | - |
Scope extends string | - |
N | - |
E | never |
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
cookie? | readonly | true | Set by a scheme that resolves a caller from a cookie, which is what makes a deployment a CSRF target: defineHttp turns it into a CookieSchemes member, and the HTTP runtime's csrf default is "any member". Absent on a scheme reading a header, where ambient authority is not in play. | packages/http-server/src/auth.ts:218 |
error | readonly | E | - | packages/http-server/src/auth.ts:210 |
needs | readonly | N | - | packages/http-server/src/auth.ts:209 |
options | readonly | unknown | - | packages/http-server/src/auth.ts:206 |
principal | readonly | P | - | packages/http-server/src/auth.ts:207 |
scope | readonly | Scope | - | packages/http-server/src/auth.ts:208 |
Authenticators
type Authenticators = Readonly<Record<string, Authenticator<unknown, string, unknown, unknown>>>;Defined in: packages/http-server/src/define-auth.ts:13
The authenticators an application declares, keyed by scheme name.
AuthenticatorService
type AuthenticatorService<P, Scope> = ((headers, query) => AsyncResult<Granted<P, Scope>,
| Unauthenticated
| CredentialRefused
| AuthenticatorUnavailable>) & object;Defined in: packages/http-server/src/auth.ts:116
Headers and the URL's query, not the request: an authenticator has no business reading a body, and the narrower arguments are what keep it testable without a socket. The query carries a credential a browser follows as a plain link — a capability URL's signed grant — where no header can.
Type Parameters
| Type Parameter | Default type |
|---|---|
P | - |
Scope extends string | never |
Type Declaration
| Name | Type | Description | Defined in |
|---|---|---|---|
bearer? | true | Verifies an RFC 6750 Bearer credential from Authorization. | packages/http-server/src/auth.ts:124 |
Grant
type Grant<P, Scope> = object;Defined in: packages/http-server/src/auth.ts:62
The scoped answer, and the reason granted() is mandatory rather than advisory: the brand is what tells it from an identity that merely happens to carry a scopes field.
Type Parameters
| Type Parameter |
|---|
P |
Scope extends string |
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
[GRANT] | readonly | true | packages/http-server/src/auth.ts:65 |
identity | readonly | P | packages/http-server/src/auth.ts:63 |
scopes | readonly | readonly Scope[] | packages/http-server/src/auth.ts:64 |
Granted
type Granted<P, Scope> = [Scope] extends [never] ? P : Grant<P, Scope>;Defined in: packages/http-server/src/auth.ts:74
What an authenticator hands back. A scheme with no scope vocabulary returns the identity bare — byte-for-byte what applications write today — and one with a vocabulary reports what the credential actually granted, so the starter can compare it against what the endpoint declared.
Type Parameters
| Type Parameter |
|---|
P |
Scope extends string |
HttpAnswerer
type HttpAnswerer = object;Defined in: packages/http-server/src/handler.ts:25
One protocol's answer to HTTP, mounted under prefix.
Everything the client receives must be written from inside handle — the unit stays open until the response completes, so there is no way to be late. It returns PromiseLike<unknown> rather than void: the package needs to know when the handler is finished so it can answer a request the handler declined, and a void-returning handler writing asynchronously would draw a premature 404 over a response still in flight. unknown because oRPC's handle resolves { matched: boolean }; the value is never the unit's result, and the runtime reads "did you answer?" off the response rather than off this — which is what lets an answerer be written against node:http alone.
host is how an answerer opens the unit's scope for a request it handles — host.fork(module, seed), once, for a request this answerer is about to answer. The runtime's own 404 never forks: only an answerer that claims a request does.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
handle | readonly | (request, response, signal, host) => PromiseLike<unknown> | - | packages/http-server/src/handler.ts:33 |
prefix | readonly | `/${string}` | Where this answerer is mounted. It owns every path at or under it, and a request is routed to the LONGEST prefix that matches — so / may host a fragment answerer while /rpc hosts oRPC, and nesting is expected rather than refused. Two answerers on one prefix is a startup failure. | packages/http-server/src/handler.ts:32 |
HttpAuth
type HttpAuth<A> = object;Defined in: packages/http-server/src/define-auth.ts:33
Shared authentication registry consumed by any HTTP answerer.
Type Parameters
| Type Parameter |
|---|
A extends Authenticators |
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
authenticators | readonly | A | packages/http-server/src/define-auth.ts:34 |
principals | readonly | Principals<A> | packages/http-server/src/define-auth.ts:36 |
providers | readonly | readonly SchemeProviders<A>[] | packages/http-server/src/define-auth.ts:35 |
HttpChallenge
type HttpChallenge = object;Defined in: packages/http-server/src/protected-resource.ts:24
A WWW-Authenticate challenge, and the request whose refusals carry it: its scheme, host, path and query, as sent.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
resourceMetadata? | readonly | string | Metadata URL for typed Bearer scope refusals, set by protectedResource(). | packages/http-server/src/protected-resource.ts:28 |
target | readonly | string | - | packages/http-server/src/protected-resource.ts:25 |
value | readonly | string | - | packages/http-server/src/protected-resource.ts:26 |
HttpInfo
type HttpInfo = object;Defined in: packages/http-server/src/http-runtime.ts:38
What the runtime publishes once it is listening, read back through RunningApp.runtimeInfo().
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
port | readonly | number | packages/http-server/src/http-runtime.ts:38 |
HttpOptions
type HttpOptions = object;Defined in: packages/http-server/src/http-runtime.ts:51
The HTTP transport's options: orpc()'s own — where the router is mounted, and the transport policy — plus what a caller pins on the socket instead of reading it from the environment. Declared as one intersection so each option is spelled ONCE across the surfaces that take it (orpc(), HttpModule, GraphqlModule), which is what the six-concerns claim drifted against when they were three parallel records.
The router itself is not an option — it is the provider the composition root supplies on the starter's router port, which this module needs.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
bodyLimit? | readonly | number | false | - | packages/http-server/src/http-runtime.ts:53 |
compression? | readonly | boolean | object | - | packages/http-server/src/http-runtime.ts:62 |
cors? | readonly | boolean | object | - | packages/http-server/src/http-runtime.ts:52 |
csrf? | readonly | boolean | - | packages/http-server/src/http-runtime.ts:63 |
headersTimeoutMs? | readonly | number | Pins HttpConfig.headersTimeoutMs instead of reading HTTP_HEADERS_TIMEOUT_MS (default DEFAULT_HEADERS_TIMEOUT_MS): how long a client may take to send a request's headers before the listener answers 408 and closes the socket — the slow-header attack's bound. | packages/http-server/src/http-runtime.ts:74 |
hostname? | readonly | string | Pins HttpConfig.hostname instead of reading HOST. | packages/http-server/src/http-runtime.ts:67 |
port? | readonly | number | Pins HttpConfig.port instead of reading PORT. | packages/http-server/src/http-runtime.ts:65 |
requestTimeoutMs? | readonly | number | Pins HttpConfig.requestTimeoutMs instead of reading HTTP_REQUEST_TIMEOUT_MS (default DEFAULT_REQUEST_TIMEOUT_MS): how long a client may take to send a WHOLE request, body included. It bounds what the client sends, never the response, so a long-lived event stream is not cut by it. | packages/http-server/src/http-runtime.ts:82 |
securityHeaders? | readonly | boolean | Readonly<Record<string, string>> | Headers set on every response, before dispatch. true (default) applies DEFAULT_SECURITY_HEADERS; false disables the feature; a record replaces the defaults outright. Not a config field, deliberately: a deployment that can silently turn x-frame-options off is a footgun the other policies are not. | packages/http-server/src/http-runtime.ts:91 |
streamBodyLimit? | readonly | number | false | Pins HttpConfig.streamBodyLimit instead of reading HTTP_STREAM_BODY_LIMIT (default DEFAULT_STREAM_BODY_LIMIT): the largest body an oRPC route reads as a stream (requestBodyHint: "octet-stream"), in bytes, counted as it arrives; false pins the unbounded 0. Every other body stays under bodyLimit. | packages/http-server/src/http-runtime.ts:61 |
unit? | readonly | Readonly<Record<string, AnyUnitModule>> | The unit module each KIND binds: anonymous for a request no leaf asked to authenticate, else the scheme that resolved the caller. The answerers fork the one that matches — seeded, for a scheme, with that scheme's principal — as the request is taken, and tear it down when the unit closes, after the response is flushed. A kind that binds no module of its own falls back to anonymous, so binding that one alone keeps forking on every leaf. | packages/http-server/src/http-runtime.ts:100 |
HttpRequestChallenge
type HttpRequestChallenge = object;Defined in: packages/http-server/src/protected-resource.ts:38
A challenge whose target depends on the request: resolve answers it, or undefined for none, and is asked only for a request whose path, as sent, is path — settled before dispatch, so no other request waits on it. It is handed the unit's signal; a client that leaves first settles the unit without waiting for it, and nothing is dispatched.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
path | readonly | string | packages/http-server/src/protected-resource.ts:39 |
resolve | readonly | (request, signal) => AsyncResult<HttpChallenge | undefined, never> | packages/http-server/src/protected-resource.ts:40 |
Kinds
type Kinds<A> = "anonymous" | keyof A & string;Defined in: packages/http-server/src/unit.ts:38
Every kind a unit may be opened under: no credential, or the scheme that resolved one.
Type Parameters
| Type Parameter |
|---|
A |
Principal
type Principal<S, Schemes> = [S] extends [never] ? never : [S] extends [keyof Schemes] ? IsUnion<S> extends true ? Tagged<S & keyof Schemes, Schemes> : Schemes[S & keyof Schemes] : never;Defined in: packages/http-server/src/principal.ts:30
What a leaf's handler reads. Bare when its requirements name one scheme — byte-for-byte what applications write today, so the common case pays nothing for the feature — and a discriminated union when they name several.
Type Parameters
| Type Parameter |
|---|
S extends string |
Schemes |
Principals
type Principals<A> = { readonly [K in keyof A & string]: PortClassOf<`HttpPrincipal:${K}`, A[K]["principal"]> };Defined in: packages/http-server/src/define-auth.ts:28
Type Parameters
| Type Parameter |
|---|
A extends Authenticators |
ProtectedResourceOptions
type ProtectedResourceOptions = object;Defined in: packages/http-server/src/protected-resource.ts:220
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
allowInsecure? | readonly | boolean | Accept an http: resource or authorization server that is NOT on a loopback host. Default false, and a ConfigInvalid at boot without it: a client follows these URLs with its credentials. | packages/http-server/src/protected-resource.ts:235 |
authorizationServers? | readonly | readonly string[] | Pins HTTP_RESOURCE_AUTHORIZATION_SERVERS: the issuers whose tokens it accepts. | packages/http-server/src/protected-resource.ts:227 |
resource? | readonly | string | Pins HTTP_RESOURCE_URI: this API's resource identifier, an https: URL — usually the audience its JWT scheme requires. | packages/http-server/src/protected-resource.ts:225 |
scopes? | readonly | readonly string[] | Advertised as scopes_supported. Omitted from the document when absent or empty. | packages/http-server/src/protected-resource.ts:229 |
ProtectedResourcePerHostOptions
type ProtectedResourcePerHostOptions = object;Defined in: packages/http-server/src/protected-resource.ts:481
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
allowInsecure? | readonly | boolean | Accept an http: authorization server, or an http: request target, that is NOT on a loopback host. Default false: a client follows these URLs with its credentials. | packages/http-server/src/protected-resource.ts:493 |
authorizationServers? | readonly | readonly string[] | Pins HTTP_RESOURCE_AUTHORIZATION_SERVERS: the issuers whose tokens it accepts. | packages/http-server/src/protected-resource.ts:485 |
path? | readonly | string | Pins HTTP_RESOURCE_PATH: the resource's path on every served host, /mcp for one. | packages/http-server/src/protected-resource.ts:483 |
scopes? | readonly | readonly string[] | Advertised as scopes_supported. Omitted from the document when absent or empty. | packages/http-server/src/protected-resource.ts:487 |
ProtectedResourcePerHostProvider
type ProtectedResourcePerHostProvider<O> = Provider<ProtectedResourcePerHost, ConfigInvalid, EnvReading<
| Unpinned<O, "path", "HTTP_RESOURCE_PATH">
| Unpinned<O, "authorizationServers", "HTTP_RESOURCE_AUTHORIZATION_SERVERS">,
| MaybePinned<O, "path", "HTTP_RESOURCE_PATH">
| MaybePinned<O, "authorizationServers", "HTTP_RESOURCE_AUTHORIZATION_SERVERS">>>;Defined in: packages/http-server/src/protected-resource.ts:499
The provider of ProtectedResourcePerHost, its variables required unless pinned.
Type Parameters
| Type Parameter |
|---|
O |
ProtectedResourceProvider
type ProtectedResourceProvider<O> = Provider<ProtectedResource, ConfigInvalid, EnvReading<
| Unpinned<O, "resource", "HTTP_RESOURCE_URI">
| Unpinned<O, "authorizationServers", "HTTP_RESOURCE_AUTHORIZATION_SERVERS">,
| MaybePinned<O, "resource", "HTTP_RESOURCE_URI">
| MaybePinned<O, "authorizationServers", "HTTP_RESOURCE_AUTHORIZATION_SERVERS">>>;Defined in: packages/http-server/src/protected-resource.ts:366
The provider of ProtectedResource, its variables required unless pinned.
Type Parameters
| Type Parameter |
|---|
O |
SchemesFrom
type SchemesFrom<A> = { readonly [K in keyof A]: A[K]["principal"] };Defined in: packages/http-server/src/define-auth.ts:17
Type Parameters
| Type Parameter |
|---|
A extends Authenticators |
SchemesOf
type SchemesOf<R> = { [I in keyof R]: keyof R[I] & string }[number];Defined in: packages/http-server/src/principal.ts:7
Type Parameters
| Type Parameter |
|---|
R extends Requirements |
UnitsOf
type UnitsOf<A> = Partial<Readonly<Record<Kinds<A>, AnyUnitModule>>>;Defined in: packages/http-server/src/unit.ts:46
The module bound per kind. Every member is optional, which makes this a weak type — so a kind the authenticators never declared is refused for having no property in common rather than passing an excess-property check that a type argument would not get.
Type Parameters
| Type Parameter |
|---|
A |
Functions
apiKeyAuthenticator()
function apiKeyAuthenticator<P>(): <Keys>(options) => Authenticator<P, ScopesOf<Keys>, never>;Defined in: packages/http-server/src/api-key.ts:79
An API-key scheme, with the constant-time compare people get wrong.
Three things it does that a hand-written one usually does not:
- It compares digests, not strings.
===on a secret leaks its prefix through timing, andtimingSafeEqualrefuses two buffers of different lengths — which would leak the key's LENGTH instead. Hashing first makes every comparison 32 bytes wide whatever was presented. - It checks every configured key, without an early return. A loop that
breaks on the first match takes longer for a key configured late, which is a slower oracle but an oracle. - A missing header takes the same path as a wrong key, so "no credential" and "bad credential" are not distinguishable by timing either. Both answer
Unauthenticated, which the starter turns into401; the endpoint's own scope check is what produces a403.
<!-- doctest: prelude import { apiKeyAuthenticator } from "@btravstack/http-server"; type ServiceIdentity = { readonly appId: string }; declare const env: { readonly REPORTING_KEY: string }; -->
export const serviceAuth = apiKeyAuthenticator<ServiceIdentity>()({
keys: [{ key: env.REPORTING_KEY, principal: { appId: "reporting" }, scopes: ["reports:read"] }],
});Keys come from the caller — an Env-bound config field, a secret store — because a key list in the image is a key list in the repository.
Type Parameters
| Type Parameter |
|---|
P |
Returns
<Keys>(options) => Authenticator<P, ScopesOf<Keys>, never>
authenticatorPort()
function authenticatorPort<S>(scheme): PortClassOf<`HttpAuthenticator:${S}`, AuthenticatorService<unknown, never>>;Defined in: packages/http-server/src/auth.ts:153
One port per scheme, its id carrying the scheme name. The service type is erased to AuthenticatorService<unknown>, since di identifies a port by id; the principal and scope types ride the description HttpAuthenticator returns.
The id is a LITERAL type, so a contract naming a scheme the registry has no authenticator for leaves that scheme's port unmet — di's own diagnostic, naming the port, rather than a gate this package writes.
Exported for the consumer defineHttp does not cover: a test substituting ONE scheme's authenticator provides its own on this port instead of minting a second registry.
Type Parameters
| Type Parameter |
|---|
S extends string |
Parameters
| Parameter | Type |
|---|---|
scheme | S |
Returns
PortClassOf<`HttpAuthenticator:${S}`, AuthenticatorService<unknown, never>>
defineAuth()
function defineAuth<A>(options?): HttpAuth<A>;Defined in: packages/http-server/src/define-auth.ts:39
Type Parameters
| Type Parameter | Default type |
|---|---|
A extends Readonly<Record<string, Authenticator<unknown, string, unknown, unknown>>> | Record<never, never> |
Parameters
| Parameter | Type |
|---|---|
options? | { authenticators: A; } |
options.authenticators | A |
Returns
HttpAuth<A>
granted()
function granted<P, Scope>(identity, scopes): Grant<P, Scope>;Defined in: packages/http-server/src/auth.ts:87
What a scoped scheme answers with:
OkAsync(granted({ userId }, ["orders:export"]));Scope is not inferred from the vocabulary — an empty grant would collapse it to never and take the return type back to the bare arm — so the array is what states it, checked against the vocabulary by the assignment.
Type Parameters
| Type Parameter | Default type |
|---|---|
P | - |
Scope extends string | never |
Parameters
| Parameter | Type |
|---|---|
identity | P |
scopes | readonly Scope[] |
Returns
Grant<P, Scope>
HttpAuthenticator()
function HttpAuthenticator<P, Scope>(): <D, O>(options) => Authenticator<P, Scope, InstanceType<D[keyof D]>, ErrorOfArm<O>>;Defined in: packages/http-server/src/auth.ts:284
The authenticator for one scheme, with its principal type — and the scopes it can grant — stated at the call:
export const userAuth = HttpAuthenticator<Identity, "orders:export">()({
inject: { verify: JwtVerifier },
sync: ({ verify }) => (headers) => verify(headers.authorization),
});
// An authenticator that reads nothing but the headers declares no deps:
export const serviceAuth = HttpAuthenticator<ServiceIdentity>()({
inject: {},
sync: () => (headers) => apiKey(headers["x-api-key"]),
});
// `make` where building the scheme can FAIL, and the failure is startup's:
export const jwtAuth = HttpAuthenticator<Identity>()({
inject: { env: Env },
make: ({ env }) => Config.parse("HttpJwt", schema)(env).map(verifier),
});sync and make are the same pair di's Provider has, and naming both is refused. make answers an AsyncResult, so its Err is the graph's — a scheme whose configuration is wrong fails the boot, still typed, rather than refusing every caller at runtime.
The type arguments are explicit rather than inferred from the arm: inference through a returned function's AsyncResult is where a principal silently widens to unknown. The scheme NAME is not stated here — it is the key this authenticator sits under in defineHttp({ authenticators }).
Type Parameters
| Type Parameter | Default type |
|---|---|
P | - |
Scope extends string | never |
Returns
<D, O>(options) => Authenticator<P, Scope, InstanceType<D[keyof D]>, ErrorOfArm<O>>
principalPort()
function principalPort<S, P>(scheme): PortClassOf<`HttpPrincipal:${S}`, P>;Defined in: packages/http-server/src/auth.ts:170
One port per scheme carrying that scheme's PRINCIPAL, so a unit module the kind binds may name it in needs and inject the caller it was opened for. Minted from the scheme name alone — the seed lands on it per unit.
Memoised on the same map as authenticatorPort, and for the same reason: defineHttp mints, a unit module depends, and a second Port(id) call would cost di's duplicate-id warning for what is the designed pattern.
Type Parameters
| Type Parameter | Default type |
|---|---|
S extends string | - |
P | unknown |
Parameters
| Parameter | Type |
|---|---|
scheme | S |
Returns
PortClassOf<`HttpPrincipal:${S}`, P>
protectedResource()
function protectedResource<O>(given?): readonly [ProtectedResourceProvider<O>, AnyProvider, AnyProvider];Defined in: packages/http-server/src/protected-resource.ts:404
This API as an OAuth 2.0 protected resource: it serves its Protected Resource Metadata (RFC 9728) and tells a refused caller where to find it, so a client that holds no token — an MCP client is the usual one — discovers which authorization server to sign in with.
export const Api = HttpModule("Api")({
router,
provides: [...protectedResource({ scopes: ["orders:read"] })],
});GET /.well-known/oauth-protected-resource<path>answers the document:resource,authorization_serversand, when given,scopes_supported.<path>is the resource identifier's own, so a resource athttps://api.test/mcpis described at/.well-known/oauth-protected-resource/mcp.- A
401for the resource's own URL carriesWWW-Authenticate: Bearer resource_metadata="<that URL>", whichever answerer refused — oRPC, GraphQL or fragments — without any of them knowing. Any other URL, a path below it or another query included, is another resource, whose metadata this is not (RFC 9728 §3.3).
It answers THREE providers, which is why it is spread: the configuration, the answerer and the HttpChallenges member.
Type Parameters
| Type Parameter | Default type |
|---|---|
O extends ProtectedResourceOptions | Record<never, never> |
Parameters
| Parameter | Type |
|---|---|
given? | O & OptionsAs<O, ProtectedResourceOptions> |
Returns
readonly [ProtectedResourceProvider<O>, AnyProvider, AnyProvider]
protectedResourcePerHost()
function protectedResourcePerHost<O>(given?): readonly [ProtectedResourcePerHostProvider<O>, Provider<HttpHandler, never,
| ProtectedResourcePerHost
| ServedHosts>, Provider<HttpChallenges, never,
| ProtectedResourcePerHost
| ServedHosts>];Defined in: packages/http-server/src/protected-resource.ts:556
This API as an OAuth 2.0 protected resource on every host the application serves — one resource per tenant domain, say — rather than on one configured URL: protectedResource's discovery, with the resource identifier <scheme>//<request host><path> derived per request.
export const Api = HttpModule("Api")({
router,
provides: [...protectedResourcePerHost({ path: "/mcp" }), servedHosts],
});The host is admitted only when ServedHosts answers true: an unserved host gets a 404 for the metadata document and no challenge, so a forged Host never mints discovery for a domain the application did not vouch for. It is asked at most once per request to the resource or its metadata, and only for those. Every matching rule of protectedResource's holds per host.
It answers THREE providers, which is why it is spread: the configuration, the answerer and the HttpChallenges member.
Type Parameters
| Type Parameter | Default type |
|---|---|
O extends ProtectedResourcePerHostOptions | Record<never, never> |
Parameters
| Parameter | Type |
|---|---|
given? | O & OptionsAs<O, ProtectedResourcePerHostOptions> |
Returns
readonly [ProtectedResourcePerHostProvider<O>, Provider<HttpHandler, never, | ProtectedResourcePerHost | ServedHosts>, Provider<HttpChallenges, never, | ProtectedResourcePerHost | ServedHosts>]
resolvePrincipal()
function resolvePrincipal(
requirements,
authenticators,
headers,
query?
): AsyncResult<unknown,
| AuthenticatorUnavailable
| UnderScoped
| Unauthenticated>;Defined in: packages/http-server/src/auth.ts:349
resolveScheme folded to what a handler is injected.
Parameters
| Parameter | Type |
|---|---|
requirements | Requirements |
authenticators | Readonly<Record<string, AuthenticatorService<unknown>>> |
headers | IncomingHttpHeaders |
query? | URLSearchParams |
Returns
AsyncResult<unknown, | AuthenticatorUnavailable | UnderScoped | Unauthenticated>