/** * Shared runtime plumbing for the application delivery outbox (WFT-85): the * per-instance runtime, the contention error, receipt projection, fleet event * description, process-local attempt release, and the commit that keeps the * header's backlog accounting consistent with every transition. * * @module core/outbox-internals */ import type { BatchOperation, ConditionalBatchCondition, Storage } from '../storage/interface.ts'; import type { AttemptRegistry } from './application-primitive-attempt-registry.ts'; import type { ApplicationDeliveryAdapter, ApplicationDeliveryReceipt, OutboxEventSink } from './outbox-contract.ts'; import { type LoadedOutboxRecord, type OutboxKeys } from './outbox-storage.ts'; import { type ApplicationDeliveryRecord } from './outbox-types.ts'; import type { ResolvedOutboxPolicy } from './outbox-validation.ts'; import { WeftError } from './weft-error.ts'; /** How many times one operation re-reads and retries a lost compare-and-swap. */ export declare const MAX_OUTBOX_TRANSITION_ATTEMPTS = 25; /** How many scan pages one maintenance pass may walk. */ export declare const OUTBOX_MAINTENANCE_MAX_PAGES = 200; /** The registry-scope tag for the outbox, so it never shares a registry with the mailbox. */ export declare const OUTBOX_PRIMITIVE = "outbox"; /** Everything an outbox operation needs that is fixed at construction. */ export type OutboxRuntime = { readonly storage: Storage; readonly events: OutboxEventSink | undefined; readonly adapter: ApplicationDeliveryAdapter | undefined; readonly policy: ResolvedOutboxPolicy; readonly keys: OutboxKeys; readonly now: () => number; readonly generateId: () => string; /** The process-local disposal signal every wait and attempt races. */ readonly disposal: AbortSignal; readonly attemptControllers: AttemptRegistry; /** Record an attempt this handle now owns, or report that disposal already won. */ readonly adoptAttempt: (attemptToken: string) => (() => void) | null; readonly readMaintenanceCursor: () => string | undefined; readonly writeMaintenanceCursor: (cursor: string | undefined) => void; }; /** * Thrown when a transition keeps losing its compare-and-swap: durable * contention on this outbox is real, and the caller decides whether to back * off, shed load, or shard the owner. * * @example * ```ts * import { OutboxContentionError } from '@lostgradient/weft'; * * const error = new OutboxContentionError('enqueue', null); * console.log(error.code); // 'OutboxContentionError' * ``` */ export declare class OutboxContentionError extends WeftError<'OutboxContentionError'> { /** The outbox operation that could not commit. */ readonly operation: string; /** The delivery the operation targeted, or `null` for outbox-wide operations. */ readonly deliveryId: string | null; constructor(operation: string, deliveryId: string | null); } /** * Project a durable record into the immutable public receipt. The attempt * token and the credential reference are never projected. */ export declare function toApplicationDeliveryReceipt(record: ApplicationDeliveryRecord): ApplicationDeliveryReceipt; /** * The durable fleet event that describes a transition. Bounded and free of * secrets: no payload, no evidence, no failure details, and neither the * destination nor the credential reference. */ export declare function describeDeliveryTransition(previous: ApplicationDeliveryRecord | null, next: ApplicationDeliveryRecord): { readonly kind: string; readonly payload: unknown; }; /** Abort and forget the process-local controller for one attempt. */ export declare function releaseAttemptController(runtime: OutboxRuntime, attemptToken: string, reason: string, deliveryId?: string): void; /** * Release every attempt this process holds for one delivery that is not its * current lease, fenced by the lease-commit serial the snapshot was read at. */ export declare function releaseAttemptsForDelivery(runtime: OutboxRuntime, deliveryId: string, reason: string, currentToken?: string, observedAt?: number): void; /** * Commit one delivery transition together with the index maintenance and * backlog accounting it implies. * * Closing a delivery decrements the header's open count and an operator * retry that reopens one increments it, each in the same conditional batch as * the record, so `capacity()` can never drift from the records it describes. * Enqueue builds its own header operation because it also allocates the * sequence. */ export declare function commitDeliveryTransition(runtime: OutboxRuntime, options: { readonly previous: ApplicationDeliveryRecord | null; readonly expectedBytes: Uint8Array | null; readonly next: ApplicationDeliveryRecord; readonly now: number; readonly extraConditions?: readonly ConditionalBatchCondition[] | undefined; readonly extraOperations?: readonly BatchOperation[] | undefined; /** A header the caller already read and decided on; the commit fences on these bytes. */ readonly header?: LoadedOutboxRecord | undefined; }): Promise;