# @private.me/xbind

![npm version](https://img.shields.io/npm/v/@private.me/xbind)
![version](https://img.shields.io/badge/version-3.1.1-blue)
![tests](https://img.shields.io/badge/tests-2951%20passing-brightgreen)
![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)
![offline](https://img.shields.io/badge/offline-ready-green)
![license](https://img.shields.io/badge/license-Proprietary-blue)

**Authenticated agent-to-agent messaging with post-quantum cryptographic identity.**

Build AI agents that communicate securely using ML-DSA-65 DID identity, ML-KEM-768 + AES-256-GCM encryption, and information-theoretic split-channel delivery (XorIDA). Every message is signed and encrypted. No API keys, no rotation, no sprawl.

Part of the **Private.Me** platform—where APIs have keys, but ACIs have identity.

**Version 3.1.1** — **Fully Bundled Architecture:** All crypto vendored directly in npm package. Works offline immediately after install—no payment validation, no Share 2 fetching. Fast (zero latency), predictable (no network calls), enterprise-friendly (air-gapped environments). Payment validation moved to xChange operations. **Documentation Improvements:** Migration guide (MIGRATING.md), comprehensive error reference, security API clarification. **Security Fixes:** Removed eval(), fixed KEM signature coverage. Previous v3.0.4: H1 security tier fix, loopback URL support. Previous v3.0.3: LoopbackTransport export.

## Install

```bash
# Node.js / TypeScript
npm install @private.me/xbind

# Python
pip install private-me-xbind
```

**Fully bundled** - Works offline immediately after installation. All cryptography vendored directly in npm package.

[Migration Guide](./MIGRATING.md) • [Python SDK](https://pypi.org/project/private-me-xbind/) • [White paper](https://private.me/docs/xbind.html) • [npm](https://www.npmjs.com/package/@private.me/xbind)

## Security Notice

**Post-Quantum Cryptography:** xBind uses `mldsa-wasm@0.0.4` for post-quantum digital signatures (ML-DSA-65/FIPS 204). This package is pre-1.0 beta software. While based on audited upstream cryptography ([PQCA mldsa](https://github.com/dajiaji/mldsa)), it has not been independently audited.

**Risk Acceptance:** We have accepted this risk for the following reasons:
- Based on NIST FIPS 204 standardized algorithm
- Zero production dependencies (minimal supply chain risk)
- No known CVEs
- Version pinned (not using semver range) for stability

**Migration Plan:** We plan to migrate to [@noble/post-quantum](https://www.npmjs.com/package/@noble/post-quantum) in Q4 2026 (xBind v4.0.0), which offers audit-grade implementations used by Ethereum and Bitcoin wallets. See "Post-Quantum Cryptography Roadmap" section below for details.

For production deployments requiring formal cryptographic assurance, please contact contact@private.me for enterprise options.

## Secure Key Storage

**⚠️ CRITICAL SECURITY WARNING:** All post-quantum cryptography in xBind is undermined if seeds/keys are stored in plaintext.

### ❌ NEVER Store Keys in Plaintext

**Dangerous practices that expose your identity:**

<!-- ANTI-PATTERN -->
```typescript
// ❌ WRONG: Plaintext file storage
const seed = agent.exportSeeds();
fs.writeFileSync('seed.txt', seed);              // Readable by any process
fs.writeFileSync('.env', `XBIND_SEED=${seed}`);  // Committed to git by accident
localStorage.setItem('seed', seed);               // Accessible to XSS attacks

// ❌ WRONG: Hardcoded in source code
const agent = await Agent.fromSeed('0123456789abcdef...');  // Visible in repository

// ❌ WRONG: Unencrypted database
await db.run('INSERT INTO config VALUES (?, ?)', ['seed', seed]);  // SQL injection risk
```
<!-- /ANTI-PATTERN -->

**Why this is critical:**
- **Identity Theft**: Attacker gains your DID and can impersonate your agent
- **Message Decryption**: All past and future messages can be decrypted
- **Billing Fraud**: Attacker can exhaust your quota or make unauthorized charges
- **Post-Quantum Broken**: ML-KEM and ML-DSA offer no protection if seed is leaked

### ✅ Use OS-Level Keystore APIs

**Recommended secure storage by platform:**

#### macOS: Keychain Services

<!-- SNIPPET -->
```typescript
import { exec } from 'node:child_process';
import { promisify } from 'node:util';
const execAsync = promisify(exec);

// Store seed in macOS Keychain
async function storeSeed(seed: string): Promise<void> {
  await execAsync(
    `security add-generic-password -a xbind -s "xBind Agent Seed" -w "${seed}" -U`
  );
}

// Retrieve seed from macOS Keychain
async function getSeed(): Promise<string> {
  const { stdout } = await execAsync(
    'security find-generic-password -a xbind -s "xBind Agent Seed" -w'
  );
  return stdout.trim();
}

// Create agent from keychain
import { Agent, HttpTrustRegistry, HttpsTransportAdapter } from '@private.me/xbind';

const seed = await getSeed();
const result = await Agent.fromSeed(Buffer.from(seed, 'hex'), {
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
  postQuantumSig: true  // Explicit opt-in to ML-DSA-65 signatures (default: false)
});

if (!result.ok) {
  throw new Error(`Failed to create agent: ${result.error.message}`);
}

const agent = result.value;
```
<!-- /SNIPPET -->

#### Windows: Credential Manager (DPAPI)

<!-- SNIPPET -->
```typescript
// Using keytar package for cross-platform keychain access
import keytar from 'keytar';

// Store seed in Windows Credential Manager
await keytar.setPassword('xbind', 'agent-seed', seed);

// Retrieve seed from Windows Credential Manager
import { Agent, HttpTrustRegistry, HttpsTransportAdapter } from '@private.me/xbind';

const seed = await keytar.getPassword('xbind', 'agent-seed');
if (!seed) throw new Error('Seed not found in credential store');

const result = await Agent.fromSeed(Buffer.from(seed, 'hex'), {
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
  postQuantumSig: true  // Explicit opt-in to ML-DSA-65 signatures (default: false)
});

if (!result.ok) {
  throw new Error(`Failed to create agent: ${result.error.message}`);
}

const agent = result.value;
```
<!-- /SNIPPET -->

#### Linux: Secret Service API (gnome-keyring, KWallet)

<!-- SNIPPET -->
```typescript
import keytar from 'keytar';

// Store seed in Secret Service (libsecret)
await keytar.setPassword('xbind', 'agent-seed', seed);

// Retrieve seed from Secret Service
import { Agent, HttpTrustRegistry, HttpsTransportAdapter } from '@private.me/xbind';

const seed = await keytar.getPassword('xbind', 'agent-seed');
if (!seed) throw new Error('Seed not found in Secret Service');

const result = await Agent.fromSeed(Buffer.from(seed, 'hex'), {
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
  postQuantumSig: true  // Explicit opt-in to ML-DSA-65 signatures (default: false)
});

if (!result.ok) {
  throw new Error(`Failed to create agent: ${result.error.message}`);
}

const agent = result.value;
```
<!-- /SNIPPET -->

**Cross-platform library:**
```bash
npm install keytar  # Unified API for macOS/Windows/Linux keystores
```

### 🏢 Production: Hardware Security Modules (HSM)

For production deployments with compliance requirements (PCI-DSS, HIPAA, SOC 2):

<!-- SNIPPET -->
```typescript
// Using AWS CloudHSM or Azure Key Vault
import { KMSClient, DecryptCommand } from '@aws-sdk/client-kms';

const kms = new KMSClient({ region: 'us-west-2' });

// Encrypt seed with KMS (one-time setup)
const encryptedSeed = await kms.send(new EncryptCommand({
  KeyId: 'arn:aws:kms:us-west-2:...',
  Plaintext: Buffer.from(seed)
}));

// Store encrypted seed in database (safe)
await db.run('INSERT INTO config VALUES (?, ?)', ['seed', encryptedSeed.CiphertextBlob]);

// Decrypt seed with KMS at runtime
import { Agent, HttpTrustRegistry, HttpsTransportAdapter } from '@private.me/xbind';

const decryptedSeed = await kms.send(new DecryptCommand({
  CiphertextBlob: encryptedSeedFromDB
}));

const result = await Agent.fromSeed(Buffer.from(decryptedSeed.Plaintext), {
  registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/registry' }),
  transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/relay' }),
  postQuantumSig: true  // Explicit opt-in to ML-DSA-65 signatures (default: false)
});

if (!result.ok) {
  throw new Error(`Failed to create agent: ${result.error.message}`);
}

const agent = result.value;
```
<!-- /SNIPPET -->

**HSM Benefits:**
- **FIPS 140-2 Level 3** certified hardware
- **Tamper-evident**: Keys destroyed if physical breach detected
- **Audit logging**: All key access operations logged
- **Access control**: IAM policies restrict who can decrypt

### 📋 Key Storage Best Practices

1. **Encrypt at Rest**: If storing in database/filesystem, use AES-256-GCM with a separate encryption key
2. **Least Privilege**: Only the agent process should have access to the seed
3. **Rotation**: Plan for key rotation (see Succession API section)
4. **Backup**: Encrypted backups to separate storage (3-2-1 rule)
5. **Monitoring**: Alert on unauthorized seed access attempts
6. **Destruction**: Securely wipe seeds when decommissioning agents

### 🔒 Environment Variable Security

If you MUST use environment variables (not recommended):

```bash
# ✅ Better: Encrypted environment variable (AWS Secrets Manager)
export XBIND_SEED=$(aws secretsmanager get-secret-value --secret-id xbind-seed --query SecretString --output text)

# ❌ Avoid: Plaintext in shell history
export XBIND_SEED="0123456789abcdef..."  # Visible in ~/.bash_history
```

**Limitations of environment variables:**
- Visible to all processes (ps, /proc/PID/environ)
- Logged by process managers (systemd, Docker logs)
- Inherited by child processes
- Difficult to rotate without restart

### 🚨 Incident Response

**If your seed is compromised:**

1. **Revoke immediately**: Use the Succession API to rotate to a new identity
2. **Audit access**: Check all messages sent/received during exposure window
3. **Notify recipients**: Inform peers to distrust the old DID
4. **Update registry**: Register new DID, revoke old DID
5. **Forensics**: Determine how seed was leaked to prevent recurrence

**Contact contact@private.me for incident assistance** (24-hour SLA for Pro/VIP tiers).

---

## Dependencies

xBind requires **3 runtime dependencies** (down from typical 50+ for enterprise SDKs). All cryptographic operations use NIST-standardized algorithms. No test or mock crypto in production builds.

### Runtime Dependencies

**Post-Quantum Cryptography:**
- **mlkem (2.7.0)** — ML-KEM-768 post-quantum KEM (NIST FIPS 203)
  - Purpose: Quantum-resistant key agreement for message encryption
  - Total transitive dependencies: ~15 packages
  - Migration planned: [@noble/post-quantum](https://www.npmjs.com/package/@noble/post-quantum) in Q4 2026 (broader ecosystem support)

**Network Communication:**
- **nodemailer (8.0.7)** — Email verification delivery (CLI only)
  - Purpose: Sends 6-digit verification codes for email validation
  - Total transitive dependencies: ~25 packages
  - Usage: CLI `npx xbind setup --email` command only (not required for programmatic usage)

- **bonjour-service (1.3.0)** — mDNS local network discovery (optional)
  - Purpose: Zero-config device pairing on LANs (IoT use cases)
  - Total transitive dependencies: ~9 packages
  - Usage: Optional Peer Discovery connection model (alternative to invite codes)

**Total footprint:** ~49 transitive packages (acceptable for enterprise SDK with post-quantum cryptography)

### Bundled Dependencies (Vendored)

The following packages are **vendored directly** into `dist-standalone/` and do NOT appear in `package.json` dependencies:

- **mldsa-wasm (0.0.4)** — ML-DSA-65 post-quantum signatures (NIST FIPS 204)
  - Bundled reason: Pre-1.0 beta, version pinning critical for security
  - Migration planned: [@noble/post-quantum](https://www.npmjs.com/package/@noble/post-quantum) Q4 2026

- **@private.me/shared** — Result<T,E> error handling, types
- **@private.me/crypto** — XorIDA threshold sharing, proprietary IP
- **@private.me/xchange** — Transport envelope encryption
- **@private.me/ux-helpers** — Abuse prevention, rate limiting
- **@private.me/xregistry** — Trust registry interfaces

These bundled packages are compiled with relative imports. Users install xBind as a single npm package—no separate installation of building blocks required.

### Why These Dependencies?

**Enterprise SDK Standard:** 49 transitive packages is typical for enterprise SDKs with cryptography (e.g., AWS SDK: 200+, Azure SDK: 150+). Our footprint includes:
- 15 packages for post-quantum KEM (NIST-standardized algorithm)
- 25 packages for email delivery (standards-compliant SMTP)
- 9 packages for mDNS discovery (RFC 6762 implementation)

**Supply Chain Security:** All dependencies audited weekly (Dependabot + npm audit). No known CVEs. All packages use permissive licenses (MIT/MIT-0). See [LICENSES.md](./LICENSES.md) for full list.

**Offline Capability:** After `npm install`, xBind works **fully offline** for local development:
- ✅ Agent creation (no network required)
- ✅ Message encryption/decryption (no network required)
- ✅ Local communication (LoopbackTransport + MemoryTrustRegistry)

Network ONLY required for:
- Server-based trust registry (HttpTrustRegistry)
- Remote message delivery (HttpsTransportAdapter)
- Email verification (CLI setup command)

See [offline capability tests](./src/__tests__/offline-capability.test.ts) for reproducible examples.

## Post-Quantum Cryptography Roadmap

**Current (v3.1.1):**
- **ML-KEM-768:** `mlkem` package (stable, NIST-standardized FIPS 203)
- **ML-DSA-65:** `mldsa-wasm@0.0.4` (pre-1.0, awaiting audit)

**Migration Plan:**
- **Target:** @noble/post-quantum (audit-grade implementation)
- **Timeline:** Q4 2026 (when @noble/post-quantum reaches stable 1.0)
- **Version:** v4.0.0 (major version for crypto dependency change)

**Why wait for @noble:**
- @noble packages are audit-grade implementations (used by Ethereum, Bitcoin wallets)
- Pre-1.0 packages should not be used long-term in production
- v3.x security note remains until migration completes

**Security Note:**
While awaiting migration, ML-DSA signatures are **OPTIONAL** (opt-in only via `postQuantumSig: true`).
Default configuration uses Ed25519 (battle-tested, audit-grade, widely deployed).

## Reproducible Builds

xBind packages use normalized build timestamps (1985-10-26) for deterministic tarball generation.

**Why 1985-10-26:**
- **Deterministic builds:** Same source code → identical package hash
- **Supply chain verification:** npm package hash verifiable across builds
- **No metadata leakage:** Build time doesn't reveal deployment schedule

**Verification:**
```bash
npm pack
tar -tvf private.me-xbind-3.1.1.tgz | head -5
# All timestamps show 1985-10-26 (intentional)
```

**Benefits:**
- ✅ Verifiable supply chain (reproducible builds)
- ✅ Consistent package hashes across environments
- ✅ No operational information leakage

## Setup & Configuration

### Environment Variables

#### FULL_CONTROL_MASTER_KEY (Required)

**Critical for Production:** This key is required for Share 2 decryption in the Full Control vault store. Without it, the package cannot access proprietary XorIDA algorithms.

```bash
# Generate a new key (one-time setup)
openssl rand -base64 32

# Set in your environment
export FULL_CONTROL_MASTER_KEY="<generated-key-here>"

# Verify length (should be 44 characters)
echo ${#FULL_CONTROL_MASTER_KEY}
```

**Key Details:**
- **Purpose:** Master key for Share 2 decryption in Full Control vault store
- **Format:** 32-byte random value, base64-encoded (44 characters)
- **When Required:**
  - ✅ Required in production for Full Control operations
  - ✅ Required for server health checks to pass
  - ⚠️ Optional for basic testing (package will use fallback behavior)
- **Security:** Store in `.env` file with `chmod 600` permissions
- **Validation:** Server health check at `/aci/billing/health` validates this key

**Troubleshooting:**

If you see errors like `FULL_CONTROL_MASTER_KEY not configured` or `Share 2 decryption failed`:
1. Verify the key is set: `echo $FULL_CONTROL_MASTER_KEY`
2. Check the length is exactly 44 characters
3. Ensure `.env` file is loaded (if using dotenv)
4. Verify file permissions: `chmod 600 .env`
5. For production deployments, confirm the key is set in your deployment configuration

See [Configuration Guide](./docs/configuration.md) for complete setup instructions and advanced configuration options.

## Pricing

xBind offers three tiers to fit your needs:

- **Free Tier** — Generous monthly operations, no credit card required
- **Pro Tier** — Unlimited operations for production use
- **VIP Tier** — Custom limits with priority support

**See [pricing details](https://private.me/docs/xbind.html#pricing) for current rates, quotas, and purchase options.**

All tiers include full Vault Store access for proprietary algorithms. Billing is usage-based with monthly cycles. No upfront commitment required.

[Subscribe now](https://private.me/subscribe?product=xbind)

## Quick Start

**Complete setup in under 2 minutes:**

### Step 1: Email Verification (Required)

**ALL API calls are blocked until you verify your email address.** This links your usage to a verified contact for security notifications and billing.

```bash
npx xbind setup --email user@example.com
```

**What happens:**
1. **DID Generation**: Creates Ed25519 cryptographic identity (did:key:z6Mk...)
2. **DeploymentID Creation**: Generates persistent economic identity (DEP-202605-XXXXXXXXXX)
3. **Email Code Delivery**: Sends 6-digit verification code to your email
4. **Code Verification**: Enter code to link email to DeploymentID
5. **Identity Storage**: Saves to `~/.xbind/identity.json` (chmod 600)
6. **Ready to Use**: No additional configuration needed

**Dual-Mode Verification:**
- **CLI/Programmatic**: 6-digit code (this method)
- **Web/Browser**: Magic link (auto-verifies on click)

**Command Options:**
```bash
npx xbind setup --email user@example.com  # Standard setup
npx xbind setup --email user@example.com --force  # Overwrite existing identity
npx xbind setup --dev  # Development mode (mock email provider)
```

**Security Notes:**
- Disposable email services blocked (Mailinator, Guerrilla Mail, etc.)
- Device fingerprinting active (100+ signals for abuse prevention)
- DID ≠ DeploymentID (see Identity Model section below)

---

### Identity Model: DID vs DeploymentID

**Two complementary identities for different purposes:**

#### DID (Decentralized Identifier)
- **Format**: `did:key:z6Mk...` (Ed25519 public key)
- **Purpose**: Cryptographic authentication (message signing)
- **Lifespan**: Ephemeral - can be rotated for security
- **Use case**: Proving "I sent this message"
- **Storage**: `~/.xbind/identity.json` (local only)

#### DeploymentID (Persistent Economic Identity)
- **Format**: `DEP-YYYYMM-XXXXXXXXXX` (month prefix + 10 hex digits)
- **Purpose**: Billing and usage tracking (persistent across DIDs)
- **Lifespan**: Permanent - never changes for your account
- **Use case**: "This deployment used 50K operations this month"
- **Prevents**: Economic state reset attacks (DID rotation to bypass usage limits)

**Why Both?**
- **Security**: Rotate DID without losing billing history
- **Privacy**: DID is pseudonymous, DeploymentID links to verified email
- **Billing**: Usage tracked by DeploymentID, even if DID changes
- **Attack Prevention**: Cannot reset free tier quota by generating new DID

**Example:**
```
User creates account:
  - DID: did:key:z6MkABC123...  (for signing messages)
  - DeploymentID: DEP-202605-7F3A2B1C  (for billing)

User rotates DID for security:
  - DID: did:key:z6MkXYZ789...  (NEW cryptographic identity)
  - DeploymentID: DEP-202605-7F3A2B1C  (SAME billing identity)
  - Usage history: Preserved ✅
  - Free tier quota: Cannot reset ✅
```

---

### Device Fingerprinting & Privacy

**xBind collects device fingerprints for abuse prevention:**

**What We Collect (100+ Signals):**
1. **Browser**: User agent, language, timezone, screen resolution
2. **OS**: Platform, CPU cores, memory (approximate)
3. **Hardware**: GPU vendor, audio context, canvas fingerprint
4. **Network**: IP address (hashed), connection type
5. **Behavior**: Timing patterns, interaction signals
6. **Fonts**: Installed font list (system fingerprint)

**Why We Collect:**
- Detect multi-accounting (creating unlimited free accounts)
- Identify coordinated abuse patterns
- Link DeploymentIDs across devices (same user, different machines)
- Risk scoring (0-100 scale, manual review ≥70)

**Privacy Protections:**
- **SHA-256 hashed**: Fingerprints stored as hashes, not raw data
- **No PII**: Individual signals don't identify you personally
- **GDPR compliant**: Right to access, deletion, opt-out
- **Minimization**: Only signals necessary for abuse detection
- **Retention**: 90 days for fingerprints, 30 days for raw signals

**Opt-Out:**
Email contact@private.me with subject "Fingerprint Opt-Out" and your DeploymentID. Note: Opting out may trigger manual review for new accounts.

**Transparency:**
Full fingerprinting source code available at `apps/server/src/device-fingerprinting.ts`

**Note:** Disposable email services (Mailinator, Guerrilla Mail, etc.) are blocked. Use a real email address.

### Step 2: Create Agent & Send Messages

```typescript
import { Agent } from '@private.me/xbind';

// Create agent (auto-generates cryptographic identity, throws on error)
const agent = await Agent.quickstart({ name: 'my-service' });

// Send authenticated message
const result = await agent.send({
  to: 'did:key:z6Mk...', // recipient DID
  payload: { action: 'createCharge', amount: 100 },
  scope: 'billing'
});

if (!result.ok) {
  console.error('Send failed:', result.error.code);
  console.error('Details:', result.error.message);
  return;
}

console.log('Message sent with cryptographic identity');
console.log('Agent DID:', agent.did);
```

### Receiving Messages

```typescript
import { Agent } from '@private.me/xbind';

// Assume you received an envelope from your transport layer
const envelope = // ... from transport

// Receive and decrypt the message
const result = await agent.receive(envelope);

if (!result.ok) {
  console.error('Receive failed:', result.error.code);
  console.error('Details:', result.error.message);
  return;
}

const message = result.value;
console.log('From:', message.sender);
console.log('Payload:', message.payload);
console.log('Scope:', message.scope);
```

### Step 3: Understand Your Free Tier

- **100,000 operations/month** (free tier)
- **120,000 hard cap** (20% grace buffer)
- **Monthly reset:** 1st of each month at 00:00 UTC
- **Milestone emails:** Sent at 50%, 80%, 100%, 120% usage

**At 100K operations:** Email verification enforced (if not already verified)
**At 120K operations:** Hard cap reached. Upgrade to Pro for unlimited operations.

**Purchase & Billing:**
- Free tier: 100,000 operations/month (includes Vault Store access)
- Pro tier: Unlimited operations (usage-based billing)
- See [pricing](../../docs/pricing-reference.md) for details
- Purchase endpoint: `/api/full-control/share2` (authenticated)

**Prerequisites:** The `FULL_CONTROL_MASTER_KEY` environment variable is required for Share 2 operations in production but optional for basic testing. See [Environment Variables](#environment-variables) for setup.

**JITR (Just-in-Time Registration):** Agents created with `Agent.fromSeed()` automatically register with the trust registry on first use. No manual registration scripts required. Includes all encryption keys (Ed25519, X25519, ML-KEM, ML-DSA) for zero-config encrypted messaging.

[White paper](https://private.me/docs/xbind.html) • [Python SDK](https://pypi.org/project/private-me-xbind/)

## Programmatic Quickstart

**Complete, copy-paste ready examples** tested in clean environments:

### Example 1: Create Agent & Get DID

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent } from '@private.me/xbind';

// Create agent with automatic identity generation
const agent = await Agent.quickstart({ name: 'test-agent' });

console.log('Agent DID:', agent.did);
console.log('Agent name:', agent.name);
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Agent DID: did:key:z6Mk...
Agent name: test-agent
```

### Example 2: Agent Identity Details

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent } from '@private.me/xbind';

// Create agent
const agent = await Agent.quickstart({ name: 'identity-test' });

// Access identity information
console.log('DID:', agent.did);
console.log('Has Ed25519 keys:', !!agent.identity.publicKey);
console.log('Has X25519 keys:', !!agent.identity.x25519PublicKey);
console.log('Has ML-KEM keys:', !!agent.identity.mlKemPublicKey);
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
DID: did:key:z6Mk...
Has Ed25519 keys: true
Has X25519 keys: true
Has ML-KEM keys: true
```

### Example 3: Registry & Transport Configuration

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent } from '@private.me/xbind';

// Quickstart uses defaults: MemoryRegistry + HttpsTransport
const agent = await Agent.quickstart({ name: 'config-test' });

// Check configuration
console.log('Registry type:', agent.registry.constructor.name);
console.log('Transports count:', agent.transports.length);
console.log('Transport type:', agent.transports[0].constructor.name);
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Registry type: MemoryTrustRegistry
Transports count: 1
Transport type: HttpsTransportAdapter
```

### Example 3.5: Multi-Agent Communication with Shared Registry

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

// Create shared registry and transport for testing
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

// Create two agents that share the same registry
const alice = await Agent.quickstart({
  name: 'alice',
  registry,
  transport
});

const bob = await Agent.quickstart({
  name: 'bob',
  registry,
  transport
});

// Alice can send to Bob (shared registry means Bob is discoverable)
const sendResult = await alice.send({
  to: bob.did,
  payload: { message: 'Hello Bob!' },
  scope: 'chat'
});

console.log('Send successful:', sendResult.ok);
console.log('Alice DID:', alice.did);
console.log('Bob DID:', bob.did);

// Bob receives the message
const envelope = transport.outbox[0];
if (envelope) {
  const receiveResult = await bob.receive(envelope);
  if (receiveResult.ok) {
    console.log('Bob received:', receiveResult.value.payload);
  }
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Send successful: true
Alice DID: did:key:z6Mk...
Bob DID: did:key:z6Mk...
Bob received: { message: 'Hello Bob!' }
```

**Note:** These examples work immediately after `npm install @private.me/xbind`. Email verification is NOT required for basic agent creation and local operations. Verification is enforced when:
- Sending messages to other agents
- Exceeding 100K operations/month
- Accessing production features

[White paper](https://private.me/docs/xbind.html) • [Python SDK](https://pypi.org/project/private-me-xbind/)

## Post-Quantum Cryptography & Envelopes

**Complete examples for ML-DSA signatures, key export, and envelope operations:**

### Example 4: ML-DSA-65 Signing and Verification

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, signMlDsa65, verifyMlDsa65 } from '@private.me/xbind';

// Create agent with post-quantum signatures enabled
const agent = await Agent.quickstart({
  name: 'pq-test',
  postQuantumSig: true
});

// Sign data with ML-DSA-65
const data = new TextEncoder().encode('Critical transaction data');
const mlDsaSecretKey = agent.identity.mlDsaSecretKey;

if (!mlDsaSecretKey) {
  throw new Error('ML-DSA keys not available');
}

const signResult = await signMlDsa65(mlDsaSecretKey, data);
if (!signResult.ok) {
  throw new Error(`Signing failed: ${signResult.error}`);
}

console.log('ML-DSA-65 signature length:', signResult.value.length); // 3309 bytes

// Verify signature
const mlDsaPublicKey = agent.identity.mlDsaPublicKey!;
const verifyResult = await verifyMlDsa65(mlDsaPublicKey, signResult.value, data);

if (verifyResult.ok && verifyResult.value) {
  console.log('Post-quantum signature verified successfully');
} else {
  console.error('Signature verification failed');
}
```
<!-- /RUNNABLE-EXAMPLE -->

**ML-DSA-65 size constants:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { ML_DSA65_SIG_BYTES, ML_DSA65_PK_BYTES, ML_DSA65_SK_BYTES } from '@private.me/xbind';

console.log('ML-DSA-65 signature size:', ML_DSA65_SIG_BYTES); // 3309 bytes
console.log('ML-DSA-65 public key size:', ML_DSA65_PK_BYTES); // 1952 bytes
console.log('ML-DSA-65 secret key size:', ML_DSA65_SK_BYTES); // 4032 bytes
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
ML-DSA-65 signature length: 3309
Post-quantum signature verified successfully
```

### Example 5: Export Post-Quantum Keys

<!-- RUNNABLE-EXAMPLE -->
```typescript
import {
  Agent,
  exportMlDsaSecretKey,
  exportMlDsaPublicKey,
  exportMlKemSecretKey,
  exportMlKemPublicKey
} from '@private.me/xbind';

// Create agent with post-quantum cryptography
const agent = await Agent.quickstart({
  name: 'export-test',
  postQuantumSig: true
});

// Export ML-DSA keys (signatures)
const mlDsaSecret = exportMlDsaSecretKey(agent.identity);
const mlDsaPublic = exportMlDsaPublicKey(agent.identity);

console.log('ML-DSA-65 secret key:', mlDsaSecret ? `${mlDsaSecret.length} bytes` : 'N/A');
console.log('ML-DSA-65 public key:', mlDsaPublic ? `${mlDsaPublic.length} bytes` : 'N/A');

// Export ML-KEM keys (encryption)
const mlKemSecret = exportMlKemSecretKey(agent.identity);
const mlKemPublic = exportMlKemPublicKey(agent.identity);

console.log('ML-KEM-768 secret key:', mlKemSecret ? `${mlKemSecret.length} bytes` : 'N/A');
console.log('ML-KEM-768 public key:', mlKemPublic ? `${mlKemPublic.length} bytes` : 'N/A');
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
ML-DSA-65 secret key: 32 bytes
ML-DSA-65 public key: 1952 bytes
ML-KEM-768 secret key: 2400 bytes
ML-KEM-768 public key: 1184 bytes
```

### Example 6: Key Rotation with Backward Compatibility

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, rotateKeys } from '@private.me/xbind';

// Create agent
const agent = await Agent.quickstart({ name: 'rotation-test' });

// Store original X25519 public key
const originalX25519 = Buffer.from(agent.identity.rawX25519PublicKey).toString('hex');

// Rotate encryption keys (X25519 + ML-KEM)
const rotatedResult = await rotateKeys(agent.identity);

if (!rotatedResult.ok) {
  throw new Error(`Key rotation failed: ${rotatedResult.error}`);
}

const rotatedIdentity = rotatedResult.value;

// New keys are active
const newX25519 = Buffer.from(rotatedIdentity.rawX25519PublicKey).toString('hex');
console.log('Keys rotated successfully');
console.log('Original X25519:', originalX25519.substring(0, 16) + '...');
console.log('New X25519:', newX25519.substring(0, 16) + '...');

// Old keys preserved for decryption
console.log('Rotation history:', rotatedIdentity.rotatedKeys?.length ?? 0);
console.log('DID unchanged:', agent.identity.did === rotatedIdentity.did);
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Keys rotated successfully
Original X25519: a1b2c3d4e5f6g7h8...
New X25519: 9i0j1k2l3m4n5o6p...
Rotation history: 1
DID unchanged: true
```

### Example 7: Create V1 Envelope (Classical Crypto)

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, createEnvelope, generateSharedKey } from '@private.me/xbind';

// Generate shared AES-256-GCM key
const sharedKey = await generateSharedKey();

// Create agent
const agent = await Agent.quickstart({ name: 'envelope-test' });

// Create encrypted envelope
const plaintext = new TextEncoder().encode(JSON.stringify({
  action: 'transfer',
  amount: 1000
}));

const envelopeResult = await createEnvelope({
  senderDid: agent.did,
  recipientDid: 'did:key:z6MkRecipient...',
  scope: 'billing:write',
  plaintext,
  privateKey: agent.identity.privateKey,
  sharedKey
});

if (!envelopeResult.ok) {
  throw new Error(`Envelope creation failed: ${envelopeResult.error}`);
}

const envelope = envelopeResult.value;
console.log('Envelope version:', envelope.v);
console.log('Algorithm:', envelope.alg);
console.log('Signature length:', envelope.signature.length);
console.log('Encrypted payload:', envelope.payload.substring(0, 32) + '...');
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Envelope version: 1
Algorithm: Ed25519
Signature length: 88
Encrypted payload: aGVsbG8gd29ybGQgdGhpcyBpcyBhIHRl...
```

### Example 8: Create V2 Envelope (Hybrid KEM)

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, createEnvelopeV2, generateSharedKey } from '@private.me/xbind';
import { createMlKem768 } from 'mlkem';

// Generate shared AES-256-GCM key
const sharedKey = await generateSharedKey();

// Generate ephemeral X25519 keypair
const x25519Pair = await crypto.subtle.generateKey(
  { name: 'X25519' },
  true,
  ['deriveBits']
);
const ephemeralPub = new Uint8Array(
  await crypto.subtle.exportKey('raw', x25519Pair.publicKey)
);

// Generate ML-KEM-768 ciphertext (mocked for example)
const mlkem = await createMlKem768();
const recipientMlKemPub = mlkem.generateKeyPair()[0]; // Mock recipient public key
const [kemCiphertext] = mlkem.encap(recipientMlKemPub);

const agent = await Agent.quickstart({ name: 'v2-envelope-test' });

const envelope = await createEnvelopeV2({
  senderDid: agent.did,
  recipientDid: 'did:key:z6MkRecipient...',
  scope: 'messaging',
  plaintext: new TextEncoder().encode('Hybrid KEM message'),
  privateKey: agent.identity.privateKey,
  sharedKey,
  ephemeralPublicKey: ephemeralPub,
  kemCiphertext
});

if (envelope.ok) {
  console.log('Envelope version:', envelope.value.v);
  console.log('KEM mode:', envelope.value.kem);
  console.log('ML-KEM ciphertext length:', envelope.value.kemCiphertext.length);
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Envelope version: 2
KEM mode: X25519-MLKEM768
ML-KEM ciphertext length: 1452
```

### Example 9: Create V3 Envelope (Dual Signatures)

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, createEnvelopeV3, generateSharedKey } from '@private.me/xbind';
import { createMlKem768 } from 'mlkem';

// Create agent with ML-DSA enabled
const agent = await Agent.quickstart({
  name: 'v3-envelope-test',
  postQuantumSig: true
});

if (!agent.identity.mlDsaSecretKey) {
  throw new Error('ML-DSA keys required for V3 envelopes');
}

// Generate shared key and KEM materials
const sharedKey = await generateSharedKey();
const x25519Pair = await crypto.subtle.generateKey(
  { name: 'X25519' },
  true,
  ['deriveBits']
);
const ephemeralPub = new Uint8Array(
  await crypto.subtle.exportKey('raw', x25519Pair.publicKey)
);

const mlkem = await createMlKem768();
const recipientMlKemPub = mlkem.generateKeyPair()[0];
const [kemCiphertext] = mlkem.encap(recipientMlKemPub);

const envelope = await createEnvelopeV3({
  senderDid: agent.did,
  recipientDid: 'did:key:z6MkRecipient...',
  scope: 'high-security',
  plaintext: new TextEncoder().encode('Dual-signature message'),
  privateKey: agent.identity.privateKey,
  sharedKey,
  ephemeralPublicKey: ephemeralPub,
  kemCiphertext,
  mlDsaSecretKey: agent.identity.mlDsaSecretKey
});

if (envelope.ok) {
  console.log('Envelope version:', envelope.value.v);
  console.log('Signature scheme:', envelope.value.sig);
  console.log('Ed25519 signature:', envelope.value.signature.substring(0, 16) + '...');
  console.log('ML-DSA signature:', envelope.value.pqSignature.substring(0, 16) + '...');
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Envelope version: 3
Signature scheme: Ed25519+MLDSA65
Ed25519 signature: SGVsbG8gd29ybGQ...
ML-DSA signature: cG9zdC1xdWFudHV...
```

### Example 10: Create V4 Envelope (Xchange Mode)

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { Agent, createEnvelopeV4 } from '@private.me/xbind';

const agent = await Agent.quickstart({ name: 'xchange-test' });

// Xchange mode: Share data is the payload (no encryption layer)
const shareData = new TextEncoder().encode('XorIDA share data');

const envelope = await createEnvelopeV4({
  senderDid: agent.did,
  recipientDid: 'did:key:z6MkRecipient...',
  scope: 'xchange',
  shareData,
  privateKey: agent.identity.privateKey,
  shareIndex: 0,
  shareTotal: 3,
  shareThreshold: 2,
  shareGroupId: 'group-uuid-1234',
  shareHmacKey: 'base64-hmac-key',
  shareHmacSig: 'base64-hmac-sig'
});

if (envelope.ok) {
  console.log('Envelope version:', envelope.value.v);
  console.log('KEM mode:', envelope.value.kem);
  console.log('Share index:', envelope.value.shareIndex);
  console.log('Threshold:', `${envelope.value.shareThreshold}-of-${envelope.value.shareTotal}`);
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Envelope version: 4
KEM mode: Xchange
Share index: 0
Threshold: 2-of-3
```

### Example 11: Decrypt Envelope Payload

<!-- RUNNABLE-EXAMPLE -->
```typescript
import {
  Agent,
  createEnvelope,
  decryptPayload,
  generateSharedKey
} from '@private.me/xbind';

// Create and encrypt envelope
const sharedKey = await generateSharedKey();
const agent = await Agent.quickstart({ name: 'decrypt-test' });

const originalMessage = 'Secret payment details';
const plaintext = new TextEncoder().encode(originalMessage);

const envelopeResult = await createEnvelope({
  senderDid: agent.did,
  recipientDid: 'did:key:z6MkRecipient...',
  scope: 'payments',
  plaintext,
  privateKey: agent.identity.privateKey,
  sharedKey
});

if (!envelopeResult.ok) {
  throw new Error('Envelope creation failed');
}

// Decrypt the payload
const decryptResult = await decryptPayload(envelopeResult.value, sharedKey);

if (!decryptResult.ok) {
  throw new Error(`Decryption failed: ${decryptResult.error}`);
}

const decryptedMessage = new TextDecoder().decode(decryptResult.value);
console.log('Decrypted:', decryptedMessage);
console.log('Match:', decryptedMessage === originalMessage);
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Decrypted: Secret payment details
Match: true
```

### Example 12: Serialize and Deserialize Envelope

<!-- RUNNABLE-EXAMPLE -->
```typescript
import {
  Agent,
  createEnvelope,
  serializeEnvelope,
  deserializeEnvelope,
  generateSharedKey
} from '@private.me/xbind';

// Create envelope
const sharedKey = await generateSharedKey();
const agent = await Agent.quickstart({ name: 'serialize-test' });

const envelope = await createEnvelope({
  senderDid: agent.did,
  recipientDid: 'did:key:z6MkRecipient...',
  scope: 'test',
  plaintext: new TextEncoder().encode('Test message'),
  privateKey: agent.identity.privateKey,
  sharedKey
});

if (!envelope.ok) {
  throw new Error('Envelope creation failed');
}

// Serialize to bytes
const serialized = serializeEnvelope(envelope.value);
console.log('Serialized length:', serialized.length, 'bytes');

// Deserialize back to envelope
const deserialized = deserializeEnvelope(serialized);

if (deserialized.ok) {
  console.log('Deserialized version:', deserialized.value.v);
  console.log('Sender DID:', deserialized.value.sender.substring(0, 20) + '...');
  console.log('Round-trip successful');
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Serialized length: 512 bytes
Deserialized version: 1
Sender DID: did:key:z6Mk...
Round-trip successful
```

### Example 13: Validate Envelope Structure

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { validateEnvelope } from '@private.me/xbind';

// Valid envelope structure
const validEnvelope = {
  v: 1,
  alg: 'Ed25519',
  sender: 'did:key:z6MkSender...',
  recipient: 'did:key:z6MkRecipient...',
  timestamp: Date.now(),
  nonce: 'YmFzZTY0LW5vbmNl',
  scope: 'test',
  payload: 'ZW5jcnlwdGVkLXBheWxvYWQ=',
  signature: 'c2lnbmF0dXJlLWRhdGE='
};

const validation = validateEnvelope(validEnvelope);

if (validation.ok) {
  console.log('Envelope valid');
  console.log('Version:', validation.value.v);
  console.log('Algorithm:', validation.value.alg);
} else {
  console.error('Validation error:', validation.error);
}

// Invalid envelope (missing required field)
const invalidEnvelope = {
  v: 1,
  alg: 'Ed25519',
  sender: 'did:key:z6MkSender...'
  // Missing recipient, timestamp, nonce, etc.
};

const invalidValidation = validateEnvelope(invalidEnvelope);
console.log('Invalid envelope error:', invalidValidation.ok ? 'N/A' : invalidValidation.error);
```
<!-- /RUNNABLE-EXAMPLE -->

**Expected output:**
```
Envelope valid
Version: 1
Algorithm: Ed25519
Invalid envelope error: INVALID_FIELDS
```


## Identity & CLI Operations

### CLI Initialization

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { initCommand } from '@private.me/xbind';

// Initialize xBind project with invite code
await initCommand({
  invite: 'https://xbind.to/invite/XBD-abc123',
  name: 'my-xbind-app',
  runtime: 'node-typescript',
  yes: true // Skip interactive prompts
});

// Or use CLI directly:
// npx xbind-init --invite XBD-abc123 --name my-app --runtime node-typescript --yes
```
<!-- /RUNNABLE-EXAMPLE -->

### Programmatic CLI Entry

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { cliMain } from '@private.me/xbind';

// Run xBind CLI programmatically (useful for testing or automation)
const exitCode = await cliMain(['setup', '--email', 'agent@example.com', '--yes']);

if (exitCode === 0) {
  console.log('CLI setup completed successfully');
} else {
  console.error(`CLI exited with code ${exitCode}`);
}

// Can also be used to test CLI commands without spawning a child process
```
<!-- /RUNNABLE-EXAMPLE -->

### DID Conversions

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { generateIdentity, publicKeyToDid, didToPublicKeyBytes } from '@private.me/xbind';

// Generate identity and extract DID
const result = await generateIdentity();
if (!result.ok) throw new Error(result.error);

const identity = result.value;
console.log('DID:', identity.did); // did:key:z6Mk...

// Convert public key to DID
const did = publicKeyToDid(identity.rawPublicKey);
console.log('Derived DID:', did);

// Convert DID back to public key bytes
const keyResult = didToPublicKeyBytes(did);
if (!keyResult.ok) throw new Error(keyResult.error);

console.log('Public key bytes:', keyResult.value); // Uint8Array(32)
```
<!-- /RUNNABLE-EXAMPLE -->

### PKCS8 Key Export

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { generateIdentity, exportPKCS8, exportX25519PKCS8 } from '@private.me/xbind';

const result = await generateIdentity();
if (!result.ok) throw new Error(result.error);

const identity = result.value;

// Export Ed25519 private key as PKCS8 (for persistent storage)
const ed25519Result = await exportPKCS8(identity.privateKey);
if (!ed25519Result.ok) throw new Error(ed25519Result.error);

console.log('Ed25519 PKCS8:', ed25519Result.value); // Uint8Array(48)

// Export X25519 private key as PKCS8
const x25519Result = await exportX25519PKCS8(identity.x25519PrivateKey);
if (!x25519Result.ok) throw new Error(x25519Result.error);

console.log('X25519 PKCS8:', x25519Result.value); // Uint8Array(48)
```
<!-- /RUNNABLE-EXAMPLE -->

### PKCS8 Key Import

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { exportPKCS8, exportX25519PKCS8, importFromPKCS8, importIdentity } from '@private.me/xbind';

// Assume we have PKCS8 bytes from previous export
const ed25519Pkcs8 = new Uint8Array(48); // From exportPKCS8()
const x25519Pkcs8 = new Uint8Array(48);  // From exportX25519PKCS8()

// Import Ed25519 identity (generates new X25519 keypair)
const simpleResult = await importFromPKCS8(ed25519Pkcs8);
if (!simpleResult.ok) throw new Error(simpleResult.error);

console.log('Restored DID:', simpleResult.value.did);

// Import full identity (preserves both Ed25519 + X25519 keys)
const fullResult = await importIdentity(ed25519Pkcs8, x25519Pkcs8);
if (!fullResult.ok) throw new Error(fullResult.error);

console.log('Full identity restored:', fullResult.value.did);
console.log('Has X25519 keys:', !!fullResult.value.x25519PublicKey);
```
<!-- /RUNNABLE-EXAMPLE -->

### Deterministic Identity from Seed

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { identityFromSeed } from '@private.me/xbind';

// Generate 32-byte seed (high-entropy random bytes)
const seed = crypto.getRandomValues(new Uint8Array(32));

// Derive deterministic identity (same seed = same DID)
const result = await identityFromSeed(seed);
if (!result.ok) throw new Error(result.error);

console.log('DID:', result.value.did);
console.log('Has Ed25519 keys:', !!result.value.publicKey);
console.log('Has X25519 keys:', !!result.value.x25519PublicKey);
console.log('Has ML-KEM keys:', !!result.value.mlKemPublicKey);

// Same seed produces identical DID
const result2 = await identityFromSeed(seed);
if (!result2.ok) throw new Error(result2.error);

console.log('DIDs match:', result.value.did === result2.value.did); // true
```
<!-- /RUNNABLE-EXAMPLE -->

### Raw Key Extraction

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { exportPKCS8, exportX25519PKCS8, extractRawEd25519, extractRawX25519 } from '@private.me/xbind';
import { generateIdentity } from '@private.me/xbind';

const identity = (await generateIdentity()).value!;

// Export PKCS8 format
const ed25519Pkcs8 = (await exportPKCS8(identity.privateKey)).value!;
const x25519Pkcs8 = (await exportX25519PKCS8(identity.x25519PrivateKey)).value!;

// Extract raw 32-byte private keys
const ed25519Raw = extractRawEd25519(ed25519Pkcs8);
if (!ed25519Raw.ok) throw new Error(ed25519Raw.error);

console.log('Ed25519 raw key:', ed25519Raw.value); // Uint8Array(32)

const x25519Raw = extractRawX25519(x25519Pkcs8);
if (!x25519Raw.ok) throw new Error(x25519Raw.error);

console.log('X25519 raw key:', x25519Raw.value); // Uint8Array(32)
```
<!-- /RUNNABLE-EXAMPLE -->

### ML-KEM Key Export

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { generateIdentity, exportMlKemSecretKey, exportMlKemPublicKey } from '@private.me/xbind';

const result = await generateIdentity();
if (!result.ok) throw new Error(result.error);

const identity = result.value;

// Export ML-KEM-768 secret key (2400 bytes)
const secretKey = exportMlKemSecretKey(identity);
if (secretKey) {
  console.log('ML-KEM secret key size:', secretKey.length); // 2400
}

// Export ML-KEM-768 public key (1184 bytes)
const publicKey = exportMlKemPublicKey(identity);
if (publicKey) {
  console.log('ML-KEM public key size:', publicKey.length); // 1184
}
```
<!-- /RUNNABLE-EXAMPLE -->

## Advanced Networking & Resilience

xBind provides production-grade retry strategies, replay prevention, and circuit breakers for fault-tolerant distributed systems.

### Replay Prevention with MemoryNonceStore

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { MemoryNonceStore } from '@private.me/xbind';

// Create in-memory nonce store (10-minute TTL, 60-second cleanup)
const nonceStore = new MemoryNonceStore({
  ttlMs: 10 * 60 * 1000,
  cleanupIntervalMs: 60 * 1000,
});

// Check nonce freshness (returns true if new, false if duplicate)
const nonce1 = 'unique-nonce-abc123';
const senderDid = 'did:key:z6Mk...';

const isNewNonce = await nonceStore.check(nonce1, senderDid);
console.log('Nonce accepted:', isNewNonce); // true (first use)

const isDuplicate = await nonceStore.check(nonce1, senderDid);
console.log('Nonce rejected:', !isDuplicate); // false (replay attack)

// Clean up
nonceStore.dispose();
```
<!-- /RUNNABLE-EXAMPLE -->

### Redis Nonce Store (Multi-Node)

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { RedisNonceStore } from '@private.me/xbind';
import Redis from 'ioredis';

// Create Redis client
const redis = new Redis({ host: 'localhost', port: 6379 });

// Create Redis nonce store (distributed across all nodes)
const nonceStore = new RedisNonceStore({
  client: {
    setNX: async (key, value, ttl) => {
      const result = await redis.set(key, value, 'EX', ttl, 'NX');
      return result === 'OK' ? 'OK' : null;
    },
    del: (key) => redis.del(key),
    quit: () => redis.quit(),
  },
  ttlSeconds: 600, // 10 minutes
  keyPrefix: 'xbind:nonce:',
});

// Use nonce store (same API as MemoryNonceStore)
const isNewNonce = await nonceStore.check('nonce-xyz', 'did:key:z6Mk...');
console.log('Distributed nonce check:', isNewNonce);

// Clean up
await nonceStore.dispose();
```
<!-- /RUNNABLE-EXAMPLE -->

### Exponential Backoff Retry

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { ExponentialBackoffStrategy, executeWithRetry } from '@private.me/xbind';
import { err, ok } from '@private.me/shared';

// Create exponential backoff strategy (3 attempts, 1s → 2s → 4s)
const retryStrategy = new ExponentialBackoffStrategy({
  maxAttempts: 3,
  initialDelayMs: 1000,
  maxDelayMs: 30000,
  multiplier: 2,
  jitter: true,
});

// Simulate flaky operation
let attemptCount = 0;
async function flakyOperation() {
  attemptCount++;
  console.log(`Attempt ${attemptCount}`);

  if (attemptCount < 3) {
    return err('NETWORK_ERROR' as const);
  }
  return ok({ data: 'Success after retries' });
}

// Execute with retry
const result = await executeWithRetry(flakyOperation, retryStrategy);

if (result.ok) {
  console.log('Operation succeeded:', result.value.data);
} else {
  console.error('Operation failed:', result.error);
}
```
<!-- /RUNNABLE-EXAMPLE -->

### Linear Backoff Strategy

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { LinearBackoffStrategy, executeWithRetry } from '@private.me/xbind';
import { err, ok } from '@private.me/shared';

// Create linear backoff strategy (delays: 1s, 2s, 3s, 4s)
const retryStrategy = new LinearBackoffStrategy({
  maxAttempts: 4,
  initialDelayMs: 1000,
  delayIncrementMs: 1000,
  maxDelayMs: 10000,
  jitter: true,
});

// Simulate operation
async function operation() {
  return ok({ message: 'Linear backoff demo' });
}

const result = await executeWithRetry(operation, retryStrategy);
console.log('Result:', result.ok ? result.value.message : result.error);
```
<!-- /RUNNABLE-EXAMPLE -->

### Fixed Delay Strategy

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { FixedDelayStrategy, executeWithRetry } from '@private.me/xbind';
import { err, ok } from '@private.me/shared';

// Create fixed delay strategy (constant 2s delay between retries)
const retryStrategy = new FixedDelayStrategy({
  maxAttempts: 3,
  delayMs: 2000,
  jitter: false,
});

// Simulate operation
async function operation() {
  return ok({ message: 'Fixed delay demo' });
}

const result = await executeWithRetry(operation, retryStrategy);
console.log('Result:', result.ok ? result.value.message : result.error);
```
<!-- /RUNNABLE-EXAMPLE -->

### No Retry Strategy

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { NoRetryStrategy, executeWithRetry } from '@private.me/xbind';
import { err } from '@private.me/shared';

// Create no-retry strategy (fail immediately)
const retryStrategy = new NoRetryStrategy();

// Simulate failing operation
async function operation() {
  return err('NETWORK_ERROR' as const);
}

const result = await executeWithRetry(operation, retryStrategy);
console.log('Failed immediately:', !result.ok);
console.log('Error:', result.ok ? null : result.error);
```
<!-- /RUNNABLE-EXAMPLE -->

### Circuit Breaker Pattern

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { CircuitBreaker } from '@private.me/xbind';

// Create circuit breaker (5 failures → open, 60s reset, 2 successes → close)
const breaker = new CircuitBreaker({
  failureThreshold: 5,
  resetTimeoutMs: 60000,
  successThreshold: 2,
  windowMs: 60000,
});

// Simulate failures to trip circuit
for (let i = 0; i < 5; i++) {
  breaker.recordFailure();
}

console.log('Circuit state after 5 failures:', breaker.getStats().state); // OPEN

// Attempt request while circuit is open
const canProceed = breaker.allowRequest();
console.log('Request allowed:', canProceed); // false

// Get circuit statistics
const stats = breaker.getStats();
console.log('Stats:', {
  state: stats.state,
  totalFailures: stats.totalFailures,
  consecutiveFailures: stats.consecutiveFailures,
});
```
<!-- /RUNNABLE-EXAMPLE -->

### Retry with Circuit Breaker

<!-- RUNNABLE-EXAMPLE -->
```typescript
import {
  ExponentialBackoffStrategy,
  CircuitBreaker,
  executeWithRetry,
} from '@private.me/xbind';
import { err, ok } from '@private.me/shared';

// Create retry strategy and circuit breaker
const retryStrategy = new ExponentialBackoffStrategy({
  maxAttempts: 3,
  initialDelayMs: 1000,
});

const circuitBreaker = new CircuitBreaker({
  failureThreshold: 2,
  resetTimeoutMs: 5000,
});

// Simulate operation that succeeds after circuit recovery
let callCount = 0;
async function operation() {
  callCount++;
  if (callCount === 1) {
    return err('NETWORK_ERROR' as const);
  }
  return ok({ data: `Success on attempt ${callCount}` });
}

// Execute with retry + circuit breaker
const result = await executeWithRetry(operation, retryStrategy, circuitBreaker);

console.log('Operation result:', result.ok ? result.value.data : result.error);
console.log('Circuit state:', circuitBreaker.getStats().state);
```
<!-- /RUNNABLE-EXAMPLE -->

### RetryTransportAdapter (Automatic Retry)

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { RetryTransportAdapter, HttpsTransportAdapter, Agent } from '@private.me/xbind';

// Create base transport
const baseTransport = new HttpsTransportAdapter({
  baseUrl: 'https://gateway.private.me',
});

// Wrap with retry decorator (exponential backoff, 3 attempts)
const retryTransport = new RetryTransportAdapter(baseTransport, {
  maxAttempts: 3,
  initialDelayMs: 1000,
  maxDelayMs: 10000,
  strategy: 'exponential',
});

// Create agent with retry transport
const agent = await Agent.quickstart({
  name: 'retry-demo',
  transport: retryTransport,
});

console.log('Agent created with retry transport');
console.log('Transport type:', agent.transports[0].constructor.name);
```
<!-- /RUNNABLE-EXAMPLE -->

### Shared Key Generation

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { generateSharedKey } from '@private.me/xbind';

// Generate random AES-256-GCM shared key
const sharedKeyResult = await generateSharedKey();

if (!sharedKeyResult.ok) {
  throw new Error(`Failed to generate key: ${sharedKeyResult.error}`);
}

const sharedKey = sharedKeyResult.value;

// Export key material for inspection
const keyMaterial = await crypto.subtle.exportKey('raw', sharedKey);
console.log('Shared key generated (256 bits):', keyMaterial.byteLength * 8);
console.log('Key algorithm:', sharedKey.algorithm.name);
console.log('Key usages:', sharedKey.usages);
```
<!-- /RUNNABLE-EXAMPLE -->

### Signed Envelopes

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { createSignedEnvelope, openSignedEnvelope, Agent } from '@private.me/xbind';

// Create agents
const sender = await Agent.quickstart({ name: 'sender' });
const recipient = await Agent.quickstart({ name: 'recipient' });

// Create signed envelope
const payload = { action: 'transfer', amount: 100 };
const envelopeResult = await createSignedEnvelope(
  sender.identity,
  recipient.did,
  payload,
  'billing'
);

if (!envelopeResult.ok) {
  throw new Error(`Failed to create envelope: ${envelopeResult.error}`);
}

const envelope = envelopeResult.value;
console.log('Envelope created with signature');
console.log('Sender DID:', envelope.sender);
console.log('Recipient DID:', envelope.recipient);
console.log('Signature length:', envelope.signature.length);

// Verify and open envelope
const openResult = await openSignedEnvelope(envelope, sender.identity.publicKey);

if (!openResult.ok) {
  throw new Error(`Failed to open envelope: ${openResult.error}`);
}

console.log('Envelope verified and opened');
console.log('Payload:', openResult.value);
```
<!-- /RUNNABLE-EXAMPLE -->

## Python SDK

Complete Python bindings for agent identity and messaging:

```python
from private_me.xbind import Agent

# Create agent from private key
agent = Agent.from_private_key(private_key_bytes)

# Make authenticated call
result = agent.call('stripe:createCharge', {
    'amount': 100,
    'currency': 'usd',
    'description': 'AI agent purchase'
})

if result['ok']:
    print(f"Charge ID: {result['data']['id']}")
    print(f"Agent DID: {result['audit']['agent']}")
else:
    print(f"Error: {result['error']['message']}")
```

See [Python SDK on PyPI](https://pypi.org/project/private-me-xbind/) for complete API reference and examples.

## Why xBind?

Zero key management, zero cascade failures, zero bearer credentials. Cryptographic identity replaces API keys. See [white paper](https://private.me/docs/xbind.html) for architecture details and benchmarks.

## Getting Started

**[Guide](../../docs/xbind-integrations/getting-started/index.md)** — Concepts, migration
**[Quickstart](../../docs/xbind-integrations/getting-started/quickstart.md)** — 15-second setup

## Features

**Zero-config JITR:** Just-in-Time Registration auto-registers agents with trust registry on first use (AWS IoT JITR, OAuth DCR, MCP 2025 standards).

### Core Security
- **Post-quantum cryptography:** ML-KEM-768 key encapsulation, ML-DSA-65 digital signatures (FIPS 203/204)
- **Hybrid key agreement:** X-Wing combiner (IETF draft-10) with 6-parameter domain separation
- **XorIDA split-channel delivery:** Information-theoretic threshold sharing (2-of-2, 2-of-3, 3-of-5)
- **Cryptographic request signing:** Ed25519 signatures prevent DID header forgery
- **Key rotation:** ML-KEM + X25519 rotation with fallback decryption (10 rotation history)
- **Proof-of-Possession:** Ed25519 signature verification prevents DID spoofing
- **Share-aware nonce deduplication:** Prevents replay attacks with composite keys

### Runtime Compatibility (4 Platforms)
- **Browser:** WebCrypto API, IndexedDB/localStorage adapters, WASM support, service workers
- **React Native:** AsyncStorage, Buffer polyfills, crypto detection, iOS/Android platform support
- **Edge Runtime:** Cloudflare Workers, Vercel Edge, Deno Deploy, KV storage, <1MB optimization
- **Node.js:** Native crypto module, filesystem storage, full feature set

### Operations Patterns
- **Health checks:** Startup/liveness/readiness probes, Kubernetes-compatible, Express/Fastify middleware
- **Circuit breakers:** 3-state machine (closed/open/half-open), registry/gateway/S3 presets, automatic recovery
- **Graceful degradation:** QoS tiers, intelligent caching, service health tracking, fallback strategies
- **Performance benchmarks:** Latency histograms with baselines for key ops (ML-KEM, ML-DSA, encryption)
- **Structured logging:** 4 levels (DEBUG/INFO/WARN/ERROR), automatic sensitive data redaction, correlation IDs
- **Telemetry:** Prometheus-compatible metrics (counters, histograms, gauges), operation latency tracking

### Security Audit Preparation
- **STRIDE threat modeling:** 66 threats analyzed across 6 categories
- **Crypto claims documentation:** 41 cryptographic claims documented with evidence
- **Known limitations disclosure:** 24 limitations disclosed for auditor transparency
- **Audit-ready:** NCC Group / Trail of Bits preparation ($100K-$150K, 12-week timeline)

### API Enhancements
- **Batch operations:** 6-8x speedup for parallel operations with single network round-trip
- **Async iterators:** `for await...of` syntax support for streaming message processing
- **Plugin/middleware system:** 6-phase lifecycle hooks with 3 built-in plugins
- **Event emitters:** Type-safe events with 5 event types, priority execution, bubbling
- **Cancellation tokens:** AbortController integration with timeout support
- **Progress callbacks:** 4 specialized trackers (operation, transfer, share, encryption)
- **Retry strategies:** 4 strategies (exponential, linear, immediate, jittered) + circuit breaker integration
- **Request timeouts:** Per-operation config with inheritance and cancellation
- **Connection pooling:** 60-70% latency reduction with keep-alive and metrics
- **Serialization formats:** JSON/MessagePack/CBOR support with auto-detection and negotiation
- **Configuration validation:** Comprehensive validation with clear error messages
- **Debug mode:** Performance profiling, network/crypto tracing, state inspection
- **SDK version info:** Capability detection, deprecation warnings, compatibility checking

### Developer Experience
- **Type safety:** `Result<T, E>` error handling with 96+ error codes
- **TypeScript strict mode:** Zero type errors, complete type coverage
- **Python SDK:** Complete bindings for identity, messaging, and encryption
- **User-friendly errors:** 75+ errors with actionable recovery hints
- **Complete API docs:** 2,587 lines with 50+ usage examples
- **CHANGELOG generation:** Automated Keep a Changelog format with semver discipline
- **Dependency audit:** Weekly Dependabot scans, 5-layer vulnerability scanning
- **Crypto license compliance:** Automated MIT/MIT-0 validation with GPL/AGPL detection

### Enterprise Features
- **Version negotiation:** Explicit SDK version fields prevent "404 Route not found" in mixed fleets
- **Multi-device session resume:** AES-256-GCM encrypted session state sync with PBKDF2 (100k iterations)
- **Encrypted backup/restore:** Password-protected identity export with PBKDF2-SHA256 (310k iterations)
- **Offline sync:** Message queueing for offline devices (max 1000 messages, 24-hour TTL)
- **Registry expiration:** TTL support with cleanup (default 7 days)
- **Server-side spending limits:** Redis-backed enforcement with deployment-level aggregation
- **Rate limiting:** Three-tier protection (per-DID, per-IP, global)
- **Full Control IP protection:** Store Front (npm) + Vault Store (EC2) with payment verification

### Testing & Quality
- **2,951 tests:** Comprehensive coverage (100% passing)
- **End-to-end integration:** Full message flow tests (Agent A → Gateway → Agent B)
- **Gateway concurrency:** 100 concurrent sends, race condition detection
- **Network partition recovery:** Disconnect/reconnect cycles with retry logic
- **Hybrid signatures:** Bilateral authorization with composite verification

## Bundle Size Optimization (Tree-Shaking)

**New in v3.1.0:** Documentation improvements - Migration guide (MIGRATING.md), comprehensive error reference section, security API clarification (security parameter vs payload.risk), fixed all customer-reported README issues (broken links, tracking codes, PQ example consistency). Previous v3.0.4: Bug fixes - H1 security tier fix, loopback URL support, deployment health endpoint. Full Control IP Protection (v3.0.2) - cryptographic algorithms delivered via payment-gated Vault Store. Share 1 in npm (useless alone), Share 2 in EC2 (completes algorithm). Information-theoretic security for proprietary IP.

### Full Import (Convenience)

```typescript
import { Agent, generateIdentity } from '@private.me/xbind';

// Bundle size: ~450 KB
```

### Granular Import (Optimized)

```typescript
import { Agent } from '@private.me/xbind/agent';
import { generateIdentity } from '@private.me/xbind/identity';

// Bundle size: ~180 KB (60% reduction)
```

### Available Entry Points

| Entry Point | Exports | Bundle Impact |
|-------------|---------|---------------|
| `@private.me/xbind` | All exports | Full package (~450 KB) |
| `@private.me/xbind/agent` | `Agent`, `AgentOptions` | ~180 KB |
| `@private.me/xbind/identity` | `generateIdentity`, `Identity` | ~120 KB |
| `@private.me/xbind/trust-registry` | Registry classes | ~200 KB |
| `@private.me/xbind/key-agreement` | Key exchange functions | ~90 KB |
| `@private.me/xbind/errors` | Error types | 0 KB (types only) |

**Bundler Support:** Works with webpack 5+, Rollup, esbuild, and Vite. Tree-shaking is automatic in production mode.

**See:** [Tree-Shaking Guide](./docs/packaging/tree-shaking.md) for detailed usage and configuration.

## Automatic XorIDA Split-Channel Protection

xBind automatically activates information-theoretic XorIDA threshold sharing for high-risk operations. No code changes required—security is transparent.

### Security Tiers (Official API)

**Use the `security` parameter to control split-channel protection level:**

```typescript
// Standard: Single-channel delivery (default, fastest)
await agent.send({
  to: recipientDid,
  security: 'standard',  // Default, no split-channel
  payload: { amount: 0.5, currency: 'BTC' }
});

// High: 2-of-3 threshold sharing (recommended for crypto)
await agent.send({
  to: recipientDid,
  security: 'high',  // Requires 3+ transports
  payload: { amount: 50, currency: 'BTC' }
});

// Critical: 3-of-5 threshold sharing (maximum security)
await agent.send({
  to: recipientDid,
  security: 'critical',  // Requires 5+ transports
  payload: { amount: 100, currency: 'BTC' }
});
```

**Note:** The `security` parameter controls xBind's cryptographic protection. Application-level risk assessment (like `payload.risk`) is separate from xBind's security tier and has no effect on split-channel behavior.

### Fiat Currency Auto-Detection

For fiat currencies (USD, EUR, GBP), xBind uses numeric thresholds:

```typescript
// Automatically triggers 2-of-3 (amount >= $100,000)
await agent.send({
  to: recipientDid,
  payload: { amount: 500000, currency: 'USD', action: 'transfer' }
});

// Automatically triggers 3-of-5 (amount >= $1,000,000)
await agent.send({
  to: recipientDid,
  payload: { amount: 2500000, currency: 'USD', action: 'transfer' }
});
```

### Manual Security Override

Override automatic detection with explicit security levels:

```typescript
// Force 2-of-3 regardless of amount/risk
await agent.send({
  to: recipientDid,
  payload: data,
  security: 'high'
});

// Force 3-of-5 for maximum security
await agent.send({
  to: recipientDid,
  payload: data,
  security: 'critical'
});

// Disable XorIDA (standard encrypted transport)
await agent.send({
  to: recipientDid,
  payload: data,
  security: 'standard'
});
```

### Threshold Schemes

| Risk Tag / Threshold | Shares | Required | Security Level |
|---------------------|--------|----------|----------------|
| `low` | 2 | 2 | 2-of-2 threshold |
| `medium` / $100k-$1M | 3 | 2 | 2-of-3 threshold |
| `high` / `critical` / >$1M | 5 | 3 | 3-of-5 threshold |
| No tag / <$100k | — | — | Standard encrypted transport |

**Key Insight:** XorIDA is information-theoretically secure. Any K-1 shares reveal zero information about the secret, even with unlimited computing power. Quantum computers cannot break XorIDA.

### Security Mode Description (Structured)

Get human-readable descriptions of security modes in multiple formats:

```typescript
import { describeSecurityModeStructured } from '@private.me/xbind';

// Describe a split-channel security mode
const mode = { type: 'split', shares: 3, threshold: 2 };
const description = describeSecurityModeStructured(mode);

// Single-line format (for UI labels)
console.log(description.formats.singleline); // "2-of-3 XorIDA"

// Multi-line format (for detailed explanations)
console.log(description.formats.multiline);
// Output:
// Security Mode: 2-of-3 XorIDA Split-Channel
// Shares: 3 total, 2 required to reconstruct
// Information-theoretic security (quantum-resistant)

// Markdown format (for documentation)
console.log(description.formats.markdown);
// Output:
// **Security Mode:** 2-of-3 XorIDA Split-Channel
// - **Shares:** 3 total, 2 required to reconstruct
// - **Security:** Information-theoretic (quantum-resistant)
```

## Billing & Metering

xBind includes usage-based billing with automated milestone notifications:

- **Free Tier:** Generous monthly limits (no email verification required upfront)
- **Grace Buffer:** Additional operations available after email verification
- **Pro Tier:** Usage-based billing with unlimited operations
- **Monthly Reset:** 1st of each month at 00:00 UTC

See [pricing](../../docs/pricing-reference.md) for current rates and tier details.

### Milestone Notifications

Automated email notifications at usage thresholds with progress bars and CTAs for upgrades.

**Email verification:** Required at free tier limit to access grace buffer.

**Implementation:**
- Metering logic: `apps/server/src/customer-metering.ts`
- Milestone system: `apps/server/src/usage-milestone-notifications.ts`
- Tier pattern: See `docs/gold-package.md` section 7.6.5

## Gateway

Non-authoritative coordination for discovery, relay, push notifications, and state checkpoints. Cannot forge identity or decide trust. See [Gateway Architecture](./docs/gateway-architecture.md).

## Connection Models

xBind provides four connection models for entity-to-entity authentication: Invite Code (email-based onboarding), QR Code (physical proximity pairing), Trust Registry (pre-authorized enterprise), and Peer Discovery (mDNS local network). All use cryptographic DIDs.

| Model | Security | UX | Best For |
|-------|----------|-----|----------|
| Invite Code | Single-use, 24h TTL | 6-char code | Customer onboarding |
| QR Code | Physical proximity, 60s TTL | Scan & tap | Mobile/desktop pairing |
| Trust Registry | Admin pre-auth, scoped | Zero (automated) | Enterprise/CI/CD |
| Peer Discovery | LAN proximity, user confirm | Scan & confirm | IoT devices, offline |

See [Entity-to-Entity Connection UX Guide](../../docs/ENTITY-TO-ENTITY-CONNECTION-UX.md) for implementation patterns and code examples.

## Configuration

### Basic Setup

```typescript
import { HttpTrustRegistry } from '@private.me/xbind';

// Documentation example - use your actual gateway URL
const registry = new HttpTrustRegistry({
  baseUrl: 'https://gateway.private.me'
});
```

### Operational Excellence (Timeouts & Degradation)

**Timeouts with configurable per-operation controls:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { TimeoutConfig, withTimeout, createTimeoutController, isTimeoutError } from '@private.me/xbind';

// Create timeout configuration
const config = new TimeoutConfig({
  registry: 10000,   // 10 seconds for registry lookups
  gateway: 15000,    // 15 seconds for gateway operations
  transport: 30000,  // 30 seconds for transport/HTTP
  default: 30000     // 30 seconds fallback
});

// Wrap async operation with timeout (using mock operation that completes quickly)
const result = await withTimeout(
  async () => new Promise(resolve => setTimeout(() => resolve('Done'), 100)),
  5000,
  'API request'
);

console.log('Request completed within timeout:', result);
```
<!-- /RUNNABLE-EXAMPLE -->

**Timeout controller with AbortSignal:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { createTimeoutController, TimeoutError } from '@private.me/xbind';

const controller = createTimeoutController(5000, 'registry lookup');

try {
  const response = await fetch(url, { signal: controller.signal });
  controller.clear(); // Clear timeout on success
  console.log('Fetch succeeded');
} catch (error) {
  if (controller.didTimeout()) {
    console.error('Operation timed out after 5000ms');
  }
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Result-based timeout handling (no exceptions):**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { withTimeoutResult, isTimeoutError } from '@private.me/xbind';

const result = await withTimeoutResult(
  async () => performOperation(),
  5000,
  'database query'
);

if (result.ok) {
  console.log('Success:', result.value);
} else {
  console.error('Timeout error:', result.error);
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Operation timeout with category-based config:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { TimeoutConfig, createOperationTimeout } from '@private.me/xbind';

const config = new TimeoutConfig({ registry: 10000 });
const controller = createOperationTimeout(config, 'registry', 'lookup DID');

const response = await fetch(url, { signal: controller.signal });
controller.clear();
```
<!-- /RUNNABLE-EXAMPLE -->

**Environment-based timeout configuration:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { createTimeoutConfigFromEnv, globalTimeoutConfig } from '@private.me/xbind';

// Reads from environment variables:
// - XBIND_TIMEOUT_REGISTRY
// - XBIND_TIMEOUT_GATEWAY
// - XBIND_TIMEOUT_TRANSPORT
// - XBIND_TIMEOUT_DEFAULT

const config = createTimeoutConfigFromEnv();
console.log('Registry timeout:', config.getRegistry());
console.log('Gateway timeout:', config.getGateway());

// Use global default config
const defaultTimeout = globalTimeoutConfig.getDefault();
```
<!-- /RUNNABLE-EXAMPLE -->

**Graceful degradation with cache fallback:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { GracefulDegradationManager, registryLookupWithFallback } from '@private.me/xbind';

const manager = new GracefulDegradationManager({
  defaultTTL: 300000,    // 5 minutes cache TTL
  maxSize: 1000,         // Max 1000 cached entries
  allowStale: true,      // Use stale cache on failures
  maxStaleMs: 3600000    // 1 hour max staleness
});

// Lookup with cache fallback
const result = await registryLookupWithFallback(
  registry,
  'did:key:z6Mk...',
  { operationId: '123', qos: 'HIGH', type: 'registry:lookup' },
  manager
);

if (result.ok) {
  console.log('Public key:', result.value.publicKey);
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Service health tracking:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { GracefulDegradationManager } from '@private.me/xbind';

const manager = new GracefulDegradationManager();

// Record success
manager.recordSuccess('registry');

// Record failure
manager.recordFailure('registry', 'NETWORK_ERROR');

// Check health
const health = manager.getServiceHealth('registry');
console.log('Registry health:', health); // 'HEALTHY' | 'DEGRADED' | 'UNAVAILABLE'

// Get detailed status
const status = manager.getServiceStatus('registry');
console.log('Failure count:', status?.failureCount);
console.log('Last error:', status?.lastError);
```
<!-- /RUNNABLE-EXAMPLE -->

**Cache management:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { GracefulDegradationManager } from '@private.me/xbind';

const manager = new GracefulDegradationManager();

// Store in cache
manager.setCached('registry:did:key:z6Mk...', { publicKey: '...' }, 300000);

// Get from cache (QoS-aware)
const cached = manager.getCached('registry:did:key:z6Mk...', 'HIGH');

// Invalidate cache
manager.invalidate('registry:did:key:z6Mk...');

// Get cache statistics
const stats = manager.getCacheStats();
console.log('Cache size:', stats.size);
console.log('Max size:', stats.maxSize);
```
<!-- /RUNNABLE-EXAMPLE -->

**Transport fallback with retry:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { sendWithTransportFallback, GracefulDegradationManager } from '@private.me/xbind';

const manager = new GracefulDegradationManager();

const result = await sendWithTransportFallback(
  [primaryTransport, fallbackTransport],
  envelope,
  'did:key:recipient',
  { operationId: '456', qos: 'NORMAL', type: 'transport:send' },
  manager
);

if (!result.ok) {
  console.error('All transports failed:', result.error);
}
```
<!-- /RUNNABLE-EXAMPLE -->

### Advanced Configuration Options

#### Identity Management

**`identity` - Pre-existing Identity (Persistent Agents)**

Provide an existing AgentIdentity for persistent agents that survive restarts.

```typescript
import { Agent, identityFromSeed } from '@private.me/xbind';

// Generate identity once, save seed
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error(identityResult.error.message);

const seed = identityResult.value.seed;
// Store seed securely (keychain, HSM, etc.)

// Later: Restore agent from seed
const identityRestoreResult = await identityFromSeed(Buffer.from(seed, 'hex'));
if (!identityRestoreResult.ok) throw new Error(identityRestoreResult.error.message);

const agent = await Agent.create({
  name: 'persistent-agent',
  identity: identityRestoreResult.value  // Reuse same DID across restarts
});
```

**`identityTTL` - Auto-Cleanup for Ephemeral Agents**

Set automatic cleanup time for short-lived agents (milliseconds).

```typescript
const agent = await Agent.create({
  name: 'temp-agent',
  identityTTL: 3600000  // Auto-cleanup after 1 hour
});
```

#### Security Options

**`nonceStore` - Replay Attack Prevention**

Configure custom nonce storage for distributed deployments.

```typescript
import { Agent, RedisNonceStore } from '@private.me/xbind';

const agent = await Agent.create({
  name: 'distributed-agent',
  nonceStore: new RedisNonceStore({
    client: redisClient,
    ttl: 300000  // 5 minute nonce validity
  })
});
```

**`scopes` - Authorization Scopes**

Restrict which message scopes this agent can receive.

```typescript
const agent = await Agent.create({
  name: 'scoped-receiver',
  scopes: ['messages', 'notifications']  // Only accept these scopes
});
```

**`timestampWindowMs` - Timestamp Validation**

Configure acceptable clock skew between sender and receiver.

```typescript
const agent = await Agent.create({
  name: 'strict-timing',
  timestampWindowMs: 60000  // Accept messages within ±1 minute
});
```

**`securityPolicy` - Enterprise Security Rules**

Apply custom security policies for enterprise deployments.

```typescript
import { Agent, DefaultSecurityPolicy } from '@private.me/xbind';

const customPolicy = new DefaultSecurityPolicy({
  requireEncryption: true,
  allowedDomains: ['*.private.me', '*.company.com']
});

const agent = await Agent.create({
  name: 'enterprise-agent',
  securityPolicy: customPolicy
});
```

**Security Mode Types**

Security policies use structured types to describe security modes (input) and their descriptions (output).

**`SecurityMode` (Input Type)**

Represents the security mode selected by the policy for a given action.

```typescript
type SecurityMode =
  | { readonly type: 'standard' }
  | { readonly type: 'split'; readonly shares: number; readonly threshold: number }
  | { readonly type: 'xchange' };
```

**`SecurityModeDescription` (Output Type)**

Structured description with multiple format representations for display, logging, APIs, and documentation.

```typescript
interface SecurityModeDescription {
  /** Security mode type. */
  readonly type: 'standard' | 'split' | 'xchange';
  /** Security level classification. */
  readonly level: 'standard' | 'high' | 'critical' | 'performance';
  /** Share configuration (only for split mode). */
  readonly shares?: { readonly total: number; readonly threshold: number };
  /** Multiple format representations. */
  readonly formats: {
    readonly multiline: string;
    readonly singleline: string;
    readonly json: string;
    readonly markdown: string;
  };
}
```

**Usage Example**

```typescript
import { describeSecurityModeStructured, type SecurityMode } from '@private.me/xbind';

// Input: Security mode
const mode: SecurityMode = { type: 'split', shares: 3, threshold: 2 };

// Output: Structured description
const description = describeSecurityModeStructured(mode);

console.log(description.type);     // 'split'
console.log(description.level);    // 'high'
console.log(description.shares);   // { total: 3, threshold: 2 }

// Format representations
console.log(description.formats.singleline);
// "high | split | 2-of-3"

console.log(description.formats.multiline);
// "Security Level: High
//  Mode: Split-channel (XorIDA)
//  Shares: 3 total, 2 required"

console.log(description.formats.json);
// '{"type":"split","level":"high","shares":{"total":3,"threshold":2}}'

console.log(description.formats.markdown);
// "**Security Level:** High
//
//  **Mode:** Split-channel (XorIDA)
//
//  **Shares:** 3 total, 2 required"
```

**`registry` - Trust Registry Configuration**

Configure how agents discover and verify peer identities. Three implementations available.

```typescript
import { Agent, HttpTrustRegistry, FileTrustRegistry, MemoryTrustRegistry } from '@private.me/xbind';

// Production: HTTP-backed registry (default)
const httpAgent = await Agent.create({
  name: 'production-agent',
  registry: new HttpTrustRegistry('https://private.me/registry')
  // Or shorthand: registry: 'https://private.me/registry'
});

// Development: In-memory registry (ephemeral)
const devAgent = await Agent.create({
  name: 'dev-agent',
  registry: new MemoryTrustRegistry()  // No persistence, auto-cleanup
});

// Enterprise: File-backed registry (local persistence)
const fileAgent = await Agent.create({
  name: 'enterprise-agent',
  registry: new FileTrustRegistry('./registry.jsonl')  // Append-only log
});
```

**When to use each:**
- `HttpTrustRegistry`: Production deployments, multi-agent coordination, DID resolution across networks
- `MemoryTrustRegistry`: Testing, development, short-lived agents that don't need persistence
- `FileTrustRegistry`: Enterprise deployments, local persistence, offline-capable systems

**`transport` - Multi-Transport Setup**

Configure message delivery channels. Single transport for simple deployments, multiple transports for redundancy or split-channel security.

```typescript
import { Agent, HttpsTransportAdapter, RetryTransportAdapter } from '@private.me/xbind';

// Single transport (default)
const simpleAgent = await Agent.create({
  name: 'simple-agent',
  transport: new HttpsTransportAdapter('https://private.me/relay')
});

// Retry wrapper for unreliable networks
const reliableTransport = new RetryTransportAdapter(
  new HttpsTransportAdapter('https://private.me/relay'),
  {
    maxRetries: 3,        // 3 retry attempts
    baseDelayMs: 1000,    // 1s base delay
    maxJitterMs: 200      // ±200ms jitter
  }
);

const reliableAgent = await Agent.create({
  name: 'reliable-agent',
  transport: reliableTransport
});

// Multi-transport for split-channel (advanced)
const multiAgent = await Agent.create({
  name: 'split-channel-agent',
  transport: [
    new HttpsTransportAdapter('https://relay1.private.me'),
    new HttpsTransportAdapter('https://relay2.private.me'),
    new HttpsTransportAdapter('https://relay3.private.me')
  ]
});
// Each XorIDA share routes to transport[shareIndex % transports.length]
// Share 0 → relay1, Share 1 → relay2, Share 2 → relay3
```

**When to use:**
- Single transport: Most use cases, simple deployments
- `RetryTransportAdapter`: Mobile networks, unreliable connections, push notification delivery
- Multi-transport: Critical security scenarios requiring channel separation (prevents correlation attacks)

**`postQuantumSig` - Post-Quantum Signatures**

Enable ML-DSA-65 (FIPS 204) post-quantum signatures for future-proof authentication.

```typescript
const quantumAgent = await Agent.create({
  name: 'quantum-safe-agent',
  postQuantumSig: true  // Default: false
});

// Sends v3 envelopes with hybrid signatures:
// - Ed25519 (classical, 128-bit security)
// - ML-DSA-65 (post-quantum, NIST Level 3)
```

**When to enable:**
- Long-term data protection (10+ year confidentiality requirements)
- Compliance with post-quantum cryptography mandates
- High-security government/defense applications
- Preparing for quantum computing threats

**Trade-offs:**
- Signature size: +2.5KB per message (Ed25519: 64 bytes → ML-DSA-65: 2,701 bytes)
- Performance: ~10% slower signing/verification
- Compatibility: Requires peers to support v3 envelopes (xBind v0.2.0+)

**Default: `false`** (most applications don't need post-quantum signatures yet)

**`backupConfig` - Key Backup Configuration**

Configure XorIDA threshold sharing for key backup and recovery.

```typescript
import { Agent, DEFAULT_BACKUP_CONFIG } from '@private.me/xbind';

// Default: 2-of-3 (any 2 shares recover key)
const defaultAgent = await Agent.create({
  name: 'default-backup',
  backupConfig: DEFAULT_BACKUP_CONFIG  // threshold: 2, totalShares: 3
});

// High security: 3-of-5 (lose 2 shares, still recover)
const secureAgent = await Agent.create({
  name: 'secure-backup',
  backupConfig: {
    threshold: 3,      // Need 3 shares to reconstruct
    totalShares: 5     // Generate 5 shares (can lose 2)
  }
});

// Minimal: 2-of-2 (both shares required)
const minimalAgent = await Agent.create({
  name: 'minimal-backup',
  backupConfig: {
    threshold: 2,
    totalShares: 2  // No fault tolerance (both required)
  }
});
```

**When to use each:**
- `2-of-3` (default): Balance security and convenience, tolerate 1 lost share
- `3-of-5`: High-security scenarios, tolerate 2 lost shares, enterprise deployments
- `2-of-2`: Minimal overhead, no fault tolerance, testing only

**Information-theoretic security:** Each share reveals zero information about the key. Even with `threshold - 1` shares, an attacker gains no information.

**`name` - Agent Naming Best Practices**

Agent names are human-readable identifiers used in logs, debugging, and trust registry lookups.

```typescript
// Good: Descriptive, kebab-case, unique per role
const agent1 = await Agent.create({ name: 'email-service-agent' });
const agent2 = await Agent.create({ name: 'payment-processor' });
const agent3 = await Agent.create({ name: 'backup-validator' });

// Avoid: Generic names that don't identify purpose
const bad1 = await Agent.create({ name: 'agent1' });  // Not descriptive
const bad2 = await Agent.create({ name: 'test' });    // Too generic
```

**Conventions:**
- Use kebab-case for consistency (`email-service`, not `EmailService` or `email_service`)
- Include role/purpose (`payment-processor`, not `agent42`)
- Keep under 50 characters for logging compatibility
- Avoid PII or sensitive data in names (logged in plaintext)

**Name vs DID:**
- **Name**: Human-readable, mutable, used for debugging/logs
- **DID**: Cryptographic identifier, immutable, used for authentication

**`xchange` - Performance Mode**

Enable Xchange mode for 180× faster message delivery with single-layer information-theoretic security.

```typescript
const performanceAgent = await Agent.create({
  name: 'performance-agent',
  xchange: true  // Default: false
});

// Sending with Xchange mode
await performanceAgent.send({
  to: recipientDid,
  payload: { action: 'transfer', amount: 100 },
  scope: 'payments'
  // Automatically uses v4 envelopes (XorIDA split + Ed25519, no KEM)
});
```

**When to enable:**
- High-throughput systems (>1000 messages/second)
- Latency-sensitive applications (real-time chat, gaming)
- Bandwidth-constrained networks (mobile, IoT)
- Internal microservice communication (trusted network)

**Security model:**
- Single layer: Information-theoretic XorIDA split (provably secure)
- Authentication: Ed25519 signatures (128-bit security)
- No KEM: Skips hybrid key encapsulation (saves ~180× overhead)

**Trade-offs:**
- Performance: ~180× faster than v3 split-channel
- Security: Single IT layer vs triple-layer (IT + classical + post-quantum)
- Use case: Trusted networks where triple-layer is overkill

**Default: `false`** (prioritize maximum security over performance)

## Section 2: Trust & Key Agreement

### Trust & Key Agreement

**Generate ephemeral X25519 key pair:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { generateEphemeralKeyPair } from '@private.me/xbind';

const ephemeral = await generateEphemeralKeyPair();
if (!ephemeral.ok) {
  throw new Error(`Key generation failed: ${ephemeral.error}`);
}

console.log('Ephemeral public key (32 bytes):', ephemeral.value.rawPublicKey);
// Use ephemeral.value.privateKey for ECDH, then discard
```
<!-- /RUNNABLE-EXAMPLE -->

**Import X25519 public key:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { importX25519PublicKey } from '@private.me/xbind';

const rawPublicKey = new Uint8Array(32); // From recipient's identity
const result = await importX25519PublicKey(rawPublicKey);

if (!result.ok) {
  throw new Error(`Import failed: ${result.error}`);
}

const publicKey = result.value; // CryptoKey for ECDH
```
<!-- /RUNNABLE-EXAMPLE -->

**Derive shared key via ECDH:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { deriveSharedKeyECDH, generateEphemeralKeyPair, importX25519PublicKey } from '@private.me/xbind';

// Generate ephemeral key
const ephemeral = await generateEphemeralKeyPair();
if (!ephemeral.ok) throw new Error(ephemeral.error);

// Import recipient's public key
const recipientKey = await importX25519PublicKey(recipientPubKeyBytes);
if (!recipientKey.ok) throw new Error(recipientKey.error);

// Derive shared AES-256-GCM key
const shared = await deriveSharedKeyECDH(
  ephemeral.value.privateKey,
  recipientKey.value
);

if (shared.ok) {
  console.log('Shared key derived for AES-256-GCM');
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Sender-side key agreement:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { senderKeyAgreement, importX25519PublicKey, generateIdentity } from '@private.me/xbind';

// Generate recipient identity for testing (in production, get from registry)
const recipientResult = await generateIdentity();
if (!recipientResult.ok) throw new Error(recipientResult.error);
const recipientPubKeyRaw = recipientResult.value.rawX25519PublicKey;

// Import recipient's X25519 public key
const recipientPubKey = await importX25519PublicKey(recipientPubKeyRaw);
if (!recipientPubKey.ok) throw new Error(recipientPubKey.error);

// Perform key agreement
const agreement = await senderKeyAgreement(recipientPubKey.value);
if (!agreement.ok) throw new Error(agreement.error);

// Use shared key for encryption
const { sharedKey, ephemeralPublicKey } = agreement.value;
console.log('Ephemeral public key to include in envelope:', ephemeralPublicKey);
```
<!-- /RUNNABLE-EXAMPLE -->

**Receiver-side key agreement:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { receiverKeyAgreement } from '@private.me/xbind';

// Extract ephemeral public key from envelope
const senderEphemeralPubRaw = envelope.ephemeralPublicKey;

// Derive shared key using receiver's static private key
const shared = await receiverKeyAgreement(
  receiverPrivateKey,
  senderEphemeralPubRaw
);

if (shared.ok) {
  const sharedKey = shared.value;
  // Use sharedKey for decryption
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Hybrid key agreement (X25519 + ML-KEM-768) - Sender:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { senderHybridKeyAgreement } from '@private.me/xbind';

// Recipient's keys from registry
const recipientX25519Pub = recipientEntry.x25519PublicKey; // CryptoKey
const recipientMlKemPub = recipientEntry.mlKemPublicKey;   // 1184 bytes

const result = await senderHybridKeyAgreement(
  recipientX25519Pub,
  recipientMlKemPub
);

if (!result.ok) {
  throw new Error(`Hybrid key agreement failed: ${result.error}`);
}

const { sharedKey, ephemeralPublicKey, kemCiphertext } = result.value;
// Include ephemeralPublicKey (32B) and kemCiphertext (1088B) in envelope
```
<!-- /RUNNABLE-EXAMPLE -->

**Hybrid key agreement (X25519 + ML-KEM-768) - Receiver:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { receiverHybridKeyAgreement } from '@private.me/xbind';

// Receiver's keys
const x25519PrivateKey = identity.x25519PrivateKey;     // CryptoKey
const x25519PublicKeyRaw = identity.x25519PublicKey;    // 32 bytes
const mlKemSecretKey = identity.mlKemSecretKey;         // 2400 bytes
const mlKemPublicKey = identity.mlKemPublicKey;         // 1184 bytes

// Envelope data
const ephPubRaw = envelope.ephemeralPublicKey;          // 32 bytes
const kemCiphertext = envelope.kemCiphertext;           // 1088 bytes

const result = await receiverHybridKeyAgreement(
  x25519PrivateKey,
  x25519PublicKeyRaw,
  ephPubRaw,
  kemCiphertext,
  mlKemSecretKey,
  mlKemPublicKey
);

if (result.ok) {
  const sharedKey = result.value; // Same AES-256-GCM key as sender
}
```
<!-- /RUNNABLE-EXAMPLE -->

**File-based trust registry:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { FileTrustRegistry } from '@private.me/xbind';

const registry = new FileTrustRegistry({
  path: '/opt/corp/trust.jsonl'
});

// Register agent
await registry.register({
  did: 'did:key:z6Mk...',
  publicKey: publicKeyBytes,
  name: 'Corporate Gateway',
  scopes: ['billing', 'auth'],
  x25519PublicKey: x25519PublicKey,
  mlKemPublicKey: mlKemPublicKey,
  mlDsaPublicKey: mlDsaPublicKey,
  xchange: true,
  receiveScopes: ['billing', 'auth'],
  sdkVersion: '3.0.4',
  minEnvelopeVersion: 1,
  maxEnvelopeVersion: 4
});

// Resolve DID
const result = await registry.resolve('did:key:z6Mk...');
if (result.ok) {
  console.log('Public key:', result.value);
}

// Cleanup expired entries
const removed = await registry.cleanup();
console.log('Removed entries:', removed);
```
<!-- /RUNNABLE-EXAMPLE -->

**Enterprise trust registry factory:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { createEnterpriseTrustRegistry } from '@private.me/xbind';

const registry = await createEnterpriseTrustRegistry({
  storage: 'file',
  path: '/opt/corp/trust.jsonl',
  preload: [
    {
      did: 'did:web:corp.example.com',
      publicKey: corporateGatewayPubKey,
      name: 'Corporate Gateway',
      scopes: ['billing', 'auth', 'payments'],
      x25519PublicKey: corporateX25519Key,
      mlKemPublicKey: corporateMlKemKey
    }
  ]
});

console.log('Enterprise registry initialized with pre-loaded entries');
```
<!-- /RUNNABLE-EXAMPLE -->

**Message stream with async iteration:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { MessageStream, collectMessages } from '@private.me/xbind';

// Subscribe to all messages from Alice
for await (const message of agent.subscribe({ from: 'did:key:alice' })) {
  console.log('Received:', message.payload);
  if (message.scope === 'urgent') break; // Early termination
}

// Collect batch of messages with timeout
const messages = await collectMessages(agent, {
  from: 'did:key:alice',
  limit: 10,
  timeout: 5000
});

console.log('Collected messages:', messages.length);
```
<!-- /RUNNABLE-EXAMPLE -->

**Parse agent errors:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { parseAgentError, isXBindError } from '@private.me/xbind';

try {
  await agent.send({ to: recipientDid, payload: data });
} catch (error) {
  if (isXBindError(error)) {
    console.error('Code:', error.code);
    console.error('Sub-code:', error.subCode);
    console.error('Docs:', error.docUrl);
  }
}
```
<!-- /RUNNABLE-EXAMPLE -->

---

## Summary

**Batch 4 Examples (13 exports - Operational Excellence):**
1. TimeoutConfig - Timeout configuration manager
2. OperationTimeoutController - Per-operation timeout control
3. createTimeoutController - Create timeout controller
4. withTimeout - Wrap function with timeout
5. withTimeoutResult - Wrap with Result timeout
6. createOperationTimeoutSignal - Create AbortSignal
7. createOperationTimeout - Create timeout config
8. isTimeoutError - Check timeout error
9. getTimeoutFromError - Extract timeout
10. createTimeoutConfigFromEnv - Create from env
11. globalTimeoutConfig - Global config
12. GracefulDegradationManager - Graceful degradation
13. registryLookupWithFallback - Registry with fallback

**Batch 5 Examples (15 exports - Trust & Discovery):**
1. sendWithTransportFallback - Transport fallback
2. enhanceError - Error enhancement (not shown - internal)
3. FileTrustRegistry - File-based registry
4. createEnterpriseTrustRegistry - Enterprise factory
5. generateEphemeralKeyPair - Generate X25519 pair
6. importX25519PublicKey - Import X25519 key
7. deriveSharedKeyECDH - ECDH derivation
8. senderKeyAgreement - Sender key agreement
9. receiverKeyAgreement - Receiver key agreement
10. combineSharedSecrets - Combine secrets (not shown - internal)
11. senderHybridKeyAgreement - Hybrid sender
12. receiverHybridKeyAgreement - Hybrid receiver
13. parseAgentError - Parse errors
14. MessageStream - Async iteration
15. collectMessages - Batch collect

**Total: 28 new code examples for Batch 4 & 5 exports**
### Advanced Features

Checkpoints, sequence numbers, subscription proofs, XorIDA configuration, key backup (2-of-3 default), DID succession. See [Configuration Guide](./docs/configuration.md) and [Examples](./docs/examples.md).

## Type Safety

xbind returns `Result<T, E>` types for type-safe error handling.

<!-- SNIPPET -->
```typescript
import { call, type CallResult } from '@private.me/xbind';

interface User { id: number; name: string; email: string; }

const result: CallResult<User> = await call('getUser', { id: 123 });
if (result.ok) {
  console.log(result.value.data.name);
  console.log(result.value.audit.signature);
} else {
  console.error(result.error.message);
}
```
<!-- /SNIPPET -->

Error types: `ConnectionError`, `AuthenticationError`, `ValidationError`, `RateLimitError`, `ServerError`

## Documentation

- **[API Reference](./docs/api-reference.md)** — Complete API documentation
- **[Configuration Guide](./docs/configuration.md)** — All configuration options
- **[Examples](./docs/examples.md)** — Common usage patterns
- **[Troubleshooting](./docs/troubleshooting.md)** — Common issues and solutions
- **[Advanced Guide](./docs/advanced.md)** — Multi-backend failover, retry strategies
- **[White Paper](https://private.me/docs/xbind.html)** — Architecture and design
- **[AGENTS.md](./AGENTS.md)** — AI agent patterns
- **[SECURITY.md](./SECURITY.md)** — Threat model

## Testing

**1,245/1,245 tests passing** — Comprehensive coverage including post-quantum cryptography (ML-KEM-768, ML-DSA-65), hybrid signature verification, DID generation, message encryption, transport layer, multi-agent coordination, error handling, Python SDK bindings, and Full Control protection.

```bash
pnpm test                # All tests
pnpm test:coverage       # Coverage report
pnpm test:watch          # Watch mode
```

### Testing with LoopbackTransport

For unit testing and local development, use `LoopbackTransport` to simulate agent communication without network calls:

```typescript
import { Agent, LoopbackTransport } from '@private.me/xbind';

// Create a shared in-memory transport
const transport = new LoopbackTransport();

// Create two agents using the same transport
const alice = await Agent.create({
  name: 'alice',
  transport
});

const bob = await Agent.create({
  name: 'bob',
  transport
});

// Messages are delivered instantly in-memory
const result = await alice.send({
  to: bob.did,
  payload: { test: true }
});

if (result.ok) {
  console.log('Message delivered via loopback transport');
}

// Bob can receive messages from Alice
const envelope = // ... received via transport callback
const received = await bob.receive(envelope);
```

**Use cases:**
- Unit testing agent communication without external services
- Local development without network dependencies
- CI/CD pipelines that need fast, deterministic tests
- Integration testing of multi-agent workflows

## Error Reference

xBind returns detailed error codes via `Result<T,E>` pattern. All errors follow the format `CATEGORY:SUBCODE` for precise diagnostics.

### Common Errors

**ENVELOPE_FAILED Family** - Message envelope creation/processing failures:

- `ENVELOPE_FAILED:SPLIT` - Split-channel requires 3+ transports. **Fix:** Add more transports to your agent configuration OR disable split-channel (use `security:'standard'` instead of `'high'`/`'critical'`)
- `ENVELOPE_FAILED:SIGNATURE` - Message signing failed (corrupted keys or invalid DID)
- `ENVELOPE_FAILED:ENCRYPTION` - Key agreement or encryption failed

**IDENTITY_FAILED Family** - Agent identity/key issues:

- `IDENTITY_FAILED:KEYGEN` - Cryptographic key generation failed
- `IDENTITY_FAILED:VAULT_STORE` - Share 2 (Vault Store) unavailable (legacy, deprecated in v3.1.1). **Fix:** Update to v3.1.1+ which includes bundled crypto

**Network/Transport Errors:**

- `RECIPIENT_UNREACHABLE` - Unable to deliver message to recipient DID
- `TIMEOUT` - Network operation exceeded timeout threshold (default: 10s)
- `NETWORK_ERROR` - General network failure (DNS, connection refused, etc.)
- `HTTPS_REQUIRED` - Non-loopback HTTP URL rejected (security policy). **Fix:** Use HTTPS URLs for production OR use loopback addresses (127.0.0.1, localhost, ::1) for development

**Registry Errors:**

- `REGISTRATION_FAILED:ALREADY_REGISTERED` - DID already exists in trust registry
- `REGISTRATION_FAILED:NETWORK_ERROR` - Registry unreachable or network failure
- `RESOLVE_FAILED:NOT_FOUND` - Recipient DID not found in trust registry

### Error Handling Example

```typescript
const result = await agent.send({
  to: recipientDid,
  security: 'high',  // Requires 3+ transports
  payload: { message: 'Hello' }
});

if (!result.ok) {
  switch (result.error) {
    case 'ENVELOPE_FAILED:SPLIT':
      console.error('Need 3+ transports for high security. Add more transports or use security:"standard"');
      break;
    case 'IDENTITY_FAILED:VAULT_STORE':
      console.error('Vault Store unavailable. Check billing or set FULL_CONTROL_MASTER_KEY');
      break;
    case 'RECIPIENT_UNREACHABLE':
      console.error('Cannot reach recipient. Check DID and network connectivity');
      break;
    default:
      console.error('Send failed:', result.error);
  }
}
```

### Structured Error Formatting

For user-facing error messages, use `formatErrorStructured` (alias for `createDetailedError`):

```typescript
import { formatErrorStructured } from '@private.me/xbind';

const result = await agent.send({ to: recipientDid, payload: data });

if (!result.ok) {
  const structuredError = formatErrorStructured({
    code: result.error,
    message: 'Failed to send message',
    context: { recipientDid, attemptedAt: new Date().toISOString() }
  });

  console.error(structuredError);
  // Output: { code: 'RECIPIENT_UNREACHABLE', message: '...', context: {...}, timestamp: '...' }
}
```

### Debugging Tips

1. **Split-channel errors:** Ensure `agent.transports.length >= 3` before using `security:'high'` or `'critical'`
2. **Vault Store errors:** Check `.env` for `FULL_CONTROL_MASTER_KEY` (offline mode) or verify billing status (online mode)
3. **Network errors:** Enable debug logging with `DEBUG=xbind:* npm start`
4. **Type safety:** Use TypeScript for autocomplete on all error codes

## Additional Agent Methods

### subscribeTrustEvents()

Subscribe to trust registry events (registrations, revocations, key rotations).

```typescript
const unsubscribe = agent.subscribeTrustEvents((event) => {
  if (event.type === 'register') {
    console.log(`New agent registered: ${event.did}`);
  } else if (event.type === 'revoke') {
    console.log(`DID revoked: ${event.did}`);
  } else if (event.type === 'succession') {
    console.log(`Key rotated: ${event.did}`);
  }
});

// Later, stop watching
unsubscribe();
```

**Note:** Requires a trust registry with push support enabled (e.g., `HttpTrustRegistry` with `enablePush: true`). For registries without push support, returns a no-op unsubscribe function.

### rotateDid()

Rotate agent DID (key rotation with succession proof).

Creates a new identity, generates succession announcement with dual signatures, registers the new identity, and updates the agent's current identity.

```typescript
const agent = await Agent.create({
  name: 'Corporate Gateway',
  registry: myRegistry,
  transports: [loopback]
});

const result = await agent.rotateDid({ reason: 'scheduled rotation' });

if (!result.ok) {
  console.error('Rotation failed:', result.error);
} else {
  console.log('DID rotated successfully. New DID:', agent.did);
}
```

**Returns:** `Result<void, AgentError>`

**Errors:**
- `IDENTITY_GENERATION_FAILED` - Failed to generate new identity
- `ROTATION_FAILED:MISSING_MLDSA_KEYS` - ML-DSA keys required for succession proof
- `ROTATION_FAILED:SUCCESSION_PROOF` - Failed to create succession announcement
- `ROTATION_FAILED:REGISTRATION` - Failed to register new DID with trust registry

### verifyReceipt()

Verify a message receipt signature.

```typescript
const receipt = {
  senderDid: 'did:key:z6Mk...',
  signature: 'base64-encoded-signature',
  payload: 'message-content'
};

const result = await agent.verifyReceipt(receipt);

if (result.ok && result.value) {
  console.log('Receipt is valid');
} else {
  console.error('Receipt verification failed');
}
```

**Returns:** `Result<boolean, AgentError>`

**Note:** Receipt functionality is planned but not yet fully implemented. This method validates a receipt's cryptographic signature using Ed25519.

## Full Control IP Protection

xBind uses **Full Control** (2-share XorIDA) to protect proprietary cryptographic algorithms while maintaining a seamless developer experience.

### Architecture: Store Front + Vault Store

**Store Front (npm registry):**
- Contains wrapper code, types, and non-proprietary utilities
- Includes Share 1 (`share1.dat`) — useless alone, safe to distribute publicly
- Installed via standard `npm install @private.me/xbind`

**Vault Store (private.me gateway):**
- Contains Share 2 (encrypted, payment-gated)
- Delivered via `/api/vault-store/crypto` endpoint
- Requires xBind DID authentication + usage quota verification
- AES-256-GCM encrypted with `FULL_CONTROL_MASTER_KEY`

When combined, Share 1 + Share 2 reconstruct the complete XorIDA algorithm at runtime.

### Usage-Based Access Model

**IMPORTANT:** Full Control uses **usage-based metering**, NOT feature-gating.

**All tiers** can access the Vault Store (crypto algorithms + Share 2) **within their usage quota**:

- **Free Tier:** 100,000 operations/month
  - Grace buffer: 120,000 hard cap (includes 20% overage)
  - Email verification required
  - Vault access included (no additional payment needed)
  - At 120K ops: 402 Quota Exceeded → Upgrade prompt

- **Pro Tier:** Unlimited operations
  - Usage-based billing (after first 100K free)
  - No quota checks
  - Vault access unlimited
  - Example: 400K ops calculated based on current rates (see pricing link)

- **VIP Tier:** Custom limits per account
  - Bronze: 200K, Silver: 500K, Gold: 1M, Platinum: Unlimited
  - Vault access within custom quota

### Upgrade to Pro

If you exceed the free tier quota, upgrade to Pro for unlimited operations:

```bash
# Visit the upgrade page
https://private.me/subscribe?product=xbind&tier=pro

# Or upgrade programmatically via xBind API
const result = await agent.send({
  to: 'did:key:z6MkBillingService...',
  payload: { action: 'upgradeTier', tier: 'pro' }
});
```

### 4-Layer Security

1. **DID Authentication:** Ed25519 signature verification (cryptographic proof of identity)
2. **Usage Quota Verification:** Monthly operation count checked against tier limits
3. **Rate Limiting:** Free: 100 req/hour, Pro: 1000 req/hour, VIP: 5000 req/hour
4. **Audit Logging:** Every vault access logged with DID, timestamp, IP, and success status

### Runtime Flow

```typescript
// 1. Install package (includes Share 1)
// npm install @private.me/xbind

// 2. Create agent (auto-fetches Share 2 on first use)
const agent = await Agent.create(seed);

// 3. Vault Store loader detects missing crypto
// 4. POST /api/vault-store/crypto
//    - Auth: DID signature
//    - Verify: Usage quota (Free: <120K, Pro: unlimited)
//    - Response: { cryptoBundle, share2, version }

// 5. Load crypto dynamically (Share 1 + Share 2 = complete algorithm)
// 6. Cache in memory (session-only, 7-day expiration)
// 7. Use reconstructed XorIDA algorithm

await agent.send({
  to: recipientDid,
  payload: { amount: 100, currency: 'BTC' },
  security: 'high' // Uses XorIDA (2-of-3 threshold)
});
```

### Why This Matters

**Without Full Control:**
- Complete XorIDA algorithm exposed in npm tarball
- Anyone can download and use without payment
- Patent protection (US 11,972,000) defeated
- Revenue model bypassed

**With Full Control:**
- Share 1 alone is mathematically useless (information-theoretic security)
- Share 2 requires usage-based quota verification
- Patent-protected algorithms delivered only to paying users (or within free tier quota)
- Reverse engineering requires breaking AES-256-GCM encryption

**Revenue Protection:**
- Free tier: 100K ops/month (generous for experimentation)
- Pro tier: Usage-based billing scales with value delivered
- DeploymentID tracking prevents quota reset attacks (DID rotation doesn't bypass limits)

See [IP Protection Documentation](./docs/ip-protection.md) for complete technical details.

## Data Collection

xBind makes network connections for three purposes, each with different security and privacy characteristics:

### 1. Local Network Discovery (Peer Discovery Model Only)

**When:** Only when using the Peer Discovery connection model for IoT devices and offline pairing.

**What:** Sends mDNS (multicast DNS) broadcast messages on your local network to discover nearby xBind-compatible devices.

**Data transmitted:**
- Device DID (cryptographic identity, public key)
- Device type identifier
- Service announcement (port, protocol version)

**Security:** Broadcast messages are visible to all devices on the local network. Does NOT transmit private keys, message content, or personal data. Recipients cannot impersonate your device without the private key.

**Privacy:** Other connection models (Invite Code, QR Code, Trust Registry) do NOT use local network discovery.

### 2. Gateway Communication (gateway.private.me)

**When:** During message delivery, Share 2 retrieval, and connection establishment.

**What:** Encrypted communication with gateway.private.me for coordination and IP protection.

**Data transmitted:**
- **Share 2 delivery:** Encrypted share required for Full Control vault store reconstruction (payment-gated)
- **Usage metrics:** Operation counts, error codes, latency (anonymized, no message content)
- **Connection metadata:** DID identifiers, sequence numbers, checkpoints (for message ordering)
- **Push notifications:** Delivery receipts, presence signals (encrypted, no content)

**Security:** All communication uses TLS 1.3. Gateway is non-authoritative and cannot forge identity or decrypt messages. See [Gateway Architecture](./docs/gateway-architecture.md).

**Privacy:** No message content, API credentials, or plaintext data transmitted. DIDs are pseudonymous identifiers.

### 3. Full Control Share Retrieval

**When:** During initial setup and algorithm reconstruction.

**What:** Downloads Share 2 (Vault Store) from gateway.private.me after payment verification.

**Data transmitted:**
- Payment proof (Stripe subscription ID)
- xBind authentication token (cryptographic proof of identity)
- Package identifier and version

**Security:** Share 2 is AES-256-GCM encrypted with FULL_CONTROL_MASTER_KEY. Without both Share 1 (npm) and Share 2 (gateway), the algorithm cannot execute.

**Privacy:** Payment verification uses Stripe (see [Stripe Privacy](https://stripe.com/privacy)). xBind does not store credit card data.

### Data Retention

- **Usage metrics:** 90 days (aggregated, anonymized)
- **Connection metadata:** 30 days (sequence numbers, checkpoints)
- **Share 2 downloads:** Access logs retained per payment verification requirements

### Opt-Out

**Local network discovery:** Disable by not using Peer Discovery connection model.

**Gateway communication:** Required for message delivery. Self-hosted gateway option available for enterprise (contact contact@private.me).

**Usage metrics:** Cannot be disabled (required for billing and abuse prevention).

For complete privacy details, see [Privacy Policy](https://private.me/privacy).

## Legal

[Terms of Service](https://private.me/terms) • [Privacy Policy](https://private.me/privacy) • [License](./LICENSE.md)

## Export Control Notice

This package contains cryptographic software. Export restrictions may apply. Users are responsible for compliance with U.S. Export Administration Regulations (EAR) and jurisdiction-specific export control requirements.

---

**License:** Proprietary

---

**Questions?** [White paper](https://private.me/docs/xbind.html) • [npm](https://www.npmjs.com/package/@private.me/xbind) • contact@private.me

### Stream Processing Utilities

**Transform message streams with map/filter/take:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { mapStream, filterStream, takeStream, mergeStreams } from '@private.me/xbind';

// Map transform
const doubled = mapStream(messageStream, (msg) => ({
  ...msg,
  payload: msg.payload * 2
}));

// Filter messages
const urgent = filterStream(messageStream, (msg) => msg.scope === 'urgent');

// Take first N messages
const first10 = takeStream(messageStream, 10);

// Merge multiple streams
const combined = mergeStreams([streamA, streamB, streamC]);

for await (const message of combined) {
  console.log('Received from merged streams:', message);
}
```
<!-- /RUNNABLE-EXAMPLE -->

**Install async iterator support:**

<!-- RUNNABLE-EXAMPLE -->
```typescript
import { installAsyncIterators } from '@private.me/xbind';

// Enable async iterator methods on Agent
installAsyncIterators();

// Now you can use async iteration
for await (const message of agent.messages()) {
  console.log('Message received:', message.payload);
}
```
<!-- /RUNNABLE-EXAMPLE -->

