Skip to content

Examples: Human Approval Flow

Suspend workflow execution for human sign-off, inspect the wait boundary, and submit a schema-validated decision. Replace the local slack stub with your application-owned client.

ts
import { invariant } from "@invariant-tech/sdk";
import { sqlite } from "@invariant-tech/sqlite";
import { z } from "zod";

type ApprovalDecision = {
  approved: boolean;
  approverId: string;
};

const slack = {
  postMessage: async (message: string) => console.log(message),
};

const app = invariant({ storage: sqlite("./data/approval.db") });
const ApprovalInputSchema = z.object({
  approved: z.boolean(),
  approverId: z.string(),
});

export const humanApproval = app.workflow("human-approval")
  .capability("notify-slack", {
    idempotencyKey: "approval-request:{{runId}}",
    handler: async () => {
      await slack.postMessage("Approval requested");
      return { notified: true };
    },
  })
  .wait<ApprovalDecision>("wait-approval", {
    schema: ApprovalInputSchema,
  })
  .step("record-decision", ({ state }) => ({
    finalStatus: state.approved ? "APPROVED" as const : "REJECTED" as const,
    approvedBy: state.approverId,
  }));

async function main() {
  const session = await app.sessions.loadOrCreateSession("sess_approval_1", "usr_requester_1");
  await session.startWorkflow(humanApproval, {});

  console.log(session.snapshot().activeWorkflow?.status); // waiting_input
  await session.submitInput({ approved: true, approverId: "mgr_42" });
  console.log(session.snapshot().projectedState.finalStatus); // APPROVED
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Invalid input rejects with WaitInputValidationError and leaves the workflow at the same wait boundary. In a real Slack integration, authenticate the callback, restore the owned durable Session if necessary, and pass the normalized payload to submitInput(). A registered graph paused at .wait() can reattach after restart; interrupted capability work is not automatically redispatched.

Next Steps

Invariant Durable Execution Engine.