UNPKG

@worker-tools/middleware

Version:

A suite of standalone HTTP server middlewares for Worker Runtimes.

79 lines 3.84 kB
// deno-lint-ignore-file no-explicit-any export { pipe as combine } from 'ts-functional-pipe'; import { ResolvablePromise } from '@worker-tools/resolvable-promise'; import { AppendOnlyList } from "./utils/append-only-list.js"; export class EffectsList extends AppendOnlyList { } /** * @deprecated Function might change name */ export function executeEffects(effects, response) { var _a; // TODO: to reduce or reduceRight, that is the question... // reduceRight matches the behavior of my initial, non-compose friendly middleware model // which was just increasingly deep levels of wrapped function calls. // In that model, the effects (post-processes) of the last applied middleware were executed first. // Regular reduce matches the order in which middlewares are applied, // which probably is close what users expect to happen, anyway... return (_a = [...effects].reduceRight(async (response, effect) => { var _a; return (_a = effect(await response)) !== null && _a !== void 0 ? _a : response; }, response)) !== null && _a !== void 0 ? _a : response; } /** * 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 function createMiddleware(_defaultExt, middlewareFn) { return middlewareFn; } /** * 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 function withMiddleware(middleware, handler, _errorHandler) { return async (request, ...args) => { const handle = new ResolvablePromise(); const handled = Promise.resolve(handle); const effects = new EffectsList(); const ctx = { request, effects, handled, args: [request, ...args], waitUntil: () => { } }; try { const userCtx = await middleware(ctx); const userRes = await handler(request, userCtx); const response = await executeEffects(effects, userRes); handle.resolve(response); return response; } catch (err) { throw err; // TODO // if (fallback && err instanceof Response) { // fallback(request, Object.assign(ctx, { response: err })) // } } }; } //# sourceMappingURL=context.js.map