Anchorage API reference
    Preparing search index...
    interface RunRouterOptions {
        beforeResume?: (
            context: ActorContext,
            workflowId: string,
            runId: string,
            body: unknown,
        ) => Promise<void>;
        beforeStart?: (
            context: ActorContext,
            workflowId: string,
            inputData: unknown,
        ) => Promise<void>;
        reconcileApprovals?: (
            context: ActorContext,
            workflowId: string,
            summary: RunSummary,
        ) => Promise<void>;
        resolve: ActorResolver;
        resume: (
            workflowId: string,
            runId: string,
            body: unknown,
            requestedBy: string,
            requestedByKind: "human" | "service" | "agent" | "system",
        ) => Promise<RunSummary>;
        start: (input: RunStartInput) => Promise<RunSummary>;
        startIdempotency: RunRouterStartIdempotency;
        status: (
            workflowId: string,
            runId: string,
        ) => Promise<RunSummary | undefined>;
        systemPrincipalId?: string;
        terminate?: (
            workflowId: string,
            runId: string,
            principal: ExecutionPrincipal,
            replayOnly: boolean,
        ) => Promise<RunSummary>;
        workflows: readonly WorkflowMeta[];
    }
    Index

    Properties

    beforeResume?: (
        context: ActorContext,
        workflowId: string,
        runId: string,
        body: unknown,
    ) => Promise<void>

    Host policy that must pass immediately before a validated raw resume.

    beforeStart?: (
        context: ActorContext,
        workflowId: string,
        inputData: unknown,
    ) => Promise<void>

    Host policy that must pass immediately before a validated run start.

    reconcileApprovals?: (
        context: ActorContext,
        workflowId: string,
        summary: RunSummary,
    ) => Promise<void>

    Self-healing hook invoked after a status() read reports the run suspended, so every status poll of a stuck run doubles as a check for a gate whose approval never made it into the queue (see reconcileApprovalsForSummary in approval-bridge.ts). Awaited rather than fire-and-forget by default: this host-agnostic layer has no ctx.waitUntil of its own to keep a detached promise alive past the response, so a plain awaited call is what it can offer on its own. Reconciliation pages the run's full approval history and may supersede stale open records before filing a fresh one, so the two ctx-capable hosts (deploy/worker.ts and the showcase worker) hand this hook a wrapper that detaches the real work via ctx.waitUntil and resolves immediately — this option's contract (an awaited function of this exact shape) is unchanged either way, only what a given host's function actually blocks on. A throw is caught and logged here, never surfaced to the caller: a broken reconcile must not turn a working status read into a 500; the next poll simply retries. Absent => today's behavior (no reconciliation). Hosts wire reconcileApprovalsOnStatus(systemPrincipalId) here, optionally wrapped for waitUntil-detachment.

    resolve: ActorResolver

    Authenticates the request and resolves the actor-scoped approval service and server-owned id minters. undefined yields 401.

    resume: (
        workflowId: string,
        runId: string,
        body: unknown,
        requestedBy: string,
        requestedByKind: "human" | "service" | "agent" | "system",
    ) => Promise<RunSummary>
    start: (input: RunStartInput) => Promise<RunSummary>

    Host topology: in-process runtime, or a DO stub fetch.

    startIdempotency: RunRouterStartIdempotency

    How this host honours idempotencyKey on POST /runs — the reservation store plus the liveness probe that resolves a claimed-but-unpersisted run.

    REQUIRED, and with no undefined in the type, for the reason ExecutionFenceWiring spells out: an option a host may omit is one a host will omit, and the failure mode of omitting THIS one is silent. A router that ignored an unwired key would answer an exactly-once request with at-least-once behaviour, and the caller would have no way to find out. The typed opt-out ('none') is honest — it makes every keyed start refuse with IDEMPOTENT_START_UNSUPPORTED — and unkeyed starts are unaffected either way.

    The probe travels WITH the store rather than beside it because a store without one cannot answer the only question the reservation cannot settle on its own, and a host that wired the first and forgot the second would fall back to guessing.

    status: (workflowId: string, runId: string) => Promise<RunSummary | undefined>
    systemPrincipalId?: string

    System-principal id used to authorize bridge bookkeeping. Approval requester provenance comes from the run summary, so this id need not be globally disjoint from human ids. Default: 'flowsafe-system'.

    terminate?: (
        workflowId: string,
        runId: string,
        principal: ExecutionPrincipal,
        replayOnly: boolean,
    ) => Promise<RunSummary>

    Optional for compatibility; when supplied, mounts POST .../terminate.

    workflows: readonly WorkflowMeta[]

    The catalog: GET /workflows lists these; POST /runs resolves against them and enforces each one's allowedRoles.

    Metadata, not WorkflowModules: the router registers nothing, so depending on the registration machinery would force every host to build a WorkflowModuleContext (and its AuditLogger) just to expose a route. Hosts pass modules.map((m) => m.meta); that the ids match what was actually committed is asserted at registration (see buildShowcaseRuntime).