Reference
alien-middleware
Functions
chain
Create a middleware chain from an existing middleware or chain.
export function chain<T extends AnyMiddleware | null | undefined>(middleware: T): T extends AnyMiddlewareChain ? T : T extends Middleware ? RequestHandler<ApplyFirstMiddleware<T>> : never;
createContext
Create an alien-middleware request context from a Web Request.
export function createContext<TRuntime = unknown, TEnv extends object = any>({ host, request, }: CreateContextOptions<TRuntime>): RequestContext<TEnv, {}, TRuntime>;
filterRuntime
Continue only when context.host.runtime?.name matches the given runtime name.
export function filterRuntime<TRuntime extends {
name: string;
}>(name: TRuntime['name']): (ctx: RequestContext) => {
runtime: TRuntime;
};
toFetchHandler
Adapt a request handler into a fetch-compatible (request) => response function.
export function toFetchHandler<T extends MiddlewareTypes, TRequest extends Request = Request>(handler: RequestHandler<T>, options?: ToFetchHandlerOptions<T['runtime'], TRequest>): FetchHandler<TRequest>;
Classes
MiddlewareChain
Immutable list of request middleware with type metadata for inference.
export class MiddlewareChain<T extends MiddlewareTypes = any> {
/** This property won't exist at runtime. It contains type information for inference purposes. */
$MiddlewareChain: T;
/** The number of parameters when called as a function. */
readonly length: 1;
protected [kRequestChain]: RequestMiddleware[];
/** Number of request middleware functions in this chain. */
get middlewareCount(): number;
/**
* Add a request middleware to the end of the chain.
*
* If a middleware chain is given, its middlewares will be executed after any
* existing middlewares in this chain.
*
* @returns a new `MiddlewareChain` instance
*/
use<const TMiddleware extends ExtractMiddleware<this>>(middleware: TMiddleware | null): RequestHandler<ApplyMiddleware<this, TMiddleware>>;
/**
* Create a middleware function that encapsulates this middleware chain, so
* any modifications it makes to the request context are not leaked.
*/
isolate(): (ctx: IsolatedContext<this>) => Awaitable<Response | void>;
/**
* @internal You should not need to call this method, unless you want a
* `RequestHandler` type from an empty middleware chain. If your middleware
* chain is **not** empty, you won't need this.
*/
toHandler<T2 extends MiddlewareTypes = T>(): RequestHandler<T2>;
}
Constants
kRequestChain
Symbol key for a chain's internal request middleware list.
const kRequestChain: unique symbol;
Types
AnyMiddleware
Any request middleware function or middleware chain.
export type AnyMiddleware = Middleware | AnyMiddlewareChain;
AnyMiddlewareChain
A value with middleware-chain type metadata.
export type AnyMiddlewareChain<T extends AnyMiddlewareTypes = AnyMiddlewareTypes> = {
$MiddlewareChain: T;
};
🔍 AnyMiddlewareChain on GitHub
AnyMiddlewareTypes
Type metadata for any middleware chain.
type AnyMiddlewareTypes = {
initial: {
env: any;
properties: any;
};
current: {
env: any;
properties: any;
};
runtime: any;
};
🔍 AnyMiddlewareTypes on GitHub
ApplyFirstMiddleware
Convert a Middleware type into a MiddlewareTypes type.
type ApplyFirstMiddleware<T extends AnyMiddleware> = T extends AnyMiddlewareChain<infer TInternal> ? TInternal : ApplyMiddleware<EmptyMiddlewareChain<MiddlewareRuntime<T>>, T>;
🔍 ApplyFirstMiddleware on GitHub
ApplyMiddleware
This applies a middleware to a chain. If the type TSecond is itself a
chain, it's treated as a nested chain, which won't leak its plugins into the
parent chain.
The TFirst type is allowed to be never, which results in the middleware's
output types being used as the request handler's input types.
export type ApplyMiddleware<TFirst extends AnyMiddlewareChain, TSecond extends AnyMiddleware> = ApplyMiddlewareOutputs<TFirst, TSecond> extends infer TCurrent extends MiddlewareTypes['current'] & {
runtime: unknown;
} ? {
initial: CastNever<Inputs<TFirst>, MiddlewareInputs<TSecond>>;
current: Pick<TCurrent, 'env' | 'properties'>;
runtime: TCurrent['runtime'];
} : never;
ApplyMiddlewareOutputs
Outputs produced after appending one middleware or chain to another.
type ApplyMiddlewareOutputs<TFirst extends AnyMiddlewareChain, TSecond extends AnyMiddleware> = TSecond extends AnyMiddlewareChain ? {
env: Merge<Env<TFirst>, Env<TSecond>>;
properties: Merge<Properties<TFirst>, Properties<TSecond>>;
runtime: Runtime<TSecond>;
} : TSecond extends (...args: any[]) => Awaitable<infer TResult> ? ApplyMiddlewareResult<TFirst, Exclude<TResult, Response>> : Current<TFirst> & {
runtime: Runtime<TFirst>;
};
🔍 ApplyMiddlewareOutputs on GitHub
ApplyMiddlewareResult
Merge a request plugin into a middleware chain.
type ApplyMiddlewareResult<TParent extends AnyMiddlewareChain, TResult> = Eval<{
env: Merge<Env<TParent>, TResult extends {
env: infer TEnv extends object | undefined;
} ? TEnv : undefined>;
properties: Merge<Properties<TParent>, TResult extends RequestPlugin ? Omit<TResult, keyof ReservedProperties> : undefined>;
runtime: [TResult] extends [never] ? Runtime<TParent> : TResult extends {
runtime: infer TRuntime;
} ? TRuntime : Runtime<TParent>;
}>;
🔍 ApplyMiddlewareResult on GitHub
ApplyMiddlewares
Flatten a list of middlewares into a MiddlewareTypes type.
export type ApplyMiddlewares<T extends AnyMiddleware[]> = T extends [
...infer TRest extends AnyMiddleware[],
infer TLast extends AnyMiddleware
] ? ApplyMiddleware<MiddlewareChain<ApplyMiddlewares<TRest>>, TLast> : ApplyFirstMiddleware<T[0]>;
Awaitable
A value that may be returned synchronously or through a promise.
type Awaitable<T> = T | Promise<T>;
CastNever
Replace never with a fallback type.
type CastNever<T, U> = [T] extends [never] ? U : T;
CreateContextOptions
Options for creating a request context from a Web Request.
export interface CreateContextOptions<TRuntime = unknown> {
request: Request;
host?: RequestHost<TRuntime> | undefined;
}
Properties
requestThe Web request being handled.hostOptional host metadata and hooks available to middleware.
🔍 CreateContextOptions on GitHub
Current
Outputs provided by the end of a middleware chain.
type Current<T extends AnyMiddlewareChain> = T['$MiddlewareChain']['current'];
EmptyMiddlewareChain
Empty chain type used when starting from no middleware.
export type EmptyMiddlewareChain<TRuntime = unknown> = MiddlewareChain<{
initial: {
env: {};
properties: {};
};
current: {
env: {};
properties: {};
};
runtime: TRuntime;
}>;
🔍 EmptyMiddlewareChain on GitHub
Env
Environment variables provided by the end of a middleware chain.
type Env<T extends AnyMiddlewareChain> = Current<T>['env'];
EnvAccessor
The context.env method used to access environment variables.
export type EnvAccessor<TEnv extends object> = {
<K extends keyof TEnv>(key: Extract<K, string>): TEnv[K];
(key: never): string | undefined;
};
Eval
Expand an object or intersection type into a readable property map.
type Eval<T> = {} & {
[K in keyof T]: T[K] extends infer U ? U : never;
};
ExtractMiddleware
Extract a Middleware type from a MiddlewareChain type.
export type ExtractMiddleware<T extends AnyMiddleware> = [T] extends [never] ? Middleware<{}, {}, any> : T extends AnyMiddlewareChain ? Middleware<Env<T>, Properties<T>, Runtime<T>> : T extends Middleware ? Extract<T, Middleware> : never;
FetchHandler
A fetch-compatible request handler.
export type FetchHandler<TRequest extends Request = Request> = (request: TRequest) => Awaitable<Response>;
InputEnv
Environment variables required by the start of a middleware chain.
type InputEnv<T extends AnyMiddlewareChain> = Inputs<T>['env'];
InputProperties
Context properties required by the start of a middleware chain.
type InputProperties<T extends AnyMiddlewareChain> = Inputs<T>['properties'];
Inputs
Inputs required by the start of a middleware chain.
type Inputs<T extends AnyMiddlewareChain> = T['$MiddlewareChain']['initial'];
IsolatedContext
Context visible inside a chain wrapped with MiddlewareChain.isolate().
type IsolatedContext<T extends AnyMiddlewareChain> = RequestContext<InputEnv<T>, InputProperties<T>, Runtime<T>>;
IsOptional
Detect whether a key is optional on an object type.
type IsOptional<T, K> = K extends keyof T ? T[K] extends Required<T>[K] ? false : true : true;
Keys
Collect keys from each object in a union.
type Keys<T> = T extends any ? keyof T : never;
Merge
Merge a union of object types (possibly undefined) into a single object type.
FIXME: Optional properties resolve as foo: Foo | undefined instead of foo?: Foo.
type Merge<TSource extends object, TOverrides extends object | undefined> = Eval<Omit<CastNever<TSource, {}>, Keys<TOverrides>> & {
[K in Keys<TOverrides>]: TOverrides extends any ? MergeProperty<CastNever<TSource, {}>, TOverrides, K> : never;
}>;
MergeProperty
Resolve one property after applying an override object to a source object.
type MergeProperty<TSource, TOverrides, K> = (K extends keyof TOverrides ? PossiblyUndefined<TOverrides, K> extends true ? TOverrides[K] : Exclude<TOverrides[K], undefined> : never) | (IsOptional<TOverrides, K> extends true ? K extends keyof TSource ? TSource[K] : undefined : never) extends infer TProperty ? TProperty : never;
Middleware
Middleware that can end the request or extend the downstream context.
export type Middleware<TEnv extends object = any, TProperties extends object = {}, TRuntime = any> = {
(context: RequestContext<TEnv, TProperties, TRuntime>): Awaitable<Response | RequestPlugin | void>;
$Middleware?: MiddlewareTypes & {
initial: {
env: TEnv;
properties: TProperties;
};
};
};
Remarks
Return a Response to stop request-phase processing, return a
RequestPlugin to add context data for later middleware, or return nothing
to continue unchanged. Use context.onResponse or a plugin onResponse
property to observe or replace the final response.
Properties
$MiddlewareThis property won't exist at runtime. It contains type information for inference purposes.
MiddlewareContext
Extract a RequestContext type from a MiddlewareChain type.
When type T is never, a default context is returned.
export type MiddlewareContext<T extends AnyMiddlewareChain | AnyMiddleware[]> = [
T
] extends [never] ? RequestContext<{}, never, unknown> : T extends AnyMiddlewareChain ? RequestContext<Env<T>, Properties<T>, Runtime<T>> : T extends AnyMiddleware[] ? MiddlewareContext<MiddlewareChain<ApplyMiddlewares<T>>> : never;
MiddlewareInputs
Inputs required by a middleware or chain.
type MiddlewareInputs<T extends AnyMiddleware> = T extends AnyMiddlewareChain ? Inputs<T> : T extends Middleware<infer TEnv, infer TProperties> ? {
env: TEnv;
properties: TProperties;
} : never;
MiddlewareRuntime
Runtime type associated with a middleware or chain.
type MiddlewareRuntime<T extends AnyMiddleware> = T extends AnyMiddlewareChain ? Runtime<T> : T extends Middleware<any, any, infer TRuntime> ? TRuntime : never;
MiddlewareTypes
Type metadata carried by middleware chains and handlers.
export type MiddlewareTypes<TEnv extends object = object, TProperties extends object = object, TRuntime = unknown> = {
initial: {
env: TEnv;
properties: TProperties;
};
current: {
env: TEnv;
properties: TProperties;
};
runtime: TRuntime;
};
Properties
initialValues expected by the start of the chain.currentValues provided by the end of the chain.runtimeValues from the host runtime.
PossiblyUndefined
Detect whether a property type accepts undefined.
type PossiblyUndefined<T, K extends keyof T> = undefined extends Required<T>[K] ? true : false;
Properties
Context properties provided by the end of a middleware chain.
type Properties<T extends AnyMiddlewareChain> = Current<T>['properties'];
RequestContext
An extensible Web request context object.
NOTE: When using this type on the right side of an extends clause, you
should prefer RequestContext<any> over RequestContext (no type
parameters), as the default type is stricter.
export type RequestContext<TEnv extends object = any, TProperties extends object = {}, TRuntime = any> = WebRequestContext<TRuntime, TEnv> & CastNever<TProperties, unknown>;
RequestHandler
Callable middleware chain that always resolves to a Response.
export interface RequestHandler<T extends MiddlewareTypes = any> extends MiddlewareChain<T> {
(context: RequestContext<any, any, T['runtime']>): Awaitable<Response>;
}
RequestHost
Host-provided request metadata and lifecycle hooks.
export interface RequestHost<TRuntime = unknown> {
env?(variable: string): unknown;
ip?: string;
runtime?: TRuntime;
waitUntil?(promise: Promise<unknown>): void;
}
Properties
envRead an environment variable supplied by the host.ipClient IP address supplied by the host, when available.runtimeRuntime-specific host metadata, such as srvx runtime details.waitUntilSchedule work that should continue after a response is produced.
RequestHostFactory
Build host metadata for each request passed to a fetch handler.
export type RequestHostFactory<TRuntime = unknown, TRequest extends Request = Request> = (request: TRequest) => RequestHost<TRuntime> | undefined;
🔍 RequestHostFactory on GitHub
RequestMiddleware
A middleware function that runs before a response is finalized.
export type RequestMiddleware<T extends AnyMiddlewareChain = MiddlewareChain> = (context: RequestContext<InputEnv<T>, InputProperties<T>, Runtime<T>>) => Awaitable<Response | RequestPlugin | void>;
RequestPlugin
The object returned by a request middleware and merged into the active request context for downstream middleware.
May contain special properties:
env: Add type-safe environment variables.runtime: Narrowcontext.host.runtimeat the type level.onResponse: Register a response callback.
export type RequestPlugin = Record<string, unknown> & ReservedProperties;
Remarks
Plain properties are defined on the request context. If a later plugin uses the same property name, the later descriptor replaces the earlier one.
ReservedProperties
Special request plugin keys consumed by the middleware runner.
type ReservedProperties = {
env?: object;
runtime?: object;
onResponse?: ResponseCallback;
};
Properties
envAdd type-safe environment variables. These are accessed with theenv()method on the request context.runtimeNarrowcontext.host.runtimefor downstream middleware.onResponseIntercept the response before it's sent to the client.
🔍 ReservedProperties on GitHub
ResponseCallback
Callback that observes or replaces the generated response.
export type ResponseCallback = (response: Response) => Awaitable<Response | void>;
Runtime
Host runtime data carried through a middleware chain.
type Runtime<T extends AnyMiddlewareChain> = T['$MiddlewareChain']['runtime'];
ToFetchHandlerOptions
Options used when adapting a request handler into a fetch handler.
export interface ToFetchHandlerOptions<TRuntime = unknown, TRequest extends Request = Request> {
host?: RequestHost<TRuntime> | RequestHostFactory<TRuntime, TRequest> | undefined;
}
Properties
hostStatic host metadata or a per-request host metadata factory.
🔍 ToFetchHandlerOptions on GitHub
WebRequestContext
Base Web request context shared by all middleware.
export interface WebRequestContext<TRuntime, TEnv extends object> {
request: Request;
host: RequestHost<TRuntime>;
env: EnvAccessor<TEnv>;
passThrough(): never;
waitUntil(promise: Promise<unknown>): void;
url: URL;
setHeader(name: string, value: string): void;
onResponse(callback: ResponseCallback): void;
}
Properties
requestThe Web request currently being handled.hostHost metadata and lifecycle hooks for the current request.envType-safe access to environment values.passThroughSkip the remaining middleware in the current chain.waitUntilSchedule work throughhost.waitUntilwhen the host supports it.urlTherequest.urlstring parsed into aURLobject. Parsing is performed on-demand and the result is cached.setHeaderSet a response header from a request middleware.Response middlewares should use
response.headers.set()instead.onResponseAdd a callback to be called when a response is generated.