@private.me/xbind
v3.2.1
Published
Identity-based M2M authentication (Contains encryption - export restrictions apply)
Maintainers
Readme
@private.me/xbind
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/xbindPython:
pip install private-me-xbindOffline 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, transportsRegistry
// TrustRegistry: register(), resolve(), isTrusted(), revoke()
// Built-in: MemoryTrustRegistry, HttpTrustRegistryTransports
// HttpsTransportAdapter, LoopbackTransport, GatewayTransport
// Adapters: RetryTransportAdapter, DualModeAdapterCLI
npx xbind init # Interactive setup
npx xbind --version # Show versionSubpaths:
@private.me/xbind/agent—Agent,generateSharedKey,parseAgentError@private.me/xbind/identity—generateIdentity,sign,verify,publicKeyToDid,didToPublicKeyBytes, and more@private.me/xbind/trust-registry—MemoryTrustRegistry,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 timeoutXBIND_TIMEOUT_GATEWAY- Gateway operation timeoutXBIND_TIMEOUT_REGISTRY- Registry operation timeoutXBIND_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 keystoresProduction: 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
- Encrypt at Rest: Use AES-256-GCM with a separate encryption key
- Least Privilege: Only the agent process should access the seed
- Rotation: Plan for key rotation (see Succession API)
- Backup: Encrypted backups to separate storage (3-2-1 rule)
- 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_historyIncident Response
If your seed is compromised:
- Revoke immediately: Use the Succession API to rotate to a new identity
- Audit access: Check all messages sent/received during exposure window
- Notify recipients: Inform peers to distrust the old DID
- 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
actionfield: Theactionparameter inAgentSendOptionsis 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:
- Generate seed:
crypto.getRandomValues(new Uint8Array(32)) - Store original seed in secure storage (keychain, vault, encrypted database)
- Create agent:
Agent.fromSeed(storedSeed, {...}) - 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); // truePost-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 timerTransports
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)→Uint8ArrayparseAgentError(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()→ throwsConfigValidationErrorassertValidConfig()→ throws on invalid configpublicKeyToDid()→ 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'); // -1Browser & 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 commandsNonce 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.
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
- Issues: https://github.com/anthropics/private-me/issues
- Email: [email protected]
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');