import { type Kysely, type Transaction } from 'kysely';
import type { Database } from '../db/types.js';
import type { DlqReason, EventRouterConfig, StoredEvent } from './types.js';
/** Either a Kysely DB handle or an active transaction. */
export type DbExecutor = Kysely<Database> | Transaction<Database>;
/**
 * Input shape for writing a new event. Excludes columns the DB fills in
 * itself (id, processed, created_at, attempts, claimed_*, last_error,
 * next_retry_at, dlq_*).
 */
export interface NewEventInput {
    eventName: string;
    payload: Record<string, unknown>;
    sourceRepo?: string;
    sourceRoutingKey?: string;
    sourceRunId?: string;
    sourceJobId?: string;
    targetRepos?: string[];
    chainDepth: number;
    expiresAt: Date;
}
/**
 * Persists and queries internal events (system + custom).
 *
 * Provides:
 *  - TTL-based cleanup for expired non-DLQ events.
 *  - Lease-based dispatch claim with bounded retries (replaces the prior
 *    "flip processed=true upfront" pattern that silently lost events when
 *    dispatch threw).
 *  - DLQ helpers for surfacing events that exhausted retries.
 */
export declare class EventStore {
    private readonly db;
    private readonly config;
    private cleanupTimer;
    constructor(db: Kysely<Database>, config: EventRouterConfig);
    /**
     * Expose the underlying Kysely handle for callers that need to issue
     * `pg_notify` outside of EventStore (e.g. the admin DLQ retry route, which
     * re-publishes after `resetFromDlq` so a healthy node picks the event up
     * before the next retry-scanner tick).
     */
    getDb(): Kysely<Database>;
    /**
     * Write a new event to the store using the default DB handle.
     * Computes expires_at from the configured TTL.
     * Returns the generated event ID.
     */
    write(event: NewEventInput): Promise<string>;
    /**
     * Write a new event using a caller-provided executor (typically a Kysely
     * Transaction). Used by `EventRouter.emitInTx` to atomically combine the
     * insert with other transactional work (e.g. cron `tryClaimFire`).
     */
    writeWith(event: NewEventInput, executor: DbExecutor): Promise<string>;
    /**
     * Retrieve a single event by ID.
     */
    getById(id: string): Promise<StoredEvent | null>;
    /**
     * Get unprocessed events for catch-up on reconnect.
     * If sinceId is null, returns all unprocessed events.
     * Ordered by created_at ASC. Excludes DLQ rows.
     */
    getUnprocessedSince(sinceId: string | null, limit?: number): Promise<StoredEvent[]>;
    /**
     * Mark an event as fully processed. Called after a successful dispatch.
     * Clears any prior lease so the row is unambiguously terminal.
     */
    markProcessed(id: string): Promise<void>;
    /**
     * Atomically take a dispatch lease on an event. Replaces the previous
     * "flip processed=true upfront" pattern that silently lost events when
     * dispatch threw after the flip.
     *
     * The UPDATE succeeds when:
     *  - the event is not yet processed and not in DLQ, AND
     *  - either no lease is held, OR the existing lease has expired.
     *
     * On success: sets `claimed_at = NOW()`, `claimed_by = $leaseHolder`,
     * increments `attempts`. The caller must subsequently call `markProcessed`
     * (success), `recordDispatchFailure` (failure with retry), or `markDlq`
     * (terminal failure) — otherwise the lease times out after
     * `leaseDurationMs` and the leader-only retry scanner releases it.
     *
     * Returns the leased event row, or null if the event was already
     * processed/leased/DLQ'd.
     */
    tryLeaseForProcessing(id: string, leaseHolder: string): Promise<StoredEvent | null>;
    /**
     * Record a failed dispatch attempt. Releases the lease, stores the
     * (truncated) error, and schedules the next retry. The leader-only
     * retry scanner will re-publish `pg_notify` for this event when
     * `next_retry_at <= NOW()`.
     */
    recordDispatchFailure(id: string, errorMessage: string, nextRetryAt: Date): Promise<void>;
    /**
     * Mark an event as DLQ. Sets `processed=true` so it stops being eligible
     * for retry, records `dlq_at` + `dlq_reason`, and preserves `last_error`
     * (overwritten if a fresh error message is provided).
     */
    markDlq(id: string, reason: DlqReason, errorMessage?: string): Promise<void>;
    /**
     * Find events whose `next_retry_at` is due. The leader-only retry scanner
     * uses this to know which events to re-publish via `pg_notify`.
     */
    findEventsDueForRetry(limit: number): Promise<StoredEvent[]>;
    /**
     * Find events whose lease has expired. The leader-only scanner releases
     * these (clears `claimed_at` + sets `next_retry_at = NOW()`) and then
     * re-publishes `pg_notify` so a healthy node picks them up.
     */
    findExpiredLeases(limit: number): Promise<StoredEvent[]>;
    /**
     * Release an expired lease so the event is once again eligible for
     * `tryLeaseForProcessing`. Used by the retry scanner together with a
     * `pg_notify` re-publication.
     */
    releaseExpiredLease(id: string): Promise<void>;
    /**
     * List events currently in the DLQ. Most recent first. Used by the
     * dashboard admin DLQ page.
     *
     * @param sourceRoutingKey - When provided, restrict the result to
     *   events whose `source_routing_key` matches. Used by routing-key
     *   -scoped admin tokens so the operator only sees their slice.
     */
    listDlq(limit: number, beforeDlqAt?: Date, sourceRoutingKey?: string): Promise<StoredEvent[]>;
    /**
     * Count events currently in the DLQ. Used by the dashboard summary row
     * and the `kici_orch_event_dlq_depth` gauge.
     *
     * @param sourceRoutingKey - When provided, restrict the count to
     *   events whose `source_routing_key` matches.
     */
    countDlq(sourceRoutingKey?: string): Promise<number>;
    /**
     * Reset a DLQ event so it gets retried on the next scanner tick. Used by
     * the dashboard "Retry" action.
     */
    resetFromDlq(id: string): Promise<boolean>;
    /**
     * Permanently delete a DLQ event. Used by the dashboard "Discard" action.
     */
    deleteDlq(id: string): Promise<boolean>;
    /**
     * Delete expired events. Returns the count of deleted rows. DLQ rows are
     * preserved so operators have time to triage them.
     */
    cleanup(): Promise<number>;
    /**
     * Start periodic cleanup using setInterval.
     */
    startCleanupTimer(): void;
    /**
     * Stop periodic cleanup.
     */
    stopCleanupTimer(): void;
    /**
     * Convert a DB row to a StoredEvent.
     */
    private rowToStoredEvent;
}
//# sourceMappingURL=event-store.d.ts.map