feat: display listings from nostr - #38
Draft
lambdakilo wants to merge 1 commit into
Draft
Conversation
lambdakilo
force-pushed
the
37/nostr-events-landing-page
branch
from
August 15, 2026 10:58
cfaa59e to
a84e50f
Compare
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
task as given: "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 bounty objects. the app could already write
kind:30050 events through /bounties/new but never read them back. it now subscribes to the
relays and renders live bounties, honouring nip-09 retractions. scope kept deliberately narrow:
data source only, no search or filter ui, bountycard untouched.
Related issue
Closes #37
Changes
makerpubkey, createdat. address keys the list and survives revisions; the rest drive
nip-09 matching.
upsertbounty, recorddeletion, visiblebounties, all pure so the risky logic is unit
testable.
loading / empty / relay-timeout states.
parsebountyevent.
reasoning
dedupe is ours to do. ndk's subscribe() dedupes only by event id, so two relays holding
different revisions of one addressable bounty deliver two events. we collapse by
kind:pubkey:d, newest wins.
@nostr-dev-kit/ndk-svelte was rejected despite being the obvious fit. its $subscribe
splices a newer revision into the list without removing the old one, so editing a bounty
duplicates it permanently, and its skipdeleted checks a non-standard ["deleted"] tag
than nip-09. ndk.subscribe(filter, { onevent }) is what ndk's own guardrails recommend for
feeds anyway.
the parser rejects rather than coerces. relay data is untrusted, and the satcode-dem
reference parser casts the s tag with as bountystatus, so an event carrying ["s","pwned"]
would reach bountycard's status lookup and blank the page. required tags are limited
the card needs, since buildbountyevent omits spec-required gov_key_*, refund_address and
check_in_days and the parser must not reject our own writes.
kind 30050 is contested namespace. verified against live relays before merging:
{ kinds: [30050], limit: 100 } returned 157 events of which 2 were bounties, the rest being
unrelated apps (encrypted key bundles, chat rooms, device handshakes). the parser dr
155 cleanly, but the limit was the real problem, since relays return the most recent kind:30050
events and genuine bounties get pushed out of the window. adding '#s': [...bounty_st
narrows to events carrying a bounty status. measured side by side on live relays: same 2
bounties, raw events down from 101 to 20.
nip-09 is honoured client side. a second filter in the same subscription picks up ki
events tagged k=30050, matched by address or event id and only when signed by the bounty's own
author. relay deletion support is advisory, so handling it in the client makes retra
reliable.
onmount rather than $effect: never runs during ssr (so ndk is only constructed in the
browser), never tracks reads, and its return value is the teardown. unreachable rela
send eose, so an 8s timeout releases the spinner.
--after merge--
Rebased onto origin/main. #35 (Single bounty page UI) landed after this branch was cut. Two files conflicted textually; three more merged clean and broke.
Known gap: the detail page is still mock-backed, so a card for a real relay bounty lands on "Bounty not found". That's where main already is, not a regression from this branch — worth a follow-up issue.
Two stale lines in the current description: "bountycard untouched", and "40 new cases" (the file runs 41 now).
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
on / without a reload
rather than duplicating