#9825: feat(nostr): upgrade to NIP-17 with NIP-65 relay discovery
channel: nostr
stale
Cluster:
Network Error Handling Improvements
## Summary
Upgrades the Nostr channel from NIP-04 to NIP-17 for encrypted DMs.
### Why?
- **NIP-04 leaks metadata** — sender/recipient pubkeys visible to relays
- **NIP-17 is the standard** — gift-wrapped messages hide metadata
- **Better relay support** — NIP-65 discovery ensures delivery
### Changes
- Default to NIP-17 gift-wrapped DMs
- Add NIP-65 relay discovery (finds recipient's preferred relays)
- Add NIP-42 AUTH support (for auth-required relays)
- Backwards compat via `dmProtocol: "nip04"` config
### New Files
- `src/nip17.ts` — Gift wrap/unwrap implementation
- `src/nip65.ts` — Relay discovery (kind:10050, 10002)
- `src/nip42.ts` — AUTH challenge/response
- Tests for all new modules
### Breaking Changes
Messages now use NIP-17 by default. Recipients need NIP-17 compatible clients:
- ✅ 0xchat, Amethyst, Damus (recent), Primal
- ❌ Very old clients
To maintain NIP-04 compatibility:
```yaml
channels:
nostr:
dmProtocol: "nip04"
```
### Testing
- NIP-17 unit tests: 30 passing
- NIP-42 unit tests: 26 passing
- NIP-65 unit tests: 8 passing (5 network-dependent skipped)
- Integration tests: 26 passing
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR upgrades the Nostr channel to use NIP-17 (gift-wrapped DMs) by default, adds NIP-65 relay discovery when sending DMs, and introduces a NIP-42 AUTH module. The main runtime changes are in `extensions/nostr/src/nostr-bus.ts`, which now (a) subscribes to kind `1059` when `dmProtocol` is `nip17`, (b) unwraps gift-wrapped events to recover sender+plaintext, and (c) discovers recipient relays before publishing.
Key things to double-check before merge:
- Receiving NIP-17 DMs depends on the wrap event matching the bus’s `"#p": [pk]` subscription filter.
- NIP-42 is currently not integrated into the relay I/O path (the handler is instantiated but unused).
<h3>Confidence Score: 2/5</h3>
- This PR has significant functional gaps in NIP-17 receiving and NIP-42 integration that should be addressed before merging.
- Score reduced due to a likely subscription/filter mismatch for kind:1059 events (could prevent receiving DMs) and because NIP-42 AUTH is added but not actually wired into relay interactions; additional minor correctness issues exist in npub decoding.
- extensions/nostr/src/nostr-bus.ts, extensions/nostr/src/nip17.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#21778: Nostr: enforce inbound DM policy and command authorization
by chansuke · 2026-02-20
74.7%
#14904: fix(nostr): handle string return from nip19.decode in normalizePubkey
by mcaxtr · 2026-02-12
71.7%
#4562: fix(nostr): use dispatchReplyFromConfig for inbound messages
by Abhijrathod · 2026-01-30
70.6%
#11898: Fix for issue #11895
by rerickardjr · 2026-02-08
70.4%
#4878: fix: string/type handling and API fixes (#4537, #4380, #4373, #4547...
by lailoo · 2026-01-30
69.8%
#16507: feat(nostr): refactor channel dispatch logic (AI-assisted)
by tanujbhaud · 2026-02-14
68.8%
#7562: fix: nostr plugin filter double-wrapping in subscribeMany
by kaigritun · 2026-02-03
68.7%
#23727: Fix Telegram channel resolution drift across announce + message sen...
by SmithLabsLLC · 2026-02-22
68.0%
#13881: fix: Address Greptile feedback - test isolation and channel resolution
by trevorgordon981 · 2026-02-11
67.6%
#12936: fix(telegram): omit message_thread_id for private DM chats
by omair445 · 2026-02-09
66.6%