diff --git a/README.md b/README.md index 0ed173e..4996402 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,31 @@ Durable, replayable multi-step operations for Rivet Actors. **[Documentation](https://rivet.dev/workflows/docs)** · **[Website](https://rivet.dev/workflows)** · **[Discord](https://rivet.dev/discord)** ```sh -pnpm add @rivet-dev/workflows rivetkit +pnpm add @rivet-dev/workflows ``` ```ts -import { workflow } from "@rivet-dev/workflows"; +import { setup, workflow } from "@rivet-dev/workflows"; export const report = workflow({ + state: { status: "pending" as "pending" | "complete" }, run: async (ctx) => { await ctx.step("generate", async (step) => { step.log.info("generating report"); + step.state.status = "complete"; }); }, + actions: { + status: (ctx) => ctx.state, + }, }); + +export const registry = setup({ use: { report } }); ``` The package preserves the existing workflow history encoding and uses only -RivetKit's public workflow-host capabilities. RivetKit continues to own the -internal SQLite schema and its migrations. +RivetKit's public workflow-host capabilities. It re-exports RivetKit, and package +managers install its compatible peer automatically, so workflow actors and +regular `actor(...)` definitions can share the same registry without another +direct dependency. RivetKit continues to own the internal SQLite schema and its +migrations. diff --git a/docs/content/docs/index.mdx b/docs/content/docs/index.mdx index 0043f00..d0fced9 100644 --- a/docs/content/docs/index.mdx +++ b/docs/content/docs/index.mdx @@ -8,7 +8,9 @@ Use workflows for durable, multi-step execution with replay safety. ## What are workflows? -A workflow is a durable, replayable run handler. +A workflow is a durable, replayable actor definition. It supports the full actor +configuration, including actions and lifecycle hooks, while its `run` function +uses replay-safe workflow primitives. - Survives restarts: workflow progress is saved automatically. - Re-runs safely: replay follows the same recorded steps. diff --git a/packages/workflows/README.md b/packages/workflows/README.md deleted file mode 100644 index 0e499e7..0000000 --- a/packages/workflows/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# @rivet-dev/workflows - -Durable, replayable workflows for Rivet Actors. - -[Documentation](https://rivet.dev/workflows/docs) - -```ts -import { workflow } from "@rivet-dev/workflows"; - -export const example = workflow({ - run: async (ctx) => { - await ctx.step("hello", async () => "world"); - }, -}); -``` - -The workflow storage format is owned and migrated by RivetKit. This package is -a format-compatible client and never creates or migrates RivetKit's internal -SQLite tables. diff --git a/packages/workflows/package.json b/packages/workflows/package.json index dec4327..a74eba4 100644 --- a/packages/workflows/package.json +++ b/packages/workflows/package.json @@ -64,7 +64,7 @@ "vbare": "^0.0.4" }, "peerDependencies": { - "rivetkit": ">=2.4.0 <3" + "rivetkit": ">=2.3.11 <2.4.0" }, "devDependencies": { "@bare-ts/tools": "^0.13.0", @@ -72,7 +72,7 @@ "commander": "^12.0.0", "legacy-rivetkit": "npm:rivetkit@2.3.7", "legacy-workflow-engine": "npm:@rivetkit/workflow-engine@2.3.7", - "rivetkit": "0.0.0-feat-workflows-public-host-apis.1550fe4", + "rivetkit": "2.3.11", "tsup": "^8.4.0", "tsx": "^4.7.0", "typescript": "^5.7.3", diff --git a/packages/workflows/src/mod.ts b/packages/workflows/src/mod.ts index 7c76c49..aac03b1 100644 --- a/packages/workflows/src/mod.ts +++ b/packages/workflows/src/mod.ts @@ -1,2 +1,11 @@ +export * from "rivetkit"; export * from "./index.js"; +export type { + WorkflowBranchContextOf, + WorkflowContextOf, + WorkflowLoopContextOf, + WorkflowStepContextOf, +} from "./rivetkit/context.js"; export * from "./rivetkit/mod.js"; +// Prefer workflow-specific meanings for names that also exist in RivetKit. +export type { WorkflowState } from "./types.js"; diff --git a/packages/workflows/src/rivetkit/inspector.ts b/packages/workflows/src/rivetkit/inspector.ts index 1421b3b..44e1c9c 100644 --- a/packages/workflows/src/rivetkit/inspector.ts +++ b/packages/workflows/src/rivetkit/inspector.ts @@ -2,6 +2,7 @@ import * as transport from "rivetkit/experimental/inspector/workflow"; import { encodeWorkflowHistoryTransport, encodeWorkflowInspectorValue, + type WorkflowHistoryBytes, type WorkflowInspectorAdapter, } from "rivetkit/experimental/inspector/workflow"; import type { @@ -21,7 +22,7 @@ function assertUnreachable(value: never): never { throw new Error(`Unexpected workflow Inspector value: ${String(value)}`); } -type HistoryListener = (history: ArrayBuffer) => void; +type HistoryListener = (history: WorkflowHistoryBytes) => void; function createHistoryEmitter() { const listeners = new Set(); @@ -31,7 +32,7 @@ function createHistoryEmitter() { listeners.add(listener); return () => listeners.delete(listener); }, - emit: (history: ArrayBuffer) => { + emit: (history: WorkflowHistoryBytes) => { for (const listener of listeners) { listener(history); } @@ -44,16 +45,17 @@ export function createWorkflowInspectorAdapter(): { update: (snapshot: WorkflowHistorySnapshot) => void; setGetState: (fn: () => Promise) => void; setReplayFromStep: ( - fn: (entryId?: string) => Promise, + fn: (entryId?: string) => Promise, ) => void; } { const emitter = createHistoryEmitter(); - let history: ArrayBuffer | null = null; + let history: WorkflowHistoryBytes | null = null; let getState: () => Promise = async () => null; - let replayFromStep: (entryId?: string) => Promise = - async () => { - throw new Error("Workflow replay controls are not initialized"); - }; + let replayFromStep: ( + entryId?: string, + ) => Promise = async () => { + throw new Error("Workflow replay controls are not initialized"); + }; const adapter: WorkflowInspectorAdapter = { getHistory: () => history, diff --git a/packages/workflows/src/rivetkit/mod.ts b/packages/workflows/src/rivetkit/mod.ts index a216d19..9276185 100644 --- a/packages/workflows/src/rivetkit/mod.ts +++ b/packages/workflows/src/rivetkit/mod.ts @@ -10,6 +10,7 @@ import { type RunContext, type RunControl, } from "rivetkit"; +import type { AnyDatabaseProvider } from "rivetkit/db"; import { isActorAbortedError } from "rivetkit/errors"; import { stringifyError } from "rivetkit/utils"; import { @@ -107,16 +108,86 @@ function isRunHandlerUnavailable(error: unknown): boolean { ); } -type DistributiveOmit = T extends unknown - ? Omit +export interface WorkflowOptions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, + TEvents extends EventSchemaConfig = Record, + TQueues extends QueueSchemaConfig = Record, +> { + onError?: ( + ctx: RunContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >, + event: WorkflowErrorEvent, + ) => void | Promise; +} + +export type WorkflowRunFunction< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, + TEvents extends EventSchemaConfig = Record, + TQueues extends QueueSchemaConfig = Record, +> = ( + ctx: WorkflowContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >, +) => Promise; + +type WorkflowRunHandler< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, + TEvents extends EventSchemaConfig = Record, + TQueues extends QueueSchemaConfig = Record, +> = ( + c: RunContext< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >, +) => Promise; + +type DistributiveOmit = T extends unknown + ? Omit : never; -export type WorkflowActorConfig< +export type WorkflowConfigInput< TState = undefined, TConnParams = undefined, TConnState = undefined, TVars = undefined, TInput = undefined, + TDatabase extends AnyDatabaseProvider = undefined, TEvents extends EventSchemaConfig = Record, TQueues extends QueueSchemaConfig = Record, TActions extends Actions< @@ -125,7 +196,7 @@ export type WorkflowActorConfig< TConnState, TVars, TInput, - undefined, + TDatabase, TEvents, TQueues > = Record, @@ -136,96 +207,66 @@ export type WorkflowActorConfig< TConnState, TVars, TInput, - undefined, + TDatabase, TEvents, TQueues, TActions >, - "run" | "db" + "run" > & { - run: ( - ctx: WorkflowContext< - TState, - TConnParams, - TConnState, - TVars, - TInput, - undefined, - TEvents, - TQueues - >, - ) => Promise; - onError?: ( - ctx: RunContext< - TState, - TConnParams, - TConnState, - TVars, - TInput, - undefined, - TEvents, - TQueues - >, - event: WorkflowErrorEvent, - ) => void | Promise; + run: WorkflowRunFunction< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >; }; -export function workflow< - TState = undefined, - TConnParams = undefined, - TConnState = undefined, - TVars = undefined, - TInput = undefined, +function createWorkflowRunHandler< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase extends AnyDatabaseProvider, TEvents extends EventSchemaConfig = Record, TQueues extends QueueSchemaConfig = Record, - TActions extends Actions< +>( + fn: WorkflowRunFunction< TState, TConnParams, TConnState, TVars, TInput, - undefined, + TDatabase, TEvents, TQueues - > = Record, ->( - config: WorkflowActorConfig< + >, + options: WorkflowOptions< TState, TConnParams, TConnState, TVars, TInput, + TDatabase, TEvents, - TQueues, - Actions< - TState, - TConnParams, - TConnState, - TVars, - TInput, - undefined, - TEvents, - TQueues - > - > & { actions?: TActions }, -): ActorDefinition< + TQueues + > = {}, +): WorkflowRunHandler< TState, TConnParams, TConnState, TVars, TInput, - undefined, + TDatabase, TEvents, - TQueues, - TActions + TQueues > { - if (Object.hasOwn(config, "db")) { - throw new TypeError( - "workflow() does not support a custom database provider", - ); - } - - const { run: workflowRun, onError, ...actorConfig } = config; + const onError = options.onError; const workflowInspectors = new Map< string, ReturnType @@ -240,6 +281,7 @@ export function workflow< } return workflowInspector; } + async function run( runCtx: RunContext< TState, @@ -247,7 +289,7 @@ export function workflow< TConnState, TVars, TInput, - undefined, + TDatabase, TEvents, TQueues >, @@ -293,7 +335,7 @@ export function workflow< const handle = runWorkflow( runCtx.actorId, - async (ctx) => await workflowRun(new WorkflowContext(ctx, runCtx)), + async (ctx) => await fn(new WorkflowContext(ctx, runCtx)), undefined, driver, { @@ -346,7 +388,7 @@ export function workflow< } } - const runHandler = defineRunHandler(run, { + return defineRunHandler(run, { icon: "diagram-project", inspectorKind: "workflow", createInspector: ({ actorId, control }) => { @@ -365,19 +407,133 @@ export function workflow< }; }, }); +} - return actor< +export function workflow< + TState = undefined, + TConnParams = undefined, + TConnState = undefined, + TVars = undefined, + TInput = undefined, + TDatabase extends AnyDatabaseProvider = undefined, + TEvents extends EventSchemaConfig = Record, + TQueues extends QueueSchemaConfig = Record, + TActions extends Actions< TState, TConnParams, TConnState, TVars, TInput, - undefined, + TDatabase, + TEvents, + TQueues + > = Record, +>( + input: WorkflowConfigInput< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, TEvents, TQueues, - TActions - >({ - ...actorConfig, - run: runHandler, + Actions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + > + > & { actions?: TActions }, + options?: WorkflowOptions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >, +): ActorDefinition< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues, + TActions +>; + +/** + * @deprecated Pass the complete actor config to `workflow({ run, ... })` + * instead of wrapping `workflow(run)` in `actor({ run: ... })`. + */ +export function workflow< + TState = undefined, + TConnParams = undefined, + TConnState = undefined, + TVars = undefined, + TInput = undefined, + TDatabase extends AnyDatabaseProvider = undefined, + TEvents extends EventSchemaConfig = Record, + TQueues extends QueueSchemaConfig = Record, +>( + run: WorkflowRunFunction< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >, + options?: WorkflowOptions< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues + >, +): WorkflowRunHandler< + TState, + TConnParams, + TConnState, + TVars, + TInput, + TDatabase, + TEvents, + TQueues +>; + +export function workflow( + input: + | WorkflowConfigInput + | WorkflowRunFunction, + options: WorkflowOptions = {}, +): + | ActorDefinition + | WorkflowRunHandler { + if (typeof input === "function") { + return createWorkflowRunHandler(input, options); + } + + // RivetKit's `types` field exists only for inference and is not accepted by + // its strict runtime config schema. + const { run, types: typeOnly, ...actorInput } = input; + void typeOnly; + return actor({ + ...actorInput, + run: createWorkflowRunHandler(run, options), }); } diff --git a/packages/workflows/tests/e2e/preview-runtime.test.ts b/packages/workflows/tests/e2e/preview-runtime.test.ts index d4525f5..f837890 100644 --- a/packages/workflows/tests/e2e/preview-runtime.test.ts +++ b/packages/workflows/tests/e2e/preview-runtime.test.ts @@ -1,7 +1,10 @@ -import { setup } from "rivetkit"; +import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { createServer } from "node:net"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { setupTest } from "rivetkit/test"; import { expect, test } from "vitest"; -import { workflow } from "../../src/rivetkit/mod"; +import { setup, workflow } from "../../src/mod"; const sleepAcrossWake = workflow({ state: { completed: [] as string[] }, @@ -21,22 +24,110 @@ const sleepAcrossWake = workflow({ sleepTimeout: 20, }, }); +async function findAvailablePort(): Promise { + const server = createServer(); + return await new Promise((resolve, reject) => { + server.once("error", reject); + server.listen(0, "127.0.0.1", () => { + const address = server.address(); + if (!address || typeof address === "string") { + server.close(); + reject(new Error("failed to allocate a local engine port")); + return; + } + server.close((error) => { + if (error) reject(error); + else resolve(address.port); + }); + }); + }); +} -const registry = setup({ use: { sleepAcrossWake } }); +async function stopTestEngine(storagePath: string): Promise { + let enginePid: number; + try { + const runtime = JSON.parse( + await readFile( + join(storagePath, ".rivetkit/var/engine/runtime.json"), + "utf8", + ), + ) as { pid?: unknown }; + if (!Number.isSafeInteger(runtime.pid) || Number(runtime.pid) <= 0) return; + enginePid = Number(runtime.pid); + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ENOENT") return; + throw error; + } -test("published runtime resumes a sleeping workflow exactly once", async (context) => { - const { client } = await setupTest(context, registry); - const handle = client.sleepAcrossWake.getOrCreate(["preview-e2e"]); - const deadline = Date.now() + 10_000; - let completed: string[] = []; - - while (Date.now() < deadline) { - completed = await handle.getCompleted(); - if (completed.includes("after-sleep")) break; - await new Promise((resolve) => setTimeout(resolve, 25)); + try { + process.kill(enginePid, "SIGTERM"); + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ESRCH") return; + throw error; } - expect(completed).toEqual(["before-sleep", "after-sleep"]); - await new Promise((resolve) => setTimeout(resolve, 150)); - expect(await handle.getCompleted()).toEqual(["before-sleep", "after-sleep"]); + for (let attempt = 0; attempt < 50; attempt++) { + await new Promise((resolve) => setTimeout(resolve, 100)); + try { + process.kill(enginePid, 0); + } catch (error) { + if ((error as NodeJS.ErrnoException).code === "ESRCH") return; + throw error; + } + } + + throw new Error(`test engine ${enginePid} did not stop after SIGTERM`); +} + +test("published runtime resumes a sleeping workflow exactly once", async (context) => { + const enginePort = await findAvailablePort(); + const storagePath = await mkdtemp(join(tmpdir(), "rivet-workflows-e2e-")); + const previousStoragePath = process.env.RIVETKIT_STORAGE_PATH; + process.env.RIVETKIT_STORAGE_PATH = storagePath; + const registry = setup({ + use: { sleepAcrossWake }, + startEngine: true, + engineHost: "127.0.0.1", + enginePort, + shutdown: { + disableSignalHandlers: true, + gracePeriodMs: 5_000, + }, + }); + let cleanedUp = false; + const cleanup = async () => { + if (cleanedUp) return; + cleanedUp = true; + await registry.shutdown(); + await stopTestEngine(storagePath); + if (previousStoragePath === undefined) { + delete process.env.RIVETKIT_STORAGE_PATH; + } else { + process.env.RIVETKIT_STORAGE_PATH = previousStoragePath; + } + await rm(storagePath, { recursive: true, force: true }); + }; + context.onTestFinished(cleanup); + + try { + const { client } = await setupTest(context, registry); + const handle = client.sleepAcrossWake.getOrCreate(["preview-e2e"]); + const deadline = Date.now() + 10_000; + let completed: string[] = []; + + while (Date.now() < deadline) { + completed = await handle.getCompleted(); + if (completed.includes("after-sleep")) break; + await new Promise((resolve) => setTimeout(resolve, 25)); + } + + expect(completed).toEqual(["before-sleep", "after-sleep"]); + await new Promise((resolve) => setTimeout(resolve, 150)); + expect(await handle.getCompleted()).toEqual([ + "before-sleep", + "after-sleep", + ]); + } finally { + await cleanup(); + } }); diff --git a/packages/workflows/tests/rivetkit/inspector.test.ts b/packages/workflows/tests/rivetkit/inspector.test.ts index 38f44c0..b93f8d6 100644 --- a/packages/workflows/tests/rivetkit/inspector.test.ts +++ b/packages/workflows/tests/rivetkit/inspector.test.ts @@ -23,7 +23,13 @@ describe("workflow Inspector adapter", () => { test("delegates state and replay through actor-bound callbacks", async () => { const inspector = createWorkflowInspectorAdapter(); - const history = new Uint8Array([1, 2, 3]).buffer; + inspector.update({ + nameRegistry: [], + entries: [], + entryMetadata: new Map(), + }); + const history = inspector.adapter.getHistory(); + if (!history) throw new Error("expected encoded workflow history"); const replay = vi.fn(async () => history); inspector.setGetState(async () => "sleeping"); inspector.setReplayFromStep(replay); diff --git a/packages/workflows/tests/rivetkit/types.test.ts b/packages/workflows/tests/rivetkit/types.test.ts index d747437..06966c2 100644 --- a/packages/workflows/tests/rivetkit/types.test.ts +++ b/packages/workflows/tests/rivetkit/types.test.ts @@ -1,6 +1,6 @@ import { type AnyActorDefinition, queue } from "rivetkit"; import type { ActorHandle } from "rivetkit/client"; -import type { RawAccess } from "rivetkit/db"; +import type { DatabaseProvider, RawAccess } from "rivetkit/db"; import { describe, expectTypeOf, test } from "vitest"; import { type WorkflowContextOf, @@ -35,9 +35,25 @@ type HasWorkflowAction = ? true : false; -function customDatabaseIsRejected() { +const customDatabase: DatabaseProvider = { + createClient: async () => { + throw new Error("type-only database provider"); + }, + onMigrate: async () => {}, +}; + +const customDatabaseDefinition = workflow({ + db: customDatabase, + run: async (ctx) => { + await ctx.step("custom-database", async (step) => { + expectTypeOf(step.db).toEqualTypeOf(); + }); + }, +}); + +function invalidDatabaseIsRejected() { workflow({ - // @ts-expect-error Workflows requires RivetKit's standard embedded database. + // @ts-expect-error Workflows requires a valid RivetKit database provider. db: {}, run: async () => {}, }); @@ -53,6 +69,7 @@ describe("workflow actor types", () => { expectTypeOf< WorkflowStepContextOf["state"] >().toEqualTypeOf<{ count: number }>(); - expectTypeOf(customDatabaseIsRejected).toBeFunction(); + expectTypeOf(customDatabaseDefinition).toMatchTypeOf(); + expectTypeOf(invalidDatabaseIsRejected).toBeFunction(); }); }); diff --git a/packages/workflows/tests/rivetkit/workflow.test.ts b/packages/workflows/tests/rivetkit/workflow.test.ts index 278ec95..57325c7 100644 --- a/packages/workflows/tests/rivetkit/workflow.test.ts +++ b/packages/workflows/tests/rivetkit/workflow.test.ts @@ -1,10 +1,72 @@ import { describe, expect, test, vi } from "vitest"; import { workflow } from "../../src/rivetkit/mod"; import { getDefinedRunHandlerOptions } from "../fixtures/rivetkit"; -import { createTestDatabase } from "../fixtures/rivetkit-db"; + +function compareBytes(a: Uint8Array, b: Uint8Array): number { + for (let index = 0; index < Math.min(a.length, b.length); index++) { + if (a[index] !== b[index]) return a[index] - b[index]; + } + return a.length - b.length; +} + +type Write = { key: Uint8Array; value: Uint8Array }; +type TestDb = { + execute: (sql: string, ...params: Uint8Array[]) => Promise; + transaction: ( + callback: (tx: TestDb) => Promise, + options?: unknown, + ) => Promise; +}; function createRunContext() { - const { db, rows } = createTestDatabase(); + const rows = new Map(); + const keyOf = (key: Uint8Array) => Buffer.from(key).toString("hex"); + const apply = (writes: Write[]) => { + for (const write of writes) { + rows.set(keyOf(write.key), write); + } + }; + const db: TestDb = { + execute: async (sql: string, ...params: Uint8Array[]) => { + if (sql.startsWith("SELECT value")) { + const row = rows.get(keyOf(params[0])); + return row ? [{ value: row.value }] : []; + } + if (sql.startsWith("SELECT key, value")) { + return [...rows.values()] + .filter( + (row) => + compareBytes(row.key, params[0]) >= 0 && + (params[1] === undefined || compareBytes(row.key, params[1]) < 0), + ) + .sort((a, b) => compareBytes(a.key, b.key)); + } + if (sql.startsWith("INSERT INTO")) { + apply([{ key: params[0], value: params[1] }]); + return []; + } + if (sql.includes("key >= ? AND key < ?")) { + for (const [key, row] of rows) { + if ( + compareBytes(row.key, params[0]) >= 0 && + compareBytes(row.key, params[1]) < 0 + ) { + rows.delete(key); + } + } + return []; + } + if (sql.includes("key = ?")) { + rows.delete(keyOf(params[0])); + return []; + } + throw new Error(`Unsupported test SQL: ${sql}`); + }, + transaction: async ( + callback: (tx: typeof db) => Promise, + _options?: unknown, + ) => await callback(db), + }; const waitUntil: Promise[] = []; const setWakeAt = vi.fn(async () => {}); return { @@ -39,30 +101,72 @@ function createRunContext() { } describe("workflow RivetKit integration", () => { - test("returns an actor definition, forwards config, and disposes Inspector state", async () => { - const step = vi.fn(async () => "done"); + test("creates a full actor definition from a workflow config", () => { const definition = workflow({ state: { count: 0 }, + run: async (ctx) => { + await ctx.step("increment", async (step) => { + step.state.count += 1; + }); + }, actions: { getCount: (ctx) => ctx.state.count, }, - options: { sleepTimeout: 250 }, - run: async (ctx) => { - await ctx.step("once", step); + options: { + sleepTimeout: 20, }, }); - expect(definition).toEqual({ - config: expect.objectContaining({ - state: { count: 0 }, - actions: expect.any(Object), - options: { sleepTimeout: 250 }, - run: expect.any(Function), + const config = definition.config as unknown as { + state: { count: number }; + actions: { getCount: (ctx: unknown) => number }; + options: { sleepTimeout: number }; + run: (...args: any[]) => any; + }; + + expect(config.state).toEqual({ count: 0 }); + expect(config.actions.getCount).toBeTypeOf("function"); + expect(config.options.sleepTimeout).toBe(20); + expect(getDefinedRunHandlerOptions(config.run)).toMatchObject({ + inspectorKind: "workflow", + }); + }); + + test("preserves actor lifecycle and connection configuration", () => { + const definition = workflow({ + types: {} as { state: { count: number } }, + createState: (_ctx, input: { seed: number }) => ({ + count: input.seed, }), + createConnState: (_ctx, params: { token: string }) => ({ + token: params.token, + }), + createVars: () => ({ transientCount: 0 }), + onCreate: (ctx, input) => { + ctx.state.count = input.seed; + }, + onConnect: (ctx, conn) => { + ctx.vars.transientCount += conn.state.token.length; + }, + run: async (ctx) => { + await ctx.step("typed-context", async (step) => { + step.state.count += step.vars.transientCount; + }); + }, + actions: { + getCount: (ctx) => ctx.state.count, + }, + }); + + expect(definition.config.onCreate).toBeTypeOf("function"); + expect(definition.config.onConnect).toBeTypeOf("function"); + expect(definition.config).not.toHaveProperty("types"); + }); + + test("publishes static Inspector metadata and disposes actor state", async () => { + const step = vi.fn(async () => "done"); + const run = workflow(async (ctx) => { + await ctx.step("once", step); }); - const run = definition.config.run; - if (typeof run !== "function") { - throw new Error("workflow actor did not install a run handler"); - } const options = getDefinedRunHandlerOptions(run); expect(options.inspectorKind).toBe("workflow"); @@ -95,13 +199,4 @@ describe("workflow RivetKit integration", () => { }); expect(nextRegistration.inspector.workflow).not.toBe(firstAdapter); }); - - test("rejects a custom database provider", () => { - expect(() => - workflow({ - run: async () => {}, - db: {}, - } as never), - ).toThrow("workflow() does not support a custom database provider"); - }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce645aa..8d1b7a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,8 +49,8 @@ importers: specifier: npm:@rivetkit/workflow-engine@2.3.7 version: '@rivetkit/workflow-engine@2.3.7' rivetkit: - specifier: 0.0.0-feat-workflows-public-host-apis.1550fe4 - version: 0.0.0-feat-workflows-public-host-apis.1550fe4(better-sqlite3@12.11.1) + specifier: 2.3.11 + version: 2.3.11(better-sqlite3@12.11.1) tsup: specifier: ^8.4.0 version: 8.5.1(postcss@8.5.26)(tsx@4.23.12)(typescript@5.9.3)(yaml@2.9.0) @@ -542,8 +542,8 @@ packages: resolution: {integrity: sha512-3qndQUQXLdwafMEqfhz24hUtDPcsf1Bu3q52Kb8MqeH8JUh3h6R4HYW3ZJXiQsLcyYyFM68PuIwlLRlg1xDEpg==} engines: {node: ^14.18.0 || >=16.0.0} - '@rivetkit/engine-cli-darwin-arm64@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-MTbiOkotK5lfu3U0sPawrZvcU9ImMNul2hmHgl/3eWJxo7lrvbwq47Eh9AN0g1PSquG1tnwENgIVxV0D9cI0Eg==} + '@rivetkit/engine-cli-darwin-arm64@2.3.11': + resolution: {integrity: sha512-cooLx87XVvBhkZISX5gw5CezO5RLrEWEwZK7xNZjJJ/OQqi6CsZLlNFkANiWcPDHXAAlx2nEQs3+bakgvMle/A==} engines: {node: '>= 20.0.0'} cpu: [arm64] os: [darwin] @@ -554,8 +554,8 @@ packages: cpu: [arm64] os: [darwin] - '@rivetkit/engine-cli-darwin-x64@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-3ZtmB9kn4LPLa4GFGNXbrFIJt+3w1/3OE/q67NIX71+QSGiiIqOfiVDomhEI8CWc+m5TXl9bpuNrR1gb/x0dxA==} + '@rivetkit/engine-cli-darwin-x64@2.3.11': + resolution: {integrity: sha512-mUoPkJa2NMbUDS9XnbXEzH4z45R2HK1j/mgGa5XTIIvLYWz/OsXpS3NcWnAn2AUE9Mi19HOhDHLYEjD7AJlSkw==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [darwin] @@ -566,8 +566,8 @@ packages: cpu: [x64] os: [darwin] - '@rivetkit/engine-cli-linux-arm64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-ZZiVwFbk3uewKr2pvRxFtjOwmfhgmr1MJIdPcAJiC45gqGUbYS08Q6dwmXROl/kDy+Md5dSRoNxxAHYNRN0LQg==} + '@rivetkit/engine-cli-linux-arm64-musl@2.3.11': + resolution: {integrity: sha512-ARnFeoSf0MbNQaB8XUI1OymwUdFKktoW3piN44bazZxJaKvsgJx7aja0KuwI12mNQOLVU0FYtY3awKGXvVLW0A==} engines: {node: '>= 20.0.0'} cpu: [arm64] os: [linux] @@ -578,8 +578,8 @@ packages: cpu: [arm64] os: [linux] - '@rivetkit/engine-cli-linux-x64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-tBMnqAIEr1CcPBTZBVhXm6/i8Oisax0U1DFJz3WSzpziYbeRkwmQNIk19hLr2aEmT9tEYtEmtGaKx1bUlbjC2w==} + '@rivetkit/engine-cli-linux-x64-musl@2.3.11': + resolution: {integrity: sha512-sVP5vzJ4tiyfkt/4yT+OQnpNeGZ4I51geXgr4u9Al5eh0Oi3lJaui4Kj5sApoOejrhhJu9D/AkYilyTGRBvEMQ==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [linux] @@ -590,22 +590,28 @@ packages: cpu: [x64] os: [linux] + '@rivetkit/engine-cli-win32-x64@2.3.11': + resolution: {integrity: sha512-S7v3kHgiEcBsya5/BLNTmcbFBSkO6JSBs8dvp1K7xiGVLjQtlZeot8pxsBPpGftvxIuq7I/nAMxQxO2LdQUriA==} + engines: {node: '>= 20.0.0'} + cpu: [x64] + os: [win32] + '@rivetkit/engine-cli-win32-x64@2.3.7': resolution: {integrity: sha512-jyA5PlHivHXyyq2ehnuXwxd5TUSbB4emomnph9EovsJo7qIdmSNaaCO13NYBT483fd0uXiNI0MK/lkJa9ePY5A==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [win32] - '@rivetkit/engine-cli@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-4sX1lGT85JX59xzZL0FOrzBoydm0TmtN4fiVrDsh0AhW5i40Dz2yXFm4DLXcDqSzGH2Ak1uJIygRovRPTyxNmg==} + '@rivetkit/engine-cli@2.3.11': + resolution: {integrity: sha512-nT4pFT12gIqPuyBR/LD/R8mlze7AxMh/NpUldOXEs3wWqSU+WDE2UwMjv/DV6VVupGC4oZG2IlUn082j3/YHWA==} engines: {node: '>= 20.0.0'} '@rivetkit/engine-cli@2.3.7': resolution: {integrity: sha512-CezLwJ0B7dWDbA7qM6Aq04mwnrJAdrDActRrrcb4NBa20h7wO9KPAYBwyJz/dRnKm9EUUNcFZ6hrSDpp6T3+Rg==} engines: {node: '>= 20.0.0'} - '@rivetkit/engine-envoy-protocol@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-OPc3ycQYt0ClNPPaOmQHtpB/1rUTHHIeZP545hUsR4pFpDNpWehnxa/ozoT4DTHnX1kcAXGQ1UfPRx1Vq2OLbw==} + '@rivetkit/engine-envoy-protocol@2.3.11': + resolution: {integrity: sha512-PDDCqj9Y5OOpIVJiDwPLXCCawvKfzvUCxzUOxor+K7ubv9U5kriYABxHUdxga4nhbFnhQct/RSZmy4jnAhieyA==} '@rivetkit/engine-envoy-protocol@2.3.7': resolution: {integrity: sha512-lsJM3ERwozQCebaOMKJzqIQlcLbbN3LXurRB0+7LsM6FUUL2l6hMoq5I2De/G35DJ6OWDva9AmzfvzI+5f1GPg==} @@ -614,8 +620,8 @@ packages: resolution: {integrity: sha512-QBN/KRBXLJdCgN4gBTL3XAc/zKm58atSnieXWMOyFSPmo6F1/yIVV/LTRdvAktfCttrGx7W6c32i/lwqCHWnsQ==} engines: {node: '>=20'} - '@rivetkit/rivetkit-napi-darwin-arm64@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-P3AZ+/aAae/qe/uz5BK1gLuCpkL1daC4GBaqBgaDNVt0RoEygSYV09dbNtdS5ZaP2tknT4k3SiMwYBUgicI0UA==} + '@rivetkit/rivetkit-napi-darwin-arm64@2.3.11': + resolution: {integrity: sha512-gcUNpWoxKnSWFI978yePOmR6Ne6MoF99toRqqzUjEFmYhF7Y2em87YqqpRq1hVycsaWQxg/B0JTTVZo4pDEyzQ==} engines: {node: '>= 20.0.0'} cpu: [arm64] os: [darwin] @@ -626,8 +632,8 @@ packages: cpu: [arm64] os: [darwin] - '@rivetkit/rivetkit-napi-darwin-x64@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-KHZofYS2KMlrtfMdRmW0nG1BBwDhlGIOAisyhz2+YSSGZxrHa3M+RQe0F2LAJtHQMNnuI6EkusqPuBVw5LyCpg==} + '@rivetkit/rivetkit-napi-darwin-x64@2.3.11': + resolution: {integrity: sha512-eGYqvIcPAODZA3KZgErHzv0ByeJRinrTu895qIN8tXdmivVehExoxXBSrmFrLsK58cYy5yigon1txzE1NcudSA==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [darwin] @@ -638,8 +644,8 @@ packages: cpu: [x64] os: [darwin] - '@rivetkit/rivetkit-napi-linux-arm64-gnu@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-UgXT77vT7PjepfHNbPaWgwy1foMsThZ2MfsY9neRS5DV9ofrWExg924G6HQ81gwTY4rlRyokjaH1B5ISX4wf3A==} + '@rivetkit/rivetkit-napi-linux-arm64-gnu@2.3.11': + resolution: {integrity: sha512-2xu+f9w/DolzMPf3k3wjH+h4/YAxeapb9tJP7U/zONgsq8kiCBx9p0o2weijutpBoQs7thfIyYx0WcIl3UQEVQ==} engines: {node: '>= 20.0.0'} cpu: [arm64] os: [linux] @@ -650,8 +656,8 @@ packages: cpu: [arm64] os: [linux] - '@rivetkit/rivetkit-napi-linux-arm64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-ADfyga+4Nvh5vqrgaPVFaV04QChH0Ttt1pO1IAuZ0m1r38c1PhvD3rYndQzQvJk1uKUDWQy3/tDEgLM3712IGA==} + '@rivetkit/rivetkit-napi-linux-arm64-musl@2.3.11': + resolution: {integrity: sha512-W3vcXDc26zIEHRkpl+B3FNoZ16wraf08c7PGF5wlctH8Pb0bGdLPi7zr6jvJ7nalEVP5twCJO6D3z3YbWYgtqA==} engines: {node: '>= 20.0.0'} cpu: [arm64] os: [linux] @@ -662,8 +668,8 @@ packages: cpu: [arm64] os: [linux] - '@rivetkit/rivetkit-napi-linux-x64-gnu@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-ynTOHBnihwt6lLBYvwZ1zhN9y0CoSfb9IMjnshz60f0p2BF/SRK2Z3umjydcTegHHrwd30Raxwg9ALP+SKgfrg==} + '@rivetkit/rivetkit-napi-linux-x64-gnu@2.3.11': + resolution: {integrity: sha512-QyOANKzvEr6IzrgQGdJyP2fbdCxrm+pH/qfnf3I08JVMmUV38DCkC+1/vu+Twtfa3kpb3Dqa/Q5KpVsH5Ur/GQ==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [linux] @@ -674,8 +680,8 @@ packages: cpu: [x64] os: [linux] - '@rivetkit/rivetkit-napi-linux-x64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-0lg3LkT392VoCpTBwkVzJvtHC5sMDLydMCCkHGTScBvVzn3NgG5ILPTfcNiufmJzPzMcNXH77Aji2ed4JRgsmA==} + '@rivetkit/rivetkit-napi-linux-x64-musl@2.3.11': + resolution: {integrity: sha512-0k6TUxhLYGHni1etmqdIVz9b7hnI4kN+i8DVhy2ViROrc9PTpi8YHCdrHp9HWvyo6U6PN91lj8Bx9K3tpngUmg==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [linux] @@ -686,42 +692,48 @@ packages: cpu: [x64] os: [linux] + '@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.11': + resolution: {integrity: sha512-1/GC4DCvf8DtsmCVK1LInMSrKCg5U7xjDAqRiPDOn0unxLQ5TYlubINPJ+XmkmavVi9ep+30KgElupBsBXY/uQ==} + engines: {node: '>= 20.0.0'} + cpu: [x64] + os: [win32] + '@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.7': resolution: {integrity: sha512-n1by/coKxWOb2FZDGLM2qmULxcLSqx8hxJuk7Hsb1gl4uNHGviUzYr+r7WAiOzonK/Dgy477u3OKf5yBie743A==} engines: {node: '>= 20.0.0'} cpu: [x64] os: [win32] - '@rivetkit/rivetkit-napi@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-7RS0mXek3iPkSyOXMLIfvXQM6hO0+tVXrmkkxVd7ES16sMm3l4tFydVyr5pkkVJCFpFiRxGVhFIHRO6kDd/Jhw==} + '@rivetkit/rivetkit-napi@2.3.11': + resolution: {integrity: sha512-rgnD1V7oCU5iVOHsDmgdGEPB7CgfRU38ctbaaeAOfddK+M/UVD4lcfpQ7SdUB+VQ9hFVyYLUgbaQWQLWSYJR8g==} engines: {node: '>= 20.0.0'} '@rivetkit/rivetkit-napi@2.3.7': resolution: {integrity: sha512-1d3HtNKzJwdkznWDWSpCwg1rBn+nVwUfcKrApINTfiEhfDyVeznwbVFkfHWqOBHsjU17vvWFfjjTtf8QsjLwUQ==} engines: {node: '>= 20.0.0'} - '@rivetkit/rivetkit-wasm@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-dgvhv5CyU+dKNqPfLn5SXvBdkKsDRILGweqGqcLSN/bpq8jqqhCh2lsdyrOsxtPsH3SaRiAGltbVJIsib0fj5g==} + '@rivetkit/rivetkit-wasm@2.3.11': + resolution: {integrity: sha512-Wtk9KPkS0vC0Od640dNDxkhDd2yzLaw9bdMc52+Ej8OGK/zFUV7HoSL3IU+Qyxj6HPT4HiBhi+xfpIAnR6T4iA==} '@rivetkit/rivetkit-wasm@2.3.7': resolution: {integrity: sha512-o7QBtFOJrajyPVBIDQ32k8sDNFsUc8v2ETfNpr+Ch374ydmZMzCv3XKJU9vubc9bZa7WpCHSzf5ztc8b8i/Xpg==} - '@rivetkit/traces@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-FD0n7nq+Lr5jyhbyEenXTtLqDZgCivtL7K+r9x7OpXzgaWUSYtNQy52aEmyq7Tkn4Eb96R5Qyx9DH6ld9kzOuA==} + '@rivetkit/traces@2.3.11': + resolution: {integrity: sha512-44lTLApHUqAv+kjDj6MkbC/Wq7mj1CJfRncXOc93ycLxkftFafEldX5A6P0hu0jQ/KHXZXNwKR7D+fNusAZYaQ==} engines: {node: '>=18.0.0'} '@rivetkit/traces@2.3.7': resolution: {integrity: sha512-B7QYjFP2HPxyfPsVjfcNIV7FPLWgGWGypmlT/dZM1i1Cf1WRdeuBumPLffgs3YceiY7Pm4D/gZZVt5p0m4Cx+A==} engines: {node: '>=18.0.0'} - '@rivetkit/virtual-websocket@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-5HTt7AoJWGk8jYI2aIHSckLd80mt1jjIxbp4zvPlLfOCd9wyIKstUZABhLyDj0v3rh8mBznwGiGffjKMg88g1Q==} + '@rivetkit/virtual-websocket@2.3.11': + resolution: {integrity: sha512-3NtJvpnyadQKS2lzFE1SwWzSjfir3RHXcB/V3m+WVlZ1lfvOsmGoLIa8n6R05261T3sZcza1k08y0UWiG9kSQw==} '@rivetkit/virtual-websocket@2.3.7': resolution: {integrity: sha512-jwxDvYbr3YB6vFuxwRdB/AqUUMwdtC1rIAc4tNN6VQR3weHbE+PrDoHKbe85zrtlBtcnG89/p8tlovrj8qyQWA==} - '@rivetkit/workflow-engine@0.0.0-feat-workflows-public-host-apis.1550fe4': - resolution: {integrity: sha512-4zAeBLBC5Nh0OVSfm7j/SF9KSN4BOfEDO50bOpgDpKZ+lMohRQ0VX9Ob7Yq036B3T9JIlGVcW4gv9gs9coK9AQ==} + '@rivetkit/workflow-engine@2.3.11': + resolution: {integrity: sha512-SLzk1tQzry0Ds052eK9+6IMtq/RaSBc30AbdUWOUnQz56hojCSgkZMUTJA8ATIaqwDwqqhsY37AkWTR1JP8Pfg==} engines: {node: '>=18.0.0'} '@rivetkit/workflow-engine@2.3.7': @@ -1742,8 +1754,8 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} - rivetkit@0.0.0-feat-workflows-public-host-apis.1550fe4: - resolution: {integrity: sha512-3wGq2SHOfMbBphCNup/JutzdeMjugYhE12j+3ZFPGroox/KtMrrfij3412DrpoZkGP5MMWyYBbnffLmI6kBz0Q==} + rivetkit@2.3.11: + resolution: {integrity: sha512-19JDIQoff7Es3t2GlQPv5vA7TvnzCanuAkJbO+ODr46UeOZ4Y0hHqiTZWXghdFU+urxqf7YkvcYUHBLcWtKo8g==} engines: {node: '>=22.0.0'} peerDependencies: drizzle-kit: ^0.31.2 @@ -2403,39 +2415,43 @@ snapshots: '@rivetkit/bare-ts@0.6.2': {} - '@rivetkit/engine-cli-darwin-arm64@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/engine-cli-darwin-arm64@2.3.11': optional: true '@rivetkit/engine-cli-darwin-arm64@2.3.7': optional: true - '@rivetkit/engine-cli-darwin-x64@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/engine-cli-darwin-x64@2.3.11': optional: true '@rivetkit/engine-cli-darwin-x64@2.3.7': optional: true - '@rivetkit/engine-cli-linux-arm64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/engine-cli-linux-arm64-musl@2.3.11': optional: true '@rivetkit/engine-cli-linux-arm64-musl@2.3.7': optional: true - '@rivetkit/engine-cli-linux-x64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/engine-cli-linux-x64-musl@2.3.11': optional: true '@rivetkit/engine-cli-linux-x64-musl@2.3.7': optional: true + '@rivetkit/engine-cli-win32-x64@2.3.11': + optional: true + '@rivetkit/engine-cli-win32-x64@2.3.7': optional: true - '@rivetkit/engine-cli@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/engine-cli@2.3.11': optionalDependencies: - '@rivetkit/engine-cli-darwin-arm64': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/engine-cli-darwin-x64': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/engine-cli-linux-arm64-musl': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/engine-cli-linux-x64-musl': 0.0.0-feat-workflows-public-host-apis.1550fe4 + '@rivetkit/engine-cli-darwin-arm64': 2.3.11 + '@rivetkit/engine-cli-darwin-x64': 2.3.11 + '@rivetkit/engine-cli-linux-arm64-musl': 2.3.11 + '@rivetkit/engine-cli-linux-x64-musl': 2.3.11 + '@rivetkit/engine-cli-win32-x64': 2.3.11 '@rivetkit/engine-cli@2.3.7': optionalDependencies: @@ -2445,7 +2461,7 @@ snapshots: '@rivetkit/engine-cli-linux-x64-musl': 2.3.7 '@rivetkit/engine-cli-win32-x64': 2.3.7 - '@rivetkit/engine-envoy-protocol@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/engine-envoy-protocol@2.3.11': dependencies: '@rivetkit/bare-ts': 0.6.2 @@ -2455,56 +2471,60 @@ snapshots: '@rivetkit/on-change@6.0.1': {} - '@rivetkit/rivetkit-napi-darwin-arm64@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi-darwin-arm64@2.3.11': optional: true '@rivetkit/rivetkit-napi-darwin-arm64@2.3.7': optional: true - '@rivetkit/rivetkit-napi-darwin-x64@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi-darwin-x64@2.3.11': optional: true '@rivetkit/rivetkit-napi-darwin-x64@2.3.7': optional: true - '@rivetkit/rivetkit-napi-linux-arm64-gnu@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi-linux-arm64-gnu@2.3.11': optional: true '@rivetkit/rivetkit-napi-linux-arm64-gnu@2.3.7': optional: true - '@rivetkit/rivetkit-napi-linux-arm64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi-linux-arm64-musl@2.3.11': optional: true '@rivetkit/rivetkit-napi-linux-arm64-musl@2.3.7': optional: true - '@rivetkit/rivetkit-napi-linux-x64-gnu@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi-linux-x64-gnu@2.3.11': optional: true '@rivetkit/rivetkit-napi-linux-x64-gnu@2.3.7': optional: true - '@rivetkit/rivetkit-napi-linux-x64-musl@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi-linux-x64-musl@2.3.11': optional: true '@rivetkit/rivetkit-napi-linux-x64-musl@2.3.7': optional: true + '@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.11': + optional: true + '@rivetkit/rivetkit-napi-win32-x64-msvc@2.3.7': optional: true - '@rivetkit/rivetkit-napi@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/rivetkit-napi@2.3.11': dependencies: '@napi-rs/cli': 2.18.4 - '@rivetkit/engine-envoy-protocol': 0.0.0-feat-workflows-public-host-apis.1550fe4 + '@rivetkit/engine-envoy-protocol': 2.3.11 optionalDependencies: - '@rivetkit/rivetkit-napi-darwin-arm64': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/rivetkit-napi-darwin-x64': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/rivetkit-napi-linux-arm64-gnu': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/rivetkit-napi-linux-arm64-musl': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/rivetkit-napi-linux-x64-gnu': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/rivetkit-napi-linux-x64-musl': 0.0.0-feat-workflows-public-host-apis.1550fe4 + '@rivetkit/rivetkit-napi-darwin-arm64': 2.3.11 + '@rivetkit/rivetkit-napi-darwin-x64': 2.3.11 + '@rivetkit/rivetkit-napi-linux-arm64-gnu': 2.3.11 + '@rivetkit/rivetkit-napi-linux-arm64-musl': 2.3.11 + '@rivetkit/rivetkit-napi-linux-x64-gnu': 2.3.11 + '@rivetkit/rivetkit-napi-linux-x64-musl': 2.3.11 + '@rivetkit/rivetkit-napi-win32-x64-msvc': 2.3.11 '@rivetkit/rivetkit-napi@2.3.7': dependencies: @@ -2519,11 +2539,11 @@ snapshots: '@rivetkit/rivetkit-napi-linux-x64-musl': 2.3.7 '@rivetkit/rivetkit-napi-win32-x64-msvc': 2.3.7 - '@rivetkit/rivetkit-wasm@0.0.0-feat-workflows-public-host-apis.1550fe4': {} + '@rivetkit/rivetkit-wasm@2.3.11': {} '@rivetkit/rivetkit-wasm@2.3.7': {} - '@rivetkit/traces@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/traces@2.3.11': dependencies: '@rivetkit/bare-ts': 0.6.2 cbor-x: 1.6.5 @@ -2537,11 +2557,11 @@ snapshots: fdb-tuple: 1.0.0 vbare: 0.0.4 - '@rivetkit/virtual-websocket@0.0.0-feat-workflows-public-host-apis.1550fe4': {} + '@rivetkit/virtual-websocket@2.3.11': {} '@rivetkit/virtual-websocket@2.3.7': {} - '@rivetkit/workflow-engine@0.0.0-feat-workflows-public-host-apis.1550fe4': + '@rivetkit/workflow-engine@2.3.11': dependencies: '@rivetkit/bare-ts': 0.6.2 cbor-x: 1.6.5 @@ -3582,19 +3602,19 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rivetkit@0.0.0-feat-workflows-public-host-apis.1550fe4(better-sqlite3@12.11.1): + rivetkit@2.3.11(better-sqlite3@12.11.1): dependencies: '@hono/zod-openapi': 1.6.1(hono@4.13.4)(zod@4.4.3) '@rivet-dev/agent-os-core': 0.1.1 '@rivetkit/bare-ts': 0.6.2 - '@rivetkit/engine-cli': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/engine-envoy-protocol': 0.0.0-feat-workflows-public-host-apis.1550fe4 + '@rivetkit/engine-cli': 2.3.11 + '@rivetkit/engine-envoy-protocol': 2.3.11 '@rivetkit/on-change': 6.0.1 - '@rivetkit/rivetkit-napi': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/rivetkit-wasm': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/traces': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/virtual-websocket': 0.0.0-feat-workflows-public-host-apis.1550fe4 - '@rivetkit/workflow-engine': 0.0.0-feat-workflows-public-host-apis.1550fe4 + '@rivetkit/rivetkit-napi': 2.3.11 + '@rivetkit/rivetkit-wasm': 2.3.11 + '@rivetkit/traces': 2.3.11 + '@rivetkit/virtual-websocket': 2.3.11 + '@rivetkit/workflow-engine': 2.3.11 cbor-x: 1.6.5 drizzle-orm: 0.44.7(better-sqlite3@12.11.1) hono: 4.13.4 diff --git a/scripts/verify-pack.ts b/scripts/verify-pack.ts index df60663..bddd495 100644 --- a/scripts/verify-pack.ts +++ b/scripts/verify-pack.ts @@ -59,7 +59,7 @@ try { "packed manifest contains an unresolved workspace/catalog specifier", ); } - if (manifest.peerDependencies?.rivetkit !== ">=2.4.0 <3") { + if (manifest.peerDependencies?.rivetkit !== ">=2.3.11 <2.4.0") { throw new Error("packed manifest has the wrong RivetKit peer range"); } if (manifest.dependencies?.rivetkit) { @@ -125,8 +125,9 @@ try { await writeFile( join(fixture, "smoke.ts"), [ - 'import { workflow } from "@rivet-dev/workflows";', + 'import { actor, setup, workflow } from "@rivet-dev/workflows";', 'import { InMemoryDriver } from "@rivet-dev/workflows/testing";', + "const worker = actor({ actions: { ping: () => 'pong' } });", "const definition = workflow({", " state: { count: 0 },", " actions: { getCount: (c) => c.state.count },", @@ -139,7 +140,8 @@ try { " });", " },", "});", - "void definition; void new InMemoryDriver();", + "const registry = setup({ use: { definition, worker } });", + "void registry; void new InMemoryDriver();", ].join("\n"), ); await writeFile(