@private.me/xbind
v3.2.0
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
// 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 repositoryWhy 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
// Cross-platform: keytar package (macOS Keychain, Windows Credential Manager, Linux Secret Service)
import keytar from 'keytar';
// Store seed securely
await keytar.setPassword('xbind', 'agent-seed', seed);
// Retrieve seed securely
const seed = await keytar.getPassword('xbind', 'agent-seed');
if (!seed) throw new Error('Seed not found in credential store');
const agent = await Agent.fromSeed(seed);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 { KMSClient, DecryptCommand } from '@aws-sdk/client-kms';
const kms = new KMSClient({ region: 'us-west-2' });
// Decrypt seed with KMS at runtime (encrypted seed stored in database)
const decryptedSeed = await kms.send(new DecryptCommand({
CiphertextBlob: encryptedSeedFromDB
}));
const agent = await Agent.fromSeed(decryptedSeed.Plaintext.toString());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)
// Agent A creates invite
const invite = await agentA.invite.create({ name: 'Alice', expiresIn: 3600 });
console.log('Share code:', invite.code); // "ABC-DEF-GHI"
// Agent B accepts invite
const result = await agentB.invite.accept(invite.code);2. QR Code (Person → Person, Offline)
// Agent A generates QR code data
const qrData = await agentA.invite.createQR({ name: 'Alice' });
// Display QR code to user
// Agent B scans QR code
const result = await agentB.invite.acceptQR(qrData);3. Trust Registry (System → System)
// Pre-registered agents in trust registry
const registry = new HttpTrustRegistry({
baseUrl: 'https://private.me/aci/registry'
});
// Auto-trust registered agents
const result = await agent.send({
to: 'did:key:z6Mk...', // Must be in registry
payload: { action: 'process' },
scope: 'production'
});4. Peer Discovery (Local Network, mDNS)
// Enable mDNS discovery
const discovery = new MdnsDiscovery({
serviceName: 'my-agent',
port: 3000
});
await discovery.start();
// Discover peers on local network
const peers = await discovery.findPeers();See Entity-to-Entity Connection UX for complete specifications.
Version
Current: v3.2.0 (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';
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) agent = result.value;AI-first wrapper (AgentBuilder):
import { AgentBuilder } from '@private.me/xbind';
const result = await AgentBuilder.create({ name: 'svc', ttl: 3600000 });Send encrypted message:
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);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:
const messages = await agent.receive({ scope: 'test', limit: 10 });
for (const msg of messages) {
console.log('From:', msg.from, 'Payload:', msg.payload);
}Identity & Cryptography
Generate new identity:
import { generateIdentity } from '@private.me/xbind/identity';
const identity = await generateIdentity();
console.log('DID:', identity.did);Reuse existing identity (persistent agents):
import { Agent } from '@private.me/xbind';
// Important: Agent.create() always generates NEW identity
// To reuse an identity, use Agent.fromParts() or Agent.fromIdentity()
// Method 1: fromParts (no registry registration)
const agent = Agent.fromParts(existingIdentity, registry, transport, {
name: 'my-persistent-agent'
});
// Method 2: fromIdentity (with registry check)
const result = await Agent.fromIdentity(existingIdentity, {
registry,
transport,
name: 'my-persistent-agent'
});
// Same DID across restarts
console.log('Agent DID:', agent.did);Seed-based agents (deterministic identity):
import { Agent } 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 agent = await Agent.fromSeed(seed, {
name: 'deterministic-agent',
registry: new MemoryTrustRegistry(),
transport: mockTransport
});
// Later: Restore agent with SAME seed
const restoredAgent = await Agent.fromSeed(storedSeed, {
name: 'deterministic-agent',
registry: new MemoryTrustRegistry(),
transport: mockTransport
});
// Same DID because same seed
console.log(agent.value.did === restoredAgent.value.did); // trueWARNING: exportSeeds() is NOT compatible with fromSeed()
The exportSeeds() method returns HKDF-derived keys, not the original seed. You cannot use exportSeeds() output with fromSeed():
// WRONG: This will NOT work
const agent = await Agent.fromSeed(originalSeed, {...});
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 seed = crypto.getRandomValues(new Uint8Array(32));
await persistToSecureStorage(seed); // ← Store original seed
const agent = await Agent.fromSeed(seed, {...});
// Later: Restore with original seed
const restored = await Agent.fromSeed(seed, {...}); // ✅ Same DIDWhy 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 { exportPKCS8, exportX25519PKCS8, importIdentity } from '@private.me/xbind/identity';
// Export PKCS8 (can be used for restore)
const edPkcs8 = await exportPKCS8(agent.identity.privateKey);
const x25519Pkcs8 = await exportX25519PKCS8(agent.identity.x25519PrivateKey);
// Later: Restore from PKCS8
const restored = await importIdentity(edPkcs8.value, x25519Pkcs8.value);
const restoredAgent = Agent.fromParts(restored.value, registry, transport);Sign and verify (Ed25519):
import { sign, verify } from '@private.me/xbind/identity';
const message = new TextEncoder().encode('Hello');
const signature = await sign(identity.privateKey, message);
const valid = await verify(identity.publicKey, message, signature);Post-quantum signatures (ML-DSA-65):
import { signMlDsa65, verifyMlDsa65 } from '@private.me/xbind/identity';
const pqSig = await signMlDsa65(identity.mlDsaPrivateKey, message);
const pqValid = await verifyMlDsa65(identity.mlDsaPublicKey, message, pqSig);DID conversions:
import { publicKeyToDid, didToPublicKeyBytes } from '@private.me/xbind/identity';
const did = publicKeyToDid(publicKeyBytes);
const pubKey = didToPublicKeyBytes(did);Key rotation with succession:
import { rotateKeys } from '@private.me/xbind';
const newIdentity = await rotateKeys(agent.identity);Envelopes
Create encrypted envelope:
import { createEnvelope } from '@private.me/xbind';
const envelope = await createEnvelope({
from: senderIdentity,
to: recipientDid,
payload: { message: 'Hello' }
});Decrypt envelope payload:
import { decryptPayload } from '@private.me/xbind';
const payload = await decryptPayload(envelope, recipientIdentity);Serialize/deserialize:
import { serializeEnvelope, deserializeEnvelope } from '@private.me/xbind';
const wireFormat = serializeEnvelope(envelope);
const parsed = deserializeEnvelope(wireFormat);Signed cleartext envelopes:
import { createSignedEnvelope, openSignedEnvelope } from '@private.me/xbind';
const signed = await createSignedEnvelope(identity, { data: 'public' });
const verified = await openSignedEnvelope(signed);Trust Registry
In-memory registry (testing):
import { MemoryTrustRegistry } from '@private.me/xbind';
const registry = new MemoryTrustRegistry();
await registry.register({
did: agent.did,
publicKey: agent.identity.rawPublicKey,
name: agent.name
});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/trust-registry';
const rateLimiter = new RegistrationRateLimiter({ maxPerHour: 100 });
const registry = createEnterpriseTrustRegistry({ rateLimiter });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({ endpoint: 'https://private.me/aci/relay' });Retry adapter with exponential backoff:
import { RetryTransportAdapter, ExponentialBackoffStrategy } from '@private.me/xbind';
const strategy = new ExponentialBackoffStrategy({ maxRetries: 3 });
const transport = new RetryTransportAdapter(baseTransport, { strategy });Circuit breaker:
import { CircuitBreaker } from '@private.me/xbind';
const breaker = new CircuitBreaker({ threshold: 5, timeout: 60000 });Timeouts & Cancellation
Timeout configuration:
import { createTimeoutController, withTimeout } from '@private.me/xbind';
const controller = createTimeoutController({ send: 5000 });
const result = await withTimeout(agent.send({...}), 5000);Cancellation:
import { createCancellationController, withCancellation } from '@private.me/xbind';
const controller = createCancellationController();
const promise = withCancellation(longRunningOp(), controller.signal);
controller.cancel(); // Abort operationCombine signals:
import { combineSignals, createTimeoutSignal } from '@private.me/xbind';
const timeout = createTimeoutSignal(5000);
const combined = combineSignals([userSignal, timeout]);Batch Operations
Batch send:
import { batchSend } from '@private.me/xbind';
const messages = [
{ to: 'did:key:z6Mk...', payload: { msg: 1 } },
{ to: 'did:key:z6Mk...', payload: { msg: 2 } }
];
const results = await batchSend(agent, messages);Batch registry operations:
import { batchRegistryOps } from '@private.me/xbind';
const ops = [
{ op: 'register', did: 'did:key:...', pubKey: key1 },
{ op: 'resolve', did: 'did:key:...' }
];
const results = await batchRegistryOps(registry, ops);Async Iterators
Message stream:
import { MessageStream } from '@private.me/xbind';
const stream = new MessageStream(agent, { scope: 'test' });
for await (const msg of stream) {
console.log('Message:', msg.payload);
if (shouldStop) break;
}Stream utilities:
import { mapStream, filterStream, takeStream } from '@private.me/xbind';
const mapped = mapStream(stream, msg => msg.payload);
const filtered = filterStream(stream, msg => msg.scope === 'important');
const limited = takeStream(stream, 10);DID Methods
did:privateme format:
import { publicKeyToPrivateMeDid, privateMeDidToPublicKeyBytes } from '@private.me/xbind';
const privateMeDid = publicKeyToPrivateMeDid(publicKeyBytes);
const pubKey = privateMeDidToPublicKeyBytes(privateMeDid);DID format conversion:
import { convertDidFormat, normalizeDid } from '@private.me/xbind';
const converted = convertDidFormat('did:key:z6Mk...', 'privateme');
const normalized = normalizeDid(did);did:web resolution:
import { DidWebResolver, resolveDid } from '@private.me/xbind';
const resolver = new DidWebResolver();
const didDoc = await resolveDid('did:web:example.com', resolver);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 } from '@private.me/xbind';
import type { Result, AgentError } from '@private.me/xbind';
const result: Result<Agent, AgentError> = await Agent.create({
name: 'my-agent',
scopes: ['read:data']
});
if (result.ok) {
const agent = result.value;
console.log('Agent created:', agent.did);
} else {
const error = result.error; // AgentError type
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 { publicKeyToDid, didToPublicKeyBytes } from '@private.me/xbind/identity';
// Infallible transformation (throws on invalid input)
const did = publicKeyToDid(rawPublicKey); // Returns string or throws
// 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/identity';
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 { enableDebugMode, generateDebugReport } from '@private.me/xbind';
enableDebugMode({ networkTracing: true, cryptoTracing: true });
// ... run operations
const report = generateDebugReport();
console.log(report);Correlation IDs:
import { generateCorrelationId, attachCorrelationId } from '@private.me/xbind';
const correlationId = generateCorrelationId();
const request = attachCorrelationId(request, correlationId);Structured logging:
import { createLogger, LogLevel } from '@private.me/xbind';
const logger = createLogger({ level: LogLevel.INFO });
logger.info('Operation started', { correlationId });Health checks:
import { createHealthChecker } from '@private.me/xbind';
const checker = createHealthChecker(agent);
const health = await checker.check();
console.log('Status:', health.status, 'Checks:', health.checks);Version & Capabilities
Version info:
import { getVersion, hasCapability, Capability } from '@private.me/xbind';
console.log('Version:', getVersion());
if (hasCapability(Capability.ML_KEM_768)) {
console.log('Post-quantum KEM supported');
}Compatibility checks:
import { checkCompatibility, compareVersions } from '@private.me/xbind';
const compatible = checkCompatibility('x.y.z', 'x.y.z+1');
const comparison = compareVersions('older', 'newer'); // -1Browser & Runtime
Runtime detection:
import { detectRuntime, isBrowser, isNode } from '@private.me/xbind/runtime';
const runtime = detectRuntime();
if (isBrowser()) {
console.log('Running in browser');
}Browser storage:
import { LocalStorageAdapter, IndexedDBAdapter } from '@private.me/xbind/runtime';
const storage = new LocalStorageAdapter();
await storage.set('key', 'value');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 { ConnectionPool, getGlobalPool } from '@private.me/xbind';
const pool = getGlobalPool();
const conn = await pool.acquire();Serialization formats:
import { serialize, deserialize, detectFormat } from '@private.me/xbind';
const msgpack = serialize(data, 'msgpack');
const deserialized = deserialize(msgpack);Event emitter:
import { XBindEventEmitter } from '@private.me/xbind';
const emitter = new XBindEventEmitter();
emitter.on('message', (msg) => console.log('Received:', msg));Backup & restore:
import { exportBackup, importBackup } from '@private.me/xbind';
const backup = await exportBackup(agent.identity, 'password');
const restored = await importBackup(backup, 'password');Split-channel operations:
import { splitForChannel, reconstructFromChannel } from '@private.me/xbind';
const shares = await splitForChannel(secret, 2, 3);
const reconstructed = await reconstructFromChannel(shares.slice(0, 2));CLI commands:
import { cliMain } from '@private.me/xbind/cli';
await cliMain(process.argv);import { initCommand } from '@private.me/xbind/cli';
await initCommand({ interactive: true });Nonce stores (replay attack prevention):
import { MemoryNonceStore } from '@private.me/xbind';
const nonceStore = new MemoryNonceStore();
await nonceStore.add('nonce123', Date.now() + 60000);import { RedisNonceStore } from '@private.me/xbind';
const redisNonce = new RedisNonceStore({ url: 'redis://localhost:6379' });Key agreement (hybrid post-quantum):
import { senderHybridKeyAgreement, receiverHybridKeyAgreement } from '@private.me/xbind';
const senderResult = await senderHybridKeyAgreement(senderIdentity, recipientPublicKey);
const sharedSecret = await receiverHybridKeyAgreement(recipientIdentity, senderPublicKey, senderResult.ciphertext);Graceful degradation:
import { registryLookupWithFallback } from '@private.me/xbind';
const did = await registryLookupWithFallback(primaryRegistry, fallbackRegistry, targetDid);Policy engine & guardrails:
import { PolicyEngine, getGlobalPolicyEngine } from '@private.me/xbind';
const engine = getGlobalPolicyEngine();
await engine.enforce({ action: 'send', scope: 'sensitive-data' });Approval flow (OAuth-style consent):
import { ApprovalFlow } from '@private.me/xbind';
const flow = new ApprovalFlow({ presenter: 'cli' });
const approved = await flow.requestApproval({ scopes: ['read:data'], requester: 'app' });DID succession (key rotation):
import { createSuccession, verifySuccession } from '@private.me/xbind';
const succession = await createSuccession(oldIdentity, newIdentity);
const valid = await verifySuccession(succession);Checkpoints (registry caching):
import { createCheckpoint, verifyCheckpoint } from '@private.me/xbind';
const checkpoint = await createCheckpoint(registryData, identity);
const isValid = await verifyCheckpoint(checkpoint);Subscription proofs:
import { createSubscriptionProof, verifySubscriptionProof } from '@private.me/xbind';
const proof = await createSubscriptionProof(deploymentId, tier, signature);
const verified = await verifySubscriptionProof(proof);Progress tracking:
import { OperationProgressTracker } from '@private.me/xbind';
const tracker = new OperationProgressTracker();
tracker.on('progress', (event) => console.log(`${event.percent}% complete`));Service discovery (mDNS):
import { MdnsDiscoveryManager } from '@private.me/xbind';
const discovery = new MdnsDiscoveryManager();
const agents = await discovery.discover({ timeout: 5000 });Pairing manager (device pairing):
import { PairingManager } from '@private.me/xbind';
const pairing = new PairingManager(agent);
const invite = await pairing.createInvite({ expiresIn: 3600000 });Lazy agent (deferred initialization):
import { createLazyAgent } from '@private.me/xbind';
const lazy = createLazyAgent({ name: 'lazy', autoInit: false });
await lazy.init(); // Initialize when neededSee 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:
const result = await agent.send({...});
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]
