UNPKG

@worker-tools/middleware

Version:

A suite of standalone HTTP server middlewares for Worker Runtimes.

172 lines (171 loc) 7.39 kB
export { pipe as combine } from 'ts-functional-pipe'; import { AppendOnlyList } from "./utils/append-only-list.js"; import { Awaitable, Callable } from "./utils/common-types.js"; export declare type ResponseEffect = (r: Response) => void | Awaitable<Response>; export declare class EffectsList extends AppendOnlyList<ResponseEffect> { } export interface Context { /** * The original request for use in middleware. Also accessible via first argument to user handler. */ request: Request; /** * A list of effects/transforms applied to the `Response` after the application handler completes. * Middleware can add effects to the list. Application handlers should ignore it. * @deprecated Prop might change name */ effects: AppendOnlyList<ResponseEffect>; /** * TODO */ waitUntil: (f: any) => void; /** * A promise that resolves when middleware is done applying effects. * Related: https://github.com/w3c/ServiceWorker/issues/1397 */ handled: Promise<Response>; /** * The URL pattern match that caused this handler to run. See the URL Pattern API for more. */ match?: URLPatternResult; /** * Only available if the router is used via `fetchEventListener`. * Many Worker Runtimes such as Deno an CF module workers don't provide fetch events. */ event?: FetchEvent; /** Might be present based on usage */ env?: any; /** Might be present based on usage */ ctx?: any; /** Might be present based on usage */ connInfo?: any; /** Might be present based on usage */ args?: any[]; } /** * Helper type to get the context type of a given middleware function. * * Example: * ```ts * const mw = combine(basics(), contentTypes(['text/html', 'application/json'])) * type MWContext = ContextOf<typeof mw>; * const handler = (req: Request, context: MWContext) => ok() * new WorkerRouter().get('/', mw, handler) * ``` */ export declare type ContextOf<MW extends (...args: any[]) => Awaitable<Context>> = Awaited<ReturnType<MW>>; /** * @deprecated Function might change name */ export declare function executeEffects(effects: EffectsList, response: Awaitable<Response>): Awaitable<Response>; /** Any record of unknown values */ export declare type Rec = Record<PropertyKey, any>; /** * A helper function to create user-defined middleware. * * Its main purpose is to allow developers to create correctly typed middleware without dealing with generics. * This is achieved via the `_defaultExt` parameter, which is used to infer the types of the *extension* added to the *context*. * As the `_` prefix implies, it is not actually used. * The purpose of the default extension object is solely to tell the type checker which additional keys to expect on the context object after this middleware is applied. * The job of adding (default) values to the context belongs to the middleware function. * * Here are some example usages. All are valid in JavaScript and TypeScript: * * ```ts * const fn = createMiddleware({}, _ => _) * const gn = createMiddleware({}, async ax => ({ ...await ax })) * const hn = createMiddleware({ foo: '' }, async ax => ({ ...await ax, foo: 'star' })) * const jn = createMiddleware({ bar: '' }, async ax => { * const x = await ax; * x.effects.push(resp => { * resp.headers.set('x-middleware', 'jn') * }) * return { ...x, bar: 'star' } * }) * const myMW = combine(fn, hn, jn, gn) * //=> Context & { foo: string } & { bar: string } * ``` * * @param _defaultExt The default extension to the current context. Can also be a function that returns the extension object, to avoid unnecessary memory allocation. * @param middlewareFn A middleware functions: Adds the keys listed in `defaultExt` to the context * @returns The provided `middlewareFn` with type annotations inferred based on `defaultExt` */ export declare function createMiddleware<Etx extends Rec>(_defaultExt: Callable<Etx>, middlewareFn: <Ctx extends Context>(ax: Awaitable<Ctx>) => Awaitable<Ctx & Etx>): <Ctx extends Context>(ax: Awaitable<Ctx>) => Awaitable<Ctx & Etx>; /** @deprecated Name might change */ export declare type ErrorContext = Context & { error: Error; response: Response; }; /** @deprecated Name might change */ export declare type Handler<X extends Context> = (request: Request, ctx: X) => Awaitable<Response>; /** @deprecated Name might change */ export declare type ErrorHandler<X extends ErrorContext> = (request: Request, ctx: X) => Awaitable<Response>; /** @deprecated Name might change */ export declare type Middleware<X extends Context, Y extends Context> = (x: Awaitable<X>) => Awaitable<Y>; /** * Takes a handler function of the form `(x: Request, ctx: Context) => Awaitable<Response>` and applies middleware to it. * @deprecated Name might change, errorHandler not implemented */ export declare function withMiddleware<X extends Context, EX extends ErrorContext>(middleware: Middleware<Context, X>, handler: Handler<X>, _errorHandler?: ErrorHandler<EX>): (request: Request, ...args: any[]) => Promise<Response>; /** * Extends the lifetime of the install and activate events dispatched on the global scope as part of the * service worker lifecycle. This ensures that any functional events (like FetchEvent) are not dispatched until it * upgrades database schemas and deletes the outdated cache entries. */ export interface ExtendableEvent extends Event { waitUntil(f: any): void; } export interface ExtendableEventInit extends EventInit { new (type: string, eventInitDict?: ExtendableEventInit): ExtendableEvent; } export interface FetchEventInit extends ExtendableEventInit { new (type: string, eventInitDict: FetchEventInit): FetchEvent; clientId?: string; preloadResponse?: Promise<any>; replacesClientId?: string; request: Request; resultingClientId?: string; } /** * This is the event type for fetch events dispatched on the service worker global scope. * It contains information about the fetch, including the request and how the receiver will treat the response. * It provides the event.respondWith() method, which allows us to provide a response to this fetch. */ export interface FetchEvent extends ExtendableEvent { readonly clientId: string; readonly preloadResponse: Promise<any>; readonly replacesClientId: string; readonly request: Request; readonly resultingClientId: string; readonly handled: Promise<void>; respondWith(r: Response | Promise<Response>): void; } export declare type URLPatternInput = URLPatternInit | string; export interface URLPatternInit { baseURL?: string; username?: string; password?: string; protocol?: string; hostname?: string; port?: string; pathname?: string; search?: string; hash?: string; } export interface URLPatternResult { inputs: [URLPatternInit] | [URLPatternInit, string]; protocol: URLPatternComponentResult; username: URLPatternComponentResult; password: URLPatternComponentResult; hostname: URLPatternComponentResult; port: URLPatternComponentResult; pathname: URLPatternComponentResult; search: URLPatternComponentResult; hash: URLPatternComponentResult; } export interface URLPatternComponentResult { input: string; groups: { [key: string]: string | undefined; }; }