/**
 * ThreadlineClient — Unified API for Threadline relay communication.
 *
 * The high-level client that agent developers use. Wraps RelayClient,
 * MessageEncryptor, and IdentityManager into a simple interface.
 *
 * Part of Threadline Relay Phase 1.
 */
import { EventEmitter } from 'node:events';
import type { AgentFingerprint, MessageEnvelope } from '../relay/types.js';
import { type PlaintextMessage } from './MessageEncryptor.js';
export interface ThreadlineClientConfig {
    name: string;
    relayUrl?: string;
    framework?: string;
    capabilities?: string[];
    version?: string;
    visibility?: 'public' | 'unlisted' | 'private';
    stateDir?: string;
}
export interface KnownAgent {
    agentId: AgentFingerprint;
    name: string;
    publicKey: Buffer;
    x25519PublicKey: Buffer;
    framework?: string;
    capabilities?: string[];
    lastSeen?: string;
    /**
     * Live presence as of the most recent discover_result, mapped from the relay's
     * per-agent `status` (which the relay derives from live presence, not a stale DB
     * column). Used by findAgentByName to prefer the live registration among same-name
     * rows. `undefined` when liveness is unknown (e.g. a hand-registered keyed entry
     * that never came through discovery).
     */
    online?: boolean;
}
export interface ReceivedMessage {
    from: AgentFingerprint;
    fromName?: string;
    threadId: string;
    messageId: string;
    content: PlaintextMessage;
    timestamp: string;
    envelope: MessageEnvelope;
}
interface ClientAffinityEntry {
    threadId: string;
    firstUsedAt: number;
    lastUsedAt: number;
}
export declare class ThreadlineClient extends EventEmitter {
    private readonly config;
    private readonly identityManager;
    private encryptor;
    private relayClient;
    private identity;
    private readonly knownAgents;
    /**
     * E2E-path session affinity (§4.1 client side).
     *
     * Maps recipient fingerprint → most-recent threadId used with that peer,
     * with sliding + absolute TTLs. Consulted ONLY by `send()` (the E2E-encrypted
     * path). Plaintext path is unaffected.
     *
     * Process-local; never persisted.
     */
    private readonly lastThreadByPeer;
    /**
     * Per-name cooldown for the offline-triggered re-discovery (§C). Keyed by
     * lowercased name → last re-discovery timestamp. Process-local; never persisted.
     */
    private readonly lastRediscoverByName;
    /** Test seam: override `Date.now()` for deterministic TTL tests. */
    private readonly nowFn;
    constructor(config: ThreadlineClientConfig, nowFn?: () => number);
    /** Peek affinity for a recipient. Returns null on miss or TTL expiry. */
    private peekClientAffinity;
    /** Record affinity for a recipient. LRU-bumps and evicts at cap. */
    private recordClientAffinity;
    /** Test seam: inspect the affinity map. Snapshot, not mutable. */
    getClientAffinitySnapshotForTests(): ReadonlyMap<AgentFingerprint, ClientAffinityEntry>;
    /**
     * Connect to the relay and start communicating.
     */
    connect(): Promise<string>;
    /**
     * Auto-discover all agents on the relay after connecting.
     * Populates knownAgents cache so name-based sends work immediately.
     */
    private autoDiscover;
    /**
     * Send a message to another agent.
     */
    send(recipientId: AgentFingerprint, content: string | PlaintextMessage, threadId?: string): string;
    /**
     * Send a plaintext message to another agent via the relay.
     * Unlike send(), this does NOT require the recipient to be in knownAgents
     * and does NOT use E2E encryption. The relay provides transport-level
     * security (TLS + Ed25519 auth). Use this for replying to unknown senders
     * who contacted us through the relay.
     */
    sendPlaintext(recipientId: AgentFingerprint, content: string, threadId?: string): string;
    /**
     * Send a message — tries E2E encrypted first, falls back to plaintext.
     * This is the recommended send method for the relay-send endpoint.
     */
    sendAuto(recipientId: AgentFingerprint, content: string, threadId?: string): string;
    /**
     * Whether the ENCRYPTED+SIGNED send path is available for a recipient — i.e. we
     * know its keys so `send()`/`sendAuto()` would use MessageEncryptor.encrypt rather
     * than the plaintext fallback. Mirrors the exact key check in `sendAuto`.
     *
     * Used by the credential-share gate (Secure A2A Verified Pairing §3.5): a credential
     * must NEVER traverse the plaintext fallback, so the outbound chokepoint refuses a
     * credential-bearing send when this returns false.
     */
    hasEncryptedSendPath(recipientId: AgentFingerprint): boolean;
    /**
     * Discover agents on the relay.
     */
    discover(filter?: {
        capability?: string;
        framework?: string;
        name?: string;
    }): Promise<KnownAgent[]>;
    /**
     * Resolve an agent name or fingerprint to a fingerprint.
     * Supports disambiguation syntax: "name:fingerprintPrefix" (e.g. "sagemind:a1b2c3d4").
     * Tries: exact fingerprint match → name match in cache → re-discover → name match.
     * Returns null if not found. Throws if name is ambiguous and no fingerprint prefix given.
     */
    resolveAgent(nameOrId: string): Promise<AgentFingerprint | null>;
    /**
     * Parse "name:fingerprintPrefix" addressing syntax.
     * If no colon or input looks like a plain name, returns the whole input as name.
     */
    private parseAgentAddress;
    /**
     * Find an agent by name (case-insensitive, partial match).
     * If fingerprintPrefix is provided, uses it to disambiguate same-named agents.
     * Throws an error if multiple agents share the name and no prefix is given.
     */
    private findAgentByName;
    /**
     * Among same-name matches, return the single live one — or undefined if zero, or
     * more than one, is online. Lets the resolver prefer the live registration over a
     * dead twin while keeping a genuinely-ambiguous (≥2 live) resolution explicit.
     */
    private pickSingleOnline;
    /**
     * Merge discovered agents into the knownAgents cache. MERGE, never replace:
     * discover_result frames are keyless (no publicKey/x25519PublicKey — see
     * relay/types.ts DiscoverResultFrame), so a plain set() would strip crypto keys from
     * a previously-keyed entry and silently regress E2E send() for that peer to plaintext.
     * Preserve existing keys when the frame omits them, and map the frame's live-presence
     * `status` onto `online` so findAgentByName can prefer the live registration.
     */
    private ingestDiscoveredAgents;
    /** True if the per-name re-discovery cooldown (§C) has elapsed. */
    private canRediscover;
    /** Stamp the per-name re-discovery cooldown. */
    private markRediscover;
    /**
     * Register a known agent (for direct messaging without discovery).
     */
    registerAgent(agent: KnownAgent): void;
    /**
     * Disconnect from the relay.
     */
    disconnect(): void;
    /**
     * Get the agent's fingerprint.
     */
    get fingerprint(): AgentFingerprint | null;
    /**
     * Get the agent's public key.
     */
    get publicKey(): Buffer | null;
    /**
     * Get connection state.
     */
    get connectionState(): string;
    /**
     * Get all known agents.
     */
    getKnownAgents(): KnownAgent[];
    private handleIncomingMessage;
}
export {};
//# sourceMappingURL=ThreadlineClient.d.ts.map