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

@anycast/agent

v0.1.20

Published

TypeScript SDK for Anycast Agents P2P connectivity

Readme

@anycast/agent

TypeScript SDK for Anycast Agents P2P connectivity.

Connect agents to the Anycast network for peer-to-peer communication with relay fallback, powered by the global Anycast edge infrastructure.

Installation

npm install @anycast/agent
# or
pnpm add @anycast/agent

Quick Start

import { AnycastAgent } from '@anycast/agent';

const agent = new AnycastAgent({
  rendezvousUrl: 'wss://agents.anycast.com/rendezvous',
  token: 'agt_your_token_here',
});

agent.on('connect', ({ agentId }) => {
  console.log(`Connected as ${agentId}`);
});

agent.on('peer', (peerId, status) => {
  console.log(`Peer ${peerId} is ${status}`);
});

agent.on('error', (err) => {
  console.error(`Error: ${err.message} (${err.code})`);
});

await agent.connect();

// Request a connection to another agent
const sessionId = agent.requestConnection('target-agent-id');

// Handle incoming WebRTC signals
agent.on('signal', (sessionId, fromAgentId, signal) => {
  // Forward to your WebRTC implementation
});

// Send WebRTC signals
agent.sendSignal(sessionId, 'target-agent-id', {
  type: 'offer',
  data: JSON.stringify(sdpOffer),
});

// Disconnect when done
await agent.disconnect();

API Reference

new AnycastAgent(options)

Create a new agent instance.

| Option | Type | Default | Description | |--------|------|---------|-------------| | rendezvousUrl | string | required | WebSocket URL of the rendezvous server | | token | string | required | Agent auth token from the Anycast portal | | machineId | string | auto-generated | Unique machine identifier | | publicKey | string | auto-generated | Public key for E2E encryption | | version | string | — | Agent version string | | reconnect | boolean | true | Auto-reconnect on disconnect | | reconnectInterval | number | 3000 | Base reconnect interval (ms) | | timeout | number | 30000 | Connection timeout (ms) | | heartbeatInterval | number | 25000 | Heartbeat interval (ms) | | discoveryMode | string | 'rendezvous' | Discovery mode: rendezvous, auto, or dht |

Properties

| Property | Type | Description | |----------|------|-------------| | agentId | string \| null | Assigned agent ID (set after connect) | | tenantId | string \| null | Tenant ID (set after connect) | | connected | boolean | Whether the agent is connected | | connectionState | ConnectionState | Current connection state |

Methods

connect(): Promise<void>

Connect to the rendezvous server. Resolves when registered.

disconnect(): Promise<void>

Disconnect from the server.

requestConnection(targetAgentId: string): string

Request a P2P connection to another agent. Returns a session ID.

sendSignal(sessionId, targetAgentId, signal)

Send a WebRTC signal (offer/answer/ICE candidate) via the rendezvous server.

disconnectSession(sessionId: string)

Close a specific session.

Events

| Event | Payload | Description | |-------|---------|-------------| | connect | { agentId, tenantId, name } | Connected and registered | | disconnect | reason: string | Disconnected | | reconnecting | attempt: number | Attempting reconnection | | peer | agentId, status | Peer came online/offline | | connect_incoming | sessionId, fromAgentId, fromAgentName | Incoming connection request | | connect_accepted | sessionId, agentId, publicKey | Connection accepted by peer | | connect_rejected | sessionId, reason | Connection rejected | | signal | sessionId, fromAgentId, signal | WebRTC signal from peer | | relay_assigned | sessionId, host, port, token | Relay server assigned | | error | AnycastError | Error occurred | | stateChange | ConnectionState | Connection state changed | | discovery | { mode, fallback } | Discovery mode resolved (emitted before connect) |

ConnectionState

enum ConnectionState {
  DISCONNECTED = 'DISCONNECTED',
  CONNECTING = 'CONNECTING',
  CONNECTED = 'CONNECTED',
  RECONNECTING = 'RECONNECTING',
}

AnycastError

class AnycastError extends Error {
  code: string;    // Error code (e.g., 'AUTH_FAILED', 'TIMEOUT')
  fatal: boolean;  // If true, reconnection won't help
}

Usage Tracking & Auto-Instrumentation

Track LLM token usage through the Anycast portal for cost visibility and analytics.

Manual tracking

await agent.trackUsage({
  model: 'claude-sonnet-4-6',
  promptTokens: 1200,
  completionTokens: 340,
  triggeredBy: 'user-123',
  context: 'slack_thread',
});

Anthropic SDK (automatic)

import Anthropic from '@anthropic-ai/sdk';

const anthropic = agent.wrapAnthropic(new Anthropic(), {
  triggeredBy: 'user-123',
  context: 'slack_thread',
});
// All calls now auto-report usage — no code changes needed
const msg = await anthropic.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Hello' }],
});

OpenAI SDK (automatic)

import OpenAI from 'openai';

const openai = agent.wrapOpenAI(new OpenAI(), { context: 'api' });
const chat = await openai.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: 'Hello' }],
});

Generic wrapper

const result = await agent.tracked(
  () => myLlmCall(prompt),
  {
    model: 'custom-model',
    extractUsage: (r) => ({
      promptTokens: r.usage.input,
      completionTokens: r.usage.output,
    }),
  }
);

All tracking is opt-in, non-blocking, and never affects the return value or throws.

Discovery Modes

The SDK supports three discovery modes, controlled via the discoveryMode option:

| Mode | Description | |------|-------------| | rendezvous | (default) Connects through the managed Anycast rendezvous server. Most reliable, works everywhere, no extra dependencies. | | auto | Tries DHT (Holepunch) first for direct peer-to-peer discovery. Falls back to rendezvous if hyperswarm is not installed or DHT fails. | | dht | DHT only via Holepunch. Requires hyperswarm (npm install hyperswarm). Throws if the dependency is missing. Experimental. |

const agent = new AnycastAgent({
  rendezvousUrl: 'wss://agents.anycast.com/rendezvous',
  token: 'agt_xxx',
  discoveryMode: 'auto', // try DHT, fall back to rendezvous
});

agent.on('discovery', ({ mode, fallback }) => {
  console.log(`Using ${mode} discovery${fallback ? ' (fallback)' : ''}`);
});

await agent.connect();

For the Go binary (any), use --discovery-mode:

any up --token agt_xxx --expose localhost:8080 --discovery-mode auto
# or via environment variable:
ANY_DISCOVERY_MODE=dht any up --token agt_xxx --expose localhost:8080

Auto-Reconnection

By default, the agent automatically reconnects with exponential backoff (3s, 6s, 12s, ..., max 30s). Disable with reconnect: false.

Receiving Messages from the Platform

Flows and integrations can send messages directly to your agent and await a reply. Handle incoming messages with the message event:

agent.on('message', async ({ text, context, reply }) => {
  // Process the message — you have 30 seconds to reply
  const response = await handleQuery(text);
  reply(response);
});

The reply() function must be called within the timeout window (default 30 seconds). After that, the platform marks the delivery as timed out and the response is discarded.

You can also reply manually using the messageId:

agent.on('message', ({ messageId, text }) => {
  processAsync(text).then((result) => {
    agent.replyToMessage(messageId, result);
  });
});

The context field contains metadata from the triggering flow (e.g. Slack channel, thread timestamp, flow ID).

License

MIT