@fungi.computer/braid 0.0.0-stage → 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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -2
  3. package/dist/cloudflare/graph-engine.d.ts +25 -0
  4. package/dist/cloudflare/graph-engine.js +46 -0
  5. package/dist/cloudflare/graph-program.d.ts +6 -0
  6. package/dist/cloudflare/graph-program.js +550 -0
  7. package/dist/cloudflare/index.d.ts +1 -0
  8. package/dist/cloudflare/index.js +1 -0
  9. package/dist/code-execution.d.ts +16 -0
  10. package/dist/code-execution.js +50 -0
  11. package/dist/code-result.d.ts +11 -0
  12. package/dist/code-result.js +19 -0
  13. package/dist/code-sandbox.d.ts +9 -0
  14. package/dist/code-sandbox.js +13 -0
  15. package/dist/compile.d.ts +43 -0
  16. package/dist/compile.js +248 -0
  17. package/dist/execution.d.ts +194 -0
  18. package/dist/execution.js +130 -0
  19. package/dist/expressions.d.ts +16 -0
  20. package/dist/expressions.js +322 -0
  21. package/dist/git-access.d.ts +59 -0
  22. package/dist/git-access.js +106 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.js +9 -0
  25. package/dist/ports.d.ts +58 -0
  26. package/dist/ports.js +256 -0
  27. package/dist/review-text.d.ts +15 -0
  28. package/dist/review-text.js +40 -0
  29. package/dist/runtime/arming-authority.d.ts +83 -0
  30. package/dist/runtime/arming-authority.js +90 -0
  31. package/dist/runtime/bindings.d.ts +25 -0
  32. package/dist/runtime/bindings.js +41 -0
  33. package/dist/runtime/capture.d.ts +18 -0
  34. package/dist/runtime/capture.js +99 -0
  35. package/dist/runtime/git-pass-contract.d.ts +63 -0
  36. package/dist/runtime/git-pass-contract.js +36 -0
  37. package/dist/runtime/git-pass-store.d.ts +32 -0
  38. package/dist/runtime/git-pass-store.js +82 -0
  39. package/dist/runtime/git-pass.d.ts +41 -0
  40. package/dist/runtime/git-pass.js +72 -0
  41. package/dist/runtime/graph-contract.d.ts +788 -0
  42. package/dist/runtime/graph-contract.js +122 -0
  43. package/dist/runtime/graph-dispatch.d.ts +31 -0
  44. package/dist/runtime/graph-dispatch.js +111 -0
  45. package/dist/runtime/graph-run-store.d.ts +79 -0
  46. package/dist/runtime/graph-run-store.js +267 -0
  47. package/dist/runtime/graph-start.d.ts +90 -0
  48. package/dist/runtime/graph-start.js +124 -0
  49. package/dist/runtime/index.d.ts +20 -0
  50. package/dist/runtime/index.js +20 -0
  51. package/dist/runtime/ports.d.ts +156 -0
  52. package/dist/runtime/ports.js +1 -0
  53. package/dist/runtime/run-authority.d.ts +60 -0
  54. package/dist/runtime/run-authority.js +145 -0
  55. package/dist/runtime/run-ceiling.d.ts +106 -0
  56. package/dist/runtime/run-ceiling.js +23 -0
  57. package/dist/runtime/run-member.d.ts +3 -0
  58. package/dist/runtime/run-member.js +12 -0
  59. package/dist/runtime/run-owner.d.ts +1650 -0
  60. package/dist/runtime/run-owner.js +513 -0
  61. package/dist/runtime/run-report.d.ts +14 -0
  62. package/dist/runtime/run-report.js +23 -0
  63. package/dist/runtime/schedules.d.ts +39 -0
  64. package/dist/runtime/schedules.js +149 -0
  65. package/dist/runtime/stored-trigger-rows.d.ts +12 -0
  66. package/dist/runtime/stored-trigger-rows.js +17 -0
  67. package/dist/runtime/trigger-owner.d.ts +594 -0
  68. package/dist/runtime/trigger-owner.js +280 -0
  69. package/dist/runtime/trigger-plans.d.ts +774 -0
  70. package/dist/runtime/trigger-plans.js +62 -0
  71. package/dist/runtime/trigger-router.d.ts +34 -0
  72. package/dist/runtime/trigger-router.js +143 -0
  73. package/dist/runtime/trigger-run-reservations.d.ts +28 -0
  74. package/dist/runtime/trigger-run-reservations.js +114 -0
  75. package/dist/schema.d.ts +1183 -0
  76. package/dist/schema.js +239 -0
  77. package/dist/triggers.d.ts +46 -0
  78. package/dist/triggers.js +75 -0
  79. package/dist/validate.d.ts +25 -0
  80. package/dist/validate.js +686 -0
  81. package/dist/workflow-id.d.ts +3 -0
  82. package/dist/workflow-id.js +3 -0
  83. package/package.json +96 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jamstack Consulting LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,261 @@
1
- # Temporary Holding Version
1
+ # Braid
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Braid owns `fungi.workflow/v1` and its graph interpreter. The browser-safe root
4
+ exports validation, compilation, and portable execution contracts.
5
+ `validate(unknown, catalog)` decodes with Effect Schema and returns typed issues
6
+ for the editor. Expected schema and expression-syntax refusals become issues;
7
+ unexpected parser or traversal defects propagate rather than being reported as
8
+ author errors. `compile` returns either issues or a topologically ordered,
9
+ installation-bound plan and SHA-256 `planDigest`. `decodeExecutionPlan` checks
10
+ stored content against that identity and recompiles its domain invariants.
11
+ Compilation grants no authority.
12
+
13
+ `catalogMethods` omits declarations marked `hidden: true` before reading their
14
+ graph ports. Visible method digests remain unchanged; the discovery marker does
15
+ not decide direct-call permissions.
16
+
17
+ ## Workers engine
18
+
19
+ `@fungi.computer/braid/cloudflare` exports `GraphWorkflow` and
20
+ `GraphWorkflowBindings`. A host subclasses the base, supplies its
21
+ `GRAPH_WORKFLOWS` binding, and implements `dispatcher(params)` and
22
+ `terminalTriggerRun(params)`. The dispatcher loads the host's admitted plan,
23
+ invokes App methods, records node events, and persists review waits. A host
24
+ admitting Code also overrides `codeExecution()` with its actual Mycelium
25
+ `Sandbox` and an explicitly captured `timeoutMs`. Hosts without this port refuse
26
+ Code with `code_execution_unavailable`. Hub and standalone hosts give Workflow
27
+ data transforms a 30,000 ms budget; this is independent of Agent policy. Local
28
+ workerd hosts set `WORKFLOW_CODE_LOCAL_DEV=true` to report that CPU limits are
29
+ not enforced; celld and deployed Workers forward the budget to the Loader.
30
+ Terminal cleanup runs through the host callback; Braid does not own grants, run
31
+ storage, Git admission, trigger reservations, cancellation requests, or
32
+ outboxes.
33
+
34
+ The root exports `GraphParams`, `NodeDispatcher`, `NodeCall`, `NodeEvent`,
35
+ `GraphReview`, `DispatchResult`, and their wire decoders without importing a
36
+ Workers runtime. App pending calls retain their stable idempotency key while
37
+ each poll has a distinct event identity. Retry attempts remain local to a poll.
38
+ Hosts must re-admit App calls using their own stored authority.
39
+
40
+ The portable root is checked with `skipLibCheck: false`. The Workers build
41
+ retains the Hub's existing `skipLibCheck: true`: Effect 4.0.2's `KeyValueStore`
42
+ declaration refers to DOM `Storage`, which the Workers type environment does not
43
+ provide. No ambient compatibility declaration is added; the native runtime tests
44
+ exercise the actual Workers implementation.
45
+
46
+ The Hub adapter consumes this same engine. Its native graph tests cover branch
47
+ selection, Pending polls, reviews, maps, and terminal cancellation. Those tests
48
+ establish Hub behavior; a standalone host must qualify its own bindings and
49
+ admission ports.
50
+
51
+ ## V1 contract
52
+
53
+ - Run input ports use the reserved node `$input`. Each node also emits `after`.
54
+ `after` is reserved for that ordering signal: App input/output schemas and
55
+ Code input/output schemas and transform fields declaring it are refused,
56
+ rather than silently overwritten.
57
+ - `admitRunInput(definition, raw)` fills absent property defaults and validates
58
+ the resulting object with the supported projection. It returns
59
+ `{kind: "accepted", input}` or `{kind: "invalid", issues}`; issues retain the
60
+ validator's instance location and message. Explicit values are never replaced
61
+ by defaults. Hosts record the admitted input, and triggers and graph execution
62
+ use the same admission function.
63
+ - Durations are integer milliseconds, positive and at most seven days. Retry
64
+ `attempts` includes the first attempt (1–5); external effects cannot retry.
65
+ - App and Code `values` and transform fields use Mapping: `{literal: Json}`,
66
+ `{template: string}`, `{from: PortRef, path?: JsonPointer}`,
67
+ `{coalesce: Mapping[]}`, `{object: Record<string, Mapping>}`,
68
+ `{array: Mapping[]}`, or
69
+ `{each: {over: Mapping, body: Mapping, maxItems: 1..50}}`. `each` exposes its
70
+ current value/index as `$item.value` and `$item.index`; nested each
71
+ expressions get their own item scope. The evaluator bounds materialization to
72
+ 64 KiB and 65536 visits. A missing required member makes the whole
73
+ construction absent. Mustache owns interpolation parsing (`{{node.port}}`,
74
+ without HTML escaping or execution); JSON Pointer owns path lookup. References
75
+ establish dependencies.
76
+ - Object method inputs/outputs keep their property ports. Non-object values and
77
+ unions use a single `value` port; the dispatcher still sends/receives the raw
78
+ declared App value. A completion union containing required `error` objects
79
+ exposes `ok` / `refused`, each carrying the entire declared record. Both sides
80
+ retain their original schema constraints. App refusals route data; host
81
+ admission refusals still fail the node. Apps do not reshape their APIs.
82
+ - App nodes may declare `gitAccess: {binding, repository, branches}` (a write
83
+ branch ceiling) or `gitAccess: {binding, repository, access: "read"}` (read
84
+ only, no push). This declaration enters the plan digest and contains no
85
+ installation IDs. The member selects installations through
86
+ `bindingsSelectionSchema`; an explicit `{kind: "team-source"}` binding selects
87
+ a registered Team source. Compilation freezes the selected binding, including
88
+ a target separate from the executing App. `resolveGitAccess` forms Agar's
89
+ canonical installation-local or Team-source `RepositoryRef`; resolved scopes
90
+ are `{repository: RepositoryRef, branches}` or
91
+ `{repository: RepositoryRef, access: "read"}`. These data alone grant no
92
+ authority: the host checks the starting human's captured ceiling and live
93
+ policy, at the access's own scope, before minting a pass, and the pass's scope
94
+ is always its admitted access. Read access may name `$trigger.repository`: an
95
+ App-event trigger declares `repository`, a mapping over its event (for example
96
+ `{from: {node: "$input", port: "payload"}, path: "/data/repository/name"}`),
97
+ and the node's binding must be that trigger's App. Arming admits no Git; each
98
+ fire resolves the event's one repository inside the emitting installation, and
99
+ run start admits the grantor's live read access to exactly it. A manual run or
100
+ another trigger has no trigger repository, so the step is refused. Branches
101
+ are unique exact `refs/heads/...` names, bounded to 256 entries; globs and
102
+ revision expressions are refused.
103
+ - Coalesce selects the first present, non-null branch. When every candidate
104
+ comes from an inactive branch, the dependent node skips. An available fallback
105
+ still runs, so alternative review choices merge with OR semantics.
106
+ - Code nodes declare `{id, kind: "code", source, input, output, values}`.
107
+ `source` is a JavaScript function body, including its return; `input` and
108
+ `output` use the same projection grammar and ports as App methods. `values`
109
+ and incoming edges explicitly map the data available to the node. Exact
110
+ source, schemas and mappings enter the plan digest. Source uses the existing
111
+ 256,000-byte whole-definition envelope; each schema retains its 20,000-byte
112
+ and depth-16 bounds. Compilation never parses or executes JavaScript and adds
113
+ no required App binding. Its only data capability is `env.INPUT.read({})`,
114
+ returning a fresh copy of its mapped JSON. No Apps or network are available.
115
+ The native step checkpoints the validated completion or a closed refusal,
116
+ including the whole 64 KiB result envelope, with automatic retries disabled.
117
+ Replay reads the checkpoint instead of rerunning JavaScript. Guest errors do
118
+ not expose source, inputs, or raw sandbox causes in run events. Sandbox calls
119
+ run inside an interruptible Effect; cancellation remains the host run owner's
120
+ native instance termination, with no separate cancellation owner.
121
+ - A named `subgraphs` entry has the same input/nodes/edges/output contract as
122
+ the root. Map body inputs are `{item, index}`. Recursive map bodies are
123
+ refused. The entire definition, including bodies, is capped at 64 nodes / 256
124
+ edges.
125
+ - `after` edges order or gate any node. Other connected inputs belong to App or
126
+ Code ports; controls name their references in their own fields. Review's
127
+ selected port carries its first shown item; a condition's selected port is a
128
+ signal.
129
+ - Unreachable means unable to contribute to a graph output or a write/external
130
+ method. Skipped branch outputs may be absent; this is not an output error.
131
+ - The static expanded estimate budgets three durable operations per node plus
132
+ all map items and three operations per item for creation, completion and
133
+ parent notification, capped at 800 (headroom below Cloudflare's 1024).
134
+ - The catalog is keyed by portable App ID and preserves T1's method shape
135
+ (description, input/output, effect, approval, requires), with a catalog-owned
136
+ `digest` per method. Bindings must match the declared App ID. Only used
137
+ methods enter the consent manifest. Used method and event catalogs, including
138
+ event-only emitter installations, enter the plan.
139
+ - `pending: true` opts a method into Agar's shared Pending result. The catalog
140
+ exposes only the completed output ports of the emitted Output/Pending union;
141
+ its digest covers the original input/output declarations and the opt-in flag.
142
+ Ordinary methods omit the flag and keep their existing digests. The Hub maps
143
+ canonical Pending to engine Pending only for opted-in methods, with integer
144
+ `retryAfterMs` from 1000 to 60000. Pending never becomes graph output and
145
+ polls retain the same run/node/iteration key.
146
+
147
+ ## Reviews
148
+
149
+ - A review shows ports to a person and waits up to its timeout. Without
150
+ `choices` it approves or rejects (ports `approved` / `rejected`). With
151
+ `choices` (two to eight `{id, label}`), the reviewer picks one; each choice id
152
+ is an output port carrying the first shown item, so branches follow the pick.
153
+
154
+ ## Triggers
155
+
156
+ - `triggers` (optional, at most 8, root graph only) declares what may start a
157
+ run besides a person or Agent. For `{id, on: "webhook"}`, the host owns the
158
+ URL, secret and signature scheme, so the format names no provider.
159
+ - Inside a trigger, `$input` is the verified event (`body`, a stable non-secret
160
+ `eventId`, allowlisted `headers`), not the run input. Every port repeats on a
161
+ redelivery, so a redelivery maps to the same input. `when` is an ordinary
162
+ predicate over it; `input` maps it onto the run's declared input with ordinary
163
+ mappings. Without `input`, the body itself must be the run input. Triggers are
164
+ part of the plan identity.
165
+ - `validate` refuses references outside the event, unmapped required run input,
166
+ undeclared fields and mismatched literals (`trigger` issues). `triggerRun`
167
+ returns `start` with input checked against `definition.input`, `ignored` when
168
+ `when` is false, or a typed refusal. `triggerRequestId` turns (scope, trigger,
169
+ event id) into the idempotent start key.
170
+ - A schedule declares
171
+ `{id, on: "schedule", cron: {expression, timeZone}, input?}`. Almanac
172
+ validates the cadence; consecutive occurrences must be at least five minutes
173
+ apart. Its event exposes `scheduledAt` (ISO) and `eventId`; without a mapping
174
+ that event is the run input. The Team arms published definitions as a member,
175
+ rechecks access at each firing, and coalesces missed ticks.
176
+
177
+ - An App event declares
178
+ `{id, on: "event", app, event, eventDigest, when?, input?}`. `catalogEvents`
179
+ pins the original emitted payload schema; rewording its description preserves
180
+ the digest. Its event ports are `payload` (the full envelope) and `eventId`.
181
+ Missing declarations and changed digests refuse compilation; a cached trigger
182
+ checks those digests against the live catalog before starting.
183
+ - Event mappings prove assignability for the payload or required object paths
184
+ within it, plus literals, templates and coalesce. JSON Pointer spelling uses
185
+ the maintained encoder. Optional paths, array indexing and unsupported schema
186
+ assertions remain unproven and are refused. An emitted `const` projects to an
187
+ enum for checking, while the digest retains the original schema. Schedule and
188
+ webhook mapping behavior is unchanged.
189
+
190
+ ## Schema scope
191
+
192
+ App projections have the same 20 KB / depth-16 envelope as T1. V1 accepts the
193
+ JSON Schema vocabulary in `PortSchema`: primitive types, standard formats from
194
+ the maintained validator registry and Fungi media annotations, enum/const,
195
+ object properties/required/additionalProperties, array items/counts, string
196
+ lengths/patterns, number bounds (including exclusive bounds), nonempty
197
+ anyOf/oneOf, and title/description/default annotations. Effect decodes that
198
+ vocabulary; `@cfworker/json-schema` validates runtime values without dynamic
199
+ code generation. Standard formats remain text ports and validate instances;
200
+ Fungi image/video/file annotations remain distinct media ports. Assignability is
201
+ conservative subset checking. Unsupported assertions (for example `$ref` or
202
+ conditionals) produce a schema issue rather than a guessed connection. This is
203
+ not a general JSON Schema implication solver.
204
+
205
+ `test/anime.fixture.ts` models beats → map{generate → review → optional
206
+ animate}. Its Prints catalog and digests are explicitly fake; it does not
207
+ establish the shipped Storyboard template's parity, installed App methods,
208
+ grants, costs or production execution.
209
+
210
+ Run `pnpm --dir packages/braid test` for `braid-validate`.
211
+
212
+ `apps/hub/test/graph-declared-ports.native.mjs` uses the actual Prints
213
+ declarations and input parsers with a provider-boundary fake. It exercises both
214
+ animate choices, keep/reject, declared refusal, Pending replay, and raw
215
+ scalar/array method values through the native graph engine; it makes no provider
216
+ calls.
217
+
218
+ ## Host runtime
219
+
220
+ `@fungi.computer/braid/runtime` owns the saved graph run, node event and review
221
+ records. Hosts provide the Watchdog SQLite owner to `createGraphWorkflowRuns`;
222
+ the store preserves immutable plans, idempotent starts and accepted review
223
+ answers across owner recreation. `resolveWorkflowNode` and `planNodeCall`
224
+ resolve calls against that saved plan. Hosts retain membership, installation,
225
+ Git and native Workflow admission and delivery. Stored rows alone grant no
226
+ permission to run an App method or answer a review.
227
+
228
+ The runtime entrypoint also owns `createTeamWorkflowTriggers`,
229
+ `createWorkflowSchedules`, `createWorkflowEventRouter`, immutable trigger plans
230
+ and run reservations. Hosts supply publication resolution, existing denial
231
+ errors, live authorization, transaction and alarm ports; the runtime owns saved
232
+ trigger state and occurrence identity. `PublishedDefinitionPort` resolves an
233
+ exact version or commit with host-issued access. A copied document never grants
234
+ that access.
235
+
236
+ A review answer is `{approved: boolean}` or `{choice: string, note?: string}`.
237
+ Choice notes are bounded to 1,000 characters. A completed review retains the
238
+ shown item on its selected outcome port and also emits `choice` (the actual
239
+ selected outcome) and `note` (an empty string when absent). Those two ports and
240
+ `after` are reserved and cannot be named choices. Downstream nodes can use these
241
+ saved outputs, including a subsequent Repeat round.
242
+
243
+ ## Bounded Repeat
244
+
245
+ A Repeat node declares `{id, kind: "repeat", body, maxRounds, until}`.
246
+ `maxRounds` is an integer from one to five. The body receives `item` from the
247
+ enclosing graph input, a zero-based `round`, and `previous`: an empty object on
248
+ the first round, then the preceding body output. The stop predicate reads the
249
+ completed body output through `$input`. It cannot reach into another graph.
250
+
251
+ When the predicate becomes true, the node emits the body output on `result`.
252
+ When all rounds finish without satisfying it, the node emits the last output on
253
+ `exhausted`. The other outlet stays inactive. Both paths emit `after`; failed
254
+ children fail the Repeat rather than fabricating a successful result.
255
+
256
+ Validation checks body input and output compatibility, references, recursive
257
+ groups, and the bounded execution budget. The Cloudflare interpreter runs each
258
+ round as a durable child with its own review identity and passes saved feedback
259
+ into the next round. Map items retain their order when their bodies contain a
260
+ Repeat. `apps/hub/test/graph-workflow-repeat.native.mjs` exercises the real
261
+ engine and run owner with a fixture App dispatcher; it calls no media provider.
@@ -0,0 +1,25 @@
1
+ import { WorkflowEntrypoint, type WorkflowEvent, type WorkflowStep } from "cloudflare:workers";
2
+ import * as S from "effect/Schema";
3
+ import type { CodeExecution } from "../code-execution.js";
4
+ import { type NodeDispatcher, type GraphParams } from "../execution.js";
5
+ import type { Json } from "../schema.js";
6
+ export type GraphWorkflowBindings = {
7
+ GRAPH_WORKFLOWS: Workflow<GraphParams>;
8
+ };
9
+ /** How a root run ended, as the engine observed it; hosts may report it. */
10
+ export type GraphRunEnding = Readonly<{
11
+ kind: "complete";
12
+ output: Readonly<Record<string, Json>>;
13
+ }> | Readonly<{
14
+ kind: "failed";
15
+ error: string;
16
+ }>;
17
+ /** Each host supplies App dispatch, run storage, and terminal cleanup. */
18
+ export declare abstract class GraphWorkflow<Env extends GraphWorkflowBindings = GraphWorkflowBindings> extends WorkflowEntrypoint<Env, GraphParams> {
19
+ /** The host scope and run identity select the owner receiving execution facts. */
20
+ protected abstract dispatcher(params: GraphParams): NodeDispatcher;
21
+ protected abstract terminalTriggerRun(params: GraphParams, ending: GraphRunEnding): Promise<void>;
22
+ /** A host may admit data-only Code with its own sandbox and captured budget. */
23
+ protected codeExecution(): CodeExecution | undefined;
24
+ run(event: Readonly<WorkflowEvent<GraphParams>>, step: WorkflowStep): Promise<Readonly<Record<string, S.Json>>>;
25
+ }
@@ -0,0 +1,46 @@
1
+ import { WorkflowEntrypoint, } from "cloudflare:workers";
2
+ import * as S from "effect/Schema";
3
+ import { graphParamsSchema, } from "../execution.js";
4
+ import { runGraphWorkflow } from "./graph-program.js";
5
+ /** Each host supplies App dispatch, run storage, and terminal cleanup. */
6
+ export class GraphWorkflow extends WorkflowEntrypoint {
7
+ /** A host may admit data-only Code with its own sandbox and captured budget. */
8
+ codeExecution() {
9
+ return undefined;
10
+ }
11
+ async run(event, step) {
12
+ const params = S.decodeUnknownSync(graphParamsSchema)(event.payload, {
13
+ onExcessProperty: "error",
14
+ });
15
+ let output;
16
+ try {
17
+ output = await runGraphWorkflow(step, params, event.instanceId, this.env.GRAPH_WORKFLOWS, this.dispatcher(params), this.codeExecution());
18
+ }
19
+ catch (cause) {
20
+ if (params.kind === "map-item")
21
+ await step.do("notify-parent-failed", async () => {
22
+ const parent = await this.env.GRAPH_WORKFLOWS.get(params.parentInstanceId);
23
+ await parent.sendEvent({
24
+ type: params.completionEvent,
25
+ payload: { refusal: "map_item_failed" },
26
+ });
27
+ return null;
28
+ });
29
+ if (params.kind === "run" && params.runId === event.instanceId)
30
+ await step.do("terminal-trigger-run", async () => {
31
+ await this.terminalTriggerRun(params, {
32
+ kind: "failed",
33
+ error: cause instanceof Error ? cause.message : "failed",
34
+ });
35
+ return null;
36
+ });
37
+ throw cause;
38
+ }
39
+ if (params.kind === "run")
40
+ await step.do("terminal-trigger-run", async () => {
41
+ await this.terminalTriggerRun(params, { kind: "complete", output });
42
+ return null;
43
+ });
44
+ return output;
45
+ }
46
+ }
@@ -0,0 +1,6 @@
1
+ import { type CodeExecution } from "../code-execution.js";
2
+ import type { WorkflowStep } from "cloudflare:workers";
3
+ import { type Json } from "../index.js";
4
+ import { type GraphParams, type NodeDispatcher } from "../execution.js";
5
+ /** Native WorkflowStep owns checkpoints, retries, sleeps and event waits. */
6
+ export declare function runGraphWorkflow(step: WorkflowStep, params: GraphParams, instanceId: string, workflows: Workflow<GraphParams>, dispatcher: NodeDispatcher, codeExecution?: CodeExecution): Promise<Readonly<Record<string, Json>>>;