import type { Context } from '../../api.js';
import type { SlackMessageEvent } from './types.js';
import type { ChannelMeta } from './scope.js';
export interface SlackHistoryPage {
    messages: SlackMessageEvent[];
    next_cursor: string | null;
}
export type SlackHistoryFetcher = (args: {
    channelId: string;
    /** Slack's opaque pagination token. Null on first page of a backfill run. */
    cursor: string | null;
    /**
     * Incremental-resume bound: skip messages with ts <= oldest. Set from
     * `slack_cursors.latest_ts` on the FIRST page of a rerun; unused on
     * subsequent pages within one run (where `cursor` carries us forward).
     * Distinct from `cursor` because Slack treats `cursor` as opaque token
     * and `oldest` as a numeric ts — feeding `latest_ts` as `cursor` breaks
     * against the live API even though it round-trips through test fetchers.
     */
    oldest?: string;
}) => Promise<SlackHistoryPage>;
export interface BackfillOpts {
    teamId: string;
    channel: ChannelMeta;
    fetcher: SlackHistoryFetcher;
    /** Stop after this many messages. Default: unlimited. */
    maxMessages?: number;
}
/**
 * Page through `conversations.history` via the injected fetcher and ingest each
 * message. The cursor is persisted to `slack_cursors` after every page so a
 * crash mid-backfill resumes near where it left off.
 *
 * Each ingested message uses a synthesized eventId of the form
 * `backfill:${teamId}:${channelId}:${ts}`. Reruns dedupe via the
 * `slack_event_log` PK so calling `backfillChannel` twice is safe.
 */
export declare function backfillChannel(ctx: Context, opts: BackfillOpts): Promise<{
    ingested: number;
    pages: number;
}>;
//# sourceMappingURL=backfill.d.ts.map