@youam/sdk 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sdk/dns-verifier.ts","../src/index.ts","../src/sdk/agent.ts","../src/protocol/index.ts","../src/protocol/types.ts","../src/protocol/errors.ts","../src/protocol/address.ts","../src/protocol/crypto.ts","../src/protocol/envelope.ts","../src/protocol/contact.ts","../src/version.ts","../src/sdk/config.ts","../src/sdk/freshness.ts","../src/sdk/key-manager.ts","../src/sdk/contact-book.ts","../src/sdk/log.ts","../src/sdk/handshake.ts","../src/sdk/resolver-base.ts","../src/sdk/tier3.ts","../src/sdk/resolver.ts","../src/sdk/transport/base.ts","../src/sdk/transport/http.ts","../src/sdk/transport/websocket.ts","../src/sdk/transport/index.ts","../src/sdk/replay-cache.ts","../src/sdk/webhook-verify.ts","../src/sdk/index.ts"],"sourcesContent":["/**\n * DNS domain verification for UAM Tier 2 addresses (DNS-01, DNS-03).\n *\n * Provides TXT record parsing, HTTPS .well-known fallback resolution,\n * and helper functions for domain ownership verification.\n *\n * TXT record format (at `_uam.{domain}`):\n *\n * v=uam1; key=ed25519:<base64-pubkey>; relay=<relay-url>\n *\n * Matches Python dns_verifier.py API surface.\n */\n\nimport { resolveTxt as dnsResolveTxt } from \"node:dns/promises\";\n\n/**\n * Parse a UAM TXT record value into tag-value pairs.\n *\n * Format: `v=uam1; key=ed25519:<base64>; relay=https://...`\n *\n * Tag names are lowercased for case-insensitive matching.\n * Unknown tags are preserved (forward compatibility).\n */\nexport function parseUamTxt(txtValue: string): Record<string, string> {\n const tags: Record<string, string> = {};\n for (const part of txtValue.split(\";\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx !== -1) {\n const tag = trimmed.slice(0, eqIdx).trim().toLowerCase();\n const value = trimmed.slice(eqIdx + 1).trim();\n tags[tag] = value;\n }\n }\n return tags;\n}\n\n/**\n * Extract the base64 public key from parsed UAM TXT tags.\n *\n * Strips the `ed25519:` prefix. Returns `null` if the key\n * tag is missing or does not have the expected prefix.\n */\nexport function extractPublicKey(\n tags: Record<string, string>\n): string | null {\n const keyValue = tags[\"key\"] ?? \"\";\n if (keyValue.startsWith(\"ed25519:\")) {\n return keyValue.slice(\"ed25519:\".length);\n }\n return null;\n}\n\n/**\n * Query `_uam.{domain}` for UAM TXT records.\n *\n * Returns a list of TXT record values that start with `v=uam1`.\n * Returns an empty list if no matching records are found or on any\n * DNS error.\n */\nexport async function queryUamTxt(\n domain: string,\n timeout?: number\n): Promise<string[]> {\n // Node dns/promises does not support per-call timeout natively.\n // We use AbortController for cancellation.\n const controller = new AbortController();\n const timer =\n timeout != null\n ? setTimeout(() => controller.abort(), timeout)\n : undefined;\n\n try {\n const records = await dnsResolveTxt(`_uam.${domain}`);\n\n // Each record is an array of strings (multi-part TXT).\n // Concatenate parts and filter for v=uam1.\n const results: string[] = [];\n for (const parts of records) {\n const txtValue = parts.join(\"\");\n if (txtValue.trim().startsWith(\"v=uam1\")) {\n results.push(txtValue);\n }\n }\n return results;\n } catch {\n // NXDOMAIN, SERVFAIL, etc. -- return empty\n return [];\n } finally {\n if (timer != null) clearTimeout(timer);\n }\n}\n\n/**\n * Resolve an agent's public key from `.well-known/uam.json` HTTPS fallback.\n *\n * Returns the base64 public key string, or `null` if the agent is not\n * found or the request fails.\n */\nexport async function resolveKeyViaHttps(\n agentName: string,\n domain: string,\n timeout?: number\n): Promise<string | null> {\n const url = `https://${domain}/.well-known/uam.json`;\n\n try {\n const resp = await fetch(url, {\n signal: AbortSignal.timeout(timeout ?? 10000),\n });\n if (!resp.ok) return null;\n\n const data = (await resp.json()) as Record<string, unknown>;\n if (data[\"v\"] !== \"uam1\") return null;\n\n const agents = (data[\"agents\"] ?? {}) as Record<\n string,\n Record<string, unknown>\n >;\n const entry = agents[agentName];\n if (!entry) return null;\n\n let keyValue = (entry[\"key\"] as string) ?? \"\";\n if (keyValue.startsWith(\"ed25519:\")) {\n keyValue = keyValue.slice(\"ed25519:\".length);\n }\n return keyValue || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Generate the TXT record value an agent should publish at `_uam.{domain}`.\n *\n * Returns a formatted string like:\n * `v=uam1; key=ed25519:<publicKey>; relay=<relayUrl>`\n */\nexport function generateTxtRecord(\n publicKey: string,\n relayUrl: string\n): string {\n return `v=uam1; key=ed25519:${publicKey}; relay=${relayUrl}`;\n}\n","/**\n * UAM -- Universal Agent Messaging.\n *\n * Top-level package exports: Agent, ContactBook, verifyWebhookSignature,\n * ReceivedMessage, protocol.\n */\n\nexport { Agent, ContactBook, verifyWebhookSignature } from \"./sdk/index.js\";\nexport type { ReceivedMessage } from \"./sdk/index.js\";\nexport * as protocol from \"./protocol/index.js\";\n","/**\n * Agent class -- the primary SDK interface (SDK-01).\n *\n * Provides send(), inbox(), handshake flow, contact management,\n * trust policies, approve/deny/block/unblock.\n *\n * Matches Python agent.py API surface.\n */\n\nimport { join } from \"node:path\";\n\nimport {\n parseAddress,\n MessageType,\n MAX_ENVELOPE_AGE,\n UAMError,\n KeyPinningError,\n SignatureVerificationError,\n DecryptionError,\n sodiumReady,\n createEnvelope,\n verifyEnvelope,\n decryptPayload,\n toWireDict,\n fromWireDict,\n serializeVerifyKey,\n deserializeVerifyKey,\n signMessage,\n utcTimestamp,\n createContactCard,\n contactCardToDict,\n contactCardFromDict,\n verifyContactCard,\n type MessageEnvelope,\n} from \"../protocol/index.js\";\nimport { SDK_VERSION } from \"../version.js\";\nimport { SDKConfig } from \"./config.js\";\nimport { RELAY_META_FEATURE, relayVouches } from \"./freshness.js\";\nimport { KeyManager } from \"./key-manager.js\";\nimport type { ReceivedMessage } from \"./message.js\";\nimport { ContactBook } from \"./contact-book.js\";\nimport { HandshakeManager, bindCardToEnvelope } from \"./handshake.js\";\nimport { log } from \"./log.js\";\nimport { type AddressResolver, SmartResolver } from \"./resolver.js\";\nimport { createTransport, type TransportBase } from \"./transport/index.js\";\nimport {\n PersistentReplayCache,\n DEFAULT_REPLAY_CACHE_CAPACITY,\n} from \"./replay-cache.js\";\n\n/** How long a relay's \"no\" to relay_meta is remembered. */\nconst RELAY_NO_MEMORY_MS = 60_000;\n\n/** Replay cache capacity from UAM_REPLAY_CACHE_CAPACITY (default 1000000). */\nfunction replayCacheCapacityFromEnv(): number {\n const raw = process.env[\"UAM_REPLAY_CACHE_CAPACITY\"];\n if (raw === undefined || raw === \"\") {\n return DEFAULT_REPLAY_CACHE_CAPACITY;\n }\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 1) {\n log.warn(\n `Ignoring invalid UAM_REPLAY_CACHE_CAPACITY=${JSON.stringify(raw)}; ` +\n `using ${DEFAULT_REPLAY_CACHE_CAPACITY}`\n );\n return DEFAULT_REPLAY_CACHE_CAPACITY;\n }\n return n;\n}\n\nexport class Agent {\n /** @internal */\n readonly _config: SDKConfig;\n /** @internal */\n readonly _keyManager: KeyManager;\n /** @internal */\n _transport: TransportBase | null = null;\n\n private _resolver: AddressResolver;\n private _address: string | null = null;\n private _token: string | null = null;\n private _connected: boolean = false;\n private _autoRegister: boolean;\n\n /** @internal */\n readonly _contactBook: ContactBook;\n /** @internal */\n readonly _handshake: HandshakeManager;\n\n /**\n * @internal Wall clock in ms since the epoch, used by the inbound\n * freshness/expiry checks and the replay cache. Replaceable in tests.\n */\n _clock: () => number = () => Date.now();\n\n /**\n * @internal Inbound replay cache, keyed by (from address, message id).\n * Kept on disk under the data dir, so it outlives restarts and is shared by\n * every process using it; capacity from UAM_REPLAY_CACHE_CAPACITY.\n */\n readonly _replayCache: PersistentReplayCache;\n\n /** Whether our relay has said it writes relay_meta. */\n private _relayStamps: boolean = false;\n\n /** Until when, by _monotonic, to take the relay's last no as still true. */\n private _relayNoUntil: number = 0;\n\n /** @internal Monotonic clock in ms. Replaceable in tests. */\n _monotonic: () => number = () => performance.now();\n\n /**\n * Create an Agent. No I/O happens here -- call connect() to initialize.\n */\n constructor(\n name: string,\n options?: {\n relay?: string | null;\n domain?: string | null;\n keyDir?: string | null;\n autoRegister?: boolean;\n displayName?: string | null;\n transport?: string;\n trustPolicy?: string;\n }\n ) {\n this._config = new SDKConfig({\n name,\n relayUrl: options?.relay,\n relayDomain: options?.domain ?? undefined,\n keyDir: options?.keyDir,\n displayName: options?.displayName ?? name,\n transportType: options?.transport ?? \"websocket\",\n trustPolicy: options?.trustPolicy ?? \"auto-accept\",\n });\n this._keyManager = new KeyManager(this._config.keyDir);\n this._resolver = new SmartResolver(this._config.relayDomain);\n this._autoRegister = options?.autoRegister ?? true;\n\n // Contact management\n this._contactBook = new ContactBook(this._config.dataDir);\n this._handshake = new HandshakeManager(\n this._contactBook,\n this._config.trustPolicy\n );\n\n this._replayCache = new PersistentReplayCache(\n join(this._config.dataDir, \"replay\", \"replay.db\"),\n {\n capacity: replayCacheCapacityFromEnv(),\n now: () => this._clock(),\n }\n );\n }\n\n // -- Properties ----------------------------------------------------------\n\n /** The agent's full UAM address (e.g., 'myagent::youam.network'). */\n get address(): string {\n if (this._address === null) {\n throw new Error(\n \"Agent not yet connected. Call await agent.connect() first.\"\n );\n }\n return this._address;\n }\n\n /** UAM SDK version. */\n get version(): string {\n return SDK_VERSION;\n }\n\n /** The agent's public key (base64-encoded Ed25519 verify key). */\n get publicKey(): string {\n return serializeVerifyKey(this._keyManager.verifyKey);\n }\n\n /** Whether the agent has completed connection setup. */\n get isConnected(): boolean {\n return this._connected;\n }\n\n /**\n * Generate and return a signed contact card for this agent.\n */\n async contactCard(): Promise<Record<string, unknown>> {\n if (!this._connected) {\n throw new Error(\"Agent not connected. Call connect() first.\");\n }\n const card = await createContactCard(\n this._address!,\n this._config.displayName,\n this._config.relayWsUrl,\n this._keyManager.signingKey\n );\n return contactCardToDict(card);\n }\n\n // -- Lifecycle -----------------------------------------------------------\n\n /**\n * Initialize the agent: load/generate keys, register, connect transport.\n *\n * Idempotent -- calling twice is safe.\n */\n async connect(): Promise<void> {\n if (this._connected) {\n return;\n }\n\n // 0. Ensure sodium is ready\n await sodiumReady;\n\n // 1. Load or generate keypair\n this._keyManager.loadOrGenerate(this._config.name);\n\n // Before registering, so its created_at predates anything signed to a\n // new agent. It opens itself on first use if this fails.\n try {\n await this._replayCache.open();\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n log.warn(`Could not open the replay cache: ${reason}`);\n }\n\n // 2. Check for stored token (returning user)\n const storedToken = this._keyManager.loadToken(\n this._config.name,\n this._config.relayUrl\n );\n\n if (storedToken) {\n // Returning user: use stored token\n this._token = storedToken;\n this._useAddress(await this._storedAddress());\n } else if (this._autoRegister) {\n // First-run: register with relay\n await this._registerWithRelay();\n } else {\n throw new UAMError(\n \"No stored token and autoRegister=false. \" +\n \"Register manually or set autoRegister=true.\"\n );\n }\n\n // 3. Create and connect transport\n this._transport = createTransport(\n this._config,\n this._token!,\n this._address!\n );\n await this._transport.connect();\n\n // 4. Open contact book\n this._contactBook.open();\n\n this._connected = true;\n\n // 5. Sweep expired handshakes (HAND-03)\n await this._sweepExpiredHandshakes();\n }\n\n /**\n * Disconnect the transport and clean up resources.\n */\n async close(): Promise<void> {\n // Close contact book first\n this._contactBook.close();\n await this._replayCache.close();\n if (this._transport) {\n await this._transport.disconnect();\n }\n this._connected = false;\n }\n\n // -- Messaging -----------------------------------------------------------\n\n /**\n * Send an encrypted, signed message. Returns the message_id.\n */\n async send(\n toAddress: string,\n message: string,\n options?: {\n threadId?: string;\n attachments?: Array<Record<string, unknown>>;\n }\n ): Promise<string> {\n await this._ensureConnected();\n\n // TOFU-05: require_verify blocks unverified first sends\n if (this._config.trustPolicy === \"require_verify\") {\n const trust = this._contactBook.getTrustState(toAddress);\n if (trust !== \"pinned\" && trust !== \"verified\") {\n throw new UAMError(\n `Trust policy 'require_verify' requires fingerprint ` +\n `verification before sending to ${toAddress}. ` +\n `Run: uam contact verify ${toAddress}`\n );\n }\n }\n\n // Resolve recipient's verify key (Ed25519). Read-only: the contact book\n // is not touched here.\n const recipientVk = await this._resolvePublicKey(toAddress);\n\n // Fire a handshake.request unless the key is already confirmed\n // (pinned/verified/trusted) or a request is already in flight\n // (handshake-sent). Any other state -- no row, provisional, unknown --\n // means the handshake never went out (or was lost). Gated on trust\n // state rather than row presence, as in the Python SDK.\n const trustState = this._contactBook.getTrustState(toAddress);\n if (\n trustState !== \"pinned\" &&\n trustState !== \"verified\" &&\n trustState !== \"trusted\" &&\n trustState !== \"handshake-sent\"\n ) {\n await this._initiateHandshake(toAddress, recipientVk);\n }\n\n // Create signed, encrypted envelope\n const envelope = await createEnvelope(\n this._address!,\n toAddress,\n MessageType.MESSAGE,\n new TextEncoder().encode(message),\n this._keyManager.signingKey,\n recipientVk,\n {\n threadId: options?.threadId,\n mediaType: \"text/plain\",\n attachments: options?.attachments,\n }\n );\n\n // Send via transport (with multi-relay failover -- CARD-06)\n const wire = toWireDict(envelope);\n const relayUrls = await this._getRelayUrls(toAddress);\n if (\n relayUrls !== null &&\n relayUrls.length === 1 &&\n relayUrls[0] === this._config.relayUrl\n ) {\n // Same relay -- use existing transport (no failover overhead)\n await this._transport!.send(wire);\n } else if (relayUrls !== null && relayUrls.length > 0) {\n // Multi-relay or cross-relay: try each in order\n await this._trySendWithFailover(wire, relayUrls);\n } else {\n // No relay info -- fall back to own transport\n await this._transport!.send(wire);\n }\n\n return envelope.messageId;\n }\n\n /**\n * Retrieve, decrypt, and verify pending messages.\n *\n * Returns a list of ReceivedMessage data objects.\n * Drops messages with invalid signatures or decryption errors. A message\n * that fails processing for any other reason (malformed envelope, bad\n * handshake payload, ...) is logged and dropped; it never aborts the\n * rest of the batch.\n */\n async inbox(limit: number = 50): Promise<ReceivedMessage[]> {\n await this._ensureConnected();\n\n // Sweep expired handshakes\n await this._sweepExpiredHandshakes();\n\n const rawMessages = await this._transport!.receive(limit);\n const result: ReceivedMessage[] = [];\n for (const raw of rawMessages) {\n let msg: ReceivedMessage | null;\n try {\n msg = await this._processInbound(raw);\n } catch (err) {\n log.warn(\n `Dropping inbound message ${String(raw[\"message_id\"])} from ` +\n `${String(raw[\"from\"])}: ` +\n `${err instanceof Error ? err.message : String(err)}`\n );\n continue;\n }\n if (msg !== null) {\n result.push(msg);\n // Auto-send receipt.read for user messages (RCPT-01)\n await this._sendReadReceipt(msg);\n }\n }\n return result;\n }\n\n // -- Trust management (HAND-02, HAND-04) ---------------------------------\n\n /** List pending handshake requests. */\n async pending(): Promise<Array<{ address: string; contactCard: string; receivedAt: string }>> {\n await this._ensureConnected();\n return this._contactBook.getPending();\n }\n\n /**\n * Approve a pending handshake request.\n *\n * Adds the sender to contacts with trust_source='explicit-approval'\n * and sends handshake.accept back.\n */\n async approve(address: string): Promise<void> {\n await this._ensureConnected();\n\n const pendingList = this._contactBook.getPending();\n const entry = pendingList.find((p) => p.address === address);\n if (!entry) {\n throw new UAMError(`No pending handshake from ${address}`);\n }\n\n // Parse and verify the stored contact card\n const cardDict = JSON.parse(entry.contactCard) as Record<string, unknown>;\n const card = contactCardFromDict(cardDict);\n verifyContactCard(card);\n\n // Re-bind the stored card to the address the request arrived from (the\n // pending row's key). Rows stored before request-side binding existed\n // may carry a card for a different address; never promote those.\n const senderVk = deserializeVerifyKey(card.publicKey);\n bindCardToEnvelope(card, { fromAddress: address }, senderVk);\n\n // Add to contacts with trust_source tracking\n this._contactBook.addContact(card.address, card.publicKey, {\n displayName: card.displayName,\n trustState: \"trusted\",\n trustSource: \"explicit-approval\",\n });\n\n // Remove from pending\n this._contactBook.removePending(address);\n\n // Send handshake.accept back\n await this._handshake._sendAccept(this, address, senderVk);\n }\n\n /**\n * Deny a pending handshake request.\n *\n * Removes the entry from pending and sends handshake.deny.\n */\n async deny(address: string): Promise<void> {\n await this._ensureConnected();\n\n const pendingList = this._contactBook.getPending();\n const entry = pendingList.find((p) => p.address === address);\n if (!entry) {\n throw new UAMError(`No pending handshake from ${address}`);\n }\n\n // Parse contact card for sender's public key\n const cardDict = JSON.parse(entry.contactCard) as Record<string, unknown>;\n const card = contactCardFromDict(cardDict);\n const senderVk = deserializeVerifyKey(card.publicKey);\n\n // Remove from pending\n this._contactBook.removePending(address);\n\n // Send handshake.deny\n await this._handshake._sendDeny(this, address, senderVk);\n }\n\n /**\n * Block an address or domain pattern (HAND-04).\n */\n async block(pattern: string): Promise<void> {\n await this._ensureConnected();\n this._contactBook.addBlock(pattern);\n }\n\n /**\n * Remove a block pattern (HAND-04).\n */\n async unblock(pattern: string): Promise<void> {\n await this._ensureConnected();\n this._contactBook.removeBlock(pattern);\n }\n\n // -- Domain verification (DNS-02) ----------------------------------------\n\n /**\n * Verify domain ownership via relay endpoint (DNS-02).\n *\n * Polls `POST /api/v1/verify-domain` until the relay confirms\n * DNS TXT (or HTTPS fallback) verification succeeds, or timeout\n * elapses.\n *\n * Returns `true` if verified, `false` on timeout.\n */\n async verifyDomain(\n domain: string,\n options?: { timeout?: number; pollInterval?: number }\n ): Promise<boolean> {\n const { generateTxtRecord } = await import(\"./dns-verifier.js\");\n await this._ensureConnected();\n\n const timeout = options?.timeout ?? 300000; // 5 minutes\n const pollInterval = options?.pollInterval ?? 10000; // 10 seconds\n\n const expectedTxt = generateTxtRecord(\n this.publicKey,\n this._config.relayUrl\n );\n // Log expected TXT for user reference (they need to publish this)\n void expectedTxt;\n\n const start = Date.now();\n while (Date.now() - start < timeout) {\n try {\n const resp = await fetch(\n `${this._config.relayUrl}/api/v1/verify-domain`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._token}`,\n },\n body: JSON.stringify({ domain }),\n signal: AbortSignal.timeout(30000),\n }\n );\n if (resp.ok) {\n const result = (await resp.json()) as Record<string, unknown>;\n if (result[\"status\"] === \"verified\") {\n return true;\n }\n }\n } catch {\n // Request failed, retry after poll interval\n }\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n return false;\n }\n\n // -- Internal methods ----------------------------------------------------\n\n /** Multi-relay failover (CARD-06). */\n private async _getRelayUrls(toAddress: string): Promise<string[] | null> {\n const urls = this._contactBook.getRelayUrls(toAddress);\n if (urls !== null) {\n return urls;\n }\n return [this._config.relayUrl];\n }\n\n /**\n * Try sending wire envelope to each relay URL in order (CARD-06).\n *\n * Uses transient fetch POST requests so the envelope can be delivered\n * to any relay that hosts the recipient.\n */\n private async _trySendWithFailover(\n wire: Record<string, unknown>,\n relayUrls: string[]\n ): Promise<void> {\n let lastError: Error | null = null;\n\n for (const url of relayUrls) {\n // Normalize: strip trailing '/ws', convert ws:// -> http://\n let base = url.replace(/\\/+$/, \"\");\n if (base.endsWith(\"/ws\")) {\n base = base.slice(0, -3);\n }\n base = base.replace(\"wss://\", \"https://\").replace(\"ws://\", \"http://\");\n const sendUrl = `${base}/api/v1/send`;\n\n try {\n const resp = await fetch(sendUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._token}`,\n },\n body: JSON.stringify({ envelope: wire }),\n signal: AbortSignal.timeout(10000),\n });\n if (!resp.ok) {\n throw new Error(`HTTP ${resp.status}`);\n }\n return; // Success\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n }\n }\n\n if (lastError !== null) {\n throw lastError;\n }\n throw new UAMError(\"No relay URLs to try\");\n }\n\n private async _ensureConnected(): Promise<void> {\n if (!this._connected) {\n await this.connect();\n }\n }\n\n /**\n * Resolve a recipient's public key, checking contact book first.\n *\n * Pure lookup: never writes to the contact book. The contact row is\n * created by _initiateHandshake (as \"handshake-sent\") once the request\n * has gone out, giving the lifecycle no row -> handshake-sent -> pinned.\n *\n * TOFU-01: Known contacts always use stored key (zero network I/O).\n * TOFU-03: Race-condition double-check after network resolve.\n * Raises KeyPinningError if a pinned contact's key doesn't match.\n */\n private async _resolvePublicKey(toAddress: string): Promise<Uint8Array> {\n // TOFU-01: Check contact book first (local-first, zero network I/O)\n const pkStr = this._contactBook.getPublicKey(toAddress);\n if (pkStr !== null) {\n // Known contact: always use stored key\n return deserializeVerifyKey(pkStr);\n }\n\n // Unknown contact: resolve from network\n const resolvedPkStr = await this._resolver.resolvePublicKey(\n toAddress,\n this._token!,\n this._config.relayUrl\n );\n\n // TOFU-03: Double-check no pinned key exists (race condition guard)\n const storedPk = this._contactBook.getPublicKey(toAddress);\n if (storedPk !== null && storedPk !== resolvedPkStr) {\n const trust = this._contactBook.getTrustState(toAddress);\n if (trust === \"pinned\" || trust === \"trusted\" || trust === \"verified\") {\n throw new KeyPinningError(\n `CRITICAL: Public key mismatch for ${toAddress}! ` +\n `Stored key does not match resolved key. ` +\n `This may indicate a relay MITM attack. ` +\n `To accept the new key: uam contact remove ${toAddress}`\n );\n }\n }\n\n return deserializeVerifyKey(resolvedPkStr);\n }\n\n private async _initiateHandshake(\n toAddress: string,\n recipientVk: Uint8Array\n ): Promise<void> {\n const wire = await this._handshake.createHandshakeRequest(\n this,\n toAddress,\n recipientVk\n );\n await this._transport!.send(wire);\n\n // Mark as handshake-sent in contact book\n this._contactBook.addContact(\n toAddress,\n serializeVerifyKey(recipientVk),\n { trustState: \"handshake-sent\" }\n );\n }\n\n /**\n * Process a single inbound envelope: verify, decrypt, handle handshakes.\n *\n * Returns null for invalid messages or handshake protocol messages.\n */\n private async _processInbound(\n raw: Record<string, unknown>\n ): Promise<ReceivedMessage | null> {\n // Parse envelope\n const envelope = fromWireDict(raw);\n\n // Check block list BEFORE expensive crypto (HAND-04)\n if (this._contactBook.isBlocked(envelope.fromAddress)) {\n return null;\n }\n\n // Look up sender's public key for verification\n let senderPkStr = this._contactBook.getPublicKey(envelope.fromAddress);\n if (senderPkStr === null) {\n // Unknown sender -- try resolving from relay\n try {\n senderPkStr = await this._resolver.resolvePublicKey(\n envelope.fromAddress,\n this._token!,\n this._config.relayUrl\n );\n } catch {\n return null;\n }\n }\n\n const senderVk = deserializeVerifyKey(senderPkStr);\n\n // Verify signature (SEC-03: mandatory)\n try {\n verifyEnvelope(envelope, senderVk);\n } catch (err) {\n if (err instanceof SignatureVerificationError) {\n return null; // Silently reject unsigned/invalid messages\n }\n throw err;\n }\n\n // Envelope checks, all AFTER signature verification so unauthenticated\n // input can never touch the replay cache. Order: recipient, freshness,\n // expiry, replay. The replay cache is the only stateful check and runs\n // last, so an envelope rejected by an earlier check records nothing.\n if (!(await this._passesInboundChecks(envelope, raw))) {\n return null;\n }\n\n // Handle handshake messages (not user-visible)\n if (\n envelope.type === MessageType.HANDSHAKE_REQUEST ||\n envelope.type === MessageType.HANDSHAKE_ACCEPT ||\n envelope.type === MessageType.HANDSHAKE_DENY\n ) {\n return this._handshake.handleInbound(this, envelope, senderVk);\n }\n\n // For non-auto-accept policies, filter messages from unapproved senders\n if (this._handshake._trustPolicy !== \"auto-accept\") {\n if (!this._contactBook.isTrustedOrVerified(envelope.fromAddress)) {\n return null;\n }\n }\n\n // Decrypt payload (SEC-04: mandatory)\n let plaintextBytes: Uint8Array;\n try {\n plaintextBytes = decryptPayload(\n envelope.payload,\n this._keyManager.signingKey,\n senderVk\n );\n } catch (err) {\n if (err instanceof DecryptionError) {\n return null;\n }\n throw err;\n }\n\n // Build ReceivedMessage data object\n return Object.freeze({\n messageId: envelope.messageId,\n fromAddress: envelope.fromAddress,\n toAddress: envelope.toAddress,\n content: new TextDecoder().decode(plaintextBytes),\n timestamp: envelope.timestamp,\n type: envelope.type,\n threadId: envelope.threadId,\n replyTo: envelope.replyTo,\n mediaType: envelope.mediaType,\n verified: true,\n });\n }\n\n /**\n * Recipient, freshness, expiry and replay checks for a signature-verified\n * inbound envelope. Returns false (and logs) when it must be dropped.\n * Matches the Python SDK's _process_inbound checks.\n */\n private async _passesInboundChecks(\n envelope: MessageEnvelope,\n raw: Record<string, unknown>\n ): Promise<boolean> {\n const id = envelope.messageId;\n const from = envelope.fromAddress;\n\n // (a) Recipient: drop envelopes addressed to someone else. Skipped when\n // no address is set yet (callers driving _processInbound directly).\n if (this._address !== null && envelope.toAddress !== this._address) {\n log.warn(\n `Dropped envelope ${id} from ${from} addressed to ` +\n `${envelope.toAddress} (we are ${this._address})`\n );\n return false;\n }\n\n const now = this._clock();\n\n // (b) Freshness: |now - timestamp| <= MAX_ENVELOPE_AGE, unless it's\n // stored mail.\n const ts = Date.parse(envelope.timestamp);\n if (Number.isNaN(ts)) {\n log.warn(\n `Dropped envelope ${id} from ${from} with malformed timestamp ` +\n JSON.stringify(envelope.timestamp)\n );\n return false;\n }\n const ageSeconds = Math.abs(now - ts) / 1000;\n if (\n ageSeconds > MAX_ENVELOPE_AGE &&\n !(await this._wasStored(raw, envelope.toAddress, ts, now))\n ) {\n log.info(\n `Dropped stale envelope ${id} from ${from} ` +\n `(age=${Math.round(ageSeconds)}s > ${MAX_ENVELOPE_AGE}s)`\n );\n return false;\n }\n\n // (c) Expiry.\n if (envelope.expires !== undefined && envelope.expires !== null) {\n const exp = Date.parse(envelope.expires);\n if (Number.isNaN(exp)) {\n log.warn(\n `Dropped envelope ${id} from ${from} with malformed expires ` +\n JSON.stringify(envelope.expires)\n );\n return false;\n }\n if (now > exp) {\n log.info(\n `Dropped expired envelope ${id} from ${from} ` +\n `(expires=${envelope.expires})`\n );\n return false;\n }\n }\n\n // (d) Replay: must stay last (the only check that records state).\n if (await this._replayCache.seenOrRecord(from, id, ts)) {\n log.info(`Dropped replayed envelope ${id} from ${from}`);\n return false;\n }\n\n return true;\n }\n\n /** True if a message too old to be live is stored mail, not a replay. */\n private async _wasStored(\n raw: Record<string, unknown>,\n toAddress: string,\n signedAt: number,\n now: number\n ): Promise<boolean> {\n // The signed address names our relay. _config.relayDomain may not: it can\n // be the URL's hostname, and youam.network is relay.youam.network.\n const relayDomain = toAddress.split(\"::\").pop()!;\n if (!relayVouches(raw, signedAt, now, relayDomain)) return false;\n // The replay cache can't speak for what came before it existed.\n if (await this._replayCache.signedBeforeCache(signedAt)) return false;\n return this._relayStampsMail();\n }\n\n /**\n * True if our relay writes relay_meta, so a sender can't have.\n *\n * Asked only when a stale message carries a stamp. A yes is remembered for\n * good, a no for RELAY_NO_MEMORY_MS: a relay can be upgraded while this\n * agent runs. A failed lookup isn't remembered, because the relay has\n * already marked this mail delivered and the next message should get a\n * real answer.\n */\n private async _relayStampsMail(): Promise<boolean> {\n if (this._relayStamps) return true;\n if (this._monotonic() < this._relayNoUntil) return false;\n try {\n const features = await this._fetchRelayFeatures();\n this._relayStamps = features.includes(RELAY_META_FEATURE);\n if (!this._relayStamps) {\n this._relayNoUntil = this._monotonic() + RELAY_NO_MEMORY_MS;\n }\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n log.warn(`Cannot read relay features: ${reason}`);\n }\n return this._relayStamps;\n }\n\n /** The relay's features; a body that doesn't list any is an empty list. */\n private async _fetchRelayFeatures(): Promise<unknown[]> {\n const resp = await fetch(`${this._config.relayUrl}/api/v1/versions`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!resp.ok) throw new UAMError(`Relay answered ${resp.status}`);\n const body = await resp.text();\n let data: { features?: unknown } | null;\n try {\n data = JSON.parse(body) as { features?: unknown } | null;\n } catch {\n return [];\n }\n return Array.isArray(data?.features) ? data.features : [];\n }\n\n /**\n * Sweep expired pending handshakes and send receipt.failed (HAND-03).\n */\n private async _sweepExpiredHandshakes(): Promise<void> {\n const expired = this._contactBook.getExpiredPending(7);\n for (const entry of expired) {\n try {\n const cardDict = JSON.parse(entry.contactCard) as Record<\n string,\n unknown\n >;\n const card = contactCardFromDict(cardDict);\n const recipientVk = deserializeVerifyKey(card.publicKey);\n\n const failPayload = JSON.stringify({\n reason: \"handshake_expired\",\n original_from: entry.address,\n });\n const envelope = await createEnvelope(\n this._address!,\n entry.address,\n MessageType.RECEIPT_FAILED,\n new TextEncoder().encode(failPayload),\n this._keyManager.signingKey,\n recipientVk\n );\n const wire = toWireDict(envelope);\n await this._transport!.send(wire);\n } catch {\n // Failed to send receipt.failed -- ignore\n }\n\n // Remove from pending regardless\n this._contactBook.removePending(entry.address);\n }\n }\n\n /**\n * Send receipt.read back to the sender (RCPT-01).\n *\n * Fire-and-forget: errors are never propagated.\n * Anti-loop guard: receipts, handshakes, and session messages are skipped.\n */\n private async _sendReadReceipt(msg: ReceivedMessage): Promise<void> {\n // Anti-loop: never generate receipts for protocol messages\n if (\n msg.type.startsWith(\"receipt.\") ||\n msg.type.startsWith(\"handshake.\") ||\n msg.type.startsWith(\"session.\")\n ) {\n return;\n }\n\n try {\n const senderPkStr = this._contactBook.getPublicKey(msg.fromAddress);\n if (senderPkStr === null) return;\n\n const senderVk = deserializeVerifyKey(senderPkStr);\n\n const receiptPayload = JSON.stringify({\n message_id: msg.messageId,\n });\n const envelope = await createEnvelope(\n this._address!,\n msg.fromAddress,\n MessageType.RECEIPT_READ,\n new TextEncoder().encode(receiptPayload),\n this._keyManager.signingKey,\n senderVk,\n { replyTo: msg.messageId }\n );\n\n const wire = toWireDict(envelope);\n await this._transport!.send(wire);\n } catch {\n // Fire-and-forget\n }\n }\n\n /**\n * Register with the relay server.\n *\n * Calls POST /api/v1/register with agent name and public key. If the\n * address exists (409), repeats it with a proof that this agent holds the\n * key. Stores the returned API key on disk.\n */\n private async _registerWithRelay(): Promise<void> {\n const body = {\n agent_name: this._config.name,\n public_key: serializeVerifyKey(this._keyManager.verifyKey),\n };\n\n let resp = await this._postRegistration(body);\n if (resp.status === 409) {\n const address = await this._addressOnRelay();\n resp = await this._postRegistration({\n ...body,\n proof: this._registrationProof(address),\n });\n if (resp.status === 409 || resp.status === 403) {\n throw this._ownershipNotProven(address);\n }\n }\n\n if (!resp.ok) {\n const text = await resp.text();\n throw new UAMError(\n `Registration failed: ${resp.status} ${text}`\n );\n }\n\n const data = (await resp.json()) as Record<string, unknown>;\n const address = data[\"address\"] as string;\n this._useAddress(address);\n this._token = data[\"token\"] as string;\n\n // Persist for the returning-user flow\n const { name } = this._config;\n const token = this._token;\n this._tryToSave(\"token\", () => this._keyManager.saveToken(name, token));\n this._saveAddress(address);\n }\n\n /** This agent's address on the relay, for signing a proof. */\n private async _addressOnRelay(): Promise<string> {\n const { name, explicitRelayDomain, relayDomain, relayUrl } = this._config;\n if (explicitRelayDomain !== null) return `${name}::${explicitRelayDomain}`;\n\n const domain = await this._fetchRelayDomain();\n if (domain === null) return `${name}::${relayDomain}`;\n if (!this._relayMayUse(domain)) {\n throw new UAMError(\n `The relay at ${relayUrl} says its domain is ${domain}. ` +\n `Pass the domain option as ${JSON.stringify(domain)} if that is right.`\n );\n }\n return `${name}::${domain}`;\n }\n\n /**\n * True if the relay's URL fits `domain`, so a proof can be signed for it.\n *\n * A proof names an address on one relay, so it is only signed for a domain\n * this URL belongs to. A relay on this machine may use any domain.\n */\n private _relayMayUse(domain: string): boolean {\n let host: string;\n try {\n host = new URL(this._config.relayUrl).hostname.toLowerCase();\n } catch {\n return false;\n }\n const wanted = domain.toLowerCase();\n return (\n host === wanted ||\n host.endsWith(`.${wanted}`) ||\n host === \"localhost\" ||\n host === \"[::1]\" ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host)\n );\n }\n\n private _postRegistration(body: Record<string, unknown>): Promise<Response> {\n return fetch(`${this._config.relayUrl}/api/v1/register`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n }\n\n /**\n * Sign a statement that this agent holds the key for `address`.\n *\n * The signed string must stay byte-identical to the Python SDK's.\n */\n private _registrationProof(address: string): {\n timestamp: string;\n signature: string;\n } {\n const timestamp = utcTimestamp();\n const signature = signMessage(\n new TextEncoder().encode(`uam-register-v1\\n${address}\\n${timestamp}`),\n this._keyManager.signingKey\n );\n return { timestamp, signature };\n }\n\n private _ownershipNotProven(address: string): UAMError {\n return new UAMError(\n `Address already registered, and this key could not prove ownership: ` +\n address\n );\n }\n\n /** Remember `address` for this relay, if the key folder allows it. */\n private _saveAddress(address: string): void {\n const { name, relayUrl } = this._config;\n this._tryToSave(\"address\", () =>\n this._keyManager.saveAddress(name, address, relayUrl)\n );\n }\n\n /** Saving is best effort: a key folder we can't write doesn't stop us. */\n private _tryToSave(what: string, save: () => void): void {\n try {\n save();\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n log.warn(`Could not save the ${what}: ${reason}`);\n }\n }\n\n /** Take `address` as ours; its domain is this relay's real domain. */\n private _useAddress(address: string): void {\n this._address = address;\n const domain = parseAddress(address).domain;\n this._config.relayDomain = domain;\n if (this._resolver instanceof SmartResolver) {\n this._resolver.relayDomain = domain;\n }\n }\n\n /**\n * The address the stored token belongs to.\n *\n * An explicit domain settles it. Otherwise the relay chooses the domain,\n * and it need not be the relay's hostname: use the address saved for this\n * relay, or ask the relay once and keep the answer.\n */\n private async _storedAddress(): Promise<string> {\n const { name, explicitRelayDomain } = this._config;\n if (explicitRelayDomain !== null) return `${name}::${explicitRelayDomain}`;\n\n const saved = this._keyManager.loadAddress(name, this._config.relayUrl);\n if (saved) return saved;\n\n const domain = await this._fetchRelayDomain();\n if (domain === null) return `${name}::${this._config.relayDomain}`;\n const address = `${name}::${domain}`;\n this._saveAddress(address);\n return address;\n }\n\n /** Ask the relay for its domain; null if it cannot say. */\n private async _fetchRelayDomain(): Promise<string | null> {\n const url = `${this._config.relayUrl}/.well-known/uam-relay.json`;\n try {\n const resp = await fetch(url, { signal: AbortSignal.timeout(10_000) });\n if (!resp.ok) return null;\n const data = (await resp.json()) as Record<string, unknown>;\n const domain = data[\"relay_domain\"];\n if (typeof domain !== \"string\" || domain === \"\") return null;\n // Throws, so counts as no answer, if it can't form an address.\n return parseAddress(`${this._config.name}::${domain}`).domain;\n } catch {\n return null;\n }\n }\n}\n","/**\n * UAM Protocol -- Universal Agent Messaging protocol library.\n *\n * Public API re-exports for the protocol layer.\n */\n\n// Types\nexport {\n UAM_VERSION,\n MAX_ENVELOPE_SIZE,\n MAX_ENVELOPE_AGE,\n MessageType,\n b64Encode,\n b64Decode,\n utcTimestamp,\n} from \"./types.js\";\n\n// Errors\nexport {\n UAMError,\n InvalidAddressError,\n InvalidEnvelopeError,\n EnvelopeTooLargeError,\n SignatureError,\n SignatureVerificationError,\n EncryptionError,\n DecryptionError,\n InvalidContactCardError,\n KeyPinningError,\n} from \"./errors.js\";\n\n// Address\nexport { type Address, parseAddress } from \"./address.js\";\n\n// Crypto\nexport {\n sodiumReady,\n type SigningKey,\n type VerifyKey,\n type Seed,\n type Keypair,\n generateKeypair,\n serializeSigningKey,\n deserializeSigningKey,\n serializeVerifyKey,\n deserializeVerifyKey,\n publicKeyFingerprint,\n canonicalize,\n signMessage,\n verifySignature,\n generateNonce,\n encryptPayload,\n decryptPayload,\n encryptPayloadAnonymous,\n decryptPayloadAnonymous,\n} from \"./crypto.js\";\n\n// Envelope\nexport {\n type MessageEnvelope,\n createEnvelope,\n verifyEnvelope,\n toWireDict,\n fromWireDict,\n validateEnvelopeSize,\n} from \"./envelope.js\";\n\n// Contact\nexport {\n type ContactCard,\n createContactCard,\n verifyContactCard,\n contactCardToDict,\n contactCardFromDict,\n} from \"./contact.js\";\n","/**\n * Core types, constants, and utility functions for UAM protocol.\n */\n\n/** Protocol version. */\nexport const UAM_VERSION = \"0.1\";\n\n/** Maximum envelope size in bytes (64 KB). */\nexport const MAX_ENVELOPE_SIZE = 65536;\n\n/**\n * Maximum allowed skew, in seconds, between an inbound envelope's signed\n * timestamp and the receiver's clock (either direction). Also the TTL of\n * the inbound replay cache. Matches Python MAX_ENVELOPE_AGE.\n */\nexport const MAX_ENVELOPE_AGE = 300;\n\n/** All UAM message types. */\nexport enum MessageType {\n MESSAGE = \"message\",\n HANDSHAKE_REQUEST = \"handshake.request\",\n HANDSHAKE_ACCEPT = \"handshake.accept\",\n HANDSHAKE_DENY = \"handshake.deny\",\n RECEIPT_DELIVERED = \"receipt.delivered\",\n RECEIPT_READ = \"receipt.read\",\n RECEIPT_FAILED = \"receipt.failed\",\n SESSION_REQUEST = \"session.request\",\n SESSION_ACCEPT = \"session.accept\",\n SESSION_DECLINE = \"session.decline\",\n SESSION_END = \"session.end\",\n}\n\n/**\n * URL-safe base64 encode, stripping padding.\n */\nexport function b64Encode(data: Uint8Array): string {\n return Buffer.from(data).toString(\"base64url\");\n}\n\n/**\n * URL-safe base64 decode, tolerating missing padding.\n */\nexport function b64Decode(s: string): Uint8Array {\n return new Uint8Array(Buffer.from(s, \"base64url\"));\n}\n\n/**\n * Return a canonical UTC timestamp: YYYY-MM-DDTHH:MM:SS.mmmZ\n */\nexport function utcTimestamp(): string {\n return new Date().toISOString();\n}\n","/**\n * UAM exception hierarchy.\n *\n * All protocol-specific errors inherit from UAMError.\n */\n\n/** Base error for all UAM protocol errors. */\nexport class UAMError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"UAMError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Raised when an address string fails validation. */\nexport class InvalidAddressError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidAddressError\";\n }\n}\n\n/** Raised when an envelope fails schema validation. */\nexport class InvalidEnvelopeError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidEnvelopeError\";\n }\n}\n\n/** Raised when an envelope exceeds the maximum allowed size. */\nexport class EnvelopeTooLargeError extends InvalidEnvelopeError {\n constructor(message?: string) {\n super(message);\n this.name = \"EnvelopeTooLargeError\";\n }\n}\n\n/** Raised on signing failures. */\nexport class SignatureError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"SignatureError\";\n }\n}\n\n/** Raised when a cryptographic signature cannot be verified. */\nexport class SignatureVerificationError extends SignatureError {\n constructor(message?: string) {\n super(message);\n this.name = \"SignatureVerificationError\";\n }\n}\n\n/** Raised on encryption failures. */\nexport class EncryptionError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"EncryptionError\";\n }\n}\n\n/** Raised on decryption failures. */\nexport class DecryptionError extends EncryptionError {\n constructor(message?: string) {\n super(message);\n this.name = \"DecryptionError\";\n }\n}\n\n/** Raised when a contact card fails validation. */\nexport class InvalidContactCardError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidContactCardError\";\n }\n}\n\n/** Raised when a pinned contact's public key doesn't match the resolved key. */\nexport class KeyPinningError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"KeyPinningError\";\n Object.setPrototypeOf(this, KeyPinningError.prototype);\n }\n}\n","/**\n * UAM address parsing and validation.\n *\n * A UAM address has the form `agent::domain` (e.g. `alice::youam.network`).\n */\n\nimport { InvalidAddressError } from \"./errors.js\";\n\n/**\n * A parsed UAM address (always lowercase).\n */\nexport interface Address {\n readonly agent: string;\n readonly domain: string;\n readonly full: string;\n}\n\n// Agent: 1-64 chars, lowercase alphanumeric + hyphen + underscore.\n// Cannot start or end with hyphen.\n// Domain: standard DNS-style, 1-255 chars.\nconst ADDRESS_RE =\n /^(?<agent>[a-z0-9][a-z0-9_-]{0,62}[a-z0-9]|[a-z0-9])::(?<domain>[a-z0-9](?:[a-z0-9.-]{0,253}[a-z0-9])?)$/;\n\nconst MAX_AGENT_LEN = 64;\nconst MAX_ADDRESS_LEN = 128;\n\n/**\n * Parse and validate a UAM address string.\n *\n * Strips whitespace, lowercases, and validates format.\n * Enforces max lengths: agent <= 64 chars, full address <= 128 chars.\n *\n * @throws {InvalidAddressError} If `raw` is not a valid `agent::domain` address.\n */\nexport function parseAddress(raw: string): Address {\n const normalized = raw.trim().toLowerCase();\n if (normalized.length > MAX_ADDRESS_LEN) {\n throw new InvalidAddressError(\n `Address exceeds ${MAX_ADDRESS_LEN} characters: ${JSON.stringify(raw)}`\n );\n }\n const m = ADDRESS_RE.exec(normalized);\n if (!m || !m.groups) {\n throw new InvalidAddressError(\n `Invalid UAM address: ${JSON.stringify(raw)}`\n );\n }\n const agent = m.groups.agent;\n if (agent.length > MAX_AGENT_LEN) {\n throw new InvalidAddressError(\n `Agent name exceeds ${MAX_AGENT_LEN} characters: ${JSON.stringify(raw)}`\n );\n }\n return {\n agent,\n domain: m.groups.domain,\n get full() {\n return `${this.agent}::${this.domain}`;\n },\n };\n}\n","/**\n * Cryptographic primitives for UAM protocol.\n *\n * Wraps libsodium-wrappers for Ed25519 signing, Curve25519 key exchange,\n * NaCl Box (authenticated encryption), and NaCl SealedBox (anonymous encryption).\n *\n * This module never hand-rolls crypto -- every operation delegates to libsodium.\n */\n\nimport sodium from \"libsodium-wrappers\";\nimport { createHash } from \"node:crypto\";\n\nimport {\n DecryptionError,\n EncryptionError,\n SignatureVerificationError,\n} from \"./errors.js\";\nimport { b64Decode, b64Encode } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Sodium initialization\n// ---------------------------------------------------------------------------\n\n/**\n * Promise that resolves when libsodium is ready.\n * Callers must await this before first use of any crypto function.\n */\nexport const sodiumReady: Promise<void> = sodium.ready;\n\n// ---------------------------------------------------------------------------\n// Key type aliases\n// ---------------------------------------------------------------------------\n\n/** 64-byte Ed25519 secret key (seed + public). */\nexport type SigningKey = Uint8Array;\n\n/** 32-byte Ed25519 public key. */\nexport type VerifyKey = Uint8Array;\n\n/** 32-byte seed. */\nexport type Seed = Uint8Array;\n\n// ---------------------------------------------------------------------------\n// Key generation and serialization\n// ---------------------------------------------------------------------------\n\nexport interface Keypair {\n signingKey: Uint8Array;\n verifyKey: Uint8Array;\n seed: Uint8Array;\n}\n\n/**\n * Generate an Ed25519 keypair.\n */\nexport function generateKeypair(): Keypair {\n const seed = sodium.randombytes_buf(32);\n const kp = sodium.crypto_sign_seed_keypair(seed);\n return {\n signingKey: kp.privateKey,\n verifyKey: kp.publicKey,\n seed,\n };\n}\n\n/**\n * Serialize a signing key to URL-safe base64 (32-byte seed).\n *\n * Matches Python: PyNaCl's SigningKey.encode() returns the 32-byte seed.\n */\nexport function serializeSigningKey(seed: Uint8Array): string {\n return b64Encode(seed);\n}\n\n/**\n * Restore a signing key from its base64-encoded seed.\n */\nexport function deserializeSigningKey(s: string): Keypair {\n const seed = b64Decode(s);\n const kp = sodium.crypto_sign_seed_keypair(seed);\n return {\n signingKey: kp.privateKey,\n verifyKey: kp.publicKey,\n seed,\n };\n}\n\n/**\n * Serialize a verify (public) key to URL-safe base64.\n */\nexport function serializeVerifyKey(key: Uint8Array): string {\n return b64Encode(key);\n}\n\n/**\n * Restore a verify key from its base64 encoding.\n */\nexport function deserializeVerifyKey(s: string): Uint8Array {\n return b64Decode(s);\n}\n\n/**\n * Return the SHA-256 hex digest of the verify key bytes.\n *\n * This 64-character string serves as the agent's identity fingerprint.\n */\nexport function publicKeyFingerprint(verifyKey: Uint8Array): string {\n return createHash(\"sha256\").update(Buffer.from(verifyKey)).digest(\"hex\");\n}\n\n// ---------------------------------------------------------------------------\n// Canonical JSON\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively sort all object keys and produce compact JSON.\n *\n * Matches Python: json.dumps(data, sort_keys=True, separators=(',',':'), ensure_ascii=True)\n */\nfunction sortedStringify(value: unknown): string {\n if (value === null || value === undefined) {\n return \"null\";\n }\n if (typeof value === \"string\") {\n return JSON.stringify(value);\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n if (Array.isArray(value)) {\n const items = value.map((v) => sortedStringify(v));\n return \"[\" + items.join(\",\") + \"]\";\n }\n if (typeof value === \"object\") {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const pairs = keys.map((k) => JSON.stringify(k) + \":\" + sortedStringify(obj[k]));\n return \"{\" + pairs.join(\",\") + \"}\";\n }\n return String(value);\n}\n\n/**\n * Produce deterministic JSON bytes for signing.\n *\n * - Excludes the \"signature\" key.\n * - Excludes keys whose value is null or undefined.\n * - Sorts keys, uses compact separators, ensures ASCII encoding.\n */\nexport function canonicalize(data: Record<string, unknown>): Uint8Array {\n const filtered: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(data)) {\n if (k !== \"signature\" && v !== null && v !== undefined) {\n filtered[k] = v;\n }\n }\n const json = sortedStringify(filtered);\n return new TextEncoder().encode(json);\n}\n\n// ---------------------------------------------------------------------------\n// Signing and verification\n// ---------------------------------------------------------------------------\n\n/**\n * Sign data with the Ed25519 signing key.\n *\n * @returns The 64-byte signature as a URL-safe base64 string.\n */\nexport function signMessage(data: Uint8Array, signingKey: Uint8Array): string {\n const signature = sodium.crypto_sign_detached(data, signingKey);\n return b64Encode(signature);\n}\n\n/**\n * Verify an Ed25519 signature.\n *\n * @throws {SignatureVerificationError} If the signature is invalid.\n */\nexport function verifySignature(\n data: Uint8Array,\n signatureB64: string,\n verifyKey: Uint8Array\n): void {\n try {\n const sigBytes = b64Decode(signatureB64);\n const valid = sodium.crypto_sign_verify_detached(sigBytes, data, verifyKey);\n if (!valid) {\n throw new SignatureVerificationError(\"Signature verification failed\");\n }\n } catch (err) {\n if (err instanceof SignatureVerificationError) {\n throw err;\n }\n throw new SignatureVerificationError(\n err instanceof Error ? err.message : String(err)\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Nonce generation\n// ---------------------------------------------------------------------------\n\n/**\n * Generate 24 cryptographically random bytes, returned as base64.\n */\nexport function generateNonce(): string {\n return b64Encode(sodium.randombytes_buf(24));\n}\n\n// ---------------------------------------------------------------------------\n// NaCl Box encryption (authenticated, both parties known)\n// ---------------------------------------------------------------------------\n\n/**\n * Encrypt plaintext using NaCl Box (authenticated encryption).\n *\n * Both parties are known; the sender signs implicitly via key exchange.\n * Format: nonce (24 bytes) || ciphertext, matching PyNaCl Box.encrypt() output.\n *\n * @returns Base64-encoded ciphertext (nonce prepended).\n * @throws {EncryptionError} On any libsodium error.\n */\nexport function encryptPayload(\n plaintext: Uint8Array,\n senderSigningKey: Uint8Array,\n recipientVerifyKey: Uint8Array\n): string {\n try {\n const senderCurve = sodium.crypto_sign_ed25519_sk_to_curve25519(senderSigningKey);\n const recipientCurve = sodium.crypto_sign_ed25519_pk_to_curve25519(recipientVerifyKey);\n const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);\n const encrypted = sodium.crypto_box_easy(plaintext, nonce, recipientCurve, senderCurve);\n // Concatenate nonce || ciphertext (matching PyNaCl format)\n const combined = new Uint8Array(nonce.length + encrypted.length);\n combined.set(nonce, 0);\n combined.set(encrypted, nonce.length);\n return b64Encode(combined);\n } catch (err) {\n if (err instanceof EncryptionError) throw err;\n throw new EncryptionError(err instanceof Error ? err.message : String(err));\n }\n}\n\n/**\n * Decrypt NaCl Box ciphertext.\n *\n * @returns The original plaintext bytes.\n * @throws {DecryptionError} On any libsodium error (wrong keys, tampered data).\n */\nexport function decryptPayload(\n ciphertextB64: string,\n recipientSigningKey: Uint8Array,\n senderVerifyKey: Uint8Array\n): Uint8Array {\n try {\n const combined = b64Decode(ciphertextB64);\n const nonce = combined.slice(0, sodium.crypto_box_NONCEBYTES);\n const ciphertext = combined.slice(sodium.crypto_box_NONCEBYTES);\n const recipientCurve = sodium.crypto_sign_ed25519_sk_to_curve25519(recipientSigningKey);\n const senderCurve = sodium.crypto_sign_ed25519_pk_to_curve25519(senderVerifyKey);\n return sodium.crypto_box_open_easy(ciphertext, nonce, senderCurve, recipientCurve);\n } catch (err) {\n if (err instanceof DecryptionError) throw err;\n throw new DecryptionError(err instanceof Error ? err.message : String(err));\n }\n}\n\n// ---------------------------------------------------------------------------\n// NaCl SealedBox encryption (anonymous sender)\n// ---------------------------------------------------------------------------\n\n/**\n * Encrypt plaintext using NaCl SealedBox (anonymous sender).\n *\n * Only the recipient's public key is required; no sender authentication.\n *\n * @returns Base64-encoded ciphertext.\n */\nexport function encryptPayloadAnonymous(\n plaintext: Uint8Array,\n recipientVerifyKey: Uint8Array\n): string {\n const recipientCurve = sodium.crypto_sign_ed25519_pk_to_curve25519(recipientVerifyKey);\n const ciphertext = sodium.crypto_box_seal(plaintext, recipientCurve);\n return b64Encode(ciphertext);\n}\n\n/**\n * Decrypt NaCl SealedBox ciphertext.\n *\n * @returns The original plaintext bytes.\n * @throws {DecryptionError} On any libsodium error.\n */\nexport function decryptPayloadAnonymous(\n ciphertextB64: string,\n recipientSigningKey: Uint8Array\n): Uint8Array {\n try {\n const ciphertext = b64Decode(ciphertextB64);\n const recipientCurveSk = sodium.crypto_sign_ed25519_sk_to_curve25519(recipientSigningKey);\n // Extract the public key from the signing key (last 32 bytes of the 64-byte Ed25519 secret key)\n const recipientVerifyKey = recipientSigningKey.slice(32);\n const recipientCurvePk = sodium.crypto_sign_ed25519_pk_to_curve25519(recipientVerifyKey);\n return sodium.crypto_box_seal_open(ciphertext, recipientCurvePk, recipientCurveSk);\n } catch (err) {\n if (err instanceof DecryptionError) throw err;\n throw new DecryptionError(err instanceof Error ? err.message : String(err));\n }\n}\n","/**\n * UAM message envelope -- creation, signing, verification, wire format.\n *\n * An envelope wraps every UAM message with cryptographic signatures and\n * encrypted payloads, using fromAddress/toAddress naming internally\n * (\"from\"/\"to\" on the wire).\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { parseAddress } from \"./address.js\";\nimport {\n canonicalize,\n encryptPayload,\n encryptPayloadAnonymous,\n generateNonce,\n signMessage,\n verifySignature,\n} from \"./crypto.js\";\nimport { EnvelopeTooLargeError, InvalidEnvelopeError } from \"./errors.js\";\nimport { MAX_ENVELOPE_SIZE, MessageType, UAM_VERSION, utcTimestamp } from \"./types.js\";\n\n/**\n * Required wire-format field names (using \"from\"/\"to\").\n */\nconst REQUIRED_WIRE_FIELDS = new Set([\n \"uam_version\",\n \"message_id\",\n \"from\",\n \"to\",\n \"timestamp\",\n \"type\",\n \"nonce\",\n \"payload\",\n \"signature\",\n]);\n\n/**\n * A signed, encrypted UAM message envelope.\n */\nexport interface MessageEnvelope {\n // Required fields\n readonly uamVersion: string;\n readonly messageId: string;\n readonly fromAddress: string;\n readonly toAddress: string;\n readonly timestamp: string;\n readonly type: string;\n readonly nonce: string;\n readonly payload: string;\n readonly signature: string;\n\n // Optional fields\n readonly threadId?: string;\n readonly replyTo?: string;\n readonly expires?: string;\n readonly mediaType?: string;\n readonly metadata?: Record<string, unknown>;\n\n // v1.1 fields -- NOT in signature scope\n readonly attachments?: Array<Record<string, unknown>>;\n}\n\n/**\n * Build the dict used for signature computation.\n *\n * Maps TypeScript names to wire names (fromAddress -> \"from\").\n * Excludes signature and any optional field that is undefined.\n */\nfunction buildSignableDict(\n envelope: MessageEnvelope\n): Record<string, unknown> {\n const d: Record<string, unknown> = {\n uam_version: envelope.uamVersion,\n message_id: envelope.messageId,\n from: envelope.fromAddress,\n to: envelope.toAddress,\n timestamp: envelope.timestamp,\n type: envelope.type,\n nonce: envelope.nonce,\n payload: envelope.payload,\n };\n if (envelope.threadId !== undefined) d[\"thread_id\"] = envelope.threadId;\n if (envelope.replyTo !== undefined) d[\"reply_to\"] = envelope.replyTo;\n if (envelope.expires !== undefined) d[\"expires\"] = envelope.expires;\n if (envelope.mediaType !== undefined) d[\"media_type\"] = envelope.mediaType;\n if (envelope.metadata !== undefined) d[\"metadata\"] = envelope.metadata;\n return d;\n}\n\n/**\n * Convert an envelope to a wire-format dict.\n *\n * Maps fromAddress -> \"from\" and toAddress -> \"to\".\n * Excludes undefined-valued optional fields.\n */\nexport function toWireDict(\n envelope: MessageEnvelope\n): Record<string, unknown> {\n const d = buildSignableDict(envelope);\n d[\"signature\"] = envelope.signature;\n if (envelope.attachments !== undefined) {\n d[\"attachments\"] = envelope.attachments;\n }\n return d;\n}\n\n/**\n * Restore an envelope from a wire-format dict.\n *\n * @throws {InvalidEnvelopeError} If any required field is missing.\n */\nexport function fromWireDict(\n d: Record<string, unknown>\n): MessageEnvelope {\n const keys = new Set(Object.keys(d));\n const missing: string[] = [];\n for (const field of REQUIRED_WIRE_FIELDS) {\n if (!keys.has(field)) missing.push(field);\n }\n if (missing.length > 0) {\n missing.sort();\n throw new InvalidEnvelopeError(\n `Missing required fields: ${JSON.stringify(missing)}`\n );\n }\n\n return Object.freeze({\n uamVersion: d[\"uam_version\"] as string,\n messageId: d[\"message_id\"] as string,\n fromAddress: d[\"from\"] as string,\n toAddress: d[\"to\"] as string,\n timestamp: d[\"timestamp\"] as string,\n type: d[\"type\"] as string,\n nonce: d[\"nonce\"] as string,\n payload: d[\"payload\"] as string,\n signature: d[\"signature\"] as string,\n threadId: d[\"thread_id\"] as string | undefined,\n replyTo: d[\"reply_to\"] as string | undefined,\n expires: d[\"expires\"] as string | undefined,\n mediaType: d[\"media_type\"] as string | undefined,\n metadata: d[\"metadata\"] as Record<string, unknown> | undefined,\n attachments: d[\"attachments\"] as Array<Record<string, unknown>> | undefined,\n });\n}\n\n/**\n * Check that the serialized envelope does not exceed MAX_ENVELOPE_SIZE.\n *\n * @throws {EnvelopeTooLargeError} If the wire JSON exceeds 64 KB.\n */\nexport function validateEnvelopeSize(envelope: MessageEnvelope): void {\n const wire = toWireDict(envelope);\n const json = JSON.stringify(wire);\n const size = new TextEncoder().encode(json).length;\n if (size > MAX_ENVELOPE_SIZE) {\n throw new EnvelopeTooLargeError(\n `Envelope size ${size} bytes exceeds maximum ${MAX_ENVELOPE_SIZE} bytes`\n );\n }\n}\n\n/**\n * Create a signed, encrypted message envelope.\n *\n * @throws {InvalidAddressError} If either address is invalid.\n * @throws {EnvelopeTooLargeError} If the serialized envelope exceeds 64 KB.\n */\nexport async function createEnvelope(\n fromAddress: string,\n toAddress: string,\n messageType: MessageType | string,\n payloadPlaintext: Uint8Array,\n signingKey: Uint8Array,\n recipientVerifyKey: Uint8Array,\n options?: {\n threadId?: string;\n replyTo?: string;\n expires?: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n attachments?: Array<Record<string, unknown>>;\n }\n): Promise<MessageEnvelope> {\n // Normalize message type\n const typeValue =\n typeof messageType === \"string\"\n ? messageType\n : (messageType as string);\n\n // Step 1: Validate addresses\n parseAddress(fromAddress);\n parseAddress(toAddress);\n\n // Step 2: Generate identifiers\n const messageId = randomUUID();\n const nonce = generateNonce();\n const timestamp = utcTimestamp();\n\n // Step 3: Encrypt payload\n let encryptedPayload: string;\n if (typeValue === MessageType.HANDSHAKE_REQUEST) {\n encryptedPayload = encryptPayloadAnonymous(payloadPlaintext, recipientVerifyKey);\n } else {\n encryptedPayload = encryptPayload(\n payloadPlaintext,\n signingKey,\n recipientVerifyKey\n );\n }\n\n // Build temporary envelope without signature\n const tempEnvelope: MessageEnvelope = {\n uamVersion: UAM_VERSION,\n messageId,\n fromAddress,\n toAddress,\n timestamp,\n type: typeValue,\n nonce,\n payload: encryptedPayload,\n signature: \"\",\n threadId: options?.threadId,\n replyTo: options?.replyTo,\n expires: options?.expires,\n mediaType: options?.mediaType,\n metadata: options?.metadata,\n attachments: options?.attachments,\n };\n\n // Step 4: Build signable dict, canonicalize, and sign\n const signable = buildSignableDict(tempEnvelope);\n const signature = signMessage(canonicalize(signable), signingKey);\n\n // Step 5: Build final envelope\n const finalEnvelope: MessageEnvelope = Object.freeze({\n uamVersion: UAM_VERSION,\n messageId,\n fromAddress,\n toAddress,\n timestamp,\n type: typeValue,\n nonce,\n payload: encryptedPayload,\n signature,\n threadId: options?.threadId,\n replyTo: options?.replyTo,\n expires: options?.expires,\n mediaType: options?.mediaType,\n metadata: options?.metadata,\n attachments: options?.attachments,\n });\n\n // Step 6: Validate size\n validateEnvelopeSize(finalEnvelope);\n\n return finalEnvelope;\n}\n\n/**\n * Verify the cryptographic signature on an envelope.\n *\n * @throws {SignatureVerificationError} If the signature is invalid.\n */\nexport function verifyEnvelope(\n envelope: MessageEnvelope,\n senderVerifyKey: Uint8Array\n): void {\n const signable = buildSignableDict(envelope);\n verifySignature(canonicalize(signable), envelope.signature, senderVerifyKey);\n}\n","/**\n * UAM contact cards -- self-signed agent identity documents.\n *\n * A contact card advertises an agent's address, public key, relay endpoint,\n * and optional metadata. The card is signed by the agent's own signing key\n * so that any recipient can verify authenticity using the embedded public key.\n */\n\nimport { parseAddress } from \"./address.js\";\nimport {\n canonicalize,\n deserializeVerifyKey,\n publicKeyFingerprint,\n serializeVerifyKey,\n signMessage,\n verifySignature,\n} from \"./crypto.js\";\nimport { InvalidContactCardError } from \"./errors.js\";\nimport { UAM_VERSION } from \"./types.js\";\n\n/**\n * A self-signed agent identity card.\n */\nexport interface ContactCard {\n readonly version: string;\n readonly address: string;\n readonly displayName: string;\n readonly description?: string;\n readonly system?: string;\n readonly connectionEndpoint?: string;\n readonly relay: string;\n readonly publicKey: string;\n readonly signature: string;\n readonly verifiedDomain?: string;\n readonly payloadFormats?: string[];\n readonly fingerprint?: string;\n /** CARD-04: Multi-relay support. Outside signature scope. */\n readonly relays?: string[];\n}\n\n/**\n * Build the dict used for signature computation.\n *\n * Includes all fields except signature, payload_formats, fingerprint, relays.\n * Excludes undefined-valued optional fields.\n */\nfunction buildSignableDict(card: ContactCard): Record<string, unknown> {\n const d: Record<string, unknown> = {\n version: card.version,\n address: card.address,\n display_name: card.displayName,\n relay: card.relay,\n public_key: card.publicKey,\n };\n if (card.description !== undefined) d[\"description\"] = card.description;\n if (card.system !== undefined) d[\"system\"] = card.system;\n if (card.connectionEndpoint !== undefined) {\n d[\"connection_endpoint\"] = card.connectionEndpoint;\n }\n if (card.verifiedDomain !== undefined) {\n d[\"verified_domain\"] = card.verifiedDomain;\n }\n return d;\n}\n\n/**\n * Serialize a contact card to a plain dict.\n *\n * Uses snake_case names on the wire, excludes undefined-valued optional fields.\n */\nexport function contactCardToDict(\n card: ContactCard\n): Record<string, unknown> {\n const d = buildSignableDict(card);\n d[\"signature\"] = card.signature;\n if (card.payloadFormats !== undefined) {\n d[\"payload_formats\"] = card.payloadFormats;\n }\n if (card.fingerprint !== undefined) {\n d[\"fingerprint\"] = card.fingerprint;\n }\n if (card.relays !== undefined) {\n d[\"relays\"] = card.relays;\n }\n return d;\n}\n\n/**\n * Deserialize a contact card from a dict.\n *\n * When verify is true (the default), the card's signature is checked\n * immediately after deserialization.\n *\n * @throws {InvalidContactCardError} If required fields are missing.\n * @throws {SignatureVerificationError} If verify is true and the signature is invalid.\n */\nexport function contactCardFromDict(\n d: Record<string, unknown>,\n options?: { verify?: boolean }\n): ContactCard {\n const verify = options?.verify ?? true;\n\n const required = new Set([\n \"version\",\n \"address\",\n \"display_name\",\n \"relay\",\n \"public_key\",\n \"signature\",\n ]);\n const keys = new Set(Object.keys(d));\n const missing: string[] = [];\n for (const field of required) {\n if (!keys.has(field)) missing.push(field);\n }\n if (missing.length > 0) {\n missing.sort();\n throw new InvalidContactCardError(\n `Missing required fields: ${JSON.stringify(missing)}`\n );\n }\n\n const card: ContactCard = Object.freeze({\n version: d[\"version\"] as string,\n address: d[\"address\"] as string,\n displayName: d[\"display_name\"] as string,\n description: d[\"description\"] as string | undefined,\n system: d[\"system\"] as string | undefined,\n connectionEndpoint: d[\"connection_endpoint\"] as string | undefined,\n relay: d[\"relay\"] as string,\n publicKey: d[\"public_key\"] as string,\n signature: d[\"signature\"] as string,\n verifiedDomain: d[\"verified_domain\"] as string | undefined,\n payloadFormats: d[\"payload_formats\"] as string[] | undefined,\n fingerprint: d[\"fingerprint\"] as string | undefined,\n relays: d[\"relays\"] as string[] | undefined,\n });\n\n if (verify) {\n verifyContactCard(card);\n }\n\n return card;\n}\n\n/**\n * Create a self-signed contact card.\n *\n * payloadFormats defaults to [\"text/plain\", \"text/markdown\"] when not specified.\n * The fingerprint is always auto-computed as the SHA-256 hex digest of the\n * Ed25519 public key bytes.\n *\n * @throws {InvalidAddressError} If address is not valid.\n */\nexport async function createContactCard(\n address: string,\n displayName: string,\n relay: string,\n signingKey: Uint8Array,\n options?: {\n description?: string;\n system?: string;\n connectionEndpoint?: string;\n verifiedDomain?: string;\n payloadFormats?: string[];\n relays?: string[];\n }\n): Promise<ContactCard> {\n // Validate address\n parseAddress(address);\n\n // Derive public key and fingerprint\n // The verify key is the last 32 bytes of the 64-byte signing key\n const verifyKey = signingKey.slice(32);\n const pubKeyB64 = serializeVerifyKey(verifyKey);\n const fp = publicKeyFingerprint(verifyKey);\n\n // Default payload formats\n const payloadFormats = options?.payloadFormats ?? [\n \"text/plain\",\n \"text/markdown\",\n ];\n\n // Build temporary card without signature\n const tempCard: ContactCard = {\n version: UAM_VERSION,\n address,\n displayName,\n description: options?.description,\n system: options?.system,\n connectionEndpoint: options?.connectionEndpoint,\n relay,\n publicKey: pubKeyB64,\n signature: \"\",\n verifiedDomain: options?.verifiedDomain,\n payloadFormats,\n fingerprint: fp,\n relays: options?.relays,\n };\n\n // Sign (payload_formats, fingerprint, relays are NOT in signable dict)\n const signable = buildSignableDict(tempCard);\n const signature = signMessage(canonicalize(signable), signingKey);\n\n // Return final card\n return Object.freeze({\n version: UAM_VERSION,\n address,\n displayName,\n description: options?.description,\n system: options?.system,\n connectionEndpoint: options?.connectionEndpoint,\n relay,\n publicKey: pubKeyB64,\n signature,\n verifiedDomain: options?.verifiedDomain,\n payloadFormats,\n fingerprint: fp,\n relays: options?.relays,\n });\n}\n\n/**\n * Verify a contact card's signature using its embedded public key.\n *\n * @throws {InvalidContactCardError} If the address is invalid.\n * @throws {SignatureVerificationError} If the signature is invalid.\n */\nexport function verifyContactCard(card: ContactCard): void {\n // Validate address format\n try {\n parseAddress(card.address);\n } catch (err) {\n throw new InvalidContactCardError(\n `Invalid address in contact card: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Deserialize the embedded public key\n const vk = deserializeVerifyKey(card.publicKey);\n\n // Verify signature\n const signable = buildSignableDict(card);\n verifySignature(canonicalize(signable), card.signature, vk);\n}\n","/**\n * SDK version, taken from package.json at build time.\n *\n * `__UAM_SDK_VERSION__` is replaced by tsup (tsup.config.ts) and defined by\n * vitest (vitest.config.ts), both from package.json's \"version\", so there is\n * a single place to bump it.\n */\n\ndeclare const __UAM_SDK_VERSION__: string;\n\nexport const SDK_VERSION: string = __UAM_SDK_VERSION__;\n","/**\n * SDK configuration (matching Python config.py).\n *\n * Priority (highest wins): constructor arg > env var > default.\n * TOML config file support is Python-only for now (unnecessary complexity for TS MVP).\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst DEFAULT_RELAY_URL = \"https://relay.youam.network\";\n\n/** `url` with any trailing slashes removed. */\nexport function trimRelayUrl(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nconst VALID_POLICIES = new Set([\n \"auto-accept\",\n \"approval-required\",\n \"allowlist-only\",\n \"require_verify\",\n]);\n\nexport class SDKConfig {\n readonly name: string;\n readonly relayUrl: string;\n readonly relayWsUrl: string;\n readonly keyDir: string;\n readonly dataDir: string;\n readonly displayName: string;\n readonly transportType: string;\n readonly trustPolicy: string;\n relayDomain: string;\n /** The domain the caller chose, if any; null when only derived. */\n readonly explicitRelayDomain: string | null;\n\n constructor(options: {\n name: string;\n relayUrl?: string | null;\n relayWsUrl?: string | null;\n keyDir?: string | null;\n dataDir?: string | null;\n displayName?: string | null;\n transportType?: string;\n trustPolicy?: string;\n relayDomain?: string;\n }) {\n this.name = options.name;\n\n // Relay URL: constructor arg > env var > default\n this.relayUrl = trimRelayUrl(\n options.relayUrl ?? process.env[\"UAM_RELAY_URL\"] ?? DEFAULT_RELAY_URL\n );\n\n // Derive relayWsUrl from relayUrl if not explicitly set\n if (options.relayWsUrl) {\n this.relayWsUrl = options.relayWsUrl;\n } else {\n let wsUrl = this.relayUrl\n .replace(\"https://\", \"wss://\")\n .replace(\"http://\", \"ws://\");\n if (!wsUrl.endsWith(\"/ws\")) {\n wsUrl = wsUrl.replace(/\\/+$/, \"\") + \"/ws\";\n }\n this.relayWsUrl = wsUrl;\n }\n\n // Derive relayDomain: env var > constructor arg > URL hostname\n const envDomain = process.env[\"UAM_RELAY_DOMAIN\"];\n this.explicitRelayDomain = envDomain || options.relayDomain || null;\n if (envDomain) {\n this.relayDomain = envDomain;\n } else if (options.relayDomain) {\n this.relayDomain = options.relayDomain;\n } else {\n // Extract hostname from relayUrl\n try {\n const parsed = new URL(this.relayUrl);\n this.relayDomain = parsed.hostname || \"localhost\";\n } catch {\n // Fallback for malformed URLs\n const afterScheme = this.relayUrl.split(\"://\").pop() || \"\";\n this.relayDomain = afterScheme.split(\"/\")[0] || \"localhost\";\n }\n }\n\n // Default key_dir and data_dir.\n // UAM_HOME env var overrides ~/.uam (useful for testing / isolation).\n const uamHome = process.env[\"UAM_HOME\"];\n const defaultHome = uamHome || join(homedir(), \".uam\");\n\n this.keyDir = options.keyDir ?? join(defaultHome, \"keys\");\n this.dataDir = options.dataDir ?? defaultHome;\n\n // Display name defaults to agent name\n this.displayName = options.displayName ?? this.name;\n\n // Transport type\n this.transportType = options.transportType ?? \"websocket\";\n\n // Trust policy: constructor arg > env var > default\n let policy = options.trustPolicy ?? \"auto-accept\";\n const envPolicy = process.env[\"UAM_TRUST_POLICY\"];\n if (envPolicy) {\n policy = envPolicy;\n }\n\n if (!VALID_POLICIES.has(policy)) {\n throw new Error(\n `Invalid trust_policy '${policy}'. ` +\n `Must be one of: ${JSON.stringify([...VALID_POLICIES].sort())}`\n );\n }\n\n this.trustPolicy = policy;\n }\n}\n","/**\n * When to believe the relay about mail that waited in storage.\n *\n * A signed timestamp cannot tell \"signed, stored, delivered later\" from an\n * old envelope sent again. The relay's relay_meta stamp can, so long as the\n * recipient's own relay wrote it.\n *\n * Matches the Python SDK's freshness.py.\n */\n\nimport { MAX_ENVELOPE_AGE } from \"../protocol/types.js\";\n\n/** Listed in GET /api/v1/versions by relays that write relay_meta. */\nexport const RELAY_META_FEATURE = \"relay_meta\";\n\n/** How long stored mail stays deliverable, in seconds. */\nexport const STORED_MAIL_MAX_AGE = 7 * 86400;\n\n// A full ISO 8601 time with a zone. Date.parse alone also takes loose formats\n// and reads a time with no zone as local.\nconst ISO_TIME =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$/;\n\n/**\n * True if `raw` carries a stamp showing it was stored soon after signing.\n *\n * This only reads the stamp. The caller must also know that the relay writes\n * these stamps, or a sender could have written this one.\n *\n * @param signedAt - The envelope's signed time, in ms since the epoch\n * @param now - The current time, in ms since the epoch\n */\nexport function relayVouches(\n raw: Record<string, unknown>,\n signedAt: number,\n now: number,\n relayDomain: string\n): boolean {\n const meta = raw[\"relay_meta\"];\n if (typeof meta !== \"object\" || meta === null || Array.isArray(meta)) {\n return false;\n }\n const stamp = meta as Record<string, unknown>;\n if (stamp[\"v\"] !== 1 || stamp[\"relay\"] !== relayDomain) return false;\n if (stamp[\"stored\"] !== true) return false;\n\n const received = stamp[\"received_at\"];\n if (typeof received !== \"string\" || !ISO_TIME.test(received)) return false;\n const receivedAt = Date.parse(received);\n if (Number.isNaN(receivedAt)) return false;\n\n const window = MAX_ENVELOPE_AGE * 1000;\n const age = now - signedAt;\n return (\n Math.abs(receivedAt - signedAt) <= window &&\n age >= 0 &&\n age <= STORED_MAIL_MAX_AGE * 1000 + window\n );\n}\n","/**\n * Ed25519 key generation, storage, loading, and token persistence.\n *\n * Matches Python key_manager.py: stores 32-byte seed (not 64-byte secret key),\n * uses same file format so keys are cross-language compatible.\n */\n\nimport {\n chmodSync,\n mkdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { platform } from \"node:os\";\n\nimport {\n type Keypair,\n type SigningKey,\n type VerifyKey,\n type Seed,\n parseAddress,\n generateKeypair,\n serializeSigningKey,\n deserializeSigningKey,\n serializeVerifyKey,\n} from \"../protocol/index.js\";\nimport { trimRelayUrl } from \"./config.js\";\n\nconst DEFAULT_KEY_DIR = join(homedir(), \".uam\", \"keys\");\n\nexport class KeyManager {\n private _keyDir: string;\n private _keypair: Keypair | null = null;\n\n constructor(keyDir?: string | null) {\n this._keyDir = keyDir ?? DEFAULT_KEY_DIR;\n }\n\n /** The 64-byte Ed25519 signing key. Throws if not loaded. */\n get signingKey(): SigningKey {\n if (this._keypair === null) {\n throw new Error(\"No keypair loaded. Call loadOrGenerate() first.\");\n }\n return this._keypair.signingKey;\n }\n\n /** The 32-byte Ed25519 verify (public) key. Throws if not loaded. */\n get verifyKey(): VerifyKey {\n if (this._keypair === null) {\n throw new Error(\"No keypair loaded. Call loadOrGenerate() first.\");\n }\n return this._keypair.verifyKey;\n }\n\n /** The 32-byte seed. Throws if not loaded. */\n get seed(): Seed {\n if (this._keypair === null) {\n throw new Error(\"No keypair loaded. Call loadOrGenerate() first.\");\n }\n return this._keypair.seed;\n }\n\n /**\n * Load existing keypair or generate a new one.\n *\n * Checks UAM_SIGNING_KEY env var first (base64-encoded Ed25519 seed).\n * Falls back to file-based storage at {keyDir}/{name}.key.\n * Generates a new keypair if neither source exists.\n */\n loadOrGenerate(name: string): void {\n // 1. Check environment variable\n const envKey = process.env[\"UAM_SIGNING_KEY\"];\n if (envKey) {\n this._keypair = deserializeSigningKey(envKey.trim());\n return;\n }\n\n // 2. File-based storage\n mkdirSync(this._keyDir, { recursive: true });\n const keyPath = join(this._keyDir, `${name}.key`);\n const pubPath = join(this._keyDir, `${name}.pub`);\n\n if (existsSync(keyPath)) {\n // Returning user: load existing keys\n this._checkPermissions(keyPath);\n const seedB64 = readFileSync(keyPath, \"utf-8\").trim();\n this._keypair = deserializeSigningKey(seedB64);\n } else {\n // First-run: generate new keypair\n this._keypair = generateKeypair();\n writeFileSync(keyPath, serializeSigningKey(this._keypair.seed));\n writeFileSync(pubPath, serializeVerifyKey(this._keypair.verifyKey));\n this._setPermissions(keyPath);\n }\n }\n\n /**\n * Store the relay token alongside the keypair.\n */\n saveToken(name: string, token: string): void {\n mkdirSync(this._keyDir, { recursive: true });\n const tokenPath = join(this._keyDir, `${name}.token`);\n writeFileSync(tokenPath, token);\n this._setPermissions(tokenPath);\n }\n\n /**\n * Store the address `relayUrl` gave this agent.\n */\n saveAddress(name: string, address: string, relayUrl: string): void {\n mkdirSync(this._keyDir, { recursive: true });\n writeFileSync(\n join(this._keyDir, `${name}.address`),\n JSON.stringify({ address, relay_url: relayUrl })\n );\n }\n\n /**\n * Load the address saved for `relayUrl`.\n *\n * Returns null if there is none: the file is missing, unreadable or\n * malformed, or it belongs to another relay.\n */\n loadAddress(name: string, relayUrl: string): string | null {\n try {\n const path = join(this._keyDir, `${name}.address`);\n const saved = JSON.parse(readFileSync(path, \"utf-8\")) as {\n address?: unknown;\n relay_url?: unknown;\n } | null;\n const address = saved?.address;\n const savedRelay = saved?.relay_url;\n if (typeof address !== \"string\" || typeof savedRelay !== \"string\") {\n return null;\n }\n if (trimRelayUrl(savedRelay) !== trimRelayUrl(relayUrl)) return null;\n parseAddress(address);\n return address;\n } catch {\n return null;\n }\n }\n\n /**\n * Load a previously saved token, or return null.\n *\n * Checks UAM_TOKEN env var first, then file-based storage,\n * then legacy .api_key files for backward compatibility. With `relayUrl`,\n * a saved token that belongs to another relay counts as none, so it is\n * only offered to the relay that issued it.\n */\n loadToken(name: string, relayUrl?: string): string | null {\n // 1. Check environment variable\n const envToken = process.env[\"UAM_TOKEN\"];\n if (envToken) {\n return envToken.trim();\n }\n\n if (relayUrl !== undefined && this._savedForAnotherRelay(name, relayUrl)) {\n return null;\n }\n\n // 2. File-based storage\n const tokenPath = join(this._keyDir, `${name}.token`);\n if (existsSync(tokenPath)) {\n return readFileSync(tokenPath, \"utf-8\").trim();\n }\n // Backward compatibility: check for legacy .api_key file\n const legacyPath = join(this._keyDir, `${name}.api_key`);\n if (existsSync(legacyPath)) {\n return readFileSync(legacyPath, \"utf-8\").trim();\n }\n return null;\n }\n\n /**\n * True if the saved address says this agent's files are another relay's.\n * A missing or damaged file says nothing.\n */\n private _savedForAnotherRelay(name: string, relayUrl: string): boolean {\n try {\n const path = join(this._keyDir, `${name}.address`);\n const saved = JSON.parse(readFileSync(path, \"utf-8\")) as {\n relay_url?: unknown;\n } | null;\n const savedRelay = saved?.relay_url;\n return (\n typeof savedRelay === \"string\" &&\n trimRelayUrl(savedRelay) !== trimRelayUrl(relayUrl)\n );\n } catch {\n return false;\n }\n }\n\n /** Set file permissions to 0o600 (owner read/write only). */\n private _setPermissions(path: string): void {\n if (platform() !== \"win32\") {\n chmodSync(path, 0o600);\n }\n }\n\n /** Warn if key file permissions are too permissive. */\n private _checkPermissions(path: string): void {\n if (platform() === \"win32\") {\n return; // Cannot reliably check on Windows\n }\n try {\n const mode = statSync(path).mode & 0o777;\n if (mode !== 0o600) {\n console.warn(\n `Key file ${path} has permissions ${mode.toString(8)} (expected 600). ` +\n `Run: chmod 600 ${path}`\n );\n }\n } catch {\n // Ignore stat errors\n }\n }\n}\n","/**\n * SQLite-backed local contact storage (HAND-03).\n *\n * Stores known contacts with their public keys and trust state.\n * Provides fast in-memory caches for isKnown() and isBlocked() checks.\n *\n * Uses better-sqlite3 for synchronous SQLite (simpler than Python's aiosqlite).\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport { KeyPinningError } from \"../protocol/errors.js\";\nimport { log } from \"./log.js\";\n\n/**\n * A row returned from listContacts().\n */\nexport interface ContactRow {\n address: string;\n displayName: string | null;\n trustState: string;\n firstSeen: string;\n lastSeen: string;\n}\n\n/**\n * A pending handshake entry.\n */\nexport interface PendingEntry {\n address: string;\n contactCard: string;\n receivedAt: string;\n}\n\n/**\n * A blocked pattern entry.\n */\nexport interface BlockedEntry {\n pattern: string;\n blockedAt: string;\n}\n\nexport class ContactBook {\n private _dbPath: string;\n private _db: Database.Database | null = null;\n private _knownAddresses: Set<string> = new Set();\n private _blockedExact: Set<string> = new Set();\n private _blockedDomains: Set<string> = new Set();\n\n constructor(dataDir: string) {\n this._dbPath = join(dataDir, \"contacts\", \"contacts.db\");\n }\n\n /**\n * Open the database, create tables, run migrations, load caches.\n */\n open(): void {\n mkdirSync(dirname(this._dbPath), { recursive: true });\n this._db = new Database(this._dbPath);\n this._db.pragma(\"journal_mode = WAL\");\n\n // Create tables with all columns upfront (no migrations needed for new DB)\n this._db.exec(`\n CREATE TABLE IF NOT EXISTS contacts (\n address TEXT PRIMARY KEY,\n public_key TEXT NOT NULL,\n display_name TEXT,\n trust_state TEXT NOT NULL DEFAULT 'unknown',\n trust_source TEXT DEFAULT 'legacy-unknown',\n relay TEXT,\n relays_json TEXT,\n pinned_at TEXT,\n first_seen TEXT NOT NULL DEFAULT (datetime('now')),\n last_seen TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS pending_handshakes (\n address TEXT PRIMARY KEY,\n contact_card TEXT NOT NULL,\n received_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS blocked_patterns (\n pattern TEXT PRIMARY KEY,\n blocked_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n `);\n\n // Run migrations\n this._migrate();\n\n // Load all known addresses into memory for fast sync lookups\n const rows = this._db\n .prepare(\"SELECT address FROM contacts\")\n .all() as Array<{ address: string }>;\n this._knownAddresses = new Set(rows.map((r) => r.address));\n\n // Load blocked patterns into memory\n this._blockedExact.clear();\n this._blockedDomains.clear();\n const blocked = this._db\n .prepare(\"SELECT pattern FROM blocked_patterns\")\n .all() as Array<{ pattern: string }>;\n for (const row of blocked) {\n this._cacheBlockPattern(row.pattern);\n }\n }\n\n /**\n * Run schema migrations using PRAGMA user_version.\n */\n private _migrate(): void {\n if (!this._db) return;\n\n const versionRow = this._db\n .prepare(\"PRAGMA user_version\")\n .get() as { user_version: number };\n const version = versionRow.user_version;\n\n if (version < 2) {\n // For new DBs, tables are created with all columns upfront\n // (including pinned_at). Skip straight to version 3.\n this._db.exec(\"PRAGMA user_version = 3\");\n } else if (version < 3) {\n // Existing v2 database: add pinned_at column for key pinning lifecycle\n this._db.exec(\n \"ALTER TABLE contacts ADD COLUMN pinned_at TEXT\"\n );\n this._db.exec(\"PRAGMA user_version = 3\");\n }\n }\n\n /**\n * Close the database connection.\n */\n close(): void {\n if (this._db !== null) {\n this._db.close();\n this._db = null;\n }\n }\n\n /**\n * Check if an address is in the contact book (in-memory, no I/O).\n */\n isKnown(address: string): boolean {\n return this._knownAddresses.has(address);\n }\n\n /**\n * Check if an address matches any blocked pattern (O(1) set lookup).\n */\n isBlocked(address: string): boolean {\n if (this._blockedExact.has(address)) {\n return true;\n }\n // Extract domain from 'name::domain' format\n if (address.includes(\"::\")) {\n const domain = address.split(\"::\")[1];\n return this._blockedDomains.has(domain);\n }\n return false;\n }\n\n /**\n * Look up the public key for a known contact.\n */\n getPublicKey(address: string): string | null {\n if (this._db === null) return null;\n const row = this._db\n .prepare(\"SELECT public_key FROM contacts WHERE address = ?\")\n .get(address) as { public_key: string } | undefined;\n return row?.public_key ?? null;\n }\n\n /**\n * Return the relay URLs for a known contact (CARD-04).\n */\n getRelayUrls(address: string): string[] | null {\n if (this._db === null) return null;\n const row = this._db\n .prepare(\"SELECT relay, relays_json FROM contacts WHERE address = ?\")\n .get(address) as { relay: string | null; relays_json: string | null } | undefined;\n if (!row) return null;\n if (row.relays_json !== null) {\n return JSON.parse(row.relays_json) as string[];\n }\n if (row.relay !== null) {\n return [row.relay];\n }\n return null;\n }\n\n /**\n * Add or update a contact (upsert).\n *\n * Refuses to replace the key of a contact whose trust_state is \"pinned\"\n * or \"verified\" with a different key, unless `force: true` is passed (for\n * a deliberate key rotation, which is logged). Matches the Python SDK's\n * ContactBook.add_contact.\n *\n * @throws {KeyPinningError} If a pinned/verified contact's key would be\n * replaced by a different key without `force`.\n */\n addContact(\n address: string,\n publicKey: string,\n options?: {\n displayName?: string | null;\n trustState?: string;\n trustSource?: string | null;\n relay?: string | null;\n relays?: string[] | null;\n force?: boolean;\n }\n ): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n\n const existing = this._db\n .prepare(\"SELECT public_key, trust_state FROM contacts WHERE address = ?\")\n .get(address) as { public_key: string; trust_state: string } | undefined;\n if (\n existing !== undefined &&\n (existing.trust_state === \"pinned\" ||\n existing.trust_state === \"verified\") &&\n existing.public_key !== publicKey\n ) {\n if (!options?.force) {\n throw new KeyPinningError(\n `Refusing to overwrite ${existing.trust_state} contact ` +\n `${JSON.stringify(address)}: stored public key does not match ` +\n `the new key. Pass force: true to rotate.`\n );\n }\n log.warn(\n `Force-replacing the key of ${existing.trust_state} contact ` +\n `${address} (key rotation)`\n );\n }\n\n const displayName = options?.displayName ?? null;\n const trustState = options?.trustState ?? \"trusted\";\n const trustSource = options?.trustSource ?? null;\n const relay = options?.relay ?? null;\n const relaysJson =\n options?.relays !== undefined && options?.relays !== null\n ? JSON.stringify(options.relays)\n : null;\n\n this._db\n .prepare(\n `INSERT INTO contacts (address, public_key, display_name, trust_state, trust_source, relay, relays_json)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(address) DO UPDATE SET\n public_key = excluded.public_key,\n display_name = excluded.display_name,\n trust_state = excluded.trust_state,\n trust_source = COALESCE(excluded.trust_source, contacts.trust_source),\n relay = COALESCE(excluded.relay, contacts.relay),\n relays_json = COALESCE(excluded.relays_json, contacts.relays_json),\n last_seen = datetime('now')`\n )\n .run(address, publicKey, displayName, trustState, trustSource, relay, relaysJson);\n\n this._knownAddresses.add(address);\n }\n\n /**\n * Return all contacts sorted by last_seen DESC.\n */\n listContacts(): ContactRow[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n \"SELECT address, display_name, trust_state, first_seen, last_seen \" +\n \"FROM contacts ORDER BY last_seen DESC\"\n )\n .all() as Array<{\n address: string;\n display_name: string | null;\n trust_state: string;\n first_seen: string;\n last_seen: string;\n }>;\n return rows.map((r) => ({\n address: r.address,\n displayName: r.display_name,\n trustState: r.trust_state,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n }));\n }\n\n /**\n * Store a pending handshake request.\n */\n addPending(address: string, contactCardJson: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\n `INSERT OR REPLACE INTO pending_handshakes (address, contact_card) VALUES (?, ?)`\n )\n .run(address, contactCardJson);\n }\n\n /**\n * Retrieve all pending handshake requests.\n */\n getPending(): PendingEntry[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n \"SELECT address, contact_card, received_at FROM pending_handshakes\"\n )\n .all() as Array<{\n address: string;\n contact_card: string;\n received_at: string;\n }>;\n return rows.map((r) => ({\n address: r.address,\n contactCard: r.contact_card,\n receivedAt: r.received_at,\n }));\n }\n\n /**\n * Remove a pending handshake request.\n */\n removePending(address: string): void {\n if (this._db === null) return;\n this._db\n .prepare(\"DELETE FROM pending_handshakes WHERE address = ?\")\n .run(address);\n }\n\n /**\n * Return pending handshakes older than N days.\n */\n getExpiredPending(days: number = 7): PendingEntry[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n `SELECT address, contact_card, received_at FROM pending_handshakes\n WHERE datetime(received_at, '+' || ? || ' days') < datetime('now')`\n )\n .all(String(days)) as Array<{\n address: string;\n contact_card: string;\n received_at: string;\n }>;\n return rows.map((r) => ({\n address: r.address,\n contactCard: r.contact_card,\n receivedAt: r.received_at,\n }));\n }\n\n /**\n * Return the trust_state for an address, or null if unknown.\n */\n getTrustState(address: string): string | null {\n if (this._db === null) return null;\n const row = this._db\n .prepare(\"SELECT trust_state FROM contacts WHERE address = ?\")\n .get(address) as { trust_state: string } | undefined;\n return row?.trust_state ?? null;\n }\n\n /**\n * Set the pinned_at timestamp and trust_state='pinned' for a contact (TOFU).\n */\n setPinnedAt(address: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\n \"UPDATE contacts SET pinned_at = datetime('now'), trust_state = 'pinned' WHERE address = ?\"\n )\n .run(address);\n }\n\n /**\n * Remove a contact by address. Returns true if a contact was deleted.\n */\n removeContact(address: string): boolean {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n const result = this._db\n .prepare(\"DELETE FROM contacts WHERE address = ?\")\n .run(address);\n this._knownAddresses.delete(address);\n return result.changes > 0;\n }\n\n /**\n * Return true if the address has trust_state 'trusted', 'verified', or 'pinned'.\n *\n * Convenience helper for inbound message filtering (CARD-05, TOFU-02).\n */\n isTrustedOrVerified(address: string): boolean {\n const state = this.getTrustState(address);\n return state === \"trusted\" || state === \"verified\" || state === \"pinned\";\n }\n\n /**\n * Block an address or domain pattern (e.g., '*::evil.com').\n */\n addBlock(pattern: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\"INSERT OR IGNORE INTO blocked_patterns (pattern) VALUES (?)\")\n .run(pattern);\n this._cacheBlockPattern(pattern);\n }\n\n /**\n * Remove a block pattern.\n */\n removeBlock(pattern: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\"DELETE FROM blocked_patterns WHERE pattern = ?\")\n .run(pattern);\n this._uncacheBlockPattern(pattern);\n }\n\n /**\n * Return all blocked patterns with their timestamps.\n */\n listBlocked(): BlockedEntry[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n \"SELECT pattern, blocked_at FROM blocked_patterns ORDER BY blocked_at DESC\"\n )\n .all() as Array<{ pattern: string; blocked_at: string }>;\n return rows.map((r) => ({\n pattern: r.pattern,\n blockedAt: r.blocked_at,\n }));\n }\n\n // -- Internal block caching ---------------------------------------------------\n\n private _cacheBlockPattern(pattern: string): void {\n if (pattern.startsWith(\"*::\")) {\n this._blockedDomains.add(pattern.slice(3));\n } else {\n this._blockedExact.add(pattern);\n }\n }\n\n private _uncacheBlockPattern(pattern: string): void {\n if (pattern.startsWith(\"*::\")) {\n this._blockedDomains.delete(pattern.slice(3));\n } else {\n this._blockedExact.delete(pattern);\n }\n }\n}\n","/**\n * Minimal SDK logger.\n *\n * Mirrors the Python SDK's use of `logging`: warnings go to stderr, info\n * messages are only printed when UAM_DEBUG is set.\n */\n\nexport const log = {\n warn(message: string): void {\n console.warn(`[uam] ${message}`);\n },\n info(message: string): void {\n if (process.env[\"UAM_DEBUG\"]) {\n console.info(`[uam] ${message}`);\n }\n },\n};\n","/**\n * First-contact handshake flow manager (HAND-01 through HAND-04).\n *\n * Handles the three-phase handshake:\n * 1. HANDSHAKE_REQUEST: sender sends contact card (encrypted with SealedBox)\n * 2. HANDSHAKE_ACCEPT: recipient stores contact and sends accept back\n * 3. HANDSHAKE_DENY: recipient rejects the handshake\n *\n * The HandshakeManager works with the ContactBook to persist trust decisions.\n */\n\nimport {\n MessageType,\n createEnvelope,\n createContactCard,\n verifyContactCard,\n contactCardToDict,\n contactCardFromDict,\n decryptPayload,\n decryptPayloadAnonymous,\n serializeVerifyKey,\n toWireDict,\n InvalidEnvelopeError,\n type ContactCard,\n type MessageEnvelope,\n type VerifyKey,\n} from \"../protocol/index.js\";\nimport type { ContactBook } from \"./contact-book.js\";\nimport type { ReceivedMessage } from \"./message.js\";\nimport { log } from \"./log.js\";\n\n// Forward reference type for Agent to avoid circular dependency\ninterface AgentLike {\n readonly address: string;\n readonly _config: {\n readonly displayName: string;\n readonly relayWsUrl: string;\n };\n readonly _keyManager: {\n readonly signingKey: Uint8Array;\n };\n readonly _transport: {\n send(envelope: Record<string, unknown>): Promise<void>;\n } | null;\n}\n\n/**\n * Check that a contact card's claimed identity is the envelope's sender.\n *\n * A card embedded in a handshake envelope must name the envelope's\n * `fromAddress` and carry the verify key that signed the envelope. Without\n * this, a sender could sign an envelope from their own address while\n * embedding a (self-consistent) card for someone else's address or key, and\n * get that identity stored in the recipient's contact book.\n *\n * `envelope` only needs `fromAddress`, so Agent.approve() can re-check a\n * stored pending entry against the address it was received from.\n *\n * Matches Python `_bind_card_to_envelope` (handshake.py).\n *\n * @throws {InvalidEnvelopeError} If the address or the key does not match.\n */\nexport function bindCardToEnvelope(\n card: ContactCard,\n envelope: { readonly fromAddress: string },\n senderVk: VerifyKey\n): void {\n if (card.address !== envelope.fromAddress) {\n throw new InvalidEnvelopeError(\n `Contact card address ${JSON.stringify(card.address)} does not match ` +\n `envelope sender ${JSON.stringify(envelope.fromAddress)}`\n );\n }\n if (card.publicKey !== serializeVerifyKey(senderVk)) {\n throw new InvalidEnvelopeError(\n \"Contact card public_key does not match envelope sender's verify key\"\n );\n }\n}\n\nexport class HandshakeManager {\n private _contactBook: ContactBook;\n readonly _trustPolicy: string;\n\n constructor(contactBook: ContactBook, trustPolicy: string) {\n this._contactBook = contactBook;\n this._trustPolicy = trustPolicy;\n }\n\n /**\n * Create a handshake request envelope with embedded contact card.\n *\n * The payload is the JSON-serialized contact card, encrypted with\n * SealedBox (anonymous encryption) to the recipient.\n *\n * Returns wire-format dict ready to send via transport.\n */\n async createHandshakeRequest(\n agent: AgentLike,\n toAddress: string,\n recipientVk: VerifyKey\n ): Promise<Record<string, unknown>> {\n // Create contact card for the sending agent\n const card = await createContactCard(\n agent.address,\n agent._config.displayName,\n agent._config.relayWsUrl,\n agent._keyManager.signingKey\n );\n const cardJson = JSON.stringify(contactCardToDict(card));\n\n // Create envelope -- createEnvelope auto-uses SealedBox for HANDSHAKE_REQUEST\n const envelope = await createEnvelope(\n agent.address,\n toAddress,\n MessageType.HANDSHAKE_REQUEST,\n new TextEncoder().encode(cardJson),\n agent._keyManager.signingKey,\n recipientVk\n );\n\n return toWireDict(envelope);\n }\n\n /**\n * Handle an inbound handshake message.\n *\n * Returns null -- handshake messages are not user-visible.\n */\n async handleInbound(\n agent: AgentLike,\n envelope: MessageEnvelope,\n senderVk: VerifyKey\n ): Promise<ReceivedMessage | null> {\n if (envelope.type === MessageType.HANDSHAKE_REQUEST) {\n await this._handleRequest(agent, envelope, senderVk);\n } else if (envelope.type === MessageType.HANDSHAKE_ACCEPT) {\n await this._handleAccept(agent, envelope, senderVk);\n } else if (envelope.type === MessageType.HANDSHAKE_DENY) {\n // Handshake denied -- logged silently\n }\n return null;\n }\n\n /**\n * Process a handshake.request: decrypt contact card, apply trust policy.\n */\n private async _handleRequest(\n agent: AgentLike,\n envelope: MessageEnvelope,\n senderVk: VerifyKey\n ): Promise<void> {\n // Handshake requests are encrypted with SealedBox (anonymous)\n const plaintext = decryptPayloadAnonymous(\n envelope.payload,\n agent._keyManager.signingKey\n );\n const cardDict = JSON.parse(\n new TextDecoder().decode(plaintext)\n ) as Record<string, unknown>;\n const card = contactCardFromDict(cardDict);\n\n // Verify the contact card's self-signature\n verifyContactCard(card);\n\n // Bind the card to the envelope sender before anything is stored.\n bindCardToEnvelope(card, envelope, senderVk);\n\n if (this._trustPolicy === \"auto-accept\") {\n // Store the contact as provisional (TOFU: trust upgrades on accept)\n this._contactBook.addContact(card.address, card.publicKey, {\n displayName: card.displayName,\n trustState: \"provisional\",\n trustSource: \"auto-accepted-provisional\",\n });\n // Send handshake.accept back\n await this._sendAccept(agent, envelope.fromAddress, senderVk);\n } else if (this._trustPolicy === \"allowlist-only\") {\n // Auto-deny: only pre-approved contacts are allowed\n await this._sendDeny(agent, envelope.fromAddress, senderVk);\n } else {\n // approval-required: store in pending for manual review\n this._contactBook.addPending(\n envelope.fromAddress,\n JSON.stringify(cardDict)\n );\n }\n }\n\n /**\n * Process a handshake.accept: store the sender as pinned (TOFU).\n *\n * Only honoured when:\n * 1. we previously sent this address a handshake.request\n * (trust_state === \"handshake-sent\"); anything else is an unsolicited\n * accept and is dropped. This also means an accept can never\n * downgrade a trusted/verified contact to pinned;\n * 2. the payload decrypts with our key and the sender's key, and parses\n * as JSON. Otherwise it is dropped without pinning;\n * 3. an embedded contact_card, if present, is well-formed, correctly\n * self-signed, and bound to the envelope sender (throws otherwise).\n */\n private async _handleAccept(\n agent: AgentLike,\n envelope: MessageEnvelope,\n senderVk: VerifyKey\n ): Promise<void> {\n const prior = this._contactBook.getTrustState(envelope.fromAddress);\n if (prior !== \"handshake-sent\") {\n log.warn(\n `Ignoring unsolicited handshake.accept from ${envelope.fromAddress} ` +\n `(trust_state=${JSON.stringify(prior)})`\n );\n return;\n }\n\n let payload: unknown;\n try {\n const plaintext = decryptPayload(\n envelope.payload,\n agent._keyManager.signingKey,\n senderVk\n );\n payload = JSON.parse(new TextDecoder().decode(plaintext));\n } catch {\n log.warn(\n `Dropping handshake.accept ${envelope.messageId} from ` +\n `${envelope.fromAddress}: payload could not be decrypted or parsed`\n );\n return;\n }\n\n if (\n payload !== null &&\n typeof payload === \"object\" &&\n \"contact_card\" in payload\n ) {\n const card = contactCardFromDict(\n (payload as Record<string, unknown>)[\"contact_card\"] as Record<\n string,\n unknown\n >\n );\n verifyContactCard(card);\n bindCardToEnvelope(card, envelope, senderVk);\n }\n\n const senderPkStr = serializeVerifyKey(senderVk);\n this._contactBook.addContact(envelope.fromAddress, senderPkStr, {\n trustState: \"pinned\",\n });\n this._contactBook.setPinnedAt(envelope.fromAddress);\n }\n\n /**\n * Send a handshake.accept envelope back to the requester.\n */\n async _sendAccept(\n agent: AgentLike,\n toAddress: string,\n recipientVk: VerifyKey\n ): Promise<void> {\n const card = await createContactCard(\n agent.address,\n agent._config.displayName,\n agent._config.relayWsUrl,\n agent._keyManager.signingKey\n );\n const acceptPayload = JSON.stringify({\n status: \"accepted\",\n contact_card: contactCardToDict(card),\n });\n\n const envelope = await createEnvelope(\n agent.address,\n toAddress,\n MessageType.HANDSHAKE_ACCEPT,\n new TextEncoder().encode(acceptPayload),\n agent._keyManager.signingKey,\n recipientVk\n );\n\n const wire = toWireDict(envelope);\n if (agent._transport) {\n await agent._transport.send(wire);\n }\n }\n\n /**\n * Send a handshake.deny envelope to the requester.\n */\n async _sendDeny(\n agent: AgentLike,\n toAddress: string,\n recipientVk: VerifyKey\n ): Promise<void> {\n const denyPayload = JSON.stringify({\n status: \"denied\",\n reason: \"allowlist-only\",\n });\n\n const envelope = await createEnvelope(\n agent.address,\n toAddress,\n MessageType.HANDSHAKE_DENY,\n new TextEncoder().encode(denyPayload),\n agent._keyManager.signingKey,\n recipientVk\n );\n\n const wire = toWireDict(envelope);\n if (agent._transport) {\n await agent._transport.send(wire);\n }\n }\n}\n","/**\n * Base class for address resolvers.\n *\n * Lives in its own module so tier3.ts can extend it without importing\n * resolver.ts (which imports tier3.ts), avoiding an import cycle.\n */\n\n/**\n * Pluggable address resolver interface.\n */\nexport abstract class AddressResolver {\n /**\n * Resolve an agent address to its public key (base64).\n *\n * @throws {UAMError} If the address cannot be resolved.\n */\n abstract resolvePublicKey(\n address: string,\n token: string,\n relayUrl: string\n ): Promise<string>;\n}\n","/**\n * Tier 3 resolver: on-chain namespace lookup via UAMNameRegistry (TSSDK-09).\n *\n * Uses viem for contract reads on Base Sepolia/Base L2.\n */\n\nimport { createPublicClient, http, type Address, defineChain } from \"viem\";\nimport { UAMError } from \"../protocol/index.js\";\nimport { parseAddress } from \"../protocol/address.js\";\nimport { AddressResolver } from \"./resolver-base.js\";\n\n// Default config\nconst DEFAULT_RPC_URL = \"https://sepolia.base.org\";\nconst DEFAULT_CHAIN_ID = 84532; // Base Sepolia\n\n// Cache TTL: 1 hour in milliseconds\nconst CACHE_TTL_MS = 3600 * 1000;\n\n// Minimal ABI for resolve() and available() -- inline to avoid file I/O\nconst REGISTRY_ABI = [\n {\n name: \"resolve\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"name\", type: \"string\" }],\n outputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"publicKey\", type: \"string\" },\n { name: \"relayUrl\", type: \"string\" },\n { name: \"expiry\", type: \"uint256\" },\n ],\n },\n {\n name: \"available\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"name\", type: \"string\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n] as const;\n\ninterface CacheEntry {\n publicKey: string;\n expiresAt: number; // Date.now() + TTL\n}\n\nexport interface Tier3Config {\n contractAddress: string;\n rpcUrl?: string;\n chainId?: number;\n cacheTtlMs?: number;\n}\n\n/**\n * Build a minimal chain definition for viem.\n * Using defineChain avoids importing chain-specific types from viem/chains\n * which cause TypeScript compatibility issues with generic PublicClient.\n */\nfunction buildChain(chainId: number, rpcUrl: string) {\n return defineChain({\n id: chainId,\n name: `chain-${chainId}`,\n nativeCurrency: { name: \"Ether\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: { http: [rpcUrl] },\n },\n });\n}\n\n/**\n * Resolve agent addresses via on-chain UAMNameRegistry contract.\n *\n * Uses viem PublicClient to call resolve() on the contract.\n * Caches results for 1 hour to minimize RPC calls.\n */\nexport class Tier3Resolver extends AddressResolver {\n private _contractAddress: Address;\n private _client: ReturnType<typeof createPublicClient>;\n private _cacheTtlMs: number;\n private _cache: Map<string, CacheEntry> = new Map();\n\n constructor(config: Tier3Config) {\n super();\n this._contractAddress = config.contractAddress as Address;\n this._cacheTtlMs = config.cacheTtlMs ?? CACHE_TTL_MS;\n const rpcUrl = config.rpcUrl ?? DEFAULT_RPC_URL;\n const chainId = config.chainId ?? DEFAULT_CHAIN_ID;\n this._client = createPublicClient({\n chain: buildChain(chainId, rpcUrl),\n transport: http(rpcUrl),\n });\n }\n\n async resolvePublicKey(\n address: string,\n _token: string,\n _relayUrl: string\n ): Promise<string> {\n const parsed = parseAddress(address);\n const name = parsed.domain; // For Tier 3, domain IS the namespace\n\n // Check cache\n const cached = this._cache.get(name);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.publicKey;\n }\n\n // Call contract\n try {\n const result = await this._client.readContract({\n address: this._contractAddress,\n abi: REGISTRY_ABI,\n functionName: \"resolve\",\n args: [name],\n });\n\n const [_owner, publicKey, _relayUrl2, _expiry] = result;\n\n if (!publicKey) {\n throw new UAMError(\n `Tier 3 name '${name}' has no public key registered`\n );\n }\n\n // Cache result\n this._cache.set(name, {\n publicKey,\n expiresAt: Date.now() + this._cacheTtlMs,\n });\n\n return publicKey;\n } catch (err) {\n if (err instanceof UAMError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"NameNotFound\") || msg.includes(\"revert\")) {\n throw new UAMError(`Tier 3 name not found on-chain: ${name}`);\n }\n throw new UAMError(`Tier 3 resolution failed for ${name}: ${msg}`);\n }\n }\n\n /**\n * Check if a name is available for registration.\n */\n async isAvailable(name: string): Promise<boolean> {\n try {\n const result = await this._client.readContract({\n address: this._contractAddress,\n abi: REGISTRY_ABI,\n functionName: \"available\",\n args: [name],\n });\n return result;\n } catch {\n return false;\n }\n }\n\n /**\n * Clear cache for a specific name or all names.\n */\n invalidateCache(name?: string): void {\n if (name) {\n this._cache.delete(name);\n } else {\n this._cache.clear();\n }\n }\n}\n","/**\n * Pluggable address resolver with Tier 1 relay lookup (SDK-08).\n *\n * Matches Python resolver.py: SmartResolver routes by domain format.\n */\n\nimport { UAMError } from \"../protocol/index.js\";\nimport { parseAddress } from \"../protocol/address.js\";\nimport { AddressResolver } from \"./resolver-base.js\";\nimport { Tier3Resolver, type Tier3Config } from \"./tier3.js\";\nimport {\n queryUamTxt,\n parseUamTxt,\n extractPublicKey,\n resolveKeyViaHttps,\n} from \"./dns-verifier.js\";\n\nexport { AddressResolver } from \"./resolver-base.js\";\n\n/**\n * Tier 1: resolve via relay HTTP API.\n *\n * Calls GET /api/v1/agents/{address}/public-key.\n */\nexport class Tier1Resolver extends AddressResolver {\n async resolvePublicKey(\n address: string,\n _token: string,\n relayUrl: string\n ): Promise<string> {\n const resp = await fetch(\n `${relayUrl}/api/v1/agents/${address}/public-key`\n );\n if (resp.status === 404) {\n throw new UAMError(`Agent not found: ${address}`);\n }\n if (!resp.ok) {\n throw new UAMError(\n `Resolver request failed: ${resp.status} ${resp.statusText}`\n );\n }\n const data = (await resp.json()) as Record<string, unknown>;\n return data[\"public_key\"] as string;\n }\n}\n\n/**\n * Tier 2: DNS TXT record resolution (DNS-01).\n *\n * Resolution order:\n * 1. Query _uam.{domain} TXT records for v=uam1 entries\n * 2. Fallback to HTTPS .well-known/uam.json\n * 3. Throw UAMError if both fail\n */\nexport class Tier2Resolver extends AddressResolver {\n async resolvePublicKey(\n address: string,\n _token: string,\n _relayUrl: string\n ): Promise<string> {\n const parsed = parseAddress(address);\n\n // 1. Try DNS TXT at _uam.{domain}\n const txtRecords = await queryUamTxt(parsed.domain);\n for (const txt of txtRecords) {\n const tags = parseUamTxt(txt);\n if (tags[\"v\"] === \"uam1\") {\n const key = extractPublicKey(tags);\n if (key) return key;\n }\n }\n\n // 2. Fallback to HTTPS .well-known\n const httpsKey = await resolveKeyViaHttps(parsed.agent, parsed.domain);\n if (httpsKey) return httpsKey;\n\n throw new UAMError(\n `Could not resolve public key for ${address} via DNS or HTTPS`\n );\n }\n}\n\n/**\n * Automatic tier-based resolver that routes by domain format (RESOLVE-01).\n *\n * Routing rules:\n * - domain == relayDomain -> Tier 1 (relay HTTP API lookup)\n * - domain contains a '.' -> Tier 2 (DNS -- stub)\n * - domain has no dots -> Tier 3 (on-chain namespace lookup)\n */\nexport class SmartResolver extends AddressResolver {\n relayDomain: string;\n private _tier1: Tier1Resolver;\n private _tier2: Tier2Resolver;\n private _tier3: Tier3Resolver | null;\n\n constructor(relayDomain: string, tier3Config?: Tier3Config) {\n super();\n this.relayDomain = relayDomain;\n this._tier1 = new Tier1Resolver();\n this._tier2 = new Tier2Resolver();\n this._tier3 = tier3Config ? new Tier3Resolver(tier3Config) : null;\n }\n\n async resolvePublicKey(\n address: string,\n token: string,\n relayUrl: string\n ): Promise<string> {\n const parsed = parseAddress(address);\n const domain = parsed.domain;\n\n if (domain === this.relayDomain) {\n return this._tier1.resolvePublicKey(address, token, relayUrl);\n }\n\n if (domain.includes(\".\")) {\n return this._tier2.resolvePublicKey(address, token, relayUrl);\n }\n\n if (!this._tier3) {\n throw new UAMError(\n `Tier 3 resolution requires contract config. ` +\n `Cannot resolve dot-free domain: '${domain}'`\n );\n }\n return this._tier3.resolvePublicKey(address, token, relayUrl);\n }\n}\n\n// Re-export Tier3 types for convenience\nexport { Tier3Resolver, type Tier3Config } from \"./tier3.js\";\n","/**\n * Abstract transport interface for relay communication.\n *\n * Two implementations:\n * - HTTPTransport: stateless polling via REST API\n * - WebSocketTransport: persistent real-time connection\n */\n\nexport abstract class TransportBase {\n /** Establish connection to the relay. */\n abstract connect(): Promise<void>;\n\n /** Close the connection. */\n abstract disconnect(): Promise<void>;\n\n /** Send a message envelope to the relay. */\n abstract send(envelope: Record<string, unknown>): Promise<void>;\n\n /** Retrieve pending messages from the relay. */\n abstract receive(limit?: number): Promise<Record<string, unknown>[]>;\n\n /**\n * Start listening for real-time messages.\n *\n * For WebSocket: registers a callback for push delivery.\n * For HTTP: not supported (throws Error).\n */\n abstract listen(\n callback: (msg: Record<string, unknown>) => Promise<void>\n ): Promise<void>;\n}\n","/**\n * HTTP transport via native fetch (SDK-09).\n *\n * Sends envelopes via POST /api/v1/send and retrieves inbox\n * via GET /api/v1/inbox/{address}.\n *\n * Uses native fetch (Node.js 18+ has global fetch).\n */\n\nimport { TransportBase } from \"./base.js\";\n\nexport class HTTPTransport extends TransportBase {\n private _relayUrl: string;\n private _token: string;\n private _address: string;\n\n constructor(relayUrl: string, token: string, address: string) {\n super();\n this._relayUrl = relayUrl.replace(/\\/+$/, \"\");\n this._token = token;\n this._address = address;\n }\n\n async connect(): Promise<void> {\n // No persistent connection needed for HTTP\n }\n\n async disconnect(): Promise<void> {\n // No-op\n }\n\n async send(envelope: Record<string, unknown>): Promise<void> {\n const resp = await fetch(`${this._relayUrl}/api/v1/send`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._token}`,\n },\n body: JSON.stringify({ envelope }),\n });\n if (!resp.ok) {\n throw new Error(\n `HTTP send failed: ${resp.status} ${resp.statusText}`\n );\n }\n }\n\n async receive(limit: number = 50): Promise<Record<string, unknown>[]> {\n const url = new URL(\n `${this._relayUrl}/api/v1/inbox/${this._address}`\n );\n url.searchParams.set(\"limit\", String(limit));\n\n const resp = await fetch(url.toString(), {\n headers: {\n Authorization: `Bearer ${this._token}`,\n },\n });\n if (!resp.ok) {\n throw new Error(\n `HTTP receive failed: ${resp.status} ${resp.statusText}`\n );\n }\n const data = (await resp.json()) as Record<string, unknown>;\n return (data[\"messages\"] as Record<string, unknown>[]) ?? [];\n }\n\n async listen(\n _callback: (msg: Record<string, unknown>) => Promise<void>\n ): Promise<void> {\n throw new Error(\n \"HTTP transport does not support real-time listening. \" +\n \"Use receive() for polling or switch to WebSocket transport.\"\n );\n }\n}\n","/**\n * WebSocket transport with exponential backoff and jitter (SDK-05).\n *\n * Maintains a persistent connection to the relay, automatically\n * reconnecting on disconnection with exponential backoff plus\n * random jitter to prevent thundering herd.\n */\n\nimport WebSocket from \"ws\";\nimport { log } from \"../log.js\";\nimport { TransportBase } from \"./base.js\";\n\n// Reconnection constants\nconst BASE_DELAY = 1.0; // Initial delay in seconds\nconst MAX_DELAY = 60.0; // Maximum delay cap\nconst JITTER_RANGE = 1.0; // Random jitter 0 to JITTER_RANGE\n\n/** How long a close waits for the relay to answer sends, in seconds. */\nexport const SEND_SETTLE_SECONDS = 5;\n\nexport class WebSocketTransport extends TransportBase {\n private _url: string;\n private _token: string;\n private _onMessage:\n | ((msg: Record<string, unknown>) => Promise<void>)\n | null;\n private _ws: WebSocket | null = null;\n private _pending: Record<string, unknown>[] = [];\n private _connected: boolean = false;\n private _connectResolve: (() => void) | null = null;\n private _connectReject: ((err: Error) => void) | null = null;\n private _running: boolean = false;\n private _reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n /** Envelopes sent that the relay hasn't answered yet. */\n private _unanswered: number = 0;\n private _settling: Promise<void> | null = null;\n private _settled: (() => void) | null = null;\n\n /** @internal How long a close waits, in ms. Replaceable in tests. */\n _settleMs: number = SEND_SETTLE_SECONDS * 1000;\n\n constructor(\n wsUrl: string,\n token: string,\n onMessage?: (msg: Record<string, unknown>) => Promise<void>\n ) {\n super();\n // The token travels in the `bearer.<token>` WebSocket subprotocol, not\n // in a ?token= query string, so it stays out of HTTP access logs and\n // proxy logs. The relay accepts this form and echoes the subprotocol\n // back (relay/ws.py); the Python SDK does the same.\n this._url = wsUrl;\n this._token = token;\n this._onMessage = onMessage ?? null;\n }\n\n async connect(): Promise<void> {\n this._running = true;\n return new Promise<void>((resolve, reject) => {\n this._connectResolve = resolve;\n this._connectReject = reject;\n this._startConnectionLoop();\n\n // 30s timeout for initial connection\n const timeout = setTimeout(() => {\n this._connectReject = null;\n this._connectResolve = null;\n reject(new Error(\"WebSocket connection timeout (30s)\"));\n }, 30000);\n\n // Patch resolve to clear timeout\n const origResolve = this._connectResolve;\n this._connectResolve = () => {\n clearTimeout(timeout);\n origResolve?.();\n };\n });\n }\n\n /**\n * Close the connection, once the relay has answered what was sent.\n *\n * The relay stops reading a socket when it can't write an ack to it, so\n * closing straight after send() loses every frame but the first.\n */\n async disconnect(): Promise<void> {\n await this._allAnswered();\n this._running = false;\n if (this._reconnectTimeout !== null) {\n clearTimeout(this._reconnectTimeout);\n this._reconnectTimeout = null;\n }\n if (this._ws) {\n this._ws.removeAllListeners();\n this._ws.close();\n this._ws = null;\n }\n this._connected = false;\n }\n\n async send(envelope: Record<string, unknown>): Promise<void> {\n if (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n throw new Error(\"WebSocket not connected\");\n }\n this._ws.send(JSON.stringify(envelope));\n this._unanswered += 1;\n }\n\n async receive(limit: number = 50): Promise<Record<string, unknown>[]> {\n const result = this._pending.slice(0, limit);\n this._pending = this._pending.slice(limit);\n return result;\n }\n\n async listen(\n callback: (msg: Record<string, unknown>) => Promise<void>\n ): Promise<void> {\n this._onMessage = callback;\n }\n\n /** Resolves when nothing is unanswered, or after _settleMs regardless. */\n private _allAnswered(): Promise<void> {\n if (this._unanswered === 0) return Promise.resolve();\n this._settling ??= new Promise<void>((resolve) => {\n const timeout = setTimeout(() => {\n log.warn(`Closing with ${this._unanswered} sends unanswered`);\n this._settled?.();\n }, this._settleMs);\n this._settled = () => {\n clearTimeout(timeout);\n this._settling = null;\n this._settled = null;\n resolve();\n };\n });\n return this._settling;\n }\n\n private _answered(): void {\n this._unanswered = Math.max(0, this._unanswered - 1);\n if (this._unanswered === 0) this._settled?.();\n }\n\n private _startConnectionLoop(): void {\n let attempt = 0;\n\n const tryConnect = () => {\n if (!this._running) return;\n\n const ws = new WebSocket(this._url, [`bearer.${this._token}`]);\n this._ws = ws;\n\n ws.on(\"open\", () => {\n this._connected = true;\n attempt = 0; // Reset on successful connection\n if (this._connectResolve) {\n this._connectResolve();\n this._connectResolve = null;\n this._connectReject = null;\n }\n });\n\n ws.on(\"message\", (data: WebSocket.Data) => {\n try {\n const msg = JSON.parse(data.toString()) as Record<string, unknown>;\n this._handleMessage(msg);\n } catch {\n // Ignore unparseable messages\n }\n });\n\n ws.on(\"close\", () => {\n this._connected = false;\n this._ws = null;\n // Their answers went with the socket.\n this._unanswered = 0;\n this._settled?.();\n if (!this._running) return;\n\n attempt += 1;\n const delay = Math.min(BASE_DELAY * Math.pow(2, attempt), MAX_DELAY);\n const jitter = Math.random() * JITTER_RANGE;\n const totalDelay = (delay + jitter) * 1000;\n\n this._reconnectTimeout = setTimeout(tryConnect, totalDelay);\n });\n\n ws.on(\"error\", (err: Error) => {\n // On first connect, reject the promise\n if (this._connectReject && !this._connected) {\n // Don't reject immediately; let 'close' handle retry\n }\n // Error will trigger close event\n });\n };\n\n tryConnect();\n }\n\n private _handleMessage(msg: Record<string, unknown>): void {\n const msgType = msg[\"type\"] as string | undefined;\n\n // First: an envelope's type and keys are the sender's to choose.\n if (\"uam_version\" in msg) {\n if (this._onMessage) {\n this._onMessage(msg).catch(() => {\n // Fire-and-forget callback errors\n });\n } else {\n this._pending.push(msg);\n }\n } else if (msgType === \"ping\") {\n // Respond to relay heartbeat\n if (this._ws && this._ws.readyState === WebSocket.OPEN) {\n this._ws.send(JSON.stringify({ type: \"pong\" }));\n }\n } else if (msgType === \"ack\") {\n this._answered();\n } else if (msgType === \"error\" || \"error\" in msg) {\n this._answered();\n }\n }\n}\n","/**\n * UAM SDK transport layer.\n */\n\nimport type { SDKConfig } from \"../config.js\";\nimport { TransportBase } from \"./base.js\";\nimport { HTTPTransport } from \"./http.js\";\nimport { WebSocketTransport } from \"./websocket.js\";\n\nexport { TransportBase } from \"./base.js\";\nexport { HTTPTransport } from \"./http.js\";\nexport { WebSocketTransport } from \"./websocket.js\";\n\n/**\n * Factory to create the appropriate transport based on config.\n */\nexport function createTransport(\n config: SDKConfig,\n token: string,\n address: string,\n onMessage?: (msg: Record<string, unknown>) => Promise<void>\n): TransportBase {\n if (config.transportType === \"http\") {\n return new HTTPTransport(config.relayUrl, token, address);\n } else {\n return new WebSocketTransport(config.relayWsUrl, token, onMessage);\n }\n}\n","/**\n * Replay protection for inbound envelopes.\n *\n * Used by Agent._processInbound to drop envelopes whose\n * (from address, message id) pair was already seen.\n *\n * PersistentReplayCache is what the Agent uses: a SQLite file under the\n * agent's data dir, shared by every process using that dir, that keeps each\n * pair for RETENTION_SECONDS. Stored mail can arrive days after it was\n * signed, so the window an envelope can be accepted in is longer than one\n * process lives.\n *\n * - Never evicts inside the window. Rows go only when they are older than\n * RETENTION_SECONDS. When the file holds `capacity` rows it fails closed:\n * an envelope signed within MAX_ENVELOPE_AGE is still accepted (and\n * deduplicated in memory); anything older is refused.\n * - Knows its age. created_at is written once, so a caller can refuse old\n * stored mail signed before the cache existed.\n *\n * EnvelopeReplayCache is the bounded in-memory cache it falls back on when\n * full: least-recently-used entries are evicted at capacity, and entries\n * older than the TTL are treated as new.\n *\n * Matches the Python SDK's sdk/replay_cache.py, and shares its file format:\n * times in the file are seconds since the epoch.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\n\nimport Database from \"better-sqlite3\";\n\nimport { MAX_ENVELOPE_AGE } from \"../protocol/types.js\";\nimport { STORED_MAIL_MAX_AGE } from \"./freshness.js\";\nimport { log } from \"./log.js\";\n\n/**\n * Seven days of stored mail, plus the freshness window on either side of the\n * signed timestamp (clock skew between sender, relay and recipient).\n */\nexport const RETENTION_SECONDS = STORED_MAIL_MAX_AGE + 2 * MAX_ENVELOPE_AGE;\n\n/** How often expired rows are purged, at most. */\nconst PURGE_INTERVAL_MS = 60_000;\n\nconst WAL_ATTEMPTS = 100;\nconst WAL_RETRY_MS = 100;\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS seen_envelopes (\n from_address TEXT NOT NULL,\n message_id TEXT NOT NULL,\n seen_at REAL NOT NULL,\n PRIMARY KEY (from_address, message_id)\n) WITHOUT ROWID;\nCREATE INDEX IF NOT EXISTS seen_envelopes_seen_at ON seen_envelopes (seen_at);\nCREATE TABLE IF NOT EXISTS replay_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n`;\n\nfunction isLocked(err: unknown): boolean {\n const code = (err as { code?: unknown }).code;\n return (\n typeof code === \"string\" &&\n (code.startsWith(\"SQLITE_BUSY\") || code.startsWith(\"SQLITE_LOCKED\"))\n );\n}\n\n/**\n * Switch `db` to WAL, waiting out another process doing the same.\n *\n * SQLite doesn't apply the busy timeout to this switch: two processes opening\n * a new file together get \"database is locked\" at once.\n */\nasync function enableWal(db: Database.Database): Promise<void> {\n for (let attempt = 1; ; attempt += 1) {\n try {\n db.pragma(\"journal_mode = WAL\");\n return;\n } catch (err) {\n if (attempt >= WAL_ATTEMPTS || !isLocked(err)) throw err;\n await sleep(WAL_RETRY_MS);\n }\n }\n}\n\nexport const DEFAULT_REPLAY_CACHE_CAPACITY = 1_000_000;\n\nexport class EnvelopeReplayCache {\n readonly capacity: number;\n readonly ttlMs: number;\n private readonly _now: () => number;\n // Map iteration order is insertion order: first key = least recently used.\n private readonly _seen = new Map<string, number>();\n\n constructor(options?: {\n capacity?: number;\n ttlMs?: number;\n now?: () => number;\n }) {\n const capacity = options?.capacity ?? 100_000;\n if (!Number.isInteger(capacity) || capacity < 1) {\n throw new RangeError(\n `Replay cache capacity must be a positive integer, got ${capacity}`\n );\n }\n this.capacity = capacity;\n this.ttlMs = options?.ttlMs ?? 300_000;\n this._now = options?.now ?? (() => Date.now());\n }\n\n get size(): number {\n return this._seen.size;\n }\n\n /** True if this pair was seen within the TTL. Records nothing. */\n has(fromAddress: string, messageId: string): boolean {\n const seenAt = this._seen.get(this._key(fromAddress, messageId));\n return seenAt !== undefined && this._now() - seenAt < this.ttlMs;\n }\n\n /**\n * Return true if this (fromAddress, messageId) pair was already seen\n * within the TTL (a replay). Otherwise record it and return false.\n */\n seenOrRecord(fromAddress: string, messageId: string): boolean {\n const key = this._key(fromAddress, messageId);\n const now = this._now();\n const seenAt = this._seen.get(key);\n if (seenAt !== undefined && now - seenAt < this.ttlMs) {\n // LRU touch: move to the most-recently-used end.\n this._seen.delete(key);\n this._seen.set(key, seenAt);\n return true;\n }\n this._seen.delete(key);\n this._seen.set(key, now);\n while (this._seen.size > this.capacity) {\n const oldest = this._seen.keys().next().value as string;\n this._seen.delete(oldest);\n }\n return false;\n }\n\n private _key(fromAddress: string, messageId: string): string {\n // JSON encoding keeps the two parts unambiguous whatever they contain.\n return JSON.stringify([fromAddress, messageId]);\n }\n}\n\n/**\n * Inbound (from address, message id) pairs kept in a SQLite file.\n *\n * Opens itself on first use, so an Agent driven without connect() still has\n * replay protection. Safe to share between processes: the insert is the\n * check (INSERT OR IGNORE), in WAL mode.\n */\nexport class PersistentReplayCache {\n readonly capacity: number;\n private readonly _path: string;\n private readonly _now: () => number;\n private _db: Database.Database | null = null;\n private _opening: Promise<Database.Database> | null = null;\n private _count = 0;\n private _lastPurge = 0;\n private _createdAt = 0;\n // Used only while the file is full, for envelopes inside MAX_ENVELOPE_AGE.\n // One can be signed that far ahead of us and stay acceptable until that far\n // behind, so its id must last both.\n private readonly _overflow: EnvelopeReplayCache;\n\n /**\n * @param path - The SQLite file\n * @param options.now - The clock, in ms since the epoch\n */\n constructor(\n path: string,\n options?: { capacity?: number; now?: () => number }\n ) {\n const capacity = options?.capacity ?? DEFAULT_REPLAY_CACHE_CAPACITY;\n if (!Number.isInteger(capacity) || capacity < 1) {\n throw new RangeError(\n `Replay cache capacity must be a positive integer, got ${capacity}`\n );\n }\n this.capacity = capacity;\n this._path = path;\n this._now = options?.now ?? (() => Date.now());\n this._overflow = new EnvelopeReplayCache({\n capacity: 10_000,\n ttlMs: 2 * MAX_ENVELOPE_AGE * 1000,\n now: this._now,\n });\n }\n\n /** Open the file now, rather than on first use. */\n async open(): Promise<void> {\n await this._open();\n }\n\n /**\n * Return true if the envelope must be dropped as a replay. Otherwise record\n * the pair and return false.\n *\n * @param signedAt - The envelope's signed time, in ms since the epoch. It\n * matters only when the cache is full.\n */\n async seenOrRecord(\n fromAddress: string,\n messageId: string,\n signedAt: number\n ): Promise<boolean> {\n const db = await this._open();\n const now = this._now();\n if (now - this._lastPurge >= PURGE_INTERVAL_MS) this._purge(db);\n\n // Accepted while the file was full, so it's only in memory.\n if (this._overflow.has(fromAddress, messageId)) return true;\n\n if (this._count < this.capacity) {\n const { changes } = db\n .prepare(\n \"INSERT OR IGNORE INTO seen_envelopes \" +\n \"(from_address, message_id, seen_at) VALUES (?, ?, ?)\"\n )\n .run(fromAddress, messageId, now / 1000);\n if (changes === 0) return true;\n this._count += 1;\n return false;\n }\n\n // Full: never evict inside the window. Known pairs are replays, fresh\n // envelopes are deduplicated in memory, older ones refused.\n const known = db\n .prepare(\n \"SELECT 1 FROM seen_envelopes WHERE from_address = ? AND message_id = ?\"\n )\n .get(fromAddress, messageId);\n if (known !== undefined) return true;\n\n if (Math.abs(now - signedAt) <= MAX_ENVELOPE_AGE * 1000) {\n return this._overflow.seenOrRecord(fromAddress, messageId);\n }\n log.warn(\n `Replay cache full (${this._count} ids); refused envelope ${messageId} ` +\n `from ${fromAddress} signed ${Math.round((now - signedAt) / 1000)}s ago`\n );\n return true;\n }\n\n /** When this cache file was first created, in ms since the epoch. */\n async createdAt(): Promise<number> {\n await this._open();\n return this._createdAt;\n }\n\n /** True if an envelope signed at `signedAt` (ms) predates this cache. */\n async signedBeforeCache(signedAt: number): Promise<boolean> {\n return signedAt < (await this.createdAt());\n }\n\n /** Number of ids currently held on disk. */\n async count(): Promise<number> {\n const db = await this._open();\n return this._countRows(db);\n }\n\n /** Close the file; the next call opens it again. */\n async close(): Promise<void> {\n await this._opening?.catch(() => undefined);\n this._db?.close();\n this._db = null;\n }\n\n private _open(): Promise<Database.Database> {\n if (this._db !== null) return Promise.resolve(this._db);\n this._opening ??= this._connect().finally(() => {\n this._opening = null;\n });\n return this._opening;\n }\n\n private async _connect(): Promise<Database.Database> {\n mkdirSync(dirname(this._path), { recursive: true });\n const db = new Database(this._path, { timeout: 30_000 });\n try {\n await enableWal(db);\n db.exec(SCHEMA);\n db.prepare(\n \"INSERT OR IGNORE INTO replay_meta (key, value) VALUES ('created_at', ?)\"\n ).run(String(this._now() / 1000));\n const row = db\n .prepare(\"SELECT value FROM replay_meta WHERE key = 'created_at'\")\n .get() as { value: string };\n this._createdAt = Number(row.value) * 1000;\n this._purge(db);\n } catch (err) {\n db.close();\n throw err;\n }\n this._db = db;\n return db;\n }\n\n private _purge(db: Database.Database): void {\n const now = this._now();\n db.prepare(\"DELETE FROM seen_envelopes WHERE seen_at < ?\").run(\n now / 1000 - RETENTION_SECONDS\n );\n this._count = this._countRows(db);\n this._lastPurge = now;\n }\n\n private _countRows(db: Database.Database): number {\n const row = db.prepare(\"SELECT COUNT(*) AS n FROM seen_envelopes\").get() as {\n n: number;\n };\n return row.n;\n }\n}\n","/**\n * Receiver-side webhook signature verification (HOOK-03).\n *\n * Small utility for webhook receivers to verify that incoming webhook\n * payloads were signed by the UAM relay. Uses HMAC-SHA256 with the\n * agent's webhook secret, which the relay returns when the webhook is set\n * (PUT /api/v1/agents/{address}/webhook). Setting the same URL again\n * returns it again.\n *\n * Matches Python webhook_verify.py API surface.\n *\n * Usage:\n *\n * import { verifyWebhookSignature } from \"@youam/sdk\";\n *\n * const payload = Buffer.from(requestBody);\n * const signature = request.headers[\"x-uam-signature\"];\n * const secret = \"your-webhook-secret\";\n *\n * if (verifyWebhookSignature(payload, signature, secret)) {\n * // payload is authentic\n * }\n */\n\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\n\n/**\n * Verify an HMAC-SHA256 webhook signature.\n *\n * @param payload - Raw request body bytes\n * @param signatureHeader - \"sha256=<hex>\" format (X-UAM-Signature header)\n * @param secret - The agent's webhook secret\n * @returns `true` if valid, `false` otherwise.\n *\n * Uses `crypto.timingSafeEqual()` for constant-time comparison\n * to prevent timing attacks.\n */\nexport function verifyWebhookSignature(\n payload: Buffer | Uint8Array,\n signatureHeader: string,\n secret: string\n): boolean {\n if (!signatureHeader.startsWith(\"sha256=\")) {\n return false;\n }\n\n const expected = createHmac(\"sha256\", secret)\n .update(payload)\n .digest(\"hex\");\n const received = signatureHeader.slice(\"sha256=\".length);\n\n // Constant-time comparison requires equal-length buffers\n const expectedBuf = Buffer.from(expected, \"utf-8\");\n const receivedBuf = Buffer.from(received, \"utf-8\");\n\n if (expectedBuf.length !== receivedBuf.length) {\n return false;\n }\n\n return timingSafeEqual(expectedBuf, receivedBuf);\n}\n","/**\n * UAM SDK -- the agent-facing API.\n */\n\nexport { Agent } from \"./agent.js\";\nexport type { ReceivedMessage } from \"./message.js\";\nexport { SDKConfig } from \"./config.js\";\nexport { KeyManager } from \"./key-manager.js\";\nexport { ContactBook } from \"./contact-book.js\";\nexport { HandshakeManager, bindCardToEnvelope } from \"./handshake.js\";\nexport { EnvelopeReplayCache, PersistentReplayCache } from \"./replay-cache.js\";\nexport { RELAY_META_FEATURE, STORED_MAIL_MAX_AGE, relayVouches } from \"./freshness.js\";\nexport { AddressResolver, SmartResolver, Tier1Resolver, Tier2Resolver, Tier3Resolver, type Tier3Config } from \"./resolver.js\";\nexport { TransportBase, HTTPTransport, WebSocketTransport, createTransport } from \"./transport/index.js\";\nexport { verifyWebhookSignature } from \"./webhook-verify.js\";\nexport { parseUamTxt, extractPublicKey, queryUamTxt, resolveKeyViaHttps, generateTxtRecord } from \"./dns-verifier.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBO,SAAS,YAAY,UAA0C;AACpE,QAAM,OAA+B,CAAC;AACtC,aAAW,QAAQ,SAAS,MAAM,GAAG,GAAG;AACtC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,UAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,QAAI,UAAU,IAAI;AAChB,YAAM,MAAM,QAAQ,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE,YAAY;AACvD,YAAM,QAAQ,QAAQ,MAAM,QAAQ,CAAC,EAAE,KAAK;AAC5C,WAAK,GAAG,IAAI;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAQO,SAAS,iBACd,MACe;AACf,QAAM,WAAW,KAAK,KAAK,KAAK;AAChC,MAAI,SAAS,WAAW,UAAU,GAAG;AACnC,WAAO,SAAS,MAAM,WAAW,MAAM;AAAA,EACzC;AACA,SAAO;AACT;AASA,eAAsB,YACpB,QACA,SACmB;AAGnB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QACJ,WAAW,OACP,WAAW,MAAM,WAAW,MAAM,GAAG,OAAO,IAC5C;AAEN,MAAI;AACF,UAAM,UAAU,UAAM,gBAAAA,YAAc,QAAQ,MAAM,EAAE;AAIpD,UAAM,UAAoB,CAAC;AAC3B,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,MAAM,KAAK,EAAE;AAC9B,UAAI,SAAS,KAAK,EAAE,WAAW,QAAQ,GAAG;AACxC,gBAAQ,KAAK,QAAQ;AAAA,MACvB;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO,CAAC;AAAA,EACV,UAAE;AACA,QAAI,SAAS,KAAM,cAAa,KAAK;AAAA,EACvC;AACF;AAQA,eAAsB,mBACpB,WACA,QACA,SACwB;AACxB,QAAM,MAAM,WAAW,MAAM;AAE7B,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,KAAK;AAAA,MAC5B,QAAQ,YAAY,QAAQ,WAAW,GAAK;AAAA,IAC9C,CAAC;AACD,QAAI,CAAC,KAAK,GAAI,QAAO;AAErB,UAAM,OAAQ,MAAM,KAAK,KAAK;AAC9B,QAAI,KAAK,GAAG,MAAM,OAAQ,QAAO;AAEjC,UAAM,SAAU,KAAK,QAAQ,KAAK,CAAC;AAInC,UAAM,QAAQ,OAAO,SAAS;AAC9B,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,WAAY,MAAM,KAAK,KAAgB;AAC3C,QAAI,SAAS,WAAW,UAAU,GAAG;AACnC,iBAAW,SAAS,MAAM,WAAW,MAAM;AAAA,IAC7C;AACA,WAAO,YAAY;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAQO,SAAS,kBACd,WACA,UACQ;AACR,SAAO,uBAAuB,SAAS,WAAW,QAAQ;AAC5D;AAhJA,IAaA;AAbA;AAAA;AAAA;AAaA,sBAA4C;AAAA;AAAA;;;ACb5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,IAAAC,oBAAqB;;;ACTrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACKO,IAAM,cAAc;AAGpB,IAAM,oBAAoB;AAO1B,IAAM,mBAAmB;AAGzB,IAAK,cAAL,kBAAKC,iBAAL;AACL,EAAAA,aAAA,aAAU;AACV,EAAAA,aAAA,uBAAoB;AACpB,EAAAA,aAAA,sBAAmB;AACnB,EAAAA,aAAA,oBAAiB;AACjB,EAAAA,aAAA,uBAAoB;AACpB,EAAAA,aAAA,kBAAe;AACf,EAAAA,aAAA,oBAAiB;AACjB,EAAAA,aAAA,qBAAkB;AAClB,EAAAA,aAAA,oBAAiB;AACjB,EAAAA,aAAA,qBAAkB;AAClB,EAAAA,aAAA,iBAAc;AAXJ,SAAAA;AAAA,GAAA;AAiBL,SAAS,UAAU,MAA0B;AAClD,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,WAAW;AAC/C;AAKO,SAAS,UAAU,GAAuB;AAC/C,SAAO,IAAI,WAAW,OAAO,KAAK,GAAG,WAAW,CAAC;AACnD;AAKO,SAAS,eAAuB;AACrC,UAAO,oBAAI,KAAK,GAAE,YAAY;AAChC;;;AC5CO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;AAGO,IAAM,sBAAN,cAAkC,SAAS;AAAA,EAChD,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,uBAAN,cAAmC,SAAS;AAAA,EACjD,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,wBAAN,cAAoC,qBAAqB;AAAA,EAC9D,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAC3C,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,6BAAN,cAAyC,eAAe;AAAA,EAC7D,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EAC5C,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,kBAAN,cAA8B,gBAAgB;AAAA,EACnD,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,0BAAN,cAAsC,SAAS;AAAA,EACpD,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,kBAAN,MAAM,yBAAwB,SAAS;AAAA,EAC5C,YAAY,SAAkB;AAC5B,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,WAAO,eAAe,MAAM,iBAAgB,SAAS;AAAA,EACvD;AACF;;;AClEA,IAAM,aACJ;AAEF,IAAM,gBAAgB;AACtB,IAAM,kBAAkB;AAUjB,SAAS,aAAa,KAAsB;AACjD,QAAM,aAAa,IAAI,KAAK,EAAE,YAAY;AAC1C,MAAI,WAAW,SAAS,iBAAiB;AACvC,UAAM,IAAI;AAAA,MACR,mBAAmB,eAAe,gBAAgB,KAAK,UAAU,GAAG,CAAC;AAAA,IACvE;AAAA,EACF;AACA,QAAM,IAAI,WAAW,KAAK,UAAU;AACpC,MAAI,CAAC,KAAK,CAAC,EAAE,QAAQ;AACnB,UAAM,IAAI;AAAA,MACR,wBAAwB,KAAK,UAAU,GAAG,CAAC;AAAA,IAC7C;AAAA,EACF;AACA,QAAM,QAAQ,EAAE,OAAO;AACvB,MAAI,MAAM,SAAS,eAAe;AAChC,UAAM,IAAI;AAAA,MACR,sBAAsB,aAAa,gBAAgB,KAAK,UAAU,GAAG,CAAC;AAAA,IACxE;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,EAAE,OAAO;AAAA,IACjB,IAAI,OAAO;AACT,aAAO,GAAG,KAAK,KAAK,KAAK,KAAK,MAAM;AAAA,IACtC;AAAA,EACF;AACF;;;ACnDA,gCAAmB;AACnB,yBAA2B;AAiBpB,IAAM,cAA6B,0BAAAC,QAAO;AA4B1C,SAAS,kBAA2B;AACzC,QAAM,OAAO,0BAAAA,QAAO,gBAAgB,EAAE;AACtC,QAAM,KAAK,0BAAAA,QAAO,yBAAyB,IAAI;AAC/C,SAAO;AAAA,IACL,YAAY,GAAG;AAAA,IACf,WAAW,GAAG;AAAA,IACd;AAAA,EACF;AACF;AAOO,SAAS,oBAAoB,MAA0B;AAC5D,SAAO,UAAU,IAAI;AACvB;AAKO,SAAS,sBAAsB,GAAoB;AACxD,QAAM,OAAO,UAAU,CAAC;AACxB,QAAM,KAAK,0BAAAA,QAAO,yBAAyB,IAAI;AAC/C,SAAO;AAAA,IACL,YAAY,GAAG;AAAA,IACf,WAAW,GAAG;AAAA,IACd;AAAA,EACF;AACF;AAKO,SAAS,mBAAmB,KAAyB;AAC1D,SAAO,UAAU,GAAG;AACtB;AAKO,SAAS,qBAAqB,GAAuB;AAC1D,SAAO,UAAU,CAAC;AACpB;AAOO,SAAS,qBAAqB,WAA+B;AAClE,aAAO,+BAAW,QAAQ,EAAE,OAAO,OAAO,KAAK,SAAS,CAAC,EAAE,OAAO,KAAK;AACzE;AAWA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AAC3D,WAAO,OAAO,KAAK;AAAA,EACrB;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,UAAM,QAAQ,MAAM,IAAI,CAAC,MAAM,gBAAgB,CAAC,CAAC;AACjD,WAAO,MAAM,MAAM,KAAK,GAAG,IAAI;AAAA,EACjC;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,MAAM;AACZ,UAAM,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK;AACnC,UAAM,QAAQ,KAAK,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI,MAAM,gBAAgB,IAAI,CAAC,CAAC,CAAC;AAC/E,WAAO,MAAM,MAAM,KAAK,GAAG,IAAI;AAAA,EACjC;AACA,SAAO,OAAO,KAAK;AACrB;AASO,SAAS,aAAa,MAA2C;AACtE,QAAM,WAAoC,CAAC;AAC3C,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,GAAG;AACzC,QAAI,MAAM,eAAe,MAAM,QAAQ,MAAM,QAAW;AACtD,eAAS,CAAC,IAAI;AAAA,IAChB;AAAA,EACF;AACA,QAAM,OAAO,gBAAgB,QAAQ;AACrC,SAAO,IAAI,YAAY,EAAE,OAAO,IAAI;AACtC;AAWO,SAAS,YAAY,MAAkB,YAAgC;AAC5E,QAAM,YAAY,0BAAAA,QAAO,qBAAqB,MAAM,UAAU;AAC9D,SAAO,UAAU,SAAS;AAC5B;AAOO,SAAS,gBACd,MACA,cACA,WACM;AACN,MAAI;AACF,UAAM,WAAW,UAAU,YAAY;AACvC,UAAM,QAAQ,0BAAAA,QAAO,4BAA4B,UAAU,MAAM,SAAS;AAC1E,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,2BAA2B,+BAA+B;AAAA,IACtE;AAAA,EACF,SAAS,KAAK;AACZ,QAAI,eAAe,4BAA4B;AAC7C,YAAM;AAAA,IACR;AACA,UAAM,IAAI;AAAA,MACR,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACjD;AAAA,EACF;AACF;AASO,SAAS,gBAAwB;AACtC,SAAO,UAAU,0BAAAA,QAAO,gBAAgB,EAAE,CAAC;AAC7C;AAeO,SAAS,eACd,WACA,kBACA,oBACQ;AACR,MAAI;AACF,UAAM,cAAc,0BAAAA,QAAO,qCAAqC,gBAAgB;AAChF,UAAM,iBAAiB,0BAAAA,QAAO,qCAAqC,kBAAkB;AACrF,UAAM,QAAQ,0BAAAA,QAAO,gBAAgB,0BAAAA,QAAO,qBAAqB;AACjE,UAAM,YAAY,0BAAAA,QAAO,gBAAgB,WAAW,OAAO,gBAAgB,WAAW;AAEtF,UAAM,WAAW,IAAI,WAAW,MAAM,SAAS,UAAU,MAAM;AAC/D,aAAS,IAAI,OAAO,CAAC;AACrB,aAAS,IAAI,WAAW,MAAM,MAAM;AACpC,WAAO,UAAU,QAAQ;AAAA,EAC3B,SAAS,KAAK;AACZ,QAAI,eAAe,gBAAiB,OAAM;AAC1C,UAAM,IAAI,gBAAgB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EAC5E;AACF;AAQO,SAAS,eACd,eACA,qBACA,iBACY;AACZ,MAAI;AACF,UAAM,WAAW,UAAU,aAAa;AACxC,UAAM,QAAQ,SAAS,MAAM,GAAG,0BAAAA,QAAO,qBAAqB;AAC5D,UAAM,aAAa,SAAS,MAAM,0BAAAA,QAAO,qBAAqB;AAC9D,UAAM,iBAAiB,0BAAAA,QAAO,qCAAqC,mBAAmB;AACtF,UAAM,cAAc,0BAAAA,QAAO,qCAAqC,eAAe;AAC/E,WAAO,0BAAAA,QAAO,qBAAqB,YAAY,OAAO,aAAa,cAAc;AAAA,EACnF,SAAS,KAAK;AACZ,QAAI,eAAe,gBAAiB,OAAM;AAC1C,UAAM,IAAI,gBAAgB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EAC5E;AACF;AAaO,SAAS,wBACd,WACA,oBACQ;AACR,QAAM,iBAAiB,0BAAAA,QAAO,qCAAqC,kBAAkB;AACrF,QAAM,aAAa,0BAAAA,QAAO,gBAAgB,WAAW,cAAc;AACnE,SAAO,UAAU,UAAU;AAC7B;AAQO,SAAS,wBACd,eACA,qBACY;AACZ,MAAI;AACF,UAAM,aAAa,UAAU,aAAa;AAC1C,UAAM,mBAAmB,0BAAAA,QAAO,qCAAqC,mBAAmB;AAExF,UAAM,qBAAqB,oBAAoB,MAAM,EAAE;AACvD,UAAM,mBAAmB,0BAAAA,QAAO,qCAAqC,kBAAkB;AACvF,WAAO,0BAAAA,QAAO,qBAAqB,YAAY,kBAAkB,gBAAgB;AAAA,EACnF,SAAS,KAAK;AACZ,QAAI,eAAe,gBAAiB,OAAM;AAC1C,UAAM,IAAI,gBAAgB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,EAC5E;AACF;;;AC9SA,IAAAC,sBAA2B;AAiB3B,IAAM,uBAAuB,oBAAI,IAAI;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAkCD,SAAS,kBACP,UACyB;AACzB,QAAM,IAA6B;AAAA,IACjC,aAAa,SAAS;AAAA,IACtB,YAAY,SAAS;AAAA,IACrB,MAAM,SAAS;AAAA,IACf,IAAI,SAAS;AAAA,IACb,WAAW,SAAS;AAAA,IACpB,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,SAAS,SAAS;AAAA,EACpB;AACA,MAAI,SAAS,aAAa,OAAW,GAAE,WAAW,IAAI,SAAS;AAC/D,MAAI,SAAS,YAAY,OAAW,GAAE,UAAU,IAAI,SAAS;AAC7D,MAAI,SAAS,YAAY,OAAW,GAAE,SAAS,IAAI,SAAS;AAC5D,MAAI,SAAS,cAAc,OAAW,GAAE,YAAY,IAAI,SAAS;AACjE,MAAI,SAAS,aAAa,OAAW,GAAE,UAAU,IAAI,SAAS;AAC9D,SAAO;AACT;AAQO,SAAS,WACd,UACyB;AACzB,QAAM,IAAI,kBAAkB,QAAQ;AACpC,IAAE,WAAW,IAAI,SAAS;AAC1B,MAAI,SAAS,gBAAgB,QAAW;AACtC,MAAE,aAAa,IAAI,SAAS;AAAA,EAC9B;AACA,SAAO;AACT;AAOO,SAAS,aACd,GACiB;AACjB,QAAM,OAAO,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC;AACnC,QAAM,UAAoB,CAAC;AAC3B,aAAW,SAAS,sBAAsB;AACxC,QAAI,CAAC,KAAK,IAAI,KAAK,EAAG,SAAQ,KAAK,KAAK;AAAA,EAC1C;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,KAAK;AACb,UAAM,IAAI;AAAA,MACR,4BAA4B,KAAK,UAAU,OAAO,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,SAAO,OAAO,OAAO;AAAA,IACnB,YAAY,EAAE,aAAa;AAAA,IAC3B,WAAW,EAAE,YAAY;AAAA,IACzB,aAAa,EAAE,MAAM;AAAA,IACrB,WAAW,EAAE,IAAI;AAAA,IACjB,WAAW,EAAE,WAAW;AAAA,IACxB,MAAM,EAAE,MAAM;AAAA,IACd,OAAO,EAAE,OAAO;AAAA,IAChB,SAAS,EAAE,SAAS;AAAA,IACpB,WAAW,EAAE,WAAW;AAAA,IACxB,UAAU,EAAE,WAAW;AAAA,IACvB,SAAS,EAAE,UAAU;AAAA,IACrB,SAAS,EAAE,SAAS;AAAA,IACpB,WAAW,EAAE,YAAY;AAAA,IACzB,UAAU,EAAE,UAAU;AAAA,IACtB,aAAa,EAAE,aAAa;AAAA,EAC9B,CAAC;AACH;AAOO,SAAS,qBAAqB,UAAiC;AACpE,QAAM,OAAO,WAAW,QAAQ;AAChC,QAAM,OAAO,KAAK,UAAU,IAAI;AAChC,QAAM,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI,EAAE;AAC5C,MAAI,OAAO,mBAAmB;AAC5B,UAAM,IAAI;AAAA,MACR,iBAAiB,IAAI,0BAA0B,iBAAiB;AAAA,IAClE;AAAA,EACF;AACF;AAQA,eAAsB,eACpB,aACA,WACA,aACA,kBACA,YACA,oBACA,SAQ0B;AAE1B,QAAM,YACJ,OAAO,gBAAgB,WACnB,cACC;AAGP,eAAa,WAAW;AACxB,eAAa,SAAS;AAGtB,QAAM,gBAAY,gCAAW;AAC7B,QAAM,QAAQ,cAAc;AAC5B,QAAM,YAAY,aAAa;AAG/B,MAAI;AACJ,MAAI,2DAA6C;AAC/C,uBAAmB,wBAAwB,kBAAkB,kBAAkB;AAAA,EACjF,OAAO;AACL,uBAAmB;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAgC;AAAA,IACpC,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,SAAS;AAAA,IACT,WAAW;AAAA,IACX,UAAU,SAAS;AAAA,IACnB,SAAS,SAAS;AAAA,IAClB,SAAS,SAAS;AAAA,IAClB,WAAW,SAAS;AAAA,IACpB,UAAU,SAAS;AAAA,IACnB,aAAa,SAAS;AAAA,EACxB;AAGA,QAAM,WAAW,kBAAkB,YAAY;AAC/C,QAAM,YAAY,YAAY,aAAa,QAAQ,GAAG,UAAU;AAGhE,QAAM,gBAAiC,OAAO,OAAO;AAAA,IACnD,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA,UAAU,SAAS;AAAA,IACnB,SAAS,SAAS;AAAA,IAClB,SAAS,SAAS;AAAA,IAClB,WAAW,SAAS;AAAA,IACpB,UAAU,SAAS;AAAA,IACnB,aAAa,SAAS;AAAA,EACxB,CAAC;AAGD,uBAAqB,aAAa;AAElC,SAAO;AACT;AAOO,SAAS,eACd,UACA,iBACM;AACN,QAAM,WAAW,kBAAkB,QAAQ;AAC3C,kBAAgB,aAAa,QAAQ,GAAG,SAAS,WAAW,eAAe;AAC7E;;;AChOA,SAASC,mBAAkB,MAA4C;AACrE,QAAM,IAA6B;AAAA,IACjC,SAAS,KAAK;AAAA,IACd,SAAS,KAAK;AAAA,IACd,cAAc,KAAK;AAAA,IACnB,OAAO,KAAK;AAAA,IACZ,YAAY,KAAK;AAAA,EACnB;AACA,MAAI,KAAK,gBAAgB,OAAW,GAAE,aAAa,IAAI,KAAK;AAC5D,MAAI,KAAK,WAAW,OAAW,GAAE,QAAQ,IAAI,KAAK;AAClD,MAAI,KAAK,uBAAuB,QAAW;AACzC,MAAE,qBAAqB,IAAI,KAAK;AAAA,EAClC;AACA,MAAI,KAAK,mBAAmB,QAAW;AACrC,MAAE,iBAAiB,IAAI,KAAK;AAAA,EAC9B;AACA,SAAO;AACT;AAOO,SAAS,kBACd,MACyB;AACzB,QAAM,IAAIA,mBAAkB,IAAI;AAChC,IAAE,WAAW,IAAI,KAAK;AACtB,MAAI,KAAK,mBAAmB,QAAW;AACrC,MAAE,iBAAiB,IAAI,KAAK;AAAA,EAC9B;AACA,MAAI,KAAK,gBAAgB,QAAW;AAClC,MAAE,aAAa,IAAI,KAAK;AAAA,EAC1B;AACA,MAAI,KAAK,WAAW,QAAW;AAC7B,MAAE,QAAQ,IAAI,KAAK;AAAA,EACrB;AACA,SAAO;AACT;AAWO,SAAS,oBACd,GACA,SACa;AACb,QAAM,SAAS,SAAS,UAAU;AAElC,QAAM,WAAW,oBAAI,IAAI;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,OAAO,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC;AACnC,QAAM,UAAoB,CAAC;AAC3B,aAAW,SAAS,UAAU;AAC5B,QAAI,CAAC,KAAK,IAAI,KAAK,EAAG,SAAQ,KAAK,KAAK;AAAA,EAC1C;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,YAAQ,KAAK;AACb,UAAM,IAAI;AAAA,MACR,4BAA4B,KAAK,UAAU,OAAO,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,QAAM,OAAoB,OAAO,OAAO;AAAA,IACtC,SAAS,EAAE,SAAS;AAAA,IACpB,SAAS,EAAE,SAAS;AAAA,IACpB,aAAa,EAAE,cAAc;AAAA,IAC7B,aAAa,EAAE,aAAa;AAAA,IAC5B,QAAQ,EAAE,QAAQ;AAAA,IAClB,oBAAoB,EAAE,qBAAqB;AAAA,IAC3C,OAAO,EAAE,OAAO;AAAA,IAChB,WAAW,EAAE,YAAY;AAAA,IACzB,WAAW,EAAE,WAAW;AAAA,IACxB,gBAAgB,EAAE,iBAAiB;AAAA,IACnC,gBAAgB,EAAE,iBAAiB;AAAA,IACnC,aAAa,EAAE,aAAa;AAAA,IAC5B,QAAQ,EAAE,QAAQ;AAAA,EACpB,CAAC;AAED,MAAI,QAAQ;AACV,sBAAkB,IAAI;AAAA,EACxB;AAEA,SAAO;AACT;AAWA,eAAsB,kBACpB,SACA,aACA,OACA,YACA,SAQsB;AAEtB,eAAa,OAAO;AAIpB,QAAM,YAAY,WAAW,MAAM,EAAE;AACrC,QAAM,YAAY,mBAAmB,SAAS;AAC9C,QAAM,KAAK,qBAAqB,SAAS;AAGzC,QAAM,iBAAiB,SAAS,kBAAkB;AAAA,IAChD;AAAA,IACA;AAAA,EACF;AAGA,QAAM,WAAwB;AAAA,IAC5B,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,aAAa,SAAS;AAAA,IACtB,QAAQ,SAAS;AAAA,IACjB,oBAAoB,SAAS;AAAA,IAC7B;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,aAAa;AAAA,IACb,QAAQ,SAAS;AAAA,EACnB;AAGA,QAAM,WAAWA,mBAAkB,QAAQ;AAC3C,QAAM,YAAY,YAAY,aAAa,QAAQ,GAAG,UAAU;AAGhE,SAAO,OAAO,OAAO;AAAA,IACnB,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,aAAa,SAAS;AAAA,IACtB,QAAQ,SAAS;AAAA,IACjB,oBAAoB,SAAS;AAAA,IAC7B;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,aAAa;AAAA,IACb,QAAQ,SAAS;AAAA,EACnB,CAAC;AACH;AAQO,SAAS,kBAAkB,MAAyB;AAEzD,MAAI;AACF,iBAAa,KAAK,OAAO;AAAA,EAC3B,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,oCAAoC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACtF;AAAA,EACF;AAGA,QAAM,KAAK,qBAAqB,KAAK,SAAS;AAG9C,QAAM,WAAWA,mBAAkB,IAAI;AACvC,kBAAgB,aAAa,QAAQ,GAAG,KAAK,WAAW,EAAE;AAC5D;;;AC1OO,IAAM,cAAsB;;;ACHnC,qBAAwB;AACxB,uBAAqB;AAErB,IAAM,oBAAoB;AAGnB,SAAS,aAAa,KAAqB;AAChD,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAEA,IAAM,iBAAiB,oBAAI,IAAI;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,YAAN,MAAgB;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACT;AAAA;AAAA,EAES;AAAA,EAET,YAAY,SAUT;AACD,SAAK,OAAO,QAAQ;AAGpB,SAAK,WAAW;AAAA,MACd,QAAQ,YAAY,QAAQ,IAAI,eAAe,KAAK;AAAA,IACtD;AAGA,QAAI,QAAQ,YAAY;AACtB,WAAK,aAAa,QAAQ;AAAA,IAC5B,OAAO;AACL,UAAI,QAAQ,KAAK,SACd,QAAQ,YAAY,QAAQ,EAC5B,QAAQ,WAAW,OAAO;AAC7B,UAAI,CAAC,MAAM,SAAS,KAAK,GAAG;AAC1B,gBAAQ,MAAM,QAAQ,QAAQ,EAAE,IAAI;AAAA,MACtC;AACA,WAAK,aAAa;AAAA,IACpB;AAGA,UAAM,YAAY,QAAQ,IAAI,kBAAkB;AAChD,SAAK,sBAAsB,aAAa,QAAQ,eAAe;AAC/D,QAAI,WAAW;AACb,WAAK,cAAc;AAAA,IACrB,WAAW,QAAQ,aAAa;AAC9B,WAAK,cAAc,QAAQ;AAAA,IAC7B,OAAO;AAEL,UAAI;AACF,cAAM,SAAS,IAAI,IAAI,KAAK,QAAQ;AACpC,aAAK,cAAc,OAAO,YAAY;AAAA,MACxC,QAAQ;AAEN,cAAM,cAAc,KAAK,SAAS,MAAM,KAAK,EAAE,IAAI,KAAK;AACxD,aAAK,cAAc,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK;AAAA,MAClD;AAAA,IACF;AAIA,UAAM,UAAU,QAAQ,IAAI,UAAU;AACtC,UAAM,cAAc,eAAW,2BAAK,wBAAQ,GAAG,MAAM;AAErD,SAAK,SAAS,QAAQ,cAAU,uBAAK,aAAa,MAAM;AACxD,SAAK,UAAU,QAAQ,WAAW;AAGlC,SAAK,cAAc,QAAQ,eAAe,KAAK;AAG/C,SAAK,gBAAgB,QAAQ,iBAAiB;AAG9C,QAAI,SAAS,QAAQ,eAAe;AACpC,UAAM,YAAY,QAAQ,IAAI,kBAAkB;AAChD,QAAI,WAAW;AACb,eAAS;AAAA,IACX;AAEA,QAAI,CAAC,eAAe,IAAI,MAAM,GAAG;AAC/B,YAAM,IAAI;AAAA,QACR,yBAAyB,MAAM,sBACV,KAAK,UAAU,CAAC,GAAG,cAAc,EAAE,KAAK,CAAC,CAAC;AAAA,MACjE;AAAA,IACF;AAEA,SAAK,cAAc;AAAA,EACrB;AACF;;;ACxGO,IAAM,qBAAqB;AAG3B,IAAM,sBAAsB,IAAI;AAIvC,IAAM,WACJ;AAWK,SAAS,aACd,KACA,UACA,KACA,aACS;AACT,QAAM,OAAO,IAAI,YAAY;AAC7B,MAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACpE,WAAO;AAAA,EACT;AACA,QAAM,QAAQ;AACd,MAAI,MAAM,GAAG,MAAM,KAAK,MAAM,OAAO,MAAM,YAAa,QAAO;AAC/D,MAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AAErC,QAAM,WAAW,MAAM,aAAa;AACpC,MAAI,OAAO,aAAa,YAAY,CAAC,SAAS,KAAK,QAAQ,EAAG,QAAO;AACrE,QAAM,aAAa,KAAK,MAAM,QAAQ;AACtC,MAAI,OAAO,MAAM,UAAU,EAAG,QAAO;AAErC,QAAM,SAAS,mBAAmB;AAClC,QAAM,MAAM,MAAM;AAClB,SACE,KAAK,IAAI,aAAa,QAAQ,KAAK,UACnC,OAAO,KACP,OAAO,sBAAsB,MAAO;AAExC;;;ACnDA,qBAMO;AACP,IAAAC,kBAA2B;AAC3B,IAAAC,oBAAqB;AACrB,IAAAC,kBAAwB;AACxB,IAAAA,kBAAyB;AAezB,IAAM,sBAAkB,4BAAK,yBAAQ,GAAG,QAAQ,MAAM;AAE/C,IAAM,aAAN,MAAiB;AAAA,EACd;AAAA,EACA,WAA2B;AAAA,EAEnC,YAAY,QAAwB;AAClC,SAAK,UAAU,UAAU;AAAA,EAC3B;AAAA;AAAA,EAGA,IAAI,aAAyB;AAC3B,QAAI,KAAK,aAAa,MAAM;AAC1B,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AACA,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,YAAuB;AACzB,QAAI,KAAK,aAAa,MAAM;AAC1B,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AACA,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,OAAa;AACf,QAAI,KAAK,aAAa,MAAM;AAC1B,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AACA,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAAe,MAAoB;AAEjC,UAAM,SAAS,QAAQ,IAAI,iBAAiB;AAC5C,QAAI,QAAQ;AACV,WAAK,WAAW,sBAAsB,OAAO,KAAK,CAAC;AACnD;AAAA,IACF;AAGA,kCAAU,KAAK,SAAS,EAAE,WAAW,KAAK,CAAC;AAC3C,UAAM,cAAU,wBAAK,KAAK,SAAS,GAAG,IAAI,MAAM;AAChD,UAAM,cAAU,wBAAK,KAAK,SAAS,GAAG,IAAI,MAAM;AAEhD,YAAI,4BAAW,OAAO,GAAG;AAEvB,WAAK,kBAAkB,OAAO;AAC9B,YAAM,cAAU,6BAAa,SAAS,OAAO,EAAE,KAAK;AACpD,WAAK,WAAW,sBAAsB,OAAO;AAAA,IAC/C,OAAO;AAEL,WAAK,WAAW,gBAAgB;AAChC,wCAAc,SAAS,oBAAoB,KAAK,SAAS,IAAI,CAAC;AAC9D,wCAAc,SAAS,mBAAmB,KAAK,SAAS,SAAS,CAAC;AAClE,WAAK,gBAAgB,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAc,OAAqB;AAC3C,kCAAU,KAAK,SAAS,EAAE,WAAW,KAAK,CAAC;AAC3C,UAAM,gBAAY,wBAAK,KAAK,SAAS,GAAG,IAAI,QAAQ;AACpD,sCAAc,WAAW,KAAK;AAC9B,SAAK,gBAAgB,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,MAAc,SAAiB,UAAwB;AACjE,kCAAU,KAAK,SAAS,EAAE,WAAW,KAAK,CAAC;AAC3C;AAAA,UACE,wBAAK,KAAK,SAAS,GAAG,IAAI,UAAU;AAAA,MACpC,KAAK,UAAU,EAAE,SAAS,WAAW,SAAS,CAAC;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,MAAc,UAAiC;AACzD,QAAI;AACF,YAAM,WAAO,wBAAK,KAAK,SAAS,GAAG,IAAI,UAAU;AACjD,YAAM,QAAQ,KAAK,UAAM,6BAAa,MAAM,OAAO,CAAC;AAIpD,YAAM,UAAU,OAAO;AACvB,YAAM,aAAa,OAAO;AAC1B,UAAI,OAAO,YAAY,YAAY,OAAO,eAAe,UAAU;AACjE,eAAO;AAAA,MACT;AACA,UAAI,aAAa,UAAU,MAAM,aAAa,QAAQ,EAAG,QAAO;AAChE,mBAAa,OAAO;AACpB,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU,MAAc,UAAkC;AAExD,UAAM,WAAW,QAAQ,IAAI,WAAW;AACxC,QAAI,UAAU;AACZ,aAAO,SAAS,KAAK;AAAA,IACvB;AAEA,QAAI,aAAa,UAAa,KAAK,sBAAsB,MAAM,QAAQ,GAAG;AACxE,aAAO;AAAA,IACT;AAGA,UAAM,gBAAY,wBAAK,KAAK,SAAS,GAAG,IAAI,QAAQ;AACpD,YAAI,4BAAW,SAAS,GAAG;AACzB,iBAAO,6BAAa,WAAW,OAAO,EAAE,KAAK;AAAA,IAC/C;AAEA,UAAM,iBAAa,wBAAK,KAAK,SAAS,GAAG,IAAI,UAAU;AACvD,YAAI,4BAAW,UAAU,GAAG;AAC1B,iBAAO,6BAAa,YAAY,OAAO,EAAE,KAAK;AAAA,IAChD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,sBAAsB,MAAc,UAA2B;AACrE,QAAI;AACF,YAAM,WAAO,wBAAK,KAAK,SAAS,GAAG,IAAI,UAAU;AACjD,YAAM,QAAQ,KAAK,UAAM,6BAAa,MAAM,OAAO,CAAC;AAGpD,YAAM,aAAa,OAAO;AAC1B,aACE,OAAO,eAAe,YACtB,aAAa,UAAU,MAAM,aAAa,QAAQ;AAAA,IAEtD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGQ,gBAAgB,MAAoB;AAC1C,YAAI,0BAAS,MAAM,SAAS;AAC1B,oCAAU,MAAM,GAAK;AAAA,IACvB;AAAA,EACF;AAAA;AAAA,EAGQ,kBAAkB,MAAoB;AAC5C,YAAI,0BAAS,MAAM,SAAS;AAC1B;AAAA,IACF;AACA,QAAI;AACF,YAAM,WAAO,yBAAS,IAAI,EAAE,OAAO;AACnC,UAAI,SAAS,KAAO;AAClB,gBAAQ;AAAA,UACN,YAAY,IAAI,oBAAoB,KAAK,SAAS,CAAC,CAAC,mCAChC,IAAI;AAAA,QAC1B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;ACtNA,IAAAC,kBAA0B;AAC1B,IAAAC,oBAA8B;AAC9B,4BAAqB;;;ACJd,IAAM,MAAM;AAAA,EACjB,KAAK,SAAuB;AAC1B,YAAQ,KAAK,SAAS,OAAO,EAAE;AAAA,EACjC;AAAA,EACA,KAAK,SAAuB;AAC1B,QAAI,QAAQ,IAAI,WAAW,GAAG;AAC5B,cAAQ,KAAK,SAAS,OAAO,EAAE;AAAA,IACjC;AAAA,EACF;AACF;;;AD2BO,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA,MAAgC;AAAA,EAChC,kBAA+B,oBAAI,IAAI;AAAA,EACvC,gBAA6B,oBAAI,IAAI;AAAA,EACrC,kBAA+B,oBAAI,IAAI;AAAA,EAE/C,YAAY,SAAiB;AAC3B,SAAK,cAAU,wBAAK,SAAS,YAAY,aAAa;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,uCAAU,2BAAQ,KAAK,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD,SAAK,MAAM,IAAI,sBAAAC,QAAS,KAAK,OAAO;AACpC,SAAK,IAAI,OAAO,oBAAoB;AAGpC,SAAK,IAAI,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAwBb;AAGD,SAAK,SAAS;AAGd,UAAM,OAAO,KAAK,IACf,QAAQ,8BAA8B,EACtC,IAAI;AACP,SAAK,kBAAkB,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAGzD,SAAK,cAAc,MAAM;AACzB,SAAK,gBAAgB,MAAM;AAC3B,UAAM,UAAU,KAAK,IAClB,QAAQ,sCAAsC,EAC9C,IAAI;AACP,eAAW,OAAO,SAAS;AACzB,WAAK,mBAAmB,IAAI,OAAO;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAiB;AACvB,QAAI,CAAC,KAAK,IAAK;AAEf,UAAM,aAAa,KAAK,IACrB,QAAQ,qBAAqB,EAC7B,IAAI;AACP,UAAM,UAAU,WAAW;AAE3B,QAAI,UAAU,GAAG;AAGf,WAAK,IAAI,KAAK,yBAAyB;AAAA,IACzC,WAAW,UAAU,GAAG;AAEtB,WAAK,IAAI;AAAA,QACP;AAAA,MACF;AACA,WAAK,IAAI,KAAK,yBAAyB;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,QAAI,KAAK,QAAQ,MAAM;AACrB,WAAK,IAAI,MAAM;AACf,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,SAA0B;AAChC,WAAO,KAAK,gBAAgB,IAAI,OAAO;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,SAA0B;AAClC,QAAI,KAAK,cAAc,IAAI,OAAO,GAAG;AACnC,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,YAAM,SAAS,QAAQ,MAAM,IAAI,EAAE,CAAC;AACpC,aAAO,KAAK,gBAAgB,IAAI,MAAM;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAgC;AAC3C,QAAI,KAAK,QAAQ,KAAM,QAAO;AAC9B,UAAM,MAAM,KAAK,IACd,QAAQ,mDAAmD,EAC3D,IAAI,OAAO;AACd,WAAO,KAAK,cAAc;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAkC;AAC7C,QAAI,KAAK,QAAQ,KAAM,QAAO;AAC9B,UAAM,MAAM,KAAK,IACd,QAAQ,2DAA2D,EACnE,IAAI,OAAO;AACd,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,IAAI,gBAAgB,MAAM;AAC5B,aAAO,KAAK,MAAM,IAAI,WAAW;AAAA,IACnC;AACA,QAAI,IAAI,UAAU,MAAM;AACtB,aAAO,CAAC,IAAI,KAAK;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,WACE,SACA,WACA,SAQM;AACN,QAAI,KAAK,QAAQ,MAAM;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAEA,UAAM,WAAW,KAAK,IACnB,QAAQ,gEAAgE,EACxE,IAAI,OAAO;AACd,QACE,aAAa,WACZ,SAAS,gBAAgB,YACxB,SAAS,gBAAgB,eAC3B,SAAS,eAAe,WACxB;AACA,UAAI,CAAC,SAAS,OAAO;AACnB,cAAM,IAAI;AAAA,UACR,yBAAyB,SAAS,WAAW,YACxC,KAAK,UAAU,OAAO,CAAC;AAAA,QAE9B;AAAA,MACF;AACA,UAAI;AAAA,QACF,8BAA8B,SAAS,WAAW,YAC7C,OAAO;AAAA,MACd;AAAA,IACF;AAEA,UAAM,cAAc,SAAS,eAAe;AAC5C,UAAM,aAAa,SAAS,cAAc;AAC1C,UAAM,cAAc,SAAS,eAAe;AAC5C,UAAM,QAAQ,SAAS,SAAS;AAChC,UAAM,aACJ,SAAS,WAAW,UAAa,SAAS,WAAW,OACjD,KAAK,UAAU,QAAQ,MAAM,IAC7B;AAEN,SAAK,IACF;AAAA,MACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUF,EACC,IAAI,SAAS,WAAW,aAAa,YAAY,aAAa,OAAO,UAAU;AAElF,SAAK,gBAAgB,IAAI,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,eAA6B;AAC3B,QAAI,KAAK,QAAQ,KAAM,QAAO,CAAC;AAC/B,UAAM,OAAO,KAAK,IACf;AAAA,MACC;AAAA,IAEF,EACC,IAAI;AAOP,WAAO,KAAK,IAAI,CAAC,OAAO;AAAA,MACtB,SAAS,EAAE;AAAA,MACX,aAAa,EAAE;AAAA,MACf,YAAY,EAAE;AAAA,MACd,WAAW,EAAE;AAAA,MACb,UAAU,EAAE;AAAA,IACd,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,SAAiB,iBAA+B;AACzD,QAAI,KAAK,QAAQ,MAAM;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,SAAK,IACF;AAAA,MACC;AAAA,IACF,EACC,IAAI,SAAS,eAAe;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,aAA6B;AAC3B,QAAI,KAAK,QAAQ,KAAM,QAAO,CAAC;AAC/B,UAAM,OAAO,KAAK,IACf;AAAA,MACC;AAAA,IACF,EACC,IAAI;AAKP,WAAO,KAAK,IAAI,CAAC,OAAO;AAAA,MACtB,SAAS,EAAE;AAAA,MACX,aAAa,EAAE;AAAA,MACf,YAAY,EAAE;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,SAAuB;AACnC,QAAI,KAAK,QAAQ,KAAM;AACvB,SAAK,IACF,QAAQ,kDAAkD,EAC1D,IAAI,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,OAAe,GAAmB;AAClD,QAAI,KAAK,QAAQ,KAAM,QAAO,CAAC;AAC/B,UAAM,OAAO,KAAK,IACf;AAAA,MACC;AAAA;AAAA,IAEF,EACC,IAAI,OAAO,IAAI,CAAC;AAKnB,WAAO,KAAK,IAAI,CAAC,OAAO;AAAA,MACtB,SAAS,EAAE;AAAA,MACX,aAAa,EAAE;AAAA,MACf,YAAY,EAAE;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,SAAgC;AAC5C,QAAI,KAAK,QAAQ,KAAM,QAAO;AAC9B,UAAM,MAAM,KAAK,IACd,QAAQ,oDAAoD,EAC5D,IAAI,OAAO;AACd,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAuB;AACjC,QAAI,KAAK,QAAQ,MAAM;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,SAAK,IACF;AAAA,MACC;AAAA,IACF,EACC,IAAI,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,SAA0B;AACtC,QAAI,KAAK,QAAQ,MAAM;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,UAAM,SAAS,KAAK,IACjB,QAAQ,wCAAwC,EAChD,IAAI,OAAO;AACd,SAAK,gBAAgB,OAAO,OAAO;AACnC,WAAO,OAAO,UAAU;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,SAA0B;AAC5C,UAAM,QAAQ,KAAK,cAAc,OAAO;AACxC,WAAO,UAAU,aAAa,UAAU,cAAc,UAAU;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,SAAuB;AAC9B,QAAI,KAAK,QAAQ,MAAM;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,SAAK,IACF,QAAQ,6DAA6D,EACrE,IAAI,OAAO;AACd,SAAK,mBAAmB,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAuB;AACjC,QAAI,KAAK,QAAQ,MAAM;AACrB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,SAAK,IACF,QAAQ,gDAAgD,EACxD,IAAI,OAAO;AACd,SAAK,qBAAqB,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,cAA8B;AAC5B,QAAI,KAAK,QAAQ,KAAM,QAAO,CAAC;AAC/B,UAAM,OAAO,KAAK,IACf;AAAA,MACC;AAAA,IACF,EACC,IAAI;AACP,WAAO,KAAK,IAAI,CAAC,OAAO;AAAA,MACtB,SAAS,EAAE;AAAA,MACX,WAAW,EAAE;AAAA,IACf,EAAE;AAAA,EACJ;AAAA;AAAA,EAIQ,mBAAmB,SAAuB;AAChD,QAAI,QAAQ,WAAW,KAAK,GAAG;AAC7B,WAAK,gBAAgB,IAAI,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C,OAAO;AACL,WAAK,cAAc,IAAI,OAAO;AAAA,IAChC;AAAA,EACF;AAAA,EAEQ,qBAAqB,SAAuB;AAClD,QAAI,QAAQ,WAAW,KAAK,GAAG;AAC7B,WAAK,gBAAgB,OAAO,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC9C,OAAO;AACL,WAAK,cAAc,OAAO,OAAO;AAAA,IACnC;AAAA,EACF;AACF;;;AEzZO,SAAS,mBACd,MACA,UACA,UACM;AACN,MAAI,KAAK,YAAY,SAAS,aAAa;AACzC,UAAM,IAAI;AAAA,MACR,wBAAwB,KAAK,UAAU,KAAK,OAAO,CAAC,mCAC/B,KAAK,UAAU,SAAS,WAAW,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,MAAI,KAAK,cAAc,mBAAmB,QAAQ,GAAG;AACnD,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,mBAAN,MAAuB;AAAA,EACpB;AAAA,EACC;AAAA,EAET,YAAY,aAA0B,aAAqB;AACzD,SAAK,eAAe;AACpB,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,uBACJ,OACA,WACA,aACkC;AAElC,UAAM,OAAO,MAAM;AAAA,MACjB,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,MAAM,YAAY;AAAA,IACpB;AACA,UAAM,WAAW,KAAK,UAAU,kBAAkB,IAAI,CAAC;AAGvD,UAAM,WAAW,MAAM;AAAA,MACrB,MAAM;AAAA,MACN;AAAA;AAAA,MAEA,IAAI,YAAY,EAAE,OAAO,QAAQ;AAAA,MACjC,MAAM,YAAY;AAAA,MAClB;AAAA,IACF;AAEA,WAAO,WAAW,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cACJ,OACA,UACA,UACiC;AACjC,QAAI,SAAS,sDAAwC;AACnD,YAAM,KAAK,eAAe,OAAO,UAAU,QAAQ;AAAA,IACrD,WAAW,SAAS,oDAAuC;AACzD,YAAM,KAAK,cAAc,OAAO,UAAU,QAAQ;AAAA,IACpD,WAAW,SAAS,gDAAqC;AAAA,IAEzD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eACZ,OACA,UACA,UACe;AAEf,UAAM,YAAY;AAAA,MAChB,SAAS;AAAA,MACT,MAAM,YAAY;AAAA,IACpB;AACA,UAAM,WAAW,KAAK;AAAA,MACpB,IAAI,YAAY,EAAE,OAAO,SAAS;AAAA,IACpC;AACA,UAAM,OAAO,oBAAoB,QAAQ;AAGzC,sBAAkB,IAAI;AAGtB,uBAAmB,MAAM,UAAU,QAAQ;AAE3C,QAAI,KAAK,iBAAiB,eAAe;AAEvC,WAAK,aAAa,WAAW,KAAK,SAAS,KAAK,WAAW;AAAA,QACzD,aAAa,KAAK;AAAA,QAClB,YAAY;AAAA,QACZ,aAAa;AAAA,MACf,CAAC;AAED,YAAM,KAAK,YAAY,OAAO,SAAS,aAAa,QAAQ;AAAA,IAC9D,WAAW,KAAK,iBAAiB,kBAAkB;AAEjD,YAAM,KAAK,UAAU,OAAO,SAAS,aAAa,QAAQ;AAAA,IAC5D,OAAO;AAEL,WAAK,aAAa;AAAA,QAChB,SAAS;AAAA,QACT,KAAK,UAAU,QAAQ;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAc,cACZ,OACA,UACA,UACe;AACf,UAAM,QAAQ,KAAK,aAAa,cAAc,SAAS,WAAW;AAClE,QAAI,UAAU,kBAAkB;AAC9B,UAAI;AAAA,QACF,8CAA8C,SAAS,WAAW,iBAChD,KAAK,UAAU,KAAK,CAAC;AAAA,MACzC;AACA;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,YAAM,YAAY;AAAA,QAChB,SAAS;AAAA,QACT,MAAM,YAAY;AAAA,QAClB;AAAA,MACF;AACA,gBAAU,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AAAA,IAC1D,QAAQ;AACN,UAAI;AAAA,QACF,6BAA6B,SAAS,SAAS,SAC1C,SAAS,WAAW;AAAA,MAC3B;AACA;AAAA,IACF;AAEA,QACE,YAAY,QACZ,OAAO,YAAY,YACnB,kBAAkB,SAClB;AACA,YAAM,OAAO;AAAA,QACV,QAAoC,cAAc;AAAA,MAIrD;AACA,wBAAkB,IAAI;AACtB,yBAAmB,MAAM,UAAU,QAAQ;AAAA,IAC7C;AAEA,UAAM,cAAc,mBAAmB,QAAQ;AAC/C,SAAK,aAAa,WAAW,SAAS,aAAa,aAAa;AAAA,MAC9D,YAAY;AAAA,IACd,CAAC;AACD,SAAK,aAAa,YAAY,SAAS,WAAW;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACJ,OACA,WACA,aACe;AACf,UAAM,OAAO,MAAM;AAAA,MACjB,MAAM;AAAA,MACN,MAAM,QAAQ;AAAA,MACd,MAAM,QAAQ;AAAA,MACd,MAAM,YAAY;AAAA,IACpB;AACA,UAAM,gBAAgB,KAAK,UAAU;AAAA,MACnC,QAAQ;AAAA,MACR,cAAc,kBAAkB,IAAI;AAAA,IACtC,CAAC;AAED,UAAM,WAAW,MAAM;AAAA,MACrB,MAAM;AAAA,MACN;AAAA;AAAA,MAEA,IAAI,YAAY,EAAE,OAAO,aAAa;AAAA,MACtC,MAAM,YAAY;AAAA,MAClB;AAAA,IACF;AAEA,UAAM,OAAO,WAAW,QAAQ;AAChC,QAAI,MAAM,YAAY;AACpB,YAAM,MAAM,WAAW,KAAK,IAAI;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UACJ,OACA,WACA,aACe;AACf,UAAM,cAAc,KAAK,UAAU;AAAA,MACjC,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,WAAW,MAAM;AAAA,MACrB,MAAM;AAAA,MACN;AAAA;AAAA,MAEA,IAAI,YAAY,EAAE,OAAO,WAAW;AAAA,MACpC,MAAM,YAAY;AAAA,MAClB;AAAA,IACF;AAEA,UAAM,OAAO,WAAW,QAAQ;AAChC,QAAI,MAAM,YAAY;AACpB,YAAM,MAAM,WAAW,KAAK,IAAI;AAAA,IAClC;AAAA,EACF;AACF;;;ACjTO,IAAe,kBAAf,MAA+B;AAWtC;;;ACfA,kBAAoE;AAMpE,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AAGzB,IAAM,eAAe,OAAO;AAG5B,IAAM,eAAe;AAAA,EACnB;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,CAAC;AAAA,IACzC,SAAS;AAAA,MACP,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,aAAa,MAAM,SAAS;AAAA,MACpC,EAAE,MAAM,YAAY,MAAM,SAAS;AAAA,MACnC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACpC;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,CAAC;AAAA,IACzC,SAAS,CAAC,EAAE,MAAM,IAAI,MAAM,OAAO,CAAC;AAAA,EACtC;AACF;AAmBA,SAAS,WAAW,SAAiB,QAAgB;AACnD,aAAO,yBAAY;AAAA,IACjB,IAAI;AAAA,IACJ,MAAM,SAAS,OAAO;AAAA,IACtB,gBAAgB,EAAE,MAAM,SAAS,QAAQ,OAAO,UAAU,GAAG;AAAA,IAC7D,SAAS;AAAA,MACP,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;AAAA,IAC5B;AAAA,EACF,CAAC;AACH;AAQO,IAAM,gBAAN,cAA4B,gBAAgB;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAkC,oBAAI,IAAI;AAAA,EAElD,YAAY,QAAqB;AAC/B,UAAM;AACN,SAAK,mBAAmB,OAAO;AAC/B,SAAK,cAAc,OAAO,cAAc;AACxC,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,UAAU,OAAO,WAAW;AAClC,SAAK,cAAU,gCAAmB;AAAA,MAChC,OAAO,WAAW,SAAS,MAAM;AAAA,MACjC,eAAW,kBAAK,MAAM;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBACJ,SACA,QACA,WACiB;AACjB,UAAM,SAAS,aAAa,OAAO;AACnC,UAAM,OAAO,OAAO;AAGpB,UAAM,SAAS,KAAK,OAAO,IAAI,IAAI;AACnC,QAAI,UAAU,OAAO,YAAY,KAAK,IAAI,GAAG;AAC3C,aAAO,OAAO;AAAA,IAChB;AAGA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,QAAQ,aAAa;AAAA,QAC7C,SAAS,KAAK;AAAA,QACd,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,IAAI;AAAA,MACb,CAAC;AAED,YAAM,CAAC,QAAQ,WAAW,YAAY,OAAO,IAAI;AAEjD,UAAI,CAAC,WAAW;AACd,cAAM,IAAI;AAAA,UACR,gBAAgB,IAAI;AAAA,QACtB;AAAA,MACF;AAGA,WAAK,OAAO,IAAI,MAAM;AAAA,QACpB;AAAA,QACA,WAAW,KAAK,IAAI,IAAI,KAAK;AAAA,MAC/B,CAAC;AAED,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,eAAe,SAAU,OAAM;AACnC,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAI,IAAI,SAAS,cAAc,KAAK,IAAI,SAAS,QAAQ,GAAG;AAC1D,cAAM,IAAI,SAAS,mCAAmC,IAAI,EAAE;AAAA,MAC9D;AACA,YAAM,IAAI,SAAS,gCAAgC,IAAI,KAAK,GAAG,EAAE;AAAA,IACnE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MAAgC;AAChD,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,QAAQ,aAAa;AAAA,QAC7C,SAAS,KAAK;AAAA,QACd,KAAK;AAAA,QACL,cAAc;AAAA,QACd,MAAM,CAAC,IAAI;AAAA,MACb,CAAC;AACD,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAqB;AACnC,QAAI,MAAM;AACR,WAAK,OAAO,OAAO,IAAI;AAAA,IACzB,OAAO;AACL,WAAK,OAAO,MAAM;AAAA,IACpB;AAAA,EACF;AACF;;;AC9JA;AAcO,IAAM,gBAAN,cAA4B,gBAAgB;AAAA,EACjD,MAAM,iBACJ,SACA,QACA,UACiB;AACjB,UAAM,OAAO,MAAM;AAAA,MACjB,GAAG,QAAQ,kBAAkB,OAAO;AAAA,IACtC;AACA,QAAI,KAAK,WAAW,KAAK;AACvB,YAAM,IAAI,SAAS,oBAAoB,OAAO,EAAE;AAAA,IAClD;AACA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI;AAAA,QACR,4BAA4B,KAAK,MAAM,IAAI,KAAK,UAAU;AAAA,MAC5D;AAAA,IACF;AACA,UAAM,OAAQ,MAAM,KAAK,KAAK;AAC9B,WAAO,KAAK,YAAY;AAAA,EAC1B;AACF;AAUO,IAAM,gBAAN,cAA4B,gBAAgB;AAAA,EACjD,MAAM,iBACJ,SACA,QACA,WACiB;AACjB,UAAM,SAAS,aAAa,OAAO;AAGnC,UAAM,aAAa,MAAM,YAAY,OAAO,MAAM;AAClD,eAAW,OAAO,YAAY;AAC5B,YAAM,OAAO,YAAY,GAAG;AAC5B,UAAI,KAAK,GAAG,MAAM,QAAQ;AACxB,cAAM,MAAM,iBAAiB,IAAI;AACjC,YAAI,IAAK,QAAO;AAAA,MAClB;AAAA,IACF;AAGA,UAAM,WAAW,MAAM,mBAAmB,OAAO,OAAO,OAAO,MAAM;AACrE,QAAI,SAAU,QAAO;AAErB,UAAM,IAAI;AAAA,MACR,oCAAoC,OAAO;AAAA,IAC7C;AAAA,EACF;AACF;AAUO,IAAM,gBAAN,cAA4B,gBAAgB;AAAA,EACjD;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,aAAqB,aAA2B;AAC1D,UAAM;AACN,SAAK,cAAc;AACnB,SAAK,SAAS,IAAI,cAAc;AAChC,SAAK,SAAS,IAAI,cAAc;AAChC,SAAK,SAAS,cAAc,IAAI,cAAc,WAAW,IAAI;AAAA,EAC/D;AAAA,EAEA,MAAM,iBACJ,SACA,OACA,UACiB;AACjB,UAAM,SAAS,aAAa,OAAO;AACnC,UAAM,SAAS,OAAO;AAEtB,QAAI,WAAW,KAAK,aAAa;AAC/B,aAAO,KAAK,OAAO,iBAAiB,SAAS,OAAO,QAAQ;AAAA,IAC9D;AAEA,QAAI,OAAO,SAAS,GAAG,GAAG;AACxB,aAAO,KAAK,OAAO,iBAAiB,SAAS,OAAO,QAAQ;AAAA,IAC9D;AAEA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI;AAAA,QACR,gFACsC,MAAM;AAAA,MAC9C;AAAA,IACF;AACA,WAAO,KAAK,OAAO,iBAAiB,SAAS,OAAO,QAAQ;AAAA,EAC9D;AACF;;;ACxHO,IAAe,gBAAf,MAA6B;AAsBpC;;;ACnBO,IAAM,gBAAN,cAA4B,cAAc;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,UAAkB,OAAe,SAAiB;AAC5D,UAAM;AACN,SAAK,YAAY,SAAS,QAAQ,QAAQ,EAAE;AAC5C,SAAK,SAAS;AACd,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,MAAM,UAAyB;AAAA,EAE/B;AAAA,EAEA,MAAM,aAA4B;AAAA,EAElC;AAAA,EAEA,MAAM,KAAK,UAAkD;AAC3D,UAAM,OAAO,MAAM,MAAM,GAAG,KAAK,SAAS,gBAAgB;AAAA,MACxD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,KAAK,MAAM;AAAA,MACtC;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC;AAAA,IACnC,CAAC;AACD,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI;AAAA,QACR,qBAAqB,KAAK,MAAM,IAAI,KAAK,UAAU;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,QAAgB,IAAwC;AACpE,UAAM,MAAM,IAAI;AAAA,MACd,GAAG,KAAK,SAAS,iBAAiB,KAAK,QAAQ;AAAA,IACjD;AACA,QAAI,aAAa,IAAI,SAAS,OAAO,KAAK,CAAC;AAE3C,UAAM,OAAO,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,MACvC,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,MAAM;AAAA,MACtC;AAAA,IACF,CAAC;AACD,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI;AAAA,QACR,wBAAwB,KAAK,MAAM,IAAI,KAAK,UAAU;AAAA,MACxD;AAAA,IACF;AACA,UAAM,OAAQ,MAAM,KAAK,KAAK;AAC9B,WAAQ,KAAK,UAAU,KAAmC,CAAC;AAAA,EAC7D;AAAA,EAEA,MAAM,OACJ,WACe;AACf,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACF;;;ACnEA,gBAAsB;AAKtB,IAAM,aAAa;AACnB,IAAM,YAAY;AAClB,IAAM,eAAe;AAGd,IAAM,sBAAsB;AAE5B,IAAM,qBAAN,cAAiC,cAAc;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EAGA,MAAwB;AAAA,EACxB,WAAsC,CAAC;AAAA,EACvC,aAAsB;AAAA,EACtB,kBAAuC;AAAA,EACvC,iBAAgD;AAAA,EAChD,WAAoB;AAAA,EACpB,oBAA0D;AAAA;AAAA,EAE1D,cAAsB;AAAA,EACtB,YAAkC;AAAA,EAClC,WAAgC;AAAA;AAAA,EAGxC,YAAoB,sBAAsB;AAAA,EAE1C,YACE,OACA,OACA,WACA;AACA,UAAM;AAKN,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,aAAa,aAAa;AAAA,EACjC;AAAA,EAEA,MAAM,UAAyB;AAC7B,SAAK,WAAW;AAChB,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC5C,WAAK,kBAAkB;AACvB,WAAK,iBAAiB;AACtB,WAAK,qBAAqB;AAG1B,YAAM,UAAU,WAAW,MAAM;AAC/B,aAAK,iBAAiB;AACtB,aAAK,kBAAkB;AACvB,eAAO,IAAI,MAAM,oCAAoC,CAAC;AAAA,MACxD,GAAG,GAAK;AAGR,YAAM,cAAc,KAAK;AACzB,WAAK,kBAAkB,MAAM;AAC3B,qBAAa,OAAO;AACpB,sBAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAA4B;AAChC,UAAM,KAAK,aAAa;AACxB,SAAK,WAAW;AAChB,QAAI,KAAK,sBAAsB,MAAM;AACnC,mBAAa,KAAK,iBAAiB;AACnC,WAAK,oBAAoB;AAAA,IAC3B;AACA,QAAI,KAAK,KAAK;AACZ,WAAK,IAAI,mBAAmB;AAC5B,WAAK,IAAI,MAAM;AACf,WAAK,MAAM;AAAA,IACb;AACA,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,MAAM,KAAK,UAAkD;AAC3D,QAAI,CAAC,KAAK,OAAO,KAAK,IAAI,eAAe,UAAAC,QAAU,MAAM;AACvD,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,SAAK,IAAI,KAAK,KAAK,UAAU,QAAQ,CAAC;AACtC,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAM,QAAQ,QAAgB,IAAwC;AACpE,UAAM,SAAS,KAAK,SAAS,MAAM,GAAG,KAAK;AAC3C,SAAK,WAAW,KAAK,SAAS,MAAM,KAAK;AACzC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OACJ,UACe;AACf,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA,EAGQ,eAA8B;AACpC,QAAI,KAAK,gBAAgB,EAAG,QAAO,QAAQ,QAAQ;AACnD,SAAK,cAAc,IAAI,QAAc,CAAC,YAAY;AAChD,YAAM,UAAU,WAAW,MAAM;AAC/B,YAAI,KAAK,gBAAgB,KAAK,WAAW,mBAAmB;AAC5D,aAAK,WAAW;AAAA,MAClB,GAAG,KAAK,SAAS;AACjB,WAAK,WAAW,MAAM;AACpB,qBAAa,OAAO;AACpB,aAAK,YAAY;AACjB,aAAK,WAAW;AAChB,gBAAQ;AAAA,MACV;AAAA,IACF,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,YAAkB;AACxB,SAAK,cAAc,KAAK,IAAI,GAAG,KAAK,cAAc,CAAC;AACnD,QAAI,KAAK,gBAAgB,EAAG,MAAK,WAAW;AAAA,EAC9C;AAAA,EAEQ,uBAA6B;AACnC,QAAI,UAAU;AAEd,UAAM,aAAa,MAAM;AACvB,UAAI,CAAC,KAAK,SAAU;AAEpB,YAAM,KAAK,IAAI,UAAAA,QAAU,KAAK,MAAM,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;AAC7D,WAAK,MAAM;AAEX,SAAG,GAAG,QAAQ,MAAM;AAClB,aAAK,aAAa;AAClB,kBAAU;AACV,YAAI,KAAK,iBAAiB;AACxB,eAAK,gBAAgB;AACrB,eAAK,kBAAkB;AACvB,eAAK,iBAAiB;AAAA,QACxB;AAAA,MACF,CAAC;AAED,SAAG,GAAG,WAAW,CAAC,SAAyB;AACzC,YAAI;AACF,gBAAM,MAAM,KAAK,MAAM,KAAK,SAAS,CAAC;AACtC,eAAK,eAAe,GAAG;AAAA,QACzB,QAAQ;AAAA,QAER;AAAA,MACF,CAAC;AAED,SAAG,GAAG,SAAS,MAAM;AACnB,aAAK,aAAa;AAClB,aAAK,MAAM;AAEX,aAAK,cAAc;AACnB,aAAK,WAAW;AAChB,YAAI,CAAC,KAAK,SAAU;AAEpB,mBAAW;AACX,cAAM,QAAQ,KAAK,IAAI,aAAa,KAAK,IAAI,GAAG,OAAO,GAAG,SAAS;AACnE,cAAM,SAAS,KAAK,OAAO,IAAI;AAC/B,cAAM,cAAc,QAAQ,UAAU;AAEtC,aAAK,oBAAoB,WAAW,YAAY,UAAU;AAAA,MAC5D,CAAC;AAED,SAAG,GAAG,SAAS,CAAC,QAAe;AAE7B,YAAI,KAAK,kBAAkB,CAAC,KAAK,YAAY;AAAA,QAE7C;AAAA,MAEF,CAAC;AAAA,IACH;AAEA,eAAW;AAAA,EACb;AAAA,EAEQ,eAAe,KAAoC;AACzD,UAAM,UAAU,IAAI,MAAM;AAG1B,QAAI,iBAAiB,KAAK;AACxB,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW,GAAG,EAAE,MAAM,MAAM;AAAA,QAEjC,CAAC;AAAA,MACH,OAAO;AACL,aAAK,SAAS,KAAK,GAAG;AAAA,MACxB;AAAA,IACF,WAAW,YAAY,QAAQ;AAE7B,UAAI,KAAK,OAAO,KAAK,IAAI,eAAe,UAAAA,QAAU,MAAM;AACtD,aAAK,IAAI,KAAK,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC,CAAC;AAAA,MAChD;AAAA,IACF,WAAW,YAAY,OAAO;AAC5B,WAAK,UAAU;AAAA,IACjB,WAAW,YAAY,WAAW,WAAW,KAAK;AAChD,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AACF;;;AC9MO,SAAS,gBACd,QACA,OACA,SACA,WACe;AACf,MAAI,OAAO,kBAAkB,QAAQ;AACnC,WAAO,IAAI,cAAc,OAAO,UAAU,OAAO,OAAO;AAAA,EAC1D,OAAO;AACL,WAAO,IAAI,mBAAmB,OAAO,YAAY,OAAO,SAAS;AAAA,EACnE;AACF;;;ACAA,IAAAC,kBAA0B;AAC1B,IAAAC,oBAAwB;AACxB,IAAAC,mBAAoC;AAEpC,IAAAC,yBAAqB;AAUd,IAAM,oBAAoB,sBAAsB,IAAI;AAG3D,IAAM,oBAAoB;AAE1B,IAAM,eAAe;AACrB,IAAM,eAAe;AAErB,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcf,SAAS,SAAS,KAAuB;AACvC,QAAM,OAAQ,IAA2B;AACzC,SACE,OAAO,SAAS,aACf,KAAK,WAAW,aAAa,KAAK,KAAK,WAAW,eAAe;AAEtE;AAQA,eAAe,UAAU,IAAsC;AAC7D,WAAS,UAAU,KAAK,WAAW,GAAG;AACpC,QAAI;AACF,SAAG,OAAO,oBAAoB;AAC9B;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,WAAW,gBAAgB,CAAC,SAAS,GAAG,EAAG,OAAM;AACrD,gBAAM,iBAAAC,YAAM,YAAY;AAAA,IAC1B;AAAA,EACF;AACF;AAEO,IAAM,gCAAgC;AAEtC,IAAM,sBAAN,MAA0B;AAAA,EACtB;AAAA,EACA;AAAA,EACQ;AAAA;AAAA,EAEA,QAAQ,oBAAI,IAAoB;AAAA,EAEjD,YAAY,SAIT;AACD,UAAM,WAAW,SAAS,YAAY;AACtC,QAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,GAAG;AAC/C,YAAM,IAAI;AAAA,QACR,yDAAyD,QAAQ;AAAA,MACnE;AAAA,IACF;AACA,SAAK,WAAW;AAChB,SAAK,QAAQ,SAAS,SAAS;AAC/B,SAAK,OAAO,SAAS,QAAQ,MAAM,KAAK,IAAI;AAAA,EAC9C;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA,EAGA,IAAI,aAAqB,WAA4B;AACnD,UAAM,SAAS,KAAK,MAAM,IAAI,KAAK,KAAK,aAAa,SAAS,CAAC;AAC/D,WAAO,WAAW,UAAa,KAAK,KAAK,IAAI,SAAS,KAAK;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,aAAqB,WAA4B;AAC5D,UAAM,MAAM,KAAK,KAAK,aAAa,SAAS;AAC5C,UAAM,MAAM,KAAK,KAAK;AACtB,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,WAAW,UAAa,MAAM,SAAS,KAAK,OAAO;AAErD,WAAK,MAAM,OAAO,GAAG;AACrB,WAAK,MAAM,IAAI,KAAK,MAAM;AAC1B,aAAO;AAAA,IACT;AACA,SAAK,MAAM,OAAO,GAAG;AACrB,SAAK,MAAM,IAAI,KAAK,GAAG;AACvB,WAAO,KAAK,MAAM,OAAO,KAAK,UAAU;AACtC,YAAM,SAAS,KAAK,MAAM,KAAK,EAAE,KAAK,EAAE;AACxC,WAAK,MAAM,OAAO,MAAM;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,KAAK,aAAqB,WAA2B;AAE3D,WAAO,KAAK,UAAU,CAAC,aAAa,SAAS,CAAC;AAAA,EAChD;AACF;AASO,IAAM,wBAAN,MAA4B;AAAA,EACxB;AAAA,EACQ;AAAA,EACA;AAAA,EACT,MAAgC;AAAA,EAChC,WAA8C;AAAA,EAC9C,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA;AAAA;AAAA;AAAA,EAIJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,YACE,MACA,SACA;AACA,UAAM,WAAW,SAAS,YAAY;AACtC,QAAI,CAAC,OAAO,UAAU,QAAQ,KAAK,WAAW,GAAG;AAC/C,YAAM,IAAI;AAAA,QACR,yDAAyD,QAAQ;AAAA,MACnE;AAAA,IACF;AACA,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO,SAAS,QAAQ,MAAM,KAAK,IAAI;AAC5C,SAAK,YAAY,IAAI,oBAAoB;AAAA,MACvC,UAAU;AAAA,MACV,OAAO,IAAI,mBAAmB;AAAA,MAC9B,KAAK,KAAK;AAAA,IACZ,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,OAAsB;AAC1B,UAAM,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aACJ,aACA,WACA,UACkB;AAClB,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,MAAM,KAAK,KAAK;AACtB,QAAI,MAAM,KAAK,cAAc,kBAAmB,MAAK,OAAO,EAAE;AAG9D,QAAI,KAAK,UAAU,IAAI,aAAa,SAAS,EAAG,QAAO;AAEvD,QAAI,KAAK,SAAS,KAAK,UAAU;AAC/B,YAAM,EAAE,QAAQ,IAAI,GACjB;AAAA,QACC;AAAA,MAEF,EACC,IAAI,aAAa,WAAW,MAAM,GAAI;AACzC,UAAI,YAAY,EAAG,QAAO;AAC1B,WAAK,UAAU;AACf,aAAO;AAAA,IACT;AAIA,UAAM,QAAQ,GACX;AAAA,MACC;AAAA,IACF,EACC,IAAI,aAAa,SAAS;AAC7B,QAAI,UAAU,OAAW,QAAO;AAEhC,QAAI,KAAK,IAAI,MAAM,QAAQ,KAAK,mBAAmB,KAAM;AACvD,aAAO,KAAK,UAAU,aAAa,aAAa,SAAS;AAAA,IAC3D;AACA,QAAI;AAAA,MACF,sBAAsB,KAAK,MAAM,2BAA2B,SAAS,SAC3D,WAAW,WAAW,KAAK,OAAO,MAAM,YAAY,GAAI,CAAC;AAAA,IACrE;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,YAA6B;AACjC,UAAM,KAAK,MAAM;AACjB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,kBAAkB,UAAoC;AAC1D,WAAO,WAAY,MAAM,KAAK,UAAU;AAAA,EAC1C;AAAA;AAAA,EAGA,MAAM,QAAyB;AAC7B,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,KAAK,WAAW,EAAE;AAAA,EAC3B;AAAA;AAAA,EAGA,MAAM,QAAuB;AAC3B,UAAM,KAAK,UAAU,MAAM,MAAM,MAAS;AAC1C,SAAK,KAAK,MAAM;AAChB,SAAK,MAAM;AAAA,EACb;AAAA,EAEQ,QAAoC;AAC1C,QAAI,KAAK,QAAQ,KAAM,QAAO,QAAQ,QAAQ,KAAK,GAAG;AACtD,SAAK,aAAa,KAAK,SAAS,EAAE,QAAQ,MAAM;AAC9C,WAAK,WAAW;AAAA,IAClB,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,WAAuC;AACnD,uCAAU,2BAAQ,KAAK,KAAK,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,UAAM,KAAK,IAAI,uBAAAC,QAAS,KAAK,OAAO,EAAE,SAAS,IAAO,CAAC;AACvD,QAAI;AACF,YAAM,UAAU,EAAE;AAClB,SAAG,KAAK,MAAM;AACd,SAAG;AAAA,QACD;AAAA,MACF,EAAE,IAAI,OAAO,KAAK,KAAK,IAAI,GAAI,CAAC;AAChC,YAAM,MAAM,GACT,QAAQ,wDAAwD,EAChE,IAAI;AACP,WAAK,aAAa,OAAO,IAAI,KAAK,IAAI;AACtC,WAAK,OAAO,EAAE;AAAA,IAChB,SAAS,KAAK;AACZ,SAAG,MAAM;AACT,YAAM;AAAA,IACR;AACA,SAAK,MAAM;AACX,WAAO;AAAA,EACT;AAAA,EAEQ,OAAO,IAA6B;AAC1C,UAAM,MAAM,KAAK,KAAK;AACtB,OAAG,QAAQ,8CAA8C,EAAE;AAAA,MACzD,MAAM,MAAO;AAAA,IACf;AACA,SAAK,SAAS,KAAK,WAAW,EAAE;AAChC,SAAK,aAAa;AAAA,EACpB;AAAA,EAEQ,WAAW,IAA+B;AAChD,UAAM,MAAM,GAAG,QAAQ,0CAA0C,EAAE,IAAI;AAGvE,WAAO,IAAI;AAAA,EACb;AACF;;;AtB/QA,IAAM,qBAAqB;AAG3B,SAAS,6BAAqC;AAC5C,QAAM,MAAM,QAAQ,IAAI,2BAA2B;AACnD,MAAI,QAAQ,UAAa,QAAQ,IAAI;AACnC,WAAO;AAAA,EACT;AACA,QAAM,IAAI,OAAO,GAAG;AACpB,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,GAAG;AACjC,QAAI;AAAA,MACF,8CAA8C,KAAK,UAAU,GAAG,CAAC,WACtD,6BAA6B;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,IAAM,QAAN,MAAY;AAAA;AAAA,EAER;AAAA;AAAA,EAEA;AAAA;AAAA,EAET,aAAmC;AAAA,EAE3B;AAAA,EACA,WAA0B;AAAA,EAC1B,SAAwB;AAAA,EACxB,aAAsB;AAAA,EACtB;AAAA;AAAA,EAGC;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMT,SAAuB,MAAM,KAAK,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7B;AAAA;AAAA,EAGD,eAAwB;AAAA;AAAA,EAGxB,gBAAwB;AAAA;AAAA,EAGhC,aAA2B,MAAM,YAAY,IAAI;AAAA;AAAA;AAAA;AAAA,EAKjD,YACE,MACA,SASA;AACA,SAAK,UAAU,IAAI,UAAU;AAAA,MAC3B;AAAA,MACA,UAAU,SAAS;AAAA,MACnB,aAAa,SAAS,UAAU;AAAA,MAChC,QAAQ,SAAS;AAAA,MACjB,aAAa,SAAS,eAAe;AAAA,MACrC,eAAe,SAAS,aAAa;AAAA,MACrC,aAAa,SAAS,eAAe;AAAA,IACvC,CAAC;AACD,SAAK,cAAc,IAAI,WAAW,KAAK,QAAQ,MAAM;AACrD,SAAK,YAAY,IAAI,cAAc,KAAK,QAAQ,WAAW;AAC3D,SAAK,gBAAgB,SAAS,gBAAgB;AAG9C,SAAK,eAAe,IAAI,YAAY,KAAK,QAAQ,OAAO;AACxD,SAAK,aAAa,IAAI;AAAA,MACpB,KAAK;AAAA,MACL,KAAK,QAAQ;AAAA,IACf;AAEA,SAAK,eAAe,IAAI;AAAA,UACtB,wBAAK,KAAK,QAAQ,SAAS,UAAU,WAAW;AAAA,MAChD;AAAA,QACE,UAAU,2BAA2B;AAAA,QACrC,KAAK,MAAM,KAAK,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,IAAI,UAAkB;AACpB,QAAI,KAAK,aAAa,MAAM;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,UAAkB;AACpB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,YAAoB;AACtB,WAAO,mBAAmB,KAAK,YAAY,SAAS;AAAA,EACtD;AAAA;AAAA,EAGA,IAAI,cAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAgD;AACpD,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,UAAM,OAAO,MAAM;AAAA,MACjB,KAAK;AAAA,MACL,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,MACb,KAAK,YAAY;AAAA,IACnB;AACA,WAAO,kBAAkB,IAAI;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAAyB;AAC7B,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAGA,UAAM;AAGN,SAAK,YAAY,eAAe,KAAK,QAAQ,IAAI;AAIjD,QAAI;AACF,YAAM,KAAK,aAAa,KAAK;AAAA,IAC/B,SAAS,KAAK;AACZ,YAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,UAAI,KAAK,oCAAoC,MAAM,EAAE;AAAA,IACvD;AAGA,UAAM,cAAc,KAAK,YAAY;AAAA,MACnC,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAEA,QAAI,aAAa;AAEf,WAAK,SAAS;AACd,WAAK,YAAY,MAAM,KAAK,eAAe,CAAC;AAAA,IAC9C,WAAW,KAAK,eAAe;AAE7B,YAAM,KAAK,mBAAmB;AAAA,IAChC,OAAO;AACL,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AAGA,SAAK,aAAa;AAAA,MAChB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AACA,UAAM,KAAK,WAAW,QAAQ;AAG9B,SAAK,aAAa,KAAK;AAEvB,SAAK,aAAa;AAGlB,UAAM,KAAK,wBAAwB;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAE3B,SAAK,aAAa,MAAM;AACxB,UAAM,KAAK,aAAa,MAAM;AAC9B,QAAI,KAAK,YAAY;AACnB,YAAM,KAAK,WAAW,WAAW;AAAA,IACnC;AACA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KACJ,WACA,SACA,SAIiB;AACjB,UAAM,KAAK,iBAAiB;AAG5B,QAAI,KAAK,QAAQ,gBAAgB,kBAAkB;AACjD,YAAM,QAAQ,KAAK,aAAa,cAAc,SAAS;AACvD,UAAI,UAAU,YAAY,UAAU,YAAY;AAC9C,cAAM,IAAI;AAAA,UACR,qFACoC,SAAS,6BAChB,SAAS;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAIA,UAAM,cAAc,MAAM,KAAK,kBAAkB,SAAS;AAO1D,UAAM,aAAa,KAAK,aAAa,cAAc,SAAS;AAC5D,QACE,eAAe,YACf,eAAe,cACf,eAAe,aACf,eAAe,kBACf;AACA,YAAM,KAAK,mBAAmB,WAAW,WAAW;AAAA,IACtD;AAGA,UAAM,WAAW,MAAM;AAAA,MACrB,KAAK;AAAA,MACL;AAAA;AAAA,MAEA,IAAI,YAAY,EAAE,OAAO,OAAO;AAAA,MAChC,KAAK,YAAY;AAAA,MACjB;AAAA,MACA;AAAA,QACE,UAAU,SAAS;AAAA,QACnB,WAAW;AAAA,QACX,aAAa,SAAS;AAAA,MACxB;AAAA,IACF;AAGA,UAAM,OAAO,WAAW,QAAQ;AAChC,UAAM,YAAY,MAAM,KAAK,cAAc,SAAS;AACpD,QACE,cAAc,QACd,UAAU,WAAW,KACrB,UAAU,CAAC,MAAM,KAAK,QAAQ,UAC9B;AAEA,YAAM,KAAK,WAAY,KAAK,IAAI;AAAA,IAClC,WAAW,cAAc,QAAQ,UAAU,SAAS,GAAG;AAErD,YAAM,KAAK,qBAAqB,MAAM,SAAS;AAAA,IACjD,OAAO;AAEL,YAAM,KAAK,WAAY,KAAK,IAAI;AAAA,IAClC;AAEA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,MAAM,QAAgB,IAAgC;AAC1D,UAAM,KAAK,iBAAiB;AAG5B,UAAM,KAAK,wBAAwB;AAEnC,UAAM,cAAc,MAAM,KAAK,WAAY,QAAQ,KAAK;AACxD,UAAM,SAA4B,CAAC;AACnC,eAAW,OAAO,aAAa;AAC7B,UAAI;AACJ,UAAI;AACF,cAAM,MAAM,KAAK,gBAAgB,GAAG;AAAA,MACtC,SAAS,KAAK;AACZ,YAAI;AAAA,UACF,4BAA4B,OAAO,IAAI,YAAY,CAAC,CAAC,SAChD,OAAO,IAAI,MAAM,CAAC,CAAC,KACnB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACvD;AACA;AAAA,MACF;AACA,UAAI,QAAQ,MAAM;AAChB,eAAO,KAAK,GAAG;AAEf,cAAM,KAAK,iBAAiB,GAAG;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAKA,MAAM,UAAwF;AAC5F,UAAM,KAAK,iBAAiB;AAC5B,WAAO,KAAK,aAAa,WAAW;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,QAAQ,SAAgC;AAC5C,UAAM,KAAK,iBAAiB;AAE5B,UAAM,cAAc,KAAK,aAAa,WAAW;AACjD,UAAM,QAAQ,YAAY,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO;AAC3D,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,6BAA6B,OAAO,EAAE;AAAA,IAC3D;AAGA,UAAM,WAAW,KAAK,MAAM,MAAM,WAAW;AAC7C,UAAM,OAAO,oBAAoB,QAAQ;AACzC,sBAAkB,IAAI;AAKtB,UAAM,WAAW,qBAAqB,KAAK,SAAS;AACpD,uBAAmB,MAAM,EAAE,aAAa,QAAQ,GAAG,QAAQ;AAG3D,SAAK,aAAa,WAAW,KAAK,SAAS,KAAK,WAAW;AAAA,MACzD,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,MACZ,aAAa;AAAA,IACf,CAAC;AAGD,SAAK,aAAa,cAAc,OAAO;AAGvC,UAAM,KAAK,WAAW,YAAY,MAAM,SAAS,QAAQ;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,SAAgC;AACzC,UAAM,KAAK,iBAAiB;AAE5B,UAAM,cAAc,KAAK,aAAa,WAAW;AACjD,UAAM,QAAQ,YAAY,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO;AAC3D,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,6BAA6B,OAAO,EAAE;AAAA,IAC3D;AAGA,UAAM,WAAW,KAAK,MAAM,MAAM,WAAW;AAC7C,UAAM,OAAO,oBAAoB,QAAQ;AACzC,UAAM,WAAW,qBAAqB,KAAK,SAAS;AAGpD,SAAK,aAAa,cAAc,OAAO;AAGvC,UAAM,KAAK,WAAW,UAAU,MAAM,SAAS,QAAQ;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,SAAgC;AAC1C,UAAM,KAAK,iBAAiB;AAC5B,SAAK,aAAa,SAAS,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,SAAgC;AAC5C,UAAM,KAAK,iBAAiB;AAC5B,SAAK,aAAa,YAAY,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,aACJ,QACA,SACkB;AAClB,UAAM,EAAE,mBAAAC,mBAAkB,IAAI,MAAM;AACpC,UAAM,KAAK,iBAAiB;AAE5B,UAAM,UAAU,SAAS,WAAW;AACpC,UAAM,eAAe,SAAS,gBAAgB;AAE9C,UAAM,cAAcA;AAAA,MAClB,KAAK;AAAA,MACL,KAAK,QAAQ;AAAA,IACf;AAEA,SAAK;AAEL,UAAM,QAAQ,KAAK,IAAI;AACvB,WAAO,KAAK,IAAI,IAAI,QAAQ,SAAS;AACnC,UAAI;AACF,cAAM,OAAO,MAAM;AAAA,UACjB,GAAG,KAAK,QAAQ,QAAQ;AAAA,UACxB;AAAA,YACE,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,gBAAgB;AAAA,cAChB,eAAe,UAAU,KAAK,MAAM;AAAA,YACtC;AAAA,YACA,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,YAC/B,QAAQ,YAAY,QAAQ,GAAK;AAAA,UACnC;AAAA,QACF;AACA,YAAI,KAAK,IAAI;AACX,gBAAM,SAAU,MAAM,KAAK,KAAK;AAChC,cAAI,OAAO,QAAQ,MAAM,YAAY;AACnC,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AACA,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,YAAY,CAAC;AAAA,IAClE;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA,EAKA,MAAc,cAAc,WAA6C;AACvE,UAAM,OAAO,KAAK,aAAa,aAAa,SAAS;AACrD,QAAI,SAAS,MAAM;AACjB,aAAO;AAAA,IACT;AACA,WAAO,CAAC,KAAK,QAAQ,QAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,qBACZ,MACA,WACe;AACf,QAAI,YAA0B;AAE9B,eAAW,OAAO,WAAW;AAE3B,UAAI,OAAO,IAAI,QAAQ,QAAQ,EAAE;AACjC,UAAI,KAAK,SAAS,KAAK,GAAG;AACxB,eAAO,KAAK,MAAM,GAAG,EAAE;AAAA,MACzB;AACA,aAAO,KAAK,QAAQ,UAAU,UAAU,EAAE,QAAQ,SAAS,SAAS;AACpE,YAAM,UAAU,GAAG,IAAI;AAEvB,UAAI;AACF,cAAM,OAAO,MAAM,MAAM,SAAS;AAAA,UAChC,QAAQ;AAAA,UACR,SAAS;AAAA,YACP,gBAAgB;AAAA,YAChB,eAAe,UAAU,KAAK,MAAM;AAAA,UACtC;AAAA,UACA,MAAM,KAAK,UAAU,EAAE,UAAU,KAAK,CAAC;AAAA,UACvC,QAAQ,YAAY,QAAQ,GAAK;AAAA,QACnC,CAAC;AACD,YAAI,CAAC,KAAK,IAAI;AACZ,gBAAM,IAAI,MAAM,QAAQ,KAAK,MAAM,EAAE;AAAA,QACvC;AACA;AAAA,MACF,SAAS,KAAK;AACZ,oBAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,MAChE;AAAA,IACF;AAEA,QAAI,cAAc,MAAM;AACtB,YAAM;AAAA,IACR;AACA,UAAM,IAAI,SAAS,sBAAsB;AAAA,EAC3C;AAAA,EAEA,MAAc,mBAAkC;AAC9C,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAc,kBAAkB,WAAwC;AAEtE,UAAM,QAAQ,KAAK,aAAa,aAAa,SAAS;AACtD,QAAI,UAAU,MAAM;AAElB,aAAO,qBAAqB,KAAK;AAAA,IACnC;AAGA,UAAM,gBAAgB,MAAM,KAAK,UAAU;AAAA,MACzC;AAAA,MACA,KAAK;AAAA,MACL,KAAK,QAAQ;AAAA,IACf;AAGA,UAAM,WAAW,KAAK,aAAa,aAAa,SAAS;AACzD,QAAI,aAAa,QAAQ,aAAa,eAAe;AACnD,YAAM,QAAQ,KAAK,aAAa,cAAc,SAAS;AACvD,UAAI,UAAU,YAAY,UAAU,aAAa,UAAU,YAAY;AACrE,cAAM,IAAI;AAAA,UACR,qCAAqC,SAAS,8HAGC,SAAS;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAEA,WAAO,qBAAqB,aAAa;AAAA,EAC3C;AAAA,EAEA,MAAc,mBACZ,WACA,aACe;AACf,UAAM,OAAO,MAAM,KAAK,WAAW;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,KAAK,WAAY,KAAK,IAAI;AAGhC,SAAK,aAAa;AAAA,MAChB;AAAA,MACA,mBAAmB,WAAW;AAAA,MAC9B,EAAE,YAAY,iBAAiB;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,gBACZ,KACiC;AAEjC,UAAM,WAAW,aAAa,GAAG;AAGjC,QAAI,KAAK,aAAa,UAAU,SAAS,WAAW,GAAG;AACrD,aAAO;AAAA,IACT;AAGA,QAAI,cAAc,KAAK,aAAa,aAAa,SAAS,WAAW;AACrE,QAAI,gBAAgB,MAAM;AAExB,UAAI;AACF,sBAAc,MAAM,KAAK,UAAU;AAAA,UACjC,SAAS;AAAA,UACT,KAAK;AAAA,UACL,KAAK,QAAQ;AAAA,QACf;AAAA,MACF,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,WAAW,qBAAqB,WAAW;AAGjD,QAAI;AACF,qBAAe,UAAU,QAAQ;AAAA,IACnC,SAAS,KAAK;AACZ,UAAI,eAAe,4BAA4B;AAC7C,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAMA,QAAI,CAAE,MAAM,KAAK,qBAAqB,UAAU,GAAG,GAAI;AACrD,aAAO;AAAA,IACT;AAGA,QACE,SAAS,wDACT,SAAS,sDACT,SAAS,gDACT;AACA,aAAO,KAAK,WAAW,cAAc,MAAM,UAAU,QAAQ;AAAA,IAC/D;AAGA,QAAI,KAAK,WAAW,iBAAiB,eAAe;AAClD,UAAI,CAAC,KAAK,aAAa,oBAAoB,SAAS,WAAW,GAAG;AAChE,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,uBAAiB;AAAA,QACf,SAAS;AAAA,QACT,KAAK,YAAY;AAAA,QACjB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,iBAAiB;AAClC,eAAO;AAAA,MACT;AACA,YAAM;AAAA,IACR;AAGA,WAAO,OAAO,OAAO;AAAA,MACnB,WAAW,SAAS;AAAA,MACpB,aAAa,SAAS;AAAA,MACtB,WAAW,SAAS;AAAA,MACpB,SAAS,IAAI,YAAY,EAAE,OAAO,cAAc;AAAA,MAChD,WAAW,SAAS;AAAA,MACpB,MAAM,SAAS;AAAA,MACf,UAAU,SAAS;AAAA,MACnB,SAAS,SAAS;AAAA,MAClB,WAAW,SAAS;AAAA,MACpB,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,qBACZ,UACA,KACkB;AAClB,UAAM,KAAK,SAAS;AACpB,UAAM,OAAO,SAAS;AAItB,QAAI,KAAK,aAAa,QAAQ,SAAS,cAAc,KAAK,UAAU;AAClE,UAAI;AAAA,QACF,oBAAoB,EAAE,SAAS,IAAI,iBAC9B,SAAS,SAAS,YAAY,KAAK,QAAQ;AAAA,MAClD;AACA,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,OAAO;AAIxB,UAAM,KAAK,KAAK,MAAM,SAAS,SAAS;AACxC,QAAI,OAAO,MAAM,EAAE,GAAG;AACpB,UAAI;AAAA,QACF,oBAAoB,EAAE,SAAS,IAAI,+BACjC,KAAK,UAAU,SAAS,SAAS;AAAA,MACrC;AACA,aAAO;AAAA,IACT;AACA,UAAM,aAAa,KAAK,IAAI,MAAM,EAAE,IAAI;AACxC,QACE,aAAa,oBACb,CAAE,MAAM,KAAK,WAAW,KAAK,SAAS,WAAW,IAAI,GAAG,GACxD;AACA,UAAI;AAAA,QACF,0BAA0B,EAAE,SAAS,IAAI,SAC/B,KAAK,MAAM,UAAU,CAAC,OAAO,gBAAgB;AAAA,MACzD;AACA,aAAO;AAAA,IACT;AAGA,QAAI,SAAS,YAAY,UAAa,SAAS,YAAY,MAAM;AAC/D,YAAM,MAAM,KAAK,MAAM,SAAS,OAAO;AACvC,UAAI,OAAO,MAAM,GAAG,GAAG;AACrB,YAAI;AAAA,UACF,oBAAoB,EAAE,SAAS,IAAI,6BACjC,KAAK,UAAU,SAAS,OAAO;AAAA,QACnC;AACA,eAAO;AAAA,MACT;AACA,UAAI,MAAM,KAAK;AACb,YAAI;AAAA,UACF,4BAA4B,EAAE,SAAS,IAAI,aAC7B,SAAS,OAAO;AAAA,QAChC;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,MAAM,KAAK,aAAa,aAAa,MAAM,IAAI,EAAE,GAAG;AACtD,UAAI,KAAK,6BAA6B,EAAE,SAAS,IAAI,EAAE;AACvD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,WACZ,KACA,WACA,UACA,KACkB;AAGlB,UAAM,cAAc,UAAU,MAAM,IAAI,EAAE,IAAI;AAC9C,QAAI,CAAC,aAAa,KAAK,UAAU,KAAK,WAAW,EAAG,QAAO;AAE3D,QAAI,MAAM,KAAK,aAAa,kBAAkB,QAAQ,EAAG,QAAO;AAChE,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,mBAAqC;AACjD,QAAI,KAAK,aAAc,QAAO;AAC9B,QAAI,KAAK,WAAW,IAAI,KAAK,cAAe,QAAO;AACnD,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,oBAAoB;AAChD,WAAK,eAAe,SAAS,SAAS,kBAAkB;AACxD,UAAI,CAAC,KAAK,cAAc;AACtB,aAAK,gBAAgB,KAAK,WAAW,IAAI;AAAA,MAC3C;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,UAAI,KAAK,+BAA+B,MAAM,EAAE;AAAA,IAClD;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAc,sBAA0C;AACtD,UAAM,OAAO,MAAM,MAAM,GAAG,KAAK,QAAQ,QAAQ,oBAAoB;AAAA,MACnE,QAAQ,YAAY,QAAQ,GAAM;AAAA,IACpC,CAAC;AACD,QAAI,CAAC,KAAK,GAAI,OAAM,IAAI,SAAS,kBAAkB,KAAK,MAAM,EAAE;AAChE,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACJ,QAAI;AACF,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AACA,WAAO,MAAM,QAAQ,MAAM,QAAQ,IAAI,KAAK,WAAW,CAAC;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,0BAAyC;AACrD,UAAM,UAAU,KAAK,aAAa,kBAAkB,CAAC;AACrD,eAAW,SAAS,SAAS;AAC3B,UAAI;AACF,cAAM,WAAW,KAAK,MAAM,MAAM,WAAW;AAI7C,cAAM,OAAO,oBAAoB,QAAQ;AACzC,cAAM,cAAc,qBAAqB,KAAK,SAAS;AAEvD,cAAM,cAAc,KAAK,UAAU;AAAA,UACjC,QAAQ;AAAA,UACR,eAAe,MAAM;AAAA,QACvB,CAAC;AACD,cAAM,WAAW,MAAM;AAAA,UACrB,KAAK;AAAA,UACL,MAAM;AAAA;AAAA,UAEN,IAAI,YAAY,EAAE,OAAO,WAAW;AAAA,UACpC,KAAK,YAAY;AAAA,UACjB;AAAA,QACF;AACA,cAAM,OAAO,WAAW,QAAQ;AAChC,cAAM,KAAK,WAAY,KAAK,IAAI;AAAA,MAClC,QAAQ;AAAA,MAER;AAGA,WAAK,aAAa,cAAc,MAAM,OAAO;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAc,iBAAiB,KAAqC;AAElE,QACE,IAAI,KAAK,WAAW,UAAU,KAC9B,IAAI,KAAK,WAAW,YAAY,KAChC,IAAI,KAAK,WAAW,UAAU,GAC9B;AACA;AAAA,IACF;AAEA,QAAI;AACF,YAAM,cAAc,KAAK,aAAa,aAAa,IAAI,WAAW;AAClE,UAAI,gBAAgB,KAAM;AAE1B,YAAM,WAAW,qBAAqB,WAAW;AAEjD,YAAM,iBAAiB,KAAK,UAAU;AAAA,QACpC,YAAY,IAAI;AAAA,MAClB,CAAC;AACD,YAAM,WAAW,MAAM;AAAA,QACrB,KAAK;AAAA,QACL,IAAI;AAAA;AAAA,QAEJ,IAAI,YAAY,EAAE,OAAO,cAAc;AAAA,QACvC,KAAK,YAAY;AAAA,QACjB;AAAA,QACA,EAAE,SAAS,IAAI,UAAU;AAAA,MAC3B;AAEA,YAAM,OAAO,WAAW,QAAQ;AAChC,YAAM,KAAK,WAAY,KAAK,IAAI;AAAA,IAClC,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,qBAAoC;AAChD,UAAM,OAAO;AAAA,MACX,YAAY,KAAK,QAAQ;AAAA,MACzB,YAAY,mBAAmB,KAAK,YAAY,SAAS;AAAA,IAC3D;AAEA,QAAI,OAAO,MAAM,KAAK,kBAAkB,IAAI;AAC5C,QAAI,KAAK,WAAW,KAAK;AACvB,YAAMC,WAAU,MAAM,KAAK,gBAAgB;AAC3C,aAAO,MAAM,KAAK,kBAAkB;AAAA,QAClC,GAAG;AAAA,QACH,OAAO,KAAK,mBAAmBA,QAAO;AAAA,MACxC,CAAC;AACD,UAAI,KAAK,WAAW,OAAO,KAAK,WAAW,KAAK;AAC9C,cAAM,KAAK,oBAAoBA,QAAO;AAAA,MACxC;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,YAAM,IAAI;AAAA,QACR,wBAAwB,KAAK,MAAM,IAAI,IAAI;AAAA,MAC7C;AAAA,IACF;AAEA,UAAM,OAAQ,MAAM,KAAK,KAAK;AAC9B,UAAM,UAAU,KAAK,SAAS;AAC9B,SAAK,YAAY,OAAO;AACxB,SAAK,SAAS,KAAK,OAAO;AAG1B,UAAM,EAAE,KAAK,IAAI,KAAK;AACtB,UAAM,QAAQ,KAAK;AACnB,SAAK,WAAW,SAAS,MAAM,KAAK,YAAY,UAAU,MAAM,KAAK,CAAC;AACtE,SAAK,aAAa,OAAO;AAAA,EAC3B;AAAA;AAAA,EAGA,MAAc,kBAAmC;AAC/C,UAAM,EAAE,MAAM,qBAAqB,aAAa,SAAS,IAAI,KAAK;AAClE,QAAI,wBAAwB,KAAM,QAAO,GAAG,IAAI,KAAK,mBAAmB;AAExE,UAAM,SAAS,MAAM,KAAK,kBAAkB;AAC5C,QAAI,WAAW,KAAM,QAAO,GAAG,IAAI,KAAK,WAAW;AACnD,QAAI,CAAC,KAAK,aAAa,MAAM,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,gBAAgB,QAAQ,uBAAuB,MAAM,+BACtB,KAAK,UAAU,MAAM,CAAC;AAAA,MACvD;AAAA,IACF;AACA,WAAO,GAAG,IAAI,KAAK,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,aAAa,QAAyB;AAC5C,QAAI;AACJ,QAAI;AACF,aAAO,IAAI,IAAI,KAAK,QAAQ,QAAQ,EAAE,SAAS,YAAY;AAAA,IAC7D,QAAQ;AACN,aAAO;AAAA,IACT;AACA,UAAM,SAAS,OAAO,YAAY;AAClC,WACE,SAAS,UACT,KAAK,SAAS,IAAI,MAAM,EAAE,KAC1B,SAAS,eACT,SAAS,WACT,uBAAuB,KAAK,IAAI;AAAA,EAEpC;AAAA,EAEQ,kBAAkB,MAAkD;AAC1E,WAAO,MAAM,GAAG,KAAK,QAAQ,QAAQ,oBAAoB;AAAA,MACvD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,mBAAmB,SAGzB;AACA,UAAM,YAAY,aAAa;AAC/B,UAAM,YAAY;AAAA,MAChB,IAAI,YAAY,EAAE,OAAO;AAAA,EAAoB,OAAO;AAAA,EAAK,SAAS,EAAE;AAAA,MACpE,KAAK,YAAY;AAAA,IACnB;AACA,WAAO,EAAE,WAAW,UAAU;AAAA,EAChC;AAAA,EAEQ,oBAAoB,SAA2B;AACrD,WAAO,IAAI;AAAA,MACT,yEACE;AAAA,IACJ;AAAA,EACF;AAAA;AAAA,EAGQ,aAAa,SAAuB;AAC1C,UAAM,EAAE,MAAM,SAAS,IAAI,KAAK;AAChC,SAAK;AAAA,MAAW;AAAA,MAAW,MACzB,KAAK,YAAY,YAAY,MAAM,SAAS,QAAQ;AAAA,IACtD;AAAA,EACF;AAAA;AAAA,EAGQ,WAAW,MAAc,MAAwB;AACvD,QAAI;AACF,WAAK;AAAA,IACP,SAAS,KAAK;AACZ,YAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,UAAI,KAAK,sBAAsB,IAAI,KAAK,MAAM,EAAE;AAAA,IAClD;AAAA,EACF;AAAA;AAAA,EAGQ,YAAY,SAAuB;AACzC,SAAK,WAAW;AAChB,UAAM,SAAS,aAAa,OAAO,EAAE;AACrC,SAAK,QAAQ,cAAc;AAC3B,QAAI,KAAK,qBAAqB,eAAe;AAC3C,WAAK,UAAU,cAAc;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,iBAAkC;AAC9C,UAAM,EAAE,MAAM,oBAAoB,IAAI,KAAK;AAC3C,QAAI,wBAAwB,KAAM,QAAO,GAAG,IAAI,KAAK,mBAAmB;AAExE,UAAM,QAAQ,KAAK,YAAY,YAAY,MAAM,KAAK,QAAQ,QAAQ;AACtE,QAAI,MAAO,QAAO;AAElB,UAAM,SAAS,MAAM,KAAK,kBAAkB;AAC5C,QAAI,WAAW,KAAM,QAAO,GAAG,IAAI,KAAK,KAAK,QAAQ,WAAW;AAChE,UAAM,UAAU,GAAG,IAAI,KAAK,MAAM;AAClC,SAAK,aAAa,OAAO;AACzB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,oBAA4C;AACxD,UAAM,MAAM,GAAG,KAAK,QAAQ,QAAQ;AACpC,QAAI;AACF,YAAM,OAAO,MAAM,MAAM,KAAK,EAAE,QAAQ,YAAY,QAAQ,GAAM,EAAE,CAAC;AACrE,UAAI,CAAC,KAAK,GAAI,QAAO;AACrB,YAAM,OAAQ,MAAM,KAAK,KAAK;AAC9B,YAAM,SAAS,KAAK,cAAc;AAClC,UAAI,OAAO,WAAW,YAAY,WAAW,GAAI,QAAO;AAExD,aAAO,aAAa,GAAG,KAAK,QAAQ,IAAI,KAAK,MAAM,EAAE,EAAE;AAAA,IACzD,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AuB1mCA,IAAAC,sBAA4C;AAarC,SAAS,uBACd,SACA,iBACA,QACS;AACT,MAAI,CAAC,gBAAgB,WAAW,SAAS,GAAG;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,eAAW,gCAAW,UAAU,MAAM,EACzC,OAAO,OAAO,EACd,OAAO,KAAK;AACf,QAAM,WAAW,gBAAgB,MAAM,UAAU,MAAM;AAGvD,QAAM,cAAc,OAAO,KAAK,UAAU,OAAO;AACjD,QAAM,cAAc,OAAO,KAAK,UAAU,OAAO;AAEjD,MAAI,YAAY,WAAW,YAAY,QAAQ;AAC7C,WAAO;AAAA,EACT;AAEA,aAAO,qCAAgB,aAAa,WAAW;AACjD;;;AC7CA;","names":["dnsResolveTxt","import_node_path","MessageType","sodium","import_node_crypto","buildSignableDict","import_node_fs","import_node_path","import_node_os","import_node_fs","import_node_path","Database","WebSocket","import_node_fs","import_node_path","import_promises","import_better_sqlite3","sleep","Database","generateTxtRecord","address","import_node_crypto"]}
1
+ {"version":3,"sources":["../src/sdk/dns-verifier.ts","../src/index.ts","../src/sdk/agent.ts","../src/protocol/index.ts","../src/protocol/types.ts","../src/protocol/errors.ts","../src/protocol/address.ts","../src/protocol/crypto.ts","../src/protocol/envelope.ts","../src/protocol/contact.ts","../src/protocol/signed.ts","../src/protocol/didkey.ts","../src/protocol/webauthn.ts","../src/version.ts","../src/sdk/config.ts","../src/sdk/freshness.ts","../src/sdk/key-manager.ts","../src/sdk/message.ts","../src/sdk/contact-book.ts","../src/sdk/log.ts","../src/sdk/handshake.ts","../src/sdk/resolver-base.ts","../src/sdk/tier3.ts","../src/sdk/resolver.ts","../src/sdk/transport/base.ts","../src/sdk/transport/http.ts","../src/sdk/transport/websocket.ts","../src/sdk/transport/index.ts","../src/sdk/replay-cache.ts","../src/sdk/webhook-verify.ts","../src/sdk/index.ts"],"sourcesContent":["/**\n * DNS domain verification for UAM Tier 2 addresses (DNS-01, DNS-03).\n *\n * Provides TXT record parsing, HTTPS .well-known fallback resolution,\n * and helper functions for domain ownership verification.\n *\n * TXT record format (at `_uam.{domain}`):\n *\n * v=uam1; key=ed25519:<base64-pubkey>; relay=<relay-url>\n *\n * Matches Python dns_verifier.py API surface.\n */\n\nimport { resolveTxt as dnsResolveTxt } from \"node:dns/promises\";\n\n/**\n * Parse a UAM TXT record value into tag-value pairs.\n *\n * Format: `v=uam1; key=ed25519:<base64>; relay=https://...`\n *\n * Tag names are lowercased for case-insensitive matching.\n * Unknown tags are preserved (forward compatibility).\n */\nexport function parseUamTxt(txtValue: string): Record<string, string> {\n const tags: Record<string, string> = {};\n for (const part of txtValue.split(\";\")) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n const eqIdx = trimmed.indexOf(\"=\");\n if (eqIdx !== -1) {\n const tag = trimmed.slice(0, eqIdx).trim().toLowerCase();\n const value = trimmed.slice(eqIdx + 1).trim();\n tags[tag] = value;\n }\n }\n return tags;\n}\n\n/**\n * Extract the base64 public key from parsed UAM TXT tags.\n *\n * Strips the `ed25519:` prefix. Returns `null` if the key\n * tag is missing or does not have the expected prefix.\n */\nexport function extractPublicKey(\n tags: Record<string, string>\n): string | null {\n const keyValue = tags[\"key\"] ?? \"\";\n if (keyValue.startsWith(\"ed25519:\")) {\n return keyValue.slice(\"ed25519:\".length);\n }\n return null;\n}\n\n/**\n * Query `_uam.{domain}` for UAM TXT records.\n *\n * Returns a list of TXT record values that start with `v=uam1`.\n * Returns an empty list if no matching records are found or on any\n * DNS error.\n */\nexport async function queryUamTxt(\n domain: string,\n timeout?: number\n): Promise<string[]> {\n // Node dns/promises does not support per-call timeout natively.\n // We use AbortController for cancellation.\n const controller = new AbortController();\n const timer =\n timeout != null\n ? setTimeout(() => controller.abort(), timeout)\n : undefined;\n\n try {\n const records = await dnsResolveTxt(`_uam.${domain}`);\n\n // Each record is an array of strings (multi-part TXT).\n // Concatenate parts and filter for v=uam1.\n const results: string[] = [];\n for (const parts of records) {\n const txtValue = parts.join(\"\");\n if (txtValue.trim().startsWith(\"v=uam1\")) {\n results.push(txtValue);\n }\n }\n return results;\n } catch {\n // NXDOMAIN, SERVFAIL, etc. -- return empty\n return [];\n } finally {\n if (timer != null) clearTimeout(timer);\n }\n}\n\n/**\n * Resolve an agent's public key from `.well-known/uam.json` HTTPS fallback.\n *\n * Returns the base64 public key string, or `null` if the agent is not\n * found or the request fails.\n */\nexport async function resolveKeyViaHttps(\n agentName: string,\n domain: string,\n timeout?: number\n): Promise<string | null> {\n const url = `https://${domain}/.well-known/uam.json`;\n\n try {\n const resp = await fetch(url, {\n signal: AbortSignal.timeout(timeout ?? 10000),\n });\n if (!resp.ok) return null;\n\n const data = (await resp.json()) as Record<string, unknown>;\n if (data[\"v\"] !== \"uam1\") return null;\n\n const agents = (data[\"agents\"] ?? {}) as Record<\n string,\n Record<string, unknown>\n >;\n const entry = agents[agentName];\n if (!entry) return null;\n\n let keyValue = (entry[\"key\"] as string) ?? \"\";\n if (keyValue.startsWith(\"ed25519:\")) {\n keyValue = keyValue.slice(\"ed25519:\".length);\n }\n return keyValue || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Generate the TXT record value an agent should publish at `_uam.{domain}`.\n *\n * Returns a formatted string like:\n * `v=uam1; key=ed25519:<publicKey>; relay=<relayUrl>`\n */\nexport function generateTxtRecord(\n publicKey: string,\n relayUrl: string\n): string {\n return `v=uam1; key=ed25519:${publicKey}; relay=${relayUrl}`;\n}\n","/**\n * UAM -- Universal Agent Messaging.\n *\n * Top-level package exports: Agent, ContactBook, verifyWebhookSignature,\n * ReceivedMessage, protocol.\n */\n\nexport { Agent, ContactBook, verifyWebhookSignature } from \"./sdk/index.js\";\nexport type { ReceivedMessage, SendResult, SendStatus } from \"./sdk/index.js\";\nexport { PENDING_NOTE, SEND_STATUSES, pendingNote, supports } from \"./sdk/index.js\";\nexport * as protocol from \"./protocol/index.js\";\n","/**\n * Agent class -- the primary SDK interface (SDK-01).\n *\n * Provides send(), inbox(), handshake flow, contact management,\n * trust policies, approve/deny/block/unblock.\n *\n * Matches Python agent.py API surface.\n */\n\nimport { join } from \"node:path\";\n\nimport {\n parseAddress,\n MessageType,\n MAX_ENVELOPE_AGE,\n UAMError,\n KeyPinningError,\n SignatureVerificationError,\n DecryptionError,\n sodiumReady,\n createEnvelope,\n verifyEnvelope,\n decryptPayload,\n toWireDict,\n fromWireDict,\n serializeVerifyKey,\n deserializeVerifyKey,\n signMessage,\n utcTimestamp,\n createContactCard,\n contactCardToDict,\n contactCardFromDict,\n verifyContactCard,\n type MessageEnvelope,\n} from \"../protocol/index.js\";\nimport { SDK_VERSION } from \"../version.js\";\nimport { SDKConfig } from \"./config.js\";\nimport { RELAY_META_FEATURE, relayVouches } from \"./freshness.js\";\nimport { KeyManager } from \"./key-manager.js\";\nimport { type ReceivedMessage, type SendResult, sendStatus } from \"./message.js\";\nimport { ContactBook } from \"./contact-book.js\";\nimport { HandshakeManager, bindCardToEnvelope } from \"./handshake.js\";\nimport { log } from \"./log.js\";\nimport { type AddressResolver, SmartResolver } from \"./resolver.js\";\nimport { readAnswer } from \"./transport/http.js\";\nimport { createTransport, type TransportBase } from \"./transport/index.js\";\nimport {\n PersistentReplayCache,\n DEFAULT_REPLAY_CACHE_CAPACITY,\n} from \"./replay-cache.js\";\n\n/** How long a relay's \"no\" to relay_meta is remembered. */\nconst RELAY_NO_MEMORY_MS = 60_000;\n\n/** Replay cache capacity from UAM_REPLAY_CACHE_CAPACITY (default 1000000). */\nfunction replayCacheCapacityFromEnv(): number {\n const raw = process.env[\"UAM_REPLAY_CACHE_CAPACITY\"];\n if (raw === undefined || raw === \"\") {\n return DEFAULT_REPLAY_CACHE_CAPACITY;\n }\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 1) {\n log.warn(\n `Ignoring invalid UAM_REPLAY_CACHE_CAPACITY=${JSON.stringify(raw)}; ` +\n `using ${DEFAULT_REPLAY_CACHE_CAPACITY}`\n );\n return DEFAULT_REPLAY_CACHE_CAPACITY;\n }\n return n;\n}\n\nexport class Agent {\n /** @internal */\n readonly _config: SDKConfig;\n /** @internal */\n readonly _keyManager: KeyManager;\n /** @internal */\n _transport: TransportBase | null = null;\n\n private _resolver: AddressResolver;\n private _address: string | null = null;\n private _token: string | null = null;\n private _connected: boolean = false;\n private _autoRegister: boolean;\n\n /** @internal */\n readonly _contactBook: ContactBook;\n /** @internal */\n readonly _handshake: HandshakeManager;\n\n /**\n * @internal Wall clock in ms since the epoch, used by the inbound\n * freshness/expiry checks and the replay cache. Replaceable in tests.\n */\n _clock: () => number = () => Date.now();\n\n /**\n * @internal Inbound replay cache, keyed by (from address, message id).\n * Kept on disk under the data dir, so it outlives restarts and is shared by\n * every process using it; capacity from UAM_REPLAY_CACHE_CAPACITY.\n */\n readonly _replayCache: PersistentReplayCache;\n\n /** Whether our relay has said it writes relay_meta. */\n private _relayStamps: boolean = false;\n\n /** Until when, by _monotonic, to take the relay's last no as still true. */\n private _relayNoUntil: number = 0;\n\n /** @internal Monotonic clock in ms. Replaceable in tests. */\n _monotonic: () => number = () => performance.now();\n\n /**\n * Create an Agent. No I/O happens here -- call connect() to initialize.\n */\n constructor(\n name: string,\n options?: {\n relay?: string | null;\n domain?: string | null;\n keyDir?: string | null;\n autoRegister?: boolean;\n displayName?: string | null;\n transport?: string;\n trustPolicy?: string;\n }\n ) {\n this._config = new SDKConfig({\n name,\n relayUrl: options?.relay,\n relayDomain: options?.domain ?? undefined,\n keyDir: options?.keyDir,\n displayName: options?.displayName ?? name,\n transportType: options?.transport ?? \"websocket\",\n trustPolicy: options?.trustPolicy ?? \"auto-accept\",\n });\n this._keyManager = new KeyManager(this._config.keyDir);\n this._resolver = new SmartResolver(this._config.relayDomain);\n this._autoRegister = options?.autoRegister ?? true;\n\n // Contact management\n this._contactBook = new ContactBook(this._config.dataDir);\n this._handshake = new HandshakeManager(\n this._contactBook,\n this._config.trustPolicy\n );\n\n this._replayCache = new PersistentReplayCache(\n join(this._config.dataDir, \"replay\", \"replay.db\"),\n {\n capacity: replayCacheCapacityFromEnv(),\n now: () => this._clock(),\n }\n );\n }\n\n // -- Properties ----------------------------------------------------------\n\n /** The agent's full UAM address (e.g., 'myagent::youam.network'). */\n get address(): string {\n if (this._address === null) {\n throw new Error(\n \"Agent not yet connected. Call await agent.connect() first.\"\n );\n }\n return this._address;\n }\n\n /** UAM SDK version. */\n get version(): string {\n return SDK_VERSION;\n }\n\n /** The agent's public key (base64-encoded Ed25519 verify key). */\n get publicKey(): string {\n return serializeVerifyKey(this._keyManager.verifyKey);\n }\n\n /** Whether the agent has completed connection setup. */\n get isConnected(): boolean {\n return this._connected;\n }\n\n /**\n * Generate and return a signed contact card for this agent.\n */\n async contactCard(): Promise<Record<string, unknown>> {\n if (!this._connected) {\n throw new Error(\"Agent not connected. Call connect() first.\");\n }\n const card = await createContactCard(\n this._address!,\n this._config.displayName,\n this._config.relayWsUrl,\n this._keyManager.signingKey\n );\n return contactCardToDict(card);\n }\n\n // -- Lifecycle -----------------------------------------------------------\n\n /**\n * Initialize the agent: load/generate keys, register, connect transport.\n *\n * Idempotent -- calling twice is safe.\n */\n async connect(): Promise<void> {\n if (this._connected) {\n return;\n }\n\n // 0. Ensure sodium is ready\n await sodiumReady;\n\n // 1. Load or generate keypair\n this._keyManager.loadOrGenerate(this._config.name);\n\n // Before registering, so its created_at predates anything signed to a\n // new agent. It opens itself on first use if this fails.\n try {\n await this._replayCache.open();\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n log.warn(`Could not open the replay cache: ${reason}`);\n }\n\n // 2. Check for stored token (returning user)\n const storedToken = this._keyManager.loadToken(\n this._config.name,\n this._config.relayUrl\n );\n\n if (storedToken) {\n // Returning user: use stored token\n this._token = storedToken;\n this._useAddress(await this._storedAddress());\n } else if (this._autoRegister) {\n // First-run: register with relay\n await this._registerWithRelay();\n } else {\n throw new UAMError(\n \"No stored token and autoRegister=false. \" +\n \"Register manually or set autoRegister=true.\"\n );\n }\n\n // 3. Create and connect transport\n this._transport = createTransport(\n this._config,\n this._token!,\n this._address!\n );\n await this._transport.connect();\n\n // 4. Open contact book\n this._contactBook.open();\n\n this._connected = true;\n\n // 5. Sweep expired handshakes (HAND-03)\n await this._sweepExpiredHandshakes();\n }\n\n /**\n * Disconnect the transport and clean up resources.\n */\n async close(): Promise<void> {\n // Close contact book first\n this._contactBook.close();\n await this._replayCache.close();\n if (this._transport) {\n await this._transport.disconnect();\n }\n this._connected = false;\n }\n\n // -- Messaging -----------------------------------------------------------\n\n /**\n * Send an encrypted, signed message.\n *\n * Returns the message id with what the relay did with it: `status`\n * \"pending\" means the recipient only takes approved contacts, and the\n * message was not kept (don't resend it). `delivered` is true only when\n * the relay says the recipient has it.\n */\n async send(\n toAddress: string,\n message: string,\n options?: {\n threadId?: string;\n attachments?: Array<Record<string, unknown>>;\n }\n ): Promise<SendResult> {\n await this._ensureConnected();\n\n // TOFU-05: require_verify blocks unverified first sends\n if (this._config.trustPolicy === \"require_verify\") {\n const trust = this._contactBook.getTrustState(toAddress);\n if (trust !== \"pinned\" && trust !== \"verified\") {\n throw new UAMError(\n `Trust policy 'require_verify' requires fingerprint ` +\n `verification before sending to ${toAddress}. ` +\n `Run: uam contact verify ${toAddress}`\n );\n }\n }\n\n // Resolve recipient's verify key (Ed25519). Read-only: the contact book\n // is not touched here.\n const recipientVk = await this._resolvePublicKey(toAddress);\n\n // Fire a handshake.request unless the key is already confirmed\n // (pinned/verified/trusted) or a request is already in flight\n // (handshake-sent). Any other state -- no row, provisional, unknown --\n // means the handshake never went out (or was lost). Gated on trust\n // state rather than row presence, as in the Python SDK.\n const trustState = this._contactBook.getTrustState(toAddress);\n if (\n trustState !== \"pinned\" &&\n trustState !== \"verified\" &&\n trustState !== \"trusted\" &&\n trustState !== \"handshake-sent\"\n ) {\n await this._initiateHandshake(toAddress, recipientVk);\n }\n\n // Create signed, encrypted envelope\n const envelope = await createEnvelope(\n this._address!,\n toAddress,\n MessageType.MESSAGE,\n new TextEncoder().encode(message),\n this._keyManager.signingKey,\n recipientVk,\n {\n threadId: options?.threadId,\n mediaType: \"text/plain\",\n attachments: options?.attachments,\n }\n );\n\n // Send via transport (with multi-relay failover -- CARD-06)\n const wire = toWireDict(envelope);\n const relayUrls = await this._getRelayUrls(toAddress);\n let answer: Record<string, unknown> | null;\n if (\n relayUrls !== null &&\n relayUrls.length === 1 &&\n relayUrls[0] === this._config.relayUrl\n ) {\n // Same relay -- use existing transport (no failover overhead)\n answer = await this._transport!.send(wire);\n } else if (relayUrls !== null && relayUrls.length > 0) {\n // Multi-relay or cross-relay: try each in order\n answer = await this._trySendWithFailover(wire, relayUrls);\n } else {\n // No relay info -- fall back to own transport\n answer = await this._transport!.send(wire);\n }\n\n const status = sendStatus(answer);\n return {\n messageId: envelope.messageId,\n status,\n delivered: status === \"delivered\",\n };\n }\n\n /**\n * Retrieve, decrypt, and verify pending messages.\n *\n * Returns a list of ReceivedMessage data objects.\n * Drops messages with invalid signatures or decryption errors. A message\n * that fails processing for any other reason (malformed envelope, bad\n * handshake payload, ...) is logged and dropped; it never aborts the\n * rest of the batch.\n */\n async inbox(limit: number = 50): Promise<ReceivedMessage[]> {\n await this._ensureConnected();\n\n // Sweep expired handshakes\n await this._sweepExpiredHandshakes();\n\n const rawMessages = await this._transport!.receive(limit);\n const result: ReceivedMessage[] = [];\n for (const raw of rawMessages) {\n let msg: ReceivedMessage | null;\n try {\n msg = await this._processInbound(raw);\n } catch (err) {\n log.warn(\n `Dropping inbound message ${String(raw[\"message_id\"])} from ` +\n `${String(raw[\"from\"])}: ` +\n `${err instanceof Error ? err.message : String(err)}`\n );\n continue;\n }\n if (msg !== null) {\n result.push(msg);\n // Auto-send receipt.read for user messages (RCPT-01)\n await this._sendReadReceipt(msg);\n }\n }\n return result;\n }\n\n // -- Trust management (HAND-02, HAND-04) ---------------------------------\n\n /** List pending handshake requests. */\n async pending(): Promise<Array<{ address: string; contactCard: string; receivedAt: string }>> {\n await this._ensureConnected();\n return this._contactBook.getPending();\n }\n\n /**\n * Approve a pending handshake request.\n *\n * Adds the sender to contacts with trust_source='explicit-approval'\n * and sends handshake.accept back.\n */\n async approve(address: string): Promise<void> {\n await this._ensureConnected();\n\n const pendingList = this._contactBook.getPending();\n const entry = pendingList.find((p) => p.address === address);\n if (!entry) {\n throw new UAMError(`No pending handshake from ${address}`);\n }\n\n // Parse and verify the stored contact card\n const cardDict = JSON.parse(entry.contactCard) as Record<string, unknown>;\n const card = contactCardFromDict(cardDict);\n verifyContactCard(card);\n\n // Re-bind the stored card to the address the request arrived from (the\n // pending row's key). Rows stored before request-side binding existed\n // may carry a card for a different address; never promote those.\n const senderVk = deserializeVerifyKey(card.publicKey);\n bindCardToEnvelope(card, { fromAddress: address }, senderVk);\n\n // Add to contacts with trust_source tracking\n this._contactBook.addContact(card.address, card.publicKey, {\n displayName: card.displayName,\n trustState: \"trusted\",\n trustSource: \"explicit-approval\",\n });\n\n // Remove from pending\n this._contactBook.removePending(address);\n\n // Send handshake.accept back\n await this._handshake._sendAccept(this, address, senderVk);\n }\n\n /**\n * Deny a pending handshake request.\n *\n * Removes the entry from pending and sends handshake.deny.\n */\n async deny(address: string): Promise<void> {\n await this._ensureConnected();\n\n const pendingList = this._contactBook.getPending();\n const entry = pendingList.find((p) => p.address === address);\n if (!entry) {\n throw new UAMError(`No pending handshake from ${address}`);\n }\n\n // Parse contact card for sender's public key\n const cardDict = JSON.parse(entry.contactCard) as Record<string, unknown>;\n const card = contactCardFromDict(cardDict);\n const senderVk = deserializeVerifyKey(card.publicKey);\n\n // Remove from pending\n this._contactBook.removePending(address);\n\n // Send handshake.deny\n await this._handshake._sendDeny(this, address, senderVk);\n }\n\n /**\n * Block an address or domain pattern (HAND-04).\n */\n async block(pattern: string): Promise<void> {\n await this._ensureConnected();\n this._contactBook.addBlock(pattern);\n }\n\n /**\n * Remove a block pattern (HAND-04).\n */\n async unblock(pattern: string): Promise<void> {\n await this._ensureConnected();\n this._contactBook.removeBlock(pattern);\n }\n\n // -- Domain verification (DNS-02) ----------------------------------------\n\n /**\n * Verify domain ownership via relay endpoint (DNS-02).\n *\n * Polls `POST /api/v1/verify-domain` until the relay confirms\n * DNS TXT (or HTTPS fallback) verification succeeds, or timeout\n * elapses.\n *\n * Returns `true` if verified, `false` on timeout.\n */\n async verifyDomain(\n domain: string,\n options?: { timeout?: number; pollInterval?: number }\n ): Promise<boolean> {\n const { generateTxtRecord } = await import(\"./dns-verifier.js\");\n await this._ensureConnected();\n\n const timeout = options?.timeout ?? 300000; // 5 minutes\n const pollInterval = options?.pollInterval ?? 10000; // 10 seconds\n\n const expectedTxt = generateTxtRecord(\n this.publicKey,\n this._config.relayUrl\n );\n // Log expected TXT for user reference (they need to publish this)\n void expectedTxt;\n\n const start = Date.now();\n while (Date.now() - start < timeout) {\n try {\n const resp = await fetch(\n `${this._config.relayUrl}/api/v1/verify-domain`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._token}`,\n },\n body: JSON.stringify({ domain }),\n signal: AbortSignal.timeout(30000),\n }\n );\n if (resp.ok) {\n const result = (await resp.json()) as Record<string, unknown>;\n if (result[\"status\"] === \"verified\") {\n return true;\n }\n }\n } catch {\n // Request failed, retry after poll interval\n }\n await new Promise((resolve) => setTimeout(resolve, pollInterval));\n }\n\n return false;\n }\n\n // -- Internal methods ----------------------------------------------------\n\n /** Multi-relay failover (CARD-06). */\n private async _getRelayUrls(toAddress: string): Promise<string[] | null> {\n const urls = this._contactBook.getRelayUrls(toAddress);\n if (urls !== null) {\n return urls;\n }\n return [this._config.relayUrl];\n }\n\n /**\n * Try sending wire envelope to each relay URL in order (CARD-06).\n *\n * Uses transient fetch POST requests so the envelope can be delivered\n * to any relay that hosts the recipient.\n */\n private async _trySendWithFailover(\n wire: Record<string, unknown>,\n relayUrls: string[]\n ): Promise<Record<string, unknown> | null> {\n let lastError: Error | null = null;\n\n for (const url of relayUrls) {\n // Normalize: strip trailing '/ws', convert ws:// -> http://\n let base = url.replace(/\\/+$/, \"\");\n if (base.endsWith(\"/ws\")) {\n base = base.slice(0, -3);\n }\n base = base.replace(\"wss://\", \"https://\").replace(\"ws://\", \"http://\");\n const sendUrl = `${base}/api/v1/send`;\n\n try {\n const resp = await fetch(sendUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._token}`,\n },\n body: JSON.stringify({ envelope: wire }),\n signal: AbortSignal.timeout(10000),\n });\n if (!resp.ok) {\n throw new Error(`HTTP ${resp.status}`);\n }\n return await readAnswer(resp); // Success\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n }\n }\n\n if (lastError !== null) {\n throw lastError;\n }\n throw new UAMError(\"No relay URLs to try\");\n }\n\n private async _ensureConnected(): Promise<void> {\n if (!this._connected) {\n await this.connect();\n }\n }\n\n /**\n * Resolve a recipient's public key, checking contact book first.\n *\n * Pure lookup: never writes to the contact book. The contact row is\n * created by _initiateHandshake (as \"handshake-sent\") once the request\n * has gone out, giving the lifecycle no row -> handshake-sent -> pinned.\n *\n * TOFU-01: Known contacts always use stored key (zero network I/O).\n * TOFU-03: Race-condition double-check after network resolve.\n * Raises KeyPinningError if a pinned contact's key doesn't match.\n */\n private async _resolvePublicKey(toAddress: string): Promise<Uint8Array> {\n // TOFU-01: Check contact book first (local-first, zero network I/O)\n const pkStr = this._contactBook.getPublicKey(toAddress);\n if (pkStr !== null) {\n // Known contact: always use stored key\n return deserializeVerifyKey(pkStr);\n }\n\n // Unknown contact: resolve from network\n const resolvedPkStr = await this._resolver.resolvePublicKey(\n toAddress,\n this._token!,\n this._config.relayUrl\n );\n\n // TOFU-03: Double-check no pinned key exists (race condition guard)\n const storedPk = this._contactBook.getPublicKey(toAddress);\n if (storedPk !== null && storedPk !== resolvedPkStr) {\n const trust = this._contactBook.getTrustState(toAddress);\n if (trust === \"pinned\" || trust === \"trusted\" || trust === \"verified\") {\n throw new KeyPinningError(\n `CRITICAL: Public key mismatch for ${toAddress}! ` +\n `Stored key does not match resolved key. ` +\n `This may indicate a relay MITM attack. ` +\n `To accept the new key: uam contact remove ${toAddress}`\n );\n }\n }\n\n return deserializeVerifyKey(resolvedPkStr);\n }\n\n private async _initiateHandshake(\n toAddress: string,\n recipientVk: Uint8Array\n ): Promise<void> {\n const wire = await this._handshake.createHandshakeRequest(\n this,\n toAddress,\n recipientVk\n );\n await this._transport!.send(wire);\n\n // Mark as handshake-sent in contact book\n this._contactBook.addContact(\n toAddress,\n serializeVerifyKey(recipientVk),\n { trustState: \"handshake-sent\" }\n );\n }\n\n /**\n * Process a single inbound envelope: verify, decrypt, handle handshakes.\n *\n * Returns null for invalid messages or handshake protocol messages.\n */\n private async _processInbound(\n raw: Record<string, unknown>\n ): Promise<ReceivedMessage | null> {\n // Parse envelope\n const envelope = fromWireDict(raw);\n\n // Check block list BEFORE expensive crypto (HAND-04)\n if (this._contactBook.isBlocked(envelope.fromAddress)) {\n return null;\n }\n\n // Look up sender's public key for verification\n let senderPkStr = this._contactBook.getPublicKey(envelope.fromAddress);\n if (senderPkStr === null) {\n // Unknown sender -- try resolving from relay\n try {\n senderPkStr = await this._resolver.resolvePublicKey(\n envelope.fromAddress,\n this._token!,\n this._config.relayUrl\n );\n } catch {\n return null;\n }\n }\n\n const senderVk = deserializeVerifyKey(senderPkStr);\n\n // Verify signature (SEC-03: mandatory)\n try {\n verifyEnvelope(envelope, senderVk);\n } catch (err) {\n if (err instanceof SignatureVerificationError) {\n return null; // Silently reject unsigned/invalid messages\n }\n throw err;\n }\n\n // Envelope checks, all AFTER signature verification so unauthenticated\n // input can never touch the replay cache. Order: recipient, freshness,\n // expiry, replay. The replay cache is the only stateful check and runs\n // last, so an envelope rejected by an earlier check records nothing.\n if (!(await this._passesInboundChecks(envelope, raw))) {\n return null;\n }\n\n // Handle handshake messages (not user-visible)\n if (\n envelope.type === MessageType.HANDSHAKE_REQUEST ||\n envelope.type === MessageType.HANDSHAKE_ACCEPT ||\n envelope.type === MessageType.HANDSHAKE_DENY\n ) {\n return this._handshake.handleInbound(this, envelope, senderVk);\n }\n\n // For non-auto-accept policies, filter messages from unapproved senders\n if (this._handshake._trustPolicy !== \"auto-accept\") {\n if (!this._contactBook.isTrustedOrVerified(envelope.fromAddress)) {\n return null;\n }\n }\n\n // Decrypt payload (SEC-04: mandatory)\n let plaintextBytes: Uint8Array;\n try {\n plaintextBytes = decryptPayload(\n envelope.payload,\n this._keyManager.signingKey,\n senderVk\n );\n } catch (err) {\n if (err instanceof DecryptionError) {\n return null;\n }\n throw err;\n }\n\n // Build ReceivedMessage data object\n return Object.freeze({\n messageId: envelope.messageId,\n fromAddress: envelope.fromAddress,\n toAddress: envelope.toAddress,\n content: new TextDecoder().decode(plaintextBytes),\n timestamp: envelope.timestamp,\n type: envelope.type,\n threadId: envelope.threadId,\n replyTo: envelope.replyTo,\n mediaType: envelope.mediaType,\n verified: true,\n });\n }\n\n /**\n * Recipient, freshness, expiry and replay checks for a signature-verified\n * inbound envelope. Returns false (and logs) when it must be dropped.\n * Matches the Python SDK's _process_inbound checks.\n */\n private async _passesInboundChecks(\n envelope: MessageEnvelope,\n raw: Record<string, unknown>\n ): Promise<boolean> {\n const id = envelope.messageId;\n const from = envelope.fromAddress;\n\n // (a) Recipient: drop envelopes addressed to someone else. Skipped when\n // no address is set yet (callers driving _processInbound directly).\n if (this._address !== null && envelope.toAddress !== this._address) {\n log.warn(\n `Dropped envelope ${id} from ${from} addressed to ` +\n `${envelope.toAddress} (we are ${this._address})`\n );\n return false;\n }\n\n const now = this._clock();\n\n // (b) Freshness: |now - timestamp| <= MAX_ENVELOPE_AGE, unless it's\n // stored mail.\n const ts = Date.parse(envelope.timestamp);\n if (Number.isNaN(ts)) {\n log.warn(\n `Dropped envelope ${id} from ${from} with malformed timestamp ` +\n JSON.stringify(envelope.timestamp)\n );\n return false;\n }\n const ageSeconds = Math.abs(now - ts) / 1000;\n if (\n ageSeconds > MAX_ENVELOPE_AGE &&\n !(await this._wasStored(raw, envelope.toAddress, ts, now))\n ) {\n log.info(\n `Dropped stale envelope ${id} from ${from} ` +\n `(age=${Math.round(ageSeconds)}s > ${MAX_ENVELOPE_AGE}s)`\n );\n return false;\n }\n\n // (c) Expiry.\n if (envelope.expires !== undefined && envelope.expires !== null) {\n const exp = Date.parse(envelope.expires);\n if (Number.isNaN(exp)) {\n log.warn(\n `Dropped envelope ${id} from ${from} with malformed expires ` +\n JSON.stringify(envelope.expires)\n );\n return false;\n }\n if (now > exp) {\n log.info(\n `Dropped expired envelope ${id} from ${from} ` +\n `(expires=${envelope.expires})`\n );\n return false;\n }\n }\n\n // (d) Replay: must stay last (the only check that records state).\n if (await this._replayCache.seenOrRecord(from, id, ts)) {\n log.info(`Dropped replayed envelope ${id} from ${from}`);\n return false;\n }\n\n return true;\n }\n\n /** True if a message too old to be live is stored mail, not a replay. */\n private async _wasStored(\n raw: Record<string, unknown>,\n toAddress: string,\n signedAt: number,\n now: number\n ): Promise<boolean> {\n // The signed address names our relay. _config.relayDomain may not: it can\n // be the URL's hostname, and youam.network is relay.youam.network.\n const relayDomain = toAddress.split(\"::\").pop()!;\n if (!relayVouches(raw, signedAt, now, relayDomain)) return false;\n // The replay cache can't speak for what came before it existed.\n if (await this._replayCache.signedBeforeCache(signedAt)) return false;\n return this._relayStampsMail();\n }\n\n /**\n * True if our relay writes relay_meta, so a sender can't have.\n *\n * Asked only when a stale message carries a stamp. A yes is remembered for\n * good, a no for RELAY_NO_MEMORY_MS: a relay can be upgraded while this\n * agent runs. A failed lookup isn't remembered, because the relay has\n * already marked this mail delivered and the next message should get a\n * real answer.\n */\n private async _relayStampsMail(): Promise<boolean> {\n if (this._relayStamps) return true;\n if (this._monotonic() < this._relayNoUntil) return false;\n try {\n const features = await this._fetchRelayFeatures();\n this._relayStamps = features.includes(RELAY_META_FEATURE);\n if (!this._relayStamps) {\n this._relayNoUntil = this._monotonic() + RELAY_NO_MEMORY_MS;\n }\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n log.warn(`Cannot read relay features: ${reason}`);\n }\n return this._relayStamps;\n }\n\n /** The relay's features; a body that doesn't list any is an empty list. */\n private async _fetchRelayFeatures(): Promise<unknown[]> {\n const resp = await fetch(`${this._config.relayUrl}/api/v1/versions`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!resp.ok) throw new UAMError(`Relay answered ${resp.status}`);\n const body = await resp.text();\n let data: { features?: unknown } | null;\n try {\n data = JSON.parse(body) as { features?: unknown } | null;\n } catch {\n return [];\n }\n return Array.isArray(data?.features) ? data.features : [];\n }\n\n /**\n * Sweep expired pending handshakes and send receipt.failed (HAND-03).\n */\n private async _sweepExpiredHandshakes(): Promise<void> {\n const expired = this._contactBook.getExpiredPending(7);\n for (const entry of expired) {\n try {\n const cardDict = JSON.parse(entry.contactCard) as Record<\n string,\n unknown\n >;\n const card = contactCardFromDict(cardDict);\n const recipientVk = deserializeVerifyKey(card.publicKey);\n\n const failPayload = JSON.stringify({\n reason: \"handshake_expired\",\n original_from: entry.address,\n });\n const envelope = await createEnvelope(\n this._address!,\n entry.address,\n MessageType.RECEIPT_FAILED,\n new TextEncoder().encode(failPayload),\n this._keyManager.signingKey,\n recipientVk\n );\n const wire = toWireDict(envelope);\n await this._transport!.send(wire);\n } catch {\n // Failed to send receipt.failed -- ignore\n }\n\n // Remove from pending regardless\n this._contactBook.removePending(entry.address);\n }\n }\n\n /**\n * Send receipt.read back to the sender (RCPT-01).\n *\n * Fire-and-forget: errors are never propagated.\n * Anti-loop guard: receipts, handshakes, and session messages are skipped.\n */\n private async _sendReadReceipt(msg: ReceivedMessage): Promise<void> {\n // Anti-loop: never generate receipts for protocol messages\n if (\n msg.type.startsWith(\"receipt.\") ||\n msg.type.startsWith(\"handshake.\") ||\n msg.type.startsWith(\"session.\")\n ) {\n return;\n }\n\n try {\n const senderPkStr = this._contactBook.getPublicKey(msg.fromAddress);\n if (senderPkStr === null) return;\n\n const senderVk = deserializeVerifyKey(senderPkStr);\n\n const receiptPayload = JSON.stringify({\n message_id: msg.messageId,\n });\n const envelope = await createEnvelope(\n this._address!,\n msg.fromAddress,\n MessageType.RECEIPT_READ,\n new TextEncoder().encode(receiptPayload),\n this._keyManager.signingKey,\n senderVk,\n { replyTo: msg.messageId }\n );\n\n const wire = toWireDict(envelope);\n await this._transport!.send(wire);\n } catch {\n // Fire-and-forget\n }\n }\n\n /**\n * Register with the relay server.\n *\n * Calls POST /api/v1/register with agent name and public key. If the\n * address exists (409), repeats it with a proof that this agent holds the\n * key. Stores the returned API key on disk.\n */\n private async _registerWithRelay(): Promise<void> {\n const body = {\n agent_name: this._config.name,\n public_key: serializeVerifyKey(this._keyManager.verifyKey),\n };\n\n let resp = await this._postRegistration(body);\n if (resp.status === 409) {\n const address = await this._addressOnRelay();\n resp = await this._postRegistration({\n ...body,\n proof: this._registrationProof(address),\n });\n if (resp.status === 409 || resp.status === 403) {\n throw this._ownershipNotProven(address);\n }\n }\n\n if (!resp.ok) {\n const text = await resp.text();\n throw new UAMError(\n `Registration failed: ${resp.status} ${text}`\n );\n }\n\n const data = (await resp.json()) as Record<string, unknown>;\n const address = data[\"address\"] as string;\n this._useAddress(address);\n this._token = data[\"token\"] as string;\n\n // Persist for the returning-user flow\n const { name } = this._config;\n const token = this._token;\n this._tryToSave(\"token\", () => this._keyManager.saveToken(name, token));\n this._saveAddress(address);\n }\n\n /** This agent's address on the relay, for signing a proof. */\n private async _addressOnRelay(): Promise<string> {\n const { name, explicitRelayDomain, relayDomain, relayUrl } = this._config;\n if (explicitRelayDomain !== null) return `${name}::${explicitRelayDomain}`;\n\n const domain = await this._fetchRelayDomain();\n if (domain === null) return `${name}::${relayDomain}`;\n if (!this._relayMayUse(domain)) {\n throw new UAMError(\n `The relay at ${relayUrl} says its domain is ${domain}. ` +\n `Pass the domain option as ${JSON.stringify(domain)} if that is right.`\n );\n }\n return `${name}::${domain}`;\n }\n\n /**\n * True if the relay's URL fits `domain`, so a proof can be signed for it.\n *\n * A proof names an address on one relay, so it is only signed for a domain\n * this URL belongs to. A relay on this machine may use any domain.\n */\n private _relayMayUse(domain: string): boolean {\n let host: string;\n try {\n host = new URL(this._config.relayUrl).hostname.toLowerCase();\n } catch {\n return false;\n }\n const wanted = domain.toLowerCase();\n return (\n host === wanted ||\n host.endsWith(`.${wanted}`) ||\n host === \"localhost\" ||\n host === \"[::1]\" ||\n /^127\\.\\d+\\.\\d+\\.\\d+$/.test(host)\n );\n }\n\n private _postRegistration(body: Record<string, unknown>): Promise<Response> {\n return fetch(`${this._config.relayUrl}/api/v1/register`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n }\n\n /**\n * Sign a statement that this agent holds the key for `address`.\n *\n * The signed string must stay byte-identical to the Python SDK's.\n */\n private _registrationProof(address: string): {\n timestamp: string;\n signature: string;\n } {\n const timestamp = utcTimestamp();\n const signature = signMessage(\n new TextEncoder().encode(`uam-register-v1\\n${address}\\n${timestamp}`),\n this._keyManager.signingKey\n );\n return { timestamp, signature };\n }\n\n private _ownershipNotProven(address: string): UAMError {\n return new UAMError(\n `Address already registered, and this key could not prove ownership: ` +\n address\n );\n }\n\n /** Remember `address` for this relay, if the key folder allows it. */\n private _saveAddress(address: string): void {\n const { name, relayUrl } = this._config;\n this._tryToSave(\"address\", () =>\n this._keyManager.saveAddress(name, address, relayUrl)\n );\n }\n\n /** Saving is best effort: a key folder we can't write doesn't stop us. */\n private _tryToSave(what: string, save: () => void): void {\n try {\n save();\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n log.warn(`Could not save the ${what}: ${reason}`);\n }\n }\n\n /** Take `address` as ours; its domain is this relay's real domain. */\n private _useAddress(address: string): void {\n this._address = address;\n const domain = parseAddress(address).domain;\n this._config.relayDomain = domain;\n if (this._resolver instanceof SmartResolver) {\n this._resolver.relayDomain = domain;\n }\n }\n\n /**\n * The address the stored token belongs to.\n *\n * An explicit domain settles it. Otherwise the relay chooses the domain,\n * and it need not be the relay's hostname: use the address saved for this\n * relay, or ask the relay once and keep the answer.\n */\n private async _storedAddress(): Promise<string> {\n const { name, explicitRelayDomain } = this._config;\n if (explicitRelayDomain !== null) return `${name}::${explicitRelayDomain}`;\n\n const saved = this._keyManager.loadAddress(name, this._config.relayUrl);\n if (saved) return saved;\n\n const domain = await this._fetchRelayDomain();\n if (domain === null) return `${name}::${this._config.relayDomain}`;\n const address = `${name}::${domain}`;\n this._saveAddress(address);\n return address;\n }\n\n /** Ask the relay for its domain; null if it cannot say. */\n private async _fetchRelayDomain(): Promise<string | null> {\n const url = `${this._config.relayUrl}/.well-known/uam-relay.json`;\n try {\n const resp = await fetch(url, { signal: AbortSignal.timeout(10_000) });\n if (!resp.ok) return null;\n const data = (await resp.json()) as Record<string, unknown>;\n const domain = data[\"relay_domain\"];\n if (typeof domain !== \"string\" || domain === \"\") return null;\n // Throws, so counts as no answer, if it can't form an address.\n return parseAddress(`${this._config.name}::${domain}`).domain;\n } catch {\n return null;\n }\n }\n}\n","/**\n * UAM Protocol -- Universal Agent Messaging protocol library.\n *\n * Public API re-exports for the protocol layer.\n */\n\n// Types\nexport {\n UAM_VERSION,\n MAX_ENVELOPE_SIZE,\n MAX_ENVELOPE_AGE,\n MessageType,\n b64Encode,\n b64Decode,\n utcTimestamp,\n} from \"./types.js\";\n\n// Errors\nexport {\n UAMError,\n InvalidAddressError,\n InvalidEnvelopeError,\n EnvelopeTooLargeError,\n SignatureError,\n SignatureVerificationError,\n EncryptionError,\n DecryptionError,\n InvalidContactCardError,\n KeyPinningError,\n SendRefusedError,\n} from \"./errors.js\";\n\n// Address\nexport { type Address, parseAddress } from \"./address.js\";\n\n// Crypto\nexport {\n sodiumReady,\n type SigningKey,\n type VerifyKey,\n type Seed,\n type Keypair,\n generateKeypair,\n serializeSigningKey,\n deserializeSigningKey,\n serializeVerifyKey,\n deserializeVerifyKey,\n publicKeyFingerprint,\n canonicalize,\n signMessage,\n verifySignature,\n generateNonce,\n encryptPayload,\n decryptPayload,\n encryptPayloadAnonymous,\n decryptPayloadAnonymous,\n} from \"./crypto.js\";\n\n// Envelope\nexport {\n type MessageEnvelope,\n createEnvelope,\n verifyEnvelope,\n toWireDict,\n fromWireDict,\n validateEnvelopeSize,\n} from \"./envelope.js\";\n\n// Contact\nexport {\n type ContactCard,\n createContactCard,\n verifyContactCard,\n contactCardToDict,\n contactCardFromDict,\n} from \"./contact.js\";\n\n// Signed owner objects\nexport {\n type Body as SignedBody,\n SignedObjectError,\n parseBody,\n canonical,\n objectHash,\n validate as validateSignedObject,\n} from \"./signed.js\";\nexport {\n type DidKeyKind,\n InvalidDidKeyError,\n encodeDidKey,\n decodeDidKey,\n} from \"./didkey.js\";\nexport {\n type Credential as PasskeyCredential,\n WebAuthnError,\n verifyRegistration,\n verifyAssertion,\n approvalChallenge,\n credentialDid,\n} from \"./webauthn.js\";\n","/**\n * Core types, constants, and utility functions for UAM protocol.\n */\n\n/** Protocol version. */\nexport const UAM_VERSION = \"0.1\";\n\n/** Maximum envelope size in bytes (64 KB). */\nexport const MAX_ENVELOPE_SIZE = 65536;\n\n/**\n * Maximum allowed skew, in seconds, between an inbound envelope's signed\n * timestamp and the receiver's clock (either direction). Also the TTL of\n * the inbound replay cache. Matches Python MAX_ENVELOPE_AGE.\n */\nexport const MAX_ENVELOPE_AGE = 300;\n\n/** All UAM message types. */\nexport enum MessageType {\n MESSAGE = \"message\",\n HANDSHAKE_REQUEST = \"handshake.request\",\n HANDSHAKE_ACCEPT = \"handshake.accept\",\n HANDSHAKE_DENY = \"handshake.deny\",\n RECEIPT_DELIVERED = \"receipt.delivered\",\n RECEIPT_READ = \"receipt.read\",\n RECEIPT_FAILED = \"receipt.failed\",\n SESSION_REQUEST = \"session.request\",\n SESSION_ACCEPT = \"session.accept\",\n SESSION_DECLINE = \"session.decline\",\n SESSION_END = \"session.end\",\n}\n\n/**\n * URL-safe base64 encode, stripping padding.\n */\nexport function b64Encode(data: Uint8Array): string {\n return Buffer.from(data).toString(\"base64url\");\n}\n\n/**\n * URL-safe base64 decode, tolerating missing padding.\n */\nexport function b64Decode(s: string): Uint8Array {\n return new Uint8Array(Buffer.from(s, \"base64url\"));\n}\n\n/**\n * Return a canonical UTC timestamp: YYYY-MM-DDTHH:MM:SS.mmmZ\n */\nexport function utcTimestamp(): string {\n return new Date().toISOString();\n}\n","/**\n * UAM exception hierarchy.\n *\n * All protocol-specific errors inherit from UAMError.\n */\n\n/** Base error for all UAM protocol errors. */\nexport class UAMError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"UAMError\";\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Raised when an address string fails validation. */\nexport class InvalidAddressError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidAddressError\";\n }\n}\n\n/** Raised when an envelope fails schema validation. */\nexport class InvalidEnvelopeError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidEnvelopeError\";\n }\n}\n\n/** Raised when an envelope exceeds the maximum allowed size. */\nexport class EnvelopeTooLargeError extends InvalidEnvelopeError {\n constructor(message?: string) {\n super(message);\n this.name = \"EnvelopeTooLargeError\";\n }\n}\n\n/** Raised on signing failures. */\nexport class SignatureError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"SignatureError\";\n }\n}\n\n/** Raised when a cryptographic signature cannot be verified. */\nexport class SignatureVerificationError extends SignatureError {\n constructor(message?: string) {\n super(message);\n this.name = \"SignatureVerificationError\";\n }\n}\n\n/** Raised on encryption failures. */\nexport class EncryptionError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"EncryptionError\";\n }\n}\n\n/** Raised on decryption failures. */\nexport class DecryptionError extends EncryptionError {\n constructor(message?: string) {\n super(message);\n this.name = \"DecryptionError\";\n }\n}\n\n/** Raised when a contact card fails validation. */\nexport class InvalidContactCardError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidContactCardError\";\n }\n}\n\n/** Raised when a pinned contact's public key doesn't match the resolved key. */\nexport class KeyPinningError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"KeyPinningError\";\n Object.setPrototypeOf(this, KeyPinningError.prototype);\n }\n}\n\n/**\n * The relay refused a message sent over WebSocket.\n *\n * `code` is the relay's error code (e.g. \"rate_limited\"), `detail` its\n * explanation. Over HTTP the same refusal is an HTTP error.\n */\nexport class SendRefusedError extends UAMError {\n readonly messageId: string;\n readonly code: string;\n readonly detail: string | undefined;\n\n constructor(messageId: string, code: string, detail?: string) {\n super(`Relay refused message ${messageId}: [${code}] ${detail ?? \"\"}`.trimEnd());\n this.name = \"SendRefusedError\";\n this.messageId = messageId;\n this.code = code;\n this.detail = detail;\n }\n}\n","/**\n * UAM address parsing and validation.\n *\n * A UAM address has the form `agent::domain` (e.g. `alice::youam.network`).\n */\n\nimport { InvalidAddressError } from \"./errors.js\";\n\n/**\n * A parsed UAM address (always lowercase).\n */\nexport interface Address {\n readonly agent: string;\n readonly domain: string;\n readonly full: string;\n}\n\n// Agent: 1-64 chars, lowercase alphanumeric + hyphen + underscore.\n// Cannot start or end with hyphen.\n// Domain: standard DNS-style, 1-255 chars.\nconst ADDRESS_RE =\n /^(?<agent>[a-z0-9][a-z0-9_-]{0,62}[a-z0-9]|[a-z0-9])::(?<domain>[a-z0-9](?:[a-z0-9.-]{0,253}[a-z0-9])?)$/;\n\nconst MAX_AGENT_LEN = 64;\nconst MAX_ADDRESS_LEN = 128;\n\n/**\n * Parse and validate a UAM address string.\n *\n * Strips whitespace, lowercases, and validates format.\n * Enforces max lengths: agent <= 64 chars, full address <= 128 chars.\n *\n * @throws {InvalidAddressError} If `raw` is not a valid `agent::domain` address.\n */\nexport function parseAddress(raw: string): Address {\n const normalized = raw.trim().toLowerCase();\n if (normalized.length > MAX_ADDRESS_LEN) {\n throw new InvalidAddressError(\n `Address exceeds ${MAX_ADDRESS_LEN} characters: ${JSON.stringify(raw)}`\n );\n }\n const m = ADDRESS_RE.exec(normalized);\n if (!m || !m.groups) {\n throw new InvalidAddressError(\n `Invalid UAM address: ${JSON.stringify(raw)}`\n );\n }\n const agent = m.groups.agent;\n if (agent.length > MAX_AGENT_LEN) {\n throw new InvalidAddressError(\n `Agent name exceeds ${MAX_AGENT_LEN} characters: ${JSON.stringify(raw)}`\n );\n }\n return {\n agent,\n domain: m.groups.domain,\n get full() {\n return `${this.agent}::${this.domain}`;\n },\n };\n}\n","/**\n * Cryptographic primitives for UAM protocol.\n *\n * Wraps libsodium-wrappers for Ed25519 signing, Curve25519 key exchange,\n * NaCl Box (authenticated encryption), and NaCl SealedBox (anonymous encryption).\n *\n * This module never hand-rolls crypto -- every operation delegates to libsodium.\n */\n\nimport sodium from \"libsodium-wrappers\";\nimport { createHash } from \"node:crypto\";\n\nimport {\n DecryptionError,\n EncryptionError,\n SignatureVerificationError,\n} from \"./errors.js\";\nimport { b64Decode, b64Encode } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Sodium initialization\n// ---------------------------------------------------------------------------\n\n/**\n * Promise that resolves when libsodium is ready.\n * Callers must await this before first use of any crypto function.\n */\nexport const sodiumReady: Promise<void> = sodium.ready;\n\n// ---------------------------------------------------------------------------\n// Key type aliases\n// ---------------------------------------------------------------------------\n\n/** 64-byte Ed25519 secret key (seed + public). */\nexport type SigningKey = Uint8Array;\n\n/** 32-byte Ed25519 public key. */\nexport type VerifyKey = Uint8Array;\n\n/** 32-byte seed. */\nexport type Seed = Uint8Array;\n\n// ---------------------------------------------------------------------------\n// Key generation and serialization\n// ---------------------------------------------------------------------------\n\nexport interface Keypair {\n signingKey: Uint8Array;\n verifyKey: Uint8Array;\n seed: Uint8Array;\n}\n\n/**\n * Generate an Ed25519 keypair.\n */\nexport function generateKeypair(): Keypair {\n const seed = sodium.randombytes_buf(32);\n const kp = sodium.crypto_sign_seed_keypair(seed);\n return {\n signingKey: kp.privateKey,\n verifyKey: kp.publicKey,\n seed,\n };\n}\n\n/**\n * Serialize a signing key to URL-safe base64 (32-byte seed).\n *\n * Matches Python: PyNaCl's SigningKey.encode() returns the 32-byte seed.\n */\nexport function serializeSigningKey(seed: Uint8Array): string {\n return b64Encode(seed);\n}\n\n/**\n * Restore a signing key from its base64-encoded seed.\n */\nexport function deserializeSigningKey(s: string): Keypair {\n const seed = b64Decode(s);\n const kp = sodium.crypto_sign_seed_keypair(seed);\n return {\n signingKey: kp.privateKey,\n verifyKey: kp.publicKey,\n seed,\n };\n}\n\n/**\n * Serialize a verify (public) key to URL-safe base64.\n */\nexport function serializeVerifyKey(key: Uint8Array): string {\n return b64Encode(key);\n}\n\n/**\n * Restore a verify key from its base64 encoding.\n */\nexport function deserializeVerifyKey(s: string): Uint8Array {\n return b64Decode(s);\n}\n\n/**\n * Return the SHA-256 hex digest of the verify key bytes.\n *\n * This 64-character string serves as the agent's identity fingerprint.\n */\nexport function publicKeyFingerprint(verifyKey: Uint8Array): string {\n return createHash(\"sha256\").update(Buffer.from(verifyKey)).digest(\"hex\");\n}\n\n// ---------------------------------------------------------------------------\n// Canonical JSON\n// ---------------------------------------------------------------------------\n\n/**\n * Recursively sort all object keys and produce compact JSON.\n *\n * Matches Python: json.dumps(data, sort_keys=True, separators=(',',':'), ensure_ascii=True)\n */\nfunction sortedStringify(value: unknown): string {\n if (value === null || value === undefined) {\n return \"null\";\n }\n if (typeof value === \"string\") {\n return JSON.stringify(value);\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n if (Array.isArray(value)) {\n const items = value.map((v) => sortedStringify(v));\n return \"[\" + items.join(\",\") + \"]\";\n }\n if (typeof value === \"object\") {\n const obj = value as Record<string, unknown>;\n const keys = Object.keys(obj).sort();\n const pairs = keys.map((k) => JSON.stringify(k) + \":\" + sortedStringify(obj[k]));\n return \"{\" + pairs.join(\",\") + \"}\";\n }\n return String(value);\n}\n\n/**\n * Produce deterministic JSON bytes for signing.\n *\n * - Excludes the \"signature\" key.\n * - Excludes keys whose value is null or undefined.\n * - Sorts keys, uses compact separators, ensures ASCII encoding.\n */\nexport function canonicalize(data: Record<string, unknown>): Uint8Array {\n const filtered: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(data)) {\n if (k !== \"signature\" && v !== null && v !== undefined) {\n filtered[k] = v;\n }\n }\n const json = sortedStringify(filtered);\n return new TextEncoder().encode(json);\n}\n\n// ---------------------------------------------------------------------------\n// Signing and verification\n// ---------------------------------------------------------------------------\n\n/**\n * Sign data with the Ed25519 signing key.\n *\n * @returns The 64-byte signature as a URL-safe base64 string.\n */\nexport function signMessage(data: Uint8Array, signingKey: Uint8Array): string {\n const signature = sodium.crypto_sign_detached(data, signingKey);\n return b64Encode(signature);\n}\n\n/**\n * Verify an Ed25519 signature.\n *\n * @throws {SignatureVerificationError} If the signature is invalid.\n */\nexport function verifySignature(\n data: Uint8Array,\n signatureB64: string,\n verifyKey: Uint8Array\n): void {\n try {\n const sigBytes = b64Decode(signatureB64);\n const valid = sodium.crypto_sign_verify_detached(sigBytes, data, verifyKey);\n if (!valid) {\n throw new SignatureVerificationError(\"Signature verification failed\");\n }\n } catch (err) {\n if (err instanceof SignatureVerificationError) {\n throw err;\n }\n throw new SignatureVerificationError(\n err instanceof Error ? err.message : String(err)\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Nonce generation\n// ---------------------------------------------------------------------------\n\n/**\n * Generate 24 cryptographically random bytes, returned as base64.\n */\nexport function generateNonce(): string {\n return b64Encode(sodium.randombytes_buf(24));\n}\n\n// ---------------------------------------------------------------------------\n// NaCl Box encryption (authenticated, both parties known)\n// ---------------------------------------------------------------------------\n\n/**\n * Encrypt plaintext using NaCl Box (authenticated encryption).\n *\n * Both parties are known; the sender signs implicitly via key exchange.\n * Format: nonce (24 bytes) || ciphertext, matching PyNaCl Box.encrypt() output.\n *\n * @returns Base64-encoded ciphertext (nonce prepended).\n * @throws {EncryptionError} On any libsodium error.\n */\nexport function encryptPayload(\n plaintext: Uint8Array,\n senderSigningKey: Uint8Array,\n recipientVerifyKey: Uint8Array\n): string {\n try {\n const senderCurve = sodium.crypto_sign_ed25519_sk_to_curve25519(senderSigningKey);\n const recipientCurve = sodium.crypto_sign_ed25519_pk_to_curve25519(recipientVerifyKey);\n const nonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES);\n const encrypted = sodium.crypto_box_easy(plaintext, nonce, recipientCurve, senderCurve);\n // Concatenate nonce || ciphertext (matching PyNaCl format)\n const combined = new Uint8Array(nonce.length + encrypted.length);\n combined.set(nonce, 0);\n combined.set(encrypted, nonce.length);\n return b64Encode(combined);\n } catch (err) {\n if (err instanceof EncryptionError) throw err;\n throw new EncryptionError(err instanceof Error ? err.message : String(err));\n }\n}\n\n/**\n * Decrypt NaCl Box ciphertext.\n *\n * @returns The original plaintext bytes.\n * @throws {DecryptionError} On any libsodium error (wrong keys, tampered data).\n */\nexport function decryptPayload(\n ciphertextB64: string,\n recipientSigningKey: Uint8Array,\n senderVerifyKey: Uint8Array\n): Uint8Array {\n try {\n const combined = b64Decode(ciphertextB64);\n const nonce = combined.slice(0, sodium.crypto_box_NONCEBYTES);\n const ciphertext = combined.slice(sodium.crypto_box_NONCEBYTES);\n const recipientCurve = sodium.crypto_sign_ed25519_sk_to_curve25519(recipientSigningKey);\n const senderCurve = sodium.crypto_sign_ed25519_pk_to_curve25519(senderVerifyKey);\n return sodium.crypto_box_open_easy(ciphertext, nonce, senderCurve, recipientCurve);\n } catch (err) {\n if (err instanceof DecryptionError) throw err;\n throw new DecryptionError(err instanceof Error ? err.message : String(err));\n }\n}\n\n// ---------------------------------------------------------------------------\n// NaCl SealedBox encryption (anonymous sender)\n// ---------------------------------------------------------------------------\n\n/**\n * Encrypt plaintext using NaCl SealedBox (anonymous sender).\n *\n * Only the recipient's public key is required; no sender authentication.\n *\n * @returns Base64-encoded ciphertext.\n */\nexport function encryptPayloadAnonymous(\n plaintext: Uint8Array,\n recipientVerifyKey: Uint8Array\n): string {\n const recipientCurve = sodium.crypto_sign_ed25519_pk_to_curve25519(recipientVerifyKey);\n const ciphertext = sodium.crypto_box_seal(plaintext, recipientCurve);\n return b64Encode(ciphertext);\n}\n\n/**\n * Decrypt NaCl SealedBox ciphertext.\n *\n * @returns The original plaintext bytes.\n * @throws {DecryptionError} On any libsodium error.\n */\nexport function decryptPayloadAnonymous(\n ciphertextB64: string,\n recipientSigningKey: Uint8Array\n): Uint8Array {\n try {\n const ciphertext = b64Decode(ciphertextB64);\n const recipientCurveSk = sodium.crypto_sign_ed25519_sk_to_curve25519(recipientSigningKey);\n // Extract the public key from the signing key (last 32 bytes of the 64-byte Ed25519 secret key)\n const recipientVerifyKey = recipientSigningKey.slice(32);\n const recipientCurvePk = sodium.crypto_sign_ed25519_pk_to_curve25519(recipientVerifyKey);\n return sodium.crypto_box_seal_open(ciphertext, recipientCurvePk, recipientCurveSk);\n } catch (err) {\n if (err instanceof DecryptionError) throw err;\n throw new DecryptionError(err instanceof Error ? err.message : String(err));\n }\n}\n","/**\n * UAM message envelope -- creation, signing, verification, wire format.\n *\n * An envelope wraps every UAM message with cryptographic signatures and\n * encrypted payloads, using fromAddress/toAddress naming internally\n * (\"from\"/\"to\" on the wire).\n */\n\nimport { randomUUID } from \"node:crypto\";\n\nimport { parseAddress } from \"./address.js\";\nimport {\n canonicalize,\n encryptPayload,\n encryptPayloadAnonymous,\n generateNonce,\n signMessage,\n verifySignature,\n} from \"./crypto.js\";\nimport { EnvelopeTooLargeError, InvalidEnvelopeError } from \"./errors.js\";\nimport { MAX_ENVELOPE_SIZE, MessageType, UAM_VERSION, utcTimestamp } from \"./types.js\";\n\n/**\n * Required wire-format field names (using \"from\"/\"to\").\n */\nconst REQUIRED_WIRE_FIELDS = new Set([\n \"uam_version\",\n \"message_id\",\n \"from\",\n \"to\",\n \"timestamp\",\n \"type\",\n \"nonce\",\n \"payload\",\n \"signature\",\n]);\n\n/**\n * A signed, encrypted UAM message envelope.\n */\nexport interface MessageEnvelope {\n // Required fields\n readonly uamVersion: string;\n readonly messageId: string;\n readonly fromAddress: string;\n readonly toAddress: string;\n readonly timestamp: string;\n readonly type: string;\n readonly nonce: string;\n readonly payload: string;\n readonly signature: string;\n\n // Optional fields\n readonly threadId?: string;\n readonly replyTo?: string;\n readonly expires?: string;\n readonly mediaType?: string;\n readonly metadata?: Record<string, unknown>;\n\n // v1.1 fields -- NOT in signature scope\n readonly attachments?: Array<Record<string, unknown>>;\n}\n\n/**\n * Build the dict used for signature computation.\n *\n * Maps TypeScript names to wire names (fromAddress -> \"from\").\n * Excludes signature and any optional field that is undefined.\n */\nfunction buildSignableDict(\n envelope: MessageEnvelope\n): Record<string, unknown> {\n const d: Record<string, unknown> = {\n uam_version: envelope.uamVersion,\n message_id: envelope.messageId,\n from: envelope.fromAddress,\n to: envelope.toAddress,\n timestamp: envelope.timestamp,\n type: envelope.type,\n nonce: envelope.nonce,\n payload: envelope.payload,\n };\n if (envelope.threadId !== undefined) d[\"thread_id\"] = envelope.threadId;\n if (envelope.replyTo !== undefined) d[\"reply_to\"] = envelope.replyTo;\n if (envelope.expires !== undefined) d[\"expires\"] = envelope.expires;\n if (envelope.mediaType !== undefined) d[\"media_type\"] = envelope.mediaType;\n if (envelope.metadata !== undefined) d[\"metadata\"] = envelope.metadata;\n return d;\n}\n\n/**\n * Convert an envelope to a wire-format dict.\n *\n * Maps fromAddress -> \"from\" and toAddress -> \"to\".\n * Excludes undefined-valued optional fields.\n */\nexport function toWireDict(\n envelope: MessageEnvelope\n): Record<string, unknown> {\n const d = buildSignableDict(envelope);\n d[\"signature\"] = envelope.signature;\n if (envelope.attachments !== undefined) {\n d[\"attachments\"] = envelope.attachments;\n }\n return d;\n}\n\n/**\n * Restore an envelope from a wire-format dict.\n *\n * @throws {InvalidEnvelopeError} If any required field is missing.\n */\nexport function fromWireDict(\n d: Record<string, unknown>\n): MessageEnvelope {\n const keys = new Set(Object.keys(d));\n const missing: string[] = [];\n for (const field of REQUIRED_WIRE_FIELDS) {\n if (!keys.has(field)) missing.push(field);\n }\n if (missing.length > 0) {\n missing.sort();\n throw new InvalidEnvelopeError(\n `Missing required fields: ${JSON.stringify(missing)}`\n );\n }\n\n return Object.freeze({\n uamVersion: d[\"uam_version\"] as string,\n messageId: d[\"message_id\"] as string,\n fromAddress: d[\"from\"] as string,\n toAddress: d[\"to\"] as string,\n timestamp: d[\"timestamp\"] as string,\n type: d[\"type\"] as string,\n nonce: d[\"nonce\"] as string,\n payload: d[\"payload\"] as string,\n signature: d[\"signature\"] as string,\n threadId: d[\"thread_id\"] as string | undefined,\n replyTo: d[\"reply_to\"] as string | undefined,\n expires: d[\"expires\"] as string | undefined,\n mediaType: d[\"media_type\"] as string | undefined,\n metadata: d[\"metadata\"] as Record<string, unknown> | undefined,\n attachments: d[\"attachments\"] as Array<Record<string, unknown>> | undefined,\n });\n}\n\n/**\n * Check that the serialized envelope does not exceed MAX_ENVELOPE_SIZE.\n *\n * @throws {EnvelopeTooLargeError} If the wire JSON exceeds 64 KB.\n */\nexport function validateEnvelopeSize(envelope: MessageEnvelope): void {\n const wire = toWireDict(envelope);\n const json = JSON.stringify(wire);\n const size = new TextEncoder().encode(json).length;\n if (size > MAX_ENVELOPE_SIZE) {\n throw new EnvelopeTooLargeError(\n `Envelope size ${size} bytes exceeds maximum ${MAX_ENVELOPE_SIZE} bytes`\n );\n }\n}\n\n/**\n * Create a signed, encrypted message envelope.\n *\n * @throws {InvalidAddressError} If either address is invalid.\n * @throws {EnvelopeTooLargeError} If the serialized envelope exceeds 64 KB.\n */\nexport async function createEnvelope(\n fromAddress: string,\n toAddress: string,\n messageType: MessageType | string,\n payloadPlaintext: Uint8Array,\n signingKey: Uint8Array,\n recipientVerifyKey: Uint8Array,\n options?: {\n threadId?: string;\n replyTo?: string;\n expires?: string;\n mediaType?: string;\n metadata?: Record<string, unknown>;\n attachments?: Array<Record<string, unknown>>;\n }\n): Promise<MessageEnvelope> {\n // Normalize message type\n const typeValue =\n typeof messageType === \"string\"\n ? messageType\n : (messageType as string);\n\n // Step 1: Validate addresses\n parseAddress(fromAddress);\n parseAddress(toAddress);\n\n // Step 2: Generate identifiers\n const messageId = randomUUID();\n const nonce = generateNonce();\n const timestamp = utcTimestamp();\n\n // Step 3: Encrypt payload\n let encryptedPayload: string;\n if (typeValue === MessageType.HANDSHAKE_REQUEST) {\n encryptedPayload = encryptPayloadAnonymous(payloadPlaintext, recipientVerifyKey);\n } else {\n encryptedPayload = encryptPayload(\n payloadPlaintext,\n signingKey,\n recipientVerifyKey\n );\n }\n\n // Build temporary envelope without signature\n const tempEnvelope: MessageEnvelope = {\n uamVersion: UAM_VERSION,\n messageId,\n fromAddress,\n toAddress,\n timestamp,\n type: typeValue,\n nonce,\n payload: encryptedPayload,\n signature: \"\",\n threadId: options?.threadId,\n replyTo: options?.replyTo,\n expires: options?.expires,\n mediaType: options?.mediaType,\n metadata: options?.metadata,\n attachments: options?.attachments,\n };\n\n // Step 4: Build signable dict, canonicalize, and sign\n const signable = buildSignableDict(tempEnvelope);\n const signature = signMessage(canonicalize(signable), signingKey);\n\n // Step 5: Build final envelope\n const finalEnvelope: MessageEnvelope = Object.freeze({\n uamVersion: UAM_VERSION,\n messageId,\n fromAddress,\n toAddress,\n timestamp,\n type: typeValue,\n nonce,\n payload: encryptedPayload,\n signature,\n threadId: options?.threadId,\n replyTo: options?.replyTo,\n expires: options?.expires,\n mediaType: options?.mediaType,\n metadata: options?.metadata,\n attachments: options?.attachments,\n });\n\n // Step 6: Validate size\n validateEnvelopeSize(finalEnvelope);\n\n return finalEnvelope;\n}\n\n/**\n * Verify the cryptographic signature on an envelope.\n *\n * @throws {SignatureVerificationError} If the signature is invalid.\n */\nexport function verifyEnvelope(\n envelope: MessageEnvelope,\n senderVerifyKey: Uint8Array\n): void {\n const signable = buildSignableDict(envelope);\n verifySignature(canonicalize(signable), envelope.signature, senderVerifyKey);\n}\n","/**\n * UAM contact cards -- self-signed agent identity documents.\n *\n * A contact card advertises an agent's address, public key, relay endpoint,\n * and optional metadata. The card is signed by the agent's own signing key\n * so that any recipient can verify authenticity using the embedded public key.\n */\n\nimport { parseAddress } from \"./address.js\";\nimport {\n canonicalize,\n deserializeVerifyKey,\n publicKeyFingerprint,\n serializeVerifyKey,\n signMessage,\n verifySignature,\n} from \"./crypto.js\";\nimport { InvalidContactCardError } from \"./errors.js\";\nimport { UAM_VERSION } from \"./types.js\";\n\n/**\n * A self-signed agent identity card.\n */\nexport interface ContactCard {\n readonly version: string;\n readonly address: string;\n readonly displayName: string;\n readonly description?: string;\n readonly system?: string;\n readonly connectionEndpoint?: string;\n readonly relay: string;\n readonly publicKey: string;\n readonly signature: string;\n readonly verifiedDomain?: string;\n readonly payloadFormats?: string[];\n readonly fingerprint?: string;\n /** CARD-04: Multi-relay support. Outside signature scope. */\n readonly relays?: string[];\n}\n\n/**\n * Build the dict used for signature computation.\n *\n * Includes all fields except signature, payload_formats, fingerprint, relays.\n * Excludes undefined-valued optional fields.\n */\nfunction buildSignableDict(card: ContactCard): Record<string, unknown> {\n const d: Record<string, unknown> = {\n version: card.version,\n address: card.address,\n display_name: card.displayName,\n relay: card.relay,\n public_key: card.publicKey,\n };\n if (card.description !== undefined) d[\"description\"] = card.description;\n if (card.system !== undefined) d[\"system\"] = card.system;\n if (card.connectionEndpoint !== undefined) {\n d[\"connection_endpoint\"] = card.connectionEndpoint;\n }\n if (card.verifiedDomain !== undefined) {\n d[\"verified_domain\"] = card.verifiedDomain;\n }\n return d;\n}\n\n/**\n * Serialize a contact card to a plain dict.\n *\n * Uses snake_case names on the wire, excludes undefined-valued optional fields.\n */\nexport function contactCardToDict(\n card: ContactCard\n): Record<string, unknown> {\n const d = buildSignableDict(card);\n d[\"signature\"] = card.signature;\n if (card.payloadFormats !== undefined) {\n d[\"payload_formats\"] = card.payloadFormats;\n }\n if (card.fingerprint !== undefined) {\n d[\"fingerprint\"] = card.fingerprint;\n }\n if (card.relays !== undefined) {\n d[\"relays\"] = card.relays;\n }\n return d;\n}\n\n/**\n * Deserialize a contact card from a dict.\n *\n * When verify is true (the default), the card's signature is checked\n * immediately after deserialization.\n *\n * @throws {InvalidContactCardError} If required fields are missing.\n * @throws {SignatureVerificationError} If verify is true and the signature is invalid.\n */\nexport function contactCardFromDict(\n d: Record<string, unknown>,\n options?: { verify?: boolean }\n): ContactCard {\n const verify = options?.verify ?? true;\n\n const required = new Set([\n \"version\",\n \"address\",\n \"display_name\",\n \"relay\",\n \"public_key\",\n \"signature\",\n ]);\n const keys = new Set(Object.keys(d));\n const missing: string[] = [];\n for (const field of required) {\n if (!keys.has(field)) missing.push(field);\n }\n if (missing.length > 0) {\n missing.sort();\n throw new InvalidContactCardError(\n `Missing required fields: ${JSON.stringify(missing)}`\n );\n }\n\n const card: ContactCard = Object.freeze({\n version: d[\"version\"] as string,\n address: d[\"address\"] as string,\n displayName: d[\"display_name\"] as string,\n description: d[\"description\"] as string | undefined,\n system: d[\"system\"] as string | undefined,\n connectionEndpoint: d[\"connection_endpoint\"] as string | undefined,\n relay: d[\"relay\"] as string,\n publicKey: d[\"public_key\"] as string,\n signature: d[\"signature\"] as string,\n verifiedDomain: d[\"verified_domain\"] as string | undefined,\n payloadFormats: d[\"payload_formats\"] as string[] | undefined,\n fingerprint: d[\"fingerprint\"] as string | undefined,\n relays: d[\"relays\"] as string[] | undefined,\n });\n\n if (verify) {\n verifyContactCard(card);\n }\n\n return card;\n}\n\n/**\n * Create a self-signed contact card.\n *\n * payloadFormats defaults to [\"text/plain\", \"text/markdown\"] when not specified.\n * The fingerprint is always auto-computed as the SHA-256 hex digest of the\n * Ed25519 public key bytes.\n *\n * @throws {InvalidAddressError} If address is not valid.\n */\nexport async function createContactCard(\n address: string,\n displayName: string,\n relay: string,\n signingKey: Uint8Array,\n options?: {\n description?: string;\n system?: string;\n connectionEndpoint?: string;\n verifiedDomain?: string;\n payloadFormats?: string[];\n relays?: string[];\n }\n): Promise<ContactCard> {\n // Validate address\n parseAddress(address);\n\n // Derive public key and fingerprint\n // The verify key is the last 32 bytes of the 64-byte signing key\n const verifyKey = signingKey.slice(32);\n const pubKeyB64 = serializeVerifyKey(verifyKey);\n const fp = publicKeyFingerprint(verifyKey);\n\n // Default payload formats\n const payloadFormats = options?.payloadFormats ?? [\n \"text/plain\",\n \"text/markdown\",\n ];\n\n // Build temporary card without signature\n const tempCard: ContactCard = {\n version: UAM_VERSION,\n address,\n displayName,\n description: options?.description,\n system: options?.system,\n connectionEndpoint: options?.connectionEndpoint,\n relay,\n publicKey: pubKeyB64,\n signature: \"\",\n verifiedDomain: options?.verifiedDomain,\n payloadFormats,\n fingerprint: fp,\n relays: options?.relays,\n };\n\n // Sign (payload_formats, fingerprint, relays are NOT in signable dict)\n const signable = buildSignableDict(tempCard);\n const signature = signMessage(canonicalize(signable), signingKey);\n\n // Return final card\n return Object.freeze({\n version: UAM_VERSION,\n address,\n displayName,\n description: options?.description,\n system: options?.system,\n connectionEndpoint: options?.connectionEndpoint,\n relay,\n publicKey: pubKeyB64,\n signature,\n verifiedDomain: options?.verifiedDomain,\n payloadFormats,\n fingerprint: fp,\n relays: options?.relays,\n });\n}\n\n/**\n * Verify a contact card's signature using its embedded public key.\n *\n * @throws {InvalidContactCardError} If the address is invalid.\n * @throws {SignatureVerificationError} If the signature is invalid.\n */\nexport function verifyContactCard(card: ContactCard): void {\n // Validate address format\n try {\n parseAddress(card.address);\n } catch (err) {\n throw new InvalidContactCardError(\n `Invalid address in contact card: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Deserialize the embedded public key\n const vk = deserializeVerifyKey(card.publicKey);\n\n // Verify signature\n const signable = buildSignableDict(card);\n verifySignature(canonicalize(signable), card.signature, vk);\n}\n","/**\n * Signed owner objects: profile, canonical form, hash and schemas.\n *\n * Mirrors uam.protocol.signed in the Python SDK; both are checked against\n * the same vectors (tests/vectors/signed/). Every owner object (key log\n * entries, links, invites, redemptions, grants) is a JSON body in a\n * restricted profile, hashed as\n *\n * h = base64url(SHA-256(\"UAM-<type>-v1\\n\" || JCS(body))) (no padding)\n *\n * The profile: printable ASCII strings, integers within +/-(2^53-1), no\n * floats, no nulls, no duplicate keys, and no members a type doesn't define\n * (new ones go under `ext`, with `crit` naming those a verifier must know).\n * A body that breaks any rule is refused, never repaired.\n */\n\nimport { createHash } from \"node:crypto\";\n\nimport { parseAddress } from \"./address.js\";\nimport { decodeDidKey, type DidKeyKind } from \"./didkey.js\";\nimport { UAMError } from \"./errors.js\";\n\nexport const MAX_INT = 2 ** 53 - 1;\nexport const GRANT_MAX_DAYS = 90;\nexport const INVITE_MAX_DAYS = 7;\n\nexport type Body = Record<string, unknown>;\n\n/** A signed-object body outside the profile or its type's schema. */\nexport class SignedObjectError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"SignedObjectError\";\n }\n}\n\nconst has = (obj: object, key: string) => Object.prototype.hasOwnProperty.call(obj, key);\n\n// --- parsing -------------------------------------------------------------------\n\n/**\n * A strict JSON parser for signed bodies. JSON.parse can't be used: it keeps\n * the last of two duplicate keys without a word.\n */\nclass Parser {\n private i = 0;\n constructor(private readonly s: string) {}\n\n fail(why: string): never {\n throw new SignedObjectError(`not JSON or outside the profile at ${this.i}: ${why}`);\n }\n\n ws(): void {\n while (this.i < this.s.length && \" \\t\\n\\r\".includes(this.s[this.i]!)) this.i += 1;\n }\n\n document(): Body {\n this.ws();\n if (this.s[this.i] !== \"{\") this.fail(\"a body must be a JSON object\");\n const value = this.value() as Body;\n this.ws();\n if (this.i !== this.s.length) this.fail(\"trailing characters\");\n return value;\n }\n\n value(): unknown {\n this.ws();\n const c = this.s[this.i];\n if (c === \"{\") return this.object();\n if (c === \"[\") return this.array();\n if (c === '\"') return this.string();\n if (c === \"-\" || (c !== undefined && c >= \"0\" && c <= \"9\")) return this.number();\n for (const [word, v] of [[\"true\", true], [\"false\", false]] as const) {\n if (this.s.startsWith(word, this.i)) {\n this.i += word.length;\n return v;\n }\n }\n if (this.s.startsWith(\"null\", this.i)) this.fail(\"null is not allowed\");\n return this.fail(\"unexpected character\");\n }\n\n object(): Body {\n this.i += 1;\n const out: Body = Object.create(null) as Body;\n this.ws();\n if (this.s[this.i] === \"}\") {\n this.i += 1;\n return out;\n }\n for (;;) {\n this.ws();\n if (this.s[this.i] !== '\"') this.fail(\"expected a key\");\n const key = this.string();\n if (has(out, key)) this.fail(`duplicate key: ${JSON.stringify(key)}`);\n this.ws();\n if (this.s[this.i] !== \":\") this.fail(\"expected ':'\");\n this.i += 1;\n Object.defineProperty(out, key, {\n value: this.value(), enumerable: true, writable: true, configurable: true,\n });\n this.ws();\n if (this.s[this.i] === \",\") {\n this.i += 1;\n continue;\n }\n if (this.s[this.i] === \"}\") {\n this.i += 1;\n return out;\n }\n this.fail(\"expected ',' or '}'\");\n }\n }\n\n array(): unknown[] {\n this.i += 1;\n const out: unknown[] = [];\n this.ws();\n if (this.s[this.i] === \"]\") {\n this.i += 1;\n return out;\n }\n for (;;) {\n out.push(this.value());\n this.ws();\n if (this.s[this.i] === \",\") {\n this.i += 1;\n continue;\n }\n if (this.s[this.i] === \"]\") {\n this.i += 1;\n return out;\n }\n this.fail(\"expected ',' or ']'\");\n }\n }\n\n string(): string {\n this.i += 1;\n let out = \"\";\n for (;;) {\n const c = this.s[this.i];\n if (c === undefined) this.fail(\"unterminated string\");\n this.i += 1;\n if (c === '\"') break;\n if (c === \"\\\\\") {\n const e = this.s[this.i];\n this.i += 1;\n const simple: Record<string, string> = {\n '\"': '\"', \"\\\\\": \"\\\\\", \"/\": \"/\", b: \"\\b\", f: \"\\f\", n: \"\\n\", r: \"\\r\", t: \"\\t\",\n };\n if (e !== undefined && has(simple, e)) {\n out += simple[e];\n } else if (e === \"u\") {\n const hex = this.s.slice(this.i, this.i + 4);\n if (!/^[0-9a-fA-F]{4}$/.test(hex)) this.fail(\"bad \\\\u escape\");\n out += String.fromCharCode(parseInt(hex, 16));\n this.i += 4;\n } else {\n this.fail(\"bad escape\");\n }\n } else {\n if (c < \" \") this.fail(\"control character in string\");\n out += c;\n }\n }\n checkString(out);\n return out;\n }\n\n number(): number {\n const m = /^-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/.exec(this.s.slice(this.i));\n if (!m) return this.fail(\"bad number\");\n const text = m[0];\n if (m[2] !== undefined || m[3] !== undefined) this.fail(`floats are not allowed: ${text}`);\n if (text === \"-0\") this.fail(\"-0 is not allowed\");\n const big = BigInt(text);\n if (big > BigInt(MAX_INT) || big < -BigInt(MAX_INT)) this.fail(`integer out of range: ${text}`);\n this.i += text.length;\n return Number(big);\n }\n}\n\n/** Parse a body, refusing anything outside the profile. */\nexport function parseBody(text: string | Uint8Array): Body {\n let s: string;\n if (typeof text === \"string\") {\n s = text;\n } else {\n try {\n s = new TextDecoder(\"utf-8\", { fatal: true }).decode(text);\n } catch {\n throw new SignedObjectError(\"body is not UTF-8\");\n }\n }\n return new Parser(s).document();\n}\n\n// --- profile and canonical form ------------------------------------------------\n\nfunction checkString(value: string): void {\n for (let i = 0; i < value.length; i += 1) {\n const code = value.charCodeAt(i);\n if (code < 0x20 || code > 0x7e) {\n throw new SignedObjectError(\"strings must be printable ASCII\");\n }\n }\n}\n\nfunction isPlainObject(value: unknown): value is Body {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const proto = Object.getPrototypeOf(value) as unknown;\n return proto === null || proto === Object.prototype;\n}\n\nfunction encode(value: unknown): string {\n if (value === true) return \"true\";\n if (value === false) return \"false\";\n if (typeof value === \"number\") {\n if (!Number.isSafeInteger(value) || Object.is(value, -0)) {\n throw new SignedObjectError(`not an integer in range: ${value}`);\n }\n return String(value);\n }\n if (typeof value === \"string\") {\n checkString(value);\n return '\"' + value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"') + '\"';\n }\n if (Array.isArray(value)) return \"[\" + value.map(encode).join(\",\") + \"]\";\n if (isPlainObject(value)) {\n // ASCII keys, so sorting by UTF-16 code unit is RFC 8785's order.\n return \"{\" + Object.keys(value).sort().map((key) => {\n checkString(key);\n return encode(key) + \":\" + encode(value[key]);\n }).join(\",\") + \"}\";\n }\n if (value === null) throw new SignedObjectError(\"null is not allowed\");\n throw new SignedObjectError(`not allowed: ${typeof value}`);\n}\n\n/** RFC 8785 canonical form (inside the profile: sorted keys, no whitespace). */\nexport function canonical(body: Body): Uint8Array {\n if (!isPlainObject(body)) throw new SignedObjectError(\"a body must be a JSON object\");\n return new TextEncoder().encode(encode(body));\n}\n\nfunction hashCanonical(body: Body): string {\n return createHash(\"sha256\")\n .update(`UAM-${String(body[\"type\"])}-v1\\n`)\n .update(canonical(body))\n .digest(\"base64url\");\n}\n\n/** The object's hash; the body is validated first. */\nexport function objectHash(body: Body): string {\n validate(body);\n return hashCanonical(body);\n}\n\n// --- schemas ---------------------------------------------------------------\n\ntype Check = (value: unknown, path: string) => void;\n\nconst TIME_RE = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})Z$/;\nconst HASH_RE = /^[A-Za-z0-9_-]{43}$/;\nconst OWNER_ID_RE = /^[A-Za-z0-9_-]{22}$/;\nconst NONCE_RE = /^[A-Za-z0-9_-]{16,64}$/;\nconst SECRET_RE = /^[A-Za-z0-9_-]{22}$/;\nconst DOMAIN_RE =\n /^(?=.{1,253}$)[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/;\n\nfunction fail(path: string, why: string): never {\n throw new SignedObjectError(`${path}: ${why}`);\n}\n\nconst string_: Check = (v, p) => {\n if (typeof v !== \"string\" || v.length === 0) fail(p, \"must be a non-empty string\");\n};\n\nconst label: Check = (v, p) => {\n string_(v, p);\n if ((v as string).length > 64) fail(p, \"at most 64 characters\");\n // Labels are quoted in the text an owner signs, so a quote in one could\n // make that text say something the object doesn't.\n if ((v as string).includes('\"')) fail(p, 'must not contain \"');\n};\n\nconst matching = (re: RegExp, what: string): Check => (v, p) => {\n if (typeof v !== \"string\" || !re.test(v)) fail(p, `must be ${what}`);\n};\n\nconst hash = matching(HASH_RE, \"a hash (43 base64url characters)\");\nconst ownerId = matching(OWNER_ID_RE, \"an owner id (22 base64url characters)\");\nconst nonce = matching(NONCE_RE, \"a nonce (16-64 base64url characters)\");\nconst secret = matching(SECRET_RE, \"a secret (22 base64url characters)\");\nconst domain = matching(DOMAIN_RE, \"a lowercase domain\");\n\nfunction parseTime(value: string): number | null {\n const m = TIME_RE.exec(value);\n if (!m) return null;\n const [y, mo, d, h, mi, s] = m.slice(1).map(Number) as [number, number, number, number, number, number];\n const t = Date.UTC(y, mo - 1, d, h, mi, s);\n const back = new Date(t);\n if (\n back.getUTCFullYear() !== y || back.getUTCMonth() !== mo - 1 || back.getUTCDate() !== d ||\n back.getUTCHours() !== h || back.getUTCMinutes() !== mi || back.getUTCSeconds() !== s\n ) {\n return null;\n }\n return t;\n}\n\nconst time: Check = (v, p) => {\n if (typeof v !== \"string\" || !TIME_RE.test(v)) fail(p, \"must be YYYY-MM-DDTHH:MM:SSZ\");\n if (parseTime(v) === null) fail(p, \"not a real time\");\n};\n\nconst bool: Check = (v, p) => {\n if (typeof v !== \"boolean\") fail(p, \"must be true or false\");\n};\n\nconst constant = (expected: string | number): Check => (v, p) => {\n if (v !== expected) fail(p, `must be ${JSON.stringify(expected)}`);\n};\n\nconst oneOf = (...options: string[]): Check => (v, p) => {\n if (typeof v !== \"string\" || !options.includes(v)) fail(p, `must be one of ${options.join(\", \")}`);\n};\n\nconst uint: Check = (v, p) => {\n if (typeof v !== \"number\" || !Number.isSafeInteger(v) || v < 0) {\n fail(p, \"must be a non-negative integer\");\n }\n};\n\nconst address: Check = (v, p) => {\n if (typeof v !== \"string\") fail(p, \"must be an address\");\n let full: string;\n try {\n full = parseAddress(v).full;\n } catch {\n return fail(p, \"must be an address\");\n }\n if (full !== v) fail(p, \"must be an address in canonical (lowercase) form\");\n};\n\nconst did = (kind: DidKeyKind): Check => (v, p) => {\n let found: DidKeyKind;\n try {\n found = decodeDidKey(v as string).kind;\n } catch (err) {\n return fail(p, err instanceof Error ? err.message : String(err));\n }\n if (found !== kind) fail(p, `must be a ${kind} did:key`);\n};\n\nconst list = (item: Check, minLen = 1, maxLen = 64): Check => (v, p) => {\n if (!Array.isArray(v) || v.length < minLen || v.length > maxLen) {\n fail(p, `must be a list of ${minLen}-${maxLen} items`);\n }\n v.forEach((entry, i) => item(entry, `${p}[${i}]`));\n};\n\nconst object = (required: Record<string, Check>, optional: Record<string, Check> = {}): Check =>\n (v, p) => {\n if (!isPlainObject(v)) fail(p, \"must be an object\");\n for (const key of Object.keys(v)) {\n if (!has(required, key) && !has(optional, key)) fail(`${p}.${key}`, \"unknown member\");\n }\n for (const [key, member] of Object.entries(required)) {\n if (!has(v, key)) fail(`${p}.${key}`, \"missing\");\n member(v[key], `${p}.${key}`);\n }\n for (const [key, member] of Object.entries(optional)) {\n if (has(v, key)) member(v[key], `${p}.${key}`);\n }\n };\n\nconst location: Check = (v, p) => {\n if (v !== \"shared\") address(v, p);\n};\n\nconst access = object({ actions: list(oneOf(\"message\"), 1, 1), locations: list(location) });\nconst ownerRef = object({ relay: domain, ownerId, keysHash: hash });\nconst ownerRefNoKeys = object({ relay: domain, ownerId });\nconst passkey = did(\"p256\");\nconst agentKey = did(\"ed25519\");\nconst keysOwner = object({ relay: domain }, { ownerId });\n\nconst EXT: Record<string, Check> = { ext: () => undefined, crit: () => undefined };\n\nfunction checkExt(body: Body): void {\n if (has(body, \"ext\") && !isPlainObject(body[\"ext\"])) fail(\"ext\", \"must be an object\");\n if (has(body, \"crit\")) {\n const crit = body[\"crit\"];\n if (!has(body, \"ext\")) fail(\"crit\", \"needs ext\");\n if (!Array.isArray(crit) || !crit.every((k) => typeof k === \"string\")) {\n fail(\"crit\", \"must be a list of ext keys\");\n }\n for (const key of crit as string[]) {\n if (!has(body[\"ext\"] as Body, key)) fail(`crit.${key}`, \"not in ext\");\n fail(`crit.${key}`, \"unknown critical extension\");\n }\n }\n}\n\nfunction span(body: Body, from: string, to: string): number {\n return parseTime(body[to] as string)! - parseTime(body[from] as string)!;\n}\n\nconst DAY = 24 * 60 * 60 * 1000;\n\nconst SCHEMAS: Record<string, (body: Body) => void> = {\n UamOwnerKeys(body) {\n object(\n {\n type: constant(\"UamOwnerKeys\"), v: constant(1), owner: keysOwner, seq: uint,\n keys: list(object({ id: passkey, rpId: domain, backupEligible: bool, label }), 1, 16),\n },\n {\n prev: hash,\n removed: list(object({ id: passkey, reason: oneOf(\"removed\", \"compromised\") }), 1, 64),\n recovery: bool,\n ...EXT,\n }\n )(body, \"$\");\n const owner = body[\"owner\"] as Body;\n if (body[\"seq\"] === 0) {\n // The owner id is the hash of entry 0, so entry 0 can't contain it.\n if (has(owner, \"ownerId\") || has(body, \"prev\")) fail(\"$\", \"entry 0 has no owner.ownerId and no prev\");\n } else if (!has(owner, \"ownerId\") || !has(body, \"prev\")) {\n fail(\"$\", \"a later entry needs owner.ownerId and prev\");\n }\n },\n\n UamOwnerLink(body) {\n object({\n type: constant(\"UamOwnerLink\"), v: constant(1), owner: ownerRef, agent: address,\n agentKey, relay: domain, via: oneOf(\"setup\", \"link\"), shared: bool,\n effectiveAt: time, validFrom: time, nonce,\n }, { ...EXT })(body, \"$\");\n },\n\n UamOwnerUnlink(body) {\n object({\n type: constant(\"UamOwnerUnlink\"), v: constant(1), owner: ownerRef, agent: address,\n agentKey, reason: oneOf(\"owner\", \"admin\", \"relink\", \"authority\", \"lapsed\"), validFrom: time, nonce,\n }, { ...EXT })(body, \"$\");\n },\n\n UamInvite(body) {\n object(\n {\n type: constant(\"UamInvite\"), v: constant(1), inviter: ownerRef, offer: access,\n ask: access, secretHash: hash, mode: oneOf(\"preapproved\", \"confirm\"),\n maxUses: constant(1), validFrom: time, redeemBy: time, nonce,\n },\n { emailHash: hash, ...EXT }\n )(body, \"$\");\n if (body[\"mode\"] === \"preapproved\" && !has(body, \"emailHash\")) {\n fail(\"$.emailHash\", \"a pre-approved invite names the invitee's email\");\n }\n const d = span(body, \"validFrom\", \"redeemBy\");\n if (!(d > 0 && d <= INVITE_MAX_DAYS * DAY)) {\n fail(\"$.redeemBy\", `must be after validFrom, within ${INVITE_MAX_DAYS} days`);\n }\n },\n\n UamRedemption(body) {\n object({\n type: constant(\"UamRedemption\"), v: constant(1), invite: hash, secret,\n invitee: ownerRef, issuer: passkey, createdAt: time, nonce,\n }, { ...EXT })(body, \"$\");\n },\n\n UamContactGrant(body) {\n object({\n type: constant(\"UamContactGrant\"), v: constant(1), issuer: passkey,\n issuerOwner: ownerRefNoKeys, credentialSubject: subject,\n authorization_details: list(object({\n type: constant(\"uam_contact\"), actions: list(oneOf(\"message\"), 1, 1),\n locations: list(location),\n }), 1, 8),\n via: oneOf(\"intro_email\", \"intro_code\", \"intro_qr\", \"request\", \"carried_over\"),\n enforcer: domain, validFrom: time, validUntil: time, nonce,\n }, { ...EXT })(body, \"$\");\n const d = span(body, \"validFrom\", \"validUntil\");\n if (!(d > 0 && d <= GRANT_MAX_DAYS * DAY)) {\n fail(\"$.validUntil\", `must be after validFrom, within ${GRANT_MAX_DAYS} days`);\n }\n },\n\n // Who may message an agent, as its owner approved it (P2e). Only a change\n // that widens it is signed; narrowing needs no passkey.\n UamAgentPolicy(body) {\n object({\n type: constant(\"UamAgentPolicy\"), v: constant(1), owner: ownerRef, agent: address,\n agentKey, policy: oneOf(\"open\", \"contacts\"), sameOwner: bool, validFrom: time, nonce,\n }, { ...EXT })(body, \"$\");\n },\n};\n\nconst SUBJECTS: Record<string, Check> = {\n owner: object({ kind: constant(\"owner\"), owner: ownerRef }),\n invitee: object({ kind: constant(\"invitee\"), invite: hash }),\n agent: object({ kind: constant(\"agent\"), id: agentKey, address }),\n};\n\nfunction subject(value: unknown, path: string): void {\n const kind = isPlainObject(value) ? value[\"kind\"] : undefined;\n if (typeof kind !== \"string\" || !has(SUBJECTS, kind)) {\n fail(`${path}.kind`, `must be one of ${Object.keys(SUBJECTS).join(\", \")}`);\n }\n SUBJECTS[kind]!(value, path);\n}\n\n/** Refuse a body outside the profile or its type's schema. */\nexport function validate(body: unknown): asserts body is Body {\n if (!isPlainObject(body)) throw new SignedObjectError(\"a body must be a JSON object\");\n encode(body); // the profile\n const type = body[\"type\"];\n if (typeof type !== \"string\" || !has(SCHEMAS, type)) {\n throw new SignedObjectError(`unknown type: ${JSON.stringify(type)}`);\n }\n SCHEMAS[type]!(body);\n checkExt(body);\n}\n","/**\n * did:key for the two key types owner objects carry (as the Python SDK).\n *\n * Ed25519 (an agent's key, `did:key:z6Mk...`, multicodec 0xed) and P-256\n * (a passkey, `did:key:zDn...`, multicodec 0x1200, compressed point).\n */\n\nimport { UAMError } from \"./errors.js\";\n\nconst B58 = \"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz\";\n\nexport type DidKeyKind = \"ed25519\" | \"p256\";\n\nconst PREFIX: Record<DidKeyKind, Uint8Array> = {\n ed25519: new Uint8Array([0xed, 0x01]),\n p256: new Uint8Array([0x80, 0x24]),\n};\nconst LENGTH: Record<DidKeyKind, number> = { ed25519: 32, p256: 33 };\n\n/** A did:key string that isn't one of the two supported key types. */\nexport class InvalidDidKeyError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"InvalidDidKeyError\";\n }\n}\n\nexport function b58encode(data: Uint8Array): string {\n let n = 0n;\n for (const byte of data) n = (n << 8n) | BigInt(byte);\n let out = \"\";\n while (n > 0n) {\n out = B58[Number(n % 58n)] + out;\n n /= 58n;\n }\n let zeros = 0;\n while (zeros < data.length && data[zeros] === 0) zeros += 1;\n return \"1\".repeat(zeros) + out;\n}\n\nexport function b58decode(text: string): Uint8Array {\n let n = 0n;\n for (const c of text) {\n const i = B58.indexOf(c);\n if (i < 0) throw new InvalidDidKeyError(`not base58btc: ${JSON.stringify(c)}`);\n n = n * 58n + BigInt(i);\n }\n const body: number[] = [];\n while (n > 0n) {\n body.unshift(Number(n & 0xffn));\n n >>= 8n;\n }\n let zeros = 0;\n while (zeros < text.length && text[zeros] === \"1\") zeros += 1;\n return new Uint8Array([...new Array<number>(zeros).fill(0), ...body]);\n}\n\nfunction checkKey(kind: DidKeyKind, key: Uint8Array): void {\n if (key.length !== LENGTH[kind]) {\n throw new InvalidDidKeyError(`${kind} key must be ${LENGTH[kind]} bytes`);\n }\n if (kind === \"p256\" && key[0] !== 2 && key[0] !== 3) {\n throw new InvalidDidKeyError(\"P-256 key must be a compressed point\");\n }\n}\n\n/** `did:key:z...` for an Ed25519 key (32 bytes) or a compressed P-256 point (33 bytes). */\nexport function encodeDidKey(kind: DidKeyKind, publicKey: Uint8Array): string {\n if (!(kind in PREFIX)) throw new InvalidDidKeyError(`unsupported key type: ${kind}`);\n checkKey(kind, publicKey);\n return \"did:key:z\" + b58encode(new Uint8Array([...PREFIX[kind], ...publicKey]));\n}\n\n/** The key type and raw public key in a did:key string. */\nexport function decodeDidKey(did: string): { kind: DidKeyKind; key: Uint8Array } {\n if (typeof did !== \"string\" || !did.startsWith(\"did:key:z\")) {\n throw new InvalidDidKeyError(\"not a did:key with base58btc multibase\");\n }\n const raw = b58decode(did.slice(\"did:key:z\".length));\n for (const kind of Object.keys(PREFIX) as DidKeyKind[]) {\n const prefix = PREFIX[kind];\n if (raw.length >= prefix.length && prefix.every((b, i) => raw[i] === b)) {\n const key = raw.slice(prefix.length);\n checkKey(kind, key);\n return { kind, key };\n }\n }\n throw new InvalidDidKeyError(\"unsupported key type\");\n}\n","/**\n * Passkeys (WebAuthn): registration, assertions and the approval challenge.\n *\n * Mirrors uam.protocol.webauthn in the Python SDK; both are checked against\n * the same vectors (tests/vectors/webauthn/).\n *\n * - registration: `webauthn.create`, attestation format `none` only, user\n * present and verified, ES256 only;\n * - assertion: `webauthn.get`, the exact challenge, the owner origin exactly,\n * no cross-origin frame, rpIdHash = SHA-256(RP ID), user present and\n * verified, backup eligibility unchanged, an ES256 signature over\n * `authenticatorData || SHA-256(clientDataJSON)` (high-S accepted), and,\n * where the stored counter is known, a counter that went up whenever either\n * count is non-zero (synced passkeys report 0 throughout; a count that\n * drops to 0 may be a clone).\n *\n * ES256 only: a passkey's did:key must never look like an agent key.\n */\n\nimport { createHash } from \"node:crypto\";\n\nimport { p256 } from \"@noble/curves/p256\";\n\nimport { encodeDidKey } from \"./didkey.js\";\nimport { UAMError } from \"./errors.js\";\nimport { SignedObjectError, canonical } from \"./signed.js\";\n\nexport const ES256 = -7;\n\nconst UP = 0x01;\nconst UV = 0x04;\nconst BE = 0x08;\nconst AT = 0x40;\nconst ED = 0x80;\n\n/** A registration or assertion that fails a check. */\nexport class WebAuthnError extends UAMError {\n constructor(message?: string) {\n super(message);\n this.name = \"WebAuthnError\";\n }\n}\n\n/** A registered passkey: its id, algorithm, compressed P-256 key and flags. */\nexport interface Credential {\n readonly id: Uint8Array;\n readonly alg: number;\n readonly publicKey: Uint8Array;\n readonly backupEligible: boolean;\n readonly signCount: number;\n}\n\nexport function credentialDid(credential: Credential): string {\n return encodeDidKey(\"p256\", credential.publicKey);\n}\n\nconst sha256 = (...parts: Uint8Array[]): Uint8Array => {\n const h = createHash(\"sha256\");\n for (const part of parts) h.update(part);\n return new Uint8Array(h.digest());\n};\n\nconst equal = (a: Uint8Array, b: Uint8Array) =>\n a.length === b.length && a.every((byte, i) => byte === b[i]);\n\n// --- CBOR (the subset WebAuthn uses) ------------------------------------------\n\ntype CborValue = number | boolean | string | Uint8Array | CborValue[] | Map<number | string, CborValue>;\n\nfunction cbor(data: Uint8Array, start: number): [CborValue, number] {\n let i = start;\n if (i >= data.length) throw new WebAuthnError(\"CBOR: truncated\");\n const first = data[i]!;\n const major = first >> 5;\n const info = first & 0x1f;\n i += 1;\n if (major === 7) {\n if (info === 20) return [false, i];\n if (info === 21) return [true, i];\n throw new WebAuthnError(\"CBOR: unsupported simple value or float\");\n }\n let n: number;\n if (info < 24) {\n n = info;\n } else if (info >= 24 && info <= 27) {\n const size = 1 << (info - 24);\n if (i + size > data.length) throw new WebAuthnError(\"CBOR: truncated\");\n let big = 0n;\n for (let k = 0; k < size; k += 1) big = (big << 8n) | BigInt(data[i + k]!);\n if (big > BigInt(Number.MAX_SAFE_INTEGER)) throw new WebAuthnError(\"CBOR: number too large\");\n n = Number(big);\n i += size;\n } else {\n throw new WebAuthnError(\"CBOR: indefinite lengths are not supported\");\n }\n if (major === 0) return [n, i];\n if (major === 1) return [-1 - n, i];\n if (major === 2 || major === 3) {\n if (i + n > data.length) throw new WebAuthnError(\"CBOR: truncated\");\n const raw = data.slice(i, i + n);\n i += n;\n if (major === 2) return [raw, i];\n try {\n return [new TextDecoder(\"utf-8\", { fatal: true }).decode(raw), i];\n } catch {\n throw new WebAuthnError(\"CBOR: text is not UTF-8\");\n }\n }\n if (major === 4) {\n const items: CborValue[] = [];\n for (let k = 0; k < n; k += 1) {\n const [item, next] = cbor(data, i);\n items.push(item);\n i = next;\n }\n return [items, i];\n }\n if (major === 5) {\n const out = new Map<number | string, CborValue>();\n for (let k = 0; k < n; k += 1) {\n const [key, afterKey] = cbor(data, i);\n if (typeof key !== \"number\" && typeof key !== \"string\") {\n throw new WebAuthnError(\"CBOR: map keys must be integers or text\");\n }\n if (out.has(key)) throw new WebAuthnError(\"CBOR: duplicate map key\");\n const [value, afterValue] = cbor(data, afterKey);\n out.set(key, value);\n i = afterValue;\n }\n return [out, i];\n }\n throw new WebAuthnError(\"CBOR: tags are not supported\");\n}\n\nfunction cborWhole(data: Uint8Array): CborValue {\n const [value, end] = cbor(data, 0);\n if (end !== data.length) throw new WebAuthnError(\"CBOR: trailing bytes\");\n return value;\n}\n\n// --- shared checks ------------------------------------------------------------\n\nfunction checkClientData(raw: Uint8Array, kind: string, challenge: Uint8Array, origin: string): void {\n let data: unknown;\n try {\n data = JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(raw));\n } catch {\n throw new WebAuthnError(\"clientDataJSON is not JSON\");\n }\n if (data === null || typeof data !== \"object\" || Array.isArray(data)) {\n throw new WebAuthnError(\"clientDataJSON is not an object\");\n }\n const d = data as Record<string, unknown>;\n if (d[\"type\"] !== kind) throw new WebAuthnError(`clientData.type must be ${kind}`);\n if (d[\"challenge\"] !== Buffer.from(challenge).toString(\"base64url\")) {\n throw new WebAuthnError(\"clientData.challenge doesn't match\");\n }\n if (d[\"origin\"] !== origin) throw new WebAuthnError(\"clientData.origin doesn't match\");\n if (\"crossOrigin\" in d && d[\"crossOrigin\"] !== false) {\n throw new WebAuthnError(\"cross-origin ceremonies are refused\");\n }\n if (\"topOrigin\" in d) throw new WebAuthnError(\"ceremonies in a frame are refused\");\n}\n\nfunction checkAuthData(data: Uint8Array, rpId: string): { flags: number; count: number } {\n if (data.length < 37) throw new WebAuthnError(\"authenticatorData too short\");\n if (!equal(data.slice(0, 32), sha256(new TextEncoder().encode(rpId)))) {\n throw new WebAuthnError(\"rpIdHash doesn't match\");\n }\n const flags = data[32]!;\n if (!(flags & UP)) throw new WebAuthnError(\"user not present\");\n if (!(flags & UV)) throw new WebAuthnError(\"user not verified\");\n const count = new DataView(data.buffer, data.byteOffset + 33, 4).getUint32(0, false);\n return { flags, count };\n}\n\nfunction point(bytes: Uint8Array) {\n try {\n return p256.ProjectivePoint.fromHex(bytes);\n } catch {\n throw new WebAuthnError(\"not a P-256 point\");\n }\n}\n\n// --- registration ---------------------------------------------------------------\n\n/** Check a `webauthn.create` response; the passkey it registers. */\nexport function verifyRegistration(args: {\n attestationObject: Uint8Array;\n clientDataJSON: Uint8Array;\n challenge: Uint8Array;\n origin: string;\n rpId: string;\n}): Credential {\n checkClientData(args.clientDataJSON, \"webauthn.create\", args.challenge, args.origin);\n const att = cborWhole(args.attestationObject);\n if (\n !(att instanceof Map) || att.size !== 3 ||\n !att.has(\"fmt\") || !att.has(\"attStmt\") || !att.has(\"authData\")\n ) {\n throw new WebAuthnError(\"attestationObject must have fmt, attStmt and authData\");\n }\n const stmt = att.get(\"attStmt\");\n if (att.get(\"fmt\") !== \"none\" || !(stmt instanceof Map) || stmt.size !== 0) {\n throw new WebAuthnError(\"only attestation format 'none' is accepted\");\n }\n const data = att.get(\"authData\");\n if (!(data instanceof Uint8Array)) throw new WebAuthnError(\"authData must be bytes\");\n const { flags, count } = checkAuthData(data, args.rpId);\n if (!(flags & AT)) throw new WebAuthnError(\"no attested credential data\");\n if (data.length < 55) throw new WebAuthnError(\"attested credential data too short\");\n const idLen = (data[53]! << 8) | data[54]!;\n const credentialId = data.slice(55, 55 + idLen);\n if (credentialId.length !== idLen) throw new WebAuthnError(\"credential id truncated\");\n const [cose, end] = cbor(data, 55 + idLen);\n if (!(flags & ED) && end !== data.length) {\n throw new WebAuthnError(\"trailing bytes after the credential key\");\n }\n // kty EC2, alg ES256, crv P-256; other COSE parameters are ignored.\n if (!(cose instanceof Map) || cose.get(1) !== 2 || cose.get(3) !== ES256 || cose.get(-1) !== 1) {\n throw new WebAuthnError(\"only ES256 (P-256) passkeys are accepted\");\n }\n const x = cose.get(-2);\n const y = cose.get(-3);\n if (!(x instanceof Uint8Array) || !(y instanceof Uint8Array) || x.length !== 32 || y.length !== 32) {\n throw new WebAuthnError(\"bad P-256 coordinates\");\n }\n const key = point(new Uint8Array([4, ...x, ...y]));\n return {\n id: credentialId,\n alg: ES256,\n publicKey: key.toRawBytes(true),\n backupEligible: Boolean(flags & BE),\n signCount: count,\n };\n}\n\n// --- assertions -----------------------------------------------------------------\n\n/**\n * Check a `webauthn.get` response from `credential`; its new sign count.\n *\n * `checkCounter: false` is for a verifier without the stored counter (an\n * agent checking an approval offline); the relay always checks it.\n */\nexport function verifyAssertion(\n credential: Credential,\n args: {\n authenticatorData: Uint8Array;\n clientDataJSON: Uint8Array;\n signature: Uint8Array;\n challenge: Uint8Array;\n origin: string;\n rpId: string;\n checkCounter?: boolean;\n }\n): number {\n if (credential.alg !== ES256) throw new WebAuthnError(\"only ES256 (P-256) passkeys are accepted\");\n checkClientData(args.clientDataJSON, \"webauthn.get\", args.challenge, args.origin);\n const { flags, count } = checkAuthData(args.authenticatorData, args.rpId);\n if (Boolean(flags & BE) !== credential.backupEligible) {\n throw new WebAuthnError(\"backup eligibility changed since registration\");\n }\n const key = point(credential.publicKey);\n const digest = sha256(args.authenticatorData, sha256(args.clientDataJSON));\n let ok = false;\n try {\n ok = p256.verify(args.signature, digest, key.toRawBytes(false), {\n format: \"der\", lowS: false, prehash: false,\n });\n } catch {\n ok = false;\n }\n if (!ok) throw new WebAuthnError(\"bad signature\");\n const checkCounter = args.checkCounter ?? true;\n if (checkCounter && (count || credential.signCount) && count <= credential.signCount) {\n throw new WebAuthnError(\"sign count didn't go up: the passkey may have been cloned\");\n }\n return count;\n}\n\n// --- approvals ------------------------------------------------------------------\n\n/**\n * The challenge one Face ID signs to approve `items` (type, hash) as shown.\n *\n * `screen` is the exact text the page showed; the challenge commits to its\n * SHA-256, so the page can't show one thing and get another signed.\n */\nexport function approvalChallenge(items: Array<[string, string]>, screen: string): Uint8Array {\n if (items.length === 0) throw new WebAuthnError(\"an approval covers at least one object\");\n const body = {\n set: items.map(([t, h]) => ({ t, h })),\n screen: createHash(\"sha256\").update(screen, \"utf8\").digest(\"hex\"),\n };\n let data: Uint8Array;\n try {\n data = canonical(body);\n } catch (err) {\n if (err instanceof SignedObjectError) throw new WebAuthnError(`bad approval set: ${err.message}`);\n throw err;\n }\n return sha256(new TextEncoder().encode(\"UAM-APPROVAL-v1\\n\"), data);\n}\n","/**\n * SDK version, taken from package.json at build time.\n *\n * `__UAM_SDK_VERSION__` is replaced by tsup (tsup.config.ts) and defined by\n * vitest (vitest.config.ts), both from package.json's \"version\", so there is\n * a single place to bump it.\n */\n\ndeclare const __UAM_SDK_VERSION__: string;\n\nexport const SDK_VERSION: string = __UAM_SDK_VERSION__;\n","/**\n * SDK configuration (matching Python config.py).\n *\n * Priority (highest wins): constructor arg > env var > default.\n * TOML config file support is Python-only for now (unnecessary complexity for TS MVP).\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst DEFAULT_RELAY_URL = \"https://relay.youam.network\";\n\n/** `url` with any trailing slashes removed. */\nexport function trimRelayUrl(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nconst VALID_POLICIES = new Set([\n \"auto-accept\",\n \"approval-required\",\n \"allowlist-only\",\n \"require_verify\",\n]);\n\nexport class SDKConfig {\n readonly name: string;\n readonly relayUrl: string;\n readonly relayWsUrl: string;\n readonly keyDir: string;\n readonly dataDir: string;\n readonly displayName: string;\n readonly transportType: string;\n readonly trustPolicy: string;\n relayDomain: string;\n /** The domain the caller chose, if any; null when only derived. */\n readonly explicitRelayDomain: string | null;\n\n constructor(options: {\n name: string;\n relayUrl?: string | null;\n relayWsUrl?: string | null;\n keyDir?: string | null;\n dataDir?: string | null;\n displayName?: string | null;\n transportType?: string;\n trustPolicy?: string;\n relayDomain?: string;\n }) {\n this.name = options.name;\n\n // Relay URL: constructor arg > env var > default\n this.relayUrl = trimRelayUrl(\n options.relayUrl ?? process.env[\"UAM_RELAY_URL\"] ?? DEFAULT_RELAY_URL\n );\n\n // Derive relayWsUrl from relayUrl if not explicitly set\n if (options.relayWsUrl) {\n this.relayWsUrl = options.relayWsUrl;\n } else {\n let wsUrl = this.relayUrl\n .replace(\"https://\", \"wss://\")\n .replace(\"http://\", \"ws://\");\n if (!wsUrl.endsWith(\"/ws\")) {\n wsUrl = wsUrl.replace(/\\/+$/, \"\") + \"/ws\";\n }\n this.relayWsUrl = wsUrl;\n }\n\n // Derive relayDomain: env var > constructor arg > URL hostname\n const envDomain = process.env[\"UAM_RELAY_DOMAIN\"];\n this.explicitRelayDomain = envDomain || options.relayDomain || null;\n if (envDomain) {\n this.relayDomain = envDomain;\n } else if (options.relayDomain) {\n this.relayDomain = options.relayDomain;\n } else {\n // Extract hostname from relayUrl\n try {\n const parsed = new URL(this.relayUrl);\n this.relayDomain = parsed.hostname || \"localhost\";\n } catch {\n // Fallback for malformed URLs\n const afterScheme = this.relayUrl.split(\"://\").pop() || \"\";\n this.relayDomain = afterScheme.split(\"/\")[0] || \"localhost\";\n }\n }\n\n // Default key_dir and data_dir.\n // UAM_HOME env var overrides ~/.uam (useful for testing / isolation).\n const uamHome = process.env[\"UAM_HOME\"];\n const defaultHome = uamHome || join(homedir(), \".uam\");\n\n this.keyDir = options.keyDir ?? join(defaultHome, \"keys\");\n this.dataDir = options.dataDir ?? defaultHome;\n\n // Display name defaults to agent name\n this.displayName = options.displayName ?? this.name;\n\n // Transport type\n this.transportType = options.transportType ?? \"websocket\";\n\n // Trust policy: constructor arg > env var > default\n let policy = options.trustPolicy ?? \"auto-accept\";\n const envPolicy = process.env[\"UAM_TRUST_POLICY\"];\n if (envPolicy) {\n policy = envPolicy;\n }\n\n if (!VALID_POLICIES.has(policy)) {\n throw new Error(\n `Invalid trust_policy '${policy}'. ` +\n `Must be one of: ${JSON.stringify([...VALID_POLICIES].sort())}`\n );\n }\n\n this.trustPolicy = policy;\n }\n}\n","/**\n * When to believe the relay about mail that waited in storage.\n *\n * A signed timestamp cannot tell \"signed, stored, delivered later\" from an\n * old envelope sent again. The relay's relay_meta stamp can, so long as the\n * recipient's own relay wrote it.\n *\n * Matches the Python SDK's freshness.py.\n */\n\nimport { MAX_ENVELOPE_AGE } from \"../protocol/types.js\";\n\n/** Listed in GET /api/v1/versions by relays that write relay_meta. */\nexport const RELAY_META_FEATURE = \"relay_meta\";\n\n/** How long stored mail stays deliverable, in seconds. */\nexport const STORED_MAIL_MAX_AGE = 7 * 86400;\n\n// A full ISO 8601 time with a zone. Date.parse alone also takes loose formats\n// and reads a time with no zone as local.\nconst ISO_TIME =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$/;\n\n/**\n * True if `raw` carries a stamp showing it was stored soon after signing.\n *\n * This only reads the stamp. The caller must also know that the relay writes\n * these stamps, or a sender could have written this one.\n *\n * @param signedAt - The envelope's signed time, in ms since the epoch\n * @param now - The current time, in ms since the epoch\n */\nexport function relayVouches(\n raw: Record<string, unknown>,\n signedAt: number,\n now: number,\n relayDomain: string\n): boolean {\n const meta = raw[\"relay_meta\"];\n if (typeof meta !== \"object\" || meta === null || Array.isArray(meta)) {\n return false;\n }\n const stamp = meta as Record<string, unknown>;\n if (stamp[\"v\"] !== 1 || stamp[\"relay\"] !== relayDomain) return false;\n if (stamp[\"stored\"] !== true) return false;\n\n const received = stamp[\"received_at\"];\n if (typeof received !== \"string\" || !ISO_TIME.test(received)) return false;\n const receivedAt = Date.parse(received);\n if (Number.isNaN(receivedAt)) return false;\n\n const window = MAX_ENVELOPE_AGE * 1000;\n const age = now - signedAt;\n return (\n Math.abs(receivedAt - signedAt) <= window &&\n age >= 0 &&\n age <= STORED_MAIL_MAX_AGE * 1000 + window\n );\n}\n","/**\n * Ed25519 key generation, storage, loading, and token persistence.\n *\n * Matches Python key_manager.py: stores 32-byte seed (not 64-byte secret key),\n * uses same file format so keys are cross-language compatible.\n */\n\nimport {\n chmodSync,\n mkdirSync,\n readFileSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { platform } from \"node:os\";\n\nimport {\n type Keypair,\n type SigningKey,\n type VerifyKey,\n type Seed,\n parseAddress,\n generateKeypair,\n serializeSigningKey,\n deserializeSigningKey,\n serializeVerifyKey,\n} from \"../protocol/index.js\";\nimport { trimRelayUrl } from \"./config.js\";\n\nconst DEFAULT_KEY_DIR = join(homedir(), \".uam\", \"keys\");\n\nexport class KeyManager {\n private _keyDir: string;\n private _keypair: Keypair | null = null;\n\n constructor(keyDir?: string | null) {\n this._keyDir = keyDir ?? DEFAULT_KEY_DIR;\n }\n\n /** The 64-byte Ed25519 signing key. Throws if not loaded. */\n get signingKey(): SigningKey {\n if (this._keypair === null) {\n throw new Error(\"No keypair loaded. Call loadOrGenerate() first.\");\n }\n return this._keypair.signingKey;\n }\n\n /** The 32-byte Ed25519 verify (public) key. Throws if not loaded. */\n get verifyKey(): VerifyKey {\n if (this._keypair === null) {\n throw new Error(\"No keypair loaded. Call loadOrGenerate() first.\");\n }\n return this._keypair.verifyKey;\n }\n\n /** The 32-byte seed. Throws if not loaded. */\n get seed(): Seed {\n if (this._keypair === null) {\n throw new Error(\"No keypair loaded. Call loadOrGenerate() first.\");\n }\n return this._keypair.seed;\n }\n\n /**\n * Load existing keypair or generate a new one.\n *\n * Checks UAM_SIGNING_KEY env var first (base64-encoded Ed25519 seed).\n * Falls back to file-based storage at {keyDir}/{name}.key.\n * Generates a new keypair if neither source exists.\n */\n loadOrGenerate(name: string): void {\n // 1. Check environment variable\n const envKey = process.env[\"UAM_SIGNING_KEY\"];\n if (envKey) {\n this._keypair = deserializeSigningKey(envKey.trim());\n return;\n }\n\n // 2. File-based storage\n mkdirSync(this._keyDir, { recursive: true });\n const keyPath = join(this._keyDir, `${name}.key`);\n const pubPath = join(this._keyDir, `${name}.pub`);\n\n if (existsSync(keyPath)) {\n // Returning user: load existing keys\n this._checkPermissions(keyPath);\n const seedB64 = readFileSync(keyPath, \"utf-8\").trim();\n this._keypair = deserializeSigningKey(seedB64);\n } else {\n // First-run: generate new keypair\n this._keypair = generateKeypair();\n writeFileSync(keyPath, serializeSigningKey(this._keypair.seed));\n writeFileSync(pubPath, serializeVerifyKey(this._keypair.verifyKey));\n this._setPermissions(keyPath);\n }\n }\n\n /**\n * Store the relay token alongside the keypair.\n */\n saveToken(name: string, token: string): void {\n mkdirSync(this._keyDir, { recursive: true });\n const tokenPath = join(this._keyDir, `${name}.token`);\n writeFileSync(tokenPath, token);\n this._setPermissions(tokenPath);\n }\n\n /**\n * Store the address `relayUrl` gave this agent.\n */\n saveAddress(name: string, address: string, relayUrl: string): void {\n mkdirSync(this._keyDir, { recursive: true });\n writeFileSync(\n join(this._keyDir, `${name}.address`),\n JSON.stringify({ address, relay_url: relayUrl })\n );\n }\n\n /**\n * Load the address saved for `relayUrl`.\n *\n * Returns null if there is none: the file is missing, unreadable or\n * malformed, or it belongs to another relay.\n */\n loadAddress(name: string, relayUrl: string): string | null {\n try {\n const path = join(this._keyDir, `${name}.address`);\n const saved = JSON.parse(readFileSync(path, \"utf-8\")) as {\n address?: unknown;\n relay_url?: unknown;\n } | null;\n const address = saved?.address;\n const savedRelay = saved?.relay_url;\n if (typeof address !== \"string\" || typeof savedRelay !== \"string\") {\n return null;\n }\n if (trimRelayUrl(savedRelay) !== trimRelayUrl(relayUrl)) return null;\n parseAddress(address);\n return address;\n } catch {\n return null;\n }\n }\n\n /**\n * Load a previously saved token, or return null.\n *\n * Checks UAM_TOKEN env var first, then file-based storage,\n * then legacy .api_key files for backward compatibility. With `relayUrl`,\n * a saved token that belongs to another relay counts as none, so it is\n * only offered to the relay that issued it.\n */\n loadToken(name: string, relayUrl?: string): string | null {\n // 1. Check environment variable\n const envToken = process.env[\"UAM_TOKEN\"];\n if (envToken) {\n return envToken.trim();\n }\n\n if (relayUrl !== undefined && this._savedForAnotherRelay(name, relayUrl)) {\n return null;\n }\n\n // 2. File-based storage\n const tokenPath = join(this._keyDir, `${name}.token`);\n if (existsSync(tokenPath)) {\n return readFileSync(tokenPath, \"utf-8\").trim();\n }\n // Backward compatibility: check for legacy .api_key file\n const legacyPath = join(this._keyDir, `${name}.api_key`);\n if (existsSync(legacyPath)) {\n return readFileSync(legacyPath, \"utf-8\").trim();\n }\n return null;\n }\n\n /**\n * True if the saved address says this agent's files are another relay's.\n * A missing or damaged file says nothing.\n */\n private _savedForAnotherRelay(name: string, relayUrl: string): boolean {\n try {\n const path = join(this._keyDir, `${name}.address`);\n const saved = JSON.parse(readFileSync(path, \"utf-8\")) as {\n relay_url?: unknown;\n } | null;\n const savedRelay = saved?.relay_url;\n return (\n typeof savedRelay === \"string\" &&\n trimRelayUrl(savedRelay) !== trimRelayUrl(relayUrl)\n );\n } catch {\n return false;\n }\n }\n\n /** Set file permissions to 0o600 (owner read/write only). */\n private _setPermissions(path: string): void {\n if (platform() !== \"win32\") {\n chmodSync(path, 0o600);\n }\n }\n\n /** Warn if key file permissions are too permissive. */\n private _checkPermissions(path: string): void {\n if (platform() === \"win32\") {\n return; // Cannot reliably check on Windows\n }\n try {\n const mode = statSync(path).mode & 0o777;\n if (mode !== 0o600) {\n console.warn(\n `Key file ${path} has permissions ${mode.toString(8)} (expected 600). ` +\n `Run: chmod 600 ${path}`\n );\n }\n } catch {\n // Ignore stat errors\n }\n }\n}\n","/**\n * ReceivedMessage -- frozen data object for inbound messages.\n *\n * Matches Python message.py: a readonly interface for decrypted messages.\n * The toString() omission is deliberate prompt-injection isolation (SDK-10).\n */\n\n/**\n * A decrypted, verified inbound message.\n *\n * This is a DATA OBJECT. Framework integrations must explicitly\n * extract .content to use in prompts. The SDK never concatenates\n * message content into LLM context automatically.\n */\nexport interface ReceivedMessage {\n readonly messageId: string;\n readonly fromAddress: string;\n readonly toAddress: string;\n readonly content: string;\n readonly timestamp: string;\n readonly type: string;\n readonly threadId?: string;\n readonly replyTo?: string;\n readonly mediaType?: string;\n readonly verified: boolean;\n}\n\n/** What a relay can say it did with a sent message (as the Python SDK). */\nexport const SEND_STATUSES = [\n \"delivered\",\n \"stored\",\n \"relayed\",\n \"queued\",\n \"duplicate\",\n \"dropped\",\n \"pending\",\n \"accepted\",\n \"unknown\",\n] as const;\n\nexport type SendStatus = (typeof SEND_STATUSES)[number];\n\n/**\n * What Agent.send() returns.\n *\n * `status` is one of SEND_STATUSES: \"pending\" means the recipient only\n * takes messages from approved contacts and the relay kept nothing.\n * `delivered` is true only when the relay says the recipient has it.\n */\nexport interface SendResult {\n readonly messageId: string;\n readonly status: SendStatus;\n readonly delivered: boolean;\n}\n\n/**\n * The status in a relay's answer to a send (HTTP body or WebSocket ack).\n *\n * null (no answer in time) is \"unknown\". An answer without a known status\n * comes from a relay before 1.1: \"accepted\".\n */\nexport function sendStatus(answer: Record<string, unknown> | null): SendStatus {\n if (answer === null) return \"unknown\";\n const status = answer[\"status\"];\n if (\n typeof status === \"string\" &&\n (SEND_STATUSES as readonly string[]).includes(status) &&\n status !== \"accepted\" &&\n status !== \"unknown\"\n ) {\n return status as SendStatus;\n }\n return \"accepted\";\n}\n\n/**\n * True when a relay's features include `name` at `version` or later.\n *\n * \"name\" is version 1; \"name:N\" means version N or later.\n */\nexport function supports(\n features: Iterable<string>,\n name: string,\n version: number = 1\n): boolean {\n const prefix = `${name}:`;\n for (const feature of features) {\n if (feature === name && version <= 1) return true;\n if (feature.startsWith(prefix)) {\n const rest = feature.slice(prefix.length);\n if (/^\\d+$/.test(rest) && Number(rest) >= version) return true;\n }\n }\n return false;\n}\n\n/** What to tell whoever sent a message the relay answered \"pending\". */\nexport const PENDING_NOTE =\n \"Not delivered: {to} only accepts messages from approved contacts. \" +\n \"Do not resend it.\";\n\nexport function pendingNote(to: string): string {\n return PENDING_NOTE.replace(\"{to}\", to);\n}\n","/**\n * SQLite-backed local contact storage (HAND-03).\n *\n * Stores known contacts with their public keys and trust state.\n * Provides fast in-memory caches for isKnown() and isBlocked() checks.\n *\n * Uses better-sqlite3 for synchronous SQLite (simpler than Python's aiosqlite).\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport Database from \"better-sqlite3\";\nimport { KeyPinningError } from \"../protocol/errors.js\";\nimport { log } from \"./log.js\";\n\n/**\n * A row returned from listContacts().\n */\nexport interface ContactRow {\n address: string;\n displayName: string | null;\n trustState: string;\n firstSeen: string;\n lastSeen: string;\n}\n\n/**\n * A pending handshake entry.\n */\nexport interface PendingEntry {\n address: string;\n contactCard: string;\n receivedAt: string;\n}\n\n/**\n * A blocked pattern entry.\n */\nexport interface BlockedEntry {\n pattern: string;\n blockedAt: string;\n}\n\nexport class ContactBook {\n private _dbPath: string;\n private _db: Database.Database | null = null;\n private _knownAddresses: Set<string> = new Set();\n private _blockedExact: Set<string> = new Set();\n private _blockedDomains: Set<string> = new Set();\n\n constructor(dataDir: string) {\n this._dbPath = join(dataDir, \"contacts\", \"contacts.db\");\n }\n\n /**\n * Open the database, create tables, run migrations, load caches.\n */\n open(): void {\n mkdirSync(dirname(this._dbPath), { recursive: true });\n this._db = new Database(this._dbPath);\n this._db.pragma(\"journal_mode = WAL\");\n\n // Create tables with all columns upfront (no migrations needed for new DB)\n this._db.exec(`\n CREATE TABLE IF NOT EXISTS contacts (\n address TEXT PRIMARY KEY,\n public_key TEXT NOT NULL,\n display_name TEXT,\n trust_state TEXT NOT NULL DEFAULT 'unknown',\n trust_source TEXT DEFAULT 'legacy-unknown',\n relay TEXT,\n relays_json TEXT,\n pinned_at TEXT,\n first_seen TEXT NOT NULL DEFAULT (datetime('now')),\n last_seen TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS pending_handshakes (\n address TEXT PRIMARY KEY,\n contact_card TEXT NOT NULL,\n received_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS blocked_patterns (\n pattern TEXT PRIMARY KEY,\n blocked_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n `);\n\n // Run migrations\n this._migrate();\n\n // Load all known addresses into memory for fast sync lookups\n const rows = this._db\n .prepare(\"SELECT address FROM contacts\")\n .all() as Array<{ address: string }>;\n this._knownAddresses = new Set(rows.map((r) => r.address));\n\n // Load blocked patterns into memory\n this._blockedExact.clear();\n this._blockedDomains.clear();\n const blocked = this._db\n .prepare(\"SELECT pattern FROM blocked_patterns\")\n .all() as Array<{ pattern: string }>;\n for (const row of blocked) {\n this._cacheBlockPattern(row.pattern);\n }\n }\n\n /**\n * Run schema migrations using PRAGMA user_version.\n */\n private _migrate(): void {\n if (!this._db) return;\n\n const versionRow = this._db\n .prepare(\"PRAGMA user_version\")\n .get() as { user_version: number };\n const version = versionRow.user_version;\n\n if (version < 2) {\n // For new DBs, tables are created with all columns upfront\n // (including pinned_at). Skip straight to version 3.\n this._db.exec(\"PRAGMA user_version = 3\");\n } else if (version < 3) {\n // Existing v2 database: add pinned_at column for key pinning lifecycle\n this._db.exec(\n \"ALTER TABLE contacts ADD COLUMN pinned_at TEXT\"\n );\n this._db.exec(\"PRAGMA user_version = 3\");\n }\n }\n\n /**\n * Close the database connection.\n */\n close(): void {\n if (this._db !== null) {\n this._db.close();\n this._db = null;\n }\n }\n\n /**\n * Check if an address is in the contact book (in-memory, no I/O).\n */\n isKnown(address: string): boolean {\n return this._knownAddresses.has(address);\n }\n\n /**\n * Check if an address matches any blocked pattern (O(1) set lookup).\n */\n isBlocked(address: string): boolean {\n if (this._blockedExact.has(address)) {\n return true;\n }\n // Extract domain from 'name::domain' format\n if (address.includes(\"::\")) {\n const domain = address.split(\"::\")[1];\n return this._blockedDomains.has(domain);\n }\n return false;\n }\n\n /**\n * Look up the public key for a known contact.\n */\n getPublicKey(address: string): string | null {\n if (this._db === null) return null;\n const row = this._db\n .prepare(\"SELECT public_key FROM contacts WHERE address = ?\")\n .get(address) as { public_key: string } | undefined;\n return row?.public_key ?? null;\n }\n\n /**\n * Return the relay URLs for a known contact (CARD-04).\n */\n getRelayUrls(address: string): string[] | null {\n if (this._db === null) return null;\n const row = this._db\n .prepare(\"SELECT relay, relays_json FROM contacts WHERE address = ?\")\n .get(address) as { relay: string | null; relays_json: string | null } | undefined;\n if (!row) return null;\n if (row.relays_json !== null) {\n return JSON.parse(row.relays_json) as string[];\n }\n if (row.relay !== null) {\n return [row.relay];\n }\n return null;\n }\n\n /**\n * Add or update a contact (upsert).\n *\n * Refuses to replace the key of a contact whose trust_state is \"pinned\"\n * or \"verified\" with a different key, unless `force: true` is passed (for\n * a deliberate key rotation, which is logged). Matches the Python SDK's\n * ContactBook.add_contact.\n *\n * @throws {KeyPinningError} If a pinned/verified contact's key would be\n * replaced by a different key without `force`.\n */\n addContact(\n address: string,\n publicKey: string,\n options?: {\n displayName?: string | null;\n trustState?: string;\n trustSource?: string | null;\n relay?: string | null;\n relays?: string[] | null;\n force?: boolean;\n }\n ): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n\n const existing = this._db\n .prepare(\"SELECT public_key, trust_state FROM contacts WHERE address = ?\")\n .get(address) as { public_key: string; trust_state: string } | undefined;\n if (\n existing !== undefined &&\n (existing.trust_state === \"pinned\" ||\n existing.trust_state === \"verified\") &&\n existing.public_key !== publicKey\n ) {\n if (!options?.force) {\n throw new KeyPinningError(\n `Refusing to overwrite ${existing.trust_state} contact ` +\n `${JSON.stringify(address)}: stored public key does not match ` +\n `the new key. Pass force: true to rotate.`\n );\n }\n log.warn(\n `Force-replacing the key of ${existing.trust_state} contact ` +\n `${address} (key rotation)`\n );\n }\n\n const displayName = options?.displayName ?? null;\n const trustState = options?.trustState ?? \"trusted\";\n const trustSource = options?.trustSource ?? null;\n const relay = options?.relay ?? null;\n const relaysJson =\n options?.relays !== undefined && options?.relays !== null\n ? JSON.stringify(options.relays)\n : null;\n\n this._db\n .prepare(\n `INSERT INTO contacts (address, public_key, display_name, trust_state, trust_source, relay, relays_json)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(address) DO UPDATE SET\n public_key = excluded.public_key,\n display_name = excluded.display_name,\n trust_state = excluded.trust_state,\n trust_source = COALESCE(excluded.trust_source, contacts.trust_source),\n relay = COALESCE(excluded.relay, contacts.relay),\n relays_json = COALESCE(excluded.relays_json, contacts.relays_json),\n last_seen = datetime('now')`\n )\n .run(address, publicKey, displayName, trustState, trustSource, relay, relaysJson);\n\n this._knownAddresses.add(address);\n }\n\n /**\n * Return all contacts sorted by last_seen DESC.\n */\n listContacts(): ContactRow[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n \"SELECT address, display_name, trust_state, first_seen, last_seen \" +\n \"FROM contacts ORDER BY last_seen DESC\"\n )\n .all() as Array<{\n address: string;\n display_name: string | null;\n trust_state: string;\n first_seen: string;\n last_seen: string;\n }>;\n return rows.map((r) => ({\n address: r.address,\n displayName: r.display_name,\n trustState: r.trust_state,\n firstSeen: r.first_seen,\n lastSeen: r.last_seen,\n }));\n }\n\n /**\n * Store a pending handshake request.\n */\n addPending(address: string, contactCardJson: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\n `INSERT OR REPLACE INTO pending_handshakes (address, contact_card) VALUES (?, ?)`\n )\n .run(address, contactCardJson);\n }\n\n /**\n * Retrieve all pending handshake requests.\n */\n getPending(): PendingEntry[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n \"SELECT address, contact_card, received_at FROM pending_handshakes\"\n )\n .all() as Array<{\n address: string;\n contact_card: string;\n received_at: string;\n }>;\n return rows.map((r) => ({\n address: r.address,\n contactCard: r.contact_card,\n receivedAt: r.received_at,\n }));\n }\n\n /**\n * Remove a pending handshake request.\n */\n removePending(address: string): void {\n if (this._db === null) return;\n this._db\n .prepare(\"DELETE FROM pending_handshakes WHERE address = ?\")\n .run(address);\n }\n\n /**\n * Return pending handshakes older than N days.\n */\n getExpiredPending(days: number = 7): PendingEntry[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n `SELECT address, contact_card, received_at FROM pending_handshakes\n WHERE datetime(received_at, '+' || ? || ' days') < datetime('now')`\n )\n .all(String(days)) as Array<{\n address: string;\n contact_card: string;\n received_at: string;\n }>;\n return rows.map((r) => ({\n address: r.address,\n contactCard: r.contact_card,\n receivedAt: r.received_at,\n }));\n }\n\n /**\n * Return the trust_state for an address, or null if unknown.\n */\n getTrustState(address: string): string | null {\n if (this._db === null) return null;\n const row = this._db\n .prepare(\"SELECT trust_state FROM contacts WHERE address = ?\")\n .get(address) as { trust_state: string } | undefined;\n return row?.trust_state ?? null;\n }\n\n /**\n * Set the pinned_at timestamp and trust_state='pinned' for a contact (TOFU).\n */\n setPinnedAt(address: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\n \"UPDATE contacts SET pinned_at = datetime('now'), trust_state = 'pinned' WHERE address = ?\"\n )\n .run(address);\n }\n\n /**\n * Remove a contact by address. Returns true if a contact was deleted.\n */\n removeContact(address: string): boolean {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n const result = this._db\n .prepare(\"DELETE FROM contacts WHERE address = ?\")\n .run(address);\n this._knownAddresses.delete(address);\n return result.changes > 0;\n }\n\n /**\n * Return true if the address has trust_state 'trusted', 'verified', or 'pinned'.\n *\n * Convenience helper for inbound message filtering (CARD-05, TOFU-02).\n */\n isTrustedOrVerified(address: string): boolean {\n const state = this.getTrustState(address);\n return state === \"trusted\" || state === \"verified\" || state === \"pinned\";\n }\n\n /**\n * Block an address or domain pattern (e.g., '*::evil.com').\n */\n addBlock(pattern: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\"INSERT OR IGNORE INTO blocked_patterns (pattern) VALUES (?)\")\n .run(pattern);\n this._cacheBlockPattern(pattern);\n }\n\n /**\n * Remove a block pattern.\n */\n removeBlock(pattern: string): void {\n if (this._db === null) {\n throw new Error(\"ContactBook not open. Call open() first.\");\n }\n this._db\n .prepare(\"DELETE FROM blocked_patterns WHERE pattern = ?\")\n .run(pattern);\n this._uncacheBlockPattern(pattern);\n }\n\n /**\n * Return all blocked patterns with their timestamps.\n */\n listBlocked(): BlockedEntry[] {\n if (this._db === null) return [];\n const rows = this._db\n .prepare(\n \"SELECT pattern, blocked_at FROM blocked_patterns ORDER BY blocked_at DESC\"\n )\n .all() as Array<{ pattern: string; blocked_at: string }>;\n return rows.map((r) => ({\n pattern: r.pattern,\n blockedAt: r.blocked_at,\n }));\n }\n\n // -- Internal block caching ---------------------------------------------------\n\n private _cacheBlockPattern(pattern: string): void {\n if (pattern.startsWith(\"*::\")) {\n this._blockedDomains.add(pattern.slice(3));\n } else {\n this._blockedExact.add(pattern);\n }\n }\n\n private _uncacheBlockPattern(pattern: string): void {\n if (pattern.startsWith(\"*::\")) {\n this._blockedDomains.delete(pattern.slice(3));\n } else {\n this._blockedExact.delete(pattern);\n }\n }\n}\n","/**\n * Minimal SDK logger.\n *\n * Mirrors the Python SDK's use of `logging`: warnings go to stderr, info\n * messages are only printed when UAM_DEBUG is set.\n */\n\nexport const log = {\n warn(message: string): void {\n console.warn(`[uam] ${message}`);\n },\n info(message: string): void {\n if (process.env[\"UAM_DEBUG\"]) {\n console.info(`[uam] ${message}`);\n }\n },\n};\n","/**\n * First-contact handshake flow manager (HAND-01 through HAND-04).\n *\n * Handles the three-phase handshake:\n * 1. HANDSHAKE_REQUEST: sender sends contact card (encrypted with SealedBox)\n * 2. HANDSHAKE_ACCEPT: recipient stores contact and sends accept back\n * 3. HANDSHAKE_DENY: recipient rejects the handshake\n *\n * The HandshakeManager works with the ContactBook to persist trust decisions.\n */\n\nimport {\n MessageType,\n createEnvelope,\n createContactCard,\n verifyContactCard,\n contactCardToDict,\n contactCardFromDict,\n decryptPayload,\n decryptPayloadAnonymous,\n serializeVerifyKey,\n toWireDict,\n InvalidEnvelopeError,\n type ContactCard,\n type MessageEnvelope,\n type VerifyKey,\n} from \"../protocol/index.js\";\nimport type { ContactBook } from \"./contact-book.js\";\nimport type { ReceivedMessage } from \"./message.js\";\nimport { log } from \"./log.js\";\n\n// Forward reference type for Agent to avoid circular dependency\ninterface AgentLike {\n readonly address: string;\n readonly _config: {\n readonly displayName: string;\n readonly relayWsUrl: string;\n };\n readonly _keyManager: {\n readonly signingKey: Uint8Array;\n };\n readonly _transport: {\n send(envelope: Record<string, unknown>): Promise<unknown>;\n } | null;\n}\n\n/**\n * Check that a contact card's claimed identity is the envelope's sender.\n *\n * A card embedded in a handshake envelope must name the envelope's\n * `fromAddress` and carry the verify key that signed the envelope. Without\n * this, a sender could sign an envelope from their own address while\n * embedding a (self-consistent) card for someone else's address or key, and\n * get that identity stored in the recipient's contact book.\n *\n * `envelope` only needs `fromAddress`, so Agent.approve() can re-check a\n * stored pending entry against the address it was received from.\n *\n * Matches Python `_bind_card_to_envelope` (handshake.py).\n *\n * @throws {InvalidEnvelopeError} If the address or the key does not match.\n */\nexport function bindCardToEnvelope(\n card: ContactCard,\n envelope: { readonly fromAddress: string },\n senderVk: VerifyKey\n): void {\n if (card.address !== envelope.fromAddress) {\n throw new InvalidEnvelopeError(\n `Contact card address ${JSON.stringify(card.address)} does not match ` +\n `envelope sender ${JSON.stringify(envelope.fromAddress)}`\n );\n }\n if (card.publicKey !== serializeVerifyKey(senderVk)) {\n throw new InvalidEnvelopeError(\n \"Contact card public_key does not match envelope sender's verify key\"\n );\n }\n}\n\nexport class HandshakeManager {\n private _contactBook: ContactBook;\n readonly _trustPolicy: string;\n\n constructor(contactBook: ContactBook, trustPolicy: string) {\n this._contactBook = contactBook;\n this._trustPolicy = trustPolicy;\n }\n\n /**\n * Create a handshake request envelope with embedded contact card.\n *\n * The payload is the JSON-serialized contact card, encrypted with\n * SealedBox (anonymous encryption) to the recipient.\n *\n * Returns wire-format dict ready to send via transport.\n */\n async createHandshakeRequest(\n agent: AgentLike,\n toAddress: string,\n recipientVk: VerifyKey\n ): Promise<Record<string, unknown>> {\n // Create contact card for the sending agent\n const card = await createContactCard(\n agent.address,\n agent._config.displayName,\n agent._config.relayWsUrl,\n agent._keyManager.signingKey\n );\n const cardJson = JSON.stringify(contactCardToDict(card));\n\n // Create envelope -- createEnvelope auto-uses SealedBox for HANDSHAKE_REQUEST\n const envelope = await createEnvelope(\n agent.address,\n toAddress,\n MessageType.HANDSHAKE_REQUEST,\n new TextEncoder().encode(cardJson),\n agent._keyManager.signingKey,\n recipientVk\n );\n\n return toWireDict(envelope);\n }\n\n /**\n * Handle an inbound handshake message.\n *\n * Returns null -- handshake messages are not user-visible.\n */\n async handleInbound(\n agent: AgentLike,\n envelope: MessageEnvelope,\n senderVk: VerifyKey\n ): Promise<ReceivedMessage | null> {\n if (envelope.type === MessageType.HANDSHAKE_REQUEST) {\n await this._handleRequest(agent, envelope, senderVk);\n } else if (envelope.type === MessageType.HANDSHAKE_ACCEPT) {\n await this._handleAccept(agent, envelope, senderVk);\n } else if (envelope.type === MessageType.HANDSHAKE_DENY) {\n // Handshake denied -- logged silently\n }\n return null;\n }\n\n /**\n * Process a handshake.request: decrypt contact card, apply trust policy.\n */\n private async _handleRequest(\n agent: AgentLike,\n envelope: MessageEnvelope,\n senderVk: VerifyKey\n ): Promise<void> {\n // Handshake requests are encrypted with SealedBox (anonymous)\n const plaintext = decryptPayloadAnonymous(\n envelope.payload,\n agent._keyManager.signingKey\n );\n const cardDict = JSON.parse(\n new TextDecoder().decode(plaintext)\n ) as Record<string, unknown>;\n const card = contactCardFromDict(cardDict);\n\n // Verify the contact card's self-signature\n verifyContactCard(card);\n\n // Bind the card to the envelope sender before anything is stored.\n bindCardToEnvelope(card, envelope, senderVk);\n\n if (this._trustPolicy === \"auto-accept\") {\n // Store the contact as provisional (TOFU: trust upgrades on accept)\n this._contactBook.addContact(card.address, card.publicKey, {\n displayName: card.displayName,\n trustState: \"provisional\",\n trustSource: \"auto-accepted-provisional\",\n });\n // Send handshake.accept back\n await this._sendAccept(agent, envelope.fromAddress, senderVk);\n } else if (this._trustPolicy === \"allowlist-only\") {\n // Auto-deny: only pre-approved contacts are allowed\n await this._sendDeny(agent, envelope.fromAddress, senderVk);\n } else {\n // approval-required: store in pending for manual review\n this._contactBook.addPending(\n envelope.fromAddress,\n JSON.stringify(cardDict)\n );\n }\n }\n\n /**\n * Process a handshake.accept: store the sender as pinned (TOFU).\n *\n * Only honoured when:\n * 1. we previously sent this address a handshake.request\n * (trust_state === \"handshake-sent\"); anything else is an unsolicited\n * accept and is dropped. This also means an accept can never\n * downgrade a trusted/verified contact to pinned;\n * 2. the payload decrypts with our key and the sender's key, and parses\n * as JSON. Otherwise it is dropped without pinning;\n * 3. an embedded contact_card, if present, is well-formed, correctly\n * self-signed, and bound to the envelope sender (throws otherwise).\n */\n private async _handleAccept(\n agent: AgentLike,\n envelope: MessageEnvelope,\n senderVk: VerifyKey\n ): Promise<void> {\n const prior = this._contactBook.getTrustState(envelope.fromAddress);\n if (prior !== \"handshake-sent\") {\n log.warn(\n `Ignoring unsolicited handshake.accept from ${envelope.fromAddress} ` +\n `(trust_state=${JSON.stringify(prior)})`\n );\n return;\n }\n\n let payload: unknown;\n try {\n const plaintext = decryptPayload(\n envelope.payload,\n agent._keyManager.signingKey,\n senderVk\n );\n payload = JSON.parse(new TextDecoder().decode(plaintext));\n } catch {\n log.warn(\n `Dropping handshake.accept ${envelope.messageId} from ` +\n `${envelope.fromAddress}: payload could not be decrypted or parsed`\n );\n return;\n }\n\n if (\n payload !== null &&\n typeof payload === \"object\" &&\n \"contact_card\" in payload\n ) {\n const card = contactCardFromDict(\n (payload as Record<string, unknown>)[\"contact_card\"] as Record<\n string,\n unknown\n >\n );\n verifyContactCard(card);\n bindCardToEnvelope(card, envelope, senderVk);\n }\n\n const senderPkStr = serializeVerifyKey(senderVk);\n this._contactBook.addContact(envelope.fromAddress, senderPkStr, {\n trustState: \"pinned\",\n });\n this._contactBook.setPinnedAt(envelope.fromAddress);\n }\n\n /**\n * Send a handshake.accept envelope back to the requester.\n */\n async _sendAccept(\n agent: AgentLike,\n toAddress: string,\n recipientVk: VerifyKey\n ): Promise<void> {\n const card = await createContactCard(\n agent.address,\n agent._config.displayName,\n agent._config.relayWsUrl,\n agent._keyManager.signingKey\n );\n const acceptPayload = JSON.stringify({\n status: \"accepted\",\n contact_card: contactCardToDict(card),\n });\n\n const envelope = await createEnvelope(\n agent.address,\n toAddress,\n MessageType.HANDSHAKE_ACCEPT,\n new TextEncoder().encode(acceptPayload),\n agent._keyManager.signingKey,\n recipientVk\n );\n\n const wire = toWireDict(envelope);\n if (agent._transport) {\n await agent._transport.send(wire);\n }\n }\n\n /**\n * Send a handshake.deny envelope to the requester.\n */\n async _sendDeny(\n agent: AgentLike,\n toAddress: string,\n recipientVk: VerifyKey\n ): Promise<void> {\n const denyPayload = JSON.stringify({\n status: \"denied\",\n reason: \"allowlist-only\",\n });\n\n const envelope = await createEnvelope(\n agent.address,\n toAddress,\n MessageType.HANDSHAKE_DENY,\n new TextEncoder().encode(denyPayload),\n agent._keyManager.signingKey,\n recipientVk\n );\n\n const wire = toWireDict(envelope);\n if (agent._transport) {\n await agent._transport.send(wire);\n }\n }\n}\n","/**\n * Base class for address resolvers.\n *\n * Lives in its own module so tier3.ts can extend it without importing\n * resolver.ts (which imports tier3.ts), avoiding an import cycle.\n */\n\n/**\n * Pluggable address resolver interface.\n */\nexport abstract class AddressResolver {\n /**\n * Resolve an agent address to its public key (base64).\n *\n * @throws {UAMError} If the address cannot be resolved.\n */\n abstract resolvePublicKey(\n address: string,\n token: string,\n relayUrl: string\n ): Promise<string>;\n}\n","/**\n * Tier 3 resolver: on-chain namespace lookup via UAMNameRegistry (TSSDK-09).\n *\n * Uses viem for contract reads on Base Sepolia/Base L2.\n */\n\nimport { createPublicClient, http, type Address, defineChain } from \"viem\";\nimport { UAMError } from \"../protocol/index.js\";\nimport { parseAddress } from \"../protocol/address.js\";\nimport { AddressResolver } from \"./resolver-base.js\";\n\n// Default config\nconst DEFAULT_RPC_URL = \"https://sepolia.base.org\";\nconst DEFAULT_CHAIN_ID = 84532; // Base Sepolia\n\n// Cache TTL: 1 hour in milliseconds\nconst CACHE_TTL_MS = 3600 * 1000;\n\n// Minimal ABI for resolve() and available() -- inline to avoid file I/O\nconst REGISTRY_ABI = [\n {\n name: \"resolve\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"name\", type: \"string\" }],\n outputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"publicKey\", type: \"string\" },\n { name: \"relayUrl\", type: \"string\" },\n { name: \"expiry\", type: \"uint256\" },\n ],\n },\n {\n name: \"available\",\n type: \"function\",\n stateMutability: \"view\",\n inputs: [{ name: \"name\", type: \"string\" }],\n outputs: [{ name: \"\", type: \"bool\" }],\n },\n] as const;\n\ninterface CacheEntry {\n publicKey: string;\n expiresAt: number; // Date.now() + TTL\n}\n\nexport interface Tier3Config {\n contractAddress: string;\n rpcUrl?: string;\n chainId?: number;\n cacheTtlMs?: number;\n}\n\n/**\n * Build a minimal chain definition for viem.\n * Using defineChain avoids importing chain-specific types from viem/chains\n * which cause TypeScript compatibility issues with generic PublicClient.\n */\nfunction buildChain(chainId: number, rpcUrl: string) {\n return defineChain({\n id: chainId,\n name: `chain-${chainId}`,\n nativeCurrency: { name: \"Ether\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: { http: [rpcUrl] },\n },\n });\n}\n\n/**\n * Resolve agent addresses via on-chain UAMNameRegistry contract.\n *\n * Uses viem PublicClient to call resolve() on the contract.\n * Caches results for 1 hour to minimize RPC calls.\n */\nexport class Tier3Resolver extends AddressResolver {\n private _contractAddress: Address;\n private _client: ReturnType<typeof createPublicClient>;\n private _cacheTtlMs: number;\n private _cache: Map<string, CacheEntry> = new Map();\n\n constructor(config: Tier3Config) {\n super();\n this._contractAddress = config.contractAddress as Address;\n this._cacheTtlMs = config.cacheTtlMs ?? CACHE_TTL_MS;\n const rpcUrl = config.rpcUrl ?? DEFAULT_RPC_URL;\n const chainId = config.chainId ?? DEFAULT_CHAIN_ID;\n this._client = createPublicClient({\n chain: buildChain(chainId, rpcUrl),\n transport: http(rpcUrl),\n });\n }\n\n async resolvePublicKey(\n address: string,\n _token: string,\n _relayUrl: string\n ): Promise<string> {\n const parsed = parseAddress(address);\n const name = parsed.domain; // For Tier 3, domain IS the namespace\n\n // Check cache\n const cached = this._cache.get(name);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.publicKey;\n }\n\n // Call contract\n try {\n const result = await this._client.readContract({\n address: this._contractAddress,\n abi: REGISTRY_ABI,\n functionName: \"resolve\",\n args: [name],\n });\n\n const [_owner, publicKey, _relayUrl2, _expiry] = result;\n\n if (!publicKey) {\n throw new UAMError(\n `Tier 3 name '${name}' has no public key registered`\n );\n }\n\n // Cache result\n this._cache.set(name, {\n publicKey,\n expiresAt: Date.now() + this._cacheTtlMs,\n });\n\n return publicKey;\n } catch (err) {\n if (err instanceof UAMError) throw err;\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes(\"NameNotFound\") || msg.includes(\"revert\")) {\n throw new UAMError(`Tier 3 name not found on-chain: ${name}`);\n }\n throw new UAMError(`Tier 3 resolution failed for ${name}: ${msg}`);\n }\n }\n\n /**\n * Check if a name is available for registration.\n */\n async isAvailable(name: string): Promise<boolean> {\n try {\n const result = await this._client.readContract({\n address: this._contractAddress,\n abi: REGISTRY_ABI,\n functionName: \"available\",\n args: [name],\n });\n return result;\n } catch {\n return false;\n }\n }\n\n /**\n * Clear cache for a specific name or all names.\n */\n invalidateCache(name?: string): void {\n if (name) {\n this._cache.delete(name);\n } else {\n this._cache.clear();\n }\n }\n}\n","/**\n * Pluggable address resolver with Tier 1 relay lookup (SDK-08).\n *\n * Matches Python resolver.py: SmartResolver routes by domain format.\n */\n\nimport { UAMError } from \"../protocol/index.js\";\nimport { parseAddress } from \"../protocol/address.js\";\nimport { AddressResolver } from \"./resolver-base.js\";\nimport { Tier3Resolver, type Tier3Config } from \"./tier3.js\";\nimport {\n queryUamTxt,\n parseUamTxt,\n extractPublicKey,\n resolveKeyViaHttps,\n} from \"./dns-verifier.js\";\n\nexport { AddressResolver } from \"./resolver-base.js\";\n\n/**\n * Tier 1: resolve via relay HTTP API.\n *\n * Calls GET /api/v1/agents/{address}/public-key.\n */\nexport class Tier1Resolver extends AddressResolver {\n async resolvePublicKey(\n address: string,\n _token: string,\n relayUrl: string\n ): Promise<string> {\n const resp = await fetch(\n `${relayUrl}/api/v1/agents/${address}/public-key`\n );\n if (resp.status === 404) {\n throw new UAMError(`Agent not found: ${address}`);\n }\n if (!resp.ok) {\n throw new UAMError(\n `Resolver request failed: ${resp.status} ${resp.statusText}`\n );\n }\n const data = (await resp.json()) as Record<string, unknown>;\n return data[\"public_key\"] as string;\n }\n}\n\n/**\n * Tier 2: DNS TXT record resolution (DNS-01).\n *\n * Resolution order:\n * 1. Query _uam.{domain} TXT records for v=uam1 entries\n * 2. Fallback to HTTPS .well-known/uam.json\n * 3. Throw UAMError if both fail\n */\nexport class Tier2Resolver extends AddressResolver {\n async resolvePublicKey(\n address: string,\n _token: string,\n _relayUrl: string\n ): Promise<string> {\n const parsed = parseAddress(address);\n\n // 1. Try DNS TXT at _uam.{domain}\n const txtRecords = await queryUamTxt(parsed.domain);\n for (const txt of txtRecords) {\n const tags = parseUamTxt(txt);\n if (tags[\"v\"] === \"uam1\") {\n const key = extractPublicKey(tags);\n if (key) return key;\n }\n }\n\n // 2. Fallback to HTTPS .well-known\n const httpsKey = await resolveKeyViaHttps(parsed.agent, parsed.domain);\n if (httpsKey) return httpsKey;\n\n throw new UAMError(\n `Could not resolve public key for ${address} via DNS or HTTPS`\n );\n }\n}\n\n/**\n * Automatic tier-based resolver that routes by domain format (RESOLVE-01).\n *\n * Routing rules:\n * - domain == relayDomain -> Tier 1 (relay HTTP API lookup)\n * - domain contains a '.' -> Tier 2 (DNS -- stub)\n * - domain has no dots -> Tier 3 (on-chain namespace lookup)\n */\nexport class SmartResolver extends AddressResolver {\n relayDomain: string;\n private _tier1: Tier1Resolver;\n private _tier2: Tier2Resolver;\n private _tier3: Tier3Resolver | null;\n\n constructor(relayDomain: string, tier3Config?: Tier3Config) {\n super();\n this.relayDomain = relayDomain;\n this._tier1 = new Tier1Resolver();\n this._tier2 = new Tier2Resolver();\n this._tier3 = tier3Config ? new Tier3Resolver(tier3Config) : null;\n }\n\n async resolvePublicKey(\n address: string,\n token: string,\n relayUrl: string\n ): Promise<string> {\n const parsed = parseAddress(address);\n const domain = parsed.domain;\n\n if (domain === this.relayDomain) {\n return this._tier1.resolvePublicKey(address, token, relayUrl);\n }\n\n if (domain.includes(\".\")) {\n return this._tier2.resolvePublicKey(address, token, relayUrl);\n }\n\n if (!this._tier3) {\n throw new UAMError(\n `Tier 3 resolution requires contract config. ` +\n `Cannot resolve dot-free domain: '${domain}'`\n );\n }\n return this._tier3.resolvePublicKey(address, token, relayUrl);\n }\n}\n\n// Re-export Tier3 types for convenience\nexport { Tier3Resolver, type Tier3Config } from \"./tier3.js\";\n","/**\n * Abstract transport interface for relay communication.\n *\n * Two implementations:\n * - HTTPTransport: stateless polling via REST API\n * - WebSocketTransport: persistent real-time connection\n */\n\nexport abstract class TransportBase {\n /** Establish connection to the relay. */\n abstract connect(): Promise<void>;\n\n /** Close the connection. */\n abstract disconnect(): Promise<void>;\n\n /**\n * Send a message envelope to the relay.\n *\n * Resolves with the relay's answer (`{status, ...}`), or null when none\n * came in time: the message may still have arrived.\n */\n abstract send(\n envelope: Record<string, unknown>\n ): Promise<Record<string, unknown> | null>;\n\n /** Retrieve pending messages from the relay. */\n abstract receive(limit?: number): Promise<Record<string, unknown>[]>;\n\n /**\n * Start listening for real-time messages.\n *\n * For WebSocket: registers a callback for push delivery.\n * For HTTP: not supported (throws Error).\n */\n abstract listen(\n callback: (msg: Record<string, unknown>) => Promise<void>\n ): Promise<void>;\n}\n","/**\n * HTTP transport via native fetch (SDK-09).\n *\n * Sends envelopes via POST /api/v1/send and retrieves inbox\n * via GET /api/v1/inbox/{address}.\n *\n * Uses native fetch (Node.js 18+ has global fetch).\n */\n\nimport { TransportBase } from \"./base.js\";\n\n/**\n * The relay's answer to a send, from a successful response's body.\n *\n * A relay before 1.1 may answer without a JSON object: that's an empty\n * answer, which reads as \"accepted\".\n */\nexport async function readAnswer(resp: Response): Promise<Record<string, unknown>> {\n try {\n const body: unknown = await resp.json();\n return body !== null && typeof body === \"object\" && !Array.isArray(body)\n ? (body as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\nexport class HTTPTransport extends TransportBase {\n private _relayUrl: string;\n private _token: string;\n private _address: string;\n\n constructor(relayUrl: string, token: string, address: string) {\n super();\n this._relayUrl = relayUrl.replace(/\\/+$/, \"\");\n this._token = token;\n this._address = address;\n }\n\n async connect(): Promise<void> {\n // No persistent connection needed for HTTP\n }\n\n async disconnect(): Promise<void> {\n // No-op\n }\n\n async send(\n envelope: Record<string, unknown>\n ): Promise<Record<string, unknown> | null> {\n const resp = await fetch(`${this._relayUrl}/api/v1/send`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this._token}`,\n },\n body: JSON.stringify({ envelope }),\n });\n if (!resp.ok) {\n throw new Error(\n `HTTP send failed: ${resp.status} ${resp.statusText}`\n );\n }\n return readAnswer(resp);\n }\n\n async receive(limit: number = 50): Promise<Record<string, unknown>[]> {\n const url = new URL(\n `${this._relayUrl}/api/v1/inbox/${this._address}`\n );\n url.searchParams.set(\"limit\", String(limit));\n\n const resp = await fetch(url.toString(), {\n headers: {\n Authorization: `Bearer ${this._token}`,\n },\n });\n if (!resp.ok) {\n throw new Error(\n `HTTP receive failed: ${resp.status} ${resp.statusText}`\n );\n }\n const data = (await resp.json()) as Record<string, unknown>;\n return (data[\"messages\"] as Record<string, unknown>[]) ?? [];\n }\n\n async listen(\n _callback: (msg: Record<string, unknown>) => Promise<void>\n ): Promise<void> {\n throw new Error(\n \"HTTP transport does not support real-time listening. \" +\n \"Use receive() for polling or switch to WebSocket transport.\"\n );\n }\n}\n","/**\n * WebSocket transport with exponential backoff and jitter (SDK-05).\n *\n * Maintains a persistent connection to the relay, automatically\n * reconnecting on disconnection with exponential backoff plus\n * random jitter to prevent thundering herd.\n */\n\nimport WebSocket from \"ws\";\nimport { SendRefusedError } from \"../../protocol/errors.js\";\nimport { log } from \"../log.js\";\nimport { TransportBase } from \"./base.js\";\n\n// Reconnection constants\nconst BASE_DELAY = 1.0; // Initial delay in seconds\nconst MAX_DELAY = 60.0; // Maximum delay cap\nconst JITTER_RANGE = 1.0; // Random jitter 0 to JITTER_RANGE\n\n/** How long a close waits for the relay to answer sends, in seconds. */\nexport const SEND_SETTLE_SECONDS = 5;\n\n/** How long send() waits for the relay's answer, in seconds. */\nexport const ACK_TIMEOUT_SECONDS = 5;\n\ntype Answer = Record<string, unknown> | null;\n\ninterface Waiting {\n resolve: (answer: Answer) => void;\n reject: (err: Error) => void;\n}\n\nexport class WebSocketTransport extends TransportBase {\n private _url: string;\n private _token: string;\n private _onMessage:\n | ((msg: Record<string, unknown>) => Promise<void>)\n | null;\n private _ws: WebSocket | null = null;\n private _pending: Record<string, unknown>[] = [];\n private _connected: boolean = false;\n private _connectResolve: (() => void) | null = null;\n private _connectReject: ((err: Error) => void) | null = null;\n private _running: boolean = false;\n private _reconnectTimeout: ReturnType<typeof setTimeout> | null = null;\n /** Envelopes sent that the relay hasn't answered yet. */\n private _unanswered: number = 0;\n private _settling: Promise<void> | null = null;\n private _settled: (() => void) | null = null;\n /** Sends waiting for the relay's answer, by message_id. */\n private _waiting = new Map<string, Waiting>();\n\n /** @internal How long a close waits, in ms. Replaceable in tests. */\n _settleMs: number = SEND_SETTLE_SECONDS * 1000;\n\n /** @internal How long send() waits for an answer, in ms. Replaceable in tests. */\n _ackMs: number = ACK_TIMEOUT_SECONDS * 1000;\n\n constructor(\n wsUrl: string,\n token: string,\n onMessage?: (msg: Record<string, unknown>) => Promise<void>\n ) {\n super();\n // The token travels in the `bearer.<token>` WebSocket subprotocol, not\n // in a ?token= query string, so it stays out of HTTP access logs and\n // proxy logs. The relay accepts this form and echoes the subprotocol\n // back (relay/ws.py); the Python SDK does the same.\n this._url = wsUrl;\n this._token = token;\n this._onMessage = onMessage ?? null;\n }\n\n async connect(): Promise<void> {\n this._running = true;\n return new Promise<void>((resolve, reject) => {\n this._connectResolve = resolve;\n this._connectReject = reject;\n this._startConnectionLoop();\n\n // 30s timeout for initial connection\n const timeout = setTimeout(() => {\n this._connectReject = null;\n this._connectResolve = null;\n reject(new Error(\"WebSocket connection timeout (30s)\"));\n }, 30000);\n\n // Patch resolve to clear timeout\n const origResolve = this._connectResolve;\n this._connectResolve = () => {\n clearTimeout(timeout);\n origResolve?.();\n };\n });\n }\n\n /**\n * Close the connection, once the relay has answered what was sent.\n *\n * The relay stops reading a socket when it can't write an ack to it, so\n * closing straight after send() loses every frame but the first.\n */\n async disconnect(): Promise<void> {\n await this._allAnswered();\n this._running = false;\n if (this._reconnectTimeout !== null) {\n clearTimeout(this._reconnectTimeout);\n this._reconnectTimeout = null;\n }\n if (this._ws) {\n this._ws.removeAllListeners();\n this._ws.close();\n this._ws = null;\n }\n this._connected = false;\n this._abandonWaiting();\n }\n\n /**\n * Send an envelope and wait for the relay's answer.\n *\n * Resolves with the ack that names the message, or null when none came\n * within _ackMs or the socket went: the message may still have arrived.\n * Rejects with SendRefusedError when the relay refuses it by message_id\n * (relays before 1.1 don't name it, so their refusals end as null).\n */\n async send(envelope: Record<string, unknown>): Promise<Answer> {\n if (!this._ws || this._ws.readyState !== WebSocket.OPEN) {\n throw new Error(\"WebSocket not connected\");\n }\n const messageId = envelope[\"message_id\"];\n let answer: Promise<Answer> | null = null;\n let timer: ReturnType<typeof setTimeout> | undefined;\n if (typeof messageId === \"string\" && !this._waiting.has(messageId)) {\n // Registered first: the ack can arrive before ws.send returns.\n answer = new Promise<Answer>((resolve, reject) => {\n this._waiting.set(messageId, { resolve, reject });\n timer = setTimeout(() => {\n log.warn(\n `No answer from the relay for ${messageId} within ${this._ackMs / 1000}s`\n );\n this._settle(messageId, null);\n }, this._ackMs);\n });\n }\n this._ws.send(JSON.stringify(envelope));\n this._unanswered += 1;\n if (answer === null) return null;\n try {\n return await answer;\n } finally {\n clearTimeout(timer);\n }\n }\n\n async receive(limit: number = 50): Promise<Record<string, unknown>[]> {\n const result = this._pending.slice(0, limit);\n this._pending = this._pending.slice(limit);\n return result;\n }\n\n async listen(\n callback: (msg: Record<string, unknown>) => Promise<void>\n ): Promise<void> {\n this._onMessage = callback;\n }\n\n /** Resolves when nothing is unanswered, or after _settleMs regardless. */\n private _allAnswered(): Promise<void> {\n if (this._unanswered === 0) return Promise.resolve();\n this._settling ??= new Promise<void>((resolve) => {\n const timeout = setTimeout(() => {\n log.warn(`Closing with ${this._unanswered} sends unanswered`);\n this._settled?.();\n }, this._settleMs);\n this._settled = () => {\n clearTimeout(timeout);\n this._settling = null;\n this._settled = null;\n resolve();\n };\n });\n return this._settling;\n }\n\n /** Hand the relay's answer (or a refusal) to the send waiting for it. */\n private _settle(messageId: unknown, answer: Answer, error?: Error): void {\n if (typeof messageId !== \"string\") return;\n const waiting = this._waiting.get(messageId);\n if (!waiting) return;\n this._waiting.delete(messageId);\n if (error) waiting.reject(error);\n else waiting.resolve(answer);\n }\n\n /** The socket went: no answers will come for what it carried. */\n private _abandonWaiting(): void {\n const waiting = [...this._waiting.values()];\n this._waiting.clear();\n for (const w of waiting) w.resolve(null);\n }\n\n private _answered(): void {\n this._unanswered = Math.max(0, this._unanswered - 1);\n if (this._unanswered === 0) this._settled?.();\n }\n\n private _startConnectionLoop(): void {\n let attempt = 0;\n\n const tryConnect = () => {\n if (!this._running) return;\n\n const ws = new WebSocket(this._url, [`bearer.${this._token}`]);\n this._ws = ws;\n\n ws.on(\"open\", () => {\n this._connected = true;\n attempt = 0; // Reset on successful connection\n if (this._connectResolve) {\n this._connectResolve();\n this._connectResolve = null;\n this._connectReject = null;\n }\n });\n\n ws.on(\"message\", (data: WebSocket.Data) => {\n try {\n const msg = JSON.parse(data.toString()) as Record<string, unknown>;\n this._handleMessage(msg);\n } catch {\n // Ignore unparseable messages\n }\n });\n\n ws.on(\"close\", () => {\n this._connected = false;\n this._ws = null;\n // Their answers went with the socket.\n this._unanswered = 0;\n this._settled?.();\n this._abandonWaiting();\n if (!this._running) return;\n\n attempt += 1;\n const delay = Math.min(BASE_DELAY * Math.pow(2, attempt), MAX_DELAY);\n const jitter = Math.random() * JITTER_RANGE;\n const totalDelay = (delay + jitter) * 1000;\n\n this._reconnectTimeout = setTimeout(tryConnect, totalDelay);\n });\n\n ws.on(\"error\", (err: Error) => {\n // On first connect, reject the promise\n if (this._connectReject && !this._connected) {\n // Don't reject immediately; let 'close' handle retry\n }\n // Error will trigger close event\n });\n };\n\n tryConnect();\n }\n\n private _handleMessage(msg: Record<string, unknown>): void {\n const msgType = msg[\"type\"] as string | undefined;\n\n // First: an envelope's type and keys are the sender's to choose.\n if (\"uam_version\" in msg) {\n if (this._onMessage) {\n this._onMessage(msg).catch(() => {\n // Fire-and-forget callback errors\n });\n } else {\n this._pending.push(msg);\n }\n } else if (msgType === \"ping\") {\n // Respond to relay heartbeat\n if (this._ws && this._ws.readyState === WebSocket.OPEN) {\n this._ws.send(JSON.stringify({ type: \"pong\" }));\n }\n } else if (msgType === \"ack\") {\n this._answered();\n this._settle(msg[\"message_id\"], msg);\n } else if (msgType === \"relay.notice\") {\n // A message the relay had queued for another relay won't be\n // delivered after all (e.g. the recipient only takes approved\n // contacts). Not an answer to a send in flight.\n log.warn(\n `Relay notice: message ${String(msg[\"message_id\"])} is ${String(msg[\"status\"])}`\n );\n } else if (msgType === \"error\" || \"error\" in msg) {\n this._answered();\n const code = String(msg[\"error\"] ?? msg[\"code\"] ?? \"error\");\n const detail = typeof msg[\"detail\"] === \"string\" ? msg[\"detail\"] : undefined;\n log.warn(`Relay error: [${code}] ${detail ?? \"\"}`.trimEnd());\n const messageId = msg[\"message_id\"];\n if (typeof messageId === \"string\") {\n this._settle(messageId, null, new SendRefusedError(messageId, code, detail));\n }\n }\n }\n}\n","/**\n * UAM SDK transport layer.\n */\n\nimport type { SDKConfig } from \"../config.js\";\nimport { TransportBase } from \"./base.js\";\nimport { HTTPTransport } from \"./http.js\";\nimport { WebSocketTransport } from \"./websocket.js\";\n\nexport { TransportBase } from \"./base.js\";\nexport { HTTPTransport } from \"./http.js\";\nexport { WebSocketTransport } from \"./websocket.js\";\n\n/**\n * Factory to create the appropriate transport based on config.\n */\nexport function createTransport(\n config: SDKConfig,\n token: string,\n address: string,\n onMessage?: (msg: Record<string, unknown>) => Promise<void>\n): TransportBase {\n if (config.transportType === \"http\") {\n return new HTTPTransport(config.relayUrl, token, address);\n } else {\n return new WebSocketTransport(config.relayWsUrl, token, onMessage);\n }\n}\n","/**\n * Replay protection for inbound envelopes.\n *\n * Used by Agent._processInbound to drop envelopes whose\n * (from address, message id) pair was already seen.\n *\n * PersistentReplayCache is what the Agent uses: a SQLite file under the\n * agent's data dir, shared by every process using that dir, that keeps each\n * pair for RETENTION_SECONDS. Stored mail can arrive days after it was\n * signed, so the window an envelope can be accepted in is longer than one\n * process lives.\n *\n * - Never evicts inside the window. Rows go only when they are older than\n * RETENTION_SECONDS. When the file holds `capacity` rows it fails closed:\n * an envelope signed within MAX_ENVELOPE_AGE is still accepted (and\n * deduplicated in memory); anything older is refused.\n * - Knows its age. created_at is written once, so a caller can refuse old\n * stored mail signed before the cache existed.\n *\n * EnvelopeReplayCache is the bounded in-memory cache it falls back on when\n * full: least-recently-used entries are evicted at capacity, and entries\n * older than the TTL are treated as new.\n *\n * Matches the Python SDK's sdk/replay_cache.py, and shares its file format:\n * times in the file are seconds since the epoch.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { setTimeout as sleep } from \"node:timers/promises\";\n\nimport Database from \"better-sqlite3\";\n\nimport { MAX_ENVELOPE_AGE } from \"../protocol/types.js\";\nimport { STORED_MAIL_MAX_AGE } from \"./freshness.js\";\nimport { log } from \"./log.js\";\n\n/**\n * Seven days of stored mail, plus the freshness window on either side of the\n * signed timestamp (clock skew between sender, relay and recipient).\n */\nexport const RETENTION_SECONDS = STORED_MAIL_MAX_AGE + 2 * MAX_ENVELOPE_AGE;\n\n/** How often expired rows are purged, at most. */\nconst PURGE_INTERVAL_MS = 60_000;\n\nconst WAL_ATTEMPTS = 100;\nconst WAL_RETRY_MS = 100;\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS seen_envelopes (\n from_address TEXT NOT NULL,\n message_id TEXT NOT NULL,\n seen_at REAL NOT NULL,\n PRIMARY KEY (from_address, message_id)\n) WITHOUT ROWID;\nCREATE INDEX IF NOT EXISTS seen_envelopes_seen_at ON seen_envelopes (seen_at);\nCREATE TABLE IF NOT EXISTS replay_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n`;\n\nfunction isLocked(err: unknown): boolean {\n const code = (err as { code?: unknown }).code;\n return (\n typeof code === \"string\" &&\n (code.startsWith(\"SQLITE_BUSY\") || code.startsWith(\"SQLITE_LOCKED\"))\n );\n}\n\n/**\n * Switch `db` to WAL, waiting out another process doing the same.\n *\n * SQLite doesn't apply the busy timeout to this switch: two processes opening\n * a new file together get \"database is locked\" at once.\n */\nasync function enableWal(db: Database.Database): Promise<void> {\n for (let attempt = 1; ; attempt += 1) {\n try {\n db.pragma(\"journal_mode = WAL\");\n return;\n } catch (err) {\n if (attempt >= WAL_ATTEMPTS || !isLocked(err)) throw err;\n await sleep(WAL_RETRY_MS);\n }\n }\n}\n\nexport const DEFAULT_REPLAY_CACHE_CAPACITY = 1_000_000;\n\nexport class EnvelopeReplayCache {\n readonly capacity: number;\n readonly ttlMs: number;\n private readonly _now: () => number;\n // Map iteration order is insertion order: first key = least recently used.\n private readonly _seen = new Map<string, number>();\n\n constructor(options?: {\n capacity?: number;\n ttlMs?: number;\n now?: () => number;\n }) {\n const capacity = options?.capacity ?? 100_000;\n if (!Number.isInteger(capacity) || capacity < 1) {\n throw new RangeError(\n `Replay cache capacity must be a positive integer, got ${capacity}`\n );\n }\n this.capacity = capacity;\n this.ttlMs = options?.ttlMs ?? 300_000;\n this._now = options?.now ?? (() => Date.now());\n }\n\n get size(): number {\n return this._seen.size;\n }\n\n /** True if this pair was seen within the TTL. Records nothing. */\n has(fromAddress: string, messageId: string): boolean {\n const seenAt = this._seen.get(this._key(fromAddress, messageId));\n return seenAt !== undefined && this._now() - seenAt < this.ttlMs;\n }\n\n /**\n * Return true if this (fromAddress, messageId) pair was already seen\n * within the TTL (a replay). Otherwise record it and return false.\n */\n seenOrRecord(fromAddress: string, messageId: string): boolean {\n const key = this._key(fromAddress, messageId);\n const now = this._now();\n const seenAt = this._seen.get(key);\n if (seenAt !== undefined && now - seenAt < this.ttlMs) {\n // LRU touch: move to the most-recently-used end.\n this._seen.delete(key);\n this._seen.set(key, seenAt);\n return true;\n }\n this._seen.delete(key);\n this._seen.set(key, now);\n while (this._seen.size > this.capacity) {\n const oldest = this._seen.keys().next().value as string;\n this._seen.delete(oldest);\n }\n return false;\n }\n\n private _key(fromAddress: string, messageId: string): string {\n // JSON encoding keeps the two parts unambiguous whatever they contain.\n return JSON.stringify([fromAddress, messageId]);\n }\n}\n\n/**\n * Inbound (from address, message id) pairs kept in a SQLite file.\n *\n * Opens itself on first use, so an Agent driven without connect() still has\n * replay protection. Safe to share between processes: the insert is the\n * check (INSERT OR IGNORE), in WAL mode.\n */\nexport class PersistentReplayCache {\n readonly capacity: number;\n private readonly _path: string;\n private readonly _now: () => number;\n private _db: Database.Database | null = null;\n private _opening: Promise<Database.Database> | null = null;\n private _count = 0;\n private _lastPurge = 0;\n private _createdAt = 0;\n // Used only while the file is full, for envelopes inside MAX_ENVELOPE_AGE.\n // One can be signed that far ahead of us and stay acceptable until that far\n // behind, so its id must last both.\n private readonly _overflow: EnvelopeReplayCache;\n\n /**\n * @param path - The SQLite file\n * @param options.now - The clock, in ms since the epoch\n */\n constructor(\n path: string,\n options?: { capacity?: number; now?: () => number }\n ) {\n const capacity = options?.capacity ?? DEFAULT_REPLAY_CACHE_CAPACITY;\n if (!Number.isInteger(capacity) || capacity < 1) {\n throw new RangeError(\n `Replay cache capacity must be a positive integer, got ${capacity}`\n );\n }\n this.capacity = capacity;\n this._path = path;\n this._now = options?.now ?? (() => Date.now());\n this._overflow = new EnvelopeReplayCache({\n capacity: 10_000,\n ttlMs: 2 * MAX_ENVELOPE_AGE * 1000,\n now: this._now,\n });\n }\n\n /** Open the file now, rather than on first use. */\n async open(): Promise<void> {\n await this._open();\n }\n\n /**\n * Return true if the envelope must be dropped as a replay. Otherwise record\n * the pair and return false.\n *\n * @param signedAt - The envelope's signed time, in ms since the epoch. It\n * matters only when the cache is full.\n */\n async seenOrRecord(\n fromAddress: string,\n messageId: string,\n signedAt: number\n ): Promise<boolean> {\n const db = await this._open();\n const now = this._now();\n if (now - this._lastPurge >= PURGE_INTERVAL_MS) this._purge(db);\n\n // Accepted while the file was full, so it's only in memory.\n if (this._overflow.has(fromAddress, messageId)) return true;\n\n if (this._count < this.capacity) {\n const { changes } = db\n .prepare(\n \"INSERT OR IGNORE INTO seen_envelopes \" +\n \"(from_address, message_id, seen_at) VALUES (?, ?, ?)\"\n )\n .run(fromAddress, messageId, now / 1000);\n if (changes === 0) return true;\n this._count += 1;\n return false;\n }\n\n // Full: never evict inside the window. Known pairs are replays, fresh\n // envelopes are deduplicated in memory, older ones refused.\n const known = db\n .prepare(\n \"SELECT 1 FROM seen_envelopes WHERE from_address = ? AND message_id = ?\"\n )\n .get(fromAddress, messageId);\n if (known !== undefined) return true;\n\n if (Math.abs(now - signedAt) <= MAX_ENVELOPE_AGE * 1000) {\n return this._overflow.seenOrRecord(fromAddress, messageId);\n }\n log.warn(\n `Replay cache full (${this._count} ids); refused envelope ${messageId} ` +\n `from ${fromAddress} signed ${Math.round((now - signedAt) / 1000)}s ago`\n );\n return true;\n }\n\n /** When this cache file was first created, in ms since the epoch. */\n async createdAt(): Promise<number> {\n await this._open();\n return this._createdAt;\n }\n\n /** True if an envelope signed at `signedAt` (ms) predates this cache. */\n async signedBeforeCache(signedAt: number): Promise<boolean> {\n return signedAt < (await this.createdAt());\n }\n\n /** Number of ids currently held on disk. */\n async count(): Promise<number> {\n const db = await this._open();\n return this._countRows(db);\n }\n\n /** Close the file; the next call opens it again. */\n async close(): Promise<void> {\n await this._opening?.catch(() => undefined);\n this._db?.close();\n this._db = null;\n }\n\n private _open(): Promise<Database.Database> {\n if (this._db !== null) return Promise.resolve(this._db);\n this._opening ??= this._connect().finally(() => {\n this._opening = null;\n });\n return this._opening;\n }\n\n private async _connect(): Promise<Database.Database> {\n mkdirSync(dirname(this._path), { recursive: true });\n const db = new Database(this._path, { timeout: 30_000 });\n try {\n await enableWal(db);\n db.exec(SCHEMA);\n db.prepare(\n \"INSERT OR IGNORE INTO replay_meta (key, value) VALUES ('created_at', ?)\"\n ).run(String(this._now() / 1000));\n const row = db\n .prepare(\"SELECT value FROM replay_meta WHERE key = 'created_at'\")\n .get() as { value: string };\n this._createdAt = Number(row.value) * 1000;\n this._purge(db);\n } catch (err) {\n db.close();\n throw err;\n }\n this._db = db;\n return db;\n }\n\n private _purge(db: Database.Database): void {\n const now = this._now();\n db.prepare(\"DELETE FROM seen_envelopes WHERE seen_at < ?\").run(\n now / 1000 - RETENTION_SECONDS\n );\n this._count = this._countRows(db);\n this._lastPurge = now;\n }\n\n private _countRows(db: Database.Database): number {\n const row = db.prepare(\"SELECT COUNT(*) AS n FROM seen_envelopes\").get() as {\n n: number;\n };\n return row.n;\n }\n}\n","/**\n * Receiver-side webhook signature verification (HOOK-03).\n *\n * Small utility for webhook receivers to verify that incoming webhook\n * payloads were signed by the UAM relay. Uses HMAC-SHA256 with the\n * agent's webhook secret, which the relay returns when the webhook is set\n * (PUT /api/v1/agents/{address}/webhook). Setting the same URL again\n * returns it again.\n *\n * Matches Python webhook_verify.py API surface.\n *\n * Usage:\n *\n * import { verifyWebhookSignature } from \"@youam/sdk\";\n *\n * const payload = Buffer.from(requestBody);\n * const signature = request.headers[\"x-uam-signature\"];\n * const secret = \"your-webhook-secret\";\n *\n * if (verifyWebhookSignature(payload, signature, secret)) {\n * // payload is authentic\n * }\n */\n\nimport { createHmac, timingSafeEqual } from \"node:crypto\";\n\n/**\n * Verify an HMAC-SHA256 webhook signature.\n *\n * @param payload - Raw request body bytes\n * @param signatureHeader - \"sha256=<hex>\" format (X-UAM-Signature header)\n * @param secret - The agent's webhook secret\n * @returns `true` if valid, `false` otherwise.\n *\n * Uses `crypto.timingSafeEqual()` for constant-time comparison\n * to prevent timing attacks.\n */\nexport function verifyWebhookSignature(\n payload: Buffer | Uint8Array,\n signatureHeader: string,\n secret: string\n): boolean {\n if (!signatureHeader.startsWith(\"sha256=\")) {\n return false;\n }\n\n const expected = createHmac(\"sha256\", secret)\n .update(payload)\n .digest(\"hex\");\n const received = signatureHeader.slice(\"sha256=\".length);\n\n // Constant-time comparison requires equal-length buffers\n const expectedBuf = Buffer.from(expected, \"utf-8\");\n const receivedBuf = Buffer.from(received, \"utf-8\");\n\n if (expectedBuf.length !== receivedBuf.length) {\n return false;\n }\n\n return timingSafeEqual(expectedBuf, receivedBuf);\n}\n","/**\n * UAM SDK -- the agent-facing API.\n */\n\nexport { Agent } from \"./agent.js\";\nexport type { ReceivedMessage, SendResult, SendStatus } from \"./message.js\";\nexport { PENDING_NOTE, SEND_STATUSES, pendingNote, sendStatus, supports } from \"./message.js\";\nexport { SDKConfig } from \"./config.js\";\nexport { KeyManager } from \"./key-manager.js\";\nexport { ContactBook } from \"./contact-book.js\";\nexport { HandshakeManager, bindCardToEnvelope } from \"./handshake.js\";\nexport { EnvelopeReplayCache, PersistentReplayCache } from \"./replay-cache.js\";\nexport { RELAY_META_FEATURE, STORED_MAIL_MAX_AGE, relayVouches } from \"./freshness.js\";\nexport { AddressResolver, SmartResolver, Tier1Resolver, Tier2Resolver, Tier3Resolver, type Tier3Config } from \"./resolver.js\";\nexport { TransportBase, HTTPTransport, WebSocketTransport, createTransport } from \"./transport/index.js\";\nexport { verifyWebhookSignature } from \"./webhook-verify.js\";\nexport { parseUamTxt, extractPublicKey, queryUamTxt, resolveKeyViaHttps, generateTxtRecord } from \"./dns-verifier.js\";\n"],"mappings":"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","names":["domain","dnsResolveTxt","import_node_path","MessageType","sodium","nonce","import_node_crypto","nonce","buildSignableDict","address","import_node_crypto","did","import_node_crypto","import_node_fs","import_node_path","import_node_os","address","import_node_fs","import_node_path","Database","address","domain","address","address","domain","address","WebSocket","address","import_node_fs","import_node_path","import_promises","import_better_sqlite3","sleep","Database","address","domain","generateTxtRecord","import_node_crypto","secret"]}