Swap the chat transport from the kez-chat server inbox to Nostr relays
without touching the identity model or the E2E crypto. The existing
SealedEnvelope (ed25519/x25519 + AES-GCM, our own key) is unchanged and
becomes the content of a Nostr event — Nostr only moves the bytes.
- nostr-id.ts: derive a secp256k1 signing key from the ed25519 seed
(HKDF, domain-separated — internal transport credential, never the
user's real Nostr account); route by a hash of the recipient's public
ed25519 primary since the curves can't be cross-derived.
- nostr-transport.ts: send/poll/stream mirroring messages.ts, via
SimplePool; per-handle time cursor + seen-id dedupe in localStorage.
- transport.ts: facade selecting server vs nostr via VITE_TRANSPORT
(code default stays "server"; this branch's .env flips it to nostr).
- inbox-service + Messages import from the facade.
Directory lookup (handle->primary) still runs on the kez-chat server;
identity stays internal. Metadata privacy is at parity with the server
transport (relay sees the from/to graph, body stays confidential).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>