@worker-tools/middleware
Version:
A suite of standalone HTTP server middlewares for Worker Runtimes.
79 lines • 3.84 kB
JavaScript
// 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