workflais 0.1.0

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 ADDED
@@ -0,0 +1,177 @@
1
+ # workflais
2
+
3
+ Declarative workflow primitives for [Cloudflare Workflows](https://developers.cloudflare.com/workflows/).
4
+
5
+ ```
6
+ npm install workflais
7
+ ```
8
+
9
+ ## Native CF Workflows vs workflais
10
+
11
+ | | Native CF Workflows | workflais |
12
+ |---|---|---|
13
+ | **Step definition** | `step.do("name", { retries: { limit: 3, delay: "10s", backoff: "exponential" }, timeout: "30s" }, async () => {...})` | `step("name", fn).retry(3).timeout("30s")` |
14
+ | **Result chaining** | Manual variables between steps | Automatic `ctx.prev` pipeline |
15
+ | **Saga compensation** | Manual implementation | `.compensate(fn)` with automatic LIFO rollback via `step.do("⟲ name")` |
16
+ | **Parallel execution** | Manual self-spawn + waitForEvent orchestration | `parallel(step1, step2, step3)` |
17
+ | **waitForEvent** | Imperative `step.waitForEvent()` call | `waitForEvent("name", opts)` in pipeline with `ctx.prev` |
18
+ | **Compile-time validation** | Runtime errors only | Duplicate step names, step count limits, timeout limits, event type validation |
19
+ | **Error types** | Generic errors | `NonRetryableError`, `TimeoutTooLongError`, `DuplicateStepNameError`, etc. |
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { step, compile, execute } from "workflais";
25
+ import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";
26
+ import type { WorkflowStep as WfStep, WorkflowEvent as WfEvent } from "workflais";
27
+
28
+ export class MyWorkflow extends WorkflowEntrypoint {
29
+ async run(event: WorkflowEvent, cfStep: WorkflowStep) {
30
+ const plan = compile([
31
+ step("fetch-data", async (ctx) => {
32
+ return { userId: ctx.event.payload.userId, name: "Alice" };
33
+ }),
34
+
35
+ step("process", async (ctx) => {
36
+ const data = ctx.prev; // automatic chaining
37
+ return { ...data, processed: true };
38
+ })
39
+ .retry(3, "1 minute")
40
+ .timeout("30 seconds"),
41
+
42
+ step("save", async (ctx) => {
43
+ return { ...ctx.prev, saved: true };
44
+ }).compensate(async () => {
45
+ // runs automatically on failure, wrapped in step.do for CF durability
46
+ }),
47
+ ]);
48
+
49
+ return execute(plan, cfStep as unknown as WfStep, event as unknown as WfEvent, this.env);
50
+ }
51
+ }
52
+ ```
53
+
54
+ ## API
55
+
56
+ ### DSL
57
+
58
+ ```typescript
59
+ step(name, fn) // durable step
60
+ .retry(limit, delay?) // retry config (default: exponential backoff)
61
+ .timeout(duration) // step timeout (max 30 min)
62
+ .compensate(fn) // saga rollback handler
63
+
64
+ parallel(step1, step2, ...) // fan-out/fan-in execution
65
+ waitForEvent(name, { type, timeout }) // pause for external event
66
+
67
+ compile(nodes) // validate + build execution plan
68
+ execute(plan, step, event, env) // run against CF Workflows runtime
69
+ ```
70
+
71
+ ### Context
72
+
73
+ Every step callback receives `ctx`:
74
+ - `ctx.prev` — previous step's return value (or `undefined` for the first step)
75
+ - `ctx.event` — workflow event (frozen, immutable)
76
+ - `ctx.env` — CF bindings
77
+
78
+ After `parallel()`, `ctx.prev` is a tuple of results in declaration order.
79
+
80
+ ## Examples
81
+
82
+ Each example is a deployable CF Workers project with `wrangler.toml`:
83
+
84
+ | Example | Pattern | Features |
85
+ |---|---|---|
86
+ | [`ecommerce-checkout`](examples/ecommerce-checkout/) | Cart → Payment → Invoice | Linear pipeline, retry, timeout |
87
+ | [`user-onboarding`](examples/user-onboarding/) | Account → Billing → Welcome | Saga compensation, LIFO rollback |
88
+ | [`image-tagging`](examples/image-tagging/) | Store → Approve → Tag → Save | Human-in-the-loop, waitForEvent |
89
+ | [`parallel-fan-out`](examples/parallel-fan-out/) | Validate → [Email, SMS, CRM] → Log | Parallel fan-out/fan-in |
90
+
91
+ ```bash
92
+ cd examples/ecommerce-checkout
93
+ npm install workflais
94
+ npx wrangler deploy
95
+ ```
96
+
97
+ ## Why Child Workflows? The Resource Isolation Problem
98
+
99
+ CF Workflows runs each instance inside a single Durable Object. A DO has hard limits:
100
+
101
+ | Resource | Limit |
102
+ |---|---|
103
+ | Memory | 128 MB per DO |
104
+ | CPU | 5 min per invocation |
105
+ | Retry budget | Shared across the entire instance |
106
+
107
+ If you run three heavy steps with `Promise.all` inside one DO, you get:
108
+
109
+ ```
110
+ ┌─ Single Durable Object (128 MB shared) ──────────────┐
111
+ │ Promise.all([ │
112
+ │ mlInference(), ← 80 MB ← 3 min CPU │
113
+ │ imageProcess(), ← 60 MB ← 2 min CPU │
114
+ │ videoTranscode(), ← 50 MB ← 4 min CPU │
115
+ │ ]) │
116
+ │ Total: 190 MB → OOM CRASH │
117
+ │ Total CPU: 9 min → TIMEOUT │
118
+ │ If imageProcess fails → all three die │
119
+ └───────────────────────────────────────────────────────┘
120
+ ```
121
+
122
+ **The problem is threefold:**
123
+
124
+ 1. **Memory** — All branches share 128 MB. Two 80 MB allocations = OOM crash, killing the entire workflow.
125
+ 2. **CPU** — All branches share 5 min. Three 2-minute tasks = timeout, even though each one is well under the limit.
126
+ 3. **Blast radius** — One branch throwing an unhandled error kills `Promise.all`, terminating siblings mid-execution. No partial results, no independent retry.
127
+
128
+ ### The Solution: Child Workflow Spawning
129
+
130
+ `parallel()` compiles to the self-spawn pattern — each branch becomes a **separate workflow instance** running in its **own DO**:
131
+
132
+ ```
133
+ Parent DO Child DO #1 Child DO #2 Child DO #3
134
+ ────────── ─────────── ─────────── ───────────
135
+ step.do("⊕ spawn") ─────────► 128 MB own memory 128 MB own memory 128 MB own memory
136
+ binding.create(child1) 5 min own CPU 5 min own CPU 5 min own CPU
137
+ binding.create(child2) own retry budget own retry budget own retry budget
138
+ binding.create(child3)
139
+ step.do("ml", fn) step.do("img", fn) step.do("vid", fn)
140
+ waitForEvent("ml:cb") ◄─ $0 ─ sendEvent(result)
141
+ waitForEvent("img:cb") ◄─ $0 ─ sendEvent(result)
142
+ waitForEvent("vid:cb") ◄─ $0 ─ sendEvent(result)
143
+
144
+ ctx.prev = [mlResult, imgResult, vidResult] // tuple in declaration order
145
+ ```
146
+
147
+ | | `Promise.all` (single DO) | `parallel()` (child DOs) |
148
+ |---|---|---|
149
+ | Memory | 128 MB shared | 128 MB **each** |
150
+ | CPU | 5 min shared | 5 min **each** |
151
+ | Retry | All-or-nothing | Per-branch |
152
+ | Failure | One kills all | Isolated |
153
+ | Parent cost while waiting | N/A | **$0** (hibernated) |
154
+
155
+ ```typescript
156
+ // workflais — each branch gets its own DO
157
+ parallel(
158
+ step("ml-inference", mlFn).retry(5, "exponential").timeout("25m"),
159
+ step("image-process", imgFn).retry(3).timeout("10m"),
160
+ step("video-transcode", vidFn).retry(2).timeout("20m"),
161
+ )
162
+ ```
163
+
164
+ The parent spawns all children in a single `step.do`, then **hibernates** via `waitForEvent`. Zero CPU, zero memory, zero cost. When all children report back, the parent wakes up with `ctx.prev = [result1, result2, result3]`.
165
+
166
+ If any branch fails after the parallel group completes, workflais runs `.compensate()` for **every** child in the group — each compensation wrapped in its own `step.do` for CF-durable retry.
167
+
168
+ ## How It Works
169
+
170
+ ```
171
+ step("a", fn).retry(3) → compile([...]) → execute(plan, cfStep, event, env)
172
+ DSL Validation CF step.do() / waitForEvent()
173
+ ```
174
+
175
+ 1. **DSL** — Declarative step definitions with chainable config
176
+ 2. **Compiler** — Validates names, limits, timeouts; builds execution plan
177
+ 3. **Runtime** — Translates plan into CF Workflows API calls with saga compensation
@@ -0,0 +1,12 @@
1
+ import type { FlowNode, ExecutionPlan } from "./types.js";
2
+ /**
3
+ * Compiles a flat array of FlowNodes into an ExecutionPlan.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Level assignment — sequential vs parallel grouping
7
+ * 2. Duplicate step name detection (CF cache-key collision prevention)
8
+ * 3. Step name validation (length, emptiness)
9
+ * 4. Step count limit check (CF max 1024)
10
+ */
11
+ export declare function compile(nodes: FlowNode[]): ExecutionPlan;
12
+ //# sourceMappingURL=compiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAER,aAAa,EAKd,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,aAAa,CAoExD"}
@@ -0,0 +1,177 @@
1
+ import { DuplicateStepNameError, StepNameTooLongError, EmptyStepNameError, StepLimitExceededError, TimeoutTooLongError, InvalidEventTypeError, } from "./types.js";
2
+ import { toStepNode } from "./dsl.js";
3
+ const MAX_STEP_NAME_LENGTH = 256;
4
+ const MAX_STEPS_PER_WORKFLOW = 1024;
5
+ const MAX_TIMEOUT_MINUTES = 30;
6
+ // Parallel overhead: 1 spawn step + N waitForEvent steps
7
+ const PARALLEL_OVERHEAD_STEPS = 1; // spawn step; waitForEvent per child added separately
8
+ /**
9
+ * Compiles a flat array of FlowNodes into an ExecutionPlan.
10
+ *
11
+ * Responsibilities:
12
+ * 1. Level assignment — sequential vs parallel grouping
13
+ * 2. Duplicate step name detection (CF cache-key collision prevention)
14
+ * 3. Step name validation (length, emptiness)
15
+ * 4. Step count limit check (CF max 1024)
16
+ */
17
+ export function compile(nodes) {
18
+ // Collect all step names for duplicate detection
19
+ const namePositions = new Map();
20
+ const allSteps = [];
21
+ let flatIndex = 0;
22
+ for (const node of nodes) {
23
+ if (node.type === "step") {
24
+ const stepNode = isChainable(node) ? toStepNode(node) : node;
25
+ validateStepName(stepNode.name);
26
+ checkDuplicate(stepNode.name, flatIndex, namePositions);
27
+ if (stepNode.timeoutConfig) {
28
+ validateTimeout(stepNode.timeoutConfig);
29
+ }
30
+ allSteps.push(stepNode);
31
+ flatIndex++;
32
+ }
33
+ else if (node.type === "parallel") {
34
+ for (const child of node.children) {
35
+ validateStepName(child.name);
36
+ checkDuplicate(child.name, flatIndex, namePositions);
37
+ if (child.timeoutConfig) {
38
+ validateTimeout(child.timeoutConfig);
39
+ }
40
+ allSteps.push(child);
41
+ flatIndex++;
42
+ }
43
+ }
44
+ else if (node.type === "waitForEvent") {
45
+ validateStepName(node.name);
46
+ checkDuplicate(node.name, flatIndex, namePositions);
47
+ validateEventType(node.eventType);
48
+ flatIndex++;
49
+ }
50
+ }
51
+ // Build levels
52
+ const levels = [];
53
+ for (const node of nodes) {
54
+ if (node.type === "step") {
55
+ const stepNode = isChainable(node) ? toStepNode(node) : node;
56
+ const level = {
57
+ type: "sequential",
58
+ node: stepNode,
59
+ };
60
+ levels.push(level);
61
+ }
62
+ else if (node.type === "parallel") {
63
+ const level = {
64
+ type: "parallel",
65
+ nodes: node.children,
66
+ };
67
+ levels.push(level);
68
+ }
69
+ else if (node.type === "waitForEvent") {
70
+ const level = {
71
+ type: "waitForEvent",
72
+ node,
73
+ };
74
+ levels.push(level);
75
+ }
76
+ }
77
+ // Calculate total CF step count
78
+ const stepCount = calculateStepCount(levels);
79
+ if (stepCount > MAX_STEPS_PER_WORKFLOW) {
80
+ throw new StepLimitExceededError(stepCount);
81
+ }
82
+ return { levels, stepCount };
83
+ }
84
+ function validateStepName(name) {
85
+ if (name === "") {
86
+ throw new EmptyStepNameError();
87
+ }
88
+ if (name.length > MAX_STEP_NAME_LENGTH) {
89
+ throw new StepNameTooLongError(name, name.length);
90
+ }
91
+ }
92
+ function checkDuplicate(name, index, namePositions) {
93
+ const existing = namePositions.get(name);
94
+ if (existing !== undefined) {
95
+ throw new DuplicateStepNameError(name, [existing, index]);
96
+ }
97
+ namePositions.set(name, index);
98
+ }
99
+ /**
100
+ * Calculates total CF step count including parallel overhead.
101
+ *
102
+ * Sequential level: 1 CF step
103
+ * Parallel level with N children: N children + 1 spawn + N waitForEvent = 2N + 1
104
+ *
105
+ * But since children run in separate workflows, they don't count
106
+ * against the PARENT's 1024 limit. The parent uses:
107
+ * - 1 spawn step.do
108
+ * - N waitForEvent calls
109
+ *
110
+ * We count conservatively: parent steps + child steps
111
+ * (each child is 1 step in its own workflow)
112
+ */
113
+ function calculateStepCount(levels) {
114
+ let count = 0;
115
+ for (const level of levels) {
116
+ if (level.type === "sequential") {
117
+ count += 1;
118
+ }
119
+ else if (level.type === "parallel") {
120
+ // Parallel: 1 spawn + N waitForEvents + N children (counted for total)
121
+ const n = level.nodes.length;
122
+ count += PARALLEL_OVERHEAD_STEPS + n + n; // spawn + waits + children
123
+ }
124
+ else if (level.type === "waitForEvent") {
125
+ count += 1;
126
+ }
127
+ }
128
+ return count;
129
+ }
130
+ /**
131
+ * Parses a CF duration string (e.g., "5m", "30 minutes", "1 hour") to minutes.
132
+ * Returns undefined if format is unrecognized.
133
+ */
134
+ function parseDurationToMinutes(duration) {
135
+ const trimmed = duration.trim().toLowerCase();
136
+ // Pattern: "30m", "5m", "1h"
137
+ const shortMatch = trimmed.match(/^(\d+(?:\.\d+)?)\s*(s|m|h)$/);
138
+ if (shortMatch) {
139
+ const value = parseFloat(shortMatch[1]);
140
+ const unit = shortMatch[2];
141
+ if (unit === "s")
142
+ return value / 60;
143
+ if (unit === "m")
144
+ return value;
145
+ if (unit === "h")
146
+ return value * 60;
147
+ }
148
+ // Pattern: "30 minutes", "1 hour", "5 seconds"
149
+ const longMatch = trimmed.match(/^(\d+(?:\.\d+)?)\s*(seconds?|minutes?|hours?)$/);
150
+ if (longMatch) {
151
+ const value = parseFloat(longMatch[1]);
152
+ const unit = longMatch[2];
153
+ if (unit.startsWith("second"))
154
+ return value / 60;
155
+ if (unit.startsWith("minute"))
156
+ return value;
157
+ if (unit.startsWith("hour"))
158
+ return value * 60;
159
+ }
160
+ return undefined;
161
+ }
162
+ const EVENT_TYPE_PATTERN = /^[a-zA-Z0-9_-]+$/;
163
+ function validateEventType(type) {
164
+ if (!EVENT_TYPE_PATTERN.test(type)) {
165
+ throw new InvalidEventTypeError(type);
166
+ }
167
+ }
168
+ function validateTimeout(duration) {
169
+ const minutes = parseDurationToMinutes(duration);
170
+ if (minutes !== undefined && minutes > MAX_TIMEOUT_MINUTES) {
171
+ throw new TimeoutTooLongError(duration);
172
+ }
173
+ }
174
+ function isChainable(node) {
175
+ return node.type === "step" && typeof node.retry === "function";
176
+ }
177
+ //# sourceMappingURL=compiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.js","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAsB,MAAM,UAAU,CAAC;AAE1D,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AACpC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAC/B,yDAAyD;AACzD,MAAM,uBAAuB,GAAG,CAAC,CAAC,CAAC,sDAAsD;AAEzF;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAC,KAAiB;IACvC,iDAAiD;IACjD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,MAAM,QAAQ,GAAe,EAAE,CAAC;IAChC,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7D,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAChC,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;YACxD,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAC3B,eAAe,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YAC1C,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACxB,SAAS,EAAE,CAAC;QACd,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACpC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC7B,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;gBACrD,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;oBACxB,eAAe,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBACvC,CAAC;gBACD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrB,SAAS,EAAE,CAAC;YACd,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACxC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;YACpD,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAClC,SAAS,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,eAAe;IACf,MAAM,MAAM,GAAY,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7D,MAAM,KAAK,GAAoB;gBAC7B,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACpC,MAAM,KAAK,GAAkB;gBAC3B,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,IAAI,CAAC,QAAQ;aACrB,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,KAAK,GAAmB;gBAC5B,IAAI,EAAE,cAAc;gBACpB,IAAI;aACL,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,MAAM,SAAS,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE7C,IAAI,SAAS,GAAG,sBAAsB,EAAE,CAAC;QACvC,MAAM,IAAI,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,kBAAkB,EAAE,CAAC;IACjC,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QACvC,MAAM,IAAI,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CACrB,IAAY,EACZ,KAAa,EACb,aAAkC;IAElC,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,sBAAsB,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,kBAAkB,CAAC,MAAe;IACzC,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACrC,uEAAuE;YACvE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC;YAC7B,KAAK,IAAI,uBAAuB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,2BAA2B;QACvE,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACzC,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE9C,6BAA6B;IAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAChE,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACpC,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,KAAK,CAAC;QAC/B,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;IACtC,CAAC;IAED,+CAA+C;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAC7B,gDAAgD,CACjD,CAAC;IACF,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;QACjD,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;QAC5C,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,GAAG,EAAE,CAAC;IACjD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAE9C,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB;IACvC,MAAM,OAAO,GAAG,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,GAAG,mBAAmB,EAAE,CAAC;QAC3D,MAAM,IAAI,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAc;IACjC,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,OAAQ,IAAsB,CAAC,KAAK,KAAK,UAAU,CAAC;AACrF,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { StepContext, WorkflowEvent } from "./types.js";
2
+ /**
3
+ * Creates a StepContext for step execution.
4
+ *
5
+ * CF Workflows rules enforced:
6
+ * - event is frozen/immutable (changes NOT persisted across steps)
7
+ * - prev carries the return value of the previous step
8
+ * - env provides access to CF bindings
9
+ */
10
+ export declare function createStepContext<TPrev = unknown>(prev: TPrev, event: WorkflowEvent, env: Record<string, unknown>): StepContext<TPrev>;
11
+ /**
12
+ * Assembles parallel results into a tuple (array in declaration order).
13
+ * Used after all parallel children complete to form ctx.prev for the next step.
14
+ */
15
+ export declare function propagateResult(results: unknown[]): unknown[];
16
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,GAAG,OAAO,EAC/C,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,WAAW,CAAC,KAAK,CAAC,CAMpB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAE7D"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Creates a StepContext for step execution.
3
+ *
4
+ * CF Workflows rules enforced:
5
+ * - event is frozen/immutable (changes NOT persisted across steps)
6
+ * - prev carries the return value of the previous step
7
+ * - env provides access to CF bindings
8
+ */
9
+ export function createStepContext(prev, event, env) {
10
+ return {
11
+ prev,
12
+ event,
13
+ env,
14
+ };
15
+ }
16
+ /**
17
+ * Assembles parallel results into a tuple (array in declaration order).
18
+ * Used after all parallel children complete to form ctx.prev for the next step.
19
+ */
20
+ export function propagateResult(results) {
21
+ return [...results];
22
+ }
23
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAW,EACX,KAAoB,EACpB,GAA4B;IAE5B,OAAO;QACL,IAAI;QACJ,KAAK;QACL,GAAG;KACJ,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAkB;IAChD,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC"}
package/dist/dsl.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { type StepNode, type ParallelNode, type WaitEventNode, type FlowNode, type StepFn, type CompensateFn, type WorkflowBackoff, type ErrorHandler, type WorkflowDefinition, type WorkflowEvent, type WorkflowStep } from "./types.js";
2
+ export interface ChainableStep extends StepNode {
3
+ retry(limit: number, backoff?: WorkflowBackoff | string): ChainableStep;
4
+ compensate(fn: CompensateFn): ChainableStep;
5
+ timeout(duration: string): ChainableStep;
6
+ schema(input?: unknown, output?: unknown): ChainableStep;
7
+ }
8
+ /** Extract plain StepNode data from a ChainableStep (strip methods) */
9
+ export declare function toStepNode(s: ChainableStep): StepNode;
10
+ export declare function step(name: string, fn: StepFn): ChainableStep;
11
+ export declare function parallel(...steps: ChainableStep[]): ParallelNode;
12
+ export declare function waitForEvent(name: string, options: {
13
+ type: string;
14
+ timeout: string;
15
+ }): WaitEventNode;
16
+ export interface ChainableWorkflow extends WorkflowDefinition {
17
+ run(event: WorkflowEvent, step: WorkflowStep): Promise<unknown>;
18
+ onError(handler: ErrorHandler): ChainableWorkflow;
19
+ }
20
+ export declare function workflow(...nodes: FlowNode[]): ChainableWorkflow;
21
+ //# sourceMappingURL=dsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsl.d.ts","sourceRoot":"","sources":["../src/dsl.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,YAAY,EAGjB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,GAAG,aAAa,CAAC;IACxE,UAAU,CAAC,EAAE,EAAE,YAAY,GAAG,aAAa,CAAC;IAC5C,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAAC;IACzC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,aAAa,CAAC;CAC1D;AA6DD,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,CAAC,EAAE,aAAa,GAAG,QAAQ,CAUrD;AAID,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,CAU5D;AAED,wBAAgB,QAAQ,CAAC,GAAG,KAAK,EAAE,aAAa,EAAE,GAAG,YAAY,CAKhE;AAED,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACzC,aAAa,CAOf;AAID,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,GAAG,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChE,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,iBAAiB,CAAC;CACnD;AAED,wBAAgB,QAAQ,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CAMhE"}
package/dist/dsl.js ADDED
@@ -0,0 +1,107 @@
1
+ import { EmptyWorkflowError, } from "./types.js";
2
+ function createChainableStep(data) {
3
+ const chainable = {
4
+ // Data properties
5
+ type: data.type,
6
+ name: data.name,
7
+ fn: data.fn,
8
+ retryConfig: data.retryConfig,
9
+ compensateFn: data.compensateFn,
10
+ timeoutConfig: data.timeoutConfig,
11
+ schemaConfig: data.schemaConfig,
12
+ // Chainable methods — each returns a NEW ChainableStep
13
+ retry(limit, backoff) {
14
+ let retry;
15
+ if (backoff === undefined ||
16
+ backoff === "exponential" ||
17
+ backoff === "linear" ||
18
+ backoff === "constant") {
19
+ // CF requires delay when retries is provided — default to 10 seconds
20
+ retry = {
21
+ limit,
22
+ delay: "10 seconds",
23
+ backoff: (backoff ?? "exponential"),
24
+ };
25
+ }
26
+ else {
27
+ // String duration like "2s" → constant backoff with fixed delay
28
+ retry = {
29
+ limit,
30
+ delay: backoff,
31
+ backoff: "constant",
32
+ };
33
+ }
34
+ return createChainableStep({ ...toStepNode(chainable), retryConfig: retry });
35
+ },
36
+ compensate(fn) {
37
+ return createChainableStep({ ...toStepNode(chainable), compensateFn: fn });
38
+ },
39
+ timeout(duration) {
40
+ return createChainableStep({ ...toStepNode(chainable), timeoutConfig: duration });
41
+ },
42
+ schema(input, output) {
43
+ const schema = { input, output };
44
+ return createChainableStep({ ...toStepNode(chainable), schemaConfig: schema });
45
+ },
46
+ };
47
+ return chainable;
48
+ }
49
+ /** Extract plain StepNode data from a ChainableStep (strip methods) */
50
+ export function toStepNode(s) {
51
+ return {
52
+ type: s.type,
53
+ name: s.name,
54
+ fn: s.fn,
55
+ retryConfig: s.retryConfig,
56
+ compensateFn: s.compensateFn,
57
+ timeoutConfig: s.timeoutConfig,
58
+ schemaConfig: s.schemaConfig,
59
+ };
60
+ }
61
+ // ─── Public DSL API ──────────────────────────────────────────────────────────
62
+ export function step(name, fn) {
63
+ return createChainableStep({
64
+ type: "step",
65
+ name,
66
+ fn,
67
+ retryConfig: null,
68
+ compensateFn: null,
69
+ timeoutConfig: null,
70
+ schemaConfig: null,
71
+ });
72
+ }
73
+ export function parallel(...steps) {
74
+ return {
75
+ type: "parallel",
76
+ children: steps.map((s) => toStepNode(s)),
77
+ };
78
+ }
79
+ export function waitForEvent(name, options) {
80
+ return {
81
+ type: "waitForEvent",
82
+ name,
83
+ eventType: options.type,
84
+ timeout: options.timeout,
85
+ };
86
+ }
87
+ export function workflow(...nodes) {
88
+ if (nodes.length === 0) {
89
+ throw new EmptyWorkflowError();
90
+ }
91
+ return createChainableWorkflow(nodes, null);
92
+ }
93
+ function createChainableWorkflow(nodes, errorHandler) {
94
+ const definition = {
95
+ nodes,
96
+ errorHandler,
97
+ async run(_event, _step) {
98
+ // Runtime engine will handle this — placeholder for now
99
+ return undefined;
100
+ },
101
+ onError(handler) {
102
+ return createChainableWorkflow([...nodes], handler);
103
+ },
104
+ };
105
+ return definition;
106
+ }
107
+ //# sourceMappingURL=dsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsl.js","sourceRoot":"","sources":["../src/dsl.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAcnB,MAAM,YAAY,CAAC;AAcpB,SAAS,mBAAmB,CAAC,IAAc;IACzC,MAAM,SAAS,GAAkB;QAC/B,kBAAkB;QAClB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,YAAY,EAAE,IAAI,CAAC,YAAY;QAE/B,uDAAuD;QACvD,KAAK,CACH,KAAa,EACb,OAAkC;YAElC,IAAI,KAAkB,CAAC;YAEvB,IACE,OAAO,KAAK,SAAS;gBACrB,OAAO,KAAK,aAAa;gBACzB,OAAO,KAAK,QAAQ;gBACpB,OAAO,KAAK,UAAU,EACtB,CAAC;gBACD,qEAAqE;gBACrE,KAAK,GAAG;oBACN,KAAK;oBACL,KAAK,EAAE,YAAY;oBACnB,OAAO,EAAE,CAAC,OAAO,IAAI,aAAa,CAAoB;iBACvD,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,gEAAgE;gBAChE,KAAK,GAAG;oBACN,KAAK;oBACL,KAAK,EAAE,OAAO;oBACd,OAAO,EAAE,UAAU;iBACpB,CAAC;YACJ,CAAC;YAED,OAAO,mBAAmB,CAAC,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,UAAU,CAAC,EAAgB;YACzB,OAAO,mBAAmB,CAAC,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7E,CAAC;QAED,OAAO,CAAC,QAAgB;YACtB,OAAO,mBAAmB,CAAC,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpF,CAAC;QAED,MAAM,CAAC,KAAe,EAAE,MAAgB;YACtC,MAAM,MAAM,GAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;YAC/C,OAAO,mBAAmB,CAAC,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;QACjF,CAAC;KACF,CAAC;IAEF,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,CAAgB;IACzC,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,YAAY,EAAE,CAAC,CAAC,YAAY;KAC7B,CAAC;AACJ,CAAC;AAED,gFAAgF;AAEhF,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,EAAU;IAC3C,OAAO,mBAAmB,CAAC;QACzB,IAAI,EAAE,MAAM;QACZ,IAAI;QACJ,EAAE;QACF,WAAW,EAAE,IAAI;QACjB,YAAY,EAAE,IAAI;QAClB,aAAa,EAAE,IAAI;QACnB,YAAY,EAAE,IAAI;KACnB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAG,KAAsB;IAChD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,OAA0C;IAE1C,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,IAAI;QACJ,SAAS,EAAE,OAAO,CAAC,IAAI;QACvB,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,QAAQ,CAAC,GAAG,KAAiB;IAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,kBAAkB,EAAE,CAAC;IACjC,CAAC;IAED,OAAO,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAiB,EACjB,YAAiC;IAEjC,MAAM,UAAU,GAAsB;QACpC,KAAK;QACL,YAAY;QAEZ,KAAK,CAAC,GAAG,CAAC,MAAqB,EAAE,KAAmB;YAClD,wDAAwD;YACxD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,CAAC,OAAqB;YAC3B,OAAO,uBAAuB,CAAC,CAAC,GAAG,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QACtD,CAAC;KACF,CAAC;IAEF,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { step, parallel, workflow, toStepNode, waitForEvent } from "./dsl.js";
2
+ export { compile } from "./compiler.js";
3
+ export { execute } from "./runtime.js";
4
+ export { createStepContext, propagateResult } from "./context.js";
5
+ export { createCompensationStack } from "./saga.js";
6
+ export type { StepNode, ParallelNode, WaitEventNode, FlowNode, StepFn, CompensateFn, RetryConfig, SchemaConfig, WorkflowBackoff, WorkflowStepConfig, WorkflowEvent, WorkflowStep, WorkflowInstance, InstanceStatus, WorkflowBinding, WorkflowInstanceCreateOptions, ExecutionPlan, Level, SequentialLevel, ParallelLevel, WaitEventLevel, StepContext, CompletedStep, ErrorHandler, WorkflowDefinition, ChildPayload, } from "./types.js";
7
+ export { isChildPayload } from "./types.js";
8
+ export { DuplicateStepNameError, StepNameTooLongError, InvalidEventTypeError, EmptyWorkflowError, StepLimitExceededError, CircularDependencyError, EmptyStepNameError, NonRetryableError, TimeoutTooLongError, } from "./types.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AAEpD,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,6BAA6B,EAC7B,aAAa,EACb,KAAK,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { step, parallel, workflow, toStepNode, waitForEvent } from "./dsl.js";
2
+ export { compile } from "./compiler.js";
3
+ export { execute } from "./runtime.js";
4
+ export { createStepContext, propagateResult } from "./context.js";
5
+ export { createCompensationStack } from "./saga.js";
6
+ export { isChildPayload } from "./types.js";
7
+ export { DuplicateStepNameError, StepNameTooLongError, InvalidEventTypeError, EmptyWorkflowError, StepLimitExceededError, CircularDependencyError, EmptyStepNameError, NonRetryableError, TimeoutTooLongError, } from "./types.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AA+BpD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { ExecutionPlan, WorkflowEvent, WorkflowStep, ErrorHandler } from "./types.js";
2
+ export interface ExecuteOptions {
3
+ onError?: ErrorHandler;
4
+ /** Workflow binding name in env (default: "WORKFLOW") */
5
+ bindingName?: string;
6
+ }
7
+ /**
8
+ * Executes an ExecutionPlan by translating it into CF Workflows API calls.
9
+ *
10
+ * Two modes:
11
+ * 1. **Parent mode** (default): Iterates levels sequentially.
12
+ * - Sequential: calls step.do
13
+ * - Parallel: spawns child workflows (separate DOs), hibernates with waitForEvent
14
+ * - WaitForEvent: calls step.waitForEvent
15
+ *
16
+ * 2. **Child mode** (detected via `__workflais` in event.payload):
17
+ * Runs a single step from the plan, then sends result back to parent via sendEvent.
18
+ * Each child runs in its own DO — isolated 128MB memory, separate CPU budget,
19
+ * per-branch retry, isolated failure. Parent pays $0 while hibernated.
20
+ *
21
+ * Maintains a compensation stack for saga rollback on failure.
22
+ */
23
+ export declare function execute(plan: ExecutionPlan, cfStep: WorkflowStep, event: WorkflowEvent, env: Record<string, unknown>, options?: ExecuteOptions): Promise<unknown>;
24
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EAGb,aAAa,EACb,YAAY,EAGZ,YAAY,EACb,MAAM,YAAY,CAAC;AAOpB,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAQlB"}
@@ -0,0 +1,222 @@
1
+ import { isChildPayload } from "./types.js";
2
+ import { createStepContext } from "./context.js";
3
+ import { createCompensationStack } from "./saga.js";
4
+ /**
5
+ * Executes an ExecutionPlan by translating it into CF Workflows API calls.
6
+ *
7
+ * Two modes:
8
+ * 1. **Parent mode** (default): Iterates levels sequentially.
9
+ * - Sequential: calls step.do
10
+ * - Parallel: spawns child workflows (separate DOs), hibernates with waitForEvent
11
+ * - WaitForEvent: calls step.waitForEvent
12
+ *
13
+ * 2. **Child mode** (detected via `__workflais` in event.payload):
14
+ * Runs a single step from the plan, then sends result back to parent via sendEvent.
15
+ * Each child runs in its own DO — isolated 128MB memory, separate CPU budget,
16
+ * per-branch retry, isolated failure. Parent pays $0 while hibernated.
17
+ *
18
+ * Maintains a compensation stack for saga rollback on failure.
19
+ */
20
+ export async function execute(plan, cfStep, event, env, options) {
21
+ // ─── Child mode: __workflais payload detected ────────────────────────
22
+ if (isChildPayload(event.payload)) {
23
+ return executeChildMode(plan, cfStep, event, env, options);
24
+ }
25
+ // ─── Parent mode: normal execution ───────────────────────────────────
26
+ return executeParentMode(plan, cfStep, event, env, options);
27
+ }
28
+ /**
29
+ * Child mode: runs a single step and sends result back to parent.
30
+ *
31
+ * Each child workflow instance runs in its own Durable Object:
32
+ * - 128 MB memory (not shared with parent)
33
+ * - Separate CPU budget
34
+ * - Per-branch retry (isolated from siblings)
35
+ * - Isolated failure blast radius
36
+ */
37
+ async function executeChildMode(plan, cfStep, event, env, options) {
38
+ const childPayload = event.payload;
39
+ if (!isChildPayload(childPayload)) {
40
+ throw new Error("executeChildMode called without __workflais payload");
41
+ }
42
+ const { stepName, input, callbackId, parentInstanceId } = childPayload;
43
+ const bindingName = options?.bindingName ?? "WORKFLOW";
44
+ // Find the step in the plan
45
+ const stepNode = findStepInPlan(plan, stepName);
46
+ if (!stepNode) {
47
+ throw new Error(`Child workflow: step "${stepName}" not found in execution plan`);
48
+ }
49
+ // Create context with the input from parent as prev
50
+ const ctx = createStepContext(input, event, env);
51
+ const config = buildStepConfig(stepNode);
52
+ // Execute the single step
53
+ let result;
54
+ if (config) {
55
+ result = await cfStep.do(stepName, config, async () => {
56
+ return await stepNode.fn(ctx);
57
+ });
58
+ }
59
+ else {
60
+ result = await cfStep.do(stepName, async () => {
61
+ return await stepNode.fn(ctx);
62
+ });
63
+ }
64
+ // Send result back to parent via sendEvent
65
+ const binding = env[bindingName];
66
+ if (binding) {
67
+ const parentInstance = await binding.get(parentInstanceId);
68
+ await parentInstance.sendEvent({
69
+ type: callbackId,
70
+ payload: result,
71
+ });
72
+ }
73
+ return result;
74
+ }
75
+ async function executeParentMode(plan, cfStep, event, env, options) {
76
+ const compensationStack = createCompensationStack();
77
+ let prev = undefined;
78
+ try {
79
+ for (const level of plan.levels) {
80
+ if (level.type === "sequential") {
81
+ prev = await executeSequentialLevel(level.node, cfStep, event, env, prev, compensationStack);
82
+ }
83
+ else if (level.type === "parallel") {
84
+ prev = await executeParallelLevel(level.nodes, cfStep, event, env, prev, options);
85
+ // Push all parallel children onto compensation stack
86
+ for (const node of level.nodes) {
87
+ compensationStack.push(node.name, node.compensateFn);
88
+ }
89
+ }
90
+ else if (level.type === "waitForEvent") {
91
+ prev = await cfStep.waitForEvent(level.node.name, {
92
+ type: level.node.eventType,
93
+ timeout: level.node.timeout,
94
+ });
95
+ }
96
+ }
97
+ return prev;
98
+ }
99
+ catch (error) {
100
+ // Call onError handler BEFORE compensation (per PRD spec)
101
+ if (options?.onError) {
102
+ const ctx = createStepContext(prev, event, env);
103
+ await options.onError(error, ctx);
104
+ }
105
+ // Run saga compensation
106
+ await compensationStack.compensate(cfStep, event, env);
107
+ // Re-throw original error
108
+ throw error;
109
+ }
110
+ }
111
+ async function executeSequentialLevel(node, cfStep, event, env, prev, compensationStack) {
112
+ const ctx = createStepContext(prev, event, env);
113
+ const config = buildStepConfig(node);
114
+ let result;
115
+ if (config) {
116
+ result = await cfStep.do(node.name, config, async () => {
117
+ return await node.fn(ctx);
118
+ });
119
+ }
120
+ else {
121
+ result = await cfStep.do(node.name, async () => {
122
+ return await node.fn(ctx);
123
+ });
124
+ }
125
+ // Push onto compensation stack after successful execution
126
+ compensationStack.push(node.name, node.compensateFn);
127
+ return result;
128
+ }
129
+ /**
130
+ * Parallel level execution via self-spawn pattern.
131
+ *
132
+ * 1. Parent spawns N child workflows via env.BINDING.create()
133
+ * - Each child gets __workflais payload with stepName, input, callbackId
134
+ * - Each child runs in its own DO (128MB, separate CPU, isolated retry)
135
+ *
136
+ * 2. Parent HIBERNATES via step.waitForEvent() for each child
137
+ * - 0 CPU, 0 memory, $0 cost while waiting
138
+ *
139
+ * 3. Children send results back via env.BINDING.sendEvent()
140
+ *
141
+ * 4. Parent assembles results as tuple in declaration order
142
+ */
143
+ async function executeParallelLevel(nodes, cfStep, event, env, prev, options) {
144
+ const childNames = nodes.map((n) => n.name);
145
+ const spawnStepName = `⊕ spawn:${childNames.join(",")}`;
146
+ const bindingName = options?.bindingName ?? "WORKFLOW";
147
+ const parentInstanceId = event.instanceId;
148
+ // Step 1: Spawn child workflows — each in its own DO
149
+ await cfStep.do(spawnStepName, async () => {
150
+ const binding = env[bindingName];
151
+ if (!binding) {
152
+ throw new Error(`Workflow binding "${bindingName}" not found in env. ` +
153
+ `Parallel execution requires the workflow's own binding. ` +
154
+ `Add it to wrangler.toml and pass bindingName in ExecuteOptions if not "WORKFLOW".`);
155
+ }
156
+ for (const node of nodes) {
157
+ await binding.create({
158
+ params: {
159
+ __workflais: true,
160
+ stepName: node.name,
161
+ input: prev,
162
+ callbackId: `${node.name}:callback`,
163
+ parentInstanceId,
164
+ },
165
+ });
166
+ }
167
+ });
168
+ // Step 2: Parent HIBERNATES — $0 cost, 0 cpu, 0 mem
169
+ // waitForEvent releases the DO. Parent only wakes when child sends event.
170
+ const results = [];
171
+ for (const node of nodes) {
172
+ const callbackType = `${node.name}:callback`;
173
+ const result = await cfStep.waitForEvent(`wait:${node.name}`, { type: callbackType, timeout: "30 minutes" });
174
+ // Extract payload from the event envelope
175
+ const payload = result?.payload ?? result;
176
+ results.push(payload);
177
+ }
178
+ return results;
179
+ }
180
+ /**
181
+ * Finds a step node by name in the execution plan.
182
+ * Used by child mode to locate the step it should execute.
183
+ */
184
+ function findStepInPlan(plan, stepName) {
185
+ for (const level of plan.levels) {
186
+ if (level.type === "sequential" && level.node.name === stepName) {
187
+ return level.node;
188
+ }
189
+ if (level.type === "parallel") {
190
+ const found = level.nodes.find((n) => n.name === stepName);
191
+ if (found)
192
+ return found;
193
+ }
194
+ }
195
+ return undefined;
196
+ }
197
+ /**
198
+ * Translates workflais retry/timeout config into CF WorkflowStepConfig.
199
+ * Returns undefined if no config is needed (cleaner CF API call).
200
+ */
201
+ function buildStepConfig(node) {
202
+ const hasRetry = node.retryConfig !== null;
203
+ const hasTimeout = node.timeoutConfig !== null;
204
+ if (!hasRetry && !hasTimeout) {
205
+ return undefined;
206
+ }
207
+ const config = {};
208
+ if (hasRetry) {
209
+ config.retries = {
210
+ limit: node.retryConfig.limit,
211
+ delay: node.retryConfig.delay,
212
+ ...(node.retryConfig.backoff !== undefined && {
213
+ backoff: node.retryConfig.backoff,
214
+ }),
215
+ };
216
+ }
217
+ if (hasTimeout) {
218
+ config.timeout = node.timeoutConfig;
219
+ }
220
+ return config;
221
+ }
222
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
package/dist/saga.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { CompensateFn, WorkflowEvent, WorkflowStep } from "./types.js";
2
+ export interface CompensationStack {
3
+ push(name: string, compensateFn: CompensateFn | null): void;
4
+ size(): number;
5
+ isEmpty(): boolean;
6
+ /**
7
+ * Executes compensations in LIFO order.
8
+ * Each compensation is wrapped in step.do for CF durability.
9
+ * Steps without compensateFn are skipped.
10
+ */
11
+ compensate(cfStep: WorkflowStep, event: WorkflowEvent, env: Record<string, unknown>): Promise<void>;
12
+ }
13
+ export declare function createCompensationStack(): CompensationStack;
14
+ //# sourceMappingURL=saga.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saga.d.ts","sourceRoot":"","sources":["../src/saga.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EAEZ,aAAa,EACb,YAAY,EACb,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,IAAI,IAAI,MAAM,CAAC;IACf,OAAO,IAAI,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CACR,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAuC3D"}
package/dist/saga.js ADDED
@@ -0,0 +1,31 @@
1
+ import { createStepContext } from "./context.js";
2
+ export function createCompensationStack() {
3
+ const stack = [];
4
+ return {
5
+ push(name, compensateFn) {
6
+ stack.push({ name, compensateFn });
7
+ },
8
+ size() {
9
+ return stack.length;
10
+ },
11
+ isEmpty() {
12
+ return stack.length === 0;
13
+ },
14
+ async compensate(cfStep, event, env) {
15
+ // LIFO order — pop from the end
16
+ for (let i = stack.length - 1; i >= 0; i--) {
17
+ const { name, compensateFn } = stack[i];
18
+ if (compensateFn === null) {
19
+ continue;
20
+ }
21
+ // Wrap in step.do for durable execution.
22
+ // CF Workflows will automatically retry failed compensations.
23
+ const ctx = createStepContext(undefined, event, env);
24
+ await cfStep.do(`⟲ ${name}`, async () => {
25
+ await compensateFn(ctx);
26
+ });
27
+ }
28
+ },
29
+ };
30
+ }
31
+ //# sourceMappingURL=saga.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"saga.js","sourceRoot":"","sources":["../src/saga.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAkBjD,MAAM,UAAU,uBAAuB;IACrC,MAAM,KAAK,GAAoB,EAAE,CAAC;IAElC,OAAO;QACL,IAAI,CAAC,IAAY,EAAE,YAAiC;YAClD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;QACrC,CAAC;QAED,IAAI;YACF,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC;QAED,OAAO;YACL,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,CAAC,UAAU,CACd,MAAoB,EACpB,KAAoB,EACpB,GAA4B;YAE5B,gCAAgC;YAChC,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAExC,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;oBAC1B,SAAS;gBACX,CAAC;gBAED,yCAAyC;gBACzC,8DAA8D;gBAC9D,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;gBAErD,MAAM,MAAM,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,IAAI,EAAE;oBACtC,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,166 @@
1
+ export type WorkflowBackoff = "constant" | "linear" | "exponential";
2
+ export interface WorkflowStepConfig {
3
+ retries?: {
4
+ limit: number;
5
+ delay: string | number;
6
+ backoff?: WorkflowBackoff;
7
+ };
8
+ timeout?: string | number;
9
+ }
10
+ export interface WorkflowEvent<T = unknown> {
11
+ payload: Readonly<T>;
12
+ timestamp: Date;
13
+ instanceId: string;
14
+ }
15
+ export interface WorkflowStep {
16
+ do<T>(name: string, callback: () => Promise<T> | T): Promise<T>;
17
+ do<T>(name: string, config: WorkflowStepConfig, callback: () => Promise<T> | T): Promise<T>;
18
+ sleep(name: string, duration: string | number): Promise<void>;
19
+ sleepUntil(name: string, timestamp: Date | number): Promise<void>;
20
+ waitForEvent<T = unknown>(name: string, options: {
21
+ type: string;
22
+ timeout: string;
23
+ }): Promise<T>;
24
+ }
25
+ export interface WorkflowInstance {
26
+ id: string;
27
+ pause(): Promise<void>;
28
+ resume(): Promise<void>;
29
+ terminate(): Promise<void>;
30
+ restart(): Promise<void>;
31
+ status(): Promise<InstanceStatus>;
32
+ sendEvent(event: {
33
+ type: string;
34
+ payload?: unknown;
35
+ }): Promise<void>;
36
+ }
37
+ export interface InstanceStatus {
38
+ status: "queued" | "running" | "paused" | "errored" | "terminated" | "complete" | "waiting" | "waitingForPause" | "unknown";
39
+ error?: {
40
+ name: string;
41
+ message: string;
42
+ };
43
+ output?: unknown;
44
+ }
45
+ export interface WorkflowInstanceCreateOptions {
46
+ id?: string;
47
+ params?: unknown;
48
+ }
49
+ export interface WorkflowBinding {
50
+ create(options?: WorkflowInstanceCreateOptions): Promise<WorkflowInstance>;
51
+ createBatch(batch: WorkflowInstanceCreateOptions[]): Promise<WorkflowInstance[]>;
52
+ get(id: string): Promise<WorkflowInstance>;
53
+ }
54
+ export type StepFn<TIn = unknown, TOut = unknown> = (ctx: StepContext<TIn>) => Promise<TOut> | TOut;
55
+ export type CompensateFn = (ctx: StepContext) => Promise<void> | void;
56
+ export interface RetryConfig {
57
+ limit: number;
58
+ delay: string | number;
59
+ backoff?: WorkflowBackoff;
60
+ }
61
+ export interface SchemaConfig {
62
+ input?: unknown;
63
+ output?: unknown;
64
+ }
65
+ /**
66
+ * Plain data structure representing a workflow step.
67
+ *
68
+ * Data property names (retryConfig, compensateFn, timeoutConfig, schemaConfig)
69
+ * are intentionally different from the chainable method names (retry, compensate,
70
+ * timeout, schema) to avoid JavaScript property conflicts.
71
+ */
72
+ export interface StepNode {
73
+ readonly type: "step";
74
+ readonly name: string;
75
+ readonly fn: StepFn;
76
+ readonly retryConfig: RetryConfig | null;
77
+ readonly compensateFn: CompensateFn | null;
78
+ readonly timeoutConfig: string | null;
79
+ readonly schemaConfig: SchemaConfig | null;
80
+ }
81
+ export interface ParallelNode {
82
+ readonly type: "parallel";
83
+ readonly children: ReadonlyArray<StepNode>;
84
+ }
85
+ export interface WaitEventNode {
86
+ readonly type: "waitForEvent";
87
+ readonly name: string;
88
+ readonly eventType: string;
89
+ readonly timeout: string;
90
+ }
91
+ export type FlowNode = StepNode | ParallelNode | WaitEventNode;
92
+ export interface SequentialLevel {
93
+ readonly type: "sequential";
94
+ readonly node: StepNode;
95
+ }
96
+ export interface ParallelLevel {
97
+ readonly type: "parallel";
98
+ readonly nodes: ReadonlyArray<StepNode>;
99
+ }
100
+ export interface WaitEventLevel {
101
+ readonly type: "waitForEvent";
102
+ readonly node: WaitEventNode;
103
+ }
104
+ export type Level = SequentialLevel | ParallelLevel | WaitEventLevel;
105
+ export interface ExecutionPlan {
106
+ readonly levels: ReadonlyArray<Level>;
107
+ readonly stepCount: number;
108
+ }
109
+ export interface StepContext<TPrev = unknown> {
110
+ readonly prev: TPrev;
111
+ readonly event: WorkflowEvent;
112
+ readonly env: Record<string, unknown>;
113
+ }
114
+ export interface CompletedStep {
115
+ readonly name: string;
116
+ readonly compensateFn: CompensateFn | null;
117
+ }
118
+ export declare class DuplicateStepNameError extends Error {
119
+ readonly stepName: string;
120
+ readonly positions: [number, number];
121
+ constructor(stepName: string, positions: [number, number]);
122
+ }
123
+ export declare class StepNameTooLongError extends Error {
124
+ readonly stepName: string;
125
+ readonly length: number;
126
+ constructor(stepName: string, length: number);
127
+ }
128
+ export declare class InvalidEventTypeError extends Error {
129
+ readonly eventType: string;
130
+ constructor(eventType: string);
131
+ }
132
+ export declare class EmptyWorkflowError extends Error {
133
+ constructor();
134
+ }
135
+ export declare class StepLimitExceededError extends Error {
136
+ readonly count: number;
137
+ constructor(count: number);
138
+ }
139
+ export declare class CircularDependencyError extends Error {
140
+ readonly cycle: string[];
141
+ constructor(cycle: string[]);
142
+ }
143
+ export declare class EmptyStepNameError extends Error {
144
+ constructor();
145
+ }
146
+ export declare class NonRetryableError extends Error {
147
+ constructor(message: string, name?: string);
148
+ }
149
+ export declare class TimeoutTooLongError extends Error {
150
+ readonly duration: string;
151
+ constructor(duration: string);
152
+ }
153
+ export interface ChildPayload {
154
+ readonly __workflais: true;
155
+ readonly stepName: string;
156
+ readonly input: unknown;
157
+ readonly callbackId: string;
158
+ readonly parentInstanceId: string;
159
+ }
160
+ export declare function isChildPayload(payload: unknown): payload is ChildPayload;
161
+ export type ErrorHandler = (error: Error, ctx: StepContext) => Promise<void> | void;
162
+ export interface WorkflowDefinition {
163
+ readonly nodes: ReadonlyArray<FlowNode>;
164
+ readonly errorHandler: ErrorHandler | null;
165
+ }
166
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,86 @@
1
+ // ─── CF Workflows Type Mirrors ───────────────────────────────────────────────
2
+ // These mirror the actual CF types from 'cloudflare:workers' / 'cloudflare:workflows'
3
+ // so we can work without installing the CF types package in dev.
4
+ // ─── Error Types ─────────────────────────────────────────────────────────────
5
+ export class DuplicateStepNameError extends Error {
6
+ stepName;
7
+ positions;
8
+ constructor(stepName, positions) {
9
+ super(`Duplicate step name "${stepName}" at positions ${positions[0]} and ${positions[1]}. ` +
10
+ `CF Workflows uses step names as cache keys — duplicates will return stale cached results.`);
11
+ this.stepName = stepName;
12
+ this.positions = positions;
13
+ this.name = "DuplicateStepNameError";
14
+ }
15
+ }
16
+ export class StepNameTooLongError extends Error {
17
+ stepName;
18
+ length;
19
+ constructor(stepName, length) {
20
+ super(`Step name "${stepName.slice(0, 50)}..." is ${length} characters. ` +
21
+ `CF Workflows allows max 256 characters per step name.`);
22
+ this.stepName = stepName;
23
+ this.length = length;
24
+ this.name = "StepNameTooLongError";
25
+ }
26
+ }
27
+ export class InvalidEventTypeError extends Error {
28
+ eventType;
29
+ constructor(eventType) {
30
+ super(`Event type "${eventType}" contains invalid characters. ` +
31
+ `CF Workflows waitForEvent type only supports [a-zA-Z0-9_-]. Dots (.) are NOT allowed.`);
32
+ this.eventType = eventType;
33
+ this.name = "InvalidEventTypeError";
34
+ }
35
+ }
36
+ export class EmptyWorkflowError extends Error {
37
+ constructor() {
38
+ super("Workflow must contain at least one step.");
39
+ this.name = "EmptyWorkflowError";
40
+ }
41
+ }
42
+ export class StepLimitExceededError extends Error {
43
+ count;
44
+ constructor(count) {
45
+ super(`Workflow has ${count} steps, exceeding CF Workflows limit of 1024 steps per workflow. ` +
46
+ `Note: step.sleep and step.sleepUntil do NOT count towards this limit.`);
47
+ this.count = count;
48
+ this.name = "StepLimitExceededError";
49
+ }
50
+ }
51
+ export class CircularDependencyError extends Error {
52
+ cycle;
53
+ constructor(cycle) {
54
+ super(`Circular dependency detected: ${cycle.join(" → ")}. ` +
55
+ `Workflow steps cannot form cycles.`);
56
+ this.cycle = cycle;
57
+ this.name = "CircularDependencyError";
58
+ }
59
+ }
60
+ export class EmptyStepNameError extends Error {
61
+ constructor() {
62
+ super("Step name cannot be empty. CF Workflows uses step names as cache keys.");
63
+ this.name = "EmptyStepNameError";
64
+ }
65
+ }
66
+ export class NonRetryableError extends Error {
67
+ constructor(message, name) {
68
+ super(message);
69
+ this.name = name ?? "NonRetryableError";
70
+ }
71
+ }
72
+ export class TimeoutTooLongError extends Error {
73
+ duration;
74
+ constructor(duration) {
75
+ super(`Timeout "${duration}" exceeds CF Workflows maximum of 30 minutes. ` +
76
+ `Ensure that the step timeout duration is 30 minutes or less.`);
77
+ this.duration = duration;
78
+ this.name = "TimeoutTooLongError";
79
+ }
80
+ }
81
+ export function isChildPayload(payload) {
82
+ return (typeof payload === "object" &&
83
+ payload !== null &&
84
+ payload.__workflais === true);
85
+ }
86
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,sFAAsF;AACtF,iEAAiE;AAiKjE,gFAAgF;AAEhF,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAE7B;IACA;IAFlB,YACkB,QAAgB,EAChB,SAA2B;QAE3C,KAAK,CACH,wBAAwB,QAAQ,kBAAkB,SAAS,CAAC,CAAC,CAAC,QAAQ,SAAS,CAAC,CAAC,CAAC,IAAI;YACpF,2FAA2F,CAC9F,CAAC;QANc,aAAQ,GAAR,QAAQ,CAAQ;QAChB,cAAS,GAAT,SAAS,CAAkB;QAM3C,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAE3B;IACA;IAFlB,YACkB,QAAgB,EAChB,MAAc;QAE9B,KAAK,CACH,cAAc,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,MAAM,eAAe;YACjE,uDAAuD,CAC1D,CAAC;QANc,aAAQ,GAAR,QAAQ,CAAQ;QAChB,WAAM,GAAN,MAAM,CAAQ;QAM9B,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAClB;IAA5B,YAA4B,SAAiB;QAC3C,KAAK,CACH,eAAe,SAAS,iCAAiC;YACvD,uFAAuF,CAC1F,CAAC;QAJwB,cAAS,GAAT,SAAS,CAAQ;QAK3C,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C;QACE,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACnB;IAA5B,YAA4B,KAAa;QACvC,KAAK,CACH,gBAAgB,KAAK,mEAAmE;YACtF,uEAAuE,CAC1E,CAAC;QAJwB,UAAK,GAAL,KAAK,CAAQ;QAKvC,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACpB;IAA5B,YAA4B,KAAe;QACzC,KAAK,CACH,iCAAiC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI;YACpD,oCAAoC,CACvC,CAAC;QAJwB,UAAK,GAAL,KAAK,CAAU;QAKzC,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C;QACE,KAAK,CACH,wEAAwE,CACzE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe,EAAE,IAAa;QACxC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,mBAAmB,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAChB;IAA5B,YAA4B,QAAgB;QAC1C,KAAK,CACH,YAAY,QAAQ,gDAAgD;YAClE,8DAA8D,CACjE,CAAC;QAJwB,aAAQ,GAAR,QAAQ,CAAQ;QAK1C,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAYD,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO,CACL,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,KAAK,IAAI;QACf,OAAmC,CAAC,WAAW,KAAK,IAAI,CAC1D,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "workflais",
3
+ "version": "0.1.0",
4
+ "description": "Effect-style composable workflow primitives for Cloudflare Workflows",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "test:cf": "vitest run --config vitest.config.cf.ts",
19
+ "test:all": "vitest run && vitest run --config vitest.config.cf.ts",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "devDependencies": {
23
+ "@cloudflare/vitest-pool-workers": "^0.12.18",
24
+ "@cloudflare/workers-types": "^4.20250214.0",
25
+ "typescript": "^5.7.0",
26
+ "vitest": "^3.0.0",
27
+ "wrangler": "^3.99.0"
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "license": "MIT"
33
+ }