Generate a workflow

Add a background workflow that survives restarts. Generates src/lib/workflows/<name>.ts with a workflow defined through ow.defineWorkflow, a Zod schema for its input, a retry policy, and a first step to build on, plus a server test that runs it to completion. Start a run from any server code — a form action, an API route, or another workflow — with .run(input). Every step's result is saved, so an interrupted run resumes from the last completed step, and runs are listed under Workflows in the PocketBase dashboard. Pass --cron with a five-field schedule to make the workflow recurring, once per minute across all servers. Projects created before workflows shipped in the base template need vela enable workflows first.

$ vela generate workflow
src/lib/workflows/send-welcome-email.ts
import { z } from "zod";
import { ow } from "$lib/server/workflows";

/**
 * Start a run from any server code with `sendWelcomeEmail.run(input)`. Runs
 * are listed under Workflows in the PocketBase dashboard.
 */
export const sendWelcomeEmail = ow.defineWorkflow(
  {
    name: "send-welcome-email",
    // What `run()` takes, checked before the run is queued.
    schema: z.object({}),
    retryPolicy: { maximumAttempts: 3 },
  },
  async ({ input, step }) => {
    // Each step's return value is saved, so a retry or a restart carries on
    // after the last step that finished. Keep every step safe to repeat.
    const result = await step.run({ name: "first-step" }, async () => {
      return input;
    });
    return result;
  },
);
src/lib/workflows/send-welcome-email.server.test.ts
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { startWorker, stopWorker } from "$lib/server/workflows";
import { sendWelcomeEmail } from "./send-welcome-email";

describe("send-welcome-email", () => {
  // The test process runs a worker of its own, so a run completes here
  // without going through the dev server.
  beforeAll(() => startWorker());
  afterAll(() => stopWorker());

  it("completes", async () => {
    const handle = await sendWelcomeEmail.run({});
    await expect(handle.result({ timeoutMs: 15_000 })).resolves.toEqual({});
  });
});