/**
 * CustomWebhookDestination -- Generic HTTPS POST destination with HMAC-SHA256 signing.
 *
 * Delivers governance events to any customer-controlled HTTPS endpoint using
 * deterministic HMAC-SHA256 request signing and zero-downtime dual-key rotation.
 *
 * Design decisions:
 *   - No external HTTP library. Plain HTTPS POST via Node built-ins (no supply-chain risk).
 *   - Secrets are NEVER stored in plaintext. Only KMS references are held.
 *     Resolved at send-time via injected SecretResolver.
 *   - Signing string: v1\nMETHOD\nPATH\ntimestamp\neventId\nsha256(body)\n
 *     Body hash prevents body tampering after signing.
 *   - Dual-key rotation: during the rotation window BOTH signatures travel in the same
 *     header, comma-separated. Receivers accept either.
 *     Window auto-completes after rotationWindowMs (default 24 h).
 *   - packBinding mandatory. Empty binding throws UnboundDataError at construction.
 *   - Secret bytes NEVER emitted to any log stream.
 *   - HTTPS enforced at construction. HTTP rejected. Raw IPs rejected.
 *   - 5xx + network = retryable. 4xx = DLQ.
 *
 * Signature header:
 *   X-AIAG-Signature: v1=<hex>                         (primary only)
 *   X-AIAG-Signature: v1=<hex_p>, v1=<hex_s>           (during rotation)
 *
 * @connexum/ai-governance
 */
import { OperatorRoles } from '../../security/operator-roles';
import type { EventPayload } from '../event-bus';
/**
 * Resolves a KMS/secret-manager reference to the actual plaintext secret.
 * Injected at construction time. The resolved bytes never live in config state.
 */
export type SecretResolver = (secretRef: string) => Promise<string>;
export interface CustomWebhookConfig {
    /** Discriminator for discriminated-union destination config registries. */
    kind: 'custom-webhook';
    /**
     * Full HTTPS endpoint URL.
     * Must be HTTPS (enforced at construction).
     * Must use a hostname, not a raw IP address.
     * Non-standard ports blocked per web-interaction-security.md Rule 5.
     */
    endpoint: string;
    /**
     * KMS reference for the current signing secret.
     * Never the raw bytes. Resolved at send-time via SecretResolver.
     */
    primarySecretRef: string;
    /** KMS reference for the outgoing/incoming secret during rotation. */
    secondarySecretRef?: string;
    /** HTTP header name for the signature. Default: 'X-AIAG-Signature'. */
    signatureHeader?: string;
    /** Signing algorithm. Only 'hmac-sha256' supported in v0. */
    signatureScheme?: 'hmac-sha256';
    /**
     * Headers included in the signing string.
     * Default: ['x-aiag-timestamp', 'x-aiag-event-id', 'content-type'].
     */
    signedHeaders?: string[];
    /** Maximum events to buffer before auto-flush. Default: 64. */
    bufferSize?: number;
    /** Request timeout in ms. Default: 5000. */
    timeoutMs?: number;
    /** Maximum retry attempts on retryable errors. Default: 3. */
    maxRetries?: number;
    /** Base retry delay in ms. Doubles each attempt with jitter. Default: 1000. */
    retryDelayMs?: number;
    /**
     * Duration (ms) of the dual-signing rotation window.
     * After this window, the secondary is auto-dropped.
     * Default: 86400000 (24 h).
     */
    rotationWindowMs?: number;
    /**
     * Compliance pack IDs governing this destination.
     * MANDATORY -- empty array throws UnboundDataError at construction.
     */
    packBinding: string[];
    /** Directory for dead-letter queue. Required. */
    dlqDir: string;
    /**
     * Allow HTTP (non-TLS) endpoints.
     * Default: false. Set true ONLY in test environments.
     */
    allowInsecure?: boolean;
}
export interface CustomWebhookDeliveryResult {
    success: boolean;
    statusCode?: number;
    attempts: number;
    error?: string;
    deliveredAt?: string;
    retryable?: boolean;
}
export interface CustomWebhookDeadLetterEntry {
    event: EventPayload;
    error: string;
    attempts: number;
    failedAt: string;
    retryable: boolean;
}
export declare class CustomWebhookDestination {
    private readonly cfg;
    private readonly resolver;
    private readonly roles;
    private readonly dlqFile;
    /** Pending event buffer. */
    private readonly pendingBuffer;
    /** Rotation window end (epoch ms). Undefined when not rotating. */
    private rotationWindowEnd;
    /** Auto-complete timer handle. */
    private rotationTimer;
    /** SHA-256 chain for rotation audit events. */
    private lastRotationEventHash;
    /** Set of emitted event UUIDs (PT-WEBHOOK-1 defense-in-depth). */
    private readonly emittedEventIds;
    constructor(config: CustomWebhookConfig, resolver: SecretResolver, roles: OperatorRoles);
    /**
     * Deliver one event to the configured endpoint.
     * Buffers events; delivers immediately in v0 (no network batching).
     */
    send(event: EventPayload): Promise<CustomWebhookDeliveryResult>;
    /**
     * Flush any pending events.
     * v0: events are delivered immediately in send(), so flush() is a no-op
     * unless there are buffered-but-undelivered events.
     */
    flush(): Promise<CustomWebhookDeliveryResult>;
    /** Get dead-letter queue entries. */
    getDLQ(limit?: number): CustomWebhookDeadLetterEntry[];
    /**
     * Begin secret rotation.
     *
     * Atomic swap: secondary = primary, primary = newPrimary.
     * Subsequent sends carry both signatures (dual-sign window).
     * Auto-completes after cfg.rotationWindowMs if not completed manually.
     *
     * Requires: 'governance.rotate-secret' permission (ADMIN role).
     */
    rotateSecret(newPrimaryRef: string, approverIdentity: string): Promise<void>;
    /**
     * Complete rotation explicitly.
     *
     * Drops the secondary secret; subsequent sends carry only the primary signature.
     * Call after confirming consumers validate against new primary.
     *
     * Requires: 'governance.rotate-secret' permission (ADMIN role).
     */
    completeRotation(approverIdentity: string): Promise<void>;
    /** Whether the destination is currently in the dual-signing rotation window. */
    isRotating(): boolean;
    /** Cancel pending rotation timers and release resources. */
    destroy(): void;
    private deliverEvent;
    private httpPost;
    private autoCompleteRotation;
    private dropSecondary;
    private emitRotationAuditEvent;
    private generateEventId;
    private writeDLQ;
    private safeEndpoint;
}
/**
 * Build the deterministic signing string.
 *
 * Format: v1\n<METHOD>\n<PATH>\n<x-aiag-timestamp>\n<x-aiag-event-id>\n<sha256(body) hex>\n
 *
 * Each field separated by \n; explicit trailing \n after body hash.
 * Including the body hash prevents body tampering after signing.
 */
export declare function buildSigningString(method: string, urlPath: string, timestamp: string, eventId: string, bodyHashHex: string): string;
/**
 * Compute HMAC-SHA256 over the signing string using the given secret.
 * Returns lowercase hex.
 */
export declare function computeHmac(secret: string, signingString: string): string;
/**
 * Serialize an audit event to canonical JSON (deterministic key order).
 * Prevents hash mismatch between signer and verifier due to key ordering.
 */
export declare function buildBody(event: EventPayload): string;
/**
 * Validate an endpoint URL at construction time.
 * - Must be HTTPS (unless allowInsecure).
 * - Must not be a raw IPv4 address.
 * - Must use standard HTTPS port (443) or omit port.
 */
export declare function validateEndpoint(endpoint: string, allowInsecure: boolean): void;
//# sourceMappingURL=custom-webhook.d.ts.map