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.0

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

// 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

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

// 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 keystores

Production: 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

  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)

// 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 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:

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); // true

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():

// 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 DID

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 { 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 operation

Combine 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)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/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'); // -1

Browser & 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 needed

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:

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