/**
 * The contract between a text channel (WhatsApp, Telegram, …) and the agent: what an adapter reads
 * off a webhook and what it is asked to deliver. Framework-free — `channels.handle()` builds the
 * {@link ChannelRequest} from Adonis's `HttpContext`, and a test builds one by hand.
 */
/** The markdown a channel renders: WhatsApp's, Telegram's MarkdownV2, or none (plain text). */
export type ChannelMarkdown = 'whatsapp' | 'telegram' | 'none';
/** What a channel can show — what the service shapes every reply to. */
export interface ChannelCapabilities {
    /**
     * The most reply buttons one message can carry. Omitted (or below 2) → the channel has none, and a
     * proposal is put to the person as a text instruction instead of Confirm/Cancel buttons.
     */
    buttons?: number;
    /** The markdown dialect replies are converted to. */
    markdown: ChannelMarkdown;
    /** The longest text one message may carry; longer replies are split into several messages. */
    maxLength: number;
    /**
     * The adapter can send files ({@link OutboundMessage} with `media`) — images and documents with a
     * caption. Omitted → a file reply is sent as its caption / fallback text.
     */
    media?: boolean;
    /** The longest caption a file may carry. Default: {@link maxLength}. */
    maxCaptionLength?: number;
    /**
     * The most entries a list message can carry (a WhatsApp list, a Telegram keyboard of one row per
     * entry). Omitted → no lists: a component's list goes out as reply buttons when it fits, else as
     * numbered text.
     */
    lists?: number;
}
/** One webhook request, as an adapter sees it. */
export interface ChannelRequest {
    /** Upper-case HTTP method. */
    method: string;
    /** Path and query string, e.g. `/webhooks/whatsapp?hub.mode=subscribe`. */
    url: string;
    /** A request header by (case-insensitive) name. */
    header(name: string): string | undefined;
    /** Route params (`/webhooks/whatsapp/:token` → `{ token }`). */
    params: Record<string, unknown>;
    /** The parsed body. */
    body: unknown;
    /**
     * The body exactly as it arrived — what a signature is computed over. `null` when the body parser
     * did not keep it (a request it does not parse).
     */
    rawBody: string | null;
}
/** A message a person sent on the channel. */
export interface InboundMessage {
    /** The provider's id for this message — retries of one delivery carry the same id. */
    id: string;
    /** Who sent it: a phone number, a Telegram user id… — what `actor()` maps to an account. */
    from: string;
    /** Where replies go: the chat / conversation id {@link ChannelAdapter.send} is called with. */
    conversation: string;
    /**
     * What the person wrote — for a button press, the button's label (or its id when there is none);
     * for a media message, its caption (`''` when it has none).
     */
    text: string;
    /** Files the message carries (an image, a voice note, a document) — downloaded and attached to the turn. */
    media?: InboundMedia[];
    /** The id of the reply button the person pressed, when the message is a button press. */
    buttonId?: string;
    /**
     * A button press whose id the provider did not forward — only its label, in {@link text}
     * (Whatsmiau). The handler maps it to the proposal card it can only have come from, if there is
     * exactly one.
     */
    buttonWithoutId?: boolean;
    /**
     * When the person sent it, in epoch milliseconds — the provider's own timestamp (Evolution /
     * Whatsmiau `messageTimestamp`, WhatsApp Cloud `timestamp`, Telegram `date`). Stored with the turn's
     * message (`StoredMessage.sentAt`), so a turn that waited (a queue, a `coalesce` burst) still knows
     * when it was said — what `messageTimestamps` shows the model. Absent when the provider sent none
     * (a Telegram button press): the message's `createdAt` stands for it.
     */
    sentAt?: number;
    /** The provider's payload, untouched. */
    raw: unknown;
}
/** One file in an inbound message, before it is downloaded. */
export interface InboundMedia {
    kind: 'image' | 'audio' | 'video' | 'document' | 'sticker';
    /** MIME type, when the webhook says (it usually does). */
    contentType?: string;
    /** The file's name, when the webhook says (documents). */
    filename?: string;
    /** Size in bytes, when the webhook says. */
    sizeBytes?: number;
    /** Whatever the adapter needs to download it (a media id, a file id, the message key). */
    ref: unknown;
}
/** A downloaded file. */
export interface ChannelMediaFile {
    data: Buffer;
    contentType: string;
    filename?: string;
}
export interface ChannelButton {
    /** What comes back as {@link InboundMessage.buttonId} when it is pressed. */
    id: string;
    label: string;
}
/** One entry of a list message. */
export interface ChannelListRow {
    /** What comes back as {@link InboundMessage.buttonId} when it is picked. */
    id: string;
    title: string;
    description?: string;
}
/** A list to pick one entry from — see {@link ChannelCapabilities.lists}. */
export interface OutboundList {
    /** The label of the button that opens the list (WhatsApp). */
    button: string;
    /** A heading over the entries. */
    title?: string;
    rows: ChannelListRow[];
}
/** A file to send: by a URL the provider downloads it from, or by its bytes. */
export interface OutboundMedia {
    kind: 'image' | 'document' | 'audio' | 'video';
    /** An `https` URL the provider fetches the file from (short-lived URLs are fine). */
    url?: string;
    /** The file itself, when there is no URL. One of `url` / `data` is required. */
    data?: Buffer;
    /** MIME type — `image/png`, `application/pdf`. Recommended (some providers require it). */
    contentType?: string;
    /** The name a document is shown under. */
    filename?: string;
}
/**
 * One message to deliver: text, text with reply buttons, or a file with a caption (`text`, `''` for
 * none). An adapter without {@link ChannelCapabilities.media} is never handed a file: the handler
 * sends the caption (or the reply's `fallbackText`) instead.
 */
export type OutboundMessage = {
    text: string;
    buttons?: undefined;
    fallbackText?: undefined;
    instruction?: undefined;
    footer?: undefined;
    media?: undefined;
    list?: undefined;
} | {
    text: string;
    buttons: ChannelButton[];
    /**
     * The same message as text only — a reply instruction in place of the buttons. What an adapter
     * sends when the provider definitely refused the buttons (a 4xx), so the person still gets a
     * way to answer.
     */
    fallbackText: string;
    /**
     * The reply instruction alone ("Reply *yes* to confirm or *no* to cancel."), already in the
     * channel's markdown. An adapter whose buttons may not render on every phone puts it in the
     * buttons message too, so the person can still answer by text.
     */
    instruction?: string;
    /**
     * A short line under the card (`texts.footer` — "Valid for 5 minutes."), already in the
     * channel's markdown. Sent as the provider's footer where it has one, else after the text.
     * `fallbackText` already ends with it.
     */
    footer?: string;
    media?: undefined;
    list?: undefined;
} | {
    /** The body over the list, already in the channel's markdown. */
    text: string;
    list: OutboundList;
    /** The same message as numbered text — what an adapter sends when the list is refused. */
    fallbackText: string;
    buttons?: undefined;
    instruction?: undefined;
    footer?: undefined;
    media?: undefined;
} | {
    /** The caption, already in the channel's markdown — `''` for none. */
    text: string;
    media: OutboundMedia;
    buttons?: undefined;
    fallbackText?: undefined;
    instruction?: undefined;
    footer?: undefined;
    list?: undefined;
};
/** A reply the adapter answers the webhook with instead of acknowledging it (a verification GET). */
export interface ChannelChallengeResponse {
    status: number;
    body: string;
    contentType?: string;
}
/** Why a webhook body carried no message to answer — see {@link ChannelAdapter.ignored}. */
export interface ChannelIgnored {
    /** The provider's event name, when the body has one. */
    event?: string;
    /** Short and content-free: `own message`, `group`, `fromMe missing and status PENDING`… */
    reason: string;
    /** It looked like a person's message but could not be read — logged as a warning, not debug. */
    unexpected?: boolean;
}
/**
 * One text channel. The built-in ones are `evolutionApi()`, `whatsmiau()`, `whatsappCloud()` and
 * `telegram()`; any object of this shape works the same way.
 */
export interface ChannelAdapter {
    /** Names the channel: the dedupe key's prefix, and `via` on a decision made with its buttons. */
    readonly name: string;
    /**
     * What the channel is — `whatsapp`, `telegram` — whatever it is named: the turn's channel
     * (`turnChannel`), so `genui({ channels: { whatsapp } })` applies to every WhatsApp adapter.
     * Default: {@link name}.
     */
    readonly kind?: string;
    readonly capabilities: ChannelCapabilities;
    /**
     * Answer a request that is not a message — WhatsApp Cloud's `GET ?hub.challenge=…` subscription
     * check. `null` → not one of those; the request goes on to {@link verify}.
     */
    challenge?(request: ChannelRequest): ChannelChallengeResponse | null;
    /** Is this request really from the provider (a signature, a shared token)? `false` → `401`. */
    verify(request: ChannelRequest): boolean | Promise<boolean>;
    /**
     * The person's message(s) in a verified webhook body. `null` (or `[]`) → nothing to answer: a
     * delivery receipt, the bot's own message, a group, a media message…
     */
    parse(body: unknown): InboundMessage | InboundMessage[] | null;
    /**
     * Why a body {@link parse}d to no message — the handler logs it, so a dropped webhook can be
     * diagnosed. Called only then; never put message content in it. `null` → no reason to give.
     */
    ignored?(body: unknown): ChannelIgnored | null;
    /**
     * Tell the provider the message was received, where it waits for that — Telegram's
     * `answerCallbackQuery` after a button press. Runs in the background, before the turn.
     */
    acknowledge?(message: InboundMessage): Promise<void>;
    /**
     * Download one of a message's {@link InboundMessage.media}. Throws {@link
     * import('./http.js').ChannelMediaTooLargeError} past `maxBytes` (without reading the rest).
     * Absent → media messages are answered with `texts.mediaRefused`.
     */
    download?(media: InboundMedia, options: {
        maxBytes: number;
    }): Promise<ChannelMediaFile>;
    /** Deliver one message to a conversation. Throws when the provider refused it. */
    send(conversation: string, message: OutboundMessage): Promise<void>;
}
//# sourceMappingURL=types.d.ts.map