/**
 * Outbound webhook deliverer.
 *
 * Fires on grant-state transitions (pending, approved, denied, revoked,
 * expired) to user-configured HTTP endpoints. Three delivery "formats":
 *
 *   "cloudevents" (default)  — CloudEvents 1.0 JSON envelope. The most
 *                              interoperable choice; consumed by Knative,
 *                              Azure Event Grid, and most event routers.
 *   "slack"                  — Slack incoming-webhook shape ({ text,
 *                              blocks? }). Auto-selected when the URL
 *                              matches hooks.slack.com.
 *   "discord"                — Discord webhook shape ({ content,
 *                              embeds? }). Auto-selected for
 *                              discord.com/api/webhooks URLs.
 *   "raw"                    — Send the raw grant JSON.
 *
 * Signing: every delivery carries an `X-Mailpouch-Signature-256` header
 * whose value is `sha256=<hex>` of HMAC(body, secret) — matches the
 * GitHub webhook convention. No signing happens when the endpoint has
 * no secret configured.
 *
 * Retries: exponential backoff (1 / 2 / 4 / 8 / 16 / 32 / 64 / 128 s)
 * with ±20 % jitter, max 8 attempts. After the final failure we log
 * at warn and drop — no DLQ yet.
 */
import type { GrantChangedEvent } from "../agents/notifications.js";
/**
 * Reject URLs that would let an attacker-controlled (or mis-configured)
 * endpoint hit internal services — cloud metadata, loopback, private
 * ranges, link-local, IPv6 ULA. Admin can opt-in to private targets via
 * the `allowPrivateTargets` flag on the dispatcher (for self-hosted
 * routers like a local n8n or Home Assistant webhook).
 *
 * URL-host form is hostname-only; no DNS resolution is performed, so a
 * hostname that resolves to a private IP at delivery time will still be
 * caught by the server-side HTTP stack (Node's fetch honors redirects
 * to the same guard on the first request but not on redirects — callers
 * should treat redirects as suspicious regardless).
 */
export declare function isPrivateWebhookTarget(rawUrl: string): boolean;
export type WebhookFormat = "cloudevents" | "slack" | "discord" | "raw";
export interface WebhookEndpoint {
    id: string;
    url: string;
    /** Optional HMAC secret. When present, signs every body. */
    secret?: string;
    format?: WebhookFormat;
    enabled?: boolean;
    /** Which event kinds to deliver. Defaults to all grant events. */
    subscribe?: Array<"grant-created" | "grant-approved" | "grant-denied" | "grant-revoked" | "grant-expired">;
}
/** Auto-detect the best format from a URL when one isn't explicitly set. */
export declare function detectFormat(url: string): WebhookFormat;
/** Build the outgoing body for a given format + grant event. */
export declare function buildPayload(ev: GrantChangedEvent, format: WebhookFormat): Record<string, unknown>;
export interface DeliveryResult {
    endpointId: string;
    url: string;
    ok: boolean;
    status?: number;
    attempts: number;
    lastError?: string;
}
export interface WebhookDispatcherDeps {
    /** Override fetch for tests. */
    fetcher?: typeof globalThis.fetch;
    /** Override sleep for deterministic tests. */
    sleep?: (ms: number) => Promise<void>;
    /**
     * Permit webhooks to loopback / RFC-1918 / link-local / ULA targets.
     * Off by default — SSRF-style defense for cloud deployments. Enable
     * only for self-hosted routers (n8n on the LAN, local Home Assistant,
     * etc.). See `isPrivateWebhookTarget` for the full guard list.
     */
    allowPrivateTargets?: boolean;
}
export declare class WebhookDispatcher {
    private readonly fetcher;
    private readonly sleep;
    private readonly allowPrivateTargets;
    constructor(deps?: WebhookDispatcherDeps);
    /**
     * Deliver one event to one endpoint with retry/backoff. Resolves with
     * the final DeliveryResult; never rejects (failures logged + returned).
     */
    deliver(endpoint: WebhookEndpoint, ev: GrantChangedEvent): Promise<DeliveryResult>;
    /** Deliver to every enabled endpoint in parallel. Returns per-endpoint results. */
    deliverAll(endpoints: WebhookEndpoint[], ev: GrantChangedEvent): Promise<DeliveryResult[]>;
}
//# sourceMappingURL=webhooks.d.ts.map