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

@nostrwatch/worker-relay

v1.3.1

Published

A nostr relay in a service worker

Downloads

26

Readme

@nostrwatch/worker-relay

In-browser Nostr relay running in a Web Worker with SQLite-wasm storage and OPFS persistence.

npm version License Status Runtime

Overview

@nostrwatch/worker-relay runs a full Nostr relay (a WebSocket server that stores and forwards signed JSON events) inside a browser Web Worker — an isolated background thread that keeps the relay off the main UI thread. Event storage is handled by sqlite-wasm, a WebAssembly build of SQLite, with persistence backed by OPFS (Origin Private File System), a browser-native file system API that survives page reloads. The package also adds NIP-119 (AND-filter tag queries) support on top of the standard relay functionality.

WorkerRelayInterface is the main class callers use. It communicates with the worker via a message-passing RPC layer, so all methods are async and return Promises.

Prerequisites

Node.js >=20 and pnpm >=9. This package runs in browser environments only — it requires Web Worker support, WebAssembly, and OPFS, which are not available in Node.js.

Installation

pnpm add @nostrwatch/worker-relay

Or with npm:

npm install @nostrwatch/worker-relay

Quick Start

import {WorkerRelayInterface} from '@nostrwatch/worker-relay'

// Create the interface — defaults to the bundled worker script
const relay = new WorkerRelayInterface()

// Open the SQLite database at the given OPFS path and run migrations
await relay.init({databasePath: 'relay.db', insertBatchSize: 10})

// Query events using a standard Nostr REQ command
const events = await relay.query(['REQ', 'sub-1', {kinds: [1], limit: 10}])
console.log(events)
// Array of NostrEvent objects matching the filter

// Publish a new event to the relay
const published = await relay.event({
  id: 'abc123...',
  pubkey: 'def456...',
  created_at: Math.floor(Date.now() / 1000),
  kind: 1,
  tags: [],
  content: 'hello nostr',
  sig: 'ghi789...'
})
console.log(published.ok) // true

API

WorkerRelayInterface

class WorkerRelayInterface {
  timeout: number
  constructor(scriptPath?: string | URL | Worker | SharedWorker, channelPort?: MessagePort)
  get worker(): Worker | SharedWorker
  setup(opts?: {timeoutMs?: number}): Promise<boolean>
  init(args: InitArgs): Promise<boolean>
  status(): Promise<RelayStorageStatus>
  query(req: ReqCommand): Promise<NostrEvent[]>
  event(ev: NostrEvent): Promise<OkResponse>
  count(req: ReqCommand): Promise<number>
  delete(req: ReqCommand): Promise<string[]>
  summary(): Promise<Record<string, number>>
  close(id: string): Promise<boolean>
  dump(): Promise<Uint8Array>
  wipe(): Promise<boolean>
  abort(): void
  forYouFeed(pubkey: string): Promise<NostrEvent[]>
  setEventMetadata(id: string, meta: EventMetadata): Promise<void>
  setLogLevel(level: LogLevel): Promise<boolean>
  countNip11s(): Promise<number>
  countUniqueNip11s(): Promise<number>
  dumpNip11s(): Promise<any[]>
  upsertNip11(args: Nip11Args): Promise<boolean>
  batchUpsertNip11(relayNip11s: Nip11Args[]): Promise<boolean>
  getNip11(relay: string): Promise<any>
}

constructor(scriptPath?, channelPort?)

Creates a WorkerRelayInterface. If scriptPath is omitted, the bundled worker script at @nostrwatch/worker-relay/dist/esm/worker.mjs is used. Pass a pre-created Worker or SharedWorker instance to reuse an existing worker. channelPort is used for SharedWorker message channel setup.

init(args)

Opens the SQLite database and runs schema migrations. Must be called before any query or event operations.

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | databasePath | string | Yes | OPFS file path for the SQLite database | | insertBatchSize | number | No | Events inserted per batch (default: unset) |

query(req)

Executes a standard Nostr REQ command against the local database. Returns matching NostrEvent objects. req is a tuple: ['REQ', subscriptionId, ...filters].

event(ev)

Publishes a Nostr event to the relay. Returns an OkResponse with ok: true on success.

count(req) / delete(req)

count returns the number of events matching the filter. delete removes matching events and returns their IDs.

status()

Returns a RelayStorageStatus object describing the current storage backend (sqlite, memory, or unknown) and any error state.

summary()

Returns a record mapping event kind numbers to their counts in the database.

dump()

Exports the full SQLite database as a Uint8Array. Useful for backup or inspection.

wipe()

Deletes all data from the database.

abort()

Terminates the worker and rejects all pending commands. Call this to clean up when the relay is no longer needed.

timeout

Command timeout in milliseconds. Defaults to 30000. Increase for slow environments or large batch operations.

Types

interface InitArgs {
  databasePath: string
  insertBatchSize?: number
}

interface RelayStorageStatus {
  kind: 'sqlite' | 'memory' | 'unknown'
  reason?: string
  errorMessage?: string
}

interface OkResponse {
  ok: boolean
  id: string
  relay: string
  message?: string
  event: NostrEvent
}

type ReqCommand = ['REQ', id: string, ...filters: ReqFilter[]]

Known Limitations

No known limitations at this time.

Agent Skills

No agent skills defined yet for this package.

Related Packages

License

MIT