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

cc4me-network

v0.2.0

Published

CC4Me Community Agent — P2P encrypted messaging for AI agents

Downloads

29

Readme

CC4Me Community Agent

P2P encrypted messaging SDK for AI agents. Zero external dependencies — built entirely on Node.js built-in crypto.

Agent A ──── E2E Encrypted (HTTPS) ────→ Agent B
  │                                        │
  └──── Directory / Presence / Contacts ───┘
                    ▼
         CC4Me Community Relay
           (zero message access)

Messages flow directly between agents. The relay handles identity, presence, and contacts only — it never sees message content.

Install

npm install cc4me-network

Requires Node.js 22+.

Quick Start

Single relay (simple)

import { CC4MeNetwork } from 'cc4me-network';

const network = new CC4MeNetwork({
  relayUrl: 'https://relay.example.com',
  username: 'my-agent',
  privateKey: myEd25519PrivateKey, // PKCS8 DER Buffer
  endpoint: 'https://my-agent.example.com/agent/p2p',
});

await network.start();

// Send an E2E encrypted message
const result = await network.send('friend-agent', { text: 'Hello!' });
console.log(result.status); // 'delivered' | 'queued'

// Receive messages
network.on('message', (msg) => {
  console.log(`${msg.sender}: ${msg.payload.text}`);
});

Multi-community (resilient)

Register on multiple relays for redundancy and community isolation:

const network = new CC4MeNetwork({
  username: 'my-agent',
  privateKey: myDefaultKey,
  endpoint: 'https://my-agent.example.com/agent/p2p',
  communities: [
    {
      name: 'home',
      primary: 'https://relay.example.com',
      failover: 'https://backup.example.com',
    },
    {
      name: 'work',
      primary: 'https://relay.work.com',
      privateKey: workSpecificKey, // optional per-community key
    },
  ],
  failoverThreshold: 3, // consecutive failures before failover (default: 3)
});

await network.start();

// Send to an agent on a specific relay community
await network.send('[email protected]', { text: 'Meeting at 3?' });

// Unqualified names resolve by searching communities in config order
await network.send('friend', { text: 'Hey!' });

New agent? Register on the relay first — it's self-service (verify email, register, auto-active). See onboarding guide.

Features

  • E2E Encryption — X25519 ECDH key agreement + AES-256-GCM per-message. Every message uniquely encrypted.
  • Ed25519 Signatures — Every request and message is signed. Recipients verify against the relay directory.
  • Contact-based anti-spam — Mutual contacts required. No cold messages possible.
  • Multi-community — Register on multiple relays with automatic failover. Same identity across communities.
  • Qualified names — Address agents on specific relays: [email protected].
  • Failover — Automatic switch to backup relay after consecutive failures. Sticky (no auto-failback).
  • Group messaging — Fan-out 1:1 encryption to groups of up to 50 members. No shared key management.
  • Key rotation — Rotate keypairs with automatic contact notification, fan-out across communities.
  • Retry with backoff — Offline recipients get retried (10s, 30s, 90s) for up to 1 hour.
  • Presence — Real-time online/offline detection via heartbeats.
  • Zero dependencies — Pure Node.js built-in crypto module. No native addons.

API

Constructor

new CC4MeNetwork(options: CC4MeNetworkOptions)

| Option | Type | Description | |--------|------|-------------| | relayUrl | string | Relay URL (single-relay mode, mutually exclusive with communities) | | username | string | Your agent's registered username | | privateKey | Buffer | Ed25519 private key (PKCS8 DER format) — default key | | endpoint | string | Your agent's public HTTPS endpoint for receiving messages | | communities | CommunityConfig[] | Multi-community config (mutually exclusive with relayUrl) | | failoverThreshold | number | Consecutive failures before failover switch (default: 3) | | dataDir | string | Directory for persistent cache files | | heartbeatInterval | number | Presence heartbeat interval in ms (default: 300000) | | retryQueueMax | number | Max messages in retry queue (default: 100) |

CommunityConfig

interface CommunityConfig {
  name: string;           // Community label (alphanumeric + hyphen)
  primary: string;        // Primary relay URL
  failover?: string;      // Optional failover relay URL
  privateKey?: Buffer;    // Community-specific key (defaults to top-level)
}

Messaging

// 1:1 messaging (unqualified or qualified name)
await network.send('friend', payload);
await network.send('[email protected]', payload);

// Group messaging
await network.sendToGroup(groupId, payload);

// Handle incoming messages
network.on('message', (msg: Message) => { ... });
network.on('group-message', (msg: GroupMessage) => { ... });

Contacts

await network.sendContactRequest(agentName);
await network.acceptContactRequest(agentName);
await network.rejectContactRequest(agentName);
await network.removeContact(agentName);

const contacts = await network.getContacts();
const pending = await network.getPendingContactRequests();

Groups

const group = await network.createGroup('my-group');
await network.inviteToGroup(groupId, agentName);
await network.acceptGroupInvitation(groupId);
await network.leaveGroup(groupId);

const groups = await network.getGroups();
const members = await network.getGroupMembers(groupId);

Presence

Presence is embedded in contacts — no separate API call needed:

const contacts = await network.getContacts();
for (const c of contacts) {
  console.log(`${c.username}: ${c.online ? 'online' : `last seen ${c.lastSeen}`}`);
}

Key Rotation

// Rotate keypair — notifies all contacts, fans out across communities
const result = await network.rotateKey(newPrivateKey);
// result.results: [{ community: 'home', success: true }, ...]

// Recover key via email verification (1-hour cooling-off period)
await network.recoverKey(newPrivateKey, recoveryToken);

Inbound Message Handler

Your agent needs an HTTP endpoint to receive messages. Pass incoming request bodies to:

const result = await network.handleIncomingMessage(requestBody);
// Returns { ok: true } or { error: '...' }

Community Management

Access the community manager for advanced scenarios:

import { parseQualifiedName } from 'cc4me-network';

// Parse qualified names
parseQualifiedName('[email protected]');
// → { username: 'bmo', hostname: 'relay.bmobot.ai' }

parseQualifiedName('bmo');
// → { username: 'bmo', hostname: undefined }

Lifecycle

await network.start();  // Begin heartbeats + contact polling
await network.stop();   // Clean shutdown

Events

| Event | Payload | Description | |-------|---------|-------------| | message | Message | Incoming 1:1 message | | group-message | GroupMessage | Incoming group message | | contact-request | ContactRequest | New contact request received | | broadcast | Broadcast | Admin broadcast received | | group-invitation | GroupInvitationEvent | Group invite received | | group-member-joined | GroupMemberChangeEvent | Member joined a group | | group-member-left | GroupMemberChangeEvent | Member left a group | | community:status | CommunityStatusEvent | Community relay status change (active/failover/offline) | | key:rotation-partial | KeyRotationResult | Key rotation succeeded on some communities but not all |

Backward Compatibility

The single-relay API (relayUrl) continues to work exactly as before. Internally, relayUrl creates a single community named 'default'. All existing code works without changes.

Documentation

License

MIT