feat: display listings from nostr - #38
Open
lambdakilo wants to merge 3 commits into
Open
Conversation
lambdakilo
force-pushed
the
37/nostr-events-landing-page
branch
from
August 15, 2026 10:58
cfaa59e to
a84e50f
Compare
lambdakilo
marked this pull request as ready for review
August 19, 2026 10:24
lambdakilo
requested review from
guildm4ster and
spherical-spinach
and
a lite review from Copilot
August 19, 2026 10:24
Member
Author
|
i hope i did the subscription feature correctly in ndk instead of using ndk-svelte since i recall guildmaster saying something about that particular function |
There was a problem hiding this comment.
Pull request overview
This PR switches the landing page bounty listing from mock data to live Nostr kind:30050 events via NDK subscriptions, adding client-side parsing/deduplication and deletion handling so edited bounties collapse into a single card and retracted bounties are hidden.
Changes:
- Add a read/parse layer for kind:30050 bounty events, including dedupe-by-address and NIP-09 deletion tracking.
- Update the landing page to subscribe to relays on mount and render loading/empty states plus live bounty cards keyed by stable address.
- Extend the
Bountytype (address + optional check-in interval) and update mocks/UI + expand unit tests substantially.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/bounty.ts | Implements parsing, deduping, deletion tracking, and visible-bounty selection for relay events. |
| src/routes/+page.svelte | Replaces mock listing with an NDK subscription and adds loading/empty/timeout UI states. |
| src/lib/types/bounty.ts | Extends Bounty with stable address and makes checkInIntervalDays optional. |
| src/lib/components/BountyCard.svelte | Links bounty cards using the stable bounty address (URL-encoded). |
| src/lib/mock/bounties.ts | Updates mock bounties and lookup to use address-based routing. |
| src/routes/bounties/[id]/+page.svelte | Adjusts detail page rendering for optional check-in interval and clarifies mock-only behavior. |
| src/lib/bounty.test.ts | Adds broad unit coverage for parsing, dedupe, and deletion visibility logic. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+110
to
+116
| const { id, pubkey, created_at: createdAt } = event; | ||
| const title = event.tagValue('title')?.trim(); | ||
| const status = event.tagValue('s'); | ||
| const resolutionMode = event.tagValue('resolution_mode'); | ||
|
|
||
| if (!id || !pubkey || !createdAt || !event.dTag || !title) return null; | ||
| if (!isBountyStatus(status)) return null; |
Comment on lines
+187
to
+199
| const { pubkey, created_at: at } = event; | ||
| if (!pubkey || !at) return; | ||
|
|
||
| const targets = [ | ||
| ...event.getMatchingTags('a'), | ||
| ...event.getMatchingTags('e') | ||
| ]; | ||
| for (const [, target] of targets) { | ||
| if (!target) continue; | ||
| const current = deletions.get(target); | ||
| if (!current || at > current.at) { | ||
| deletions.set(target, { at, by: pubkey }); | ||
| } |
Comment on lines
+34
to
+41
| // One subscription, one EOSE. `#s` keeps other apps' kind-30050 events out | ||
| // of the limit; the deletion filter uses the `k` tag NDKEvent.delete() | ||
| // writes, so it only matches retracted bounties. | ||
| const sub = ndk().subscribe( | ||
| [ | ||
| { kinds: [BOUNTY_KIND], '#s': [...BOUNTY_STATUSES], limit: 100 }, | ||
| { kinds: [NDKKind.EventDeletion], '#k': [String(BOUNTY_KIND)] } | ||
| ], |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
prompt for opus 4.8: display nostr events in listing view i.e. the landing page. the code should
be as minimal as possible and as close to official documentation and best practices as possible
because its production code and not poc. i think the bounties should be fetched from the relays.
might be hard to remove the asdfasdf note i sent already to some relays.
the landing page rendered three hardcoded bounties. the app could already write kind:30050 events
at /bounties/new but never read them back. it now subscribes to the relays and renders live
bounties, dropping anything its author has retracted, which has to happen client side because
relay deletion support is advisory. scope is the data source only, no search or filter ui.
rebased onto origin/main, which brought in #35 (single bounty page ui). #35 changed both the card
and the bounty type, so this branch adopts those rather than keeping its own.
@nostr-dev-kit/ndk-svelte was rejected despite being the obvious fit: its subscription helper
leaves the old copy in place when an edit arrives, so editing a bounty duplicates it permanently,
and its deletion handling checks a non-standard tag rather than nip-09. worth knowing about ndk
proper too: its guardrails throw rather than warn, and their fetchevents check does not exempt
kind 30050, so enabling them outside production would start failing bounty queries.
the detail page is still mock-backed, so a card for a real relay bounty lands on "bounty not
found". that is where main already is rather than a regression from this branch, and it wants a
follow-up issue.
Related issue
Closes #37
Changes made
relay returns into one card, since subscribe() dedupes only by event id and an addressable event
gets a new id on every edit. the parser rejects rather than coerces, because one event with a
bogus status tag would otherwise blank the page, and it requires only the tags the ui cannot
render without, since our own publisher omits several the spec asks for. all pure functions, so
the parts most likely to be wrong are unit tested.
query is narrowed to events carrying a bounty status, because kind 30050 is a shared namespace
and unrelated apps' traffic would otherwise push real bounties out of the query window: same 2
bounties either way, raw events down from 101 to 20.
the author and timestamp retraction matching needs.
link and the rebase took it silently, so every edit would have broken that bounty's own link.
keeps working with the widened type.
Author checklist
bun run prruns all the commands below in one go.bun run format- code has been formattedbun run lint- no prettier/eslint errorsbun run check- no svelte-check/TypeScript errorsbun run test- all tests passbun run build- build succeedsReviewer manual testing checklist
without a reload