import { EventEmitter } from "node:events";
import { TelemetryReporter } from "@agentvault/crypto";
import type { SecureChannelConfig, ChannelState, HistoryEntry, SendOptions, DecisionRequest, DecisionResponse, HeartbeatStatus, StatusAlert, RoomMemberInfo, RoomConversationInfo, RoomInfo, A2AChannel, DeliveryTarget, DeliveryContent, DeliveryOptions, DeliveryReceipt, TargetInfo } from "./types.js";
export declare class SecureChannel extends EventEmitter {
    private config;
    private _state;
    private _deviceId;
    private _fingerprint;
    private _primaryConversationId;
    private _deviceJwt;
    private _sessions;
    private _ws;
    private _pollTimer;
    private _reconnectAttempt;
    private _reconnectTimer;
    private _rapidDisconnects;
    private _lastWsOpenTime;
    private _pingTimer;
    private _lastServerMessage;
    private _pendingAcks;
    private _ackTimer;
    private _stopped;
    private _persisted;
    private _httpServer;
    private _mcpServer;
    private _pollFallbackTimer;
    private _heartbeatTimer;
    private _heartbeatCallback;
    private _heartbeatIntervalSeconds;
    private _wakeDetectorTimer;
    private _lastWakeTick;
    private _trustToken;
    private _trustTier;
    private _trustTokenExpiresAt;
    private _trustTokenInterval;
    private _pendingPollTimer;
    private _syncMessageIds;
    private _deliveryHeartbeat;
    private _deliveryPulling;
    /** MLS group managers per room/conversation (roomId or conv:conversationId -> MLSGroupManager) */
    private _mlsGroups;
    /** Cached MLS KeyPackage bundle for this device (regenerated on each connect). */
    private _mlsKeyPackage;
    /** Pending KeyPackage bundle from request-Welcome flow (used by _handleMlsWelcome). */
    private _pendingMlsKpBundle;
    /** In-memory credential store for renter-provided credentials (never persisted). */
    private _credentialStore;
    /** Dedup buffer for A2A message IDs (prevents double-delivery via direct + Redis) */
    private _a2aSeenMessageIds;
    private static readonly A2A_SEEN_MAX;
    /** Dedup buffer for regular message IDs (prevents double-decrypt via direct WS + Redis pub/sub) */
    private _seenMessageIds;
    private static readonly SEEN_MSG_MAX;
    private _scanEngine;
    private _scanRuleSetVersion;
    private _telemetryReporter;
    /** Topic ID from the most recent inbound message — used as fallback for replies. */
    private _lastIncomingTopicId;
    /** Room ID from the most recent inbound room message — used as fallback for HTTP /send replies. */
    private _lastInboundRoomId;
    /** Rate-limit: last resync_request timestamp per conversation (5-min cooldown). */
    private _lastResyncRequest;
    /** Debounce timer for server backup uploads (60s). */
    private _serverBackupTimer;
    private _serverBackupRunning;
    private static readonly PING_INTERVAL_MS;
    private static readonly SILENCE_TIMEOUT_MS;
    private static readonly POLL_FALLBACK_INTERVAL_MS;
    private static readonly POLL_FALLBACK_IDLE_MS;
    constructor(config: SecureChannelConfig);
    get state(): ChannelState;
    get deviceId(): string | null;
    get fingerprint(): string | null;
    /** Returns the primary conversation ID (backward-compatible). */
    get conversationId(): string | null;
    /** Returns all active conversation IDs. */
    get conversationIds(): string[];
    /** Returns the number of active sessions. */
    get sessionCount(): number;
    /** Room ID from the most recent inbound room message (for HTTP /send fallback). */
    get lastInboundRoomId(): string | undefined;
    /** Returns all persisted room IDs and names (for outbound target registration). */
    get roomIds(): Array<{
        roomId: string;
        name: string;
    }>;
    /** Returns hub addresses of all persisted A2A peer participants. */
    get a2aPeerAddresses(): string[];
    /** Resolves an A2A channel ID to the first active peer's hub address, or null if not found. */
    resolveA2AChannelHub(channelId: string): string | null;
    /** Returns the TelemetryReporter instance (available after WebSocket connect). */
    get telemetry(): TelemetryReporter | null;
    /**
     * Check if a skill is in shadow mode. Returns the shadow config if active, undefined otherwise.
     */
    getShadowConfig(skillName: string): {
        sessionId: string;
        autonomyLevel: string;
        decisionClass: string;
    } | undefined;
    start(): Promise<void>;
    /**
     * Fetch scan rules from the server and load them into the ScanEngine.
     */
    private _fetchScanRules;
    /**
     * Append a message to persistent history for cross-device replay.
     */
    private _appendHistory;
    /**
     * Get recent message history for a specific room, for LLM context injection.
     * Returns the last N messages tagged with `room:{roomId}`.
     */
    getRoomHistory(roomId: string, maxMessages?: number): HistoryEntry[];
    /**
     * Encrypt and send a message to ALL owner devices (fanout).
     * Each session gets the same plaintext encrypted independently.
     */
    send(plaintext: string, options?: SendOptions): Promise<void>;
    /**
     * Send a typing indicator to all owner devices.
     * Ephemeral (unencrypted metadata), no ratchet advancement.
     */
    sendTyping(): void;
    /**
     * Send an activity span to all owner devices via WS.
     * Ephemeral (unencrypted metadata, like typing), no ratchet advancement.
     */
    sendActivitySpan(spanData: Record<string, unknown>): void;
    /**
     * Send a decision request to the owner.
     * Builds a structured envelope with decision metadata and sends it
     * as a high-priority message. Returns the generated decision_id.
     */
    sendDecisionRequest(request: DecisionRequest): Promise<string>;
    /**
     * Wait for a decision response matching the given decisionId.
     * Listens on the "message" event for messages where
     * metadata.messageType === "decision_response" and the parsed plaintext
     * contains a matching decision.decision_id.
     * Optional timeout rejects with an Error.
     */
    waitForDecision(decisionId: string, timeoutMs?: number): Promise<DecisionResponse>;
    /**
     * Join a room by collecting pairwise conversation IDs involving this device.
     * Encryption is handled by MLS group operations, not per-member DR sessions.
     */
    joinRoom(roomData: {
        roomId: string;
        name: string;
        members: RoomMemberInfo[];
        conversations: RoomConversationInfo[];
        forceRekey?: boolean;
    }): Promise<void>;
    /**
     * Send an encrypted message to all members of a room.
     * Uses MLS (preferred) or pairwise fan-out as fallback.
     */
    sendToRoom(roomId: string, plaintext: string, opts?: {
        messageType?: string;
        priority?: string;
        metadata?: Record<string, unknown>;
    }): Promise<void>;
    /**
     * Leave a room: remove sessions and persisted room state.
     */
    leaveRoom(roomId: string): Promise<void>;
    /**
     * Return info for all joined rooms.
     */
    getRooms(): RoomInfo[];
    startHeartbeat(intervalSeconds: number, statusCallback: () => HeartbeatStatus): void;
    stopHeartbeat(): Promise<void>;
    sendStatusAlert(alert: StatusAlert): Promise<void>;
    sendArtifact(artifact: {
        filePath: string;
        filename: string;
        mimeType: string;
        description?: string;
    }): Promise<void>;
    sendActionConfirmation(confirmation: {
        action: string;
        status: "completed" | "failed" | "partial";
        decisionId?: string;
        detail?: string;
    }): Promise<void>;
    sendActionConfirmationToRoom(roomId: string, confirmation: {
        action: string;
        status: "completed" | "failed" | "partial";
        decisionId?: string;
        detail?: string;
        estimated_cost?: number;
    }): Promise<void>;
    /**
     * Canonical message dispatcher. ALL outbound messages should flow through this method.
     * Routes based on explicit target — never silently falls back to a room.
     */
    deliver(target: DeliveryTarget, content: DeliveryContent, options?: DeliveryOptions): Promise<DeliveryReceipt>;
    /**
     * Returns all available delivery destinations with availability status.
     */
    listTargets(): TargetInfo[];
    private _sendHeartbeat;
    getTrustHeaders(): Record<string, string>;
    get trustToken(): string | null;
    get trustTier(): string | null;
    get trustTokenExpiresAt(): string | null;
    refreshTrustToken(): Promise<void>;
    startTrustTokenRefresh(): void;
    stopTrustTokenRefresh(): void;
    stop(): Promise<void>;
    startHttpServer(port: number): void;
    private _stopHttpServer;
    /**
     * Attach an MCP server instance to this channel.
     * The MCP server will be served at /mcp on the local HTTP server.
     */
    setMcpServer(mcpServer: import("./mcp-server.js").AgentVaultMcpServer): void;
    /** The attached MCP server, if any. */
    get mcpServer(): import("./mcp-server.js").AgentVaultMcpServer | null;
    /**
     * Create a new topic within the conversation group.
     * Requires the channel to be initialized with a groupId (from activation).
     */
    createTopic(name: string): Promise<{
        id: string;
        name: string;
        isDefault: boolean;
    }>;
    /**
     * List all topics in the conversation group.
     * Requires the channel to be initialized with a groupId (from activation).
     */
    listTopics(): Promise<Array<{
        id: string;
        name: string;
        isDefault: boolean;
    }>>;
    /**
     * Request a new A2A channel with another agent by their hub address.
     * Returns the channel_id from the server response.
     */
    requestA2AChannel(responderHubAddress: string): Promise<string>;
    /**
     * Invite another agent to an existing A2A channel by their hub address.
     */
    inviteToA2AChannel(channelId: string, hubAddress: string): Promise<void>;
    /**
     * Send a message to another agent via an active A2A channel.
     * Looks up the A2A conversation by hub address and sends via WS.
     *
     * If the channel has an established E2E session, the message is encrypted
     * with the Double Ratchet. If the responder hasn't received the initiator's
     * first message yet (ratchet not activated), the message is queued locally
     * and flushed when the first inbound message arrives.
     *
     * Falls back to plaintext for channels without a session (legacy/pre-encryption).
     */
    sendToAgent(hubAddress: string, text: string, opts?: {
        parentSpanId?: string;
    }): Promise<void>;
    /**
     * Send a message to a specific A2A channel by channel ID.
     * Used for multi-agent channels where hub address routing is ambiguous.
     */
    sendToA2AChannel(channelId: string, text: string): Promise<void>;
    /**
     * List all A2A channels for this agent.
     * Fetches from the server and updates local persisted state.
     */
    listA2AChannels(): Promise<A2AChannel[]>;
    private _enroll;
    private _poll;
    private _activate;
    private _connect;
    /**
     * Handle an incoming encrypted message from a specific conversation.
     * Decrypts using the appropriate session ratchet, emits to the agent,
     * and relays as sync messages to sibling sessions.
     */
    /**
     * Handle an incoming MLS-encrypted 1:1 message.
     * Decrypts via the conversation's MLSGroupManager and emits the plaintext.
     */
    private _handleMessageMLS;
    private _handleIncomingMessage;
    /**
     * Download an encrypted attachment blob, decrypt it, verify integrity,
     * and save the plaintext file to disk.
     */
    private _downloadAndDecryptAttachment;
    /**
     * Upload an attachment file: encrypt, upload to server, return metadata
     * for inclusion in the message envelope.
     */
    private _uploadAttachment;
    /**
     * Send a message with an attached file. Encrypts the file, uploads it,
     * then sends the envelope with attachment metadata via Double Ratchet.
     */
    sendWithAttachment(plaintext: string, filePath: string, options?: {
        topicId?: string;
    }): Promise<void>;
    /**
     * Relay an owner's message to all sibling sessions as encrypted sync messages.
     * This allows all owner devices to see messages from any single device.
     */
    private _relaySyncToSiblings;
    /**
     * Resolve the agent's workspace directory.
     * Looks for OpenClaw workspace config, falls back to default path.
     */
    private _resolveWorkspaceDir;
    /**
     * Send a structured JSON reply to a specific conversation.
     * Encrypts the payload via the conversation's ratchet and sends via WebSocket.
     */
    private _sendStructuredReply;
    /**
     * Send stored message history to a newly-activated session.
     * Batches all history into a single encrypted message.
     */
    private _replayHistoryToSession;
    /**
     * Handle a device_linked event: a new owner device has joined.
     * Fetches the new device's public keys, performs X3DH, and initializes
     * a new ratchet session.
     */
    private _handleDeviceLinked;
    /**
     * Handle a resync_request from the owner (owner-initiated ratchet re-establishment).
     * Re-derives shared secret via X3DH as responder, initializes fresh receiver ratchet,
     * and sends resync_ack back with agent's public keys.
     */
    private _handleResyncRequest;
    /**
     * Handle credential protocol messages (grant, revoke, request).
     * These are intercepted before reaching the agent's onMessage callback.
     */
    private _handleCredentialMessage;
    /**
     * Send a credential_ack back to a room.
     */
    private _sendCredentialAck;
    /** Get a specific renter credential for a room. */
    getCredential(roomId: string, key: string): import("./credential-store.js").RenterCredential | undefined;
    /** Get all renter credentials for a room (includes values — for agent context). */
    getCredentials(roomId: string): import("./credential-store.js").RenterCredential[];
    /** Get credential key→value map for a room (for context injection). */
    getCredentialMap(roomId: string): Record<string, string>;
    /** Check if a specific credential exists for a room. */
    hasCredential(roomId: string, key: string): boolean;
    /** Purge all credentials for a room (call on rental end). */
    purgeRoomCredentials(roomId: string): void;
    private _handleRoomMessageMLS;
    /**
     * Handle a history catch-up request from a device that just rejoined a room.
     * Only the elected agent (smallest device_id among agents) responds.
     */
    private _handleHistoryCatchupRequest;
    private _handleMlsCommit;
    private _handleMlsWelcome;
    /**
     * Pull pending MLS messages from the delivery queue and process them.
     * Called on WS connect, on mls_delivery ping, and every 30s heartbeat.
     */
    private _pullDeliveryQueue;
    private _handleMlsSyncResponse;
    /**
     * Handle an incoming MLS-encrypted A2A message.
     * The observer (owner device) decrypts as a regular MLS group member.
     */
    private _handleA2AMessageMLS;
    /**
     * Found the MLS group for an A2A channel as the creator agent.
     * Calls /mls/a2a/{channelId}/init, creates the local MLS group, and sends
     * Welcome messages to all active/invited participants.
     * Extracted from the a2a_channel_approved WS handler so it can also be called
     * from the sync fallback in listA2AChannels.
     */
    private _foundA2AGroup;
    /**
     * Paginated sync: fetch missed messages in pages of 200, up to 5 pages (1000 messages).
     * Tracks message IDs in _syncMessageIds to prevent duplicate processing from concurrent WS messages.
     */
    private _syncMissedMessages;
    private _sendAck;
    private _flushAcks;
    private _flushOutboundQueue;
    private _startPing;
    private _stopPing;
    private _startWakeDetector;
    private _stopWakeDetector;
    private _startPendingPoll;
    private _stopPendingPoll;
    private _checkPendingMessages;
    private _scheduleReconnect;
    private _setState;
    private _startPollFallback;
    private _stopPollFallback;
    private _handleError;
    /**
     * Persist all ratchet session states to disk.
     * Syncs live ratchet states back into the persisted sessions map.
     */
    private _persistState;
    /**
     * Debounced server backup upload (60s after last state change).
     * Only runs when backupCode is configured.
     */
    private _scheduleServerBackup;
}
//# sourceMappingURL=channel.d.ts.map