Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

@nostrwatch/negentropy-utils

Utilities for NIP-77 Negentropy set reconciliation between Nostr clients and relays.

npm version License Status Runtime

Overview

@nostrwatch/negentropy-utils implements the NIP-77 Negentropy protocol — a set reconciliation algorithm that efficiently identifies which Nostr events (signed JSON objects that are the fundamental unit of the Nostr protocol) a client and relay do not have in common. Instead of transferring full event lists, Negentropy uses fingerprint-based range comparisons to minimize data transferred during sync. The package provides ClientHandler for use in Nostr clients and ServerHandler for use in relay implementations, both operating over a pluggable Transport interface.

Prerequisites

Node.js >=20 and pnpm >=9.

Installation

pnpm add @nostrwatch/negentropy-utils

Or with npm:

npm install @nostrwatch/negentropy-utils

Quick Start

import {ClientHandler} from '@nostrwatch/negentropy-utils'
import {WebSocketTransport} from '@nostrwatch/negentropy-utils/transports/WebSocket'
import type {RecordItem} from '@nostrwatch/negentropy-utils'

// Local event records (timestamp + 32-byte ID)
const localRecords: RecordItem[] = [
  {timestamp: BigInt(1700000000), id: new Uint8Array(32).fill(1)},
  {timestamp: BigInt(1700000001), id: new Uint8Array(32).fill(2)}
]

const ws = new WebSocket('wss://relay.damus.io')
const transport = new WebSocketTransport(ws)

// Subscribe to kind 1 events and start sync
const client = new ClientHandler(localRecords, transport, {kinds: [1]}, 'sync-1')

ws.onopen = () => {
  client.startSync()
  // Sends NEG-OPEN to the relay and begins reconciliation
}

API

ClientHandler

Used on the client side to synchronize a local event set with a relay.

class ClientHandler {
  constructor(
    records: RecordItem[],
    transport: Transport,
    filter: object,
    subscriptionId: string
  )
  startSync(): void
  handleMessage(message: string): void
}

constructor(records, transport, filter, subscriptionId)

Parameter Type Description
records RecordItem[] Local event records to synchronize
transport Transport Message transport (e.g., WebSocketTransport)
filter object Nostr filter (e.g., {kinds: [1]}) scoping which events to sync
subscriptionId string Unique identifier for this sync session

startSync()

Initiates the NIP-77 handshake by sending a NEG-OPEN message to the relay. Call this after the transport connection is open.

handleMessage(message: string)

Processes an incoming relay message (NEG-MSG, NEG-ERR, or NEG-CLOSE). The Transport implementation calls this automatically via onMessage.

ServerHandler

Used on the relay side to respond to client sync requests.

class ServerHandler {
  constructor(
    records: RecordItem[],
    transport: Transport,
    applyFilter: (records: RecordItem[], filter: object) => Promise<RecordItem[]>
  )
  handleMessage(message: string): Promise<void>
}

constructor(records, transport, applyFilter)

Parameter Type Description
records RecordItem[] All event records stored on the relay
transport Transport Message transport connected to the client
applyFilter function Async function that filters records by a Nostr filter object

handleMessage(message: string)

Handles incoming client messages (NEG-OPEN, NEG-MSG, NEG-CLOSE). The Transport implementation calls this automatically.

Transport

An abstract interface that both handlers communicate through. Implement it for any transport layer (WebSocket, stdio, etc.).

abstract class Transport {
  abstract send(message: string): void
  abstract onMessage(handler: (message: string) => void): void
}

Types

type RecordItem = {timestamp: bigint; id: Uint8Array}

type RangeMode = 0 | 1 | 2

interface Range {
  upperBound: Bound
  mode: RangeMode
  payload: Uint8Array
}

interface Bound {
  timestampOffset: bigint
  idPrefix: Uint8Array
}

Known Limitations

No known limitations at this time.

Agent Skills

No agent skills defined yet for this package.

Related Packages

License

MIT