Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sandwichfarm/nostr-watch/llms.txt

Use this file to discover all available pages before exploring further.

@nostrwatch/auditor tests Nostr relays for protocol conformance. Given a relay URL, it runs a battery of NIP (Nostr Implementation Possibility) test suites and returns a structured result indicating which NIPs the relay supports correctly. Use it to benchmark new relays, validate relay upgrades, or power relay-health dashboards. Auditor is a library — it runs tests but does not store results. Pair it with @nostrwatch/route66 for persistent relay monitoring or @nostrwatch/nocap for low-level connection checks.

Installation

npm install @nostrwatch/auditor

Quick start

import {Auditor} from '@nostrwatch/auditor'

const auditor = new Auditor({nips: new Set(['Nip01', 'Nip11'])})
await auditor.detectSupportedNips('wss://relay.damus.io')
const result = await auditor.test('wss://relay.damus.io')
console.log(result)
// { relay: 'wss://relay.damus.io', pass: true, passrate: 0.875, suites: {...} }

Auditor class

class Auditor {
  constructor(conf?: IAuditorConf)
  detectSupportedNips(relay: string): Promise<void>
  test(relay: string): Promise<IAuditorResult>
  run(relay: string): Promise<IAuditorResult>
  addSuite(suite: string, options?: any): void
  removeSuite(suite: string): void
  abort(): void
  get result(): IAuditorResult
  get suites(): Set<string>
}

Constructor

conf
IAuditorConf
Optional configuration. If omitted, only the Nip01 suite runs by default.

Methods

detectSupportedNips(relay) Fetches the relay’s NIP-11 info document and adds matching NIP suites to the configured suite set. Call this before test() to automatically test only the NIPs the relay claims to support. test(relay) Runs all configured NIP suites against the relay URL and returns an IAuditorResult. Equivalent to run(). run(relay) Alias for test(). addSuite(suite, options?) Adds a NIP suite by name using the 'NipXX' format (e.g., 'Nip42'). Unknown suite names are silently ignored. removeSuite(suite) Removes a NIP suite from the configured set. abort() Emits an abort signal to all active suites. Use this to cancel an in-progress test run.

Getters

result — The most recent IAuditorResult after a test() or run() call. suites — The current Set<string> of configured suite names.

IAuditorConf interface

interface IAuditorConf {
  nips: Set<string>
  options: Record<string, any>
}

IAuditorResult interface

interface IAuditorResult {
  relay: string
  pass: boolean
  passrate: number
  reason: string
  suites: Record<string, ISuiteResult>
}
relay
string
required
The relay URL that was tested.
pass
boolean
required
true if all non-skipped suites passed.
passrate
number
required
Fraction of non-skipped suites that passed, from 0 to 1.
reason
string
Human-readable summary of the test outcome.
suites
Record<string, ISuiteResult>
required
Per-suite results keyed by suite name (e.g., 'Nip01', 'Nip42').

Supported NIP suites

Nip01

NIP-01 — Basic relay protocol. Tests filters, subscriptions, and event publishing.

Nip02

NIP-02 — Contact list events. Tests relay handling of kind 3 contact list events.

Nip11

NIP-11 — Relay information document. Tests the relay’s HTTP info endpoint.

Nip22

NIP-22 — Comment events. Tests relay handling of comment event kinds.

Nip42

NIP-42 — Authentication of clients to relays. Tests the AUTH challenge/response flow.

Nip50

NIP-50 — Search capability. Tests full-text search filter support.

Nip65

NIP-65 — Relay list metadata. Tests relay handling of kind 10002 relay list events.

Nip77

NIP-77 — Negentropy syncing. Tests efficient set reconciliation between client and relay.

SuiteTest pattern

Individual NIP tests extend SuiteTest and implement a test() method that uses a behavior assertion helper. This pattern applies when writing custom test suites:
import {SuiteTest, type ISuiteTest} from '@nostrwatch/auditor'

export class FilterLimit extends SuiteTest implements ISuiteTest {
  readonly slug: string = 'FilterLimit'
  limit: number = 1

  get filters() {
    return [{limit: this.limit}]
  }

  test({behavior}) {
    behavior.toEqual(this.totalEvents, this.limit, 'returned correct number of events')
    behavior.toBeOk(this.totalEvents > 0, 'returned at least one event')
  }
}
The behavior object provides assertion methods that record pass/fail outcomes without throwing, allowing all assertions in a test to run before the suite aggregates results. The slug is used as the test identifier in the suite result.

Usage patterns

import {Auditor} from '@nostrwatch/auditor'

const auditor = new Auditor({
  nips: new Set(['Nip01', 'Nip42', 'Nip50'])
})
const result = await auditor.test('wss://relay.example.com')
console.log(`Pass rate: ${result.passrate * 100}%`)

Known limitations

Incomplete filter range testing. Ambiguity handling in filter range selection is unimplemented. Filter range selection for timestamp-based queries may produce incorrect ranges in edge cases. No workaround is available at this time.

@nostrwatch/nocap

Low-level relay connection primitives. Auditor builds on nocap adapters internally.

@nostrwatch/route66

Persistent relay monitoring that uses auditor for health checks.

Build docs developers (and LLMs) love