UNPKG

@akala/core

Version:
112 lines (98 loc) 4.21 kB
import { convertToErrorMiddleware, isStandardMiddleware, isErrorMiddleware, NotHandled } from './shared.js'; import type { AnyAsyncMiddleware, ErrorMiddleware, ErrorMiddlewareAsync, MiddlewareAsync, MiddlewarePromise, OptionsResponse, SpecialNextParam } from './shared.js'; // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars export interface ExtendableIndexedMiddleware<T extends unknown[]> { } /** * MiddlewareIndexedAsync class that implements MiddlewareAsync and ExtendableIndexedMiddleware. * @template T - The type of the arguments. * @template TMiddleware - The type of the middleware. */ export class MiddlewareIndexedAsync<T extends unknown[], TMiddleware extends AnyAsyncMiddleware<T>> implements MiddlewareAsync<T>, ExtendableIndexedMiddleware<T> { public readonly name?: string protected _delegate: MiddlewareAsync<T>; /** * Constructor for MiddlewareIndexedAsync. * @param {function} getIndexKey - Function to get the index key. * @param {string} [name] - Optional name for the middleware. */ constructor(private getIndexKey: (...args: T) => string, name?: string) { this.name = name; } /** * Get the keys of the index. * @returns {string[]} The keys of the index. */ protected getKeys(): string[] { return Object.keys(this.index).filter(v => v !== ''); } protected readonly index: Record<string, TMiddleware> & { ''?: ErrorMiddleware<T> } = {}; /** * Use middleware for a specific key. * @param {null|string} key - The key for the middleware. * @param {AnyAsyncMiddleware} middleware - The middleware to use. * @returns {this} The instance of MiddlewareIndexedAsync. */ public useMiddleware(key: null, middleware: MiddlewareAsync<T>): this public useMiddleware(key: '', middleware: ErrorMiddlewareAsync<T>): this public useMiddleware(key: string, middleware: TMiddleware): this public useMiddleware(key: string, middleware: AnyAsyncMiddleware<T>): this { if (key === null) this._delegate = middleware as MiddlewareAsync<T>; else this.index[key] = middleware as TMiddleware; return this; } /** * Use an error handler. * @param {function} handler - The error handler function. * @returns {this} The instance of MiddlewareIndexedAsync. */ public useError(handler: ((error: Error | OptionsResponse, ...args: T) => Promise<unknown>)): this { return this.useMiddleware('', convertToErrorMiddleware<T, SpecialNextParam>(handler)); } /** * Process the request. * @template X - The type of the return value. * @param {...T} req - The request arguments. * @returns {Promise<X>} The result of the processing. */ public process<X = unknown>(...req: T): Promise<X> { return this.handle(...req).then(x => typeof x !== 'undefined' ? Promise.reject(x) : Promise.resolve(x), x => Promise.resolve(x)); } /** * Handle an error. * @param {Error|OptionsResponse} error - The error to handle. * @param {...T} req - The request arguments. * @returns {MiddlewarePromise} The result of the error handling. */ public async handleError(error: Error | OptionsResponse, ...req: T): MiddlewarePromise { if (isErrorMiddleware(this.index[''])) return this.index[''].handleError(error, ...req); return error; } /** * Handle the request. * @param {...T} req - The request arguments. * @returns {MiddlewarePromise} The result of the handling. */ public handle(...req: T): MiddlewarePromise { var key = this.getIndexKey(...req); if (!key || !this.index[key]) if (this._delegate) return this._delegate.handle(...req); else return NotHandled; const middleware = this.index[key]; if (isStandardMiddleware(middleware)) return middleware.handle(...req).then(e => (typeof e === 'undefined') && this._delegate ? this._delegate.handle(...req) : e); return NotHandled; } }