NIP-28 compatibility proxy for [Sprout](../../VISION.md). Lets standard Nostr clients (Coracle, Amethyst, nak, etc.) connect to a Sprout relay using familiar NIP-28 channel events.
- **Shadow keys:** Each external pubkey gets a deterministic shadow keypair (HMAC-SHA256 of salt + pubkey). The relay sees the shadow key; the external user's real key is never exposed.
- **Channel map:** Loaded at startup from the relay's REST API. kind:40/41 events are synthesized locally — never forwarded upstream.
- **Invite tokens:** In-memory, scoped to specific channels, time-limited, use-limited. Lost on proxy restart.
- **`proxy:submit` scope:** Allows the proxy's API token to submit shadow-signed events through the relay's pubkey enforcement.
- **Pre-auth buffering:** REQ messages sent before NIP-42 auth completes are buffered (max 20 msgs / 64 KiB) and replayed after auth.
---
## Troubleshooting
| Symptom | Cause | Fix |
|---------|-------|-----|
| `"error: invite token not found"` | Token expired, used up, or proxy restarted | Create new token via `POST /admin/invite` |
| `"auth-required: authentication timeout"` | Client didn't respond to AUTH challenge within 30s | Use a NIP-42-capable client |
| `"error: channel not found"` | Channel created after proxy started | Restart proxy to refresh channel map |
| Connection drops immediately | Relay not running or wrong `SPROUT_UPSTREAM_URL` | Check `just relay` is running |
| No messages appearing | Wrong kind:40 event ID in subscription | Re-query kind:40 to get correct event ID |
| Startup fails: "failed to initialize channel map" | Can't reach relay REST API | Check relay health and API token scopes |
---
For the full guide including client-specific setup, architecture details, and extended troubleshooting, see [GUIDES/NOSTR_CLIENT_GUIDE.md](../../GUIDES/NOSTR_CLIENT_GUIDE.md).