import type { DatabaseSyncLike } from '../../db.js';
import { type Context } from '../../api.js';
export type DlqBucket = 'parse_error' | 'unroutable' | 'signature_fail';
export interface DlqItem {
    id: number;
    tenantId: string;
    teamId: string | null;
    rawPayload: string;
    error: string;
    receivedAt: string;
    retriedAt: string | null;
    bucket: DlqBucket | string;
    retryCount: number;
    signature: string | null;
    slackTimestamp: string | null;
}
/**
 * v0.39 commit 3: writeToDlq is now bucket-aware. `bucket` defaults to
 * 'parse_error' to preserve the legacy single-arg call sites while letting
 * new callers tag rows for `hippo slack dlq replay` triage.
 *
 * `tenantId: null` means "no tenant resolved" (unroutable team). Stored as
 * the sentinel '__unroutable__' so the column stays NOT NULL — a mismatch
 * the listing CLI surfaces explicitly.
 */
export interface WriteDlqOpts {
    tenantId: string | null;
    rawPayload: string;
    error: string;
    bucket?: DlqBucket;
    teamId?: string | null;
    signature?: string | null;
    slackTimestamp?: string | null;
}
export declare function writeToDlq(db: DatabaseSyncLike, opts: WriteDlqOpts): number;
export declare function listDlq(db: DatabaseSyncLike, opts: {
    tenantId: string;
    limit?: number;
}): DlqItem[];
export declare function getDlqEntry(db: DatabaseSyncLike, id: number): DlqItem | null;
export declare function markDlqRetried(db: DatabaseSyncLike, id: number): void;
export interface ReplayDlqOpts {
    /** Skip signature verification when the row's signature/timestamp are missing or stale. */
    force?: boolean;
    /** Current signing secret. If omitted, signature check is skipped (force-only path). */
    signingSecret?: string;
    /** Now (unix seconds) override for tests. */
    now?: number;
    /** Skew window override for tests. */
    skewSeconds?: number;
}
export interface ReplayDlqResult {
    ok: boolean;
    status: string;
    memoryId: string | null;
    retryCount: number;
    reason?: string;
}
/**
 * Replay a DLQ row through the normal ingest path. Used by `hippo slack dlq
 * replay <id> [--force]`.
 *
 * Behavior:
 *   1. SELECT the row.
 *   2. If signature + slack_timestamp are present and `signingSecret` is set,
 *      re-verify with the CURRENT secret (not previous). Failure → bail unless
 *      --force. Legacy rows from before v19 may have NULL signature; those
 *      require --force to replay safely.
 *   3. Re-parse the raw_payload and dispatch to ingestMessage / handleMessageDeleted.
 *   4. On success: mark retried_at, increment retry_count.
 *   5. On failure: increment retry_count only, leave the row.
 *
 * The replay always uses the routing the deployment has NOW (current
 * slack_workspaces table + env), not whatever was in effect when the original
 * envelope was DLQed. That is intentional: the DLQ exists to be drained after
 * the operator fixed the routing.
 */
export declare function replayDlqEntry(ctx: Pick<Context, 'hippoRoot'>, id: number, opts?: ReplayDlqOpts): ReplayDlqResult;
//# sourceMappingURL=dlq.d.ts.map