Anchorage API reference
    Preparing search index...

    Interface FlowsafeWorkerConfig<Env>

    interface FlowsafeWorkerConfig<Env extends FlowsafeWorkerEnv> {
        artifactStore?: TenantArtifactPurger;
        backgroundTasks?: BackgroundTasksCleanupConfig;
        buildAgentRouter?: (
            resolve: TenantResolver,
            env: Env,
        ) => AgentRouter | undefined;
        buildObjectiveRouter?: (
            resolve: TenantResolver,
            env: Env,
        ) => ((request: Request) => Promise<Response | null>) | undefined;
        buildResumeRun?: (fallback: ResumeRunFn, env: Env) => ResumeRunFn;
        buildScheduleRouter?: (
            resolve: TenantResolver,
            env: Env,
        ) => ((request: Request) => Promise<Response | null>) | undefined;
        buildSignalRouter?: (
            resolve: TenantResolver,
            env: Env,
        ) => ((request: Request) => Promise<Response | null>) | undefined;
        buildVerifier: (env: Env) => TokenVerifier;
        crons: { purge: string; sweep: string; tick?: string };
        extraPurgeDuties?: (
            env: Env,
            cron: string,
        ) => Promise<Record<string, unknown>>;
        notify?: (env: Env) => ApprovalNotificationSink | undefined;
        preRoutes?: (
            request: Request,
            env: Env,
            ctx: FlowsafeWorkerContext,
            kit: { resolve: TenantResolver; topology: DoRunTopology },
        ) => Promise<Response | null>;
        scheduleTick?: (env: Env) => (() => Promise<unknown>) | undefined;
        systemActorId: string;
        workflows: readonly WorkflowMeta[];
        wrapResolve?: (resolve: TenantResolver, env: Env) => TenantResolver;
        wrapResume?: (
            resume: (
                workflowId: string,
                runId: string,
                body: unknown,
            ) => Promise<RunSummary>,
            env: Env,
        ) => (
            workflowId: string,
            runId: string,
            body: unknown,
        ) => Promise<RunSummary>;
        wrapStart?: (
            start: (
                workflowId: string,
                runId: string,
                inputData: unknown,
            ) => Promise<RunSummary>,
            env: Env,
        ) => (
            workflowId: string,
            runId: string,
            inputData: unknown,
        ) => Promise<RunSummary>;
    }

    Type Parameters

    Index

    Properties

    artifactStore?: TenantArtifactPurger

    When set, the retention purge (runPurgeMaintenance -> the built-in purgeExpiredWorkflowRuns) deletes each expired run's R2 artifacts WITH its snapshot row. The snapshot row is the only enumerable record of a run's artifact keys (R2 keys lead with workflowId — there is no run-level listing without it), so a retention purge without this pairing strands the run's artifacts beyond even purgeTenant's reach. Pass the same TenantArtifactPurger (an R2ArtifactStore) purgeTenant gets; undefined keeps the byte-identical row-only purge. NOT via extraPurgeDuties — that hook runs AFTER the rows are deleted, when the keys are already unenumerable.

    Opt-in background-task TTL cleanup. When present, the purge cron reaps terminal mastra_background_tasks rows past the TTL as its OWN failure-isolated duty — the storage-layer belt to a hosting DO's manager cleanup (which needs the DO alive). Absent => no duty, byte-identical (background tasks are opt-in). NOT via extraPurgeDuties: this needs its own try/catch and its own log fields, like every sibling purge duty.

    buildAgentRouter?: (
        resolve: TenantResolver,
        env: Env,
    ) => AgentRouter | undefined

    Opt-in authenticated agent catalog/run router. Structurally typed so this module does not import the server-only agent-host subpath.

    buildObjectiveRouter?: (
        resolve: TenantResolver,
        env: Env,
    ) => ((request: Request) => Promise<Response | null>) | undefined

    Opt-in goal-objective stage. Mirrors buildSignalRouter: the host builds its createObjectiveRouter (which needs the thread-state store from its D1 domains, plus its audit/maxRuns config) and returns it here, closed over the request's resolved TenantResolver; the composer mounts it after the signal stage. Both live under /api/threads/* but do not overlap — goals use the /goal segment, signals the channel segments. INJECTED rather than built here because createObjectiveRouter lives in goals/, which imports host-kit — host-kit importing it back would cycle. Absent (or returns undefined) ⇒ no goal stage, byte-identical.

    buildResumeRun?: (fallback: ResumeRunFn, env: Env) => ResumeRunFn

    Compose approval-driven resume handling. Agent hosts use this to handle agent-thread targets and delegate generic workflow targets to fallback.

    buildScheduleRouter?: (
        resolve: TenantResolver,
        env: Env,
    ) => ((request: Request) => Promise<Response | null>) | undefined

    Opt-in schedule CRUD facade. Mirrors buildSignalRouter/ buildObjectiveRouter: the host builds its createScheduleRouter (which needs the schedules store from its D1 domains + its audit/cap config) and returns it here, closed over the request's resolved TenantResolver; the composer mounts it after the goal stage. Its /api/schedules/* routes don't overlap the others. INJECTED (not built here, typed structurally) because createScheduleRouter lives in schedules/, which transitively imports host-kit — importing it back would cycle. Absent (or returns undefined) ⇒ no schedule surface, byte-identical.

    buildSignalRouter?: (
        resolve: TenantResolver,
        env: Env,
    ) => ((request: Request) => Promise<Response | null>) | undefined

    Opt-in signal-ingestion stage. The host builds its createSignalRouter (which needs its per-thread DO namespace via createThreadTopology, plus its audit/rate/allowlist config) and returns it here, closed over the request's resolved TenantResolver; the composer mounts it after preRoutes, ahead of approvals/runs (its /api/threads/* routes don't overlap). INJECTED rather than built here because createSignalRouter lives in signals/, which imports host-kit — host-kit importing it back would cycle. Absent (or returns undefined) => no signal stage, byte-identical.

    buildVerifier: (env: Env) => TokenVerifier

    The identity seam: env -> TokenVerifier. Called once per fetch (and per scheduled notify), so hosts keep their own per-isolate memoization — re-parsing a token map on every request is pure waste, but that is the host's trade to make.

    crons: { purge: string; sweep: string; tick?: string }

    The cron expressions scheduled() dispatches on. sweep + purge are required and must never share an invocation. tick is optional for schedules: when set and scheduleTick is provided, the schedule tick runs on it as its OWN failure-isolated invocation (a runaway fire pass gets its own CPU budget, the same rationale that keeps sweep and purge apart). Keep these byte-equal to wrangler.jsonc's triggers.crons; an unrecognized expression runs the sweep + purge duties sequentially and logs a config-error (availability beats purity on a misconfig). Absent tick ⇒ no schedule-tick invocation, byte-identical.

    extraPurgeDuties?: (env: Env, cron: string) => Promise<Record<string, unknown>>

    Extra purge-cron duties (e.g. the showcase's demo-tenant reaper). The returned fields fold into the ONE combined {type:'maintenance'} log line. Isolated: a throw here logs a maintenance-error and never blocks the combined log — though duties SHOULD own their try/catch so their error surface stays specific.

    notify?: (env: Env) => ApprovalNotificationSink | undefined

    Reviewer-facing notification transport (ApprovalNotificationSink) for created records and SLA escalations. Built per invocation from env (transports usually need secrets); undefined = no notifications.

    preRoutes?: (
        request: Request,
        env: Env,
        ctx: FlowsafeWorkerContext,
        kit: { resolve: TenantResolver; topology: DoRunTopology },
    ) => Promise<Response | null>

    Deployment-specific routes tried AFTER /healthz and BEFORE the approval and run routers (the showcase mounts its demo sign-in and sandbox reset here). kit hands over the request's already-built resolver and DO topology so a pre-route can share them (the reset route authenticates through the same resolve). Return null to fall through.

    scheduleTick?: (env: Env) => (() => Promise<unknown>) | undefined

    Opt-in schedule tick. The host builds its createScheduleTick (which needs the schedules store, its run-start seam — topology.start — and the run-cap + audit config) and returns the closure here. The composer runs it on the crons.tick cron as its OWN failure-isolated duty (own try/catch, own schedule-tick log line). INJECTED (not built here, structurally typed as () => Promise<unknown>) because createScheduleTick lives in schedules/, which transitively imports host-kit — host-kit importing it back would cycle. Absent (or crons.tick unset) ⇒ no tick invocation, byte-identical.

    systemActorId: string

    Id for system-created records (the bridge's record creator and the cron maintenance attribution). Must differ from human actor ids or the separation-of-duties check can never fire.

    workflows: readonly WorkflowMeta[]

    The catalog createRunRouter serves and gates (hosts pass their metas).

    wrapResolve?: (resolve: TenantResolver, env: Env) => TenantResolver

    Wrap the tenant resolver (e.g. withSubdomainCrossCheck behind an env var).

    wrapResume?: (
        resume: (
            workflowId: string,
            runId: string,
            body: unknown,
        ) => Promise<RunSummary>,
        env: Env,
    ) => (
        workflowId: string,
        runId: string,
        body: unknown,
    ) => Promise<RunSummary>

    Wrap the raw-resume thunk (metered like starts on budgeted hosts).

    wrapStart?: (
        start: (
            workflowId: string,
            runId: string,
            inputData: unknown,
        ) => Promise<RunSummary>,
        env: Env,
    ) => (
        workflowId: string,
        runId: string,
        inputData: unknown,
    ) => Promise<RunSummary>

    Wrap the run-start thunk (e.g. charge a budget BEFORE the DO round-trip).