snstr
Version:
Secure Nostr Software Toolkit for Renegades - A comprehensive TypeScript library for Nostr protocol implementation
698 lines (551 loc) • 25.4 kB
Markdown
# SNSTR - Secure Nostr Software Toolkit for Renegades

[](https://www.npmjs.com/package/snstr)
### Beta Release 🚧
SNSTR is a secure, lightweight TypeScript library for interacting with the Nostr protocol. It provides a simple, easy-to-use API with minimal dependencies.
*SNSTR is fierce. Fierce in its speed, in its flexibility, and most of all its security.*
*SNSTR is steadfast, ever persistent, watching, waiting.*
*SNSTR has vengeance on its mind.*
*SNSTR is a Nostr Development Kit for people that go swimming in jeans*
**⚠️ Important**: This library is in beta testing. While mostly stable, some features may still undergo changes. We encourage users to test thoroughly and report any issues or unexpected behavior.
## Table of Contents
- [Features](#features)
- [Supported NIPs](#supported-nips)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Configuring Rate Limits](#configuring-rate-limits)
- [Documentation](#documentation)
- [Examples](#examples)
- [Testing](#testing)
- [Scripts](#scripts)
- [Build Scripts](#build-scripts)
- [Testing Scripts](#testing-scripts)
- [Example Scripts](#example-scripts)
- [Code Quality Scripts](#code-quality-scripts)
- [Development](#development)
- [Security](#security)
## Features

### Core Functionality
- Event creation and signing with comprehensive validation
- Relay connections with automatic reconnect
- **RelayPool for multi-relay management** - Efficient connection pooling, automatic failover, and batch operations
- **Cross-relay event querying** - `fetchMany()` and `fetchOne()` methods for aggregated event retrieval
- Filter-based subscriptions
- Support for replaceable events (kinds 0, 3, 10000-19999)
- Support for addressable events (kinds 30000-39999)
### Advanced Features
- Encrypted messaging with both NIP-04 (AES-CBC) and NIP-44 (ChaCha20+HMAC)
- Identity verification with NIP-05 DNS-based identifiers
- Browser extension integration via NIP-07
- Remote signing capability via NIP-46
- Automatic subscription cleanup with `autoClose` option
- Lightning Zaps integration via NIP-57
- Threaded conversations via NIP-10
- Wallet connection via NIP-47
- Relay list metadata via NIP-65
- Built-in ephemeral relay for testing and development
## Supported NIPs
SNSTR currently implements the following Nostr Implementation Possibilities (NIPs):
- **NIP-01**: Basic protocol functionality with comprehensive event validation
- **NIP-02**: Contact List events and interactions (Kind 3)
- **NIP-04**: Encrypted direct messages using AES-CBC
- **NIP-05**: DNS identifier verification and relay discovery
- **NIP-07**: Browser extension integration for key management
- **NIP-09**: Event deletion requests for removing published events
- **NIP-10**: Text notes and threading metadata
- **NIP-11**: Relay Information Document for discovering relay capabilities
- **NIP-17**: Gift wrapped direct messages using NIP-44 encryption
- **NIP-19**: Bech32-encoded entities for human-readable identifiers
- **NIP-21**: URI scheme for nostr links
- **NIP-44**: Improved encryption with ChaCha20 and HMAC-SHA256 authentication
- **NIP-46**: Remote signing (bunker) support for secure key management
- **NIP-47**: Nostr Wallet Connect for secure wallet communication
- **NIP-50**: Search capability via `search` subscription filters
- **NIP-57**: Lightning Zaps protocol for Bitcoin payments via Lightning
- **NIP-65**: Relay List metadata for read/write relay preferences
- **NIP-66**: Relay discovery and liveness monitoring
For detailed information on each implementation, see the corresponding directories in the `src/` directory (e.g., `src/nip01/`, `src/nip04/`, etc.).
## Installation
```bash
# Install from npm (beta release)
npm install snstr
# Or clone and build locally for development:
git clone https://github.com/AustinKelsay/snstr.git
cd snstr
npm install
npm run build
```
### React Native / Expo
- Works out of the box — no Node polyfills are required.
- Add secure RNG once at app startup (required by various features):
```ts
import 'react-native-get-random-values';
```
- NIP-04 now works on Web and React Native with the exact same API as Node:
```ts
import { encryptNIP04, decryptNIP04 } from 'snstr';
const c = encryptNIP04(alicePriv, bobPub, 'hello');
const p = decryptNIP04(bobPriv, alicePub, c);
```
- Prefer NIP-44 for new apps; keep NIP-04 for legacy compatibility.
## Basic Usage
```typescript
import { Nostr, RelayEvent } from "snstr";
async function main() {
// Initialize with relays and connection timeout
const client = new Nostr(["wss://relay.nostr.band"]);
// Generate keypair
const keys = await client.generateKeys();
// Connect to relays
await client.connectToRelays();
// Set up event handlers
client.on(RelayEvent.Connect, (relay) => {
console.log(`Connected to ${relay}`);
});
// Publish a note
const note = await client.publishTextNote("Hello, Nostr!");
console.log(`Published note with ID: ${note?.id}`);
// Subscribe to events
const subIds = client.subscribe(
[{ kinds: [1], limit: 10 }], // Filter for text notes
(event, relay) => {
console.log(`Received event from ${relay}:`, event);
},
undefined,
{ autoClose: true, eoseTimeout: 5000 },
);
// Query events from all relays
const manyEvents = await client.fetchMany(
[{ kinds: [1], authors: ["pubkey"], limit: 10 }],
{ maxWait: 5000 }
);
console.log(`Found ${manyEvents.length} events`);
// Get the most recent event from all relays
const latestEvent = await client.fetchOne(
[{ kinds: [1], authors: ["pubkey"] }],
{ maxWait: 3000 }
);
if (latestEvent) {
console.log("Latest event:", latestEvent.content);
}
// Cleanup
setTimeout(() => {
client.unsubscribe(subIds);
client.disconnectFromRelays();
}, 10000);
}
main().catch(console.error);
```
### Configuring Rate Limits
SNSTR includes built-in rate limiting to prevent abuse. Configure custom limits when creating a client:
```typescript
import { Nostr } from "snstr";
const client = new Nostr(["wss://relay.nostr.band"], {
rateLimits: {
subscribe: { limit: 100, windowMs: 60000 }, // 100 per minute (default: 50)
publish: { limit: 200, windowMs: 60000 }, // 200 per minute (default: 100)
fetch: { limit: 500, windowMs: 60000 } // 500 per minute (default: 200)
}
});
// Update limits dynamically
client.updateRateLimits({ subscribe: { limit: 150, windowMs: 30000 } });
```
See [NIP-01 documentation](src/nip01/README.md#rate-limiting) for detailed configuration options.
### Using RelayPool for Multi-Relay Management
```typescript
import { RelayPool, generateKeys, createEvent } from "snstr";
async function relayPoolExample() {
// Initialize RelayPool with multiple relays
const pool = new RelayPool([
"wss://relay.nostr.band",
"wss://nos.lol",
"wss://relay.damus.io"
]);
// Generate keypair
const keys = await generateKeys();
// Publish to multiple relays simultaneously
const event = createEvent({
kind: 1,
content: "Hello from RelayPool!",
tags: [],
privateKey: keys.privateKey
});
const publishPromises = pool.publish(
["wss://relay.nostr.band", "wss://nos.lol"],
event
);
const results = await Promise.all(publishPromises);
// Subscribe across multiple relays with automatic failover
const subscription = await pool.subscribe(
["wss://relay.nostr.band", "wss://nos.lol", "wss://relay.damus.io"],
[{ kinds: [1], limit: 10 }],
(event, relayUrl) => {
console.log(`Event from ${relayUrl}:`, event.content);
},
() => {
console.log("All relays finished sending stored events");
}
);
// Query events synchronously from multiple relays
const events = await pool.querySync(
["wss://relay.nostr.band", "wss://nos.lol"],
{ kinds: [1], limit: 5 },
{ timeout: 10000 }
);
console.log(`Retrieved ${events.length} events`);
// Cleanup
subscription.close();
await pool.close();
}
relayPoolExample().catch(console.error);
```
### Event Querying with fetchMany and fetchOne
```typescript
import { Nostr } from "snstr";
async function queryExample() {
const client = new Nostr(["wss://relay.nostr.band", "wss://nos.lol"]);
await client.connectToRelays();
// Fetch multiple events from all connected relays
const events = await client.fetchMany(
[
{ kinds: [1], authors: ["pubkey1", "pubkey2"], limit: 20 },
{ kinds: [0], authors: ["pubkey1"] } // Profile metadata
],
{ maxWait: 5000 } // Wait up to 5 seconds
);
console.log(`Retrieved ${events.length} events from all relays`);
// Fetch the most recent single event
const latestNote = await client.fetchOne(
[{ kinds: [1], authors: ["pubkey1"] }],
{ maxWait: 3000 }
);
if (latestNote) {
console.log("Latest note:", latestNote.content);
}
client.disconnectFromRelays();
}
queryExample().catch(console.error);
```
For more examples including encryption, relay management, and NIP-specific features, see the [examples directory](./examples/README.md).
### Custom WebSocket Implementation
SNSTR relies on `websocket-polyfill` when running in Node.js. If you want to provide your own `WebSocket` class (for example when using a different runtime), you can set it with `useWebSocketImplementation`:
```typescript
import { useWebSocketImplementation } from "snstr";
import WS from "isomorphic-ws";
useWebSocketImplementation(WS);
```
You can also reset back to the default implementation:
```typescript
import { resetWebSocketImplementation } from "snstr";
resetWebSocketImplementation();
```
**Note**: To run the custom WebSocket example (`npm run example:custom-websocket`), you need to install a WebSocket package first:
```bash
# Install the ws package (used in the example)
npm install ws
npm install --save-dev @types/ws
# Or use isomorphic-ws for cross-platform compatibility
npm install isomorphic-ws
```
## Documentation
The project is organized with detailed documentation for different components:
#### Core Documentation
- **[Test Documentation](tests/README.md)**: Overview of test organization and execution
- **[Examples Documentation](examples/README.md)**: Complete guide to examples for all features
#### NIP Documentation
- **[NIP-01](src/nip01/README.md)**: Basic protocol functionality
- **[NIP-02](src/nip02/README.md)**: Contact List recommendation
- **[NIP-04](src/nip04/README.md)**: Encrypted direct messages
- **[NIP-05](src/nip05/README.md)**: DNS identifier verification
- **[NIP-07](src/nip07/README.md)**: Browser extension integration
- **[NIP-09](src/nip09/README.md)**: Event deletion requests
- **[NIP-10](src/nip10/README.md)**: Text notes and threads
- **[NIP-11](src/nip11/README.md)**: Relay information document
- **[NIP-17](src/nip17/README.md)**: Gift wrapped direct messages
- **[NIP-19](src/nip19/README.md)**: Bech32-encoded entities
- **[NIP-21](src/nip21/README.md)**: URI scheme for nostr links
- **[NIP-44](src/nip44/README.md)**: Versioned encryption
- **[NIP-46](src/nip46/README.md)**: Remote signing protocol
- **[NIP-47](src/nip47/README.md)**: Nostr Wallet Connect
- **[NIP-50](src/nip50/README.md)**: Search capability
- **[NIP-57](src/nip57/README.md)**: Lightning Zaps
- **[NIP-65](src/nip65/README.md)**: Relay List metadata
- **[NIP-66](src/nip66/README.md)**: Relay discovery and liveness monitoring
#### Standardization Guidelines
- **[NIP Implementation Guide](src/NIP_STANDARDIZATION.md)**: Standards for implementing NIPs
- **[Test Standardization](tests/TEST_STANDARDIZATION.md)**: Guide for writing standardized tests
- **[Example Standardization](examples/EXAMPLE_STANDARDIZATION.md)**: Guide for creating standardized examples
## Examples
SNSTR includes comprehensive examples for all supported features and NIPs:
```bash
# Run the basic example
npm run example
# Run the direct messaging example
npm run example:dm # Uses NIP-04 implementation
# Run additional basic examples
npm run example:verbose # Verbose logging
npm run example:debug # Debug logging
npm run example:custom-websocket # Custom WebSocket implementation
npm run example:crypto # Cryptographic functions
npm run example:rate-limits # Rate limit configuration demo
# Run NIP-01 examples
npm run example:nip01:event:ordering # Event ordering demonstration
npm run example:nip01:event:addressable # Addressable events
npm run example:nip01:event:replaceable # Replaceable events
npm run example:nip01:relay:connection # Relay connection management
npm run example:nip01:relay:pool # RelayPool multi-relay demo
npm run example:nip01:relay:filters # Filter types
npm run example:nip01:relay:auto-close # Auto-unsubscribe example
npm run example:nip01:relay:query # Pooled event queries
npm run example:nip01:relay:reconnect # Relay reconnection
npm run example:nip01:validation # NIP-01 validation flow
# Run other NIP-specific examples
npm run example:nip04 # Encrypted direct messages
npm run example:nip05 # DNS identifiers
npm run example:nip09 # Deletion requests
npm run example:nip19 # Bech32-encoded entities
npm run example:nip44 # Versioned encryption
npm run example:nip17 # Gift wrapped direct messages
npm run example:nip46 # Remote signing protocol
npm run example:nip50 # Search capability
npm run example:nip57 # Lightning Zaps
npm run example:nip65 # Relay list metadata
npm run example:nip66 # Relay discovery and monitoring
# Additional NIP-specific example variants
npm run example:nip07 # Browser extension (runs local server)
npm run example:nip07:build # Build browser extension examples
npm run example:nip07:dm # Browser extension direct message
npm run example:nip10 # Text Notes and Threads (see README)
npm run example:nip11 # Relay information
npm run example:nip19:bech32 # Basic Bech32 examples
npm run example:nip19:tlv # TLV entity examples
npm run example:nip19:validation # Validation examples
npm run example:nip19:security # Security features
npm run example:nip21 # URI scheme
npm run example:nip44:js # JavaScript version of NIP-44
npm run example:nip44:version-compat # Version compatibility
npm run example:nip44:test-vector # Test vector validation
npm run example:nip46:minimal # Minimal NIP-46 example
npm run example:nip46:basic # Basic NIP-46 example
npm run example:nip46:advanced # Advanced features
npm run example:nip46:from-scratch # Implementation from scratch
npm run example:nip46:simple # Simple client/server
npm run example:nip47:verbose # Verbose wallet connect
npm run example:nip47:client-service # Client service example
npm run example:nip47:error-handling # Error handling
npm run example:nip47:expiration # Request expiration
npm run example:nip57:client # Zap client
npm run example:nip57:lnurl # LNURL server simulation
npm run example:nip57:validation # Invoice validation
```
For a full list of examples and detailed descriptions, see the [examples README](./examples/README.md).
## Testing
SNSTR includes a comprehensive test suite that uses an ephemeral relay to avoid external dependencies:
### Main Test Commands
```bash
# Run all tests
npm test
# Run tests with watch mode for development
npm run test:watch
# Generate code coverage report
npm run test:coverage
# Run integration tests
npm run test:integration
```
### Test Categories
Tests are organized into logical categories for focused testing:
```bash
npm run test:core # Core functionality tests (all NIP-01)
npm run test:crypto # All crypto tests (utils/crypto + NIP-04 + NIP-44)
npm run test:identity # Identity-related tests (NIP-05, NIP-07, NIP-19)
npm run test:protocols # Protocol implementations (NIP-46, NIP-47, NIP-57)
```
### NIP-01 Core Protocol Tests
NIP-01 tests are further organized by component:
```bash
# Main NIP-01 tests
npm run test:nip01 # All NIP-01 tests
npm run test:nip01:event # All event-related tests
npm run test:nip01:relay # All relay-related tests
# Event-specific tests
npm run test:event # Core event creation/validation
npm run test:event:ordering # Event ordering tests
npm run test:event:addressable # Addressable events (kinds 30000-39999)
npm run test:event:all # All event tests combined
# Relay-specific tests
npm run test:relay # All relay functionality
npm run test:nip01:relay:connection # Relay connection management
npm run test:nip01:relay:filter # Subscription filter tests
npm run test:nip01:relay:reconnect # Relay reconnection logic
npm run test:nip01:relay:pool # RelayPool multi-relay tests
npm run test:nip01:relay:websocket # WebSocket implementation tests
# Client and utilities
npm run test:nostr # Nostr client tests
npm run test:crypto:core # Core cryptographic utilities
npm run test:utils:relayUrl # Relay URL normalization
```
### NIP-Specific Tests
Run tests for individual NIP implementations:
```bash
npm run test:nip02 # NIP-02 (Contact Lists)
npm run test:nip04 # NIP-04 (Encrypted Direct Messages)
npm run test:nip05 # NIP-05 (DNS Identifiers)
npm run test:nip07 # NIP-07 (Browser Extensions)
npm run test:nip09 # NIP-09 (Event Deletion)
npm run test:nip10 # NIP-10 (Text Notes and Threads)
npm run test:nip11 # NIP-11 (Relay Information)
npm run test:nip17 # NIP-17 (Gift Wrapped Messages)
npm run test:nip19 # NIP-19 (Bech32 Entities)
npm run test:nip21 # NIP-21 (URI Scheme)
npm run test:nip44 # NIP-44 (Versioned Encryption)
npm run test:nip46 # NIP-46 (Remote Signing)
npm run test:nip47 # NIP-47 (Wallet Connect)
npm run test:nip50 # NIP-50 (Search Capability)
npm run test:nip57 # NIP-57 (Lightning Zaps)
npm run test:nip65 # NIP-65 (Relay List Metadata)
npm run test:nip66 # NIP-66 (Relay Discovery)
```
The test suite is organized by NIP number, with dedicated directories for each implemented NIP (e.g., `tests/nip01/`, `tests/nip04/`, etc.). This structure allows for focused testing of specific implementations while maintaining comprehensive coverage.
For more information about the test structure and methodology, see the [tests README](./tests/README.md).
## Scripts
SNSTR provides numerous npm scripts to help with development, testing, and running examples:
### Build Scripts
```bash
# Build the library
npm run build
# Build example files
npm run build:examples
```
### Testing Scripts
```bash
# Run all tests
npm test
# Run tests with watch mode
npm run test:watch
# Generate code coverage report
npm run test:coverage
# Test by category
npm run test:core # Core functionality (NIP-01)
npm run test:crypto # All crypto (utils/crypto + NIP-04 + NIP-44)
npm run test:identity # Identity-related features (NIP-05, NIP-07, NIP-19)
npm run test:protocols # Protocol implementations (NIP-46, NIP-47, NIP-57)
npm run test:integration # Integration tests
# Test specific NIP-01 components
npm run test:nip01 # All NIP-01 tests
npm run test:nip01:event # Event-related tests
npm run test:nip01:relay # Relay-related tests
npm run test:nip01:relay:connection # Relay connection tests
npm run test:nip01:relay:filter # Relay filter tests
npm run test:nip01:relay:reconnect # Relay reconnection tests
npm run test:nip01:relay:pool # RelayPool tests
npm run test:nostr # Nostr client
npm run test:event # Event creation and validation
npm run test:event:ordering # Event ordering tests
npm run test:event:addressable # Addressable events tests
npm run test:event:all # All event tests
npm run test:relay # Relay functionality
npm run test:crypto:core # Core crypto utilities
# Test specific NIPs
npm run test:nip02 # NIP-02 (Contact Lists)
npm run test:nip04 # NIP-04 (Encrypted Direct Messages)
npm run test:nip05 # NIP-05 (DNS Identifiers)
npm run test:nip07 # NIP-07 (Browser Extensions)
npm run test:nip09 # NIP-09 (Event Deletion Requests)
npm run test:nip10 # NIP-10 (Text Notes and Threads)
npm run test:nip11 # NIP-11 (Relay Information)
npm run test:nip17 # NIP-17 (Direct Messages)
npm run test:nip19 # NIP-19 (Bech32 Entities)
npm run test:nip21 # NIP-21 (URI Scheme)
npm run test:nip44 # NIP-44 (Versioned Encryption)
npm run test:nip46 # NIP-46 (Remote Signing)
npm run test:nip47 # NIP-47 (Wallet Connect)
npm run test:nip50 # NIP-50 (Search Capability)
npm run test:nip57 # NIP-57 (Lightning Zaps)
npm run test:nip65 # NIP-65 (Relay List Metadata)
npm run test:nip66 # NIP-66 (Relay Discovery)
```
### Example Scripts
```bash
# Run the basic example
npm run example
# Run with different logging levels
npm run example:verbose # Verbose logging
npm run example:debug # Debug logging
# NIP-01 examples
npm run example:nip01:event:ordering # Event ordering demonstration
npm run example:nip01:event:addressable # Addressable events
npm run example:nip01:event:replaceable # Replaceable events
npm run example:nip01:relay:connection # Relay connection management
npm run example:nip01:relay:pool # RelayPool multi-relay demo
npm run example:nip01:relay:filters # Filter types
npm run example:nip01:relay:query # Pooled event queries
npm run example:nip01:relay:reconnect # Relay reconnection
npm run example:nip01:validation # NIP-01 validation flow
# Example categories
npm run example:basic # Basic functionality (core, crypto, direct messages)
npm run example:messaging # Messaging examples (DM, NIP-04, NIP-44)
npm run example:identity # Identity examples (NIP-05, NIP-07, NIP-19)
npm run example:payments # Payment examples (NIP-47, NIP-57)
npm run example:advanced # Advanced protocol examples (NIP-46, error handling)
# Feature-specific examples
npm run example:crypto # Cryptographic functions
npm run example:dm # Direct messaging (NIP-04)
# NIP-specific examples
npm run example:nip02 # Contact Lists (NIP-02)
npm run example:nip04 # Encrypted direct messages (NIP-04)
npm run example:nip05 # DNS identifiers (NIP-05)
npm run example:nip07 # Browser extensions (NIP-07)
npm run example:nip09 # Deletion requests (NIP-09)
npm run example:nip10 # Text notes and threads (NIP-10)
npm run example:nip11 # Relay information (NIP-11)
npm run example:nip21 # URI scheme (NIP-21)
npm run example:nip17 # Gift wrapped direct messages (NIP-17)
npm run example:nip19 # Bech32-encoded entities (NIP-19)
npm run example:nip44 # Versioned encryption (NIP-44)
npm run example:nip46 # Remote signing protocol (NIP-46)
npm run example:nip47 # Wallet connect (NIP-47)
npm run example:nip50 # Search capability (NIP-50)
npm run example:nip57 # Lightning zaps (NIP-57)
npm run example:nip65 # Relay list metadata (NIP-65)
npm run example:nip66 # Relay discovery and monitoring (NIP-66)
```
### Code Quality Scripts
```bash
# Run linting
npm run lint
# Format code with Prettier
npm run format
```
For a complete list of available scripts, see the `scripts` section in `package.json`.
## Development
```bash
# Build the project
npm run build
# Build examples
npm run build:examples
# Run linting
npm run lint
# Format code
npm run format
```
### Directory Structure Notes
- **Source Code**: All NIP implementations follow the `src/nipXX` naming pattern (lowercase)
- **Core Protocol**: NIP-01 is implemented in the `src/nip01/` directory with specialized files:
- `event.ts`: Event creation, validation, and utilities
- `nostr.ts`: Main Nostr client implementation
- `relay.ts`: Relay connection and subscription management
- `relayPool.ts`: Multi-relay pool management
- **Examples**: Organized by NIP in `examples/nipXX` directories
- NIP-01 examples further divided into `event/` and `relay/` subdirectories
- Client-specific examples in `examples/client`
- **Tests**: Organized by NIP in `tests/nipXX` directories
- For more details on code organization standards, see the [NIP Implementation Guide](src/NIP_STANDARDIZATION.md)
## Security
SNSTR implements robust security features throughout the codebase:
- **Comprehensive Event Validation**: Full verification of event signatures and structure
- **Secure Key Generation**: Safe private key generation within the secp256k1 curve limits
- **NIP-19 Security**: Relay URL validation and filtering to prevent injection attacks
- **NIP-44 Encryption**: Authenticated encryption with ChaCha20 and HMAC-SHA256
- **Input Validation**: Thorough validation and error checking across all components
For details on security considerations for specific NIPs, see the documentation in each implementation folder.