/**
 * BlueBubbles config-shape helpers (multi-ACCOUNT aware; mirrors Slack's
 * `account-config.ts`).
 *
 * BlueBubbles is a richer iMessage transport than the native `imessage` channel:
 * instead of driving a local `imsg` CLI subprocess, it talks to a BlueBubbles
 * macOS server over HTTP REST (outbound) and receives inbound updates via a
 * webhook POST the server fires at a Brigade gateway HTTP route. So unlike
 * `imessage` (which has no secret), BlueBubbles HAS a real secret — the server
 * `password` — which is sealed into the encrypted credential store and embedded
 * in the registered webhook URL query string (BlueBubbles webhooks can't carry
 * custom headers).
 *
 * The knobs this module resolves per account:
 *
 *   - `serverUrl`    base URL of the BlueBubbles server (`http://192.168.1.5:1234`).
 *   - `password`     the SECRET — REST auth (`?password=…`) + webhook auth. Sealed.
 *   - `webhookPath`  the gateway inbound route path (default `/bluebubbles/webhook`).
 *   - `actions`      per-rich-action toggles (`reactions`/`edit`/`unsend`/`effects`/`groupAdmin`).
 *   - `region`       default phone-number region for E.164 normalisation (US).
 *   - `mediaMaxMb`   cap on an outbound attachment's size (MB).
 *   - `probeTimeoutMs` HTTP round-trip timeout for the doctor/probe + REST calls.
 *
 * Two config shapes are recognised so the surface lines up with the other
 * channels:
 *
 *   Legacy (single-account):
 *     channels.bluebubbles = { enabled: true, serverUrl: "http://…", password: "${BB_PASSWORD}" }
 *
 *   Multi-account:
 *     channels.bluebubbles = {
 *       enabled: true,
 *       accounts: [
 *         { id: "home", serverUrl: "http://192.168.1.5:1234", password: "${BB_HOME}" },
 *         { id: "work", serverUrl: "http://10.0.0.9:1234",    password: "${BB_WORK}" },
 *       ],
 *     }
 *
 * A legacy config with no `accounts[]` reads as `[{ id: "default" }]`.
 */
import type { BrigadeConfig } from "../../../config/io.js";
import type { BlueBubblesCatchupConfig } from "./catchup.js";
/** Canonical channel id + default account id. */
declare const CHANNEL_ID = "bluebubbles";
declare const DEFAULT_ACCOUNT_ID = "default";
/** Default inbound webhook route path (base; named accounts get a slug suffix). */
declare const DEFAULT_WEBHOOK_PATH = "/bluebubbles/webhook";
/** Default HTTP probe / request timeout (ms). */
export declare const DEFAULT_BLUEBUBBLES_PROBE_TIMEOUT_MS = 10000;
/** Default rolling group-history context size (recent messages attached to an untagged group msg). */
export declare const DEFAULT_BLUEBUBBLES_HISTORY_LIMIT = 10;
/** Hard ceiling on the rolling-history fetch size. */
export declare const BLUEBUBBLES_MAX_HISTORY_LIMIT = 100;
/** Per-knob env var consulted as a last-resort fallback for the password. */
declare const PASSWORD_ENV_VAR = "BLUEBUBBLES_PASSWORD";
/** Per-knob env var consulted as a last-resort fallback for the server URL. */
declare const SERVER_URL_ENV_VAR = "BLUEBUBBLES_SERVER_URL";
/**
 * Rich-action toggles. The five COARSE flags are the umbrella switches (each
 * defaults ON; the operator disables per account). The optional FINE-GRAINED
 * flags let the operator gate a single op independently — e.g. allow group
 * renames but forbid removing participants. A fine flag left undefined inherits
 * its umbrella (group-admin ops ← `groupAdmin`; `sendWithEffect` ← `effects`;
 * `reply`/`sendAttachment` ← always on) — finer per-op gating layered on top of
 * the coarse switches, which stay the simple default surface.
 */
export interface BlueBubblesActionFlags {
    reactions: boolean;
    edit: boolean;
    unsend: boolean;
    effects: boolean;
    groupAdmin: boolean;
    /** Native inline reply (a threaded reply to a specific message). Default: on. */
    reply?: boolean;
    /** Send with a bubble/screen effect. Default: inherits `effects`. */
    sendWithEffect?: boolean;
    /** Rename a group chat. Default: inherits `groupAdmin`. */
    renameGroup?: boolean;
    /** Set a group chat icon. Default: inherits `groupAdmin`. */
    setGroupIcon?: boolean;
    /** Add a participant to a group. Default: inherits `groupAdmin`. */
    addParticipant?: boolean;
    /** Remove a participant from a group. Default: inherits `groupAdmin`. */
    removeParticipant?: boolean;
    /** Leave a group. Default: inherits `groupAdmin`. */
    leaveGroup?: boolean;
    /** Send a media attachment. Default: on. */
    sendAttachment?: boolean;
}
/** Default rich-action toggles — everything on (Private API gates the rest at runtime). */
export declare const DEFAULT_BLUEBUBBLES_ACTIONS: BlueBubblesActionFlags;
/** The fine-grained per-op action flag names. */
export type BlueBubblesFineActionName = "reply" | "sendWithEffect" | "renameGroup" | "setGroupIcon" | "addParticipant" | "removeParticipant" | "leaveGroup" | "sendAttachment";
/**
 * Resolve whether a FINE-GRAINED op is allowed, honouring an explicit per-op
 * flag when set and otherwise inheriting the umbrella:
 *   - group-admin ops (rename/icon/add/remove/leave) ← `groupAdmin`;
 *   - `sendWithEffect` ← `effects`;
 *   - `reply` / `sendAttachment` ← always on (no coarse umbrella gates them).
 */
export declare function isBlueBubblesOpAllowed(actions: BlueBubblesActionFlags, op: BlueBubblesFineActionName): boolean;
/** Network policy overrides — relax the SSRF guard for a trusted LAN server. */
export interface BlueBubblesNetworkConfig {
    /**
     * Allow private/LAN/loopback BlueBubbles hosts (default TRUE — a BlueBubbles
     * server is almost always on the operator's LAN). Cloud-metadata stays blocked
     * regardless. Set false to force the strict public-only SSRF policy.
     */
    allowPrivate?: boolean;
}
/** Resolved per-account info — what the adapter runtime reads. */
export interface ResolvedBlueBubblesAccount {
    accountId: string;
    enabled: boolean;
    /** Base server URL (scheme-normalised, trailing slash stripped). */
    serverUrl: string;
    /** The server password (REST + webhook auth). May be "" when unset. */
    password: string;
    /** The gateway inbound route path for this account. */
    webhookPath: string;
    /** Default phone-number region (E.164 normalisation). */
    region: string;
    /** Outbound media size cap (bytes). */
    mediaMaxBytes: number;
    /** HTTP probe / request timeout (ms). */
    probeTimeoutMs: number;
    /** Per-rich-action toggles. */
    actions: BlueBubblesActionFlags;
    /** On-(re)connect catch-up backfill config (undefined → defaults; `enabled:false` disables). */
    catchup?: BlueBubblesCatchupConfig;
    /**
     * Inbound coalescing window (ms). When > 0, a text + its link-preview balloon
     * (or a text + a split-out attachment) arriving as two `new-message` webhooks
     * are merged into ONE agent turn. 0 (default) disables coalescing.
     */
    inboundDebounceMs: number;
    /**
     * Rolling group-history context: how many recent messages to fetch + attach
     * as context on an untagged GROUP message (so the agent sees what it's
     * replying into). 0 disables. Default 10.
     */
    historyLimit: number;
    /** Same as `historyLimit` but for DMs. 0 disables. Default 0 (DMs already carry their own thread). */
    dmHistoryLimit: number;
    /**
     * Allow-list of local directory roots an OUTBOUND attachment may be read from.
     * Layered ON TOP OF the central media-path denylist. Empty (default) = no
     * extra root restriction (the central guard still applies).
     */
    mediaLocalRoots: string[];
    /** Allow private/LAN/loopback targets through the SSRF guard (default TRUE). */
    allowPrivateNetwork: boolean;
    /**
     * The bot's OWN iMessage handle (phone/email) — used as `selfId` for group
     * mention-gating. Empty when the operator hasn't set it (mention-gating in
     * groups then can't fire and the channel falls back to its other group
     * addressed-signals). Normalised to digits for a phone, lower-case for email.
     */
    selfHandle: string;
    verbose: boolean;
}
/** Is the BlueBubbles channel switched on at all (any shape)? */
export declare function bluebubblesChannelEnabled(cfg: BrigadeConfig): boolean;
/** List configured account ids. Legacy single-account configs surface `["default"]`. */
export declare function listBlueBubblesAccountIds(cfg: BrigadeConfig): string[];
/**
 * Normalise a BlueBubbles server URL: trim, default the scheme to `http://`
 * when absent (BlueBubbles is commonly a LAN HTTP host), and strip trailing
 * slashes. Returns "" for an empty input (don't throw at config-read time).
 */
export declare function normalizeBlueBubblesServerUrl(raw: string): string;
/**
 * Resolve the BlueBubbles server URL for an account. Precedence: per-account
 * config `${VAR}`/literal → top-level config → `BLUEBUBBLES_SERVER_URL` env → "".
 */
export declare function resolveBlueBubblesServerUrl(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
/**
 * Resolve the server password (the SECRET) for an account. Precedence:
 * per-account config `${VAR}`/literal → top-level config `${VAR}`/literal →
 * durable sealed token (`channel:bluebubbles`) → `BLUEBUBBLES_PASSWORD` env → "".
 *
 * The sealed token is per-channel (NOT per-account today, like Slack's bot
 * token), so multi-account installs that need distinct passwords should use
 * `${VAR}` refs / env per account.
 */
export declare function resolveBlueBubblesPassword(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
/**
 * Resolve the inbound webhook route path for an account. The default account
 * keeps the base path; a named account (only present when >1 account is
 * configured) gets a distinct, collision-free path so two servers never share
 * one route. An explicit per-account `webhookPath` overrides the derived slug.
 */
export declare function resolveBlueBubblesWebhookPath(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
/** Resolve the HTTP probe / request timeout (ms) for an account. */
export declare function resolveBlueBubblesProbeTimeoutMs(cfg: BrigadeConfig, accountId?: string | null): number;
/** Resolve the per-rich-action toggles for an account. */
export declare function resolveBlueBubblesActions(cfg: BrigadeConfig, accountId?: string | null): BlueBubblesActionFlags;
/**
 * Normalise a handle for self/mention matching: an email lower-cases; a phone
 * keeps only its digits (so `+1 (555) 123-4567` and `15551234567` compare equal).
 * Returns "" for an empty input.
 */
export declare function normalizeBlueBubblesSelfHandle(raw: string | undefined): string;
/**
 * Resolve the bot's own handle for an account (per-account `selfHandle` wins over
 * the top-level slot), normalised. Empty when unset.
 */
export declare function resolveBlueBubblesSelfHandle(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): string;
/**
 * Resolve whether the SSRF guard should allow private/LAN/loopback hosts for an
 * account. Per-account `network.allowPrivate` wins over the top-level slot;
 * DEFAULTS TO TRUE (a BlueBubbles server is normally on the operator's LAN).
 * Cloud-metadata stays blocked regardless of this flag.
 */
export declare function resolveBlueBubblesAllowPrivateNetwork(cfg: BrigadeConfig, accountId?: string | null): boolean;
/**
 * Resolve the on-(re)connect catch-up backfill config for an account
 * (per-account overrides the top-level slot). Returns `undefined` when neither
 * level configured it — the connection then uses catch-up's built-in defaults.
 */
export declare function resolveBlueBubblesCatchup(cfg: BrigadeConfig, accountId?: string | null): BlueBubblesCatchupConfig | undefined;
/**
 * Resolve the inbound coalescing window (ms) for an account (per-account wins
 * over the top-level slot). 0 (default) disables coalescing.
 */
export declare function resolveBlueBubblesInboundDebounceMs(cfg: BrigadeConfig, accountId?: string | null): number;
/**
 * Resolve the rolling group-history context size for an account (per-account
 * wins over the top-level slot). Defaults to {@link DEFAULT_BLUEBUBBLES_HISTORY_LIMIT};
 * 0 disables.
 */
export declare function resolveBlueBubblesHistoryLimit(cfg: BrigadeConfig, accountId?: string | null): number;
/**
 * Resolve the rolling DM-history context size for an account. Defaults to 0
 * (a DM already carries its own thread context); 0 disables.
 */
export declare function resolveBlueBubblesDmHistoryLimit(cfg: BrigadeConfig, accountId?: string | null): number;
/**
 * Resolve the OUTBOUND-attachment local-root allow-list for an account
 * (per-account entries merged with the top-level slot, de-duped). Empty when
 * neither level configured it — the central media-path denylist still applies.
 */
export declare function resolveBlueBubblesMediaLocalRoots(cfg: BrigadeConfig, accountId?: string | null): string[];
/** Resolve a per-account view of the config (defaults filled in). */
export declare function resolveBlueBubblesAccount(cfg: BrigadeConfig, accountId?: string | null, env?: NodeJS.ProcessEnv): ResolvedBlueBubblesAccount;
/**
 * Resolve the idle-thread-session TTL in ms, or `null` when unset / disabled.
 * Accepts a number (ms) or a duration string (`"6h"`, `"30m"`, …). The cron
 * session-reaper uses this to age out idle BlueBubbles group sessions.
 */
export declare function bluebubblesThreadIdleTtlMs(cfg: BrigadeConfig): number | null;
export { CHANNEL_ID as BLUEBUBBLES_CHANNEL_ID, DEFAULT_ACCOUNT_ID as BLUEBUBBLES_DEFAULT_ACCOUNT_ID, PASSWORD_ENV_VAR as BLUEBUBBLES_PASSWORD_ENV_VAR, SERVER_URL_ENV_VAR as BLUEBUBBLES_SERVER_URL_ENV_VAR, DEFAULT_WEBHOOK_PATH as BLUEBUBBLES_DEFAULT_WEBHOOK_PATH, };
//# sourceMappingURL=account-config.d.ts.map