import type { MessengerAdapter } from './types.js';
import { type OutboxKind, type OutboxPriority } from './outbox.js';
export type SinkKind = OutboxKind;
export type SinkPriority = OutboxPriority;
export interface SinkPayload {
    threadId: string;
    platform: string;
    channelId: string;
    /** For 'text': the message body (string).
     *  For 'card': the card object (will be JSON-encoded for storage).
     *  For 'typing': 'start' or 'stop'. */
    payload: string | object;
    kind: SinkKind;
    /** Default 'normal'. 'high' tries a synchronous send first and falls
     *  back to the queue only on failure — use for approval / restart
     *  notices where 1s+ worker latency matters. */
    priority?: SinkPriority;
    /** Link this delivery back to a jobs row (inline job / scheduled job).
     *  Phase 2 will use this to mark jobs.status='delivered' when the row
     *  reaches the IM. */
    jobId?: number | null;
    /** Optional explicit thread key. Default is
     *  `${platform}:${channelId}:${threadId}` (matches session.ts). */
    threadKey?: string;
    /** Optional already-resolved adapter. When provided, sink uses it
     *  directly for the sync attempt instead of consulting the global
     *  registry. Required by callers that maintain their own resolution
     *  indirection (e.g. approval-router.install accepts a custom
     *  resolveMessenger hook used by tests + multi-tenant setups). The
     *  outbox row is still recorded with platform=<name>; if the sync
     *  attempt fails, the worker re-resolves via registry the normal way. */
    adapter?: MessengerAdapter;
    /**
     * Origin of the message. Determines whether the viewer router gets to
     * truncate-and-link the payload.
     *   - 'agent'  → freeform LLM output. Long replies may route to the
     *               web viewer; the IM gets a summary + link.
     *   - 'system' (default) → operational confirmations, approval cards,
     *               reminders, restart notices, error blurbs, command
     *               outputs. ALWAYS inline, regardless of length —
     *               truncating these would hide the actual answer (e.g.
     *               a memo-creation confirmation, an approval prompt, an
     *               error message). Default is 'system' so any new
     *               callsite stays inline unless the dev opts in.
     */
    source?: 'agent' | 'system';
}
export interface SinkResult {
    /** Row id in the outbox table. -1 if persistence is unavailable AND the
     *  sync fallback also failed (the rare double-failure case — caller has
     *  no recourse beyond logging). */
    outboxId: number;
    /** True = the message was sent inline before this call returned (only
     *  possible when priority='high' and the sync attempt succeeded).
     *  False = queued for the worker. */
    immediate: boolean;
}
/** Resolve a platform name (e.g. 'wechat' / 'wechat-ilink' / 'feishu') to
 *  the actual MessengerAdapter. Exact match first, then a fuzzy `${name}-*`
 *  / `${name}_*` prefix walk so reminders.ts / scheduler / web callers can
 *  pass the generic platform ('wechat') and still hit 'wechat-ilink'. Mirrors
 *  the helper that already exists in reminders.ts:873 — kept in sink so the
 *  rest of the codebase can stop caring about adapter naming.
 *
 *  Exported for tests; production callers go through deliver(). */
export declare function resolveMessenger(platform: string): MessengerAdapter | undefined;
export declare function deliver(p: SinkPayload): Promise<SinkResult>;
export declare function startWorker(): void;
export declare function stopWorker(): void;
/** Test hook — run one tick synchronously. */
export declare function _tickWorkerForTests(): Promise<void>;
export declare const sink: {
    deliver: typeof deliver;
    startWorker: typeof startWorker;
    stopWorker: typeof stopWorker;
};
//# sourceMappingURL=message-sink.d.ts.map