/** * Durable WhatsApp message ownership and provider-effect truth (ADR-0008). * * This is intentionally WhatsApp-specific. WAMIDs, Cloud API acceptance and * status webhooks are provider semantics, not a generic channel queue. */ import type { ThreadMap } from '../types.js'; export type WhatsAppInboundState = 'queued' | 'processing' | 'replied' | 'run_unknown' | 'delivery_failed' | 'delivery_unknown' | 'handoff_requested' | 'handoff_deferred'; export type WhatsAppAttemptState = 'prepared' | 'accepted' | 'sent' | 'delivered' | 'read' | 'rejected' | 'failed' | 'unknown'; export type WhatsAppHandoffState = 'requested' | 'accepted' | 'resumed'; export interface WhatsAppDeliveryAttempt { readonly attemptId: string; readonly chunk: number; readonly target: string; readonly contentDigest: string; readonly contentLength: number; readonly state: WhatsAppAttemptState; readonly providerMessageId: string | null; readonly outcomeCode: string | null; readonly preparedAt: number; readonly updatedAt: number; } export interface WhatsAppInboundRecord { readonly key: string; readonly channelId: string; readonly phoneNumberId: string; readonly inboundId: string; readonly from: string; readonly text: string | null; readonly runIdempotencyKey: string; readonly runThreadResolved: boolean; readonly runThreadId: string | null; readonly state: WhatsAppInboundState; readonly attempts: readonly WhatsAppDeliveryAttempt[]; readonly receivedAt: number; readonly updatedAt: number; } export interface WhatsAppHandoff { readonly requestId: string; readonly channelId: string; readonly customer: string; readonly state: WhatsAppHandoffState; readonly requestedAt: number; readonly acceptedAt: number | null; readonly resumedAt: number | null; readonly updatedAt: number; } export interface EnqueueWhatsAppInbound { readonly channelId: string; readonly phoneNumberId: string; readonly inboundId: string; readonly from: string; readonly text: string; } export type WhatsAppProviderStatus = 'sent' | 'delivered' | 'read' | 'failed' | 'deleted'; interface StoredProviderStatus { readonly providerMessageId: string; readonly status: WhatsAppProviderStatus; readonly outcomeCode: string | null; readonly observedAt: number; } interface DeliveryState { readonly version: 1; inbounds: WhatsAppInboundRecord[]; handoffs: WhatsAppHandoff[]; orphanStatuses: StoredProviderStatus[]; threadBindings: Array<{ readonly sessionKey: string; readonly threadId: string; }>; } export interface WhatsAppDeliveryStore { enqueue(input: EnqueueWhatsAppInbound, now?: number): { added: boolean; record: WhatsAppInboundRecord; }; hasInbound(channelId: string, inboundId: string): boolean; getInbound(key: string): WhatsAppInboundRecord | null; listInbounds(channelId?: string, limit?: number): WhatsAppInboundRecord[]; claim(key: string, now?: number): WhatsAppInboundRecord | null; bindRunThread(key: string, threadId: string | null, now?: number): WhatsAppInboundRecord; queued(channelId?: string): WhatsAppInboundRecord[]; recover(now?: number): { requeued: number; unknown: number; replied: number; }; prepareAttempt(key: string, target: string, text: string, now?: number): WhatsAppDeliveryAttempt; markAttemptAccepted(key: string, attemptId: string, providerMessageId: string, now?: number): void; markAttemptRejected(key: string, attemptId: string, outcomeCode: string, now?: number): void; markAttemptUnknown(key: string, attemptId: string, outcomeCode: string, now?: number): void; finishReply(key: string, now?: number): void; finishFailure(key: string, now?: number): void; recordStatus(providerMessageId: string, status: WhatsAppProviderStatus, outcomeCode?: string, now?: number): void; requestHandoff(key: string, now?: number): WhatsAppHandoff; handoffFor(channelId: string, customer: string): WhatsAppHandoff | null; listHandoffs(channelId?: string): WhatsAppHandoff[]; acceptHandoff(requestId: string, now?: number): WhatsAppHandoff; resumeHandoff(requestId: string, now?: number): WhatsAppHandoff; deferToHuman(key: string, now?: number): void; pruneTerminal(before: number): number; getThread(sessionKey: string): string | undefined; setThread(sessionKey: string, threadId: string): void; deleteThread(sessionKey: string): void; } declare abstract class BaseWhatsAppDeliveryStore implements WhatsAppDeliveryStore { protected abstract readState(): DeliveryState; protected abstract mutate(fn: (state: DeliveryState) => T): T; enqueue(input: EnqueueWhatsAppInbound, now?: number): { added: boolean; record: WhatsAppInboundRecord; }; hasInbound(channelId: string, inboundId: string): boolean; getInbound(key: string): WhatsAppInboundRecord | null; listInbounds(channelId?: string, limit?: number): WhatsAppInboundRecord[]; claim(key: string, now?: number): WhatsAppInboundRecord | null; bindRunThread(key: string, threadId: string | null, now?: number): WhatsAppInboundRecord; queued(channelId?: string): WhatsAppInboundRecord[]; recover(now?: number): { requeued: number; unknown: number; replied: number; }; prepareAttempt(key: string, target: string, text: string, now?: number): WhatsAppDeliveryAttempt; markAttemptAccepted(key: string, attemptId: string, providerMessageId: string, now?: number): void; markAttemptRejected(key: string, attemptId: string, outcomeCode: string, now?: number): void; markAttemptUnknown(key: string, attemptId: string, outcomeCode: string, now?: number): void; finishReply(key: string, now?: number): void; finishFailure(key: string, now?: number): void; recordStatus(providerMessageId: string, status: WhatsAppProviderStatus, outcomeCode?: string, now?: number): void; requestHandoff(key: string, now?: number): WhatsAppHandoff; handoffFor(channelId: string, customer: string): WhatsAppHandoff | null; listHandoffs(channelId?: string): WhatsAppHandoff[]; acceptHandoff(requestId: string, now?: number): WhatsAppHandoff; resumeHandoff(requestId: string, now?: number): WhatsAppHandoff; deferToHuman(key: string, now?: number): void; pruneTerminal(before: number): number; getThread(sessionKey: string): string | undefined; setThread(sessionKey: string, threadId: string): void; deleteThread(sessionKey: string): void; private updateAttemptState; private transitionHandoff; } export declare class InMemoryWhatsAppDeliveryStore extends BaseWhatsAppDeliveryStore { private state; protected readState(): DeliveryState; protected mutate(fn: (state: DeliveryState) => T): T; } export interface FileWhatsAppDeliveryStoreOptions { readonly dir: string; readonly secret?: string; } export declare class FileWhatsAppDeliveryStore extends BaseWhatsAppDeliveryStore { private readonly file; private readonly lockFile; private readonly key; constructor(opts: FileWhatsAppDeliveryStoreOptions); protected readState(): DeliveryState; protected mutate(fn: (state: DeliveryState) => T): T; private readUnlocked; private writeUnlocked; private withLock; } export declare function deterministicRunKey(channelId: string, inboundId: string): string; /** ThreadMap facade over the encrypted WhatsApp provider store. */ export declare class WhatsAppDeliveryThreadMap implements ThreadMap { private readonly store; constructor(store: WhatsAppDeliveryStore); get(sessionKey: string): Promise; set(sessionKey: string, threadId: string): Promise; delete(sessionKey: string): Promise; } export {}; //# sourceMappingURL=delivery-store.d.ts.map