Registry / communication / nostr-tools

nostr-tools

JSON →
library1.4.1jsnpmunverified

nostr-tools is a core JavaScript/TypeScript library providing low-level utilities for developing Nostr clients. It enables essential functionalities such as generating Nostr secret and public keys, creating and signing events, verifying event integrity, and interacting with Nostr relays through a `SimplePool` abstraction. The current stable version is 2.23.3, and the project appears to have an active release cadence, evidenced by significant breaking changes in version 2.0.0 and subsequent updates. Key differentiators include its minimalist dependency footprint, relying primarily on `@scure` and `@noble` cryptography packages, and its modular structure which allows importing only necessary components. It specifically focuses on lower-level primitives, suggesting `@nostr/gadgets` for higher-level client features. It also provides robust relay management features like configurable pinging and automatic reconnection.

npm install nostr-tools
INSTALL
IMPORT
SIG · NOSTR-TOOLS
N
nostr-tools
communicationjavascriptv1.4.1
Install
Import
Disk
Pass rate
0/ 6
Env Coverage0 / 6
glibc
1822
musl
1822
Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
node 18226 runs
build_error
glibc
node 18226 runs
build_error
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

generateSecretKey, getPublicKey
import { generateSecretKey, getPublicKey } from '@nostr/tools/pure'
const { generateSecretKey, getPublicKey } = require('nostr-tools/pure')
ESM-only for modern usage. These are pure functions for cryptographic operations.
finalizeEvent, verifyEvent
import { finalizeEvent, verifyEvent } from '@nostr/tools/pure'
import { finalizeEvent } from 'nostr-tools'
Since v2.0.0, functions are imported from specific subpaths like `/pure` due to modularization. Avoid legacy 'nostr-tools' root import for these functions.
SimplePool
import { SimplePool } from '@nostr/tools/pool'
import { SimplePool } from 'nostr-tools'
The primary class for relay interaction. Must be imported from the `/pool` subpath since v2.0.0.
useWebSocketImplementation
import { useWebSocketImplementation } from '@nostr/tools/pool'
import { useWebSocketImplementation } from '@nostr/tools/relay'
Essential for Node.js environments to explicitly provide a WebSocket implementation (e.g., `ws` package) to the library. Can also be from `/relay` if using `Relay` directly.

Demonstrates generating Nostr keys, creating and signing an event, publishing it to relays, subscribing to events from a public key, and configuring the WebSocket implementation for Node.js.

import { finalizeEvent, generateSecretKey, getPublicKey } from '@nostr/tools/pure'; import { SimplePool, useWebSocketImplementation } from '@nostr/tools/pool'; import WebSocket from 'ws'; // For Node.js environments import { bytesToHex } from '@noble/hashes/utils'; // For convenience // For Node.js, set up the WebSocket implementation useWebSocketImplementation(WebSocket); async function runNostrClient() { const pool = new SimplePool({ enablePing: true, enableReconnect: true }); // Use a real, publicly available relay for testing const relays = ['wss://relay.damus.io', 'wss://nostr.wine', 'wss://eden.nostr.land']; // 1. Generate keys let sk = generateSecretKey(); // Uint8Array let pk = getPublicKey(sk); // hex string console.log(`Generated secret key (hex): ${bytesToHex(sk)}`); console.log(`Generated public key (hex): ${pk}`); // 2. Create and sign an event let eventTemplate = { kind: 1, // Text Note created_at: Math.floor(Date.now() / 1000), tags: [], content: `Hello Nostr from nostr-tools! This is a test event from a registry quickstart. ${Math.random()}`, }; const signedEvent = finalizeEvent(eventTemplate, sk); console.log('Signed event:', signedEvent); // 3. Publish the event to a couple of relays console.log(`Publishing event to ${relays.slice(0, 2).join(', ')}...`); try { // Promise.any will resolve as soon as one relay successfully publishes await Promise.any(pool.publish(relays.slice(0, 2), signedEvent)); console.log('Event published successfully to at least one relay.'); } catch (error) { console.error('Failed to publish event to any relay:', error); } // 4. Subscribe to events from our public key console.log(`Subscribing to events from public key ${pk}...`); const sub = pool.subscribe( relays, { kinds: [1], authors: [pk], since: Math.floor(Date.now() / 1000) - 60, // Look for events in the last 60 seconds }, { onevent(event) { console.log('Received own event:', event.content); // Once we receive our own event, we can unsubscribe if desired sub.close(); }, oneose() { console.log('Subscription End of Stored Events (EOSE) received.'); }, onclose(wasClean: boolean) { console.log(`Subscription closed (wasClean: ${wasClean}).`); } } ); // Optional: Query for some existing events console.log('Querying for recent text notes (kind 1)...'); const recentEvents = await pool.querySync( relays, { kinds: [1], limit: 5, }, { onprogress(percent: number) { // console.log(`Query progress: ${Math.round(percent)}%`); } } ); if (recentEvents && recentEvents.length > 0) { console.log(`Found ${recentEvents.length} recent events. Example:`, recentEvents[0].content); } else { console.log('No recent events found.'); } // Allow some time for events to propagate and be received await new Promise(resolve => setTimeout(resolve, 5000)); pool.close(); // Close all relay connections console.log('Pool closed.'); } runNostrClient().catch(console.error);
Debug
Known issues
breakingVersion 2.0.0 introduced significant breaking changes, including API renames, removal of deprecated methods, changes to Event type parameters (e.g., `Event<number>` was removed), and kind constants replacing enums.
fix
Review the v2.0.0 release notes and update all imports, method calls, and type usages according to the new API structure and modular import paths. Kinds are now constants, not enums.
affects: >=2.0.0
breakingWith v2.0.0, the package transitioned to a modular structure, requiring imports from specific subpaths (e.g., `@nostr/tools/pure`, `@nostr/tools/pool`) instead of the root `@nostr/tools` package for most functionality.
fix
Change your import statements from `import { SomeSymbol } from '@nostr/tools'` to `import { SomeSymbol } from '@nostr/tools/subpath'`, where `subpath` is typically `pure`, `pool`, or `relay`.
affects: >=2.0.0
gotchaWhen using `SimplePool` or `Relay` in a Node.js environment, you must explicitly provide a WebSocket implementation, typically by installing the `ws` package and calling `useWebSocketImplementation(WebSocket)`.
fix
Install the `ws` package (`npm install ws`) and add the following code at the entry point of your Node.js application: `import WebSocket from 'ws'; import { useWebSocketImplementation } from '@nostr/tools/pool'; useWebSocketImplementation(WebSocket);`
affects: *
gotchaThe package lists TypeScript >= 5.0.0 as a peer dependency. Using an older version of TypeScript may lead to type incompatibility issues or compilation errors.
fix
Ensure your project's `devDependencies` or `dependencies` include `"typescript": ">=5.0.0"` and update your TypeScript installation if necessary.
affects: *
Errors
Common errors & fixes
TypeError: global.WebSocket is not a constructor
Attempting to use `SimplePool` or `Relay` in a Node.js environment without a global WebSocket implementation being set.
fix
Install `ws` (`npm install ws`) and call `useWebSocketImplementation(WebSocket)` from `@nostr/tools/pool` (or `/relay`) with the `ws` import.
ReferenceError: WebSocket is not defined
Similar to the `TypeError`, this occurs in Node.js when the `SimplePool` or `Relay` tries to instantiate a WebSocket without an available global `WebSocket` constructor.
fix
Provide a WebSocket implementation by installing `ws` and calling `useWebSocketImplementation(WebSocket)` from `@nostr/tools/pool` (or `/relay`).
SyntaxError: Cannot use import statement outside a module
The `nostr-tools` library is primarily distributed as an ES Module (ESM). This error occurs when trying to use `import` statements in a CommonJS (CJS) context in Node.js.
fix
Convert your Node.js project to use ES Modules by adding `"type": "module"` to your `package.json` and using `.js` files (or `.mjs`). Alternatively, use a bundler (e.g., Webpack, Rollup) for client-side applications.
Upgrade
Version history
1.4.1latest on npm
Audit
Dependencies
typescriptrequiredPeer dependency, required for TypeScript users.
wsoptionalRuntime dependency for Node.js environments to provide a WebSocket implementation for SimplePool and Relay.
Agent activity
28 hits · last 30 days
node
22
OpenAI (training)
1
Resources
nostr-tools — npm install nostr-tools · libregistry