Files
bitvid/docs/nostr-client-overview.md
T

3.7 KiB

NostrClient Overview

The NostrClient class in js/nostr/client.js is the central controller for all Nostr protocol interactions in the application. It handles connection management, event publishing, state synchronization, and caching.

Key Responsibilities

  1. Connection Management: Maintains a pool of connections to Nostr relays (SimplePool).
  2. State Management:
    • allEvents: A raw map of all fetched events, useful for history.
    • activeMap: A "materialized view" containing only the latest version of each video (deduplicated by videoRootId or d tag).
    • tombstones: Tracks deleted events to prevent them from reappearing if an old relay broadcasts them.
  3. Event Publishing: Handles signing and broadcasting events (Kind 30078 video posts, Kind 1 metadata, etc.).
  4. Buffering: Implements a buffering strategy for incoming events to optimize UI rendering performance.
  5. Caching: Uses EventsCacheStore (IndexedDB + localStorage) to persist state across sessions for instant load times.
  6. Signer Abstraction: Manages different signing methods (NIP-07 extension, NIP-46 remote signer, local keys).

Core Concepts

Eventual Consistency & activeMap

Nostr is a decentralized protocol where events can arrive out of order or be duplicated across relays. The activeMap is critical for presenting a consistent view to the user.

  • Logic: When a new event arrives, activeMap only updates if the new event has a newer created_at timestamp than the existing entry for that videoRootId (or d tag).
  • Deletions: If an event is deleted (Kind 5 or explicit deleted: true flag), a "tombstone" is recorded. Future events with a timestamp older than the tombstone are ignored.

Buffering Strategy (subscribeVideos)

To prevent the UI from freezing when thousands of events arrive during the initial connection:

  1. Incoming events are pushed into an eventBuffer.
  2. A debounced flush function processes the buffer every ~75ms.
  3. Events are processed in batches: validation, deduplication, and state updates happen in bulk.
  4. The UI is notified only once per batch.

Caching (EventsCacheStore)

The client attempts to restore state immediately on load ("Stale-While-Revalidate"):

  1. Restore: restoreLocalData reads from IndexedDB (or localStorage fallback).
  2. Display: The UI renders cached content immediately.
  3. Fetch: The client connects to relays and fetches new events, updating the UI as they arrive.
  4. Persist: The EventsCacheStore periodically saves the current state to disk, using fingerprints to avoid unnecessary writes.

Common Workflows

1. Publishing a Video

publishVideo(videoPayload, pubkey)

  1. Constructs the video metadata (Kind 30078).
  2. Signs the event using the active signer.
  3. Publishes to configured relays.
  4. Side Effects:
    • If a hosted URL is present, publishes a NIP-94 mirror event (Kind 1063).
    • If NIP-71 categorization tags are present, publishes a wrapper event (Kind 22).

2. Loading the Feed

subscribeVideos(onVideo, options)

  1. Checks cache for the latest timestamp.
  2. Subscribes to relays with since filter (if cached) or full history.
  3. Buffers incoming events.
  4. Updates activeMap and calls onVideo for valid updates.

When to Modify

  • New Event Kinds: If adding support for a new NIP or event type, add handlers here.
  • Performance Tuning: Adjust buffering timeouts or cache policies in EventsCacheStore if UI responsiveness issues arise.
  • Signer Logic: If modifying how keys are handled (e.g., adding a new wallet adapter), update signerHelpers.js or nip46Client.js, but ensure NostrClient integrates it correctly.