Skip to content

Commit 7f27dc1

Browse files
authored
feat(workflows): unify workflow and actor API (#10)
1 parent 02a873f commit 7f27dc1

13 files changed

Lines changed: 623 additions & 232 deletions

File tree

README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,31 @@ Durable, replayable multi-step operations for Rivet Actors.
55
**[Documentation](https://rivet.dev/workflows/docs)** · **[Website](https://rivet.dev/workflows)** · **[Discord](https://rivet.dev/discord)**
66

77
```sh
8-
pnpm add @rivet-dev/workflows rivetkit
8+
pnpm add @rivet-dev/workflows
99
```
1010

1111
```ts
12-
import { workflow } from "@rivet-dev/workflows";
12+
import { setup, workflow } from "@rivet-dev/workflows";
1313

1414
export const report = workflow({
15+
state: { status: "pending" as "pending" | "complete" },
1516
run: async (ctx) => {
1617
await ctx.step("generate", async (step) => {
1718
step.log.info("generating report");
19+
step.state.status = "complete";
1820
});
1921
},
22+
actions: {
23+
status: (ctx) => ctx.state,
24+
},
2025
});
26+
27+
export const registry = setup({ use: { report } });
2128
```
2229

2330
The package preserves the existing workflow history encoding and uses only
24-
RivetKit's public workflow-host capabilities. RivetKit continues to own the
25-
internal SQLite schema and its migrations.
31+
RivetKit's public workflow-host capabilities. It re-exports RivetKit, and package
32+
managers install its compatible peer automatically, so workflow actors and
33+
regular `actor(...)` definitions can share the same registry without another
34+
direct dependency. RivetKit continues to own the internal SQLite schema and its
35+
migrations.

docs/content/docs/index.mdx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ Use workflows for durable, multi-step execution with replay safety.
88

99
## What are workflows?
1010

11-
A workflow is a durable, replayable run handler.
11+
A workflow is a durable, replayable actor definition. It supports the full actor
12+
configuration, including actions and lifecycle hooks, while its `run` function
13+
uses replay-safe workflow primitives.
1214

1315
- Survives restarts: workflow progress is saved automatically.
1416
- Re-runs safely: replay follows the same recorded steps.

packages/workflows/README.md

Lines changed: 0 additions & 19 deletions
This file was deleted.

packages/workflows/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@
6464
"vbare": "^0.0.4"
6565
},
6666
"peerDependencies": {
67-
"rivetkit": ">=2.4.0 <3"
67+
"rivetkit": ">=2.3.11 <2.4.0"
6868
},
6969
"devDependencies": {
7070
"@bare-ts/tools": "^0.13.0",
7171
"@types/node": "^22.13.1",
7272
"commander": "^12.0.0",
7373
"legacy-rivetkit": "npm:rivetkit@2.3.7",
7474
"legacy-workflow-engine": "npm:@rivetkit/workflow-engine@2.3.7",
75-
"rivetkit": "0.0.0-feat-workflows-public-host-apis.1550fe4",
75+
"rivetkit": "2.3.11",
7676
"tsup": "^8.4.0",
7777
"tsx": "^4.7.0",
7878
"typescript": "^5.7.3",

packages/workflows/src/mod.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1+
export * from "rivetkit";
12
export * from "./index.js";
3+
export type {
4+
WorkflowBranchContextOf,
5+
WorkflowContextOf,
6+
WorkflowLoopContextOf,
7+
WorkflowStepContextOf,
8+
} from "./rivetkit/context.js";
29
export * from "./rivetkit/mod.js";
10+
// Prefer workflow-specific meanings for names that also exist in RivetKit.
11+
export type { WorkflowState } from "./types.js";

packages/workflows/src/rivetkit/inspector.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as transport from "rivetkit/experimental/inspector/workflow";
22
import {
33
encodeWorkflowHistoryTransport,
44
encodeWorkflowInspectorValue,
5+
type WorkflowHistoryBytes,
56
type WorkflowInspectorAdapter,
67
} from "rivetkit/experimental/inspector/workflow";
78
import type {
@@ -21,7 +22,7 @@ function assertUnreachable(value: never): never {
2122
throw new Error(`Unexpected workflow Inspector value: ${String(value)}`);
2223
}
2324

24-
type HistoryListener = (history: ArrayBuffer) => void;
25+
type HistoryListener = (history: WorkflowHistoryBytes) => void;
2526

2627
function createHistoryEmitter() {
2728
const listeners = new Set<HistoryListener>();
@@ -31,7 +32,7 @@ function createHistoryEmitter() {
3132
listeners.add(listener);
3233
return () => listeners.delete(listener);
3334
},
34-
emit: (history: ArrayBuffer) => {
35+
emit: (history: WorkflowHistoryBytes) => {
3536
for (const listener of listeners) {
3637
listener(history);
3738
}
@@ -44,16 +45,17 @@ export function createWorkflowInspectorAdapter(): {
4445
update: (snapshot: WorkflowHistorySnapshot) => void;
4546
setGetState: (fn: () => Promise<WorkflowState | null>) => void;
4647
setReplayFromStep: (
47-
fn: (entryId?: string) => Promise<ArrayBuffer | null>,
48+
fn: (entryId?: string) => Promise<WorkflowHistoryBytes | null>,
4849
) => void;
4950
} {
5051
const emitter = createHistoryEmitter();
51-
let history: ArrayBuffer | null = null;
52+
let history: WorkflowHistoryBytes | null = null;
5253
let getState: () => Promise<WorkflowState | null> = async () => null;
53-
let replayFromStep: (entryId?: string) => Promise<ArrayBuffer | null> =
54-
async () => {
55-
throw new Error("Workflow replay controls are not initialized");
56-
};
54+
let replayFromStep: (
55+
entryId?: string,
56+
) => Promise<WorkflowHistoryBytes | null> = async () => {
57+
throw new Error("Workflow replay controls are not initialized");
58+
};
5759

5860
const adapter: WorkflowInspectorAdapter = {
5961
getHistory: () => history,

0 commit comments

Comments
 (0)