import type { Fn } from 'everyday-types'
import { bool, toFluent } from 'to-fluent'
export class AbortOptions {
throw = bool
latest = bool
timeout?: number
}
export const abort = toFluent(
AbortOptions,
options =>
(fn:
(signal: AbortSignal) => Fn
): Fn
? R : Promise> => {
let ctrl: AbortController
const wrap = Object.assign(async function wrap(this: any, ...args: P) {
if (options.latest && ctrl) ctrl.abort()
ctrl = new AbortController()
if (options.timeout != null) {
const timeoutError = new Error('Timed out')
try {
return await Promise.race([
new Promise((_, reject) => setTimeout(reject, options.timeout, timeoutError)),
fn(ctrl.signal).apply(this, args),
])
} catch (error) {
if (error === timeoutError) {
ctrl.abort()
if (options.throw)
throw error
else {
//!warn error
}
} else {
if (options.throw)
throw error
else {
//!warn error
}
}
}
} else {
return fn(ctrl.signal).apply(this, args)
}
// @ts-ignore
}, { fn: fn() })
return wrap as any
}
)