@orkestrel/workflow 0.0.15 → 0.0.17
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 +3 -3
- package/dist/src/browser/index.d.ts +41 -44
- package/dist/src/browser/index.js +46 -67
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +1160 -674
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +1464 -1030
- package/dist/src/core/index.d.ts +1464 -1030
- package/dist/src/core/index.js +1145 -666
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +12 -19
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +11 -12
- package/dist/src/server/index.d.ts +11 -12
- package/dist/src/server/index.js +13 -20
- package/dist/src/server/index.js.map +1 -1
- package/package.json +16 -16
package/README.md
CHANGED
|
@@ -33,13 +33,13 @@ attempt. Runtime pause gates are intentionally not persisted.
|
|
|
33
33
|
|
|
34
34
|
Provider sessions, external processes, MCP projection, journals, leases, and
|
|
35
35
|
distributed fencing remain integration concerns rather than core workflow
|
|
36
|
-
behavior. See [guides/
|
|
37
|
-
shipped contract. The proposed integration architecture
|
|
36
|
+
behavior. See [guides/workflow.md](./guides/workflow.md) for the complete
|
|
37
|
+
shipped contract. The proposed integration architecture lives with the
|
|
38
38
|
package that implements it, as `plan/PROPOSAL.md` in `@orkestrel/supervisor`.
|
|
39
39
|
|
|
40
40
|
## Package
|
|
41
41
|
|
|
42
|
-
Published as
|
|
42
|
+
Published as environment-scoped entry points: `.` provides the shared
|
|
43
43
|
environment-agnostic core and default scheduler, `./browser` adds browser-native
|
|
44
44
|
schedulers, and `./server` adds the Node-native scheduler. Core ships dual
|
|
45
45
|
ESM+CJS builds; `./browser` is ESM-only.
|
|
@@ -3,7 +3,7 @@ import { SchedulerOptions } from '@orkestrel/workflow';
|
|
|
3
3
|
import { SchedulerPriority } from '@orkestrel/workflow';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Implements the browser {@link SchedulerInterface} — the browser-native cooperative-yield backend
|
|
7
7
|
* built on the Prioritized Task Scheduling API (`scheduler.postTask`), falling back to a
|
|
8
8
|
* zero-delay macrotask where it is absent.
|
|
9
9
|
*
|
|
@@ -13,9 +13,9 @@ import { SchedulerPriority } from '@orkestrel/workflow';
|
|
|
13
13
|
* priority (`user` → `'user-blocking'`, `normal` → `'user-visible'`, `background` →
|
|
14
14
|
* `'background'`), so the host genuinely regains control and the urgency hint is
|
|
15
15
|
* honoured. The capability is feature-detected through guards (`isRecord` / `isFunction`),
|
|
16
|
-
* never an `as
|
|
17
|
-
* it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn,
|
|
18
|
-
*
|
|
16
|
+
* never an `as`. Where the API is absent (Firefox today, older engines),
|
|
17
|
+
* it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn, without
|
|
18
|
+
* priority. `delay(ms)` is always a real `setTimeout`.
|
|
19
19
|
* - **Abort fidelity is verbatim.** The shared `scheduleHost` lifecycle links an owned
|
|
20
20
|
* settlement composite before scheduling, preserving the exact caller reason without
|
|
21
21
|
* invoking caller-owned signal methods. The caller signal is NOT handed to `postTask`;
|
|
@@ -39,26 +39,25 @@ import { SchedulerPriority } from '@orkestrel/workflow';
|
|
|
39
39
|
export declare class BrowserScheduler implements SchedulerInterface {
|
|
40
40
|
#private;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
* `setTimeout(0)` macrotask where the API is absent), then
|
|
42
|
+
* Yields control to the host through `scheduler.postTask` at the given priority (or a
|
|
43
|
+
* `setTimeout(0)` macrotask where the API is absent), then resumes; abort rejects with
|
|
44
44
|
* `signal.reason`.
|
|
45
45
|
*/
|
|
46
46
|
yield(options?: SchedulerOptions): Promise<void>;
|
|
47
47
|
/**
|
|
48
|
-
*
|
|
48
|
+
* Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
|
|
49
49
|
* `signal.reason`.
|
|
50
50
|
*
|
|
51
51
|
* @remarks
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* throwing.
|
|
52
|
+
* Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
|
|
53
|
+
* straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
|
|
54
|
+
* out-of-domain `ms` resolves on the next host turn rather than throwing.
|
|
56
55
|
*/
|
|
57
56
|
delay(ms: number, options?: SchedulerOptions): Promise<void>;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
/**
|
|
61
|
-
*
|
|
60
|
+
* Creates the browser-native cooperative-yield {@link SchedulerInterface} — `yield()` uses
|
|
62
61
|
* the Prioritized Task Scheduling API (`scheduler.postTask`) at the requested priority
|
|
63
62
|
* when present, falling back to a `setTimeout(0)` macrotask; `delay(ms)` is a real
|
|
64
63
|
* `setTimeout`.
|
|
@@ -85,13 +84,13 @@ export declare class BrowserScheduler implements SchedulerInterface {
|
|
|
85
84
|
export declare function createBrowserScheduler(): SchedulerInterface;
|
|
86
85
|
|
|
87
86
|
/**
|
|
88
|
-
*
|
|
89
|
-
* just before the next paint
|
|
87
|
+
* Creates the frame-aligned cooperative-yield {@link SchedulerInterface} — `yield()` resumes
|
|
88
|
+
* just before the next paint through `requestAnimationFrame`; `delay(ms)` is a real
|
|
90
89
|
* `setTimeout`.
|
|
91
90
|
*
|
|
92
91
|
* @remarks
|
|
93
|
-
* Use it for work that
|
|
94
|
-
*
|
|
92
|
+
* Use it for work that batches per render frame (animation, incremental DOM updates) and
|
|
93
|
+
* naturally pauses while the tab is hidden. `yield` is abort-aware: pass `options.signal`
|
|
95
94
|
* and a pending yield rejects with the signal's `reason` verbatim, cancelling the pending
|
|
96
95
|
* frame request. `options.priority` is accepted but a no-op — a frame callback has no
|
|
97
96
|
* priority dimension.
|
|
@@ -109,8 +108,8 @@ export declare function createBrowserScheduler(): SchedulerInterface;
|
|
|
109
108
|
export declare function createFrameScheduler(): SchedulerInterface;
|
|
110
109
|
|
|
111
110
|
/**
|
|
112
|
-
*
|
|
113
|
-
* the host is idle
|
|
111
|
+
* Creates the idle-time cooperative-yield {@link SchedulerInterface} — `yield()` resumes when
|
|
112
|
+
* the host is idle through `requestIdleCallback` when present, falling back to a `setTimeout(0)`
|
|
114
113
|
* macrotask; `delay(ms)` is a real `setTimeout`.
|
|
115
114
|
*
|
|
116
115
|
* @remarks
|
|
@@ -133,14 +132,14 @@ export declare function createFrameScheduler(): SchedulerInterface;
|
|
|
133
132
|
export declare function createIdleScheduler(): SchedulerInterface;
|
|
134
133
|
|
|
135
134
|
/**
|
|
136
|
-
*
|
|
137
|
-
* whose `yield` resumes just before the next paint
|
|
135
|
+
* Implements the frame-aligned {@link SchedulerInterface} — a browser cooperative-yield backend
|
|
136
|
+
* whose `yield` resumes just before the next paint through `requestAnimationFrame`.
|
|
138
137
|
*
|
|
139
138
|
* @remarks
|
|
140
139
|
* - **`yield` resumes before the next paint.** `yield()` waits on `requestAnimationFrame`,
|
|
141
140
|
* so the resumption is aligned to the browser's render loop — ideal for work that
|
|
142
|
-
*
|
|
143
|
-
*
|
|
141
|
+
* batches per frame (animation, incremental DOM updates) and pauses while the tab is
|
|
142
|
+
* hidden (the host throttles rAF). `delay(ms)` is a real `setTimeout`, unaligned to
|
|
144
143
|
* frames. `options.priority` is accepted for contract compliance but a no-op — a frame
|
|
145
144
|
* callback has no priority dimension.
|
|
146
145
|
* - **Abort fidelity is verbatim, with cleanup.** The shared `scheduleHost` lifecycle links
|
|
@@ -164,41 +163,40 @@ export declare function createIdleScheduler(): SchedulerInterface;
|
|
|
164
163
|
export declare class FrameScheduler implements SchedulerInterface {
|
|
165
164
|
#private;
|
|
166
165
|
/**
|
|
167
|
-
*
|
|
168
|
-
* `requestAnimationFrame`, then
|
|
166
|
+
* Yields control to the host until just before the next paint through
|
|
167
|
+
* `requestAnimationFrame`, then resumes; abort rejects with `signal.reason`.
|
|
169
168
|
*/
|
|
170
169
|
yield(options?: SchedulerOptions): Promise<void>;
|
|
171
170
|
/**
|
|
172
|
-
*
|
|
171
|
+
* Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
|
|
173
172
|
* `signal.reason`.
|
|
174
173
|
*
|
|
175
174
|
* @remarks
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* throwing.
|
|
175
|
+
* Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
|
|
176
|
+
* straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
|
|
177
|
+
* out-of-domain `ms` resolves on the next host turn rather than throwing.
|
|
180
178
|
*/
|
|
181
179
|
delay(ms: number, options?: SchedulerOptions): Promise<void>;
|
|
182
180
|
}
|
|
183
181
|
|
|
184
182
|
/**
|
|
185
|
-
*
|
|
183
|
+
* Declares the narrowed `requestIdleCallback` / `cancelIdleCallback` pair feature-detected off
|
|
186
184
|
* `globalThis`.
|
|
187
185
|
*
|
|
188
186
|
* @remarks
|
|
189
187
|
* A `request` taking a callback and returning a numeric handle, and a `cancel` taking that
|
|
190
188
|
* handle. {@link IdleScheduler} feature-detects the pair through a guard (`isFunction`,
|
|
191
|
-
* never an `as`
|
|
189
|
+
* never an `as`) and resolves to `undefined` when the API is absent (Safari
|
|
192
190
|
* today), so `yield` falls back to a macrotask.
|
|
193
191
|
*/
|
|
194
|
-
export declare interface
|
|
192
|
+
export declare interface IdleInterface {
|
|
195
193
|
readonly request: (callback: () => void) => number;
|
|
196
194
|
readonly cancel: (handle: number) => void;
|
|
197
195
|
}
|
|
198
196
|
|
|
199
197
|
/**
|
|
200
|
-
*
|
|
201
|
-
* `yield` resumes when the host is idle
|
|
198
|
+
* Implements the idle-time {@link SchedulerInterface} — a browser cooperative-yield backend whose
|
|
199
|
+
* `yield` resumes when the host is idle through `requestIdleCallback`, falling back to a
|
|
202
200
|
* zero-delay macrotask where it is absent.
|
|
203
201
|
*
|
|
204
202
|
* @remarks
|
|
@@ -206,8 +204,8 @@ export declare interface IdleAPI {
|
|
|
206
204
|
* `yield()` waits on it, so the resumption happens when the browser has spare time after
|
|
207
205
|
* rendering and input — ideal for low-priority background work that must not contend with
|
|
208
206
|
* the user. The capability is feature-detected through a guard (`isFunction`), never an
|
|
209
|
-
* `as
|
|
210
|
-
* `setTimeout(0)` macrotask — still a real host-turn,
|
|
207
|
+
* `as`. Where the API is absent (Safari today), it **falls back** to a
|
|
208
|
+
* `setTimeout(0)` macrotask — still a real host-turn, not idle-gated. `delay(ms)` is
|
|
211
209
|
* always a real `setTimeout`. `options.priority` is accepted for contract compliance but a
|
|
212
210
|
* no-op — idle scheduling has no priority dimension.
|
|
213
211
|
* - **Abort fidelity is verbatim, with cleanup.** The shared `scheduleHost` lifecycle links
|
|
@@ -231,26 +229,25 @@ export declare interface IdleAPI {
|
|
|
231
229
|
export declare class IdleScheduler implements SchedulerInterface {
|
|
232
230
|
#private;
|
|
233
231
|
/**
|
|
234
|
-
*
|
|
235
|
-
* `setTimeout(0)` macrotask where the API is absent), then
|
|
232
|
+
* Yields control to the host until it is idle through `requestIdleCallback` (or a
|
|
233
|
+
* `setTimeout(0)` macrotask where the API is absent), then resumes; abort rejects with
|
|
236
234
|
* `signal.reason`.
|
|
237
235
|
*/
|
|
238
236
|
yield(options?: SchedulerOptions): Promise<void>;
|
|
239
237
|
/**
|
|
240
|
-
*
|
|
238
|
+
* Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
|
|
241
239
|
* `signal.reason`.
|
|
242
240
|
*
|
|
243
241
|
* @remarks
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
* throwing.
|
|
242
|
+
* Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
|
|
243
|
+
* straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
|
|
244
|
+
* out-of-domain `ms` resolves on the next host turn rather than throwing.
|
|
248
245
|
*/
|
|
249
246
|
delay(ms: number, options?: SchedulerOptions): Promise<void>;
|
|
250
247
|
}
|
|
251
248
|
|
|
252
249
|
/**
|
|
253
|
-
*
|
|
250
|
+
* Maps each portable {@link SchedulerPriority} to the browser-native `postTask` priority — the
|
|
254
251
|
* Prioritized Task Scheduling API's three levels.
|
|
255
252
|
*
|
|
256
253
|
* @remarks
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { scheduleHost } from "../core/index.js";
|
|
1
|
+
import { delayHost, scheduleHost } from "../core/index.js";
|
|
2
2
|
import { isFunction, isPromise, isRecord } from "@orkestrel/contract";
|
|
3
3
|
//#region src/browser/constants.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Maps each portable {@link SchedulerPriority} to the browser-native `postTask` priority — the
|
|
6
6
|
* Prioritized Task Scheduling API's three levels.
|
|
7
7
|
*
|
|
8
8
|
* @remarks
|
|
@@ -19,7 +19,7 @@ var POST_TASK_PRIORITY = Object.freeze({
|
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/browser/BrowserScheduler.ts
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Implements the browser {@link SchedulerInterface} — the browser-native cooperative-yield backend
|
|
23
23
|
* built on the Prioritized Task Scheduling API (`scheduler.postTask`), falling back to a
|
|
24
24
|
* zero-delay macrotask where it is absent.
|
|
25
25
|
*
|
|
@@ -29,9 +29,9 @@ var POST_TASK_PRIORITY = Object.freeze({
|
|
|
29
29
|
* priority (`user` → `'user-blocking'`, `normal` → `'user-visible'`, `background` →
|
|
30
30
|
* `'background'`), so the host genuinely regains control and the urgency hint is
|
|
31
31
|
* honoured. The capability is feature-detected through guards (`isRecord` / `isFunction`),
|
|
32
|
-
* never an `as
|
|
33
|
-
* it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn,
|
|
34
|
-
*
|
|
32
|
+
* never an `as`. Where the API is absent (Firefox today, older engines),
|
|
33
|
+
* it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn, without
|
|
34
|
+
* priority. `delay(ms)` is always a real `setTimeout`.
|
|
35
35
|
* - **Abort fidelity is verbatim.** The shared `scheduleHost` lifecycle links an owned
|
|
36
36
|
* settlement composite before scheduling, preserving the exact caller reason without
|
|
37
37
|
* invoking caller-owned signal methods. The caller signal is NOT handed to `postTask`;
|
|
@@ -54,27 +54,26 @@ var POST_TASK_PRIORITY = Object.freeze({
|
|
|
54
54
|
*/
|
|
55
55
|
var BrowserScheduler = class {
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
58
|
-
* `setTimeout(0)` macrotask where the API is absent), then
|
|
57
|
+
* Yields control to the host through `scheduler.postTask` at the given priority (or a
|
|
58
|
+
* `setTimeout(0)` macrotask where the API is absent), then resumes; abort rejects with
|
|
59
59
|
* `signal.reason`.
|
|
60
60
|
*/
|
|
61
61
|
yield(options) {
|
|
62
62
|
const post = this.#postTask();
|
|
63
|
-
if (post === void 0) return
|
|
63
|
+
if (post === void 0) return delayHost(0, options?.signal);
|
|
64
64
|
return this.#yieldVia(post, options?.priority ?? "normal", options?.signal);
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
67
|
+
* Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
|
|
68
68
|
* `signal.reason`.
|
|
69
69
|
*
|
|
70
70
|
* @remarks
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* throwing.
|
|
71
|
+
* Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
|
|
72
|
+
* straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
|
|
73
|
+
* out-of-domain `ms` resolves on the next host turn rather than throwing.
|
|
75
74
|
*/
|
|
76
75
|
delay(ms, options) {
|
|
77
|
-
return
|
|
76
|
+
return delayHost(ms, options?.signal);
|
|
78
77
|
}
|
|
79
78
|
#postTask() {
|
|
80
79
|
const candidate = Reflect.get(globalThis, "scheduler");
|
|
@@ -94,24 +93,18 @@ var BrowserScheduler = class {
|
|
|
94
93
|
return () => internal.abort();
|
|
95
94
|
}, signal);
|
|
96
95
|
}
|
|
97
|
-
#timer(ms, signal) {
|
|
98
|
-
return scheduleHost((complete) => {
|
|
99
|
-
const handle = setTimeout(complete, ms);
|
|
100
|
-
return () => clearTimeout(handle);
|
|
101
|
-
}, signal);
|
|
102
|
-
}
|
|
103
96
|
};
|
|
104
97
|
//#endregion
|
|
105
98
|
//#region src/browser/FrameScheduler.ts
|
|
106
99
|
/**
|
|
107
|
-
*
|
|
108
|
-
* whose `yield` resumes just before the next paint
|
|
100
|
+
* Implements the frame-aligned {@link SchedulerInterface} — a browser cooperative-yield backend
|
|
101
|
+
* whose `yield` resumes just before the next paint through `requestAnimationFrame`.
|
|
109
102
|
*
|
|
110
103
|
* @remarks
|
|
111
104
|
* - **`yield` resumes before the next paint.** `yield()` waits on `requestAnimationFrame`,
|
|
112
105
|
* so the resumption is aligned to the browser's render loop — ideal for work that
|
|
113
|
-
*
|
|
114
|
-
*
|
|
106
|
+
* batches per frame (animation, incremental DOM updates) and pauses while the tab is
|
|
107
|
+
* hidden (the host throttles rAF). `delay(ms)` is a real `setTimeout`, unaligned to
|
|
115
108
|
* frames. `options.priority` is accepted for contract compliance but a no-op — a frame
|
|
116
109
|
* callback has no priority dimension.
|
|
117
110
|
* - **Abort fidelity is verbatim, with cleanup.** The shared `scheduleHost` lifecycle links
|
|
@@ -134,24 +127,23 @@ var BrowserScheduler = class {
|
|
|
134
127
|
*/
|
|
135
128
|
var FrameScheduler = class {
|
|
136
129
|
/**
|
|
137
|
-
*
|
|
138
|
-
* `requestAnimationFrame`, then
|
|
130
|
+
* Yields control to the host until just before the next paint through
|
|
131
|
+
* `requestAnimationFrame`, then resumes; abort rejects with `signal.reason`.
|
|
139
132
|
*/
|
|
140
133
|
yield(options) {
|
|
141
134
|
return this.#frame(options?.signal);
|
|
142
135
|
}
|
|
143
136
|
/**
|
|
144
|
-
*
|
|
137
|
+
* Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
|
|
145
138
|
* `signal.reason`.
|
|
146
139
|
*
|
|
147
140
|
* @remarks
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
* throwing.
|
|
141
|
+
* Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
|
|
142
|
+
* straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
|
|
143
|
+
* out-of-domain `ms` resolves on the next host turn rather than throwing.
|
|
152
144
|
*/
|
|
153
145
|
delay(ms, options) {
|
|
154
|
-
return
|
|
146
|
+
return delayHost(ms, options?.signal);
|
|
155
147
|
}
|
|
156
148
|
#frame(signal) {
|
|
157
149
|
return scheduleHost((complete) => {
|
|
@@ -159,18 +151,12 @@ var FrameScheduler = class {
|
|
|
159
151
|
return () => cancelAnimationFrame(handle);
|
|
160
152
|
}, signal);
|
|
161
153
|
}
|
|
162
|
-
#sleep(ms, signal) {
|
|
163
|
-
return scheduleHost((complete) => {
|
|
164
|
-
const handle = setTimeout(complete, ms);
|
|
165
|
-
return () => clearTimeout(handle);
|
|
166
|
-
}, signal);
|
|
167
|
-
}
|
|
168
154
|
};
|
|
169
155
|
//#endregion
|
|
170
156
|
//#region src/browser/IdleScheduler.ts
|
|
171
157
|
/**
|
|
172
|
-
*
|
|
173
|
-
* `yield` resumes when the host is idle
|
|
158
|
+
* Implements the idle-time {@link SchedulerInterface} — a browser cooperative-yield backend whose
|
|
159
|
+
* `yield` resumes when the host is idle through `requestIdleCallback`, falling back to a
|
|
174
160
|
* zero-delay macrotask where it is absent.
|
|
175
161
|
*
|
|
176
162
|
* @remarks
|
|
@@ -178,8 +164,8 @@ var FrameScheduler = class {
|
|
|
178
164
|
* `yield()` waits on it, so the resumption happens when the browser has spare time after
|
|
179
165
|
* rendering and input — ideal for low-priority background work that must not contend with
|
|
180
166
|
* the user. The capability is feature-detected through a guard (`isFunction`), never an
|
|
181
|
-
* `as
|
|
182
|
-
* `setTimeout(0)` macrotask — still a real host-turn,
|
|
167
|
+
* `as`. Where the API is absent (Safari today), it **falls back** to a
|
|
168
|
+
* `setTimeout(0)` macrotask — still a real host-turn, not idle-gated. `delay(ms)` is
|
|
183
169
|
* always a real `setTimeout`. `options.priority` is accepted for contract compliance but a
|
|
184
170
|
* no-op — idle scheduling has no priority dimension.
|
|
185
171
|
* - **Abort fidelity is verbatim, with cleanup.** The shared `scheduleHost` lifecycle links
|
|
@@ -202,29 +188,28 @@ var FrameScheduler = class {
|
|
|
202
188
|
*/
|
|
203
189
|
var IdleScheduler = class {
|
|
204
190
|
/**
|
|
205
|
-
*
|
|
206
|
-
* `setTimeout(0)` macrotask where the API is absent), then
|
|
191
|
+
* Yields control to the host until it is idle through `requestIdleCallback` (or a
|
|
192
|
+
* `setTimeout(0)` macrotask where the API is absent), then resumes; abort rejects with
|
|
207
193
|
* `signal.reason`.
|
|
208
194
|
*/
|
|
209
195
|
yield(options) {
|
|
210
|
-
const idle = this.#
|
|
211
|
-
if (idle === void 0) return
|
|
196
|
+
const idle = this.#idleCallback();
|
|
197
|
+
if (idle === void 0) return delayHost(0, options?.signal);
|
|
212
198
|
return this.#idle(idle, options?.signal);
|
|
213
199
|
}
|
|
214
200
|
/**
|
|
215
|
-
*
|
|
201
|
+
* Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
|
|
216
202
|
* `signal.reason`.
|
|
217
203
|
*
|
|
218
204
|
* @remarks
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* throwing.
|
|
205
|
+
* Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
|
|
206
|
+
* straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
|
|
207
|
+
* out-of-domain `ms` resolves on the next host turn rather than throwing.
|
|
223
208
|
*/
|
|
224
209
|
delay(ms, options) {
|
|
225
|
-
return
|
|
210
|
+
return delayHost(ms, options?.signal);
|
|
226
211
|
}
|
|
227
|
-
#
|
|
212
|
+
#idleCallback() {
|
|
228
213
|
const request = Reflect.get(globalThis, "requestIdleCallback");
|
|
229
214
|
const cancel = Reflect.get(globalThis, "cancelIdleCallback");
|
|
230
215
|
if (!isFunction(request) || !isFunction(cancel)) return void 0;
|
|
@@ -239,12 +224,6 @@ var IdleScheduler = class {
|
|
|
239
224
|
return () => idle.cancel(handle);
|
|
240
225
|
}, signal);
|
|
241
226
|
}
|
|
242
|
-
#sleep(ms, signal) {
|
|
243
|
-
return scheduleHost((complete) => {
|
|
244
|
-
const handle = setTimeout(complete, ms);
|
|
245
|
-
return () => clearTimeout(handle);
|
|
246
|
-
}, signal);
|
|
247
|
-
}
|
|
248
227
|
#request(request, callback) {
|
|
249
228
|
return Number(Reflect.apply(request, globalThis, [callback]));
|
|
250
229
|
}
|
|
@@ -255,7 +234,7 @@ var IdleScheduler = class {
|
|
|
255
234
|
//#endregion
|
|
256
235
|
//#region src/browser/factories.ts
|
|
257
236
|
/**
|
|
258
|
-
*
|
|
237
|
+
* Creates the browser-native cooperative-yield {@link SchedulerInterface} — `yield()` uses
|
|
259
238
|
* the Prioritized Task Scheduling API (`scheduler.postTask`) at the requested priority
|
|
260
239
|
* when present, falling back to a `setTimeout(0)` macrotask; `delay(ms)` is a real
|
|
261
240
|
* `setTimeout`.
|
|
@@ -283,13 +262,13 @@ function createBrowserScheduler() {
|
|
|
283
262
|
return new BrowserScheduler();
|
|
284
263
|
}
|
|
285
264
|
/**
|
|
286
|
-
*
|
|
287
|
-
* just before the next paint
|
|
265
|
+
* Creates the frame-aligned cooperative-yield {@link SchedulerInterface} — `yield()` resumes
|
|
266
|
+
* just before the next paint through `requestAnimationFrame`; `delay(ms)` is a real
|
|
288
267
|
* `setTimeout`.
|
|
289
268
|
*
|
|
290
269
|
* @remarks
|
|
291
|
-
* Use it for work that
|
|
292
|
-
*
|
|
270
|
+
* Use it for work that batches per render frame (animation, incremental DOM updates) and
|
|
271
|
+
* naturally pauses while the tab is hidden. `yield` is abort-aware: pass `options.signal`
|
|
293
272
|
* and a pending yield rejects with the signal's `reason` verbatim, cancelling the pending
|
|
294
273
|
* frame request. `options.priority` is accepted but a no-op — a frame callback has no
|
|
295
274
|
* priority dimension.
|
|
@@ -308,8 +287,8 @@ function createFrameScheduler() {
|
|
|
308
287
|
return new FrameScheduler();
|
|
309
288
|
}
|
|
310
289
|
/**
|
|
311
|
-
*
|
|
312
|
-
* the host is idle
|
|
290
|
+
* Creates the idle-time cooperative-yield {@link SchedulerInterface} — `yield()` resumes when
|
|
291
|
+
* the host is idle through `requestIdleCallback` when present, falling back to a `setTimeout(0)`
|
|
313
292
|
* macrotask; `delay(ms)` is a real `setTimeout`.
|
|
314
293
|
*
|
|
315
294
|
* @remarks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"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>> = Object.freeze({\n\tuser: 'user-blocking',\n\tnormal: 'user-visible',\n\tbackground: 'background',\n})\n","import type { SchedulerInterface, SchedulerOptions, SchedulerPriority } from '@src/core'\nimport { scheduleHost } from '@src/core'\nimport { isFunction, isPromise, 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.** The shared `scheduleHost` lifecycle links an owned\n * settlement composite before scheduling, preserving the exact caller reason without\n * invoking caller-owned signal methods. The caller signal is NOT handed to `postTask`;\n * an internal controller cancels that native task. An unexpected native promise rejection\n * is routed back as the exact host failure instead of being discarded.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { BrowserScheduler } from '@orkestrel/workflow/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.#timer(0, 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` boundary with an internal cancellation controller; `scheduleHost`\n\t// owns caller linking and first-settlement arbitration, including native promise failure.\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\treturn scheduleHost((complete, failure) => {\n\t\t\tconst internal = new AbortController()\n\t\t\tconst task = post(complete, {\n\t\t\t\tpriority: POST_TASK_PRIORITY[priority],\n\t\t\t\tsignal: internal.signal,\n\t\t\t})\n\t\t\tif (isPromise(task)) void task.catch(failure)\n\t\t\treturn () => internal.abort()\n\t\t}, signal)\n\t}\n\n\t// The browser timer boundary shared by `delay` and fallback `yield`.\n\t#timer(ms: number, signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setTimeout(complete, ms)\n\t\t\treturn () => clearTimeout(handle)\n\t\t}, signal)\n\t}\n}\n","import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { scheduleHost } 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.** The shared `scheduleHost` lifecycle links\n * an owned settlement composite before requesting a frame, never invokes caller-owned\n * signal methods, and cancels the native handle when abort wins.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { FrameScheduler } from '@orkestrel/workflow/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 frame request boundary; `scheduleHost` owns cancellation lifecycle.\n\t#frame(signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = requestAnimationFrame(complete)\n\t\t\treturn () => cancelAnimationFrame(handle)\n\t\t}, signal)\n\t}\n\n\t// The browser timer boundary; `scheduleHost` owns cancellation lifecycle.\n\t#sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setTimeout(complete, ms)\n\t\t\treturn () => clearTimeout(handle)\n\t\t}, signal)\n\t}\n}\n","import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { scheduleHost } from '@src/core'\nimport type { AnyFunction } from '@orkestrel/contract'\nimport type { IdleAPI } from './types.js'\nimport { isFunction } from '@orkestrel/contract'\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.** The shared `scheduleHost` lifecycle links\n * an owned settlement composite before scheduling, never invokes caller-owned signal\n * methods, and cancels the idle callback or fallback timer when abort wins.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { IdleScheduler } from '@orkestrel/workflow/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: this.#request.bind(this, request),\n\t\t\tcancel: this.#cancel.bind(this, cancel),\n\t\t}\n\t}\n\n\t// The idle callback boundary; `scheduleHost` owns cancellation lifecycle.\n\t#idle(idle: IdleAPI, signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = idle.request(complete)\n\t\t\treturn () => idle.cancel(handle)\n\t\t}, signal)\n\t}\n\n\t// The browser timer boundary shared by `delay` and fallback `yield`.\n\t#sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setTimeout(complete, ms)\n\t\t\treturn () => clearTimeout(handle)\n\t\t}, signal)\n\t}\n\n\t#request(request: AnyFunction, callback: () => void): number {\n\t\treturn Number(Reflect.apply(request, globalThis, [callback]))\n\t}\n\n\t#cancel(cancel: AnyFunction, handle: number): void {\n\t\tReflect.apply(cancel, globalThis, [handle])\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 exact `reason`; the shared owned-signal lifecycle\n * cancels the native handle without invoking caller listener methods. Prefer\n * {@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 '@orkestrel/workflow/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 '@orkestrel/workflow/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 '@orkestrel/workflow/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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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"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 * Maps each portable {@link SchedulerPriority} to the browser-native `postTask` priority — 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>> = Object.freeze({\n\tuser: 'user-blocking',\n\tnormal: 'user-visible',\n\tbackground: 'background',\n})\n","import type { SchedulerInterface, SchedulerOptions, SchedulerPriority } from '@src/core'\nimport { delayHost, scheduleHost } from '@src/core'\nimport { isFunction, isPromise, isRecord } from '@orkestrel/contract'\nimport { POST_TASK_PRIORITY } from './constants.js'\n\n/**\n * Implements 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`. Where the API is absent (Firefox today, older engines),\n * it **falls back** to a `setTimeout(0)` macrotask — still a real host-turn, without\n * priority. `delay(ms)` is always a real `setTimeout`.\n * - **Abort fidelity is verbatim.** The shared `scheduleHost` lifecycle links an owned\n * settlement composite before scheduling, preserving the exact caller reason without\n * invoking caller-owned signal methods. The caller signal is NOT handed to `postTask`;\n * an internal controller cancels that native task. An unexpected native promise rejection\n * is routed back as the exact host failure instead of being discarded.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { BrowserScheduler } from '@orkestrel/workflow/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 * Yields control to the host through `scheduler.postTask` at the given priority (or a\n\t * `setTimeout(0)` macrotask where the API is absent), then resumes; 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 delayHost(0, options?.signal)\n\t\treturn this.#yieldVia(post, options?.priority ?? 'normal', options?.signal)\n\t}\n\n\t/**\n\t * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with\n\t * `signal.reason`.\n\t *\n\t * @remarks\n\t * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`\n\t * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an\n\t * out-of-domain `ms` resolves on the next host turn rather than throwing.\n\t */\n\tdelay(ms: number, options?: SchedulerOptions): Promise<void> {\n\t\treturn delayHost(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` boundary with an internal cancellation controller; `scheduleHost`\n\t// owns caller linking and first-settlement arbitration, including native promise failure.\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\treturn scheduleHost((complete, failure) => {\n\t\t\tconst internal = new AbortController()\n\t\t\tconst task = post(complete, {\n\t\t\t\tpriority: POST_TASK_PRIORITY[priority],\n\t\t\t\tsignal: internal.signal,\n\t\t\t})\n\t\t\tif (isPromise(task)) void task.catch(failure)\n\t\t\treturn () => internal.abort()\n\t\t}, signal)\n\t}\n}\n","import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { delayHost, scheduleHost } from '@src/core'\n\n/**\n * Implements the frame-aligned {@link SchedulerInterface} — a browser cooperative-yield backend\n * whose `yield` resumes just before the next paint through `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 * batches per frame (animation, incremental DOM updates) and pauses while the tab is\n * 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.** The shared `scheduleHost` lifecycle links\n * an owned settlement composite before requesting a frame, never invokes caller-owned\n * signal methods, and cancels the native handle when abort wins.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { FrameScheduler } from '@orkestrel/workflow/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 * Yields control to the host until just before the next paint through\n\t * `requestAnimationFrame`, then resumes; 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 * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with\n\t * `signal.reason`.\n\t *\n\t * @remarks\n\t * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`\n\t * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an\n\t * out-of-domain `ms` resolves on the next host turn rather than throwing.\n\t */\n\tdelay(ms: number, options?: SchedulerOptions): Promise<void> {\n\t\treturn delayHost(ms, options?.signal)\n\t}\n\n\t// === Private\n\n\t// The frame request boundary; `scheduleHost` owns cancellation lifecycle.\n\t#frame(signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = requestAnimationFrame(complete)\n\t\t\treturn () => cancelAnimationFrame(handle)\n\t\t}, signal)\n\t}\n}\n","import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport type { AnyFunction } from '@orkestrel/contract'\nimport type { IdleInterface } from './types.js'\nimport { delayHost, scheduleHost } from '@src/core'\nimport { isFunction } from '@orkestrel/contract'\n\n/**\n * Implements the idle-time {@link SchedulerInterface} — a browser cooperative-yield backend whose\n * `yield` resumes when the host is idle through `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`. Where the API is absent (Safari today), it **falls back** to a\n * `setTimeout(0)` macrotask — still a real host-turn, 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.** The shared `scheduleHost` lifecycle links\n * an owned settlement composite before scheduling, never invokes caller-owned signal\n * methods, and cancels the idle callback or fallback timer when abort wins.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { IdleScheduler } from '@orkestrel/workflow/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 * Yields control to the host until it is idle through `requestIdleCallback` (or a\n\t * `setTimeout(0)` macrotask where the API is absent), then resumes; abort rejects with\n\t * `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\tconst idle = this.#idleCallback()\n\t\tif (idle === undefined) return delayHost(0, options?.signal)\n\t\treturn this.#idle(idle, options?.signal)\n\t}\n\n\t/**\n\t * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with\n\t * `signal.reason`.\n\t *\n\t * @remarks\n\t * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`\n\t * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an\n\t * out-of-domain `ms` resolves on the next host turn rather than throwing.\n\t */\n\tdelay(ms: number, options?: SchedulerOptions): Promise<void> {\n\t\treturn delayHost(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#idleCallback(): IdleInterface | 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: this.#request.bind(this, request),\n\t\t\tcancel: this.#cancel.bind(this, cancel),\n\t\t}\n\t}\n\n\t// The idle yield boundary; `scheduleHost` owns cancellation lifecycle.\n\t#idle(idle: IdleInterface, signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = idle.request(complete)\n\t\t\treturn () => idle.cancel(handle)\n\t\t}, signal)\n\t}\n\n\t#request(request: AnyFunction, callback: () => void): number {\n\t\treturn Number(Reflect.apply(request, globalThis, [callback]))\n\t}\n\n\t#cancel(cancel: AnyFunction, handle: number): void {\n\t\tReflect.apply(cancel, globalThis, [handle])\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 * Creates 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 exact `reason`; the shared owned-signal lifecycle\n * cancels the native handle without invoking caller listener methods. Prefer\n * {@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 '@orkestrel/workflow/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 * Creates the frame-aligned cooperative-yield {@link SchedulerInterface} — `yield()` resumes\n * just before the next paint through `requestAnimationFrame`; `delay(ms)` is a real\n * `setTimeout`.\n *\n * @remarks\n * Use it for work that batches per render frame (animation, incremental DOM updates) and\n * naturally pauses 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 '@orkestrel/workflow/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 * Creates the idle-time cooperative-yield {@link SchedulerInterface} — `yield()` resumes when\n * the host is idle through `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 '@orkestrel/workflow/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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"}
|