/** * Bounds and input validation for the durable application delivery outbox * (WFT-85): construction options, offered deliveries, and adapter outcomes. * * Every bound here exists so a hostile or buggy caller — or a misbehaving * transport — cannot grow durable storage without limit, push an unbounded * string into a storage key, or write a record the decoder rejects. The outbox * validates at the boundary, before any write, so a rejected input leaves no * trace. * * @module core/outbox-validation */ import type { JSONValue } from './json.ts'; import type { ApplicationDeliveryInput, OutboxOptions } from './outbox-contract.ts'; import type { ApplicationDeliveryFailure, ApplicationDeliveryPayload, ApplicationDeliveryUnknownOutcomePolicy } from './outbox-types.ts'; /** Outbox defaults resolved once at construction. */ export type ResolvedOutboxPolicy = Readonly<{ namespace: string; ownerId: string; maxBacklog: number; visibilityTimeoutMs: number; attemptTimeoutMs: number; maxAttempts: number; retryBackoffMs: number; maxRetryBackoffMs: number; terminalRetentionMs: number; maxInlinePayloadBytes: number; maintenanceBatchSize: number; unknownOutcomePolicy: ApplicationDeliveryUnknownOutcomePolicy; backgroundTasks: 'automatic' | 'manual'; maintenanceIntervalMs: number; }>; /** * Resolve and range-check the outbox construction options. * * `attemptTimeoutMs` and `maintenanceIntervalMs` are each scheduled as one * timer, so they are bounded by the largest delay a timer honours rather than * by the general duration ceiling: a larger value would be clamped to a tick by * the runtime, and every attempt would abort at once. * * @throws {ApplicationDeliveryValidationError} When any option is out of range. */ export declare function resolveOutboxPolicy(options: OutboxOptions): ResolvedOutboxPolicy; /** A validated delivery input with its digest and effective per-delivery policy resolved. */ export type ValidatedDeliveryInput = Readonly<{ destinationRef: string; credentialRef?: string | undefined; kind: string; payload: ApplicationDeliveryPayload; payloadDigest: string; payloadMediaType?: string | undefined; payloadSchema?: string | undefined; idempotencyKey?: string | undefined; externalIdempotencyKey?: string | undefined; unknownOutcomePolicy: ApplicationDeliveryUnknownOutcomePolicy; causation?: ApplicationDeliveryInput['causation'] | undefined; availableAfterMs: number; maxAttempts: number; visibilityTimeoutMs: number; attemptTimeoutMs: number; }>; /** * Validate one delivery offered for enqueue and resolve its effective policy. * * The unknown-outcome policy and the external idempotency evidence are * validated together here, so a record with `retry-with-idempotency` and no * `externalIdempotencyKey` can never exist: recovery never has to decide what * to do with a retry it cannot make safely. * * @throws {ApplicationDeliveryValidationError} When any field is missing, * oversized, out of range, or the policy lacks its evidence. */ export declare function validateDeliveryInput(input: ApplicationDeliveryInput, policy: ResolvedOutboxPolicy): Promise; /** A transport outcome with every caller-supplied field validated and snapshotted. */ export type ValidatedOutcome = { readonly status: 'acknowledged'; readonly evidence: JSONValue | undefined; } | { readonly status: 'retryable'; readonly failure: ApplicationDeliveryFailure; readonly retryAfterMs: number | undefined; } | { readonly status: 'rejected'; readonly failure: ApplicationDeliveryFailure; } | { readonly status: 'unknown'; readonly failure: { readonly reason: 'unknown-outcome'; readonly message?: string | undefined; }; }; /** * Validate what a transport reported before it becomes durable evidence. * * A malformed outcome — not an object, an unknown status, `NaN` for * `retryAfterMs`, a `Map` as evidence — is not a caller mistake the outbox can * refuse: the send may already have happened. It is therefore mapped to * `unknown` with a diagnostic message, so the delivery follows the unknown- * outcome policy instead of being retried on the strength of nothing. */ export declare function validateOutcome(outcome: unknown): ValidatedOutcome;