Reference
yieldless/signal
Deadline helpers for AbortSignal-aware work.
yieldless/signal adds a small missing piece around native cancellation: derived deadline signals that clean up after themselves.
Exports
createTimeoutSignal(timeoutMs, options?): TimeoutSignalwithTimeout(operation, options): Promise<T>class TimeoutError extends Error
Options
| Option | Description |
|---|---|
timeoutMs | Maximum time before the derived signal aborts |
signal | Optional parent signal to inherit cancellation from |
reason | Optional custom timeout reason |
Typical use
import { safeTry } from "yieldless/error";
import { withTimeout } from "yieldless/signal";
const [error, response] = await safeTry(
withTimeout(
(signal) => fetch("https://example.com/api/repos", { signal }),
{
timeoutMs: 5_000,
},
),
);Long-lived scope
Use createTimeoutSignal() when you need to pass one deadline signal across several calls.
import { createTimeoutSignal } from "yieldless/signal";
const deadline = createTimeoutSignal(10_000, {
signal: request.signal,
});
try {
const [error, result] = await runCommandSafe(
"git",
["fetch", "--all"],
{ signal: deadline.signal },
);
} finally {
deadline[Symbol.dispose]();
}Operational rules
- The parent signal wins if it aborts first.
- Timeout failures use
TimeoutErrorby default. - Disposing the derived signal clears its timer and parent listener.
timeoutMsmust be zero or greater.
Good fits
- HTTP requests that should not hang forever
- Git commands or subprocesses with a firm deadline
- Any abort-aware operation where you want one shared time budget
Good
Use withTimeout() for one operation.
const [error, response] = await safeTry(
withTimeout(
(signal) => fetch(url, { signal }),
{ timeoutMs: 5_000, signal: request.signal },
),
);Use createTimeoutSignal() for a scope of related operations.
const deadline = createTimeoutSignal(10_000, { signal });
try {
await readProfile(deadline.signal);
await readPermissions(deadline.signal);
} finally {
deadline[Symbol.dispose]();
}Avoid
Do not create ad hoc timers that outlive the request.
const timer = setTimeout(() => controller.abort(), 5_000);
await doWork(controller.signal);Use withTimeout() or dispose the derived signal explicitly so timers and parent listeners are cleaned up.