@orkestrel/timeout 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/src/core/index.cjs +31 -29
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +43 -27
- package/dist/src/core/index.d.ts +43 -27
- package/dist/src/core/index.js +32 -30
- package/dist/src/core/index.js.map +1 -1
- package/package.json +19 -15
package/README.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
A typed, **controllable** `setTimeout` wrapper — a deadline handle that
|
|
4
4
|
exposes an `AbortSignal` which fires on expiry, for racing against work.
|
|
5
5
|
Deliberately small: `start()` arms the deadline, `clear()` cancels it without
|
|
6
|
-
firing, and
|
|
7
|
-
deadline without re-construction. An optional parent `signal` links in
|
|
8
|
-
inheriting `AbortSignal.any` semantics — a parent abort during the
|
|
9
|
-
window _clears_ the timeout (it never expires) rather than firing it.
|
|
10
|
-
the `@orkestrel` line.
|
|
6
|
+
firing, and calling `start()` again after expiry reuses the handle for a
|
|
7
|
+
fresh deadline without re-construction. An optional parent `signal` links in
|
|
8
|
+
without inheriting `AbortSignal.any` semantics — a parent abort during the
|
|
9
|
+
timing window _clears_ the timeout (it never expires) rather than firing it.
|
|
10
|
+
Part of the `@orkestrel` line.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -17,8 +17,8 @@ npm install @orkestrel/timeout
|
|
|
17
17
|
|
|
18
18
|
## Requirements
|
|
19
19
|
|
|
20
|
-
- Node.js >=
|
|
21
|
-
- ESM
|
|
20
|
+
- Node.js >= 22.12.0, matching the `engines` field in `package.json`
|
|
21
|
+
- ESM (`import`) and CommonJS (`require`) through the `exports` field
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
@@ -61,7 +61,7 @@ once-read helper that returns a fresh copy without absent optional keys.
|
|
|
61
61
|
## Guide
|
|
62
62
|
|
|
63
63
|
For the full surface — the deadline lifecycle, parent-signal linking, and
|
|
64
|
-
reuse semantics — see [`guides/
|
|
64
|
+
reuse semantics — see [`guides/timeout.md`](guides/timeout.md).
|
|
65
65
|
|
|
66
66
|
## Package
|
|
67
67
|
|
package/dist/src/core/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let _orkestrel_contract = require("@orkestrel/contract");
|
|
3
3
|
//#region src/core/constants.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Names the largest timeout duration accepted by the package, in milliseconds.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* ```ts
|
|
@@ -13,10 +13,10 @@ var MAX_TIMEOUT_MS = 2147483647;
|
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/core/validators.ts
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Determines whether a value is an accepted timeout duration.
|
|
17
17
|
*
|
|
18
18
|
* @param value - Unknown duration candidate
|
|
19
|
-
* @returns
|
|
19
|
+
* @returns True if the value is an integer in the inclusive timeout range; false otherwise
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
22
|
* ```ts
|
|
@@ -25,10 +25,10 @@ var MAX_TIMEOUT_MS = 2147483647;
|
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
function isTimeoutDuration(value) {
|
|
28
|
-
return (0, _orkestrel_contract.
|
|
28
|
+
return (0, _orkestrel_contract.isInteger)(value) && value >= 0 && value <= 2147483647;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* Determines whether a value is a genuine native `AbortSignal`.
|
|
32
32
|
*
|
|
33
33
|
* @remarks
|
|
34
34
|
* The intrinsic `aborted` getter performs the native brand check. The boundary
|
|
@@ -36,7 +36,7 @@ function isTimeoutDuration(value) {
|
|
|
36
36
|
* allowing their errors to escape.
|
|
37
37
|
*
|
|
38
38
|
* @param value - Unknown signal candidate
|
|
39
|
-
* @returns
|
|
39
|
+
* @returns True if the native `AbortSignal` getter accepts the value; false otherwise
|
|
40
40
|
*
|
|
41
41
|
* @example
|
|
42
42
|
* ```ts
|
|
@@ -56,7 +56,7 @@ function isTimeoutSignal(value) {
|
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region src/core/helpers.ts
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
59
|
+
* Validates and normalizes timeout construction options.
|
|
60
60
|
*
|
|
61
61
|
* @remarks
|
|
62
62
|
* Each property is read exactly once before validation. The returned object is
|
|
@@ -65,8 +65,8 @@ function isTimeoutSignal(value) {
|
|
|
65
65
|
*
|
|
66
66
|
* @param options - Potentially untrusted timeout options
|
|
67
67
|
* @returns A fresh validated `TimeoutOptions` object
|
|
68
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
69
|
-
* does not satisfy `TimeoutOptions`
|
|
68
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
69
|
+
* input does not satisfy `TimeoutOptions`
|
|
70
70
|
*
|
|
71
71
|
* @example
|
|
72
72
|
* ```ts
|
|
@@ -142,7 +142,7 @@ function validateTimeoutOptions(options) {
|
|
|
142
142
|
//#endregion
|
|
143
143
|
//#region src/core/Timeout.ts
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
145
|
+
* Represents a controllable deadline whose native `AbortSignal` aborts when it expires.
|
|
146
146
|
*
|
|
147
147
|
* @remarks
|
|
148
148
|
* `start()` arms or replaces the current deadline. Expiry sets `expired` and
|
|
@@ -167,21 +167,26 @@ function validateTimeoutOptions(options) {
|
|
|
167
167
|
* ```
|
|
168
168
|
*/
|
|
169
169
|
var Timeout = class {
|
|
170
|
-
id;
|
|
171
|
-
ms;
|
|
170
|
+
#id;
|
|
171
|
+
#ms;
|
|
172
172
|
#parent;
|
|
173
173
|
#listener;
|
|
174
174
|
#controller;
|
|
175
175
|
#handle;
|
|
176
|
-
#linked = false;
|
|
177
176
|
constructor(options) {
|
|
178
177
|
const input = validateTimeoutOptions(options);
|
|
179
|
-
this
|
|
180
|
-
this
|
|
178
|
+
this.#id = input.id === void 0 ? crypto.randomUUID() : input.id;
|
|
179
|
+
this.#ms = input.ms;
|
|
181
180
|
this.#parent = input.signal;
|
|
182
181
|
this.#controller = new AbortController();
|
|
183
182
|
this.#listener = this.clear.bind(this);
|
|
184
183
|
}
|
|
184
|
+
get id() {
|
|
185
|
+
return this.#id;
|
|
186
|
+
}
|
|
187
|
+
get ms() {
|
|
188
|
+
return this.#ms;
|
|
189
|
+
}
|
|
185
190
|
get signal() {
|
|
186
191
|
return this.#controller.signal;
|
|
187
192
|
}
|
|
@@ -196,15 +201,12 @@ var Timeout = class {
|
|
|
196
201
|
}
|
|
197
202
|
this.#detach();
|
|
198
203
|
if (this.#controller.signal.aborted) this.#controller = new AbortController();
|
|
199
|
-
if (this.#parent !== void 0) {
|
|
200
|
-
this.#parent.addEventListener("abort", this.#listener, { once: true });
|
|
201
|
-
this.#linked = true;
|
|
202
|
-
}
|
|
204
|
+
if (this.#parent !== void 0) this.#parent.addEventListener("abort", this.#listener, { once: true });
|
|
203
205
|
this.#handle = setTimeout(() => {
|
|
204
206
|
this.#handle = void 0;
|
|
205
207
|
this.#detach();
|
|
206
208
|
this.#controller.abort();
|
|
207
|
-
}, this
|
|
209
|
+
}, this.#ms);
|
|
208
210
|
}
|
|
209
211
|
clear() {
|
|
210
212
|
if (this.#handle !== void 0) {
|
|
@@ -215,27 +217,27 @@ var Timeout = class {
|
|
|
215
217
|
if (this.#controller.signal.aborted) this.#controller = new AbortController();
|
|
216
218
|
}
|
|
217
219
|
#detach() {
|
|
218
|
-
|
|
219
|
-
this.#parent?.removeEventListener("abort", this.#listener);
|
|
220
|
-
this.#linked = false;
|
|
221
|
-
}
|
|
220
|
+
this.#parent?.removeEventListener("abort", this.#listener);
|
|
222
221
|
}
|
|
223
222
|
};
|
|
224
223
|
//#endregion
|
|
225
224
|
//#region src/core/factories.ts
|
|
226
225
|
/**
|
|
227
|
-
*
|
|
226
|
+
* Creates a controllable deadline whose native signal aborts on expiry.
|
|
228
227
|
*
|
|
229
228
|
* @remarks
|
|
230
229
|
* `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.
|
|
231
230
|
* A parent `options.signal` clears an armed timeout without aborting the
|
|
232
|
-
* timeout's own signal.
|
|
233
|
-
*
|
|
234
|
-
*
|
|
231
|
+
* timeout's own signal. `start()` returns without arming when the parent
|
|
232
|
+
* `signal` supplied at construction has already aborted, so a handle whose
|
|
233
|
+
* parent aborted never expires again and its `signal` never fires. Omitted
|
|
234
|
+
* `options.id` values generate a random UUID. Malformed or unreadable options
|
|
235
|
+
* use contract code `bound`; invalid `id`, `ms`, and `signal` values use
|
|
236
|
+
* `literal`, `range`, and `placement`.
|
|
235
237
|
*
|
|
236
238
|
* @param options - Validated deadline, optional trace label, and optional native parent signal
|
|
237
239
|
* @returns A reusable timeout handle
|
|
238
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
240
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
239
241
|
* JavaScript input does not satisfy `TimeoutOptions`
|
|
240
242
|
*
|
|
241
243
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["#parent","#listener","#controller","#handle","#detach","#linked"],"sources":["../../../src/core/constants.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Timeout.ts","../../../src/core/factories.ts"],"sourcesContent":["/**\n * Largest timeout duration accepted by the package, in milliseconds.\n *\n * @example\n * ```ts\n * createTimeout({ ms: MAX_TIMEOUT_MS })\n * ```\n */\nexport const MAX_TIMEOUT_MS = 2_147_483_647\n","import { isFiniteNumber, isInteger } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\n\n/**\n * Determine whether a value is an accepted timeout duration.\n *\n * @param value - Unknown duration candidate\n * @returns `true` only for an integer in the inclusive timeout range\n *\n * @example\n * ```ts\n * isTimeoutDuration(0) // true\n * isTimeoutDuration(1.5) // false\n * ```\n */\nexport function isTimeoutDuration(value: unknown): value is number {\n\treturn isFiniteNumber(value) && isInteger(value) && value >= 0 && value <= MAX_TIMEOUT_MS\n}\n\n/**\n * Determine whether a value is a genuine native `AbortSignal`.\n *\n * @remarks\n * The intrinsic `aborted` getter performs the native brand check. The boundary\n * contains revoked proxies and hostile receivers, returning `false` instead of\n * allowing their errors to escape.\n *\n * @param value - Unknown signal candidate\n * @returns `true` only when the native `AbortSignal` getter accepts the value\n *\n * @example\n * ```ts\n * isTimeoutSignal(new AbortController().signal) // true\n * isTimeoutSignal({ aborted: false }) // false\n * ```\n */\nexport function isTimeoutSignal(value: unknown): value is AbortSignal {\n\ttry {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')\n\t\tif (descriptor?.get === undefined) return false\n\t\treturn typeof Reflect.apply(descriptor.get, value, []) === 'boolean'\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { TimeoutOptions } from './types.js'\nimport { ContractError, isRecord, isString, preview } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\nimport { isTimeoutDuration, isTimeoutSignal } from './validators.js'\n\n/**\n * Validate and normalize timeout construction options.\n *\n * @remarks\n * Each property is read exactly once before validation. The returned object is\n * a fresh copy and omits absent optional properties. No timer, controller, or\n * listener lifecycle begins at this boundary.\n *\n * @param options - Potentially untrusted timeout options\n * @returns A fresh validated `TimeoutOptions` object\n * @throws {@link import('@orkestrel/contract').ContractError} When the input\n * does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * const options = validateTimeoutOptions({ ms: 5_000 })\n * ```\n */\nexport function validateTimeoutOptions(options: TimeoutOptions): TimeoutOptions {\n\tif (!isRecord(options)) {\n\t\tthrow new ContractError('Timeout: options must be a plain record', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t})\n\t}\n\n\tlet id: TimeoutOptions['id']\n\tlet ms: TimeoutOptions['ms']\n\tlet signal: TimeoutOptions['signal']\n\ttry {\n\t\tid = options.id\n\t\tms = options.ms\n\t\tsignal = options.signal\n\t} catch (cause) {\n\t\tthrow new ContractError('Timeout: options could not be read', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'readable plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t\tcause,\n\t\t})\n\t}\n\n\tif (id !== undefined && !isString(id)) {\n\t\tthrow new ContractError('Timeout: id must be a string when defined', {\n\t\t\tcode: 'literal',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'id'],\n\t\t\t\tlimit: 'string or undefined',\n\t\t\t\treceived: preview(id),\n\t\t\t},\n\t\t})\n\t}\n\tif (!isTimeoutDuration(ms)) {\n\t\tthrow new ContractError('Timeout: ms must be an integer in the supported range', {\n\t\t\tcode: 'range',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'ms'],\n\t\t\t\tlimit: `integer in [0, ${MAX_TIMEOUT_MS}]`,\n\t\t\t\treceived: preview(ms),\n\t\t\t},\n\t\t})\n\t}\n\tif (signal !== undefined && !isTimeoutSignal(signal)) {\n\t\tthrow new ContractError('Timeout: signal must be a native AbortSignal when defined', {\n\t\t\tcode: 'placement',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'signal'],\n\t\t\t\tlimit: 'native AbortSignal or undefined',\n\t\t\t\treceived: preview(signal),\n\t\t\t},\n\t\t})\n\t}\n\n\tif (id !== undefined && signal !== undefined) return { id, ms, signal }\n\tif (id !== undefined) return { id, ms }\n\tif (signal !== undefined) return { ms, signal }\n\treturn { ms }\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { validateTimeoutOptions } from './helpers.js'\n\n/**\n * A controllable deadline whose native `AbortSignal` aborts when it expires.\n *\n * @remarks\n * `start()` arms or replaces the current deadline. Expiry sets `expired` and\n * aborts the current signal once. `clear()` cancels without aborting and resets\n * `expired`. Starting or clearing after expiry installs a fresh signal. A parent\n * abort deliberately clears the timeout without aborting its signal; once the\n * parent has aborted, later starts are inert.\n *\n * Construction validates the complete JavaScript boundary before creating an\n * `AbortController`. A malformed or unreadable options record throws a\n * `bound`-coded {@link import('@orkestrel/contract').ContractError}; an invalid\n * `id`, `ms`, or `signal` uses `literal`, `range`, or `placement`, respectively.\n *\n * @example\n * ```ts\n * import { Timeout } from '@orkestrel/timeout'\n *\n * const timeout = new Timeout({ ms: 5_000 })\n * timeout.start()\n * timeout.signal.addEventListener('abort', () => giveUp(), { once: true })\n * timeout.clear()\n * ```\n */\nexport class Timeout implements TimeoutInterface {\n\treadonly id: string\n\treadonly ms: number\n\treadonly #parent: AbortSignal | undefined\n\treadonly #listener: () => void\n\t#controller: AbortController\n\t#handle: ReturnType<typeof setTimeout> | undefined\n\t#linked = false\n\n\tconstructor(options: TimeoutOptions) {\n\t\tconst input = validateTimeoutOptions(options)\n\t\tthis.id = input.id === undefined ? crypto.randomUUID() : input.id\n\t\tthis.ms = input.ms\n\t\tthis.#parent = input.signal\n\t\tthis.#controller = new AbortController()\n\t\tthis.#listener = this.clear.bind(this)\n\t}\n\n\tget signal(): AbortSignal {\n\t\treturn this.#controller.signal\n\t}\n\n\tget expired(): boolean {\n\t\treturn this.#controller.signal.aborted\n\t}\n\n\tstart(): void {\n\t\tif (this.#parent?.aborted === true) return\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t\tif (this.#parent !== undefined) {\n\t\t\tthis.#parent.addEventListener('abort', this.#listener, { once: true })\n\t\t\tthis.#linked = true\n\t\t}\n\t\tthis.#handle = setTimeout(() => {\n\t\t\tthis.#handle = undefined\n\t\t\tthis.#detach()\n\t\t\tthis.#controller.abort()\n\t\t}, this.ms)\n\t}\n\n\tclear(): void {\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t}\n\n\t#detach(): void {\n\t\tif (this.#linked) {\n\t\t\tthis.#parent?.removeEventListener('abort', this.#listener)\n\t\t\tthis.#linked = false\n\t\t}\n\t}\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { Timeout } from './Timeout.js'\n\n/**\n * Create a controllable deadline whose native signal aborts on expiry.\n *\n * @remarks\n * `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.\n * A parent `options.signal` clears an armed timeout without aborting the\n * timeout's own signal. Omitted `options.id` values generate a random UUID.\n * Malformed or unreadable options use contract code `bound`; invalid `id`,\n * `ms`, and `signal` values use `literal`, `range`, and `placement`.\n *\n * @param options - Validated deadline, optional trace label, and optional native parent signal\n * @returns A reusable timeout handle\n * @throws {@link import('@orkestrel/contract').ContractError} When the\n * JavaScript input does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * import { createTimeout } from '@orkestrel/timeout'\n *\n * const timeout = createTimeout({ ms: 5_000 })\n * timeout.start()\n * try {\n * \tawait fetch('/work', { signal: timeout.signal })\n * } finally {\n * \ttimeout.clear()\n * }\n * ```\n */\nexport function createTimeout(options: TimeoutOptions): TimeoutInterface {\n\treturn new Timeout(options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["#id","#ms","#parent","#listener","#controller","#handle","#detach"],"sources":["../../../src/core/constants.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Timeout.ts","../../../src/core/factories.ts"],"sourcesContent":["/**\n * Names the largest timeout duration accepted by the package, in milliseconds.\n *\n * @example\n * ```ts\n * createTimeout({ ms: MAX_TIMEOUT_MS })\n * ```\n */\nexport const MAX_TIMEOUT_MS = 2_147_483_647\n","import { isInteger } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\n\n/**\n * Determines whether a value is an accepted timeout duration.\n *\n * @param value - Unknown duration candidate\n * @returns True if the value is an integer in the inclusive timeout range; false otherwise\n *\n * @example\n * ```ts\n * isTimeoutDuration(0) // true\n * isTimeoutDuration(1.5) // false\n * ```\n */\nexport function isTimeoutDuration(value: unknown): value is number {\n\treturn isInteger(value) && value >= 0 && value <= MAX_TIMEOUT_MS\n}\n\n/**\n * Determines whether a value is a genuine native `AbortSignal`.\n *\n * @remarks\n * The intrinsic `aborted` getter performs the native brand check. The boundary\n * contains revoked proxies and hostile receivers, returning `false` instead of\n * allowing their errors to escape.\n *\n * @param value - Unknown signal candidate\n * @returns True if the native `AbortSignal` getter accepts the value; false otherwise\n *\n * @example\n * ```ts\n * isTimeoutSignal(new AbortController().signal) // true\n * isTimeoutSignal({ aborted: false }) // false\n * ```\n */\nexport function isTimeoutSignal(value: unknown): value is AbortSignal {\n\ttry {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')\n\t\tif (descriptor?.get === undefined) return false\n\t\treturn typeof Reflect.apply(descriptor.get, value, []) === 'boolean'\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { TimeoutOptions } from './types.js'\nimport { ContractError, isRecord, isString, preview } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\nimport { isTimeoutDuration, isTimeoutSignal } from './validators.js'\n\n/**\n * Validates and normalizes timeout construction options.\n *\n * @remarks\n * Each property is read exactly once before validation. The returned object is\n * a fresh copy and omits absent optional properties. No timer, controller, or\n * listener lifecycle begins at this boundary.\n *\n * @param options - Potentially untrusted timeout options\n * @returns A fresh validated `TimeoutOptions` object\n * @throws {@link import('@orkestrel/contract').ContractError} Thrown when the\n * input does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * const options = validateTimeoutOptions({ ms: 5_000 })\n * ```\n */\nexport function validateTimeoutOptions(options: TimeoutOptions): TimeoutOptions {\n\tif (!isRecord(options)) {\n\t\tthrow new ContractError('Timeout: options must be a plain record', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t})\n\t}\n\n\tlet id: TimeoutOptions['id']\n\tlet ms: TimeoutOptions['ms']\n\tlet signal: TimeoutOptions['signal']\n\ttry {\n\t\tid = options.id\n\t\tms = options.ms\n\t\tsignal = options.signal\n\t} catch (cause) {\n\t\tthrow new ContractError('Timeout: options could not be read', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'readable plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t\tcause,\n\t\t})\n\t}\n\n\tif (id !== undefined && !isString(id)) {\n\t\tthrow new ContractError('Timeout: id must be a string when defined', {\n\t\t\tcode: 'literal',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'id'],\n\t\t\t\tlimit: 'string or undefined',\n\t\t\t\treceived: preview(id),\n\t\t\t},\n\t\t})\n\t}\n\tif (!isTimeoutDuration(ms)) {\n\t\tthrow new ContractError('Timeout: ms must be an integer in the supported range', {\n\t\t\tcode: 'range',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'ms'],\n\t\t\t\tlimit: `integer in [0, ${MAX_TIMEOUT_MS}]`,\n\t\t\t\treceived: preview(ms),\n\t\t\t},\n\t\t})\n\t}\n\tif (signal !== undefined && !isTimeoutSignal(signal)) {\n\t\tthrow new ContractError('Timeout: signal must be a native AbortSignal when defined', {\n\t\t\tcode: 'placement',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'signal'],\n\t\t\t\tlimit: 'native AbortSignal or undefined',\n\t\t\t\treceived: preview(signal),\n\t\t\t},\n\t\t})\n\t}\n\n\tif (id !== undefined && signal !== undefined) return { id, ms, signal }\n\tif (id !== undefined) return { id, ms }\n\tif (signal !== undefined) return { ms, signal }\n\treturn { ms }\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { validateTimeoutOptions } from './helpers.js'\n\n/**\n * Represents a controllable deadline whose native `AbortSignal` aborts when it expires.\n *\n * @remarks\n * `start()` arms or replaces the current deadline. Expiry sets `expired` and\n * aborts the current signal once. `clear()` cancels without aborting and resets\n * `expired`. Starting or clearing after expiry installs a fresh signal. A parent\n * abort deliberately clears the timeout without aborting its signal; once the\n * parent has aborted, later starts are inert.\n *\n * Construction validates the complete JavaScript boundary before creating an\n * `AbortController`. A malformed or unreadable options record throws a\n * `bound`-coded {@link import('@orkestrel/contract').ContractError}; an invalid\n * `id`, `ms`, or `signal` uses `literal`, `range`, or `placement`, respectively.\n *\n * @example\n * ```ts\n * import { Timeout } from '@orkestrel/timeout'\n *\n * const timeout = new Timeout({ ms: 5_000 })\n * timeout.start()\n * timeout.signal.addEventListener('abort', () => giveUp(), { once: true })\n * timeout.clear()\n * ```\n */\nexport class Timeout implements TimeoutInterface {\n\treadonly #id: string\n\treadonly #ms: number\n\treadonly #parent: AbortSignal | undefined\n\treadonly #listener: () => void\n\t#controller: AbortController\n\t#handle: ReturnType<typeof setTimeout> | undefined\n\n\tconstructor(options: TimeoutOptions) {\n\t\tconst input = validateTimeoutOptions(options)\n\t\tthis.#id = input.id === undefined ? crypto.randomUUID() : input.id\n\t\tthis.#ms = input.ms\n\t\tthis.#parent = input.signal\n\t\tthis.#controller = new AbortController()\n\t\tthis.#listener = this.clear.bind(this)\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget ms(): number {\n\t\treturn this.#ms\n\t}\n\n\tget signal(): AbortSignal {\n\t\treturn this.#controller.signal\n\t}\n\n\tget expired(): boolean {\n\t\treturn this.#controller.signal.aborted\n\t}\n\n\tstart(): void {\n\t\tif (this.#parent?.aborted === true) return\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t\tif (this.#parent !== undefined) {\n\t\t\tthis.#parent.addEventListener('abort', this.#listener, { once: true })\n\t\t}\n\t\tthis.#handle = setTimeout(() => {\n\t\t\tthis.#handle = undefined\n\t\t\tthis.#detach()\n\t\t\tthis.#controller.abort()\n\t\t}, this.#ms)\n\t}\n\n\tclear(): void {\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t}\n\n\t#detach(): void {\n\t\tthis.#parent?.removeEventListener('abort', this.#listener)\n\t}\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { Timeout } from './Timeout.js'\n\n/**\n * Creates a controllable deadline whose native signal aborts on expiry.\n *\n * @remarks\n * `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.\n * A parent `options.signal` clears an armed timeout without aborting the\n * timeout's own signal. `start()` returns without arming when the parent\n * `signal` supplied at construction has already aborted, so a handle whose\n * parent aborted never expires again and its `signal` never fires. Omitted\n * `options.id` values generate a random UUID. Malformed or unreadable options\n * use contract code `bound`; invalid `id`, `ms`, and `signal` values use\n * `literal`, `range`, and `placement`.\n *\n * @param options - Validated deadline, optional trace label, and optional native parent signal\n * @returns A reusable timeout handle\n * @throws {@link import('@orkestrel/contract').ContractError} Thrown when the\n * JavaScript input does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * import { createTimeout } from '@orkestrel/timeout'\n *\n * const timeout = createTimeout({ ms: 5_000 })\n * timeout.start()\n * try {\n * \tawait fetch('/work', { signal: timeout.signal })\n * } finally {\n * \ttimeout.clear()\n * }\n * ```\n */\nexport function createTimeout(options: TimeoutOptions): TimeoutInterface {\n\treturn new Timeout(options)\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Creates a controllable deadline whose native signal aborts on expiry.
|
|
3
3
|
*
|
|
4
4
|
* @remarks
|
|
5
5
|
* `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.
|
|
6
6
|
* A parent `options.signal` clears an armed timeout without aborting the
|
|
7
|
-
* timeout's own signal.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* timeout's own signal. `start()` returns without arming when the parent
|
|
8
|
+
* `signal` supplied at construction has already aborted, so a handle whose
|
|
9
|
+
* parent aborted never expires again and its `signal` never fires. Omitted
|
|
10
|
+
* `options.id` values generate a random UUID. Malformed or unreadable options
|
|
11
|
+
* use contract code `bound`; invalid `id`, `ms`, and `signal` values use
|
|
12
|
+
* `literal`, `range`, and `placement`.
|
|
10
13
|
*
|
|
11
14
|
* @param options - Validated deadline, optional trace label, and optional native parent signal
|
|
12
15
|
* @returns A reusable timeout handle
|
|
13
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
16
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
14
17
|
* JavaScript input does not satisfy `TimeoutOptions`
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
@@ -29,10 +32,10 @@
|
|
|
29
32
|
export declare function createTimeout(options: TimeoutOptions): TimeoutInterface;
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
*
|
|
35
|
+
* Determines whether a value is an accepted timeout duration.
|
|
33
36
|
*
|
|
34
37
|
* @param value - Unknown duration candidate
|
|
35
|
-
* @returns
|
|
38
|
+
* @returns True if the value is an integer in the inclusive timeout range; false otherwise
|
|
36
39
|
*
|
|
37
40
|
* @example
|
|
38
41
|
* ```ts
|
|
@@ -43,7 +46,7 @@
|
|
|
43
46
|
export declare function isTimeoutDuration(value: unknown): value is number;
|
|
44
47
|
|
|
45
48
|
/**
|
|
46
|
-
*
|
|
49
|
+
* Determines whether a value is a genuine native `AbortSignal`.
|
|
47
50
|
*
|
|
48
51
|
* @remarks
|
|
49
52
|
* The intrinsic `aborted` getter performs the native brand check. The boundary
|
|
@@ -51,7 +54,7 @@
|
|
|
51
54
|
* allowing their errors to escape.
|
|
52
55
|
*
|
|
53
56
|
* @param value - Unknown signal candidate
|
|
54
|
-
* @returns
|
|
57
|
+
* @returns True if the native `AbortSignal` getter accepts the value; false otherwise
|
|
55
58
|
*
|
|
56
59
|
* @example
|
|
57
60
|
* ```ts
|
|
@@ -62,7 +65,7 @@
|
|
|
62
65
|
export declare function isTimeoutSignal(value: unknown): value is AbortSignal;
|
|
63
66
|
|
|
64
67
|
/**
|
|
65
|
-
*
|
|
68
|
+
* Names the largest timeout duration accepted by the package, in milliseconds.
|
|
66
69
|
*
|
|
67
70
|
* @example
|
|
68
71
|
* ```ts
|
|
@@ -72,7 +75,7 @@
|
|
|
72
75
|
export declare const MAX_TIMEOUT_MS = 2147483647;
|
|
73
76
|
|
|
74
77
|
/**
|
|
75
|
-
*
|
|
78
|
+
* Represents a controllable deadline whose native `AbortSignal` aborts when it expires.
|
|
76
79
|
*
|
|
77
80
|
* @remarks
|
|
78
81
|
* `start()` arms or replaces the current deadline. Expiry sets `expired` and
|
|
@@ -98,9 +101,9 @@
|
|
|
98
101
|
*/
|
|
99
102
|
export declare class Timeout implements TimeoutInterface {
|
|
100
103
|
#private;
|
|
101
|
-
readonly id: string;
|
|
102
|
-
readonly ms: number;
|
|
103
104
|
constructor(options: TimeoutOptions);
|
|
105
|
+
get id(): string;
|
|
106
|
+
get ms(): number;
|
|
104
107
|
get signal(): AbortSignal;
|
|
105
108
|
get expired(): boolean;
|
|
106
109
|
start(): void;
|
|
@@ -108,7 +111,7 @@
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
/**
|
|
111
|
-
*
|
|
114
|
+
* Represents a controllable deadline exposing a native `AbortSignal` that aborts on expiry.
|
|
112
115
|
*
|
|
113
116
|
* @example
|
|
114
117
|
* ```ts
|
|
@@ -118,22 +121,35 @@
|
|
|
118
121
|
* ```
|
|
119
122
|
*/
|
|
120
123
|
export declare interface TimeoutInterface {
|
|
121
|
-
/**
|
|
124
|
+
/** Holds the trace label supplied at construction or generated as a random UUID. */
|
|
122
125
|
readonly id: string;
|
|
123
|
-
/**
|
|
126
|
+
/** Holds the validated integer deadline in milliseconds. */
|
|
124
127
|
readonly ms: number;
|
|
125
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* Holds the native signal that aborts once when the current deadline
|
|
130
|
+
* expires. A `start()` or `clear()` call after an expiry installs a fresh
|
|
131
|
+
* signal, so a caller holding an earlier reference keeps the aborted one.
|
|
132
|
+
*/
|
|
126
133
|
readonly signal: AbortSignal;
|
|
127
|
-
/**
|
|
134
|
+
/** Reports whether the owned signal has aborted, derived directly from that signal. */
|
|
128
135
|
readonly expired: boolean;
|
|
129
136
|
/**
|
|
130
|
-
*
|
|
137
|
+
* Arms or re-arms the deadline.
|
|
138
|
+
*
|
|
139
|
+
* @remarks
|
|
140
|
+
* Returns without arming when the parent `signal` supplied at construction
|
|
141
|
+
* has already aborted, so a handle whose parent aborted never expires again
|
|
142
|
+
* and its `signal` never fires.
|
|
131
143
|
*
|
|
132
144
|
* @returns Nothing
|
|
133
145
|
*/
|
|
134
146
|
start(): void;
|
|
135
147
|
/**
|
|
136
|
-
*
|
|
148
|
+
* Cancels an armed deadline without aborting its signal and resets expiry state.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Installs a fresh non-aborted signal when the current signal has already
|
|
152
|
+
* aborted; a signal that never fired keeps its identity.
|
|
137
153
|
*
|
|
138
154
|
* @returns Nothing
|
|
139
155
|
*/
|
|
@@ -141,7 +157,7 @@
|
|
|
141
157
|
}
|
|
142
158
|
|
|
143
159
|
/**
|
|
144
|
-
*
|
|
160
|
+
* Represents the options for constructing a timeout deadline.
|
|
145
161
|
*
|
|
146
162
|
* @remarks
|
|
147
163
|
* `ms` is an integer from `0` through `2_147_483_647`, inclusive. `id`
|
|
@@ -155,16 +171,16 @@
|
|
|
155
171
|
* ```
|
|
156
172
|
*/
|
|
157
173
|
export declare interface TimeoutOptions {
|
|
158
|
-
/**
|
|
174
|
+
/** Holds the trace label for the timeout; omission generates a random UUID. */
|
|
159
175
|
readonly id?: string;
|
|
160
|
-
/**
|
|
176
|
+
/** Holds the integer deadline in milliseconds, inclusive from `0` through `2_147_483_647`. */
|
|
161
177
|
readonly ms: number;
|
|
162
|
-
/**
|
|
178
|
+
/** Holds the native parent signal whose abort clears an armed timeout. */
|
|
163
179
|
readonly signal?: AbortSignal;
|
|
164
180
|
}
|
|
165
181
|
|
|
166
182
|
/**
|
|
167
|
-
*
|
|
183
|
+
* Validates and normalizes timeout construction options.
|
|
168
184
|
*
|
|
169
185
|
* @remarks
|
|
170
186
|
* Each property is read exactly once before validation. The returned object is
|
|
@@ -173,8 +189,8 @@
|
|
|
173
189
|
*
|
|
174
190
|
* @param options - Potentially untrusted timeout options
|
|
175
191
|
* @returns A fresh validated `TimeoutOptions` object
|
|
176
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
177
|
-
* does not satisfy `TimeoutOptions`
|
|
192
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
193
|
+
* input does not satisfy `TimeoutOptions`
|
|
178
194
|
*
|
|
179
195
|
* @example
|
|
180
196
|
* ```ts
|
package/dist/src/core/index.d.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Creates a controllable deadline whose native signal aborts on expiry.
|
|
3
3
|
*
|
|
4
4
|
* @remarks
|
|
5
5
|
* `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.
|
|
6
6
|
* A parent `options.signal` clears an armed timeout without aborting the
|
|
7
|
-
* timeout's own signal.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* timeout's own signal. `start()` returns without arming when the parent
|
|
8
|
+
* `signal` supplied at construction has already aborted, so a handle whose
|
|
9
|
+
* parent aborted never expires again and its `signal` never fires. Omitted
|
|
10
|
+
* `options.id` values generate a random UUID. Malformed or unreadable options
|
|
11
|
+
* use contract code `bound`; invalid `id`, `ms`, and `signal` values use
|
|
12
|
+
* `literal`, `range`, and `placement`.
|
|
10
13
|
*
|
|
11
14
|
* @param options - Validated deadline, optional trace label, and optional native parent signal
|
|
12
15
|
* @returns A reusable timeout handle
|
|
13
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
16
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
14
17
|
* JavaScript input does not satisfy `TimeoutOptions`
|
|
15
18
|
*
|
|
16
19
|
* @example
|
|
@@ -29,10 +32,10 @@
|
|
|
29
32
|
export declare function createTimeout(options: TimeoutOptions): TimeoutInterface;
|
|
30
33
|
|
|
31
34
|
/**
|
|
32
|
-
*
|
|
35
|
+
* Determines whether a value is an accepted timeout duration.
|
|
33
36
|
*
|
|
34
37
|
* @param value - Unknown duration candidate
|
|
35
|
-
* @returns
|
|
38
|
+
* @returns True if the value is an integer in the inclusive timeout range; false otherwise
|
|
36
39
|
*
|
|
37
40
|
* @example
|
|
38
41
|
* ```ts
|
|
@@ -43,7 +46,7 @@
|
|
|
43
46
|
export declare function isTimeoutDuration(value: unknown): value is number;
|
|
44
47
|
|
|
45
48
|
/**
|
|
46
|
-
*
|
|
49
|
+
* Determines whether a value is a genuine native `AbortSignal`.
|
|
47
50
|
*
|
|
48
51
|
* @remarks
|
|
49
52
|
* The intrinsic `aborted` getter performs the native brand check. The boundary
|
|
@@ -51,7 +54,7 @@
|
|
|
51
54
|
* allowing their errors to escape.
|
|
52
55
|
*
|
|
53
56
|
* @param value - Unknown signal candidate
|
|
54
|
-
* @returns
|
|
57
|
+
* @returns True if the native `AbortSignal` getter accepts the value; false otherwise
|
|
55
58
|
*
|
|
56
59
|
* @example
|
|
57
60
|
* ```ts
|
|
@@ -62,7 +65,7 @@
|
|
|
62
65
|
export declare function isTimeoutSignal(value: unknown): value is AbortSignal;
|
|
63
66
|
|
|
64
67
|
/**
|
|
65
|
-
*
|
|
68
|
+
* Names the largest timeout duration accepted by the package, in milliseconds.
|
|
66
69
|
*
|
|
67
70
|
* @example
|
|
68
71
|
* ```ts
|
|
@@ -72,7 +75,7 @@
|
|
|
72
75
|
export declare const MAX_TIMEOUT_MS = 2147483647;
|
|
73
76
|
|
|
74
77
|
/**
|
|
75
|
-
*
|
|
78
|
+
* Represents a controllable deadline whose native `AbortSignal` aborts when it expires.
|
|
76
79
|
*
|
|
77
80
|
* @remarks
|
|
78
81
|
* `start()` arms or replaces the current deadline. Expiry sets `expired` and
|
|
@@ -98,9 +101,9 @@
|
|
|
98
101
|
*/
|
|
99
102
|
export declare class Timeout implements TimeoutInterface {
|
|
100
103
|
#private;
|
|
101
|
-
readonly id: string;
|
|
102
|
-
readonly ms: number;
|
|
103
104
|
constructor(options: TimeoutOptions);
|
|
105
|
+
get id(): string;
|
|
106
|
+
get ms(): number;
|
|
104
107
|
get signal(): AbortSignal;
|
|
105
108
|
get expired(): boolean;
|
|
106
109
|
start(): void;
|
|
@@ -108,7 +111,7 @@
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
/**
|
|
111
|
-
*
|
|
114
|
+
* Represents a controllable deadline exposing a native `AbortSignal` that aborts on expiry.
|
|
112
115
|
*
|
|
113
116
|
* @example
|
|
114
117
|
* ```ts
|
|
@@ -118,22 +121,35 @@
|
|
|
118
121
|
* ```
|
|
119
122
|
*/
|
|
120
123
|
export declare interface TimeoutInterface {
|
|
121
|
-
/**
|
|
124
|
+
/** Holds the trace label supplied at construction or generated as a random UUID. */
|
|
122
125
|
readonly id: string;
|
|
123
|
-
/**
|
|
126
|
+
/** Holds the validated integer deadline in milliseconds. */
|
|
124
127
|
readonly ms: number;
|
|
125
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* Holds the native signal that aborts once when the current deadline
|
|
130
|
+
* expires. A `start()` or `clear()` call after an expiry installs a fresh
|
|
131
|
+
* signal, so a caller holding an earlier reference keeps the aborted one.
|
|
132
|
+
*/
|
|
126
133
|
readonly signal: AbortSignal;
|
|
127
|
-
/**
|
|
134
|
+
/** Reports whether the owned signal has aborted, derived directly from that signal. */
|
|
128
135
|
readonly expired: boolean;
|
|
129
136
|
/**
|
|
130
|
-
*
|
|
137
|
+
* Arms or re-arms the deadline.
|
|
138
|
+
*
|
|
139
|
+
* @remarks
|
|
140
|
+
* Returns without arming when the parent `signal` supplied at construction
|
|
141
|
+
* has already aborted, so a handle whose parent aborted never expires again
|
|
142
|
+
* and its `signal` never fires.
|
|
131
143
|
*
|
|
132
144
|
* @returns Nothing
|
|
133
145
|
*/
|
|
134
146
|
start(): void;
|
|
135
147
|
/**
|
|
136
|
-
*
|
|
148
|
+
* Cancels an armed deadline without aborting its signal and resets expiry state.
|
|
149
|
+
*
|
|
150
|
+
* @remarks
|
|
151
|
+
* Installs a fresh non-aborted signal when the current signal has already
|
|
152
|
+
* aborted; a signal that never fired keeps its identity.
|
|
137
153
|
*
|
|
138
154
|
* @returns Nothing
|
|
139
155
|
*/
|
|
@@ -141,7 +157,7 @@
|
|
|
141
157
|
}
|
|
142
158
|
|
|
143
159
|
/**
|
|
144
|
-
*
|
|
160
|
+
* Represents the options for constructing a timeout deadline.
|
|
145
161
|
*
|
|
146
162
|
* @remarks
|
|
147
163
|
* `ms` is an integer from `0` through `2_147_483_647`, inclusive. `id`
|
|
@@ -155,16 +171,16 @@
|
|
|
155
171
|
* ```
|
|
156
172
|
*/
|
|
157
173
|
export declare interface TimeoutOptions {
|
|
158
|
-
/**
|
|
174
|
+
/** Holds the trace label for the timeout; omission generates a random UUID. */
|
|
159
175
|
readonly id?: string;
|
|
160
|
-
/**
|
|
176
|
+
/** Holds the integer deadline in milliseconds, inclusive from `0` through `2_147_483_647`. */
|
|
161
177
|
readonly ms: number;
|
|
162
|
-
/**
|
|
178
|
+
/** Holds the native parent signal whose abort clears an armed timeout. */
|
|
163
179
|
readonly signal?: AbortSignal;
|
|
164
180
|
}
|
|
165
181
|
|
|
166
182
|
/**
|
|
167
|
-
*
|
|
183
|
+
* Validates and normalizes timeout construction options.
|
|
168
184
|
*
|
|
169
185
|
* @remarks
|
|
170
186
|
* Each property is read exactly once before validation. The returned object is
|
|
@@ -173,8 +189,8 @@
|
|
|
173
189
|
*
|
|
174
190
|
* @param options - Potentially untrusted timeout options
|
|
175
191
|
* @returns A fresh validated `TimeoutOptions` object
|
|
176
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
177
|
-
* does not satisfy `TimeoutOptions`
|
|
192
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
193
|
+
* input does not satisfy `TimeoutOptions`
|
|
178
194
|
*
|
|
179
195
|
* @example
|
|
180
196
|
* ```ts
|
package/dist/src/core/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ContractError,
|
|
1
|
+
import { ContractError, isInteger, isRecord, isString, preview } from "@orkestrel/contract";
|
|
2
2
|
//#region src/core/constants.ts
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Names the largest timeout duration accepted by the package, in milliseconds.
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
7
|
* ```ts
|
|
@@ -12,10 +12,10 @@ var MAX_TIMEOUT_MS = 2147483647;
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/core/validators.ts
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Determines whether a value is an accepted timeout duration.
|
|
16
16
|
*
|
|
17
17
|
* @param value - Unknown duration candidate
|
|
18
|
-
* @returns
|
|
18
|
+
* @returns True if the value is an integer in the inclusive timeout range; false otherwise
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* ```ts
|
|
@@ -24,10 +24,10 @@ var MAX_TIMEOUT_MS = 2147483647;
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
function isTimeoutDuration(value) {
|
|
27
|
-
return
|
|
27
|
+
return isInteger(value) && value >= 0 && value <= 2147483647;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
30
|
+
* Determines whether a value is a genuine native `AbortSignal`.
|
|
31
31
|
*
|
|
32
32
|
* @remarks
|
|
33
33
|
* The intrinsic `aborted` getter performs the native brand check. The boundary
|
|
@@ -35,7 +35,7 @@ function isTimeoutDuration(value) {
|
|
|
35
35
|
* allowing their errors to escape.
|
|
36
36
|
*
|
|
37
37
|
* @param value - Unknown signal candidate
|
|
38
|
-
* @returns
|
|
38
|
+
* @returns True if the native `AbortSignal` getter accepts the value; false otherwise
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
41
41
|
* ```ts
|
|
@@ -55,7 +55,7 @@ function isTimeoutSignal(value) {
|
|
|
55
55
|
//#endregion
|
|
56
56
|
//#region src/core/helpers.ts
|
|
57
57
|
/**
|
|
58
|
-
*
|
|
58
|
+
* Validates and normalizes timeout construction options.
|
|
59
59
|
*
|
|
60
60
|
* @remarks
|
|
61
61
|
* Each property is read exactly once before validation. The returned object is
|
|
@@ -64,8 +64,8 @@ function isTimeoutSignal(value) {
|
|
|
64
64
|
*
|
|
65
65
|
* @param options - Potentially untrusted timeout options
|
|
66
66
|
* @returns A fresh validated `TimeoutOptions` object
|
|
67
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
68
|
-
* does not satisfy `TimeoutOptions`
|
|
67
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
68
|
+
* input does not satisfy `TimeoutOptions`
|
|
69
69
|
*
|
|
70
70
|
* @example
|
|
71
71
|
* ```ts
|
|
@@ -141,7 +141,7 @@ function validateTimeoutOptions(options) {
|
|
|
141
141
|
//#endregion
|
|
142
142
|
//#region src/core/Timeout.ts
|
|
143
143
|
/**
|
|
144
|
-
*
|
|
144
|
+
* Represents a controllable deadline whose native `AbortSignal` aborts when it expires.
|
|
145
145
|
*
|
|
146
146
|
* @remarks
|
|
147
147
|
* `start()` arms or replaces the current deadline. Expiry sets `expired` and
|
|
@@ -166,21 +166,26 @@ function validateTimeoutOptions(options) {
|
|
|
166
166
|
* ```
|
|
167
167
|
*/
|
|
168
168
|
var Timeout = class {
|
|
169
|
-
id;
|
|
170
|
-
ms;
|
|
169
|
+
#id;
|
|
170
|
+
#ms;
|
|
171
171
|
#parent;
|
|
172
172
|
#listener;
|
|
173
173
|
#controller;
|
|
174
174
|
#handle;
|
|
175
|
-
#linked = false;
|
|
176
175
|
constructor(options) {
|
|
177
176
|
const input = validateTimeoutOptions(options);
|
|
178
|
-
this
|
|
179
|
-
this
|
|
177
|
+
this.#id = input.id === void 0 ? crypto.randomUUID() : input.id;
|
|
178
|
+
this.#ms = input.ms;
|
|
180
179
|
this.#parent = input.signal;
|
|
181
180
|
this.#controller = new AbortController();
|
|
182
181
|
this.#listener = this.clear.bind(this);
|
|
183
182
|
}
|
|
183
|
+
get id() {
|
|
184
|
+
return this.#id;
|
|
185
|
+
}
|
|
186
|
+
get ms() {
|
|
187
|
+
return this.#ms;
|
|
188
|
+
}
|
|
184
189
|
get signal() {
|
|
185
190
|
return this.#controller.signal;
|
|
186
191
|
}
|
|
@@ -195,15 +200,12 @@ var Timeout = class {
|
|
|
195
200
|
}
|
|
196
201
|
this.#detach();
|
|
197
202
|
if (this.#controller.signal.aborted) this.#controller = new AbortController();
|
|
198
|
-
if (this.#parent !== void 0) {
|
|
199
|
-
this.#parent.addEventListener("abort", this.#listener, { once: true });
|
|
200
|
-
this.#linked = true;
|
|
201
|
-
}
|
|
203
|
+
if (this.#parent !== void 0) this.#parent.addEventListener("abort", this.#listener, { once: true });
|
|
202
204
|
this.#handle = setTimeout(() => {
|
|
203
205
|
this.#handle = void 0;
|
|
204
206
|
this.#detach();
|
|
205
207
|
this.#controller.abort();
|
|
206
|
-
}, this
|
|
208
|
+
}, this.#ms);
|
|
207
209
|
}
|
|
208
210
|
clear() {
|
|
209
211
|
if (this.#handle !== void 0) {
|
|
@@ -214,27 +216,27 @@ var Timeout = class {
|
|
|
214
216
|
if (this.#controller.signal.aborted) this.#controller = new AbortController();
|
|
215
217
|
}
|
|
216
218
|
#detach() {
|
|
217
|
-
|
|
218
|
-
this.#parent?.removeEventListener("abort", this.#listener);
|
|
219
|
-
this.#linked = false;
|
|
220
|
-
}
|
|
219
|
+
this.#parent?.removeEventListener("abort", this.#listener);
|
|
221
220
|
}
|
|
222
221
|
};
|
|
223
222
|
//#endregion
|
|
224
223
|
//#region src/core/factories.ts
|
|
225
224
|
/**
|
|
226
|
-
*
|
|
225
|
+
* Creates a controllable deadline whose native signal aborts on expiry.
|
|
227
226
|
*
|
|
228
227
|
* @remarks
|
|
229
228
|
* `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.
|
|
230
229
|
* A parent `options.signal` clears an armed timeout without aborting the
|
|
231
|
-
* timeout's own signal.
|
|
232
|
-
*
|
|
233
|
-
*
|
|
230
|
+
* timeout's own signal. `start()` returns without arming when the parent
|
|
231
|
+
* `signal` supplied at construction has already aborted, so a handle whose
|
|
232
|
+
* parent aborted never expires again and its `signal` never fires. Omitted
|
|
233
|
+
* `options.id` values generate a random UUID. Malformed or unreadable options
|
|
234
|
+
* use contract code `bound`; invalid `id`, `ms`, and `signal` values use
|
|
235
|
+
* `literal`, `range`, and `placement`.
|
|
234
236
|
*
|
|
235
237
|
* @param options - Validated deadline, optional trace label, and optional native parent signal
|
|
236
238
|
* @returns A reusable timeout handle
|
|
237
|
-
* @throws {@link import('@orkestrel/contract').ContractError}
|
|
239
|
+
* @throws {@link import('@orkestrel/contract').ContractError} Thrown when the
|
|
238
240
|
* JavaScript input does not satisfy `TimeoutOptions`
|
|
239
241
|
*
|
|
240
242
|
* @example
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#parent","#listener","#controller","#handle","#detach","#linked"],"sources":["../../../src/core/constants.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Timeout.ts","../../../src/core/factories.ts"],"sourcesContent":["/**\n * Largest timeout duration accepted by the package, in milliseconds.\n *\n * @example\n * ```ts\n * createTimeout({ ms: MAX_TIMEOUT_MS })\n * ```\n */\nexport const MAX_TIMEOUT_MS = 2_147_483_647\n","import { isFiniteNumber, isInteger } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\n\n/**\n * Determine whether a value is an accepted timeout duration.\n *\n * @param value - Unknown duration candidate\n * @returns `true` only for an integer in the inclusive timeout range\n *\n * @example\n * ```ts\n * isTimeoutDuration(0) // true\n * isTimeoutDuration(1.5) // false\n * ```\n */\nexport function isTimeoutDuration(value: unknown): value is number {\n\treturn isFiniteNumber(value) && isInteger(value) && value >= 0 && value <= MAX_TIMEOUT_MS\n}\n\n/**\n * Determine whether a value is a genuine native `AbortSignal`.\n *\n * @remarks\n * The intrinsic `aborted` getter performs the native brand check. The boundary\n * contains revoked proxies and hostile receivers, returning `false` instead of\n * allowing their errors to escape.\n *\n * @param value - Unknown signal candidate\n * @returns `true` only when the native `AbortSignal` getter accepts the value\n *\n * @example\n * ```ts\n * isTimeoutSignal(new AbortController().signal) // true\n * isTimeoutSignal({ aborted: false }) // false\n * ```\n */\nexport function isTimeoutSignal(value: unknown): value is AbortSignal {\n\ttry {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')\n\t\tif (descriptor?.get === undefined) return false\n\t\treturn typeof Reflect.apply(descriptor.get, value, []) === 'boolean'\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { TimeoutOptions } from './types.js'\nimport { ContractError, isRecord, isString, preview } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\nimport { isTimeoutDuration, isTimeoutSignal } from './validators.js'\n\n/**\n * Validate and normalize timeout construction options.\n *\n * @remarks\n * Each property is read exactly once before validation. The returned object is\n * a fresh copy and omits absent optional properties. No timer, controller, or\n * listener lifecycle begins at this boundary.\n *\n * @param options - Potentially untrusted timeout options\n * @returns A fresh validated `TimeoutOptions` object\n * @throws {@link import('@orkestrel/contract').ContractError} When the input\n * does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * const options = validateTimeoutOptions({ ms: 5_000 })\n * ```\n */\nexport function validateTimeoutOptions(options: TimeoutOptions): TimeoutOptions {\n\tif (!isRecord(options)) {\n\t\tthrow new ContractError('Timeout: options must be a plain record', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t})\n\t}\n\n\tlet id: TimeoutOptions['id']\n\tlet ms: TimeoutOptions['ms']\n\tlet signal: TimeoutOptions['signal']\n\ttry {\n\t\tid = options.id\n\t\tms = options.ms\n\t\tsignal = options.signal\n\t} catch (cause) {\n\t\tthrow new ContractError('Timeout: options could not be read', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'readable plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t\tcause,\n\t\t})\n\t}\n\n\tif (id !== undefined && !isString(id)) {\n\t\tthrow new ContractError('Timeout: id must be a string when defined', {\n\t\t\tcode: 'literal',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'id'],\n\t\t\t\tlimit: 'string or undefined',\n\t\t\t\treceived: preview(id),\n\t\t\t},\n\t\t})\n\t}\n\tif (!isTimeoutDuration(ms)) {\n\t\tthrow new ContractError('Timeout: ms must be an integer in the supported range', {\n\t\t\tcode: 'range',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'ms'],\n\t\t\t\tlimit: `integer in [0, ${MAX_TIMEOUT_MS}]`,\n\t\t\t\treceived: preview(ms),\n\t\t\t},\n\t\t})\n\t}\n\tif (signal !== undefined && !isTimeoutSignal(signal)) {\n\t\tthrow new ContractError('Timeout: signal must be a native AbortSignal when defined', {\n\t\t\tcode: 'placement',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'signal'],\n\t\t\t\tlimit: 'native AbortSignal or undefined',\n\t\t\t\treceived: preview(signal),\n\t\t\t},\n\t\t})\n\t}\n\n\tif (id !== undefined && signal !== undefined) return { id, ms, signal }\n\tif (id !== undefined) return { id, ms }\n\tif (signal !== undefined) return { ms, signal }\n\treturn { ms }\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { validateTimeoutOptions } from './helpers.js'\n\n/**\n * A controllable deadline whose native `AbortSignal` aborts when it expires.\n *\n * @remarks\n * `start()` arms or replaces the current deadline. Expiry sets `expired` and\n * aborts the current signal once. `clear()` cancels without aborting and resets\n * `expired`. Starting or clearing after expiry installs a fresh signal. A parent\n * abort deliberately clears the timeout without aborting its signal; once the\n * parent has aborted, later starts are inert.\n *\n * Construction validates the complete JavaScript boundary before creating an\n * `AbortController`. A malformed or unreadable options record throws a\n * `bound`-coded {@link import('@orkestrel/contract').ContractError}; an invalid\n * `id`, `ms`, or `signal` uses `literal`, `range`, or `placement`, respectively.\n *\n * @example\n * ```ts\n * import { Timeout } from '@orkestrel/timeout'\n *\n * const timeout = new Timeout({ ms: 5_000 })\n * timeout.start()\n * timeout.signal.addEventListener('abort', () => giveUp(), { once: true })\n * timeout.clear()\n * ```\n */\nexport class Timeout implements TimeoutInterface {\n\treadonly id: string\n\treadonly ms: number\n\treadonly #parent: AbortSignal | undefined\n\treadonly #listener: () => void\n\t#controller: AbortController\n\t#handle: ReturnType<typeof setTimeout> | undefined\n\t#linked = false\n\n\tconstructor(options: TimeoutOptions) {\n\t\tconst input = validateTimeoutOptions(options)\n\t\tthis.id = input.id === undefined ? crypto.randomUUID() : input.id\n\t\tthis.ms = input.ms\n\t\tthis.#parent = input.signal\n\t\tthis.#controller = new AbortController()\n\t\tthis.#listener = this.clear.bind(this)\n\t}\n\n\tget signal(): AbortSignal {\n\t\treturn this.#controller.signal\n\t}\n\n\tget expired(): boolean {\n\t\treturn this.#controller.signal.aborted\n\t}\n\n\tstart(): void {\n\t\tif (this.#parent?.aborted === true) return\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t\tif (this.#parent !== undefined) {\n\t\t\tthis.#parent.addEventListener('abort', this.#listener, { once: true })\n\t\t\tthis.#linked = true\n\t\t}\n\t\tthis.#handle = setTimeout(() => {\n\t\t\tthis.#handle = undefined\n\t\t\tthis.#detach()\n\t\t\tthis.#controller.abort()\n\t\t}, this.ms)\n\t}\n\n\tclear(): void {\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t}\n\n\t#detach(): void {\n\t\tif (this.#linked) {\n\t\t\tthis.#parent?.removeEventListener('abort', this.#listener)\n\t\t\tthis.#linked = false\n\t\t}\n\t}\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { Timeout } from './Timeout.js'\n\n/**\n * Create a controllable deadline whose native signal aborts on expiry.\n *\n * @remarks\n * `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.\n * A parent `options.signal` clears an armed timeout without aborting the\n * timeout's own signal. Omitted `options.id` values generate a random UUID.\n * Malformed or unreadable options use contract code `bound`; invalid `id`,\n * `ms`, and `signal` values use `literal`, `range`, and `placement`.\n *\n * @param options - Validated deadline, optional trace label, and optional native parent signal\n * @returns A reusable timeout handle\n * @throws {@link import('@orkestrel/contract').ContractError} When the\n * JavaScript input does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * import { createTimeout } from '@orkestrel/timeout'\n *\n * const timeout = createTimeout({ ms: 5_000 })\n * timeout.start()\n * try {\n * \tawait fetch('/work', { signal: timeout.signal })\n * } finally {\n * \ttimeout.clear()\n * }\n * ```\n */\nexport function createTimeout(options: TimeoutOptions): TimeoutInterface {\n\treturn new Timeout(options)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["#id","#ms","#parent","#listener","#controller","#handle","#detach"],"sources":["../../../src/core/constants.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Timeout.ts","../../../src/core/factories.ts"],"sourcesContent":["/**\n * Names the largest timeout duration accepted by the package, in milliseconds.\n *\n * @example\n * ```ts\n * createTimeout({ ms: MAX_TIMEOUT_MS })\n * ```\n */\nexport const MAX_TIMEOUT_MS = 2_147_483_647\n","import { isInteger } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\n\n/**\n * Determines whether a value is an accepted timeout duration.\n *\n * @param value - Unknown duration candidate\n * @returns True if the value is an integer in the inclusive timeout range; false otherwise\n *\n * @example\n * ```ts\n * isTimeoutDuration(0) // true\n * isTimeoutDuration(1.5) // false\n * ```\n */\nexport function isTimeoutDuration(value: unknown): value is number {\n\treturn isInteger(value) && value >= 0 && value <= MAX_TIMEOUT_MS\n}\n\n/**\n * Determines whether a value is a genuine native `AbortSignal`.\n *\n * @remarks\n * The intrinsic `aborted` getter performs the native brand check. The boundary\n * contains revoked proxies and hostile receivers, returning `false` instead of\n * allowing their errors to escape.\n *\n * @param value - Unknown signal candidate\n * @returns True if the native `AbortSignal` getter accepts the value; false otherwise\n *\n * @example\n * ```ts\n * isTimeoutSignal(new AbortController().signal) // true\n * isTimeoutSignal({ aborted: false }) // false\n * ```\n */\nexport function isTimeoutSignal(value: unknown): value is AbortSignal {\n\ttry {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted')\n\t\tif (descriptor?.get === undefined) return false\n\t\treturn typeof Reflect.apply(descriptor.get, value, []) === 'boolean'\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { TimeoutOptions } from './types.js'\nimport { ContractError, isRecord, isString, preview } from '@orkestrel/contract'\nimport { MAX_TIMEOUT_MS } from './constants.js'\nimport { isTimeoutDuration, isTimeoutSignal } from './validators.js'\n\n/**\n * Validates and normalizes timeout construction options.\n *\n * @remarks\n * Each property is read exactly once before validation. The returned object is\n * a fresh copy and omits absent optional properties. No timer, controller, or\n * listener lifecycle begins at this boundary.\n *\n * @param options - Potentially untrusted timeout options\n * @returns A fresh validated `TimeoutOptions` object\n * @throws {@link import('@orkestrel/contract').ContractError} Thrown when the\n * input does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * const options = validateTimeoutOptions({ ms: 5_000 })\n * ```\n */\nexport function validateTimeoutOptions(options: TimeoutOptions): TimeoutOptions {\n\tif (!isRecord(options)) {\n\t\tthrow new ContractError('Timeout: options must be a plain record', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t})\n\t}\n\n\tlet id: TimeoutOptions['id']\n\tlet ms: TimeoutOptions['ms']\n\tlet signal: TimeoutOptions['signal']\n\ttry {\n\t\tid = options.id\n\t\tms = options.ms\n\t\tsignal = options.signal\n\t} catch (cause) {\n\t\tthrow new ContractError('Timeout: options could not be read', {\n\t\t\tcode: 'bound',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options'],\n\t\t\t\tlimit: 'readable plain record',\n\t\t\t\treceived: preview(options),\n\t\t\t},\n\t\t\tcause,\n\t\t})\n\t}\n\n\tif (id !== undefined && !isString(id)) {\n\t\tthrow new ContractError('Timeout: id must be a string when defined', {\n\t\t\tcode: 'literal',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'id'],\n\t\t\t\tlimit: 'string or undefined',\n\t\t\t\treceived: preview(id),\n\t\t\t},\n\t\t})\n\t}\n\tif (!isTimeoutDuration(ms)) {\n\t\tthrow new ContractError('Timeout: ms must be an integer in the supported range', {\n\t\t\tcode: 'range',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'ms'],\n\t\t\t\tlimit: `integer in [0, ${MAX_TIMEOUT_MS}]`,\n\t\t\t\treceived: preview(ms),\n\t\t\t},\n\t\t})\n\t}\n\tif (signal !== undefined && !isTimeoutSignal(signal)) {\n\t\tthrow new ContractError('Timeout: signal must be a native AbortSignal when defined', {\n\t\t\tcode: 'placement',\n\t\t\tcontext: {\n\t\t\t\tpath: ['options', 'signal'],\n\t\t\t\tlimit: 'native AbortSignal or undefined',\n\t\t\t\treceived: preview(signal),\n\t\t\t},\n\t\t})\n\t}\n\n\tif (id !== undefined && signal !== undefined) return { id, ms, signal }\n\tif (id !== undefined) return { id, ms }\n\tif (signal !== undefined) return { ms, signal }\n\treturn { ms }\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { validateTimeoutOptions } from './helpers.js'\n\n/**\n * Represents a controllable deadline whose native `AbortSignal` aborts when it expires.\n *\n * @remarks\n * `start()` arms or replaces the current deadline. Expiry sets `expired` and\n * aborts the current signal once. `clear()` cancels without aborting and resets\n * `expired`. Starting or clearing after expiry installs a fresh signal. A parent\n * abort deliberately clears the timeout without aborting its signal; once the\n * parent has aborted, later starts are inert.\n *\n * Construction validates the complete JavaScript boundary before creating an\n * `AbortController`. A malformed or unreadable options record throws a\n * `bound`-coded {@link import('@orkestrel/contract').ContractError}; an invalid\n * `id`, `ms`, or `signal` uses `literal`, `range`, or `placement`, respectively.\n *\n * @example\n * ```ts\n * import { Timeout } from '@orkestrel/timeout'\n *\n * const timeout = new Timeout({ ms: 5_000 })\n * timeout.start()\n * timeout.signal.addEventListener('abort', () => giveUp(), { once: true })\n * timeout.clear()\n * ```\n */\nexport class Timeout implements TimeoutInterface {\n\treadonly #id: string\n\treadonly #ms: number\n\treadonly #parent: AbortSignal | undefined\n\treadonly #listener: () => void\n\t#controller: AbortController\n\t#handle: ReturnType<typeof setTimeout> | undefined\n\n\tconstructor(options: TimeoutOptions) {\n\t\tconst input = validateTimeoutOptions(options)\n\t\tthis.#id = input.id === undefined ? crypto.randomUUID() : input.id\n\t\tthis.#ms = input.ms\n\t\tthis.#parent = input.signal\n\t\tthis.#controller = new AbortController()\n\t\tthis.#listener = this.clear.bind(this)\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget ms(): number {\n\t\treturn this.#ms\n\t}\n\n\tget signal(): AbortSignal {\n\t\treturn this.#controller.signal\n\t}\n\n\tget expired(): boolean {\n\t\treturn this.#controller.signal.aborted\n\t}\n\n\tstart(): void {\n\t\tif (this.#parent?.aborted === true) return\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t\tif (this.#parent !== undefined) {\n\t\t\tthis.#parent.addEventListener('abort', this.#listener, { once: true })\n\t\t}\n\t\tthis.#handle = setTimeout(() => {\n\t\t\tthis.#handle = undefined\n\t\t\tthis.#detach()\n\t\t\tthis.#controller.abort()\n\t\t}, this.#ms)\n\t}\n\n\tclear(): void {\n\t\tif (this.#handle !== undefined) {\n\t\t\tclearTimeout(this.#handle)\n\t\t\tthis.#handle = undefined\n\t\t}\n\t\tthis.#detach()\n\t\tif (this.#controller.signal.aborted) this.#controller = new AbortController()\n\t}\n\n\t#detach(): void {\n\t\tthis.#parent?.removeEventListener('abort', this.#listener)\n\t}\n}\n","import type { TimeoutInterface, TimeoutOptions } from './types.js'\nimport { Timeout } from './Timeout.js'\n\n/**\n * Creates a controllable deadline whose native signal aborts on expiry.\n *\n * @remarks\n * `options.ms` must be an integer from `0` through `2_147_483_647`, inclusive.\n * A parent `options.signal` clears an armed timeout without aborting the\n * timeout's own signal. `start()` returns without arming when the parent\n * `signal` supplied at construction has already aborted, so a handle whose\n * parent aborted never expires again and its `signal` never fires. Omitted\n * `options.id` values generate a random UUID. Malformed or unreadable options\n * use contract code `bound`; invalid `id`, `ms`, and `signal` values use\n * `literal`, `range`, and `placement`.\n *\n * @param options - Validated deadline, optional trace label, and optional native parent signal\n * @returns A reusable timeout handle\n * @throws {@link import('@orkestrel/contract').ContractError} Thrown when the\n * JavaScript input does not satisfy `TimeoutOptions`\n *\n * @example\n * ```ts\n * import { createTimeout } from '@orkestrel/timeout'\n *\n * const timeout = createTimeout({ ms: 5_000 })\n * timeout.start()\n * try {\n * \tawait fetch('/work', { signal: timeout.signal })\n * } finally {\n * \ttimeout.clear()\n * }\n * ```\n */\nexport function createTimeout(options: TimeoutOptions): TimeoutInterface {\n\treturn new Timeout(options)\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkestrel/timeout",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "A typed, controllable setTimeout wrapper — an AbortSignal deadline with start/clear lifecycle and parent-signal linking. Part of the @orkestrel line.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"abort-signal",
|
|
@@ -46,40 +46,44 @@
|
|
|
46
46
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
47
47
|
"copy": "node -e \"const fs=require('node:fs'),p=require('node:path'),a=process.argv[1],b=process.argv[2];fs.mkdirSync(p.dirname(b),{recursive:true});fs.cpSync(a,b,{force:true});console.log('Copied: '+a+' to '+b)\"",
|
|
48
48
|
"scaffold": "scaffold",
|
|
49
|
-
"lint": "oxlint --config .oxlintrc.json --fix
|
|
49
|
+
"lint": "oxlint --config .oxlintrc.json --fix .",
|
|
50
50
|
"check": "tsc --noEmit --project tsconfig.json && npm run check:src",
|
|
51
51
|
"check:src": "npm run check:src:core",
|
|
52
52
|
"check:src:core": "tsc --noEmit -p configs/src/tsconfig.core.json",
|
|
53
53
|
"format": "oxfmt --config .oxfmtrc.json --write .",
|
|
54
54
|
"format:check": "oxfmt --config .oxfmtrc.json --check .",
|
|
55
55
|
"lint:check": "oxlint --config .oxlintrc.json --deny-warnings .",
|
|
56
|
-
"test": "npm run test:src && npm run test:policy && npm run test:config && npm run test:guides",
|
|
56
|
+
"test": "npm run test:src && npm run test:policy && npm run test:config && npm run test:setup && npm run test:guides",
|
|
57
57
|
"test:src": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
|
|
58
58
|
"test:src:core": "vitest run --config vite.config.ts --no-cache --reporter=dot --project src:core",
|
|
59
59
|
"test:policy": "vitest run --config vite.config.ts --no-cache --reporter=dot --project policy",
|
|
60
60
|
"test:config": "vitest run --config vite.config.ts --no-cache --reporter=dot --project config",
|
|
61
|
-
"test:guides": "vitest run --config vite.config.ts --reporter=dot --project guides",
|
|
61
|
+
"test:guides": "vitest run --config vite.config.ts --no-cache --reporter=dot --project guides",
|
|
62
62
|
"build": "npm run clean && npm run build:src",
|
|
63
63
|
"build:src": "npm run build:src:core",
|
|
64
64
|
"build:src:core": "vite build --config configs/src/vite.core.config.ts && npm run copy dist/src/core/index.d.ts dist/src/core/index.d.cts",
|
|
65
|
-
"prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test"
|
|
65
|
+
"prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test && npm run test:distribution -- --mode release",
|
|
66
|
+
"test:distribution": "vitest run --config vite.config.ts --no-cache --reporter=dot --project distribution",
|
|
67
|
+
"test:probe": "vitest run --config vite.config.ts --no-cache --reporter=verbose --project probe",
|
|
68
|
+
"test:bench": "vitest bench --config vite.config.ts --no-cache --project probe",
|
|
69
|
+
"prepack": "npm run build",
|
|
70
|
+
"test:setup": "vitest run --config vite.config.ts --no-cache --reporter=dot --project setup"
|
|
66
71
|
},
|
|
67
72
|
"dependencies": {
|
|
68
|
-
"@orkestrel/contract": "^0.0.
|
|
73
|
+
"@orkestrel/contract": "^0.0.16"
|
|
69
74
|
},
|
|
70
75
|
"devDependencies": {
|
|
71
76
|
"@microsoft/api-extractor": "^7.59.0",
|
|
72
|
-
"@orkestrel/guide": "^0.0.
|
|
73
|
-
"@orkestrel/probe": "^0.0.
|
|
74
|
-
"@orkestrel/scaffold": "^0.0.
|
|
75
|
-
"@orkestrel/test": "^0.0.
|
|
76
|
-
"@types/node": "^26.
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"oxlint": "^1.79.0",
|
|
77
|
+
"@orkestrel/guide": "^0.0.16",
|
|
78
|
+
"@orkestrel/probe": "^0.0.11",
|
|
79
|
+
"@orkestrel/scaffold": "^0.0.61",
|
|
80
|
+
"@orkestrel/test": "^0.0.13",
|
|
81
|
+
"@types/node": "^26.4.1",
|
|
82
|
+
"oxfmt": "^0.66.0",
|
|
83
|
+
"oxlint": "^1.81.0",
|
|
80
84
|
"typescript": "^6.0.3",
|
|
81
85
|
"vite": "^8.2.2",
|
|
82
|
-
"vite-plugin-dts": "^5.0
|
|
86
|
+
"vite-plugin-dts": "^5.1.0",
|
|
83
87
|
"vitest": "^4.1.11"
|
|
84
88
|
},
|
|
85
89
|
"engines": {
|