@orkestrel/workflow 0.0.16 → 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.
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _src_core = require("../core/index.cjs");
3
3
  //#region src/server/NodeScheduler.ts
4
4
  /**
5
- * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
5
+ * Implements the Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
6
6
  *
7
7
  * @remarks
8
8
  * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the
@@ -36,24 +36,23 @@ let _src_core = require("../core/index.cjs");
36
36
  */
37
37
  var NodeScheduler = class {
38
38
  /**
39
- * Yield control back to the event loop via `setImmediate` so pending I/O and timers
40
- * can run, then resume; abort rejects with `signal.reason`.
39
+ * Yields control back to the event loop through `setImmediate` so pending I/O and timers
40
+ * can run, then resumes; abort rejects with `signal.reason`.
41
41
  */
42
42
  yield(options) {
43
43
  return this.#immediate(options?.signal);
44
44
  }
45
45
  /**
46
- * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
46
+ * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
47
47
  * `signal.reason`.
48
48
  *
49
49
  * @remarks
50
- * `ms` should be a non-negative finite number. The primitive does no validation: it
51
- * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
52
- * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
53
- * throwing.
50
+ * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
51
+ * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
52
+ * out-of-domain `ms` resolves on the next host turn rather than throwing.
54
53
  */
55
54
  delay(ms, options) {
56
- return this.#sleep(ms, options?.signal);
55
+ return (0, _src_core.delayHost)(ms, options?.signal);
57
56
  }
58
57
  #immediate(signal) {
59
58
  return (0, _src_core.scheduleHost)((complete) => {
@@ -61,24 +60,18 @@ var NodeScheduler = class {
61
60
  return () => clearImmediate(handle);
62
61
  }, signal);
63
62
  }
64
- #sleep(ms, signal) {
65
- return (0, _src_core.scheduleHost)((complete) => {
66
- const handle = setTimeout(complete, ms);
67
- return () => clearTimeout(handle);
68
- }, signal);
69
- }
70
63
  };
71
64
  //#endregion
72
65
  //#region src/server/factories.ts
73
66
  /**
74
- * Create the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
67
+ * Creates the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
75
68
  * `setImmediate` host-turn (the canonical Node "give the event loop a turn"), `delay(ms)`
76
69
  * a real `setTimeout`.
77
70
  *
78
71
  * @remarks
79
- * Use it on a server instead of the cross-environment `createScheduler` when a yield
80
- * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
81
- * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
72
+ * Use it on a server instead of the cross-environment `createScheduler` when a yield must
73
+ * hand the event loop a full turn (after pending I/O) through `setImmediate` rather than a
74
+ * zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
82
75
  * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
83
76
  * lifecycle clears the native handle without invoking caller listener methods.
84
77
  * `options.priority` is accepted for contract compliance but a
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/server/NodeScheduler.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { scheduleHost } from '@src/core'\n\n/**\n * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.\n *\n * @remarks\n * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the\n * canonical Node \"give the host a turn\" — it runs AFTER the current operation and\n * any pending I/O callbacks, so the event loop genuinely regains control before\n * resuming (unlike a microtask, which drains within the current task). `delay(ms)`\n * waits on a real `setTimeout`.\n * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with\n * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite\n * before arming either Node handle, so caller signal method mutation is harmless and the\n * first completion, abort, or setup failure owns settlement and cleanup. It deliberately\n * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason\n * with a Node `AbortError` (`code: 'ABORT_ERR'`).\n * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent\n * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted\n * for contract compliance and ignored — every yield/delay is uniform.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { NodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = new NodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal }) // a setImmediate host-turn\n * }\n * ```\n */\nexport class NodeScheduler implements SchedulerInterface {\n\t/**\n\t * Yield control back to the event loop via `setImmediate` so pending I/O and timers\n\t * can run, then resume; abort rejects with `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#immediate(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 Node-native immediate boundary; `scheduleHost` owns cancellation lifecycle.\n\t#immediate(signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setImmediate(complete)\n\t\t\treturn () => clearImmediate(handle)\n\t\t}, signal)\n\t}\n\n\t// The Node 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 } from '@src/core'\nimport { NodeScheduler } from './NodeScheduler.js'\n\n/**\n * Create the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a\n * `setImmediate` host-turn (the canonical Node \"give the event loop a turn\"), `delay(ms)`\n * a real `setTimeout`.\n *\n * @remarks\n * Use it on a server instead of the cross-environment `createScheduler` when a yield\n * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather\n * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a\n * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal\n * lifecycle clears the native handle without invoking caller listener methods.\n * `options.priority` is accepted for contract compliance but a\n * no-op — Node has no priority primitive.\n *\n * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { createNodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = createNodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal })\n * }\n * ```\n */\nexport function createNodeScheduler(): SchedulerInterface {\n\treturn new NodeScheduler()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,gBAAb,MAAyD;;;;;CAKxD,MAAM,SAA2C;EAChD,OAAO,KAAK,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;;CAYA,MAAM,IAAY,SAA2C;EAC5D,OAAO,KAAK,OAAO,IAAI,SAAS,MAAM;CACvC;CAKA,WAAW,QAAqC;EAC/C,QAAA,GAAO,UAAA,aAAA,EAAc,aAAa;GACjC,MAAM,SAAS,aAAa,QAAQ;GACpC,aAAa,eAAe,MAAM;EACnC,GAAG,MAAM;CACV;CAGA,OAAO,IAAY,QAAqC;EACvD,QAAA,GAAO,UAAA,aAAA,EAAc,aAAa;GACjC,MAAM,SAAS,WAAW,UAAU,EAAE;GACtC,aAAa,aAAa,MAAM;EACjC,GAAG,MAAM;CACV;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5CA,SAAgB,sBAA0C;CACzD,OAAO,IAAI,cAAc;AAC1B"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/server/NodeScheduler.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { delayHost, scheduleHost } from '@src/core'\n\n/**\n * Implements the Node {@link SchedulerInterface} — the server-native cooperative-yield backend.\n *\n * @remarks\n * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the\n * canonical Node \"give the host a turn\" — it runs AFTER the current operation and\n * any pending I/O callbacks, so the event loop genuinely regains control before\n * resuming (unlike a microtask, which drains within the current task). `delay(ms)`\n * waits on a real `setTimeout`.\n * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with\n * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite\n * before arming either Node handle, so caller signal method mutation is harmless and the\n * first completion, abort, or setup failure owns settlement and cleanup. It deliberately\n * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason\n * with a Node `AbortError` (`code: 'ABORT_ERR'`).\n * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent\n * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted\n * for contract compliance and ignored — every yield/delay is uniform.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { NodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = new NodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal }) // a setImmediate host-turn\n * }\n * ```\n */\nexport class NodeScheduler implements SchedulerInterface {\n\t/**\n\t * Yields control back to the event loop through `setImmediate` so pending I/O and timers\n\t * can run, then resumes; abort rejects with `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#immediate(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 Node-native immediate boundary; `scheduleHost` owns cancellation lifecycle.\n\t#immediate(signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setImmediate(complete)\n\t\t\treturn () => clearImmediate(handle)\n\t\t}, signal)\n\t}\n}\n","import type { SchedulerInterface } from '@src/core'\nimport { NodeScheduler } from './NodeScheduler.js'\n\n/**\n * Creates the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a\n * `setImmediate` host-turn (the canonical Node \"give the event loop a turn\"), `delay(ms)`\n * a real `setTimeout`.\n *\n * @remarks\n * Use it on a server instead of the cross-environment `createScheduler` when a yield must\n * hand the event loop a full turn (after pending I/O) through `setImmediate` rather than a\n * zero-delay timer. Both methods are abort-aware: pass `options.signal` and a\n * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal\n * lifecycle clears the native handle without invoking caller listener methods.\n * `options.priority` is accepted for contract compliance but a\n * no-op — Node has no priority primitive.\n *\n * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { createNodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = createNodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal })\n * }\n * ```\n */\nexport function createNodeScheduler(): SchedulerInterface {\n\treturn new NodeScheduler()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,gBAAb,MAAyD;;;;;CAKxD,MAAM,SAA2C;EAChD,OAAO,KAAK,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;CAWA,MAAM,IAAY,SAA2C;EAC5D,QAAA,GAAO,UAAA,UAAA,CAAU,IAAI,SAAS,MAAM;CACrC;CAKA,WAAW,QAAqC;EAC/C,QAAA,GAAO,UAAA,aAAA,EAAc,aAAa;GACjC,MAAM,SAAS,aAAa,QAAQ;GACpC,aAAa,eAAe,MAAM;EACnC,GAAG,MAAM;CACV;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,SAAgB,sBAA0C;CACzD,OAAO,IAAI,cAAc;AAC1B"}
@@ -2,14 +2,14 @@ import { SchedulerInterface } from '@orkestrel/workflow';
2
2
  import { SchedulerOptions } from '@orkestrel/workflow';
3
3
 
4
4
  /**
5
- * Create the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
5
+ * Creates the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
6
6
  * `setImmediate` host-turn (the canonical Node "give the event loop a turn"), `delay(ms)`
7
7
  * a real `setTimeout`.
8
8
  *
9
9
  * @remarks
10
- * Use it on a server instead of the cross-environment `createScheduler` when a yield
11
- * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
12
- * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
10
+ * Use it on a server instead of the cross-environment `createScheduler` when a yield must
11
+ * hand the event loop a full turn (after pending I/O) through `setImmediate` rather than a
12
+ * zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
13
13
  * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
14
14
  * lifecycle clears the native handle without invoking caller listener methods.
15
15
  * `options.priority` is accepted for contract compliance but a
@@ -33,7 +33,7 @@ import { SchedulerOptions } from '@orkestrel/workflow';
33
33
  export declare function createNodeScheduler(): SchedulerInterface;
34
34
 
35
35
  /**
36
- * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
36
+ * Implements the Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
37
37
  *
38
38
  * @remarks
39
39
  * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the
@@ -68,19 +68,18 @@ export declare function createNodeScheduler(): SchedulerInterface;
68
68
  export declare class NodeScheduler implements SchedulerInterface {
69
69
  #private;
70
70
  /**
71
- * Yield control back to the event loop via `setImmediate` so pending I/O and timers
72
- * can run, then resume; abort rejects with `signal.reason`.
71
+ * Yields control back to the event loop through `setImmediate` so pending I/O and timers
72
+ * can run, then resumes; abort rejects with `signal.reason`.
73
73
  */
74
74
  yield(options?: SchedulerOptions): Promise<void>;
75
75
  /**
76
- * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
76
+ * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
77
77
  * `signal.reason`.
78
78
  *
79
79
  * @remarks
80
- * `ms` should be a non-negative finite number. The primitive does no validation: it
81
- * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
82
- * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
83
- * throwing.
80
+ * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
81
+ * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
82
+ * out-of-domain `ms` resolves on the next host turn rather than throwing.
84
83
  */
85
84
  delay(ms: number, options?: SchedulerOptions): Promise<void>;
86
85
  }
@@ -2,14 +2,14 @@ import { SchedulerInterface } from '@orkestrel/workflow';
2
2
  import { SchedulerOptions } from '@orkestrel/workflow';
3
3
 
4
4
  /**
5
- * Create the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
5
+ * Creates the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
6
6
  * `setImmediate` host-turn (the canonical Node "give the event loop a turn"), `delay(ms)`
7
7
  * a real `setTimeout`.
8
8
  *
9
9
  * @remarks
10
- * Use it on a server instead of the cross-environment `createScheduler` when a yield
11
- * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
12
- * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
10
+ * Use it on a server instead of the cross-environment `createScheduler` when a yield must
11
+ * hand the event loop a full turn (after pending I/O) through `setImmediate` rather than a
12
+ * zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
13
13
  * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
14
14
  * lifecycle clears the native handle without invoking caller listener methods.
15
15
  * `options.priority` is accepted for contract compliance but a
@@ -33,7 +33,7 @@ import { SchedulerOptions } from '@orkestrel/workflow';
33
33
  export declare function createNodeScheduler(): SchedulerInterface;
34
34
 
35
35
  /**
36
- * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
36
+ * Implements the Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
37
37
  *
38
38
  * @remarks
39
39
  * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the
@@ -68,19 +68,18 @@ export declare function createNodeScheduler(): SchedulerInterface;
68
68
  export declare class NodeScheduler implements SchedulerInterface {
69
69
  #private;
70
70
  /**
71
- * Yield control back to the event loop via `setImmediate` so pending I/O and timers
72
- * can run, then resume; abort rejects with `signal.reason`.
71
+ * Yields control back to the event loop through `setImmediate` so pending I/O and timers
72
+ * can run, then resumes; abort rejects with `signal.reason`.
73
73
  */
74
74
  yield(options?: SchedulerOptions): Promise<void>;
75
75
  /**
76
- * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
76
+ * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
77
77
  * `signal.reason`.
78
78
  *
79
79
  * @remarks
80
- * `ms` should be a non-negative finite number. The primitive does no validation: it
81
- * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
82
- * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
83
- * throwing.
80
+ * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
81
+ * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
82
+ * out-of-domain `ms` resolves on the next host turn rather than throwing.
84
83
  */
85
84
  delay(ms: number, options?: SchedulerOptions): Promise<void>;
86
85
  }
@@ -1,7 +1,7 @@
1
- import { scheduleHost } from "../core/index.js";
1
+ import { delayHost, scheduleHost } from "../core/index.js";
2
2
  //#region src/server/NodeScheduler.ts
3
3
  /**
4
- * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
4
+ * Implements the Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
5
5
  *
6
6
  * @remarks
7
7
  * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the
@@ -35,24 +35,23 @@ import { scheduleHost } from "../core/index.js";
35
35
  */
36
36
  var NodeScheduler = class {
37
37
  /**
38
- * Yield control back to the event loop via `setImmediate` so pending I/O and timers
39
- * can run, then resume; abort rejects with `signal.reason`.
38
+ * Yields control back to the event loop through `setImmediate` so pending I/O and timers
39
+ * can run, then resumes; abort rejects with `signal.reason`.
40
40
  */
41
41
  yield(options) {
42
42
  return this.#immediate(options?.signal);
43
43
  }
44
44
  /**
45
- * Resume after at least `ms` milliseconds via `setTimeout`; abort rejects with
45
+ * Resumes after at least `ms` milliseconds through `setTimeout`; abort rejects with
46
46
  * `signal.reason`.
47
47
  *
48
48
  * @remarks
49
- * `ms` should be a non-negative finite number. The primitive does no validation: it
50
- * passes `ms` straight to the host `setTimeout`, which clamps a negative value or
51
- * `NaN` to ~0 — so an out-of-domain `ms` resolves on the next host turn rather than
52
- * throwing.
49
+ * Pass a non-negative finite `ms`. The primitive does no validation: it passes `ms`
50
+ * straight to the host `setTimeout`, which clamps a negative value or `NaN` to ~0 — so an
51
+ * out-of-domain `ms` resolves on the next host turn rather than throwing.
53
52
  */
54
53
  delay(ms, options) {
55
- return this.#sleep(ms, options?.signal);
54
+ return delayHost(ms, options?.signal);
56
55
  }
57
56
  #immediate(signal) {
58
57
  return scheduleHost((complete) => {
@@ -60,24 +59,18 @@ var NodeScheduler = class {
60
59
  return () => clearImmediate(handle);
61
60
  }, signal);
62
61
  }
63
- #sleep(ms, signal) {
64
- return scheduleHost((complete) => {
65
- const handle = setTimeout(complete, ms);
66
- return () => clearTimeout(handle);
67
- }, signal);
68
- }
69
62
  };
70
63
  //#endregion
71
64
  //#region src/server/factories.ts
72
65
  /**
73
- * Create the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
66
+ * Creates the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a
74
67
  * `setImmediate` host-turn (the canonical Node "give the event loop a turn"), `delay(ms)`
75
68
  * a real `setTimeout`.
76
69
  *
77
70
  * @remarks
78
- * Use it on a server instead of the cross-environment `createScheduler` when a yield
79
- * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
80
- * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
71
+ * Use it on a server instead of the cross-environment `createScheduler` when a yield must
72
+ * hand the event loop a full turn (after pending I/O) through `setImmediate` rather than a
73
+ * zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
81
74
  * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
82
75
  * lifecycle clears the native handle without invoking caller listener methods.
83
76
  * `options.priority` is accepted for contract compliance but a
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/server/NodeScheduler.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { scheduleHost } from '@src/core'\n\n/**\n * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.\n *\n * @remarks\n * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the\n * canonical Node \"give the host a turn\" — it runs AFTER the current operation and\n * any pending I/O callbacks, so the event loop genuinely regains control before\n * resuming (unlike a microtask, which drains within the current task). `delay(ms)`\n * waits on a real `setTimeout`.\n * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with\n * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite\n * before arming either Node handle, so caller signal method mutation is harmless and the\n * first completion, abort, or setup failure owns settlement and cleanup. It deliberately\n * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason\n * with a Node `AbortError` (`code: 'ABORT_ERR'`).\n * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent\n * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted\n * for contract compliance and ignored — every yield/delay is uniform.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { NodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = new NodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal }) // a setImmediate host-turn\n * }\n * ```\n */\nexport class NodeScheduler implements SchedulerInterface {\n\t/**\n\t * Yield control back to the event loop via `setImmediate` so pending I/O and timers\n\t * can run, then resume; abort rejects with `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#immediate(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 Node-native immediate boundary; `scheduleHost` owns cancellation lifecycle.\n\t#immediate(signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setImmediate(complete)\n\t\t\treturn () => clearImmediate(handle)\n\t\t}, signal)\n\t}\n\n\t// The Node 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 } from '@src/core'\nimport { NodeScheduler } from './NodeScheduler.js'\n\n/**\n * Create the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a\n * `setImmediate` host-turn (the canonical Node \"give the event loop a turn\"), `delay(ms)`\n * a real `setTimeout`.\n *\n * @remarks\n * Use it on a server instead of the cross-environment `createScheduler` when a yield\n * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather\n * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a\n * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal\n * lifecycle clears the native handle without invoking caller listener methods.\n * `options.priority` is accepted for contract compliance but a\n * no-op — Node has no priority primitive.\n *\n * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { createNodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = createNodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal })\n * }\n * ```\n */\nexport function createNodeScheduler(): SchedulerInterface {\n\treturn new NodeScheduler()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,gBAAb,MAAyD;;;;;CAKxD,MAAM,SAA2C;EAChD,OAAO,KAAK,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;;CAYA,MAAM,IAAY,SAA2C;EAC5D,OAAO,KAAK,OAAO,IAAI,SAAS,MAAM;CACvC;CAKA,WAAW,QAAqC;EAC/C,OAAO,cAAc,aAAa;GACjC,MAAM,SAAS,aAAa,QAAQ;GACpC,aAAa,eAAe,MAAM;EACnC,GAAG,MAAM;CACV;CAGA,OAAO,IAAY,QAAqC;EACvD,OAAO,cAAc,aAAa;GACjC,MAAM,SAAS,WAAW,UAAU,EAAE;GACtC,aAAa,aAAa,MAAM;EACjC,GAAG,MAAM;CACV;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5CA,SAAgB,sBAA0C;CACzD,OAAO,IAAI,cAAc;AAC1B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/server/NodeScheduler.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { SchedulerInterface, SchedulerOptions } from '@src/core'\nimport { delayHost, scheduleHost } from '@src/core'\n\n/**\n * Implements the Node {@link SchedulerInterface} — the server-native cooperative-yield backend.\n *\n * @remarks\n * - **`yield` is a `setImmediate` host-turn.** `yield()` waits on `setImmediate`, the\n * canonical Node \"give the host a turn\" — it runs AFTER the current operation and\n * any pending I/O callbacks, so the event loop genuinely regains control before\n * resuming (unlike a microtask, which drains within the current task). `delay(ms)`\n * waits on a real `setTimeout`.\n * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with\n * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite\n * before arming either Node handle, so caller signal method mutation is harmless and the\n * first completion, abort, or setup failure owns settlement and cleanup. It deliberately\n * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason\n * with a Node `AbortError` (`code: 'ABORT_ERR'`).\n * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent\n * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted\n * for contract compliance and ignored — every yield/delay is uniform.\n * - **Event-free.** A pure functional primitive — no Emitter, no events.\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { NodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = new NodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal }) // a setImmediate host-turn\n * }\n * ```\n */\nexport class NodeScheduler implements SchedulerInterface {\n\t/**\n\t * Yields control back to the event loop through `setImmediate` so pending I/O and timers\n\t * can run, then resumes; abort rejects with `signal.reason`.\n\t */\n\tyield(options?: SchedulerOptions): Promise<void> {\n\t\treturn this.#immediate(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 Node-native immediate boundary; `scheduleHost` owns cancellation lifecycle.\n\t#immediate(signal?: AbortSignal): Promise<void> {\n\t\treturn scheduleHost((complete) => {\n\t\t\tconst handle = setImmediate(complete)\n\t\t\treturn () => clearImmediate(handle)\n\t\t}, signal)\n\t}\n}\n","import type { SchedulerInterface } from '@src/core'\nimport { NodeScheduler } from './NodeScheduler.js'\n\n/**\n * Creates the Node-native cooperative-yield {@link SchedulerInterface} — `yield()` is a\n * `setImmediate` host-turn (the canonical Node \"give the event loop a turn\"), `delay(ms)`\n * a real `setTimeout`.\n *\n * @remarks\n * Use it on a server instead of the cross-environment `createScheduler` when a yield must\n * hand the event loop a full turn (after pending I/O) through `setImmediate` rather than a\n * zero-delay timer. Both methods are abort-aware: pass `options.signal` and a\n * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal\n * lifecycle clears the native handle without invoking caller listener methods.\n * `options.priority` is accepted for contract compliance but a\n * no-op — Node has no priority primitive.\n *\n * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`\n *\n * @example\n * ```ts\n * import { createAbort } from '@orkestrel/abort'\n * import { createNodeScheduler } from '@orkestrel/workflow/server'\n *\n * const abort = createAbort()\n * const scheduler = createNodeScheduler()\n * while (!abort.signal.aborted) {\n * \tdoSomeWork()\n * \tawait scheduler.yield({ signal: abort.signal })\n * }\n * ```\n */\nexport function createNodeScheduler(): SchedulerInterface {\n\treturn new NodeScheduler()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,IAAa,gBAAb,MAAyD;;;;;CAKxD,MAAM,SAA2C;EAChD,OAAO,KAAK,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;CAWA,MAAM,IAAY,SAA2C;EAC5D,OAAO,UAAU,IAAI,SAAS,MAAM;CACrC;CAKA,WAAW,QAAqC;EAC/C,OAAO,cAAc,aAAa;GACjC,MAAM,SAAS,aAAa,QAAQ;GACpC,aAAa,eAAe,MAAM;EACnC,GAAG,MAAM;CACV;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA,SAAgB,sBAA0C;CACzD,OAAO,IAAI,cAAc;AAC1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkestrel/workflow",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "A typed workflow engine for the @orkestrel line — a serializable Workflow → Phase → Task tree run by a composed runner on a cooperative scheduler. Part of the @orkestrel line.",
5
5
  "keywords": [
6
6
  "orchestration",
@@ -91,28 +91,28 @@
91
91
  "test:setup": "vitest run --config vite.config.ts --no-cache --reporter=dot --project setup"
92
92
  },
93
93
  "dependencies": {
94
- "@orkestrel/abort": "^0.0.8",
95
- "@orkestrel/budget": "^0.0.8",
96
- "@orkestrel/contract": "^0.0.13",
97
- "@orkestrel/database": "^0.0.12",
98
- "@orkestrel/emitter": "^0.0.8",
99
- "@orkestrel/queue": "^0.0.11",
100
- "@orkestrel/timeout": "^0.0.8"
94
+ "@orkestrel/abort": "^0.0.9",
95
+ "@orkestrel/budget": "^0.0.9",
96
+ "@orkestrel/contract": "^0.0.16",
97
+ "@orkestrel/database": "^0.0.13",
98
+ "@orkestrel/emitter": "^0.0.9",
99
+ "@orkestrel/queue": "^0.0.12",
100
+ "@orkestrel/timeout": "^0.0.9"
101
101
  },
102
102
  "devDependencies": {
103
103
  "@microsoft/api-extractor": "^7.59.0",
104
- "@orkestrel/guide": "^0.0.15",
105
- "@orkestrel/probe": "^0.0.9",
106
- "@orkestrel/scaffold": "^0.0.57",
107
- "@orkestrel/test": "^0.0.11",
108
- "@types/node": "^26.4.0",
104
+ "@orkestrel/guide": "^0.0.17",
105
+ "@orkestrel/probe": "^0.0.11",
106
+ "@orkestrel/scaffold": "^0.0.62",
107
+ "@orkestrel/test": "^0.0.13",
108
+ "@types/node": "^26.4.1",
109
109
  "@vitest/browser-playwright": "^4.1.11",
110
- "oxfmt": "^0.65.0",
111
- "oxlint": "^1.80.0",
110
+ "oxfmt": "^0.66.0",
111
+ "oxlint": "^1.81.0",
112
112
  "playwright": "^1.62.1",
113
113
  "typescript": "^6.0.3",
114
114
  "vite": "^8.2.2",
115
- "vite-plugin-dts": "^5.0.3",
115
+ "vite-plugin-dts": "^5.1.0",
116
116
  "vitest": "^4.1.11"
117
117
  },
118
118
  "engines": {