Anchorage API reference
    Preparing search index...

    Interface ApprovalServiceOptions

    interface ApprovalServiceOptions {
        allowSelfDecision?: SelfDecisionPolicy;
        audit?: ApprovalAuditSink;
        defaultSlaSeconds?: number;
        executionFence: ExecutionFenceWiring;
        notify?: ApprovalNotificationSink;
        now?: () => Date;
        resumeRun?: (
            record: ApprovalRecord,
            decision: ApprovalDecision,
        ) => Promise<unknown>;
        store: ApprovalStore;
        stream?: ApprovalStreamSink;
    }
    Index

    Properties

    allowSelfDecision?: SelfDecisionPolicy

    Permit the requester to decide their own request. Off by default — separation of duties is the safe enterprise default. true exempts every decider; { roles } exempts only those roles (a single-operator deployment sets e.g. { roles: ['admin'] }). A permitted self-decision is audited with detail.selfDecision: true.

    Structural match for breakwater AuditLogger.record — wire (event) => auditLogger.record(event). Must not throw; failures are contained anyway (availability over export reliability, matching AuditLogger's own sink policy).

    defaultSlaSeconds?: number

    Applied when CreateApprovalInput.slaSeconds is absent.

    executionFence: ExecutionFenceWiring

    The deployment execution fence, consulted before a DECISION commits, or 'none' for a service with no database to fence against.

    DECIDE is gated wherever resume is, because decide() COMMITS and THEN resumes (see #resume): a lock that only stopped the resume would leave the approval durably decided on a deployment that can never act on it, and the deployment taking over would inherit a decision with no resume behind it. Reads, claims, and delegation stay open in every state — they move no run.

    REQUIRED, and 'none' has to be WRITTEN. This service is the last leaf of the wiring to admit an omission, and it is the leaf where an omission costs the most: an unfenced service looks identical to a fenced one until the day an operator locks the deployment, and then it records decisions the deployment can never act on. Naming the opt-out turns that into a decision someone made rather than one they missed. See ExecutionFenceWiring.

    Notification transport seam — fired once per record actually CREATED (created: true; the idempotent re-observation of an already-open step never re-notifies). Fire-and-forget: a throwing or rejecting sink is contained and recorded to the audit sink as approval.notify/'error', never failing the create. See ApprovalNotificationSink (contract.ts) for the ctx.waitUntil convention on Workers hosts.

    now?: () => Date

    Injectable clock (tests, deterministic SLA math).

    resumeRun?: (
        record: ApprovalRecord,
        decision: ApprovalDecision,
    ) => Promise<unknown>

    Resumes a suspension-bound, explicitly run-scoped, or trusted-target run after a decision (approve AND reject — the workflow learns the outcome via resumeData). Decision-only queue records never call this seam. Same-Worker deployments use resumeViaRuntime(runtime); cross-Worker ones fetch the run's DO.

    The deployment's approval store. Obtain via a store factory's store() (one memoized schema pass per isolate).

    Live-stream fan-out seam — fired once per SUCCESSFUL mutation (create with created: true, claim, decide, delegate, supersede) with the POST-transition record. Distinct from notify (reviewer transport, created/escalated only): this is the same-trust in-deployment feed the deployment hub relays to open dashboards. Fire-and-forget with the same containment as notify: a throwing or rejecting sink is audited as approval.stream/'error' and never fails the mutation. See ApprovalStreamSink (contract.ts) for the ctx.waitUntil convention.