Skip to content

Conversation

@alltheseas
Copy link
Contributor

@alltheseas alltheseas commented Dec 19, 2025

Summary

Upgrade from alltheseas/rust-nostr fork (PR #1172) to upstream rust-nostr/nostr with merged PR #1156 for relay provenance tracking.

Changes

Dependencies

  • nostr-sdk and nostr: now point to upstream rust-nostr/nostr @ 1ecd7161

API Migration

Aspect Before (PR #1172) After (PR #1156)
Return type BoxedStream<RelayEvent> BoxedStream<(RelayUrl, Result<Event, Error>)>
Relay URL .relay_url()Option<&RelayUrl> Direct from tuple (always present)
Event access .event via Deref Unwrap from Result

Error Handling

  • Track success_relays and error_relays per stream
  • Only fail when ALL distinct targeted relays error
  • Dedupe relay targets before comparison (handles duplicate bech32 hints)
  • Use early returns with combined conditions (nevernesting pattern)

Files Changed

  • Cargo.toml / Cargo.lock: Updated dependencies
  • src/relay_pool.rs: New return type and method names
  • src/render.rs: Handle Result wrapper, per-relay error tracking

Relay Provenance Preserved

  • Source relay URLs collected for NIP-19 bech32 hints ✅
  • Event deduplication across relays ✅
  • All 10 tests passing ✅

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for embedded quotes with author details, timestamps, and content previews.
    • Added rendering for highlighted text with contextual information and source attribution.
    • Enhanced article previews with draft status indicators.
  • Chores

    • Improved dependency management for build stability.
    • Enhanced CI workflow for reliable package installations.

✏️ Tip: You can customize this high-level summary in your review settings.

alltheseas and others added 8 commits December 18, 2025 21:23
Adds comprehensive rendering for additional nostr event types:

NIP-84 Highlights (kind:9802):
- Extract highlight metadata (context, comment, source references)
- Render highlighted text with blockquote styling
- Support source attribution for web URLs, notes, and articles
- Preserve relay hints via bech32 parsing for nevent/naddr

NIP-18 Quote Embeds (q tags and inline mentions):
- Parse q tags and inline nostr:nevent/note mentions for quote references
- Rich embedded quotes with author avatar, name, @username
- Relative timestamps (e.g., "7h", "2d") with full date on hover
- "Show more" link for truncated content
- NIP-10 reply detection via e-tag "reply" marker

NIP-23 Draft Badge:
- Visual indicator for unpublished articles (kind:30024)

Human-readable mentions:
- Resolve @npub profile mentions to display names when available
- Show abbreviated bech32 as fallback when profile not cached

Helper functions for clean code organization:
- parse_hex_id(): hex string to 32-byte array
- detect_reply_author(): NIP-10 compliant reply detection
- lookup_profile_handle(): profile name resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes 404 errors when Ubuntu package versions change on mirrors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add @username handle below author name in note/article/highlight headers
- Fix profile name lookup to filter out empty strings (prevents showing
  just "@" when profile has empty display_name/name fields)
- Add CSS styling for .damus-note-handle

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show "Article" badge for kind 30023 embedded quotes
- Show "Draft" badge (orange) for kind 30024 embedded quotes
- Show "Highlight" badge for kind 9802 embedded quotes
- Fix empty string filtering in embedded quote profile extraction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add support for highlight (kind 9802) references in naddr mentions
- Style embedded highlights with left purple border instead of tag
- Remove quotation marks from highlight content
- Filter empty strings in embedded quote profile extraction

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Embedded article quotes now display as cards matching iOS Damus:
- Hero image (if available)
- Bold article title
- Summary text (if available)
- Word count
- DRAFT badge via CSS for kind 30024

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Integrate relay provenance tracking from rust-nostr PR #1172 to enable
proper NIP-19 bech32 links with relay hints for better content discoverability.

Changes:
- Update nostr-sdk to alltheseas/rust-nostr relay-provenance-tracking branch
- RelayPool::stream_events returns BoxedStream<RelayEvent> with source relay URL
- NoteAndProfileRenderData stores source_relays captured during fetch
- Generate bech32 links with relay hints for all event types (notes, articles, highlights)
- Filter profile (kind 0) relays from note hints
- Prioritize default relays in source_relays for reliability
- Preserve author/kind fields when rebuilding nevent bech32
- Graceful fallback to original nip19 on encoding failure with metric
- Add bech32_with_relays() helper with 8 unit tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Switch from alltheseas/rust-nostr fork (PR #1172) to upstream
rust-nostr/nostr with merged PR #1156 relay provenance support.

API changes:
- stream_events returns (RelayUrl, Result<Event, Error>) tuples
- Removed RelayEvent wrapper type
- RelayUrl now always present (previously Optional)

Error handling:
- Track success/error relays separately per stream
- Only fail when ALL distinct targeted relays error
- Dedupe relay targets before comparison (handles duplicate bech32 hints)
- Use early returns with combined conditions (nevernesting)

Relay provenance preserved:
- Source relay URLs collected for NIP-19 bech32 hints
- Event deduplication across relays maintained

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@alltheseas
Copy link
Contributor Author

@coderabbitai review please

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

@alltheseas, I'll review the changes in this PR for you.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Jan 16, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive support for NIP-18 (quotes) and NIP-84 (highlights) with rich HTML rendering, introduces relay URL support in bech32 encoding, refactors to use git-sourced dependencies, simplifies the RelayPool API by removing timeout parameters, and expands relay discovery with source relay tracking.

Changes

Cohort / File(s) Summary
Infrastructure & Dependencies
.github/workflows/rust.yml, Cargo.toml
Updated CI workflow to use apt-get update with non-interactive flag for reliable package installation; switched nostr-sdk and nostr dependencies from crates.io to git sources pinned to specific revisions.
Styling for NIP-18 & NIP-84
assets/damus.css
Added comprehensive CSS classes for embedded quotes, highlights (text, context, source, labels, comments), article previews (image, title with draft badge, summary, word count), and responsive adjustments. Introduced .damus-note-handle, .damus-article-draft, highlight-related classes, and extensive quote container styling.
HTML Rendering Engine
src/html.rs
Significantly expanded to support NIP-84 highlights and NIP-18 quotes: added HighlightMetadata extraction, quote reference resolution from q-tags, rich HTML preview generation with author info and timestamps, article metadata handling (title, image, summary, draft status), helper functions for profile/article lookups, and new build_embedded_quotes_html function. Modified render_note_content signature to accept database context (Ndb, Transaction).
Bech32 with Relay Support
src/nip19.rs
Introduced bech32_with_relays() function to embed relay URLs into bech32-encoded Nip19 events and coordinates, with comprehensive fallback logic and unit tests. Updated relay handling for Nip19::Event and Nip19::Coordinate.
Relay Pool & Streaming API
src/relay_pool.rs
Removed connect_timeout parameter from RelayPool::new() and eliminated timeout field; updated stream_events() signature to accept single Filter instead of vector and return BoxedStream<(RelayUrl, Result<Event, ClientError>)> instead of ReceiverStream<Event>; refactored internal connection handling.
Render Data & Source Relays
src/render.rs
Added source_relays field and helper methods to NoteAndProfileRenderData; modified find_note() to return prioritized relay list; refactored relay discovery to process filters individually with per-relay error tracking; updated public key conversions from serialize() to to_bytes() for Nip19 handling.
Integration
src/main.rs
Removed timeout argument from RelayPool::new() constructor call to match simplified API.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant RelayPool as Relay Pool
    participant Database as NostrDB
    participant HTMLRenderer as HTML Renderer
    
    Client->>RelayPool: Request note rendering
    RelayPool->>Database: Query note by NIP19
    Database-->>RelayPool: Return note + metadata
    
    RelayPool->>RelayPool: Extract quote references (q-tags)
    RelayPool->>Database: Lookup quoted note/article
    Database-->>RelayPool: Return quoted content
    
    RelayPool->>Database: Lookup author profile
    Database-->>RelayPool: Return profile (name, avatar)
    
    RelayPool->>HTMLRenderer: Pass note + quotes + profiles
    HTMLRenderer->>HTMLRenderer: Extract highlight metadata (NIP-84)
    HTMLRenderer->>HTMLRenderer: Build article source links
    HTMLRenderer->>HTMLRenderer: Render quote containers with author info
    HTMLRenderer->>HTMLRenderer: Assemble embedded_quotes_html
    HTMLRenderer-->>Client: Return rich HTML with quotes/highlights
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Hopping through quotes with relay delight,
Highlights now shine in HTML so bright,
NIP-eighteen dances with twenty-four's gleam,
Articles nested in every feed stream,
A web of connections, our code takes flight!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly references the core change: upgrading to upstream rust-nostr PR #1156 for relay provenance tracking, which aligns with the primary objective of migrating from a fork to upstream dependencies.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
src/html.rs (1)

619-673: Note: extract_url_pills is dead code.

This function is marked #[allow(dead_code)] and may be re-enabled in the future. If this is intentional for potential future use, consider adding a TODO comment explaining when it might be enabled.


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad9d797 and 68c0e9f.

⛔ Files ignored due to path filters (14)
  • .DS_Store is excluded by !**/.DS_Store
  • Cargo.lock is excluded by !**/*.lock
  • PM.png is excluded by !**/*.png
  • QL.png is excluded by !**/*.png
  • borked.png is excluded by !**/*.png
  • brokenlongformquote.png is excluded by !**/*.png
  • brokenquote.png is excluded by !**/*.png
  • draft.png is excluded by !**/*.png
  • iosquote.jpg is excluded by !**/*.jpg
  • missingname.png is excluded by !**/*.png
  • missingqh.png is excluded by !**/*.png
  • missingqh2.png is excluded by !**/*.png
  • npubnotname.png is excluded by !**/*.png
  • quote1.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • .github/workflows/rust.yml
  • Cargo.toml
  • assets/damus.css
  • src/html.rs
  • src/main.rs
  • src/nip19.rs
  • src/relay_pool.rs
  • src/render.rs
💤 Files with no reviewable changes (1)
  • src/main.rs
🧰 Additional context used
🧬 Code graph analysis (3)
src/html.rs (1)
src/abbrev.rs (2)
  • abbrev_str (24-31)
  • abbreviate (33-36)
src/nip19.rs (2)
src/relay_pool.rs (1)
  • new (29-54)
src/render.rs (1)
  • new (80-86)
src/render.rs (1)
src/relay_pool.rs (2)
  • new (29-54)
  • default_relays (56-58)
🔇 Additional comments (36)
.github/workflows/rust.yml (1)

18-21: LGTM!

Running apt-get update before apt-get install is best practice for CI environments — ensures the package index is current and prevents "package not found" failures when the runner's base image has stale package lists.

Cargo.toml (1)

20-24: Good use of git dependency with documentation.

The pinned revision approach is appropriate for consuming unreleased upstream features (PR #1156). The commit 1ecd716 ("relay-pool: include relay URL and result when streaming events") is stable and reachable from the master branch in the upstream repository. The comment explaining the dependency source is helpful for future maintainers.

Consider transitioning back to crates.io versions once rust-nostr publishes a release containing this feature, to benefit from the crate registry's availability guarantees.

src/nip19.rs (4)

1-1: LGTM on import changes.

The explicit import of Nip19Coordinate and Nip19Event from the nip19 module is correct and enables the new relay replacement functionality.


6-13: LGTM on relay extraction logic.

The nip19_relays function correctly clones relays from Event, Coordinate, and Profile variants. The direct .clone() approach is cleaner than manual parsing.


19-46: LGTM on bech32_with_relays implementation.

The function correctly:

  1. Returns original encoding when source_relays is empty (line 21-23)
  2. Preserves author and kind fields for Events (lines 30-35)
  3. Provides fallback to original encoding if new encoding fails (lines 36, 41)
  4. Handles Coordinate variant appropriately (lines 38-42)
  5. Returns original for unsupported variants (line 44)

The builder pattern with conditional chaining for author/kind is idiomatic.


48-208: Excellent test coverage.

The tests comprehensively cover:

  • Adding relays to nevent and naddr
  • Empty source_relays returning original
  • Replacing existing relays
  • Preserving author and kind fields
  • Extracting relays from various Nip19 variants

The assertions verify both the encoding and decoding round-trip behavior.

src/relay_pool.rs (3)

3-4: LGTM on import updates.

The imports correctly reflect the upstream API changes:

  • ClientError alias for proper error typing in the stream
  • BoxedStream for the new streaming return type

29-29: LGTM on simplified constructor.

Removing connect_timeout from the constructor aligns with the upstream API where timeout is specified per-operation rather than at pool construction time.


145-161: Approved: stream_events API correctly implements relay provenance from upstream PR #1156.

The signature BoxedStream<(RelayUrl, Result<Event, ClientError>)> properly surfaces both the source relay URL and per-event error handling from the pinned upstream commit. The conditional delegation to stream_events (empty relays) vs stream_events_from (specific relays) is correct.

src/render.rs (9)

74-97: LGTM on source_relays field and methods.

The source_relays field enables relay-hinted bech32 link generation. The add_source_relay method correctly prevents duplicates with the contains check (line 94).


348-396: LGTM on stream processing with relay provenance.

The pattern correctly:

  1. Unwraps events from Result (lines 365-373)
  2. Tracks success/error relays separately (lines 369, 375)
  3. Skips metadata events for note hints (lines 387-389)
  4. Deduplicates source relays (lines 391-395)

399-408: Well-designed failure condition with deduplication.

The logic correctly handles duplicate bech32 hints by comparing against unique_targets (line 400). The condition error_relays.len() >= target_count ensures we only fail when all distinct targeted relays have errored, not when the same relay errors multiple times.


410-418: LGTM on relay prioritization.

Sorting with b_is_default.cmp(&a_is_default) correctly places default relays first (since true > false). Truncating to MAX_SOURCE_RELAYS (3) keeps bech32 strings reasonably sized.


588-605: LGTM on source relay capture in complete().

The pattern correctly captures source relays from the fetch task and stores them in NoteAndProfileRenderData for later use in bech32 link generation.


686-739: LGTM on collect_profile_relays error handling.

Processing filters individually and tracking success/error counts is appropriate given the single-filter API. The warning when no relays succeed but errors occurred (lines 732-737) provides useful debugging info while still returning defaults.


794-803: Consistent error handling pattern.

The "all relays failed" logic mirrors find_note correctly, ensuring consistent behavior across both functions.


818-818: LGTM on API migration to to_bytes().

The change from serialize() to to_bytes() reflects the upstream nostr-sdk API. This is consistent across all Nip19 variant handling (Event author, Coordinate public_key, Profile public_key, Pubkey).

Also applies to: 861-861, 895-895, 906-906


1287-1287: LGTM on test API update.

Tag::coordinate(coordinate, None) matches the updated nostr SDK API for constructing coordinate tags without relay hints.

assets/damus.css (5)

261-266: LGTM on note handle styling.

The .damus-note-handle class provides appropriate styling for displaying the @username below the display name, with muted color for visual hierarchy.


358-372: LGTM on draft badge styling.

The orange gradient provides good visual distinction for draft articles. The small font size (0.4em) and uppercase styling clearly communicate the draft status without overwhelming the title.


374-408: LGTM on NIP-84 highlight styles.

The highlight styling correctly:

  • Uses left border accent for visual recognition
  • Applies italic styling for quoted text
  • Provides distinct styling for context, source, and comment sections

503-659: LGTM on embedded quote styling.

The comprehensive styling for NIP-18 embedded quotes includes:

  • Proper card-like appearance with hover effects
  • Avatar, author, username, and timestamp layout
  • Special handling for article cards with image, title, summary
  • Highlight styling with left border accent
  • URL pills for link previews

The CSS is well-organized and maintains consistency with the Damus design system.


615-626: LGTM on embedded draft badge pseudo-element.

Using ::after with content: "DRAFT" is an appropriate technique for adding the badge to embedded article titles. The styling matches the standalone draft badge.

src/html.rs (13)

11-11: LGTM on FromBech32 import.

The FromBech32 trait import enables parsing bech32 strings for relay hint extraction in highlight and quote metadata.


80-101: LGTM on HighlightMetadata struct.

The struct correctly captures NIP-84 highlight metadata:

  • context: surrounding text for context
  • comment: user's annotation
  • source_url, source_event_id, source_article_addr: source references
  • Preservation of original bech32 strings for relay hints

The documentation comments clearly explain each field's purpose.


177-293: LGTM on extract_highlight_metadata implementation.

The function correctly parses NIP-84 tags:

  • Handles both bech32 (nevent1, naddr1) and hex formats for e/a tags
  • Preserves original bech32 for relay hints
  • Validates URL schemes for r tags
  • Uses early continues with guard patterns for clean control flow

400-505: LGTM on render_note_content updates.

Adding ndb and txn parameters enables profile lookups for human-readable mentions. The handling of different mention types is appropriate:

  • Profile/Pubkey: displays resolved name with @ prefix
  • Event/Note: skipped inline (rendered as embedded quotes below)
  • Addr: displays abbreviated address with link

507-587: LGTM on profile lookup helpers.

The helpers provide clean abstractions:

  • lookup_profile_name: prefers display_name, falls back to name
  • lookup_profile_handle: prefers name (handle), falls back to display_name, formats as @username
  • detect_reply_author: implements NIP-10 reply detection with proper fallback chain
  • format_relative_time: provides compact time formatting (m/h/d/w)

831-1048: LGTM on build_embedded_quotes_html.

The function provides rich quote rendering with:

  • Author profile lookup (name, username, pfp)
  • Relative timestamp formatting
  • Reply context detection per NIP-10
  • Different layouts for articles vs notes vs highlights
  • Proper HTML escaping throughout

The article card layout with image, title, summary, and word count is well-structured.


1050-1085: LGTM on lookup_article_by_addr.

The function correctly:

  1. Parses the kind:pubkey:d-tag address format
  2. Queries with author and kind filter
  3. Iterates results to find matching d-tag
  4. Re-fetches by key for owned reference

1087-1122: LGTM on build_quote_link.

The function correctly prioritizes original bech32 to preserve relay hints, with fallbacks to generate bech32 without hints when necessary.


1189-1210: LGTM on quote deduplication.

The deduplication logic (lines 1196-1208) correctly prevents duplicate embedded quotes by comparing event_id or article_addr fields.


1329-1386: LGTM on build_highlight_content_html.

The highlight card structure correctly displays:

  • Author header with avatar and handle
  • Optional comment (user's annotation)
  • Highlighted text in blockquote with accent border
  • Optional context
  • Source attribution

1388-1425: LGTM on build_highlight_source_markup.

The source priority (article > note > URL) is correct per NIP-84 spec, using the most specific source type available.


2304-2316: LGTM on bech32 encoding with relay fallback.

The code correctly:

  1. Attempts relay-enhanced bech32 encoding first
  2. Falls back to original encoding on failure
  3. Logs warning and increments metric for monitoring fallback frequency

2327-2436: LGTM on kind-based routing.

The routing logic correctly handles:

  • kind 30023/30024: Long-form articles with draft badge for 30024
  • kind 9802: NIP-84 highlights with source attribution
  • Other kinds: Regular notes with embedded quotes

The relay handling (lines 2430-2434) appropriately prefers source_relays when available.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant