@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
77 lines • 2.73 kB
JavaScript
/**
* @module Async
*/
import {} from "../../../utilities/_module-exports.js";
import { callInvokable } from "../../../utilities/_module-exports.js";
import { AbortAsyncError, TimeoutAsyncError } from "../../../async/async.errors.js";
import { abortAndFail } from "../../../async/utilities/_module.js";
/**
* The `timeout` middleware automatically cancels functions after a specified time period, throwing an error when aborted.
* Note the original function continues executing (even if the promise fails), you'll need to provide a settings.signalBinder to forward the `AbortSignal`.
*
* IMPORT_PATH: `"@daiso-tech/core/async"`
* @group Middleware
*
* @throws {TimeoutAsyncError} {@link TimeoutAsyncError}
*
* @example
* ```ts
* import { timeout } from "@daiso-tech/core/async";
* import { AsyncHooks, TimeSpan } from "@daiso-tech/core/utilities";
*
* const abortController = new AbortController();
*
* const promise = new AsyncHooks(async (url: string, signal?: AbortSignal): Promise<unknown> => {
* const response = await fetch(url, {
* signal
* });
* const json = await response.json();
* if (!response.ok) {
* throw json
* }
* return json;
* }, timeout({
* time: TimeSpan.fromSeconds(2),
* // With the defined signalBinder the HTTP request will be arboted when timed out or when the inputed `AbortSignal` is called.
* signalBinder: ([url, fetchSignal], timeoutSignal) => {
* return [
* url,
* AbortSignal.any([
* fetchSignal,
* timeoutSignal
* ].filter(signal => signal !== undefined))
* ] as const;
* }
* }))
* .invoke("ENDPOINT", abortController.signal);
*
* abortController.abort();
*
* // An error will be thrown.
* await promise;
* ```
*/
export function timeout(settings) {
const { time, signalBinder = (args) => args, onTimeout = () => { }, } = settings;
return async (args, next, context) => {
const timeoutController = new AbortController();
const timeoutId = setTimeout(() => {
timeoutController.abort(new TimeoutAsyncError("The promise exceded time"));
}, time.toMilliseconds());
try {
return await abortAndFail(next(...callInvokable(signalBinder, args, timeoutController.signal)), timeoutController.signal);
}
catch (error) {
if (error instanceof AbortAsyncError &&
error.cause instanceof TimeoutAsyncError) {
callInvokable(onTimeout, { maxTime: time, args, context });
throw error.cause;
}
throw error;
}
finally {
clearTimeout(timeoutId);
}
};
}
//# sourceMappingURL=timeout.middleware.js.map