Skip to content

@snort/worker-relay Examples

Real-world usage of WorkerRelayInterface from the Snort app.

Initialization with search index configuration

The app configures full-text search on kind 1 events and handles the Vite dev/production worker loading pattern:

typescript
// Cache/index.ts
const workerRelay = hasWasm
  ? new WorkerRelayInterface(
      import.meta.env.DEV
        ? new URL("@snort/worker-relay/dist/esm/worker.mjs", import.meta.url)
        : new WorkerVite(),
    )
  : undefined

export async function initRelayWorker() {
  try {
    if (workerRelay) {
      await workerRelay.debug("*")
      await workerRelay.init({
        databasePath: "relay.db",
        insertBatchSize: 100,
      })
      await workerRelay.configureSearchIndex({
        1: [],  // full-text search index for kind 1, don't index tags
      })
    }
  } catch (e) {
    console.error(e)
  }
}

forYouFeed() for personalized recommendations

The ML-powered feed runs entirely against the local SQLite database — no network round-trips:

typescript
// ForYouTab.tsx
const getFeed = useCallback(() => {
  if (!login.publicKey) return []
  if (!getForYouFeedPromise && Relay instanceof WorkerRelayInterface) {
    getForYouFeedPromise = Relay.forYouFeed(login.publicKey)
  }
  getForYouFeedPromise?.then(notes => {
    getForYouFeedPromise = null
    if (notes.length < 10) {
      setTimeout(() => {
        if (Relay instanceof WorkerRelayInterface) {
          getForYouFeedPromise = Relay.forYouFeed(login.publicKey!)
        }
      }, 1000)
    }
    setNotes(notes)
  })
}, [login.publicKey])

setEventMetadata for tracking seen_at

Mark when a user sees an event (debounced to avoid excessive writes):

typescript
// Note.tsx
useEffect(() => {
  let timeout: ReturnType<typeof setTimeout>
  if (setSeenAtInView && Relay instanceof WorkerRelayInterface) {
    const r = Relay as WorkerRelayInterface
    timeout = setTimeout(() => {
      r.setEventMetadata(ev.id, { seen_at: Math.round(Date.now() / 1000) })
    }, 1000)
  }
  return () => clearTimeout(timeout)
}, [setSeenAtInView, ev.id])

count() for reply counts from cache

Avoid a full relay subscription by counting replies in the local cache:

typescript
// NoteFooter.tsx
useEffect(() => {
  const cacheRelay = system.cacheRelay
  if (cacheRelay instanceof WorkerRelayInterface && !props.replyCount) {
    const fx = new RequestFilterBuilder()
      .kinds([EventKind.TextNote, EventKind.Comment])
      .replyToLink([link])
    cacheRelay.count(["REQ", "", fx.filter]).then(setReplyCount)
  }
}, [system, link, props.replyCount])

Admin UI: summary, wipe, and dump

typescript
// Cache.tsx
useEffect(() => {
  if (Relay instanceof WorkerRelayInterface) {
    Relay.summary().then(setCounts)              // event counts by kind
    if (login.publicKey) {
      Relay.count(["REQ", "my", { authors: [login.publicKey] }]).then(setMyEvents)
    }
  }
}, [login.publicKey])

// Wipe the database:
await Relay.wipe()

// Dump the database:
const data = Relay instanceof WorkerRelayInterface ? await Relay.dump() : undefined