npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@private.me/xbind

v3.2.1

Published

Identity-based M2M authentication (Contains encryption - export restrictions apply)

Readme

@private.me/xbind

npm version dependencies tests license

Post-quantum cryptographic identity for agent-to-agent messaging. Zero runtime dependencies.

Build AI agents that communicate securely using ML-DSA-65 signatures, ML-KEM-768 + AES-256-GCM encryption, and information-theoretic split-channel delivery. 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.

Install

Node.js / TypeScript:

npm install @private.me/xbind

Python:

pip install private-me-xbind

Offline Ready: All cryptography vendored. Agent.quickstart() works fully offline.

Quick Start

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

// Create agent with defaults (works offline)
const agent = await Agent.quickstart({ name: 'my-agent' });

console.log('Agent DID:', agent.did);

// Send encrypted message
const result = await agent.send({
  to: 'did:key:z6Mk...',
  payload: { action: 'process', data: [1, 2, 3] },
  scope: 'test'
});

if (result.ok) {
  console.log('Sent:', result.value.envelopeId);
}

// Cleanup
agent.cleanup();

Production Setup:

For production with the Private.Me platform registry and relay, use Agent.create() (returns Result<Agent, Error>). Requires a registered account — run npx xbind init first to set up your identity and verify your email.

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

const result = await Agent.create({
  name: 'production-agent',
  scopes: ['read:data', 'write:logs'],
  registry: new HttpTrustRegistry({
    baseUrl: process.env.XBIND_REGISTRY_URL || 'https://private.me/aci/registry'
  }),
  transport: new HttpsTransportAdapter({
    baseUrl: process.env.XBIND_RELAY_URL || 'https://private.me/aci/relay'
  })
});

if (result.ok) {
  const agent = result.value;
  console.log('Agent DID:', agent.did);
  // ... use agent
  agent.cleanup();
} else {
  // Common errors: REGISTRATION_FAILED (no account), NETWORK_ERROR (offline)
  console.error('Failed to create agent:', result.error);
}

Local development — use loopback transport (no network required):

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

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

const result = await alice.send({
  to: bob.did,
  payload: { hello: 'world' },
  scope: 'test'
});

if (result.ok) {
  console.log('Sent:', result.value.envelopeId);
}

alice.cleanup();
bob.cleanup();

Key Features

Cryptographic Identity:

  • ML-DSA-65 signatures (NIST post-quantum standard)
  • ML-KEM-768 + AES-256-GCM hybrid encryption
  • Ed25519 + X25519 for backward compatibility
  • DID-based addressing (did:key:z6Mk...)

Split-Channel Security:

  • XorIDA threshold secret sharing (patent-protected)
  • Information-theoretic security (mathematically unbreakable)
  • No single transport has complete message

Transport Flexibility:

  • Loopback (in-memory, testing)
  • Email (nodemailer integration)
  • mDNS (local network discovery)
  • Gateway (Private.Me platform relay)
  • Custom transports via plugin API

Developer Experience:

  • Zero runtime dependencies
  • Fully offline capable
  • TypeScript strict mode
  • 2988 passing tests
  • ESM + CJS support

API

Agent

// Static: Agent.create(options), Agent.quickstart(name), Agent.fromSeed(seed, opts)
// Instance: send(), receive(), verifySignature(), rotateDid(), revoke(), cleanup()
// Props: did, name, identity, registry, transports

Registry

// TrustRegistry: register(), resolve(), isTrusted(), revoke()
// Built-in: MemoryTrustRegistry, HttpTrustRegistry

Transports

// HttpsTransportAdapter, LoopbackTransport, GatewayTransport
// Adapters: RetryTransportAdapter, DualModeAdapter

CLI

npx xbind init              # Interactive setup
npx xbind --version         # Show version

Subpaths:

  • @private.me/xbind/agentAgent, generateSharedKey, parseAgentError
  • @private.me/xbind/identitygenerateIdentity, sign, verify, publicKeyToDid, didToPublicKeyBytes, and more
  • @private.me/xbind/trust-registryMemoryTrustRegistry, HttpTrustRegistry, FileTrustRegistry
  • @private.me/xbind/key-agreement — Key exchange functions
  • @private.me/xbind/errors — Error classes and codes

See API-REFERENCE.md for complete export list.

Configuration

Config: ~/.xbind/config.json | Env: XBIND_CONFIG_PATH, XBIND_DATA_DIR

Optional peers (lazy-loaded): bonjour-service (mDNS), nodemailer (Email)

Environment Variables

Core:

  • XBIND_SEED - Agent identity seed (64-char hex)
  • XBIND_INVITE_CODE - Auto-accept invite on first run

Endpoints:

  • XBIND_REGISTRY_URL - Trust registry endpoint (default: https://private.me/aci/registry)
  • XBIND_RELAY_URL - Message relay endpoint (default: https://private.me/aci/relay)
  • XBIND_DOC_BASE - Documentation base URL (default: https://private.me/docs/xbind)

Timeouts (milliseconds):

  • XBIND_TIMEOUT_DEFAULT - Default operation timeout
  • XBIND_TIMEOUT_GATEWAY - Gateway operation timeout
  • XBIND_TIMEOUT_REGISTRY - Registry operation timeout
  • XBIND_TIMEOUT_TRANSPORT - Transport operation timeout

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

/*
 * ANTI-PATTERN EXAMPLE - DO NOT USE IN PRODUCTION
 *
 * The following code demonstrates INSECURE key storage patterns that
 * compromise xBind's post-quantum cryptographic security. These are shown
 * for educational purposes only to illustrate what NOT to do.
 *
 * 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
 *
 * For secure key storage, see the examples below using OS-level keystore APIs
 * or Hardware Security Modules (HSM).
 */

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

Use OS-Level Keystore APIs

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

/*
 * Cross-platform keystore integration using keytar package
 * (macOS Keychain, Windows Credential Manager, Linux Secret Service)
 *
 * Installation: npm install keytar
 *
 * NOTE: This example uses mock implementations for demonstration.
 * In production, install the keytar package for actual OS keystore integration.
 */

// Mock keytar implementation for demonstration
const mockKeytar = {
  setPassword: async (service, account, password) => {
    console.log(`[Mock] Storing password for ${service}:${account}`);
  },
  getPassword: async (service, account) => {
    console.log(`[Mock] Retrieving password for ${service}:${account}`);
    return globalThis.crypto.getRandomValues(new Uint8Array(32));
  }
};

// Generate and store seed securely
const seed = globalThis.crypto.getRandomValues(new Uint8Array(32));
await mockKeytar.setPassword('xbind', 'agent-seed', Buffer.from(seed).toString('hex'));

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

const result = await Agent.fromSeed(storedSeed, {
  name: 'secure-agent',
  registry: new MemoryTrustRegistry(),
  transport: new LoopbackTransport()
});

if (result.ok) {
  console.log('Agent created with secure seed storage:', result.value.did);
  result.value.cleanup();
}
npm install keytar  # Unified API for macOS/Windows/Linux keystores

Production: Hardware Security Modules (HSM)

For compliance requirements (PCI-DSS, HIPAA, SOC 2), use HSM-backed key management:

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

/*
 * HSM-backed key management using AWS KMS
 *
 * Installation: npm install @aws-sdk/client-kms
 *
 * NOTE: This example uses mock implementations for demonstration.
 * In production, install the AWS SDK and configure KMS credentials.
 */

// Mock KMS client for demonstration
const mockKMS = {
  decrypt: async (encryptedData) => {
    console.log('[Mock] Decrypting seed with KMS');
    return globalThis.crypto.getRandomValues(new Uint8Array(32));
  }
};

// Encrypted seed from database (in production, this would be KMS-encrypted)
const encryptedSeedFromDB = new Uint8Array(64);

try {
  // Decrypt seed with KMS at runtime
  const decryptedSeed = await mockKMS.decrypt(encryptedSeedFromDB);

  const result = await Agent.fromSeed(decryptedSeed, {
    name: 'hsm-agent',
    registry: new MemoryTrustRegistry(),
    transport: new LoopbackTransport()
  });

  if (result.ok) {
    console.log('Agent created with HSM-backed key:', result.value.did);
    result.value.cleanup();
  }
} catch (error) {
  console.error('KMS decryption failed:', error);
}

Key Storage Best Practices

  1. Encrypt at Rest: Use AES-256-GCM with a separate encryption key
  2. Least Privilege: Only the agent process should access the seed
  3. Rotation: Plan for key rotation (see Succession API)
  4. Backup: Encrypted backups to separate storage (3-2-1 rule)
  5. Monitoring: Alert on unauthorized seed access attempts

Environment Variable Security

If you must use environment variables (not recommended for production):

# Better: Encrypted environment variable via 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

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

Contact [email protected] for incident assistance.


Architecture

Flow: Sign (ML-DSA-65) → Encrypt (ML-KEM-768 + AES-256-GCM) → Split (XorIDA) → Send → Combine → Decrypt → Verify

Security: Confidentiality (AES-256-GCM), Authenticity (ML-DSA-65), Forward secrecy (ephemeral keys), Information-theoretic split (XorIDA)

Connection Models

xBind supports 4 entity-to-entity connection patterns for establishing secure agent communication:

1. Invite Code (Person → Person)

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

// Create two agents
const agentA = await Agent.quickstart({ name: 'alice', registry, transport });
const agentB = await Agent.quickstart({ name: 'bob', registry, transport });

// Agent A sends invite to Agent B
const result = await agentA.invite({
  to: agentB.did,
  message: 'Connect our systems'
});

if (result.ok) {
  console.log('Invite sent to', agentB.did);
}

agentA.cleanup();
agentB.cleanup();

2. QR Code (Person → Person, Offline)

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

// Create two agents
const agentA = await Agent.quickstart({ name: 'alice', registry, transport });
const agentB = await Agent.quickstart({ name: 'bob', registry, transport });

// Agent A's DID can be encoded as QR code data
const qrData = agentA.did;
console.log('Display QR code to user (contains DID for connection)');

// Agent B can use the DID to send messages
const result = await agentB.send({
  to: qrData,
  payload: { message: 'Connected via QR' },
  scope: 'connect'
});

if (result.ok) {
  console.log('Connection established via QR code');
}

agentA.cleanup();
agentB.cleanup();

3. Trust Registry (System → System)

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

// Pre-registered agents in trust registry
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

// Create two agents
const agent = await Agent.quickstart({ name: 'production-agent', registry, transport });
const recipient = await Agent.quickstart({ name: 'recipient-agent', registry, transport });

try {
  // Auto-trust registered agents
  const result = await agent.send({
    to: recipient.did, // Must be in registry
    payload: { action: 'process' },
    scope: 'production'
  });

  if (result.ok) {
    console.log('Message sent to registered agent:', result.value.envelopeId);
  }
} catch (error) {
  console.log('Network error (expected in test):', error.message);
} finally {
  agent.cleanup();
  recipient.cleanup();
}

4. Peer Discovery (Local Network, mDNS)

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

/*
 * mDNS discovery for local network peer detection
 *
 * Installation: npm install bonjour-service
 *
 * NOTE: This example uses mock implementations for demonstration.
 * In production, install bonjour-service for actual mDNS discovery.
 */

// Mock mDNS discovery for demonstration
const mockDiscovery = {
  start: async () => {
    console.log('[Mock] Starting mDNS discovery on port 3000');
  },
  findPeers: async () => {
    console.log('[Mock] Discovering peers on local network');
    return [{ name: 'peer-1', did: 'did:key:z6Mk...' }];
  }
};

// Enable mDNS discovery
await mockDiscovery.start();

// Discover peers on local network
const peers = await mockDiscovery.findPeers();
console.log('Discovered peers:', peers.length);

See Entity-to-Entity Connection UX for complete specifications.

Version

Current: v3.2.1 (June 2026) - See CHANGELOG.md

Examples

Core Agent Operations

Quickstart (offline, default config):

import { Agent } from '@private.me/xbind';
const agent = await Agent.quickstart({ name: 'my-agent' });
console.log('DID:', agent.did);
agent.cleanup();

Production setup with Result<T,E>:

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

try {
  const result = await Agent.create({
    name: 'production-agent',
    registry: new HttpTrustRegistry({ baseUrl: 'https://private.me/aci/registry' }),
    transport: new HttpsTransportAdapter({ baseUrl: 'https://private.me/aci/relay' })
  });

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

  const agent = result.value;
  console.log('Production agent created:', agent.did);
  agent.cleanup();
} catch (error) {
  console.log('Network error (expected in test):', error.message);
}

AI-first wrapper (AgentBuilder):

import { AgentBuilder } from '@private.me/xbind';

try {
  const result = await AgentBuilder.create({ name: 'svc', ttl: 3600000 });

  if (result.ok) {
    const agent = result.value;
    console.log('AgentBuilder created agent:', agent.did);
    agent.cleanup();
  } else {
    console.error('Failed to create agent:', result.error);
  }
} catch (error) {
  console.log('Network error (expected in test):', error.message);
}

Send encrypted message:

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'sender', registry, transport });

try {
  const sendResult = await agent.send({
    to: 'did:key:z6Mk...',
    payload: { action: 'process', data: [1, 2, 3] },
    scope: 'test',
    action: 'process', // Security classification (sender-side only, NOT in envelope)
  });

  if (sendResult.ok) {
    console.log('Sent:', sendResult.value.envelopeId);
  }
} catch (error) {
  console.log('Network error (expected in test):', error.message);
} finally {
  agent.cleanup();
}

Note on action field: The action parameter in AgentSendOptions is used for security policy classification (determines when to auto-apply XorIDA split-channel) and is NOT preserved in the envelope. The receiver cannot access this value. If the receiver needs to know the action, include it in the payload: payload: { action: 'transfer', ... }.

Receive messages:

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'receiver', registry, transport });

try {
  const messages = await agent.receive({ scope: 'test', limit: 10 });
  for (const msg of messages) {
    console.log('From:', msg.from, 'Payload:', msg.payload);
  }
} catch (error) {
  console.log('Network error (expected in test):', error.message);
} finally {
  agent.cleanup();
}

Identity & Cryptography

Generate new identity:

import { generateIdentity } from '@private.me/xbind';
const result = await generateIdentity();
if (!result.ok) throw new Error('Failed to generate identity');
const identity = result.value;
console.log('DID:', identity.did);

Reuse existing identity (persistent agents):

import { Agent, generateIdentity, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

// Important: Agent.create() always generates NEW identity
// To reuse an identity, use Agent.fromParts() or Agent.fromIdentity()

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

// Generate identity once
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const existingIdentity = identityResult.value;

// Method 1: fromParts (no registry registration)
const agent = Agent.fromParts(existingIdentity, registry, transport, {
  name: 'my-persistent-agent'
});
console.log('Agent created with fromParts:', agent.did);

// Method 2: fromIdentity (with registry check)
const result = await Agent.fromIdentity(existingIdentity, {
  registry,
  transport,
  name: 'my-persistent-agent-v2'
});

if (result.ok) {
  // Same DID across restarts
  console.log('Agent DID:', result.value.did);
  result.value.cleanup();
}

agent.cleanup();

Seed-based agents (deterministic identity):

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

// CRITICAL: Store the ORIGINAL seed before creating agent
const seed = crypto.getRandomValues(new Uint8Array(32));
// saveToKeychain(seed);  // ← Store THIS, not exportSeeds() output

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

const result = await Agent.fromSeed(seed, {
  name: 'deterministic-agent',
  registry,
  transport
});

if (!result.ok) throw new Error('Failed to create agent from seed');
const agent = result.value;
console.log('Agent created from seed:', agent.did);

// Later: Restore agent with SAME seed
const restoredResult = await Agent.fromSeed(seed, {
  name: 'deterministic-agent',
  registry,
  transport
});

if (restoredResult.ok) {
  const restoredAgent = restoredResult.value;
  // Same DID because same seed
  console.log('Same DID:', agent.did === restoredAgent.did); // true
  restoredAgent.cleanup();
}

agent.cleanup();

WARNING: exportSeeds() is NOT compatible with fromSeed()

The exportSeeds() method returns HKDF-derived keys, not the original seed. You cannot use exportSeeds() output with fromSeed():

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const seed = crypto.getRandomValues(new Uint8Array(32));

/*
 * ANTI-PATTERN EXAMPLE - DO NOT USE
 *
 * WRONG: This will NOT work
 * const agent = await Agent.fromSeed(seed, { registry, transport });
 * const exported = await agent.value.exportSeeds(); // HKDF-derived keys
 * const restored = await Agent.fromSeed(exported.ed25519, {...}); // FAILS - different DID
 */

// CORRECT: Store original seed BEFORE creating agent
const originalSeed = crypto.getRandomValues(new Uint8Array(32));
// await persistToSecureStorage(originalSeed); // ← Store original seed

const result = await Agent.fromSeed(originalSeed, { name: 'agent', registry, transport });
if (!result.ok) throw new Error('Failed to create agent');
const agent = result.value;

// Later: Restore with original seed
const restoredResult = await Agent.fromSeed(originalSeed, { name: 'agent', registry, transport });
if (restoredResult.ok) {
  console.log('Same DID:', agent.did === restoredResult.value.did); // ✅ true
  restoredResult.value.cleanup();
}

agent.cleanup();

Why this happens: fromSeed() uses HKDF (one-way function) to derive Ed25519 and X25519 keys from the seed. exportSeeds() returns these derived keys, not the original seed. HKDF is cryptographically non-reversible.

For seed persistence:

  1. Generate seed: crypto.getRandomValues(new Uint8Array(32))
  2. Store original seed in secure storage (keychain, vault, encrypted database)
  3. Create agent: Agent.fromSeed(storedSeed, {...})
  4. Restore agent: Use same original seed from storage

For PKCS8-based persistence (alternative):

import { Agent, generateIdentity, exportPKCS8, exportX25519PKCS8, importIdentity, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

// Generate identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

const agent = Agent.fromParts(identity, registry, transport, { name: 'pkcs8-agent' });

// Export PKCS8 (can be used for restore)
const edPkcs8 = await exportPKCS8(agent.identity.privateKey);
const x25519Pkcs8 = await exportX25519PKCS8(agent.identity.x25519PrivateKey);

if (!edPkcs8.ok || !x25519Pkcs8.ok) {
  throw new Error('Failed to export PKCS8 keys');
}

// Later: Restore from PKCS8
const restored = await importIdentity(edPkcs8.value, x25519Pkcs8.value);
if (!restored.ok) throw new Error('Failed to import identity');

const restoredAgent = Agent.fromParts(restored.value, registry, transport, { name: 'restored-agent' });
console.log('Restored agent:', restoredAgent.did);

agent.cleanup();
restoredAgent.cleanup();

Sign and verify (Ed25519):

import { generateIdentity, sign, verify } from '@private.me/xbind';

// Generate identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

const message = new TextEncoder().encode('Hello');

// Sign message
const sigResult = await sign(identity.privateKey, message);
if (!sigResult.ok) throw new Error('Sign failed');

// Verify signature
const verifyResult = await verify(identity.publicKey, message, sigResult.value);
console.log('Valid:', verifyResult.ok && verifyResult.value); // true

Post-quantum signatures (ML-DSA-65):

import { generateIdentity, signMlDsa65, verifyMlDsa65 } from '@private.me/xbind';

// Generate identity with post-quantum signature keys
const identityResult = await generateIdentity({ postQuantumSig: true });
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

const message = new TextEncoder().encode('Hello');

// Sign with post-quantum ML-DSA-65
const pqSigResult = await signMlDsa65(identity.mlDsaSecretKey, message);
if (!pqSigResult.ok) throw new Error('Post-quantum sign failed');

// Verify post-quantum signature
const pqValidResult = await verifyMlDsa65(identity.mlDsaPublicKey, message, pqSigResult.value);
console.log('Post-quantum signature valid:', pqValidResult.ok && pqValidResult.value);

DID conversions:

import { generateIdentity, publicKeyToDid, didToPublicKeyBytes } from '@private.me/xbind';

// Generate identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

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

// Convert DID back to public key bytes
const pubKeyResult = didToPublicKeyBytes(did);
if (pubKeyResult.ok) {
  console.log('Public key bytes match:', Buffer.compare(publicKeyBytes, pubKeyResult.value) === 0);
}

Key rotation with succession:

import { Agent, rotateKeys, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

const agent = await Agent.quickstart({ name: 'rotation-test', registry, transport });

// Rotate keys
const newIdentityResult = await rotateKeys(agent.identity);
if (newIdentityResult.ok) {
  console.log('Keys rotated. New DID:', newIdentityResult.value.did);
  console.log('Old DID:', agent.did);
} else {
  console.error('Key rotation failed:', newIdentityResult.error);
}

agent.cleanup();

Envelopes

Create encrypted envelope:

import { generateIdentity, createEnvelope } from '@private.me/xbind';

// Generate sender and recipient identities
const senderResult = await generateIdentity();
const recipientResult = await generateIdentity();

if (!senderResult.ok || !recipientResult.ok) {
  throw new Error('Failed to generate identities');
}

const senderIdentity = senderResult.value;
const recipientDid = recipientResult.value.did;

// Create encrypted envelope
const envelopeResult = await createEnvelope({
  from: senderIdentity,
  to: recipientDid,
  payload: { message: 'Hello' }
});

if (envelopeResult.ok) {
  console.log('Envelope created:', envelopeResult.value.envelopeId);
}

Decrypt envelope payload:

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

// Create sender and recipient agents
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

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

// Send message (creates envelope internally)
const sendResult = await sender.send({
  to: recipient.did,
  payload: { message: 'Hello' },
  scope: 'default'
});

if (!sendResult.ok) throw new Error('Failed to send message');

// Get envelope from loopback transport and decrypt
const envelope = transport.outbox[0];
const receiveResult = await recipient.receive(envelope);
if (receiveResult.ok) {
  console.log('Decrypted payload:', receiveResult.value.payload);
}

sender.cleanup();
recipient.cleanup();

Serialize/deserialize:

import { Agent, MemoryTrustRegistry, LoopbackTransport, serializeEnvelope, deserializeEnvelope } from '@private.me/xbind';

// Create agents
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

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

// Send message to get envelope
const sendResult = await sender.send({
  to: recipient.did,
  payload: { message: 'Hello' },
  scope: 'default'
});

if (!sendResult.ok) throw new Error('Failed to send message');

// Get envelope from transport and decrypt
const envelope = transport.outbox[0];
const receiveResult = await recipient.receive(envelope);
if (!receiveResult.ok) throw new Error('Failed to receive message');

// Note: serializeEnvelope/deserializeEnvelope work with low-level envelope structures
// For most use cases, use Agent.send() and Agent.receive() which handle serialization
console.log('Message sent and received successfully');

sender.cleanup();
recipient.cleanup();

Signed cleartext envelopes:

import { generateIdentity, createSignedEnvelope, openSignedEnvelope } from '@private.me/xbind';

// Generate identity for signing
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

// Create signed cleartext envelope
const signedResult = await createSignedEnvelope({
  plaintext: new TextEncoder().encode(JSON.stringify({ data: 'public' })),
  senderDid: identity.did,
  privateKey: identity.privateKey,
  scope: 'announce'
});

if (!signedResult.ok) throw new Error('Failed to create signed envelope');

// Verify signed envelope
const verifiedResult = await openSignedEnvelope(signedResult.value);
if (verifiedResult.ok) {
  console.log('Signature verified, payload:', verifiedResult.value);
}

Trust Registry

In-memory registry (testing):

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

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();

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

// Register agent in registry
await registry.register({
  did: agent.did,
  publicKey: agent.identity.rawPublicKey,
  name: agent.name
});

console.log('Agent registered in memory registry');
agent.cleanup();

HTTP registry (production):

import { HttpTrustRegistry } from '@private.me/xbind';
const registry = new HttpTrustRegistry({ baseUrl: 'https://private.me/aci/registry' });

File-based registry:

import { FileTrustRegistry } from '@private.me/xbind/trust-registry';
const registry = new FileTrustRegistry({ path: '/opt/private.me/data/xbind-registry.jsonl' });

Enterprise registry with rate limiting:

import { createEnterpriseTrustRegistry, RegistrationRateLimiter } from '@private.me/xbind';
const rateLimiter = new RegistrationRateLimiter(100, 1000, 3600000);
const registry = await createEnterpriseTrustRegistry({ storage: 'memory', rateLimiter });
console.log('Enterprise registry created with rate limiting');
rateLimiter.destroy(); // Clean up interval timer

Transports

HTTPS transport:

import { HttpsTransportAdapter } from '@private.me/xbind';
const transport = new HttpsTransportAdapter({ baseUrl: 'https://private.me/aci/relay' });

Loopback (in-memory, testing):

import { LoopbackTransport } from '@private.me/xbind';
const transport = new LoopbackTransport();

Gateway relay:

import { GatewayTransport } from '@private.me/xbind';
const transport = new GatewayTransport({ gateway: 'https://private.me/aci/relay', apiKey: 'your-api-key' });

Retry adapter with exponential backoff:

import { LoopbackTransport, RetryTransportAdapter, ExponentialBackoffStrategy } from '@private.me/xbind';

// Create base transport
const baseTransport = new LoopbackTransport();

// Create retry strategy
const strategy = new ExponentialBackoffStrategy({ maxRetries: 3 });

// Wrap base transport with retry adapter
const transport = new RetryTransportAdapter(baseTransport, { strategy });
console.log('Retry transport configured with exponential backoff');

Circuit breaker:

import { CircuitBreaker } from '@private.me/xbind';
const breaker = new CircuitBreaker({ threshold: 5, timeout: 60000 });

Timeouts & Cancellation

Timeout configuration:

import { Agent, createTimeoutController, withTimeout, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

// Create agent
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'timeout-test', registry, transport });

// Create timeout controller
const controller = createTimeoutController({ send: 5000 });

// Use withTimeout for send operation
try {
  const result = await withTimeout(
    () => agent.send({
      to: 'did:key:z6Mk...',
      payload: { data: 'test' },
      scope: 'test'
    }),
    5000
  );
  console.log('Send completed within timeout');
} catch (error) {
  console.log('Operation timed out or failed');
} finally {
  agent.cleanup();
}

Cancellation:

import { createCancellationController, withCancellation } from '@private.me/xbind';

// Create cancellation controller
const controller = createCancellationController();

// Mock long-running operation
const longRunningOp = () => new Promise(resolve => setTimeout(() => resolve('done'), 2000));

// Start operation with cancellation support
const promise = withCancellation(longRunningOp(), controller.signal);

// Cancel after 1 second
setTimeout(() => {
  controller.cancel(); // Abort operation
  console.log('Operation cancelled');
}, 1000);

// Handle result or cancellation
try {
  const result = await promise;
  console.log('Operation completed:', result);
} catch (error) {
  console.log('Operation was cancelled or failed');
}

Combine signals:

import { combineSignals, createTimeoutSignal, createCancellationController } from '@private.me/xbind';

// Create timeout signal
const timeoutObj = createTimeoutSignal(5000);
const timeout = timeoutObj.signal;

// Create user cancellation signal
const userController = createCancellationController();
const userSignal = userController.signal;

// Combine multiple signals
const combined = combineSignals([userSignal, timeout]);
console.log('Combined signal created - will trigger on timeout or user cancellation');

Batch Operations

Batch send:

import { Agent, batchSend, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

// Create agent
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'batch-sender', registry, transport });

// Send multiple messages in batch
const results = await batchSend(agent, {
  messages: [
    { to: 'did:key:z6Mk...', payload: { msg: 1 }, scope: 'batch' },
    { to: 'did:key:z6Mk...', payload: { msg: 2 }, scope: 'batch' }
  ]
});

console.log('Batch send results:', results.length, 'messages');
agent.cleanup();

Batch registry operations:

import { generateIdentity, batchRegistryOps, MemoryTrustRegistry } from '@private.me/xbind';

// Create registry
const registry = new MemoryTrustRegistry();

// Generate test identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

// Batch operations
const results = await batchRegistryOps(registry, {
  operations: [
    { type: 'register', did: identity.did, params: { publicKey: identity.rawPublicKey, name: 'test-agent' } },
    { type: 'revoke', did: identity.did }
  ]
});
console.log('Batch registry operations completed:', results.total);

Async Iterators

Message stream:

import { Agent, MessageStream, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

// Create agent
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'stream-test', registry, transport });

// Create message stream
const stream = new MessageStream(agent, { scope: 'test' });
console.log('Message stream created for scope: test');

// Stream is ready to process incoming messages
// In production, messages would arrive asynchronously
agent.cleanup();

Stream utilities:

import { Agent, MessageStream, mapStream, filterStream, takeStream, MemoryTrustRegistry, LoopbackTransport } from '@private.me/xbind';

// Create agent and stream
const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'stream-utils-test', registry, transport });
const stream = new MessageStream(agent, { scope: 'test' });

// Apply stream transformations
const mapped = mapStream(stream, msg => msg.payload);
const filtered = filterStream(stream, msg => msg.scope === 'important');
const limited = takeStream(stream, 10);

console.log('Stream utilities configured');
agent.cleanup();

DID Methods

did:privateme format:

import { generateIdentity, publicKeyToPrivateMeDid, privateMeDidToPublicKeyBytes } from '@private.me/xbind';

// Generate identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

const publicKeyBytes = identity.rawPublicKey;

// Convert to did:privateme format
const privateMeDid = publicKeyToPrivateMeDid(publicKeyBytes);
console.log('Private.me DID:', privateMeDid);

// Convert back to public key bytes
const pubKeyResult = privateMeDidToPublicKeyBytes(privateMeDid);
if (pubKeyResult.ok) {
  console.log('Public key bytes match:', Buffer.compare(publicKeyBytes, pubKeyResult.value) === 0);
}

DID format conversion:

import { generateIdentity, convertDidFormat, normalizeDid } from '@private.me/xbind';

// Generate identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const did = identityResult.value.did;

// Convert DID format
const convertedResult = convertDidFormat(did);
if (convertedResult.ok) {
  console.log('Converted DID:', convertedResult.value);
}

// Normalize DID
const normalizedResult = normalizeDid(did);
if (normalizedResult.ok) {
  console.log('Normalized DID:', normalizedResult.value);
}

did:web resolution:

import { generateIdentity, resolveDid } from '@private.me/xbind';

// Generate identity
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');
const identity = identityResult.value;

// Resolve DID to DID document
try {
  const didDoc = await resolveDid(identity.did, identity.rawPublicKey);
  if (didDoc.ok) {
    console.log('DID document:', didDoc.value);
  }
} catch (error) {
  console.log('DID resolution failed (expected for did:key):', error.message);
}

Error Handling

xBind uses four distinct error patterns based on operation type. Understanding when each pattern is used helps you write correct error handling code.

Pattern 1: Result<T, E> (Operations That Can Fail)

Used for operations that can fail due to invalid inputs, network errors, or crypto failures. This is the most common pattern in xBind.

When used: Identity operations, envelope creation, agent operations, key agreement, registry lookups

Example:

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

const result = await Agent.create({
  name: 'my-agent',
  scopes: ['read:data'],
  registry: new HttpTrustRegistry({
    baseUrl: 'https://private.me/aci/registry'
  }),
  transport: new HttpsTransportAdapter({
    baseUrl: 'https://private.me/aci/relay'
  })
});

if (result.ok) {
  const agent = result.value;
  console.log('Agent created:', agent.did);
} else {
  const error = result.error;
  console.error('Failed to create agent:', error);
}

Functions using Result<T, E>:

  • Agent.create()Result<Agent, AgentError>
  • agent.send()Result<SendReceipt, AgentError>
  • generateIdentity()Result<AgentIdentity, IdentityError>
  • generateEphemeralKeyPair()Result<EphemeralKeyPair, KeyAgreementError>
  • registry.resolve()Result<Uint8Array, RegistryError>

Pattern 2: Raw Return (Infallible Transformations)

Used for pure transformations that cannot fail given valid inputs. These functions validate inputs and throw on programmer errors.

When used: DID formatting, data conversions

Example:

import { generateIdentity, publicKeyToDid, didToPublicKeyBytes } from '@private.me/xbind';

// Generate identity to get a public key
const identityResult = await generateIdentity();
if (!identityResult.ok) throw new Error('Failed to generate identity');

// Infallible transformation (throws on invalid input)
const did = publicKeyToDid(identityResult.value.rawPublicKey);

// Fallible parsing (returns Result)
const pubKeyResult = didToPublicKeyBytes(did);
if (pubKeyResult.ok) {
  console.log('Public key:', pubKeyResult.value);
}

Why throw instead of Result? These are programmer errors (wrong types, invalid lengths), not runtime failures. TypeScript should catch these at compile time.

Functions using raw return:

  • publicKeyToDid(rawPublicKey)string (throws on length != 32)
  • serializeEnvelope(envelope)Uint8Array
  • parseAgentError(error){ code: string, subCode?: string }

Pattern 3: Throws (Programming Errors)

Used for programming errors that should not occur in correct code. These indicate bugs, not runtime conditions.

When used: Invalid configuration, type mismatches, assertion failures

Example:

import { validateAgentOptions, ConfigValidationError } from '@private.me/xbind';

try {
  validateAgentOptions({
    name: '',  // Invalid: empty name
    scopes: 'not-an-array'  // Invalid: wrong type
  });
} catch (err) {
  if (err instanceof ConfigValidationError) {
    console.error('Configuration error:', err.details);
    // Details: { field: 'name', reason: 'Name cannot be empty' }
  }
}

Functions that throw:

  • validateAgentOptions() → throws ConfigValidationError
  • assertValidConfig() → throws on invalid config
  • publicKeyToDid() → throws on invalid key length

Pattern 4: Undefined (Optional Features)

Used for optional capabilities that may not be available at runtime (e.g., post-quantum crypto).

When used: Feature detection, optional algorithms

Example:

import { generateIdentity } from '@private.me/xbind';

const result = await generateIdentity({ postQuantumSig: true });

if (result.ok) {
  const identity = result.value;

  // ML-DSA key may be undefined if PQ crypto unavailable
  if (identity.mlDsaPublicKey) {
    console.log('Post-quantum signatures available');
  } else {
    console.warn('Falling back to classical Ed25519');
  }
}

Fields using undefined:

  • AgentIdentity.mlKemPublicKey?: Uint8Array (PQ KEM key)
  • AgentIdentity.mlDsaPublicKey?: Uint8Array (PQ signature key)
  • AgentIdentity.rotatedKeys?: RotatedKeys[] (key rotation history)

Quick Reference Table

| Pattern | When to Use | Example | |---------|-------------|---------| | Result<T, E> | Operations that can fail (network, crypto, validation) | agent.send(), generateIdentity() | | Raw Return | Infallible transformations (pure functions) | publicKeyToDid(), serializeEnvelope() | | Throws | Programming errors (invalid config, type errors) | validateAgentOptions(), assertValidConfig() | | Undefined | Optional features (PQ crypto, rotated keys) | identity.mlDsaPublicKey |

Error Classes (Optional)

For try/catch consumers, xBind provides error classes:

import {
  XBindError,
  XBindIdentityError,
  XBindTransportError,
  XBindRegistryError,
  toXBindError,
  isXBindError
} from '@private.me/xbind/errors';

try {
  await riskyOperation();
} catch (err) {
  if (isXBindError(err)) {
    console.error('XBind error:', err.code, err.message);
  } else {
    console.error('Unknown error:', err);
  }
}

Note: Most xBind APIs use Result<T, E> (Pattern 1), not exceptions. Error classes are provided for interop with try/catch code.

Future: v4.0 Will Unify to Result<T, E>

The current inconsistency is acknowledged as technical debt. xBind v4.0 will unify all error handling to Result<T, E>:

  • publicKeyToDid()Result<string, IdentityError>
  • validateAgentOptions()Result<void, ValidationError>
  • All functions will use Result pattern

This is a breaking change and cannot be done in v3.x. For now, use the patterns documented above.

Debugging & Observability

Debug mode:

import { Agent, MemoryTrustRegistry, LoopbackTransport, enableDebugMode, generateDebugReport } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'debug-agent', registry, transport });

enableDebugMode({ networkTracing: true, cryptoTracing: true });

// Run operations
const result = await agent.send({
  to: agent.did,
  payload: { test: 'debug' },
  scope: 'test'
});

const report = generateDebugReport();
console.log('Debug report:', report);
agent.cleanup();

Correlation IDs:

import { Agent, MemoryTrustRegistry, LoopbackTransport, generateCorrelationId, attachCorrelationId } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'correlation-agent', registry, transport });

const correlationId = generateCorrelationId();
const request = { to: agent.did, payload: { data: 'test' }, scope: 'test' };
const trackedRequest = attachCorrelationId(request, correlationId);

console.log('Correlation ID:', correlationId);
agent.cleanup();

Structured logging:

import { Agent, MemoryTrustRegistry, LoopbackTransport, createLogger, LogLevel, generateCorrelationId } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'logging-agent', registry, transport });

const logger = createLogger({ level: LogLevel.INFO });
const correlationId = generateCorrelationId();

logger.info('Operation started', { correlationId, agent: agent.did });

// Perform operation
const result = await agent.send({
  to: agent.did,
  payload: { action: 'test' },
  scope: 'test'
});

logger.info('Operation completed', { correlationId, success: result.ok });
agent.cleanup();

Health checks:

import { Agent, MemoryTrustRegistry, LoopbackTransport, createHealthChecker } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'health-agent', registry, transport });

const checker = createHealthChecker(agent);
const health = await checker.check();

console.log('Healthy:', health.healthy);
console.log('Checks:', health.checks);
agent.cleanup();

Version & Capabilities

Version info:

import { getVersion, hasCapability, Capability, VERSION } from '@private.me/xbind';
console.log('Version:', VERSION);                    // '3.2.1' (string)
const info = getVersion();                           // VersionInfo object
console.log('Semver:', info.semver);                 // '3.2.1'
if (hasCapability(Capability.ML_KEM_768)) {
  console.log('Post-quantum KEM supported');
}

Compatibility checks:

import { checkCompatibility, compareVersions } from '@private.me/xbind';
const compatible = checkCompatibility('^3.0.0');
const comparison = compareVersions('3.0.0', '3.1.0'); // -1

Browser & Runtime

Runtime detection:

import { getVersion } from '@private.me/xbind';
const version = getVersion();
console.log('xBind version:', version.semver);
console.log('Node version:', version.nodeVersion);

Version capabilities:

import { hasCapability, getCapabilities } from '@private.me/xbind';

// Check for specific capability
if (hasCapability('ml-kem-768')) {
  console.log('Post-quantum key encapsulation supported');
}

// List all capabilities
const capabilities = getCapabilities();
console.log('Available capabilities:', capabilities);

Plugin System

Create plugin:

import { createPlugin, MiddlewareChain } from '@private.me/xbind';
const plugin = createPlugin({
  name: 'my-plugin',
  before: async (envelope) => {
    console.log('Before send:', envelope.id);
    return envelope;
  }
});

Built-in plugins:

import { createLoggingPlugin, createMetricsPlugin } from '@private.me/xbind';
const logger = createLoggingPlugin({ level: 'info' });
const metrics = createMetricsPlugin({ endpoint: '/metrics' });

Advanced Features

Connection pooling:

import { Agent, MemoryTrustRegistry, LoopbackTransport, ConnectionPool } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'pool-agent', registry, transport });

// Create connection pool
const pool = new ConnectionPool({ maxSize: 10, idleTimeout: 60000 });

console.log('Connection pool created with max size:', pool.maxSize);

// Use agent to send message
await agent.send({ to: agent.did, payload: { test: true }, scope: 'test' });

agent.cleanup();

Serialization formats:

import { serialize, deserialize, detectFormat } from '@private.me/xbind';

const data = { message: 'hello', value: 42 };
const msgpack = serialize(data, 'msgpack');
console.log('Serialized to MessagePack:', msgpack.byteLength, 'bytes');

const deserialized = deserialize(msgpack);
console.log('Deserialized:', deserialized);

// Auto-detect format
const format = detectFormat(msgpack);
console.log('Detected format:', format);

Event emitter:

import { XBindEventEmitter } from '@private.me/xbind';

const emitter = new XBindEventEmitter();

// Subscribe to events
emitter.on('message', (msg) => console.log('Received:', msg));
emitter.on('error', (err) => console.error('Error:', err));

// Emit events
emitter.emit('message', { id: 'msg-1', payload: 'test' });
emitter.emit('message', { id: 'msg-2', payload: 'hello' });

// One-time listeners
emitter.once('complete', () => console.log('Operation complete'));
emitter.emit('complete');

Backup & restore:

import { Agent, MemoryTrustRegistry, LoopbackTransport, exportBackup, importBackup } from '@private.me/xbind';

const registry = new MemoryTrustRegistry();
const transport = new LoopbackTransport();
const agent = await Agent.quickstart({ name: 'backup-agent', registry, transport });

// Export encrypted backup
const backupResult = await exportBackup(agent.identity, 'strong-password-123');
if (!backupResult.ok) throw new Error('Backup failed');
const backup = backupResult.value;
console.log('Backup created:', backup.ciphertext.length, 'chars encrypted');

// Restore from backup
const restoredResult = await importBackup(backup, 'strong-password-123');
if (!restoredResult.ok) throw new Error('Restore failed');
const restored = restoredResult.value;
console.log('Identity restored:', restored.did);

agent.cleanup();

Split-channel operations:

import { splitForChannel, reconstructFromChannel } from '@private.me/xbind';

const secret = new TextEncoder().encode('my-secret-data');

// Split into 3 shares, require 2 to reconstruct (2-of-3 threshold)
const result = await splitForChannel(secret, { threshold: 2, totalShares: 3 });
if (!result.ok) throw new Error(result.error);
const shares = result.value;
console.log('Split into', shares.length, 'shares');

// Reconstruct from any 2 shares
const reconstructResult = await reconstructFromChannel(shares.slice(0, 2));
if (!reconstructResult.ok) throw new Error(reconstructResult.error);
const recoveredSecret = new TextDecoder().decode(reconstructResult.value);
console.log('Reconstructed secret:', recoveredSecret);

CLI commands:

// CLI usage: npx @private.me/xbind init
// See the CLI section below for available commands

Nonce stores (replay attack prevention):

import { MemoryNonceStore } from '@private.me/xbind';
const nonceStore = new MemoryNonceStore();
const senderDid = 'did:privateme:sender123';
const isValid = await nonceStore.check('nonce123', senderDid); // true (first time)
const isDuplicate = await nonceStore.check('nonce123', senderDid); // false (replay detected)
import { RedisNonceStore } from '@private.me/xbind';
const redisNonce = new RedisNonceStore({ url: 'redis://localhost:6379' });

Key agreement (hybrid post-quantum):

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

// xBind uses ML-KEM-768 + X25519 hybrid key agreement internally
// Key agreement happens automatically during secure messaging
const alice = await Agent.quickstart({ name: 'alice' });
const bob = await Agent.quickstart({ name: 'bob' });

// Send establishes shared secret automatically
const result = await alice.send({
  to: bob.identity.did,
  payload: { type: 'greeting', text: 'Hello Bob!' }
});
if (result.ok) console.log('Message sent with PQ-secure encryption');

Graceful degradation:

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

// Agent automatically falls back to local cache if registry is unavailable
const agent = await Agent.quickstart({ name: 'resilient-agent' });
const peerDid = 'did:key:z6MkpeerKey123';
// Lookup uses registry with automatic fallback to cached entries
const result = await agent.discover('messaging');
if (result.ok) {
  console.log('Found services:', result.value.length);
}

Policy engine & guardrails:

import { getGlobalPolicyEngine } from '@private.me/xbind';
const engine = getGlobalPolicyEngine();
const agentDid = 'did:privateme:agent123';
const result = engine.evaluate(agentDid, 'stripe:createCharge', { amount: 100 }, {
  allowedTools: ['stripe:*'],
  maxAmountPerTransaction: 1000
});
if (!result.ok) console.error('Policy violation:', result.error);

Approval flow (OAuth-style consent):

import { ApprovalFlow } from '@private.me/xbind';
const flow = new ApprovalFlow();
const result = await flow.requestApproval({
  agentDid: 'did:privateme:agent123',
  scopes: ['read:data', 'write:messages'],
  duration: '1h'
});
if (result.ok && result.value.approved) {
  console.log('Approval granted:', result.value.token);
}

DID succession (key rotation):

import { Agent } from '@private.me/xbind';
const oldAgent = await Agent.quickstart({ name: 'old-identity' });
const result = await oldAgent.rotateDid({ reason: 'Scheduled key rotation' });
if (result.ok) {
  console.log('DID rotation successful');
}
oldAgent.cleanup();

Checkpoints (registry caching):

import { createCheckpoint, verifyCheckpoint } from '@private.me/xbind';
const subject = 'did:key:z6Mk...';
const publicKey = new Uint8Array(32);
const revoked = false;
const rotationSequence = 1;
const gatewayPrivateKey = new Uint8Array(32);
const result = await createCheckpoint(subject, publicKey, revoked, rotationSequence, gatewayPrivateKey);
if (result.ok) {
  const isValid = await verifyCheckpoint(result.value, new Uint8Array(32));
  console.log('Checkpoint valid:', isValid.ok);
}

Subscription proofs:

import { Agent, hashBloomFilter } from '@private.me/xbind';
const agent = await Agent.quickstart({ name: 'subscription-demo' });
const bloomData = new Uint8Array([1, 2, 3, 4, 5]);
const hashResult = hashBloomFilter(bloomData);
if (hashResult.ok) {
  console.log('Bloom filter hash:', hashResult.value);
}
agent.cleanup();

Progress tracking:

import { OperationProgressTracker } from '@private.me/xbind';
const tracker = new OperationProgressTracker((event) => {
  console.log(`${event.percent}% complete`);
});
tracker.startStage('processing', 50, 'Processing data');
tracker.updateStageProgress(25);

Service discovery (mDNS):

import { MdnsDiscoveryManager } from '@private.me/xbind';
const discovery = new MdnsDiscoveryManager();
const ownDid = 'did:key:z6Mk...';
const result = await discovery.scan(ownDid, 5000);
if (result.ok) {
  console.log('Found agents:', result.value.length);
}

Pairing manager (device pairing):

import { Agent } from '@private.me/xbind';
const agent = await Agent.quickstart({ name: 'device-a' });
const result = await agent.invite({
  email: '[email protected]',
  message: 'Join my secure channel'
});
if (result.ok) {
  console.log('Invitation sent successfully');
}

Lazy agent (deferred initialization):

import { createLazyAgent } from '@private.me/xbind';
const lazy = await createLazyAgent({ name: 'lazy', autoInit: false });
const result = await lazy.ensureInitialized();
if (result.ok) {
  console.log('Lazy agent initialized:', lazy.did);
}

See API-REFERENCE.md for complete export details and additional examples.

Documentation

  • White Paper: https://private.me/docs/xbind.html
  • Complete API: API-REFERENCE.md (all 72+ exports)
  • Migration Guide: MIGRATING.md
  • AI Integration: AGENTS.md
  • Platform: https://private.me (224 ACIs)
  • npm: https://www.npmjs.com/package/@private.me/xbind

Pricing

Free Tier: 100K operations/month with full platform access Pro Tier: Unlimited operations with SLA and priority support

See pricing details or internal reference.

Subscribe to xBind

Error Reference

All methods return Result<T, E> for type-safe error handling:

import { Agent } from '@private.me/xbind';
const agent = await Agent.quickstart({ name: 'sender' });
const result = await agent.send({
  to: 'did:key:z6MkpeerKey123',
  payload: { message: 'hello' },
  scope: 'test'
});
if (!result.ok) {
  console.error('Error:', result.error);
  // AgentError types: RECIPIENT_NOT_FOUND, DECRYPT_FAILED, etc.
}

Common error families:

  • RECIPIENT_*:** DID resolution errors
  • DECRYPT_FAILED*:** Decryption/key agreement errors
  • VERIFICATION_FAILED*:** Signature verification errors
  • ENVELOPE_FAILED*:** Message creation errors
  • SCOPE_DENIED: Authorization errors

Network Activity

This package makes network calls to:

  • Trust Registry (optional): DID resolution and trust management
  • Gateway Transport (optional): Message relay via Private.Me platform
  • Full Control (build-time only): Fetches algorithm completion for IP protection

All network activity is opt-in via configuration. Offline mode fully supported.

Privacy & Terms

  • Privacy Policy: https://private.me/privacy
  • Terms of Service: https://private.me/terms
  • Data Collection: Only when using Gateway transport (opt-in). See Network Activity section.

License

Proprietary - See LICENSE.md

Export Restrictions: Contains encryption subject to U.S. export control laws.

Support

Import Public Key

Import an external Ed25519 public key:

import { importPublicKey } from '@private.me/xbind';

const publicKeyBytes = new Uint8Array(32); // Your 32-byte Ed25519 public key
const result = await importPublicKey(publicKeyBytes);

if (!result.ok) throw new Error('Import failed');
const cryptoKey = result.value;
console.log('Public key imported');