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

@vbyte/nostr-sdk

v1.0.1

Published

Software development kit for the nostr protocol.

Readme

@vbyte/nostr-sdk

npm version License: MIT

A TypeScript SDK for the Nostr protocol.

Features

  • Single relay connections - NostrSocket for connecting to individual relays.
  • Multi-relay aggregation - NostrClient for managing multiple relay connections.
  • Peer-to-peer communication - NostrNode for encrypted RPC messaging between peers.
  • Health monitoring and keep-alive - For socket connections and subscriptions.
  • Rate-limited message queuing - Prevents spamming nodes with events (and getting banned from the relay).
  • Event de-duplication - O(1) cache for filtering duplicate events from multiple subscriptions.
  • TypeScript-first - Full type definitions included
  • Zod schema validation - Runtime validation for events and messages

Installation

npm install @vbyte/nostr-sdk
pnpm add @vbyte/nostr-sdk

Note: The ws package is a peer dependency for Node.js environments.

Quick Start

Connect to a Single Relay

import { NostrSocket, CRYPTO, LIB } from '@vbyte/nostr-sdk'

// Create socket and connect
const socket = new NostrSocket('wss://relay.example.com')
await socket.connect()

// Generate keys
const seckey = CRYPTO.gen_seckey()
const pubkey = CRYPTO.get_pubkey(seckey)

// Create and sign an event
const template = LIB.create_event({
  kind: 1,
  content: 'Hello Nostr!',
  pubkey
})
const event = LIB.sign_event(template, seckey)

// Publish the event
await socket.publish(event)

// Close connection
socket.close()

Subscribe to Events

const sub = await socket.subscribe({ kinds: [1], limit: 10 })

sub.on('event', (event) => console.log(event))

Query Events

const events = await socket.query({ kinds: [1], limit: 10 })
console.log(events)

Multi-Relay Client

import { NostrClient } from '@vbyte/nostr-sdk'

const client = new NostrClient([
  'wss://relay1.example.com',
  'wss://relay2.example.com'
])
await client.connect()

// Publish to all relays (resolves on first success)
await client.publish(event)

// Subscribe with automatic deduplication
const sub = client.subscribe({ kinds: [1] })
sub.on('event', (event) => console.log(event))

// Close all connections
client.close()

P2P Node

import { NostrNode, CRYPTO } from '@vbyte/nostr-sdk'

// Generate keys for two peers
const aliceSecret = CRYPTO.gen_seckey()
const alicePubkey = CRYPTO.get_pubkey(aliceSecret)
const bobPubkey = '...' // Bob's public key

// Create node with peer list
const node = new NostrNode(
  [bobPubkey],                    // Peers to communicate with
  ['wss://relay.example.com'],    // Relay URLs
  aliceSecret                     // Your secret key
)

// Connect and start listening
await node.connect()

// Handle incoming messages
node.on('message', (msg) => {
  if (msg.type === 'request') {
    console.log(`Request from ${msg.event.pubkey}: ${msg.method}`)
    // Respond to requests
    node.respond(msg).accept({ result: 'ok' })
  }
})

// Send request to a peer
const response = await node.request(
  { method: 'ping' },
  bobPubkey,
  { timeout: 5000 }
)

// Broadcast to all peers
node.announce({ topic: 'status', data: { online: true } }, [bobPubkey])

// Close node
node.close()

API Reference

NostrSocket

Single WebSocket connection to a Nostr relay.

Constructor

new NostrSocket(url: string, options?: Partial<NostrSocketConfig>)

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | max_retries | number | 3 | Max reconnection attempts | | queue_ival | number | 500 | Queue processing interval (ms) | | queue_limit | number | 10 | Messages per queue batch | | msg_timeout | number | 5000 | Message response timeout (ms) | | sub_timeout | number | 30000 | Subscription EOSE timeout (ms) |

Methods

| Method | Returns | Description | |--------|---------|-------------| | connect() | Promise<void> | Establish connection | | publish(event) | Promise<PublishResponse> | Publish signed event | | subscribe(filters) | NostrSubscription | Create persistent subscription | | query(filters, duration?) | Promise<SignedEvent[]> | One-shot event query | | close(delay?) | void | Close connection | | send(msg) | void | Send message via queue |

Events

| Event | Payload | Description | |-------|---------|-------------| | ready | NostrSocket | Connection established | | closed | NostrSocket | Connection closed | | error | string | Error occurred | | message | RelayMessage | Relay message received | | notice | string | NOTICE message from relay | | receipt | RelayReceiptMessage | OK receipt for published event |

NostrClient

Multi-relay client with event deduplication.

Constructor

new NostrClient(relays: string[], options?: Partial<NostrClientConfig>)

Additional Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | cache_size | number | 500 | Event deduplication cache size |

Methods

Same as NostrSocket, but operations are distributed across all relays:

  • connect() - Resolves when first relay connects
  • publish(event) - Resolves on first successful publish
  • query(filters, duration?) - Resolves with first relay's response
  • subscribe(filter) - Returns SubscriptionManager directly with deduplication
  • close() - Closes all connections

NostrNode

P2P communication node for encrypted RPC messaging over Nostr.

Constructor

new NostrNode(
  peers: string[],                    // Public keys of peers
  relays: string[],                   // Relay URLs
  seckey: string,                     // Your secret key
  options?: Partial<NostrNodeConfig>
)

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | msg_timeout | number | 5000 | Request timeout (ms) | | sub_timeout | number | 30000 | Subscription timeout (ms) | | rpc_kind | number | 25000 | Event kind for RPC messages |

Properties

| Property | Type | Description | |----------|------|-------------| | is_ready | boolean | Whether node is connected and active | | client | NostrClient | Underlying multi-relay client | | peers | Set<string> | Registered peer public keys | | pubkey | string | Node's public key |

Methods

| Method | Returns | Description | |--------|---------|-------------| | connect() | Promise<void> | Connect and start listening | | request(template, peer, options?) | Promise<RpcMessageData> | Send request and wait for response | | respond(request) | { accept, reject } | Create response to a request | | announce(template, peers) | Promise<void>[] | Broadcast event to peers | | close() | void | Close node and connections |

Events

| Event | Payload | Description | |-------|---------|-------------| | ready | NostrNode | Node connected and active | | closed | NostrNode | Node closed | | error | [string, unknown] | Error occurred | | message | RpcMessageData | RPC message received | | bounced | SignedEvent | Event failed decryption/filtering | | notice | string | NOTICE from relay |

Crypto Module

import { CRYPTO } from '@vbyte/nostr-sdk'
// or
import * as CRYPTO from '@vbyte/nostr-sdk/crypto'

Key Management

| Function | Description | |----------|-------------| | gen_seckey(seed?) | Generate secret key (optionally from seed) | | get_pubkey(seckey) | Derive public key from secret key | | get_shared_secret(seckey, pubkey) | Compute ECDH shared secret |

Signatures

| Function | Description | |----------|-------------| | create_signature(seckey, message) | Create Schnorr signature | | verify_signature(message, pubkey, sig) | Verify Schnorr signature |

Encryption

| Function | Description | |----------|-------------| | nip04_encrypt(secret, content, iv?) | NIP-04 AES-CBC encryption | | nip04_decrypt(secret, content) | NIP-04 AES-CBC decryption | | nip44_encrypt(secret, content, nonce?) | NIP-44 ChaCha20 encryption | | nip44_decrypt(secret, payload) | NIP-44 ChaCha20 decryption |

Encoding

| Function | Description | |----------|-------------| | encode_b64url(data) | Encode bytes to base64url | | decode_b64url(str) | Decode base64url to bytes |

Library Module

import { LIB } from '@vbyte/nostr-sdk'
// or
import * as LIB from '@vbyte/nostr-sdk/lib'

Event Handling

| Function | Description | |----------|-------------| | create_event(config) | Create event template | | sign_event(template, seckey) | Sign event with secret key | | verify_event(event) | Verify event signature (returns error string or null) | | get_event_id(template) | Compute event ID hash | | get_event_tag(event, tag) | Get first tag by name | | filter_event_tags(event, tag) | Get all tags by name | | is_pubkey_mentioned(event, pubkey) | Check if pubkey is in 'p' tags | | is_event_expired(event, current?) | Check if event has expired |

Filtering

| Function | Description | |----------|-------------| | match_filter(event, filter) | Check if event matches filter | | match_any_filter(event, filters) | Check if event matches any filter | | process_filters(events, filters) | Filter event array | | is_kind_regular(kind) | Check if kind is regular (1, 2, 4-44, 1000-9999) | | is_kind_replace(kind) | Check if kind is replaceable (0, 3, 10000-19999) | | is_kind_ephemeral(kind) | Check if kind is ephemeral (20000-29999) | | is_kind_address(kind) | Check if kind is addressable (30000-39999) |

Types

import type {
  // Events
  SignedEvent,
  EventTemplate,
  EventFilter,
  EventConfig,

  // Configuration
  NostrSocketConfig,
  NostrClientConfig,
  NostrNodeConfig,

  // Responses
  PublishResponse,

  // RPC (for NostrNode)
  RpcMessageData,
  RequestRpcTemplate,
  EventRpcTemplate
} from '@vbyte/nostr-sdk'

Development

Requirements

  • Node.js 18+ (20+ recommended)

Setup

git clone https://github.com/cmdcode/nostr-sdk
cd nostr-sdk
npm install

Scripts

| Command | Description | |---------|-------------| | npm run check | TypeScript type checking | | npm run lint | Biome linting | | npm run lint:fix | Auto-fix linting issues | | npm run format | Format code with Biome | | npm run test | Run test suite | | npm run build | Build distribution | | npm run package | Full pipeline (lint, check, test, build) |

Build Outputs

  • dist/ - ES Modules with TypeScript declarations
  • Organized by module: class/, lib/, crypto/, schema/, types/

Resources

Contributing

Contributions are welcome. Please open an issue or submit a pull request.

License

MIT License