/** * What a document is waiting for, and who may end the wait. * * A suspension is a durable wait: the run stops, the executor lock is released, * and a later execution reaches the same wait rather than starting over. Two * values describe it. The **request** says what is awaited, in whatever shape * the waiting document chose. The **response schema** says what a value must * look like to end that wait, so a host offering one can be refused before the * document ever sees it. * * ## Identity is position, not a name * * A caller supplies neither an identifier nor a claim. The trusted execution * derives one suspension ID from the run and the exact durable coroutine * position, which is what makes the wait a document reaches at one point in a * procedure the same wait it reaches there after a resume — and what keeps two * different waits from receiving each other's input. A caller that could name * its own would be a caller that could claim another wait's answer. * * ## The route composes; the request at this position admits * * The controller is reached through a stable contextual name. That name is how a * component carrying its own loaded copy of this package finds the controller * the running binary installed, so the route is composition and behaves like it: * middleware may refuse or suppress it for its descendants. * * What it may not do is end a wait. No value arriving through the route is an * answer — this slice delivers none — so a suppressed route leaves the wait * unentered, and an unentered wait is where the operation stops. It does not * return, and it does not raise: an ordinary error is something a document can * catch, and a caught suspension would be a document continuing past a wait it * asked for and did not get. * * Admission is the retained request at the caller's exact current durable * position. The identifier presented must be the one this run derives for the * position immediately behind the caller, and the yield there must be that * request, describing what is presented. An identifier from elsewhere in the * journal, a reconstructed contextual name, or a matching row without the * position each admit nothing. Another durable operation may reproduce the * request and arrive at that position — replay identity is a type and a name, * both public — and when it does it is standing at the same validated wait, * which is what a wait is identified by. */ import { type Api } from "@effectionx/context-api"; import type { Operation } from "effection"; import { type Json, type JsonObject } from "@executablemd/core"; import { WorkflowStorageError } from "../storage/errors.js"; /** What one durable wait is for, and what may end it. */ export interface WorkflowSuspensionRequest { readonly request: Json; readonly responseSchema: JsonObject; } /** A request whose shape this run will not retain. */ export declare class WorkflowSuspensionRequestError extends WorkflowStorageError { name: string; } /** No suspension controller is installed, so no wait can be entered. */ export declare class WorkflowSuspensionProviderError extends WorkflowStorageError { name: string; constructor(); } export interface WorkflowSuspensionApi { /** * Report this execution's suspension to whoever owns its executor lock. * * Returns the value that ends the wait. With no delivered input it does not * return at all: the wait is what the operation is, and the owner ends the * execution around it. */ enter(suspensionId: string, request: WorkflowSuspensionRequest): Operation; } export declare const WorkflowSuspension: Api; /** * The request this value is, or a refusal naming what is wrong with it. * * Refused before anything is published, because a request that cannot be * retained must not become a durable event, and a schema that cannot describe a * response must not be the thing a later host validates against. Both halves * are ordinary document input and neither has been checked by anyone else. */ export declare function parseSuspensionRequest(value: unknown): WorkflowSuspensionRequest; /** * The stable name of one wait's request and the shape that may end it. * * What a retained answer is correlated by. Delivery computes it from the * request it read out of the journal and stores it beside the value; a resume * recomputes it from the request the execution actually reached and compares — * a run whose retained request at that position is not the one the value was * judged against is a run that answer was never for. * * One function rather than one per caller. Everything that judges an answer has * to agree about this exactly, and a second spelling of it would be a second * answer to the same question. */ export declare function suspensionRequestFingerprint(request: WorkflowSuspensionRequest): string;