The "strictly-monotonic created_at per coord" section named useRSVP.ts as canonical, but that file no longer exists. monotonicCreatedAt() in src/lib/nostr/timestamp.ts is now the single implementation — make the doc reference it and show both the per-coord-Map and single-field tracking shapes. Keeps doc and code aligned per the docs discipline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| profiles.md | ||
| publishing.md | ||
| reactions-and-deletions.md | ||
| README.md | ||
| replaceable-events.md | ||
| services-and-di.md | ||
| subscriptions.md | ||
Nostr patterns
Living reference for reusable Nostr patterns that show up across modules (events, forum, market, chat, tasks, base, nostr-feed).
Read before writing any new Nostr code in this repo. Update whenever you introduce, refine, or correct a pattern. Each section has a "Canonical implementation" line — that's the file the pattern was harvested from. If a caller deviates, document why or align with the canonical version.
The single biggest reason this directory exists: Nostr's edge cases (relay dedup, replaceable events, reactivity-of-nested-Map, EOSE timing) are subtle enough that re-deriving them per module produces different bugs each time. Consolidating the resolution prevents that.
Index
- Subscriptions & lifecycle — RelayHub usage, EOSE, unsubscribe on unmount, visibility-aware reconnect.
- Replaceable events — NIP-01 §13 semantics,
monotonic
created_at, per-pubkey latest-wins state, replaceable bookmark lists. - Publishing & confirmation —
RelayHub.publishEventresult checks, optimistic updates, signing withnostr-tools, pending-coord debounce. - Reactions, deletions & dedup — NIP-25 toggle, NIP-09 deletion handling, per-event-id dedup.
- Profiles & batch fetch — kind-0 caching, request dedup.
- Services, DI & reactivity —
BaseService,tryInjectService, exposing service state via computed, Vue 3 nested ref-Map reactivity gotchas.
Patterns specific to a single NIP that doesn't repeat across modules (currently: NIP-59 gift-wrapped market orders) are not listed here yet — only the cross-cutting patterns. When a second consumer adopts an NIP-specific pattern, promote it.
Conventions
- Canonical implementation is a single file path with line numbers. If a pattern lives in multiple modules, list one canonical and the rest as "alternates" with a short note on what differs.
- Why sections explain the failure mode the pattern prevents — not just what it does. If the why is obvious from the code, omit it.
- Cross-link by file when patterns compose (e.g. replaceable events almost always pair with the pending-coord debounce).
- Don't duplicate code into the docs. Reference file:line and quote at most the 5-line core. Drift between code and docs is the failure mode.
Updating
When you implement a new pattern (or fix a subtle bug in an existing one):
- Add or amend the relevant topic file — leave a brief "added 2026-MM-DD, from " note if it helps trace provenance.
- If it's a brand-new topic, add a section to this README's index and create a new topic file.
- If the pattern obsoletes an alternate implementation listed here, either align that implementation or note explicitly why it diverges.
Improving
We periodically deep-dive into well-known open-source Nostr apps (Coracle,
Snort, Damus, NoStrudel, Habla, Highlighter, Flotilla, Zap.cooking) to mine
patterns we haven't reinvented yet. Tracked as a recurring issue on Forgejo
(aiolabs/webapp). Findings land here.