@orkestrel/workflow 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let _src_core = require("../core/index.cjs");
2
3
  //#region src/server/NodeScheduler.ts
3
4
  /**
4
5
  * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
@@ -10,17 +11,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
10
11
  * resuming (unlike a microtask, which drains within the current task). `delay(ms)`
11
12
  * waits on a real `setTimeout`.
12
13
  * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with
13
- * `signal.reason` exactly the value the caller passed, never wrapped or replaced.
14
- * The discipline mirrors the cross-environment default's `#sleep`: an already-aborted
15
- * signal rejects immediately WITHOUT arming a timer; otherwise the timer is armed and
16
- * a `{ once: true }` abort listener attached, and the two settle paths are mutually
17
- * exclusive the timer path removes the listener before resolving (so a later abort
18
- * cannot reach `reject`), and the abort path clears the timer before rejecting (so the
19
- * macrotask cannot reach `resolve`). The promise settles exactly once, with no leaked
20
- * timer and no leaked listener. It deliberately does NOT use `node:timers/promises`,
21
- * whose `{ signal }` option rejects with a Node `AbortError` (`code: 'ABORT_ERR'`)
22
- * rather than the caller's `signal.reason` — that would break reason fidelity, so the
23
- * timer and listener are hand-rolled to match the contract.
14
+ * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite
15
+ * before arming either Node handle, so caller signal method mutation is harmless and the
16
+ * first completion, abort, or setup failure owns settlement and cleanup. It deliberately
17
+ * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason
18
+ * with a Node `AbortError` (`code: 'ABORT_ERR'`).
24
19
  * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent
25
20
  * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted
26
21
  * for contract compliance and ignored — every yield/delay is uniform.
@@ -28,8 +23,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
28
23
  *
29
24
  * @example
30
25
  * ```ts
31
- * import { createAbort } from '@src/core'
32
- * import { NodeScheduler } from '@src/server'
26
+ * import { createAbort } from '@orkestrel/abort'
27
+ * import { NodeScheduler } from '@orkestrel/workflow/server'
33
28
  *
34
29
  * const abort = createAbort()
35
30
  * const scheduler = new NodeScheduler()
@@ -61,34 +56,16 @@ var NodeScheduler = class {
61
56
  return this.#sleep(ms, options?.signal);
62
57
  }
63
58
  #immediate(signal) {
64
- if (signal?.aborted === true) return Promise.reject(signal.reason);
65
- return new Promise((resolve, reject) => {
66
- const handle = setImmediate(() => {
67
- signal?.removeEventListener("abort", onAbort);
68
- resolve();
69
- });
70
- const onAbort = this.#abortImmediate.bind(this, handle, reject, signal);
71
- signal?.addEventListener("abort", onAbort, { once: true });
72
- });
59
+ return (0, _src_core.scheduleHost)((complete) => {
60
+ const handle = setImmediate(complete);
61
+ return () => clearImmediate(handle);
62
+ }, signal);
73
63
  }
74
64
  #sleep(ms, signal) {
75
- if (signal?.aborted === true) return Promise.reject(signal.reason);
76
- return new Promise((resolve, reject) => {
77
- const handle = setTimeout(() => {
78
- signal?.removeEventListener("abort", onAbort);
79
- resolve();
80
- }, ms);
81
- const onAbort = this.#abortTimeout.bind(this, handle, reject, signal);
82
- signal?.addEventListener("abort", onAbort, { once: true });
83
- });
84
- }
85
- #abortImmediate(handle, reject, signal) {
86
- clearImmediate(handle);
87
- reject(signal?.reason);
88
- }
89
- #abortTimeout(handle, reject, signal) {
90
- clearTimeout(handle);
91
- reject(signal?.reason);
65
+ return (0, _src_core.scheduleHost)((complete) => {
66
+ const handle = setTimeout(complete, ms);
67
+ return () => clearTimeout(handle);
68
+ }, signal);
92
69
  }
93
70
  };
94
71
  //#endregion
@@ -102,16 +79,17 @@ var NodeScheduler = class {
102
79
  * Use it on a server instead of the cross-environment `createScheduler` when a yield
103
80
  * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
104
81
  * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
105
- * pending yield/delay rejects with the signal's `reason` (verbatim, with full
106
- * timer/listener cleanup). `options.priority` is accepted for contract compliance but a
82
+ * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
83
+ * lifecycle clears the native handle without invoking caller listener methods.
84
+ * `options.priority` is accepted for contract compliance but a
107
85
  * no-op — Node has no priority primitive.
108
86
  *
109
87
  * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`
110
88
  *
111
89
  * @example
112
90
  * ```ts
113
- * import { createAbort } from '@src/core'
114
- * import { createNodeScheduler } from '@src/server'
91
+ * import { createAbort } from '@orkestrel/abort'
92
+ * import { createNodeScheduler } from '@orkestrel/workflow/server'
115
93
  *
116
94
  * const abort = createAbort()
117
95
  * const scheduler = createNodeScheduler()
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["#immediate","#sleep","#abortImmediate","#abortTimeout"],"sources":["../../../src/server/NodeScheduler.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { SchedulerInterface, SchedulerOptions } 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 value the caller passed, never wrapped or replaced.\n * The discipline mirrors the cross-environment default's `#sleep`: an already-aborted\n * signal rejects immediately WITHOUT arming a timer; otherwise the timer is armed and\n * a `{ once: true }` abort listener attached, and the two settle paths are mutually\n * exclusive the timer path removes the listener before resolving (so a later abort\n * cannot reach `reject`), and the abort path clears the timer before rejecting (so the\n * macrotask cannot reach `resolve`). The promise settles exactly once, with no leaked\n * timer and no leaked listener. It deliberately does NOT use `node:timers/promises`,\n * whose `{ signal }` option rejects with a Node `AbortError` (`code: 'ABORT_ERR'`)\n * rather than the caller's `signal.reason` — that would break reason fidelity, so the\n * timer and listener are hand-rolled to match the contract.\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 '@src/core'\n * import { NodeScheduler } from '@src/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 `setImmediate` host-turn for `yield`. Resolves after the immediate callback\n\t// fires (after the current operation and pending I/O); rejects with `signal.reason`\n\t// if the signal is already aborted (no immediate armed) or aborts while pending.\n\t// The two settle paths disarm each other: the immediate path removes the abort\n\t// listener before resolving; the abort path clears the immediate before rejecting —\n\t// so it settles exactly once, with no leaked handle and no leaked listener.\n\t#immediate(signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst handle = setImmediate(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t})\n\t\t\tconst onAbort = this.#abortImmediate.bind(this, handle, reject, signal)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t// The abort-aware `setTimeout` sleep for `delay`. Same settle-once discipline as\n\t// `#immediate`, with a timer in place of the immediate: an already-aborted signal\n\t// rejects without arming; otherwise the timer path removes the listener before\n\t// resolving and the abort path clears the timer before rejecting with `signal.reason`.\n\t#sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst handle = setTimeout(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t\tconst onAbort = this.#abortTimeout.bind(this, handle, reject, signal)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t#abortImmediate(\n\t\thandle: ReturnType<typeof setImmediate>,\n\t\treject: (reason?: unknown) => void,\n\t\tsignal?: AbortSignal,\n\t): void {\n\t\tclearImmediate(handle)\n\t\treject(signal?.reason)\n\t}\n\n\t#abortTimeout(\n\t\thandle: ReturnType<typeof setTimeout>,\n\t\treject: (reason?: unknown) => void,\n\t\tsignal?: AbortSignal,\n\t): void {\n\t\tclearTimeout(handle)\n\t\treject(signal?.reason)\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 `reason` (verbatim, with full\n * timer/listener cleanup). `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 '@src/core'\n * import { createNodeScheduler } from '@src/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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,gBAAb,MAAyD;;;;;CAKxD,MAAM,SAA2C;EAChD,OAAO,KAAKA,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;;CAYA,MAAM,IAAY,SAA2C;EAC5D,OAAO,KAAKC,OAAO,IAAI,SAAS,MAAM;CACvC;CAUA,WAAW,QAAqC;EAC/C,IAAI,QAAQ,YAAY,MAAM,OAAO,QAAQ,OAAO,OAAO,MAAM;EACjE,OAAO,IAAI,SAAe,SAAS,WAAW;GAC7C,MAAM,SAAS,mBAAmB;IACjC,QAAQ,oBAAoB,SAAS,OAAO;IAC5C,QAAQ;GACT,CAAC;GACD,MAAM,UAAU,KAAKC,gBAAgB,KAAK,MAAM,QAAQ,QAAQ,MAAM;GACtE,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAC1D,CAAC;CACF;CAMA,OAAO,IAAY,QAAqC;EACvD,IAAI,QAAQ,YAAY,MAAM,OAAO,QAAQ,OAAO,OAAO,MAAM;EACjE,OAAO,IAAI,SAAe,SAAS,WAAW;GAC7C,MAAM,SAAS,iBAAiB;IAC/B,QAAQ,oBAAoB,SAAS,OAAO;IAC5C,QAAQ;GACT,GAAG,EAAE;GACL,MAAM,UAAU,KAAKC,cAAc,KAAK,MAAM,QAAQ,QAAQ,MAAM;GACpE,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAC1D,CAAC;CACF;CAEA,gBACC,QACA,QACA,QACO;EACP,eAAe,MAAM;EACrB,OAAO,QAAQ,MAAM;CACtB;CAEA,cACC,QACA,QACA,QACO;EACP,aAAa,MAAM;EACnB,OAAO,QAAQ,MAAM;CACtB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtFA,SAAgB,sBAA0C;CACzD,OAAO,IAAI,cAAc;AAC1B"}
1
+ {"version":3,"file":"index.cjs","names":["#immediate","#sleep"],"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,KAAKA,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;;CAYA,MAAM,IAAY,SAA2C;EAC5D,OAAO,KAAKC,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"}
@@ -10,16 +10,17 @@ import { SchedulerOptions } from '../core/index.ts';
10
10
  * Use it on a server instead of the cross-environment `createScheduler` when a yield
11
11
  * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
12
12
  * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
13
- * pending yield/delay rejects with the signal's `reason` (verbatim, with full
14
- * timer/listener cleanup). `options.priority` is accepted for contract compliance but a
13
+ * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
14
+ * lifecycle clears the native handle without invoking caller listener methods.
15
+ * `options.priority` is accepted for contract compliance but a
15
16
  * no-op — Node has no priority primitive.
16
17
  *
17
18
  * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`
18
19
  *
19
20
  * @example
20
21
  * ```ts
21
- * import { createAbort } from '@src/core'
22
- * import { createNodeScheduler } from '@src/server'
22
+ * import { createAbort } from '@orkestrel/abort'
23
+ * import { createNodeScheduler } from '@orkestrel/workflow/server'
23
24
  *
24
25
  * const abort = createAbort()
25
26
  * const scheduler = createNodeScheduler()
@@ -41,17 +42,11 @@ export declare function createNodeScheduler(): SchedulerInterface;
41
42
  * resuming (unlike a microtask, which drains within the current task). `delay(ms)`
42
43
  * waits on a real `setTimeout`.
43
44
  * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with
44
- * `signal.reason` exactly the value the caller passed, never wrapped or replaced.
45
- * The discipline mirrors the cross-environment default's `#sleep`: an already-aborted
46
- * signal rejects immediately WITHOUT arming a timer; otherwise the timer is armed and
47
- * a `{ once: true }` abort listener attached, and the two settle paths are mutually
48
- * exclusive the timer path removes the listener before resolving (so a later abort
49
- * cannot reach `reject`), and the abort path clears the timer before rejecting (so the
50
- * macrotask cannot reach `resolve`). The promise settles exactly once, with no leaked
51
- * timer and no leaked listener. It deliberately does NOT use `node:timers/promises`,
52
- * whose `{ signal }` option rejects with a Node `AbortError` (`code: 'ABORT_ERR'`)
53
- * rather than the caller's `signal.reason` — that would break reason fidelity, so the
54
- * timer and listener are hand-rolled to match the contract.
45
+ * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite
46
+ * before arming either Node handle, so caller signal method mutation is harmless and the
47
+ * first completion, abort, or setup failure owns settlement and cleanup. It deliberately
48
+ * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason
49
+ * with a Node `AbortError` (`code: 'ABORT_ERR'`).
55
50
  * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent
56
51
  * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted
57
52
  * for contract compliance and ignored — every yield/delay is uniform.
@@ -59,8 +54,8 @@ export declare function createNodeScheduler(): SchedulerInterface;
59
54
  *
60
55
  * @example
61
56
  * ```ts
62
- * import { createAbort } from '@src/core'
63
- * import { NodeScheduler } from '@src/server'
57
+ * import { createAbort } from '@orkestrel/abort'
58
+ * import { NodeScheduler } from '@orkestrel/workflow/server'
64
59
  *
65
60
  * const abort = createAbort()
66
61
  * const scheduler = new NodeScheduler()
@@ -10,16 +10,17 @@ import { SchedulerOptions } from '../core/index.ts';
10
10
  * Use it on a server instead of the cross-environment `createScheduler` when a yield
11
11
  * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
12
12
  * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
13
- * pending yield/delay rejects with the signal's `reason` (verbatim, with full
14
- * timer/listener cleanup). `options.priority` is accepted for contract compliance but a
13
+ * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
14
+ * lifecycle clears the native handle without invoking caller listener methods.
15
+ * `options.priority` is accepted for contract compliance but a
15
16
  * no-op — Node has no priority primitive.
16
17
  *
17
18
  * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`
18
19
  *
19
20
  * @example
20
21
  * ```ts
21
- * import { createAbort } from '@src/core'
22
- * import { createNodeScheduler } from '@src/server'
22
+ * import { createAbort } from '@orkestrel/abort'
23
+ * import { createNodeScheduler } from '@orkestrel/workflow/server'
23
24
  *
24
25
  * const abort = createAbort()
25
26
  * const scheduler = createNodeScheduler()
@@ -41,17 +42,11 @@ export declare function createNodeScheduler(): SchedulerInterface;
41
42
  * resuming (unlike a microtask, which drains within the current task). `delay(ms)`
42
43
  * waits on a real `setTimeout`.
43
44
  * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with
44
- * `signal.reason` exactly the value the caller passed, never wrapped or replaced.
45
- * The discipline mirrors the cross-environment default's `#sleep`: an already-aborted
46
- * signal rejects immediately WITHOUT arming a timer; otherwise the timer is armed and
47
- * a `{ once: true }` abort listener attached, and the two settle paths are mutually
48
- * exclusive the timer path removes the listener before resolving (so a later abort
49
- * cannot reach `reject`), and the abort path clears the timer before rejecting (so the
50
- * macrotask cannot reach `resolve`). The promise settles exactly once, with no leaked
51
- * timer and no leaked listener. It deliberately does NOT use `node:timers/promises`,
52
- * whose `{ signal }` option rejects with a Node `AbortError` (`code: 'ABORT_ERR'`)
53
- * rather than the caller's `signal.reason` — that would break reason fidelity, so the
54
- * timer and listener are hand-rolled to match the contract.
45
+ * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite
46
+ * before arming either Node handle, so caller signal method mutation is harmless and the
47
+ * first completion, abort, or setup failure owns settlement and cleanup. It deliberately
48
+ * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason
49
+ * with a Node `AbortError` (`code: 'ABORT_ERR'`).
55
50
  * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent
56
51
  * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted
57
52
  * for contract compliance and ignored — every yield/delay is uniform.
@@ -59,8 +54,8 @@ export declare function createNodeScheduler(): SchedulerInterface;
59
54
  *
60
55
  * @example
61
56
  * ```ts
62
- * import { createAbort } from '@src/core'
63
- * import { NodeScheduler } from '@src/server'
57
+ * import { createAbort } from '@orkestrel/abort'
58
+ * import { NodeScheduler } from '@orkestrel/workflow/server'
64
59
  *
65
60
  * const abort = createAbort()
66
61
  * const scheduler = new NodeScheduler()
@@ -1,3 +1,4 @@
1
+ import { scheduleHost } from "../core/index.js";
1
2
  //#region src/server/NodeScheduler.ts
2
3
  /**
3
4
  * The Node {@link SchedulerInterface} — the server-native cooperative-yield backend.
@@ -9,17 +10,11 @@
9
10
  * resuming (unlike a microtask, which drains within the current task). `delay(ms)`
10
11
  * waits on a real `setTimeout`.
11
12
  * - **Abort fidelity is verbatim.** A pending `yield` / `delay` rejects with
12
- * `signal.reason` exactly the value the caller passed, never wrapped or replaced.
13
- * The discipline mirrors the cross-environment default's `#sleep`: an already-aborted
14
- * signal rejects immediately WITHOUT arming a timer; otherwise the timer is armed and
15
- * a `{ once: true }` abort listener attached, and the two settle paths are mutually
16
- * exclusive the timer path removes the listener before resolving (so a later abort
17
- * cannot reach `reject`), and the abort path clears the timer before rejecting (so the
18
- * macrotask cannot reach `resolve`). The promise settles exactly once, with no leaked
19
- * timer and no leaked listener. It deliberately does NOT use `node:timers/promises`,
20
- * whose `{ signal }` option rejects with a Node `AbortError` (`code: 'ABORT_ERR'`)
21
- * rather than the caller's `signal.reason` — that would break reason fidelity, so the
22
- * timer and listener are hand-rolled to match the contract.
13
+ * `signal.reason` exactly. The shared `scheduleHost` lifecycle links an owned composite
14
+ * before arming either Node handle, so caller signal method mutation is harmless and the
15
+ * first completion, abort, or setup failure owns settlement and cleanup. It deliberately
16
+ * does NOT use `node:timers/promises`, whose `{ signal }` option replaces the caller reason
17
+ * with a Node `AbortError` (`code: 'ABORT_ERR'`).
23
18
  * - **Priority is accepted but a no-op.** Node has no priority primitive (no equivalent
24
19
  * of the browser's `scheduler.postTask` priorities), so `options.priority` is accepted
25
20
  * for contract compliance and ignored — every yield/delay is uniform.
@@ -27,8 +22,8 @@
27
22
  *
28
23
  * @example
29
24
  * ```ts
30
- * import { createAbort } from '@src/core'
31
- * import { NodeScheduler } from '@src/server'
25
+ * import { createAbort } from '@orkestrel/abort'
26
+ * import { NodeScheduler } from '@orkestrel/workflow/server'
32
27
  *
33
28
  * const abort = createAbort()
34
29
  * const scheduler = new NodeScheduler()
@@ -60,34 +55,16 @@ var NodeScheduler = class {
60
55
  return this.#sleep(ms, options?.signal);
61
56
  }
62
57
  #immediate(signal) {
63
- if (signal?.aborted === true) return Promise.reject(signal.reason);
64
- return new Promise((resolve, reject) => {
65
- const handle = setImmediate(() => {
66
- signal?.removeEventListener("abort", onAbort);
67
- resolve();
68
- });
69
- const onAbort = this.#abortImmediate.bind(this, handle, reject, signal);
70
- signal?.addEventListener("abort", onAbort, { once: true });
71
- });
58
+ return scheduleHost((complete) => {
59
+ const handle = setImmediate(complete);
60
+ return () => clearImmediate(handle);
61
+ }, signal);
72
62
  }
73
63
  #sleep(ms, signal) {
74
- if (signal?.aborted === true) return Promise.reject(signal.reason);
75
- return new Promise((resolve, reject) => {
76
- const handle = setTimeout(() => {
77
- signal?.removeEventListener("abort", onAbort);
78
- resolve();
79
- }, ms);
80
- const onAbort = this.#abortTimeout.bind(this, handle, reject, signal);
81
- signal?.addEventListener("abort", onAbort, { once: true });
82
- });
83
- }
84
- #abortImmediate(handle, reject, signal) {
85
- clearImmediate(handle);
86
- reject(signal?.reason);
87
- }
88
- #abortTimeout(handle, reject, signal) {
89
- clearTimeout(handle);
90
- reject(signal?.reason);
64
+ return scheduleHost((complete) => {
65
+ const handle = setTimeout(complete, ms);
66
+ return () => clearTimeout(handle);
67
+ }, signal);
91
68
  }
92
69
  };
93
70
  //#endregion
@@ -101,16 +78,17 @@ var NodeScheduler = class {
101
78
  * Use it on a server instead of the cross-environment `createScheduler` when a yield
102
79
  * should hand the event loop a full turn (after pending I/O) via `setImmediate` rather
103
80
  * than a zero-delay timer. Both methods are abort-aware: pass `options.signal` and a
104
- * pending yield/delay rejects with the signal's `reason` (verbatim, with full
105
- * timer/listener cleanup). `options.priority` is accepted for contract compliance but a
81
+ * pending yield/delay rejects with the signal's exact `reason`; the shared owned-signal
82
+ * lifecycle clears the native handle without invoking caller listener methods.
83
+ * `options.priority` is accepted for contract compliance but a
106
84
  * no-op — Node has no priority primitive.
107
85
  *
108
86
  * @returns A {@link SchedulerInterface} backed by Node's `setImmediate` / `setTimeout`
109
87
  *
110
88
  * @example
111
89
  * ```ts
112
- * import { createAbort } from '@src/core'
113
- * import { createNodeScheduler } from '@src/server'
90
+ * import { createAbort } from '@orkestrel/abort'
91
+ * import { createNodeScheduler } from '@orkestrel/workflow/server'
114
92
  *
115
93
  * const abort = createAbort()
116
94
  * const scheduler = createNodeScheduler()
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#immediate","#sleep","#abortImmediate","#abortTimeout"],"sources":["../../../src/server/NodeScheduler.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { SchedulerInterface, SchedulerOptions } 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 value the caller passed, never wrapped or replaced.\n * The discipline mirrors the cross-environment default's `#sleep`: an already-aborted\n * signal rejects immediately WITHOUT arming a timer; otherwise the timer is armed and\n * a `{ once: true }` abort listener attached, and the two settle paths are mutually\n * exclusive the timer path removes the listener before resolving (so a later abort\n * cannot reach `reject`), and the abort path clears the timer before rejecting (so the\n * macrotask cannot reach `resolve`). The promise settles exactly once, with no leaked\n * timer and no leaked listener. It deliberately does NOT use `node:timers/promises`,\n * whose `{ signal }` option rejects with a Node `AbortError` (`code: 'ABORT_ERR'`)\n * rather than the caller's `signal.reason` — that would break reason fidelity, so the\n * timer and listener are hand-rolled to match the contract.\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 '@src/core'\n * import { NodeScheduler } from '@src/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 `setImmediate` host-turn for `yield`. Resolves after the immediate callback\n\t// fires (after the current operation and pending I/O); rejects with `signal.reason`\n\t// if the signal is already aborted (no immediate armed) or aborts while pending.\n\t// The two settle paths disarm each other: the immediate path removes the abort\n\t// listener before resolving; the abort path clears the immediate before rejecting —\n\t// so it settles exactly once, with no leaked handle and no leaked listener.\n\t#immediate(signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst handle = setImmediate(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t})\n\t\t\tconst onAbort = this.#abortImmediate.bind(this, handle, reject, signal)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t// The abort-aware `setTimeout` sleep for `delay`. Same settle-once discipline as\n\t// `#immediate`, with a timer in place of the immediate: an already-aborted signal\n\t// rejects without arming; otherwise the timer path removes the listener before\n\t// resolving and the abort path clears the timer before rejecting with `signal.reason`.\n\t#sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\t\tif (signal?.aborted === true) return Promise.reject(signal.reason)\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tconst handle = setTimeout(() => {\n\t\t\t\tsignal?.removeEventListener('abort', onAbort) // load-bearing: prevents a post-resolve reject\n\t\t\t\tresolve()\n\t\t\t}, ms)\n\t\t\tconst onAbort = this.#abortTimeout.bind(this, handle, reject, signal)\n\t\t\tsignal?.addEventListener('abort', onAbort, { once: true })\n\t\t})\n\t}\n\n\t#abortImmediate(\n\t\thandle: ReturnType<typeof setImmediate>,\n\t\treject: (reason?: unknown) => void,\n\t\tsignal?: AbortSignal,\n\t): void {\n\t\tclearImmediate(handle)\n\t\treject(signal?.reason)\n\t}\n\n\t#abortTimeout(\n\t\thandle: ReturnType<typeof setTimeout>,\n\t\treject: (reason?: unknown) => void,\n\t\tsignal?: AbortSignal,\n\t): void {\n\t\tclearTimeout(handle)\n\t\treject(signal?.reason)\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 `reason` (verbatim, with full\n * timer/listener cleanup). `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 '@src/core'\n * import { createNodeScheduler } from '@src/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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,gBAAb,MAAyD;;;;;CAKxD,MAAM,SAA2C;EAChD,OAAO,KAAKA,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;;CAYA,MAAM,IAAY,SAA2C;EAC5D,OAAO,KAAKC,OAAO,IAAI,SAAS,MAAM;CACvC;CAUA,WAAW,QAAqC;EAC/C,IAAI,QAAQ,YAAY,MAAM,OAAO,QAAQ,OAAO,OAAO,MAAM;EACjE,OAAO,IAAI,SAAe,SAAS,WAAW;GAC7C,MAAM,SAAS,mBAAmB;IACjC,QAAQ,oBAAoB,SAAS,OAAO;IAC5C,QAAQ;GACT,CAAC;GACD,MAAM,UAAU,KAAKC,gBAAgB,KAAK,MAAM,QAAQ,QAAQ,MAAM;GACtE,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAC1D,CAAC;CACF;CAMA,OAAO,IAAY,QAAqC;EACvD,IAAI,QAAQ,YAAY,MAAM,OAAO,QAAQ,OAAO,OAAO,MAAM;EACjE,OAAO,IAAI,SAAe,SAAS,WAAW;GAC7C,MAAM,SAAS,iBAAiB;IAC/B,QAAQ,oBAAoB,SAAS,OAAO;IAC5C,QAAQ;GACT,GAAG,EAAE;GACL,MAAM,UAAU,KAAKC,cAAc,KAAK,MAAM,QAAQ,QAAQ,MAAM;GACpE,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAC1D,CAAC;CACF;CAEA,gBACC,QACA,QACA,QACO;EACP,eAAe,MAAM;EACrB,OAAO,QAAQ,MAAM;CACtB;CAEA,cACC,QACA,QACA,QACO;EACP,aAAa,MAAM;EACnB,OAAO,QAAQ,MAAM;CACtB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtFA,SAAgB,sBAA0C;CACzD,OAAO,IAAI,cAAc;AAC1B"}
1
+ {"version":3,"file":"index.js","names":["#immediate","#sleep"],"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,KAAKA,WAAW,SAAS,MAAM;CACvC;;;;;;;;;;;CAYA,MAAM,IAAY,SAA2C;EAC5D,OAAO,KAAKC,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkestrel/workflow",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
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",
@@ -87,23 +87,23 @@
87
87
  "dependencies": {
88
88
  "@orkestrel/abort": "^0.0.4",
89
89
  "@orkestrel/budget": "^0.0.4",
90
- "@orkestrel/contract": "^0.0.8",
91
- "@orkestrel/database": "^0.0.6",
92
- "@orkestrel/emitter": "^0.0.4",
93
- "@orkestrel/queue": "^0.0.4",
90
+ "@orkestrel/contract": "^0.0.9",
91
+ "@orkestrel/database": "^0.0.7",
92
+ "@orkestrel/emitter": "^0.0.5",
93
+ "@orkestrel/queue": "^0.0.7",
94
94
  "@orkestrel/timeout": "^0.0.4"
95
95
  },
96
96
  "devDependencies": {
97
97
  "@microsoft/api-extractor": "^7.58.12",
98
- "@orkestrel/guide": "^0.0.7",
99
- "@orkestrel/scaffold": "^0.0.7",
98
+ "@orkestrel/guide": "^0.0.8",
99
+ "@orkestrel/scaffold": "^0.0.16",
100
100
  "@types/node": "^26.1.2",
101
101
  "@vitest/browser-playwright": "^4.1.10",
102
102
  "oxfmt": "^0.61.0",
103
103
  "oxlint": "^1.76.0",
104
- "playwright": "^1.62.0",
104
+ "playwright": "^1.62.1",
105
105
  "typescript": "^6.0.3",
106
- "vite": "^8.1.5",
106
+ "vite": "^8.2.0",
107
107
  "vite-plugin-dts": "^5.0.3",
108
108
  "vitest": "^4.1.10"
109
109
  },