@orkestrel/workflow 0.0.1

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.
@@ -0,0 +1,399 @@
1
+ import { isFunction, isRecord } from "@orkestrel/contract";
2
+ //#region src/browser/constants.ts
3
+ /**
4
+ * The browser-native `postTask` priority for each portable {@link SchedulerPriority} — the
5
+ * Prioritized Task Scheduling API's three levels.
6
+ *
7
+ * @remarks
8
+ * A `user` hint maps to the most urgent `'user-blocking'`, `normal` to the default
9
+ * `'user-visible'`, and `background` to `'background'`. {@link BrowserScheduler} reads this
10
+ * map to translate the caller's portable priority into the value passed to
11
+ * `scheduler.postTask`, so the urgency hint is honoured by the host.
12
+ */
13
+ var POST_TASK_PRIORITY = {
14
+ user: "user-blocking",
15
+ normal: "user-visible",
16
+ background: "background"
17
+ };
18
+ //#endregion
19
+ //#region src/browser/BrowserScheduler.ts
20
+ /**
21
+ * The browser {@link SchedulerInterface} — the browser-native cooperative-yield backend
22
+ * built on the Prioritized Task Scheduling API (`scheduler.postTask`), falling back to a
23
+ * zero-delay macrotask where it is absent.
24
+ *
25
+ * @remarks
26
+ * - **`yield` prefers `scheduler.postTask`, honouring priority.** When `globalThis`
27
+ * exposes a `scheduler` with a `postTask` method, `yield()` posts a task at the mapped
28
+ * priority (`user` → `'user-blocking'`, `normal` → `'user-visible'`, `background` →
29
+ * `'background'`), so the host genuinely regains control and the urgency hint is
30
+ * honoured. The capability is feature-detected through guards (`isRecord` / `isFunction`),
31
+ * never an `as` (AGENTS §14). Where the API is absent (Firefox today, older engines),
32
+ * it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn, just
33
+ * without priority. `delay(ms)` is always a real `setTimeout`.
34
+ * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with `signal.reason`
35
+ * exactly — the value the caller passed, never wrapped or replaced. The discipline
36
+ * mirrors the cross-environment default's `#sleep`: an already-aborted signal rejects
37
+ * immediately WITHOUT scheduling; otherwise the host-turn is scheduled and a
38
+ * `{ once: true }` abort listener attached, and the two settle paths are mutually
39
+ * exclusive — the turn path removes the listener before resolving, and the abort path
40
+ * cancels the scheduled turn before rejecting. The promise settles exactly once, with no
41
+ * leaked task/timer and no leaked listener. The caller's `signal` is NOT handed to
42
+ * `postTask` (whose own abort would reject with a platform `AbortError`, not the
43
+ * caller's `reason`); instead an internal controller cancels the posted task while this
44
+ * scheduler rejects with the verbatim `signal.reason`.
45
+ * - **Event-free.** A pure functional primitive — no Emitter, no events.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { createAbort } from '@src/core'
50
+ * import { BrowserScheduler } from '@src/browser'
51
+ *
52
+ * const abort = createAbort()
53
+ * const scheduler = new BrowserScheduler()
54
+ * while (!abort.signal.aborted) {
55
+ * doSomeWork()
56
+ * await scheduler.yield({ priority: 'background', signal: abort.signal })
57
+ * }
58
+ * ```
59
+ */
60
+ var BrowserScheduler = class {
61
+ /**
62
+ * Yield control to the host via `scheduler.postTask` at the given priority (or a
63
+ * `setTimeout(0)` macrotask where the API is absent), then resume; abort rejects with
64
+ * `signal.reason`.
65
+ */
66
+ yield(options) {
67
+ const post = this.#postTask();
68
+ if (post === void 0) return this.#macrotask(options?.signal);
69
+ return this.#yieldVia(post, options?.priority ?? "normal", options?.signal);
70
+ }
71
+ /**
72
+ * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
73
+ * `signal.reason`.
74
+ *
75
+ * @remarks
76
+ * `ms` should be a non-negative finite number. The primitive does no validation: it
77
+ * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
78
+ * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
79
+ * throwing.
80
+ */
81
+ delay(ms, options) {
82
+ return this.#timer(ms, options?.signal);
83
+ }
84
+ #postTask() {
85
+ const candidate = Reflect.get(globalThis, "scheduler");
86
+ if (!isRecord(candidate)) return void 0;
87
+ const post = candidate.postTask;
88
+ if (!isFunction(post)) return void 0;
89
+ return (callback, options) => Reflect.apply(post, candidate, [callback, options]);
90
+ }
91
+ #yieldVia(post, priority, signal) {
92
+ if (signal?.aborted === true) return Promise.reject(signal.reason);
93
+ return new Promise((resolve, reject) => {
94
+ const internal = new AbortController();
95
+ const onAbort = () => {
96
+ internal.abort();
97
+ reject(signal?.reason);
98
+ };
99
+ const task = post(() => {
100
+ signal?.removeEventListener("abort", onAbort);
101
+ resolve();
102
+ }, {
103
+ priority: POST_TASK_PRIORITY[priority],
104
+ signal: internal.signal
105
+ });
106
+ if (task instanceof Promise) task.catch(() => {});
107
+ signal?.addEventListener("abort", onAbort, { once: true });
108
+ });
109
+ }
110
+ #macrotask(signal) {
111
+ return this.#timer(0, signal);
112
+ }
113
+ #timer(ms, signal) {
114
+ if (signal?.aborted === true) return Promise.reject(signal.reason);
115
+ return new Promise((resolve, reject) => {
116
+ const onAbort = () => {
117
+ clearTimeout(handle);
118
+ reject(signal?.reason);
119
+ };
120
+ const handle = setTimeout(() => {
121
+ signal?.removeEventListener("abort", onAbort);
122
+ resolve();
123
+ }, ms);
124
+ signal?.addEventListener("abort", onAbort, { once: true });
125
+ });
126
+ }
127
+ };
128
+ //#endregion
129
+ //#region src/browser/FrameScheduler.ts
130
+ /**
131
+ * The frame-aligned {@link SchedulerInterface} — a browser cooperative-yield backend
132
+ * whose `yield` resumes just before the next paint via `requestAnimationFrame`.
133
+ *
134
+ * @remarks
135
+ * - **`yield` resumes before the next paint.** `yield()` waits on `requestAnimationFrame`,
136
+ * so the resumption is aligned to the browser's render loop — ideal for work that
137
+ * should batch per frame (animation, incremental DOM updates) and pause while the tab
138
+ * is hidden (the host throttles rAF). `delay(ms)` is a real `setTimeout`, unaligned to
139
+ * frames. `options.priority` is accepted for contract compliance but a no-op — a frame
140
+ * callback has no priority dimension.
141
+ * - **Abort fidelity is verbatim, with cleanup.** A pending `yield` / `delay` rejects with
142
+ * `signal.reason` exactly. The discipline mirrors the cross-environment default's
143
+ * `#sleep`: an already-aborted signal rejects immediately WITHOUT scheduling a frame;
144
+ * otherwise the frame is requested and a `{ once: true }` abort listener attached, and
145
+ * the two settle paths are mutually exclusive — the frame path removes the listener
146
+ * before resolving, and the abort path `cancelAnimationFrame`s the pending handle before
147
+ * rejecting. The promise settles exactly once, with no leaked frame request and no
148
+ * leaked listener.
149
+ * - **Event-free.** A pure functional primitive — no Emitter, no events.
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * import { createAbort } from '@src/core'
154
+ * import { FrameScheduler } from '@src/browser'
155
+ *
156
+ * const abort = createAbort()
157
+ * const scheduler = new FrameScheduler()
158
+ * while (!abort.signal.aborted) {
159
+ * renderOneFrameOfWork()
160
+ * await scheduler.yield({ signal: abort.signal }) // resume before the next paint
161
+ * }
162
+ * ```
163
+ */
164
+ var FrameScheduler = class {
165
+ /**
166
+ * Yield control to the host until just before the next paint via
167
+ * `requestAnimationFrame`, then resume; abort rejects with `signal.reason`.
168
+ */
169
+ yield(options) {
170
+ return this.#frame(options?.signal);
171
+ }
172
+ /**
173
+ * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
174
+ * `signal.reason`.
175
+ *
176
+ * @remarks
177
+ * `ms` should be a non-negative finite number. The primitive does no validation: it
178
+ * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
179
+ * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
180
+ * throwing.
181
+ */
182
+ delay(ms, options) {
183
+ return this.#sleep(ms, options?.signal);
184
+ }
185
+ #frame(signal) {
186
+ if (signal?.aborted === true) return Promise.reject(signal.reason);
187
+ return new Promise((resolve, reject) => {
188
+ const onAbort = () => {
189
+ cancelAnimationFrame(handle);
190
+ reject(signal?.reason);
191
+ };
192
+ const handle = requestAnimationFrame(() => {
193
+ signal?.removeEventListener("abort", onAbort);
194
+ resolve();
195
+ });
196
+ signal?.addEventListener("abort", onAbort, { once: true });
197
+ });
198
+ }
199
+ #sleep(ms, signal) {
200
+ if (signal?.aborted === true) return Promise.reject(signal.reason);
201
+ return new Promise((resolve, reject) => {
202
+ const onAbort = () => {
203
+ clearTimeout(handle);
204
+ reject(signal?.reason);
205
+ };
206
+ const handle = setTimeout(() => {
207
+ signal?.removeEventListener("abort", onAbort);
208
+ resolve();
209
+ }, ms);
210
+ signal?.addEventListener("abort", onAbort, { once: true });
211
+ });
212
+ }
213
+ };
214
+ //#endregion
215
+ //#region src/browser/IdleScheduler.ts
216
+ /**
217
+ * The idle-time {@link SchedulerInterface} — a browser cooperative-yield backend whose
218
+ * `yield` resumes when the host is idle via `requestIdleCallback`, falling back to a
219
+ * zero-delay macrotask where it is absent.
220
+ *
221
+ * @remarks
222
+ * - **`yield` resumes during idle time.** When `globalThis` exposes `requestIdleCallback`,
223
+ * `yield()` waits on it, so the resumption happens when the browser has spare time after
224
+ * rendering and input — ideal for low-priority background work that must not contend with
225
+ * the user. The capability is feature-detected through a guard (`isFunction`), never an
226
+ * `as` (AGENTS §14). Where the API is absent (Safari today), it **falls back** to a
227
+ * `setTimeout(0)` macrotask — still a real host-turn, just not idle-gated. `delay(ms)` is
228
+ * always a real `setTimeout`. `options.priority` is accepted for contract compliance but a
229
+ * no-op — idle scheduling has no priority dimension.
230
+ * - **Abort fidelity is verbatim, with cleanup.** A pending `yield` / `delay` rejects with
231
+ * `signal.reason` exactly. The discipline mirrors the cross-environment default's
232
+ * `#sleep`: an already-aborted signal rejects immediately WITHOUT scheduling; otherwise
233
+ * the idle callback (or fallback timer) is requested and a `{ once: true }` abort listener
234
+ * attached, and the two settle paths are mutually exclusive — the resume path removes the
235
+ * listener before resolving, and the abort path `cancelIdleCallback`s (or `clearTimeout`s)
236
+ * the pending handle before rejecting. The promise settles exactly once, with no leaked
237
+ * callback/timer and no leaked listener.
238
+ * - **Event-free.** A pure functional primitive — no Emitter, no events.
239
+ *
240
+ * @example
241
+ * ```ts
242
+ * import { createAbort } from '@src/core'
243
+ * import { IdleScheduler } from '@src/browser'
244
+ *
245
+ * const abort = createAbort()
246
+ * const scheduler = new IdleScheduler()
247
+ * while (!abort.signal.aborted) {
248
+ * doLowPriorityWork()
249
+ * await scheduler.yield({ signal: abort.signal }) // resume when the host is idle
250
+ * }
251
+ * ```
252
+ */
253
+ var IdleScheduler = class {
254
+ /**
255
+ * Yield control to the host until it is idle via `requestIdleCallback` (or a
256
+ * `setTimeout(0)` macrotask where the API is absent), then resume; abort rejects with
257
+ * `signal.reason`.
258
+ */
259
+ yield(options) {
260
+ const idle = this.#idleAPI();
261
+ if (idle === void 0) return this.#sleep(0, options?.signal);
262
+ return this.#idle(idle, options?.signal);
263
+ }
264
+ /**
265
+ * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
266
+ * `signal.reason`.
267
+ *
268
+ * @remarks
269
+ * `ms` should be a non-negative finite number. The primitive does no validation: it
270
+ * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
271
+ * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
272
+ * throwing.
273
+ */
274
+ delay(ms, options) {
275
+ return this.#sleep(ms, options?.signal);
276
+ }
277
+ #idleAPI() {
278
+ const request = Reflect.get(globalThis, "requestIdleCallback");
279
+ const cancel = Reflect.get(globalThis, "cancelIdleCallback");
280
+ if (!isFunction(request) || !isFunction(cancel)) return void 0;
281
+ return {
282
+ request: (callback) => Number(Reflect.apply(request, globalThis, [callback])),
283
+ cancel: (handle) => {
284
+ Reflect.apply(cancel, globalThis, [handle]);
285
+ }
286
+ };
287
+ }
288
+ #idle(idle, signal) {
289
+ if (signal?.aborted === true) return Promise.reject(signal.reason);
290
+ return new Promise((resolve, reject) => {
291
+ const onAbort = () => {
292
+ idle.cancel(handle);
293
+ reject(signal?.reason);
294
+ };
295
+ const handle = idle.request(() => {
296
+ signal?.removeEventListener("abort", onAbort);
297
+ resolve();
298
+ });
299
+ signal?.addEventListener("abort", onAbort, { once: true });
300
+ });
301
+ }
302
+ #sleep(ms, signal) {
303
+ if (signal?.aborted === true) return Promise.reject(signal.reason);
304
+ return new Promise((resolve, reject) => {
305
+ const onAbort = () => {
306
+ clearTimeout(handle);
307
+ reject(signal?.reason);
308
+ };
309
+ const handle = setTimeout(() => {
310
+ signal?.removeEventListener("abort", onAbort);
311
+ resolve();
312
+ }, ms);
313
+ signal?.addEventListener("abort", onAbort, { once: true });
314
+ });
315
+ }
316
+ };
317
+ //#endregion
318
+ //#region src/browser/factories.ts
319
+ /**
320
+ * Create the browser-native cooperative-yield {@link SchedulerInterface} — `yield()` uses
321
+ * the Prioritized Task Scheduling API (`scheduler.postTask`) at the requested priority
322
+ * when present, falling back to a `setTimeout(0)` macrotask; `delay(ms)` is a real
323
+ * `setTimeout`.
324
+ *
325
+ * @remarks
326
+ * The default browser scheduler: it honours `options.priority` (`user` /
327
+ * `normal` / `background`) when `scheduler.postTask` is available and degrades to a plain
328
+ * macrotask elsewhere. Both methods are abort-aware: pass `options.signal` and a pending
329
+ * yield/delay rejects with the signal's `reason` verbatim, with full task/timer/listener
330
+ * cleanup. Prefer {@link createFrameScheduler} for paint-aligned work or
331
+ * {@link createIdleScheduler} for idle-time background work.
332
+ *
333
+ * @returns A {@link SchedulerInterface} backed by `scheduler.postTask` (or a macrotask)
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * import { createBrowserScheduler } from '@src/browser'
338
+ *
339
+ * const scheduler = createBrowserScheduler()
340
+ * await scheduler.yield({ priority: 'background' })
341
+ * ```
342
+ */
343
+ function createBrowserScheduler() {
344
+ return new BrowserScheduler();
345
+ }
346
+ /**
347
+ * Create the frame-aligned cooperative-yield {@link SchedulerInterface} — `yield()` resumes
348
+ * just before the next paint via `requestAnimationFrame`; `delay(ms)` is a real
349
+ * `setTimeout`.
350
+ *
351
+ * @remarks
352
+ * Use it for work that should batch per render frame (animation, incremental DOM updates)
353
+ * and naturally pause while the tab is hidden. `yield` is abort-aware: pass `options.signal`
354
+ * and a pending yield rejects with the signal's `reason` verbatim, cancelling the pending
355
+ * frame request. `options.priority` is accepted but a no-op — a frame callback has no
356
+ * priority dimension.
357
+ *
358
+ * @returns A {@link SchedulerInterface} backed by `requestAnimationFrame`
359
+ *
360
+ * @example
361
+ * ```ts
362
+ * import { createFrameScheduler } from '@src/browser'
363
+ *
364
+ * const scheduler = createFrameScheduler()
365
+ * await scheduler.yield() // resumes before the next paint
366
+ * ```
367
+ */
368
+ function createFrameScheduler() {
369
+ return new FrameScheduler();
370
+ }
371
+ /**
372
+ * Create the idle-time cooperative-yield {@link SchedulerInterface} — `yield()` resumes when
373
+ * the host is idle via `requestIdleCallback` when present, falling back to a `setTimeout(0)`
374
+ * macrotask; `delay(ms)` is a real `setTimeout`.
375
+ *
376
+ * @remarks
377
+ * Use it for low-priority background work that must not contend with rendering or input.
378
+ * Where `requestIdleCallback` is absent (Safari today) it degrades to a plain macrotask.
379
+ * `yield` is abort-aware: pass `options.signal` and a pending yield rejects with the
380
+ * signal's `reason` verbatim, cancelling the pending idle callback. `options.priority` is
381
+ * accepted but a no-op — idle scheduling has no priority dimension.
382
+ *
383
+ * @returns A {@link SchedulerInterface} backed by `requestIdleCallback` (or a macrotask)
384
+ *
385
+ * @example
386
+ * ```ts
387
+ * import { createIdleScheduler } from '@src/browser'
388
+ *
389
+ * const scheduler = createIdleScheduler()
390
+ * await scheduler.yield() // resumes when the host is idle
391
+ * ```
392
+ */
393
+ function createIdleScheduler() {
394
+ return new IdleScheduler();
395
+ }
396
+ //#endregion
397
+ export { BrowserScheduler, FrameScheduler, IdleScheduler, POST_TASK_PRIORITY, createBrowserScheduler, createFrameScheduler, createIdleScheduler };
398
+
399
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["#postTask","#macrotask","#yieldVia","#timer","#frame","#sleep","#idleAPI","#sleep","#idle"],"sources":["../../../src/browser/constants.ts","../../../src/browser/BrowserScheduler.ts","../../../src/browser/FrameScheduler.ts","../../../src/browser/IdleScheduler.ts","../../../src/browser/factories.ts"],"sourcesContent":["import type { SchedulerPriority } from '@src/core'\n\n/**\n * The browser-native `postTask` priority for each portable {@link SchedulerPriority} — the\n * Prioritized Task Scheduling API's three levels.\n *\n * @remarks\n * A `user` hint maps to the most urgent `'user-blocking'`, `normal` to the default\n * `'user-visible'`, and `background` to `'background'`. {@link BrowserScheduler} reads this\n * map to translate the caller's portable priority into the value passed to\n * `scheduler.postTask`, so the urgency hint is honoured by the host.\n */\nexport const POST_TASK_PRIORITY: Readonly<Record<SchedulerPriority, string>> = {\n\tuser: 'user-blocking',\n\tnormal: 'user-visible',\n\tbackground: 'background',\n}\n","import type { SchedulerInterface, SchedulerOptions, SchedulerPriority } from '@src/core'\nimport { isFunction, isRecord } from '@orkestrel/contract'\nimport { POST_TASK_PRIORITY } from './constants.js'\n\n/**\n * The browser {@link SchedulerInterface} — the browser-native cooperative-yield backend\n * built on the Prioritized Task Scheduling API (`scheduler.postTask`), falling back to a\n * zero-delay macrotask where it is absent.\n *\n * @remarks\n * - **`yield` prefers `scheduler.postTask`, honouring priority.** When `globalThis`\n * exposes a `scheduler` with a `postTask` method, `yield()` posts a task at the mapped\n * priority (`user` → `'user-blocking'`, `normal` → `'user-visible'`, `background` →\n * `'background'`), so the host genuinely regains control and the urgency hint is\n * honoured. The capability is feature-detected through guards (`isRecord` / `isFunction`),\n * never an `as` (AGENTS §14). Where the API is absent (Firefox today, older engines),\n * it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn, just\n * without priority. `delay(ms)` is always a real `setTimeout`.\n * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with `signal.reason`\n * exactly — the value the caller passed, never wrapped or replaced. The discipline\n * mirrors the cross-environment default's `#sleep`: an already-aborted signal rejects\n * immediately WITHOUT scheduling; otherwise the host-turn is scheduled and a\n * `{ once: true }` abort listener attached, and the two settle paths are mutually\n * exclusive — the turn path removes the listener before resolving, and the abort path\n * cancels the scheduled turn before rejecting. The promise settles exactly once, with no\n * leaked task/timer and no leaked listener. The caller's `signal` is NOT handed to\n * `postTask` (whose own abort would reject with a platform `AbortError`, not the\n * caller's `reason`); instead an internal controller cancels the posted task while this\n * scheduler rejects with the verbatim `signal.reason`.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@src/core'\n * import { BrowserScheduler } from '@src/browser'\n *\n * const abort = createAbort()\n * const scheduler = new BrowserScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ priority: 'background', signal: abort.signal })\n * }\n * ```\n */\nexport class BrowserScheduler implements SchedulerInterface {\n\t/**\n\t * Yield control to the host via `scheduler.postTask` at the given priority (or a\n\t * `setTimeout(0)` macrotask where the API is absent), then resume; abort rejects with\n\t * `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\tconst post = this.#postTask()\n\t\tif (post === undefined) return this.#macrotask(options?.signal)\n\t\treturn this.#yieldVia(post, options?.priority ?? 'normal', options?.signal)\n\t}\n\n\t/**\n\t * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with\n\t * `signal.reason`.\n\t *\n\t * @remarks\n\t * `ms` should be a non-negative finite number. The primitive does no validation: it\n\t * passes `ms` straight to the host `setTimeout`, which clamps a negative value or\n\t * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than\n\t * throwing.\n\t */\n\tdelay(ms: number, options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#timer(ms, options?.signal)\n\t}\n\n\t// === Private\n\n\t// Feature-detect the Prioritized Task Scheduling API through guards (no `as`): the\n\t// global `scheduler` must be a record carrying a callable `postTask`. Returns the\n\t// narrowed `postTask` function, or `undefined` when the API is absent (the fallback).\n\t#postTask(): ((callback: () => void, options: Record<string, unknown>) => unknown) | undefined {\n\t\tconst candidate: unknown = Reflect.get(globalThis, 'scheduler')\n\t\tif (!isRecord(candidate)) return undefined\n\t\tconst post = candidate.postTask\n\t\tif (!isFunction(post)) return undefined\n\t\treturn (callback, options) => Reflect.apply(post, candidate, [callback, options])\n\t}\n\n\t// A `scheduler.postTask` host-turn at the mapped priority. The caller's signal is NOT\n\t// passed to `postTask` (its abort rejects with a platform `AbortError`, not the\n\t// caller's `reason`); instead an internal controller cancels the posted task on abort\n\t// while this rejects with the verbatim `signal.reason`. Settle-once, no leak: the task\n\t// path removes the abort listener before resolving; the abort path aborts the internal\n\t// controller (cancelling the task) before rejecting.\n\t#yieldVia(\n\t\tpost: (callback: () => void, options: Record<string, unknown>) => unknown,\n\t\tpriority: SchedulerPriority,\n\t\tsignal?: AbortSignal,\n\t): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst internal = new AbortController()\n\t\t\tconst onAbort = () => {\n\t\t\t\tinternal.abort()\n\t\t\t\treject(signal?.reason)\n\t\t\t}\n\t\t\tconst task = post(\n\t\t\t\t() => {\n\t\t\t\t\tsignal?.removeEventListener('abort', onAbort)\n\t\t\t\t\tresolve()\n\t\t\t\t},\n\t\t\t\t{ priority: POST_TASK_PRIORITY[priority], signal: internal.signal },\n\t\t\t)\n\t\t\t// `postTask` returns a promise that rejects when the internal controller aborts;\n\t\t\t// swallow that rejection (the abort path already rejected with the real reason).\n\t\t\tif (task instanceof Promise) task.catch(() => {})\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t// The `setTimeout(0)` macrotask fallback for `yield` when `postTask` is absent. Same\n\t// settle-once discipline as the core `#sleep`: an already-aborted signal rejects\n\t// without arming; otherwise the timer path removes the listener before resolving and\n\t// the abort path clears the timer before rejecting with `signal.reason`.\n\t#macrotask(signal?: AbortSignal): Promise<void> {\n\t\treturn this.#timer(0, signal)\n\t}\n\n\t// The abort-aware `setTimeout` sleep shared by `delay` and the `yield` macrotask\n\t// fallback. Settle-once, no leak (the core `#sleep` discipline): already-aborted →\n\t// reject without arming; the timer path removes the listener before resolving; the\n\t// abort path clears the timer before rejecting with the verbatim `signal.reason`.\n\t#timer(ms: number, signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst onAbort = () => {\n\t\t\t\tclearTimeout(handle)\n\t\t\t\treject(signal?.reason)\n\t\t\t}\n\t\t\tconst handle = setTimeout(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n}\n","import type { SchedulerInterface, SchedulerOptions } from '@src/core'\n\n/**\n * The frame-aligned {@link SchedulerInterface} — a browser cooperative-yield backend\n * whose `yield` resumes just before the next paint via `requestAnimationFrame`.\n *\n * @remarks\n * - **`yield` resumes before the next paint.** `yield()` waits on `requestAnimationFrame`,\n * so the resumption is aligned to the browser's render loop — ideal for work that\n * should batch per frame (animation, incremental DOM updates) and pause while the tab\n * is hidden (the host throttles rAF). `delay(ms)` is a real `setTimeout`, unaligned to\n * frames. `options.priority` is accepted for contract compliance but a no-op — a frame\n * callback has no priority dimension.\n * - **Abort fidelity is verbatim, with cleanup.** A pending `yield` / `delay` rejects with\n * `signal.reason` exactly. The discipline mirrors the cross-environment default's\n * `#sleep`: an already-aborted signal rejects immediately WITHOUT scheduling a frame;\n * otherwise the frame is requested and a `{ once: true }` abort listener attached, and\n * the two settle paths are mutually exclusive — the frame path removes the listener\n * before resolving, and the abort path `cancelAnimationFrame`s the pending handle before\n * rejecting. The promise settles exactly once, with no leaked frame request and no\n * leaked listener.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@src/core'\n * import { FrameScheduler } from '@src/browser'\n *\n * const abort = createAbort()\n * const scheduler = new FrameScheduler()\n * while (!abort.signal.aborted) {\n * \trenderOneFrameOfWork()\n * \tawait scheduler.yield({ signal: abort.signal }) // resume before the next paint\n * }\n * ```\n */\nexport class FrameScheduler implements SchedulerInterface {\n\t/**\n\t * Yield control to the host until just before the next paint via\n\t * `requestAnimationFrame`, then resume; abort rejects with `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#frame(options?.signal)\n\t}\n\n\t/**\n\t * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with\n\t * `signal.reason`.\n\t *\n\t * @remarks\n\t * `ms` should be a non-negative finite number. The primitive does no validation: it\n\t * passes `ms` straight to the host `setTimeout`, which clamps a negative value or\n\t * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than\n\t * throwing.\n\t */\n\tdelay(ms: number, options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#sleep(ms, options?.signal)\n\t}\n\n\t// === Private\n\n\t// The `requestAnimationFrame` host-turn for `yield`. Resolves in the next frame\n\t// callback (before paint); rejects with `signal.reason` if already aborted (no frame\n\t// requested) or aborted while pending. Settle-once, no leak: the frame path removes the\n\t// abort listener before resolving; the abort path cancels the frame before rejecting.\n\t#frame(signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst onAbort = () => {\n\t\t\t\tcancelAnimationFrame(handle)\n\t\t\t\treject(signal?.reason)\n\t\t\t}\n\t\t\tconst handle = requestAnimationFrame(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t})\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t// The abort-aware `setTimeout` sleep for `delay`. Same settle-once discipline as the\n\t// core `#sleep`: already-aborted → reject without arming; the timer path removes the\n\t// listener before resolving; the abort path clears the timer before rejecting with the\n\t// verbatim `signal.reason`.\n\t#sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst onAbort = () => {\n\t\t\t\tclearTimeout(handle)\n\t\t\t\treject(signal?.reason)\n\t\t\t}\n\t\t\tconst handle = setTimeout(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n}\n","import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { isFunction } from '@orkestrel/contract'\nimport type { IdleAPI } from './types.js'\n\n/**\n * The idle-time {@link SchedulerInterface} — a browser cooperative-yield backend whose\n * `yield` resumes when the host is idle via `requestIdleCallback`, falling back to a\n * zero-delay macrotask where it is absent.\n *\n * @remarks\n * - **`yield` resumes during idle time.** When `globalThis` exposes `requestIdleCallback`,\n * `yield()` waits on it, so the resumption happens when the browser has spare time after\n * rendering and input — ideal for low-priority background work that must not contend with\n * the user. The capability is feature-detected through a guard (`isFunction`), never an\n * `as` (AGENTS §14). Where the API is absent (Safari today), it **falls back** to a\n * `setTimeout(0)` macrotask — still a real host-turn, just not idle-gated. `delay(ms)` is\n * always a real `setTimeout`. `options.priority` is accepted for contract compliance but a\n * no-op — idle scheduling has no priority dimension.\n * - **Abort fidelity is verbatim, with cleanup.** A pending `yield` / `delay` rejects with\n * `signal.reason` exactly. The discipline mirrors the cross-environment default's\n * `#sleep`: an already-aborted signal rejects immediately WITHOUT scheduling; otherwise\n * the idle callback (or fallback timer) is requested and a `{ once: true }` abort listener\n * attached, and the two settle paths are mutually exclusive — the resume path removes the\n * listener before resolving, and the abort path `cancelIdleCallback`s (or `clearTimeout`s)\n * the pending handle before rejecting. The promise settles exactly once, with no leaked\n * callback/timer and no leaked listener.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@src/core'\n * import { IdleScheduler } from '@src/browser'\n *\n * const abort = createAbort()\n * const scheduler = new IdleScheduler()\n * while (!abort.signal.aborted) {\n * \tdoLowPriorityWork()\n * \tawait scheduler.yield({ signal: abort.signal }) // resume when the host is idle\n * }\n * ```\n */\nexport class IdleScheduler implements SchedulerInterface {\n\t/**\n\t * Yield control to the host until it is idle via `requestIdleCallback` (or a\n\t * `setTimeout(0)` macrotask where the API is absent), then resume; abort rejects with\n\t * `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\tconst idle = this.#idleAPI()\n\t\tif (idle === undefined) return this.#sleep(0, options?.signal)\n\t\treturn this.#idle(idle, options?.signal)\n\t}\n\n\t/**\n\t * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with\n\t * `signal.reason`.\n\t *\n\t * @remarks\n\t * `ms` should be a non-negative finite number. The primitive does no validation: it\n\t * passes `ms` straight to the host `setTimeout`, which clamps a negative value or\n\t * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than\n\t * throwing.\n\t */\n\tdelay(ms: number, options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#sleep(ms, options?.signal)\n\t}\n\n\t// === Private\n\n\t// Feature-detect `requestIdleCallback` / `cancelIdleCallback` off `globalThis` through\n\t// guards (no `as`): both must be callable. Returns the narrowed pair, or `undefined`\n\t// when the API is absent (the macrotask fallback).\n\t#idleAPI(): IdleAPI | undefined {\n\t\tconst request: unknown = Reflect.get(globalThis, 'requestIdleCallback')\n\t\tconst cancel: unknown = Reflect.get(globalThis, 'cancelIdleCallback')\n\t\tif (!isFunction(request) || !isFunction(cancel)) return undefined\n\t\treturn {\n\t\t\trequest: (callback) => Number(Reflect.apply(request, globalThis, [callback])),\n\t\t\tcancel: (handle) => {\n\t\t\t\tReflect.apply(cancel, globalThis, [handle])\n\t\t\t},\n\t\t}\n\t}\n\n\t// The `requestIdleCallback` host-turn for `yield`. Resolves in the idle callback;\n\t// rejects with `signal.reason` if already aborted (nothing scheduled) or aborted while\n\t// pending. Settle-once, no leak: the resume path removes the abort listener before\n\t// resolving; the abort path cancels the idle callback before rejecting.\n\t#idle(idle: IdleAPI, signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst onAbort = () => {\n\t\t\t\tidle.cancel(handle)\n\t\t\t\treject(signal?.reason)\n\t\t\t}\n\t\t\tconst handle = idle.request(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t})\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t// The abort-aware `setTimeout` sleep shared by `delay` and the `yield` macrotask\n\t// fallback. Same settle-once discipline as the core `#sleep`: already-aborted → reject\n\t// without arming; the timer path removes the listener before resolving; the abort path\n\t// clears the timer before rejecting with the verbatim `signal.reason`.\n\t#sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst onAbort = () => {\n\t\t\t\tclearTimeout(handle)\n\t\t\t\treject(signal?.reason)\n\t\t\t}\n\t\t\tconst handle = setTimeout(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n}\n","import type { SchedulerInterface } from '@src/core'\nimport { BrowserScheduler } from './BrowserScheduler.js'\nimport { FrameScheduler } from './FrameScheduler.js'\nimport { IdleScheduler } from './IdleScheduler.js'\n\n/**\n * Create the browser-native cooperative-yield {@link SchedulerInterface} — `yield()` uses\n * the Prioritized Task Scheduling API (`scheduler.postTask`) at the requested priority\n * when present, falling back to a `setTimeout(0)` macrotask; `delay(ms)` is a real\n * `setTimeout`.\n *\n * @remarks\n * The default browser scheduler: it honours `options.priority` (`user` /\n * `normal` / `background`) when `scheduler.postTask` is available and degrades to a plain\n * macrotask elsewhere. Both methods are abort-aware: pass `options.signal` and a pending\n * yield/delay rejects with the signal's `reason` verbatim, with full task/timer/listener\n * cleanup. Prefer {@link createFrameScheduler} for paint-aligned work or\n * {@link createIdleScheduler} for idle-time background work.\n *\n * @returns A {@link SchedulerInterface} backed by `scheduler.postTask` (or a macrotask)\n *\n * @example\n * ```ts\n * import { createBrowserScheduler } from '@src/browser'\n *\n * const scheduler = createBrowserScheduler()\n * await scheduler.yield({ priority: 'background' })\n * ```\n */\nexport function createBrowserScheduler(): SchedulerInterface {\n\treturn new BrowserScheduler()\n}\n\n/**\n * Create the frame-aligned cooperative-yield {@link SchedulerInterface} — `yield()` resumes\n * just before the next paint via `requestAnimationFrame`; `delay(ms)` is a real\n * `setTimeout`.\n *\n * @remarks\n * Use it for work that should batch per render frame (animation, incremental DOM updates)\n * and naturally pause while the tab is hidden. `yield` is abort-aware: pass `options.signal`\n * and a pending yield rejects with the signal's `reason` verbatim, cancelling the pending\n * frame request. `options.priority` is accepted but a no-op — a frame callback has no\n * priority dimension.\n *\n * @returns A {@link SchedulerInterface} backed by `requestAnimationFrame`\n *\n * @example\n * ```ts\n * import { createFrameScheduler } from '@src/browser'\n *\n * const scheduler = createFrameScheduler()\n * await scheduler.yield() // resumes before the next paint\n * ```\n */\nexport function createFrameScheduler(): SchedulerInterface {\n\treturn new FrameScheduler()\n}\n\n/**\n * Create the idle-time cooperative-yield {@link SchedulerInterface} — `yield()` resumes when\n * the host is idle via `requestIdleCallback` when present, falling back to a `setTimeout(0)`\n * macrotask; `delay(ms)` is a real `setTimeout`.\n *\n * @remarks\n * Use it for low-priority background work that must not contend with rendering or input.\n * Where `requestIdleCallback` is absent (Safari today) it degrades to a plain macrotask.\n * `yield` is abort-aware: pass `options.signal` and a pending yield rejects with the\n * signal's `reason` verbatim, cancelling the pending idle callback. `options.priority` is\n * accepted but a no-op — idle scheduling has no priority dimension.\n *\n * @returns A {@link SchedulerInterface} backed by `requestIdleCallback` (or a macrotask)\n *\n * @example\n * ```ts\n * import { createIdleScheduler } from '@src/browser'\n *\n * const scheduler = createIdleScheduler()\n * await scheduler.yield() // resumes when the host is idle\n * ```\n */\nexport function createIdleScheduler(): SchedulerInterface {\n\treturn new IdleScheduler()\n}\n"],"mappings":"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"}