/** * Optional sender-side mailbox retry databaser. * * KERIpy correspondence: * - there is no direct KERIpy `Outboxer`; this is a Tufa-only additive sidecar * * Design rule: * - keep sender retry state separate from `Mailboxer` * - `Mailboxer` is recipient/provider inbox storage * - `Outboxer` is sender retry state for mailbox-target deliveries */ import { type Operation } from "effection"; import { OutboxMessageRecord, type OutboxMessageRecordShape, OutboxTargetRecord } from "../core/records.js"; import { LMDBer, type LMDBerOptions } from "./core/lmdber.js"; import { Komer } from "./koming.js"; import { Suber } from "./subing.js"; /** * Open options for the sender retry sidecar. * * `compat` is intentionally rejected because KERIpy-compatible stores do not * model an outbox databaser. */ export interface OutboxerOptions extends LMDBerOptions { compat?: boolean; } /** One pending sender retry item paired with its current target state. */ export interface PendingOutboxEntry { said: string; message: OutboxMessageRecord; raw: Uint8Array; target: OutboxTargetRecord; } /** * Shared outbox contract used by both the real and disabled implementations. * * This lets the rest of the runtime treat retry support as optional without * leaking `if enabled` checks into every caller. */ export interface OutboxerLike { readonly enabled: boolean; /** Return the number of mailbox-target deliveries still waiting to retry. */ pendingCount(): number; /** Iterate each mailbox-target delivery that is still pending. */ iterPending(): Generator; /** Persist one logical outbound message and seed target rows for each mailbox. */ queueMessage(said: string, raw: Uint8Array, message: OutboxMessageRecordShape, eids: Iterable): void; /** Mark one mailbox target as delivered and prune the message if complete. */ markDelivered(said: string, eid: string, deliveredAt: string): void; /** Record one failed attempt while keeping the target pending for retry. */ markFailed(said: string, eid: string, attemptedAt: string, error: string): void; /** Cancel one mailbox target explicitly. */ cancelTarget(said: string, eid: string, cancelledAt: string, error?: string): void; /** Cancel all pending targets for one mailbox AID. */ cancelMailbox(eid: string, cancelledAt: string): void; /** Close the sidecar implementation. */ close(clear?: boolean): Operation; } /** * No-op outboxer used when the Tufa-only retry sidecar is disabled. * * The rest of the runtime still talks to the same interface, but no retry * state is persisted or replayed. */ export declare class DisabledOutboxer implements OutboxerLike { readonly enabled = false; pendingCount(): number; iterPending(): Generator; queueMessage(_said: string, _raw: Uint8Array, _message: OutboxMessageRecordShape, _eids: Iterable): void; markDelivered(_said: string, _eid: string, _deliveredAt: string): void; markFailed(_said: string, _eid: string, _attemptedAt: string, _error: string): void; cancelTarget(_said: string, _eid: string, _cancelledAt: string, _error?: string): void; cancelMailbox(_eid: string, _cancelledAt: string): void; close(_clear?: boolean): Operation; } /** Raw-byte value family used for stored outbound message payloads. */ declare class BytesSuber extends Suber { protected _ser(val: Uint8Array): Uint8Array; protected _des(val: Uint8Array | null): Uint8Array | null; } /** * Durable sender-side mailbox delivery retry storage. * * Storage model: * - `.msgs` stores the raw signed message by logical message SAID * - `.items` stores message metadata keyed by SAID * - `.tgts` stores per-mailbox-target delivery state keyed by `(said, eid)` */ export declare class Outboxer extends LMDBer implements OutboxerLike { readonly enabled = true; msgs: BytesSuber; items: Komer; tgts: Komer; /** Default primary path for Tufa-owned outbox environments. */ static readonly TailDirPath = "keri/obx"; /** Default alternate path for Tufa-owned outbox environments. */ static readonly AltTailDirPath = ".tufa/obx"; /** Unused compat path kept only to mirror `LMDBer` configuration shape. */ static readonly CompatAltTailDirPath = ".keri/obx"; static readonly TempPrefix = "keri_obx_"; static readonly MaxNamedDBs = 8; constructor(options?: OutboxerOptions); reopen(options?: Partial): Operation; /** * Persist one logical outbound message and seed per-mailbox-target state. * * The message SAID identifies the logical message, while target rows track * delivery independently per mailbox endpoint. */ queueMessage(said: string, raw: Uint8Array, message: OutboxMessageRecordShape, eids: Iterable): void; /** Return the raw signed payload for one logical outbound message. */ getMessage(said: string): Uint8Array | null; /** Return the metadata row for one logical outbound message. */ getRecord(said: string): OutboxMessageRecord | null; /** Return the per-target state row for one logical message and mailbox. */ getTarget(said: string, eid: string): OutboxTargetRecord | null; /** Count mailbox-target rows that still need delivery work. */ pendingCount(): number; /** Iterate each mailbox-target row that is still pending. */ iterPending(): Generator; /** * Mark one mailbox target delivered and prune the parent message when all * targets are terminal. */ markDelivered(said: string, eid: string, deliveredAt: string): void; /** * Record one failed attempt while keeping the target pending for future * retry. */ markFailed(said: string, eid: string, attemptedAt: string, error: string): void; /** * Cancel one mailbox target explicitly. * * Cancellation is terminal and participates in message pruning once no * pending targets remain. */ cancelTarget(said: string, eid: string, cancelledAt: string, error?: string): void; /** Cancel every pending target that points at one removed mailbox AID. */ cancelMailbox(eid: string, cancelledAt: string): void; /** Remove the payload, metadata, and all target rows for one logical message. */ removeMessage(said: string): void; private pinTarget; private pruneIfComplete; private requireTarget; } /** Open options for `createOutboxer()`, including existence enforcement. */ export interface CreateOutboxerOptions extends OutboxerOptions { mustExist?: boolean; } /** * Open the optional sender retry sidecar. * * Compatibility rule: * - compat mode is rejected because KERIpy stores do not model this additive * domain * - `mustExist` is used by commands that require a previously initialized * outbox sidecar instead of silently creating one */ export declare function createOutboxer(options?: CreateOutboxerOptions): Operation; export {}; //# sourceMappingURL=outboxing.d.ts.map