You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

8.2 KiB

Nostr Archives integration — rollout checkpoint

Last updated: 2026-06-03
Purpose: Preserve plan position across agent “Fix” runs and chat resets. Resume from Next step below.

API docs: https://nostrarchives.com/docs
Rule file: .cursor/rules/nostr-archives-integration.mdc


Status summary

Phase Description Status
0 Foundation (API client, ingest, graceful failure, search relay constant) DONE
1 Profile: follower count + paginated followers list DONE
2 search.nostrarchives.com in SEARCHABLE_RELAY_URLS DONE (in Phase 0)
3 General notes search: local + Archives REST merge DONE
4 Note stats: prefetch /v1/events/{id}/interactions DONE
5a /v1/search/suggest in profile picker DONE
5b POST /v1/profiles/metadata in search/thread UIs DONE
6 Note page: layered load (session → IDB → Archives → relays) DONE

Other recent work (same branch, separate from Archives): Post editor TipTap blank-field fix (stable extensions + placeholder shell) — see commit history on imwald.


Cross-cutting rules (all phases)

  1. Persist verified events — Any Archives payload with valid Nostr events goes through persistArchivesEventsIfNew / persistArchivesPayloadEvents → session cache + IndexedDB archive (client.addEventToCachequeuePersistSeenEvent). Skip if already in session or archive. Slim rows without valid sig are not persisted; use getEventById or relay backfill for offline.
  2. Graceful failurenostrArchivesApi returns TArchivesApiResult; never throw. On failure: hide Archives-only UI or fall back to relays/local. Circuit breaker (2 failures → 60s). Setting: storage.getUseNostrArchivesApi() (default on). Hook: useNostrArchivesAvailable().
  3. Rate limit — 100 req/min client budget via nostrArchivesApi only; batch metadata and interaction prefetch.

Phase 0 — DONE (foundation files)

File Role
src/constants.ts NOSTR_ARCHIVES_API_BASE_URL, NOSTR_ARCHIVES_SEARCH_RELAY_URL, rate limit, StorageKey.USE_NOSTR_ARCHIVES_API, search relay in SEARCHABLE_RELAY_URLS
src/types/nostr-archives.ts TArchivesApiResult, social, interactions, metadata, note page types
src/lib/nostr-archives-event.ts Strip enrichment fields; archivesJsonToVerifiedEvent()
src/lib/nostr-archives-ingest.ts persistArchivesEventsIfNew, persistArchivesPayloadEvents
src/services/nostr-archives-api.service.ts HTTP client, circuit breaker, all endpoint stubs
src/services/local-storage.service.ts getUseNostrArchivesApi / setUseNostrArchivesApi
src/hooks/useNostrArchivesAvailable.ts UI availability
.cursor/rules/nostr-archives-integration.mdc Agent constraints

Service methods ready: getEventInteractions, getSocialGraph, getEventById, getNotePage, searchNotes, searchGeneral, searchSuggest, fetchProfilesMetadata.


Phase 1 — DONE: Followers on profile

File Role
src/hooks/useNostrArchivesSocial.ts Counts via getSocialGraph (followers_limit=0)
src/components/Profile/SmartFollowers.tsx Count + link; hidden when API unavailable or no count
src/components/Profile/index.tsx Renders SmartFollowers next to SmartFollowings
src/pages/secondary/FollowersListPage/index.tsx Paginated list (100/page), infinite scroll
src/lib/link.ts toFollowersList
src/routes.tsx, PageManager.tsx, navigation.service.ts Route + mobile/desktop nav
i18n en.ts / de.ts Followers strings + indexer hint

Offline: !social.ok or !useNostrArchivesAvailable() → hide count and list unavailable message on list page.


File Role
src/lib/nostr-archives-search.ts searchArchivesNotesForGeneralSearch/v1/notes/search
src/components/SearchResult/FullTextSearchByRelay.tsx Parallel local + Archives rows; merged hits; source badges

Offline: Archives progress row hidden when !useNostrArchivesAvailable(); local search unchanged.

Deferred: searchGeneral resolved entity navigation (profile/note picker) — not wired in notes full-text UI yet.


Phase 4 — DONE: Interaction prefetch

File Role
src/lib/note-stats-archives-prefetch.ts Batched queue → getEventInteractions
src/services/note-stats.service.ts archivesInteractions on TNoteStats, applyArchivesInteractionCounts, display helpers
src/components/NoteStats/index.tsx prefetchArchivesInteractions when near viewport
Stat buttons displayListCountWithArchives / displayZapSatsWithArchives, noteStatsHasResolvableCounts

Offline: Prefetch no-op; relay stats unchanged.


Phase 5 — Profiles medium

5a — DONE

  • src/lib/archives-profile-metadata.tsarchivesMetadataToProfile
  • client.searchProfilesStagedsearchSuggest after local, before profile relays

5b — DONE

File Role
src/lib/profile-metadata-batch.ts fetchProfilesMetadataBatch — Archives POST metadata, relay gap fill
FullTextSearchByRelay.tsx Search merged profile provider
ThreadProfileBatchProvider.tsx Thread/note panel batch
ProfileList/index.tsx Followers list + other pubkey lists
ProfileListBySearch/index.tsx Profile search results prefetch

Phase 6 — DONE: Note page pipeline

File Role
src/lib/note-page-load-pipeline.ts resolveNoteEventFromArchives, fetchArchivesNotePageBundle, prewarmArchivesNotePage
src/lib/thread-context-local.ts Archives REST after IDB archive, before publication store
src/hooks/useFetchEvent.tsx Local stores + Archives before relay fetchEvent
src/pages/secondary/NotePage/index.tsx Background prewarmArchivesNotePage (replies + interaction counts)

Deferred: optional IDB bundle cache service; NoteCard hover prewarm (no hover handler in card today).


Suggested PR order (unchanged)

  1. PR0+2: Foundation + search relay (done)
  2. PR1: Phase 1 followers ← resume here after review fixes
  3. PR3: Notes search merge
  4. PR4: Interactions prefetch
  5. PR5: Suggest
  6. PR6: Metadata batch
  7. PR7: Note page pipeline

Agent review / Fix button — scratch pad

Use this section to note review findings so the next session does not lose context.

Open issues (fill in when Fix runs)

None — minor gaps addressed 2026-06-03 (settings toggle, search resolved, note bundle profiles, feed metadata batch).

Fixes applied

  • ARCHIVES_ENGAGEMENT_KEYS included 'event' — stripped nested { event: … } wrappers before archivesJsonToVerifiedEvent could unwrap them. Removed 'event' from the set; test in src/lib/nostr-archives-event.test.ts.
  • isPersistableNostrEventShape allowed NaN kindtypeof NaN === 'number' passed; now Number.isFinite(ev.kind) (and early return in archivesJsonToVerifiedEvent after coercion).
  • Duplicate getEventById in useFetchEvent — removed second resolveNoteEventFromArchives call; resolveThreadContextEventFromLocalStores already hits Archives REST.
  • Settings UI — General settings toggle for useNostrArchivesApi; nostrArchivesApi.notifySettingsChanged() on change.
  • searchGeneral resolvedtryResolveSearchViaArchives in SearchPage submit path; src/lib/nostr-archives-search-resolved.ts.
  • Note page bundle profilesThreadProfileBatchProvider.seedProfiles + prewarmArchivesNotePage callback on NotePage.
  • Feed profile batchNoteList uses fetchProfilesMetadataBatch.

Resume prompt (paste into a new chat)

Continue Nostr Archives rollout from `.cursor/plans/nostr-archives-rollout.md`.
Nostr Archives rollout phases 0–6 are complete. Use this file for review fixes or follow-ups (e.g. `searchGeneral` resolved navigation, optional note bundle IDB cache).
Respect `.cursor/rules/nostr-archives-integration.mdc`.
Check "Agent review / Fix button" section for any open issues first.