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

relays

v1.0.3

Published

A combined nostr and GUN relay

Readme

Peer Relay - Cloudflare Edition

A combined Nostr and GUN relay deployed on Cloudflare Workers + Durable Objects for serverless, globally-distributed relay infrastructure.

Features

  • Nostr Relay (NIP-01): WebSocket-based event pub/sub via Durable Objects
  • GUN Relay: P2P graph database synchronization via Durable Objects
  • Serverless: Deployed on Cloudflare Workers (no server management)
  • Global: Automatic Cloudflare edge distribution
  • Scalable: Durable Objects handle persistent state and connections

Deployment

Prerequisites

  • Cloudflare account with Workers enabled
  • Wrangler CLI installed: npm install -g wrangler
  • Node.js 18+

Quick Deploy

cd worker
npm install
wrangler deploy

The Worker will be deployed to: https://relay-nostr-gun.draeder.workers.dev

Access via: relay.peer.ooo

Usage

Nostr Relay

WebSocket Endpoint: wss://relay.peer.ooo/

Connect with any Nostr client:

import { relayInit } from 'nostr-tools';

const relay = relayInit('wss://relay.peer.ooo/');
await relay.connect();

// Subscribe to events
let sub = relay.sub([{ kinds: [1] }]);
sub.on('event', event => {
  console.log('Received event:', event);
});

// Publish an event
const event = await signEvent({
  kind: 1,
  content: 'Hello, Nostr!',
  created_at: Math.floor(Date.now() / 1000),
  tags: []
});
relay.publish(event);

Supported NIPs: NIP-01 (Event handling)

GUN Relay

WebSocket Endpoint: wss://relay.peer.ooo/gun

Connect with GUN clients:

const Gun = require('gun');
const gun = Gun(['wss://relay.peer.ooo/gun']);

// Store data
gun.get('greeting').put({ message: 'Hello, GUN!' });

// Read data
gun.get('greeting').on((data) => {
  console.log(data);
});

Info Endpoint

HTTP GET https://relay.peer.ooo/

Returns NIP-11 relay metadata:

{
  "name": "Peer Relay (Cloudflare)",
  "description": "Nostr relay on Cloudflare Durable Objects + GUN relay",
  "pubkey": "",
  "contact": "",
  "supported_nips": [1, 11],
  "software": "combined-relay-worker",
  "version": "1.0.0"
}

Architecture

                   Cloudflare Edge
        ┌──────────────────────────────┐
        │    Worker (HTTP Router)      │
        ├──────────┬───────────────────┤
        │          │                   │
        │  /       │        /gun        │
        │  │       │        │           │
        ├──┼───────┼────────┼─────────┤
        │  ▼       │        ▼         │
        │ NOSTR_RELAY      GUN_RELAY │
        │ (Durable Object) (Durable  │
        │                  Object)   │
        │                            │
        └────────────────────────────┘
             Persistent State

Development

Local Testing

cd worker

# Install dependencies
npm install

# Run tests (requires WebSocket support)
node test-nostr-valid.js

Project Structure

worker/
├── src/
│   └── worker.js          # Main Worker + Durable Object classes
├── wrangler.toml          # Cloudflare Worker config
└── package.json

Security Notes

  • No hardcoded secrets: All configuration via environment variables (if needed)
  • Signature validation: Nostr events are validated (ID hash checked)
  • Event storage: Ephemeral in-memory storage (resets on DO restart)
  • Database: GUN uses DO storage (persistent within the namespace)

Secrets Management

If you need to add API keys or secrets:

  1. Store in Cloudflare Dashboard: Workers > Settings > Environment Variables
  2. Access in code via env.SECRET_NAME
  3. Never commit secrets to Git

Example:

export default {
  async fetch(request, env) {
    const apiKey = env.MY_API_KEY; // Never hardcode this
  }
};

Performance

  • Nostr relay: ~1000 events in-memory per instance
  • GUN relay: Uses Durable Objects persistent storage
  • Latency: Global edge distribution via Cloudflare
  • Concurrency: Unlimited concurrent WebSocket connections

Limitations

  • Nostr events stored in-memory (ephemeral)
  • Basic Nostr validation (no signature verification for performance)
  • GUN relay is basic (get/put operations only)

Future Improvements

  • [ ] Persistent event storage (R2 or D1)
  • [ ] Full signature verification
  • [ ] Event filtering (NIP-01 compliance)
  • [ ] Relay authentication (NIP-42)
  • [ ] Better GUN protocol support

Troubleshooting

WebSocket connection fails (400 error)

  • Ensure you're connecting with Upgrade: websocket header
  • Verify endpoint URL is correct

Events not stored

  • Durable Objects may restart, clearing in-memory storage
  • For persistence, implement D1 database integration

Slow performance

  • Check Cloudflare dashboard for errors
  • Verify DNS is pointing to correct Worker

Links

License

MIT License - See LICENSE file for details