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>
29 lines
1.2 KiB
TypeScript
29 lines
1.2 KiB
TypeScript
// Transport facade. The rest of the app (inbox-service, Messages) imports
|
|
// send/poll/stream/decrypt from here and never learns which pipe carries
|
|
// the bytes. Both transports expose an identical surface and both ship the
|
|
// same sealed envelope from crypto.ts — only the delivery mechanism differs.
|
|
//
|
|
// VITE_TRANSPORT=server (default) → kez-chat server inbox over HTTP/SSE
|
|
// VITE_TRANSPORT=nostr → Nostr relays
|
|
//
|
|
// Set it in .env / .env.local. Switching transports is build-time; there's
|
|
// no reason to flip it at runtime and keeping it static lets Vite tree-shake
|
|
// the unused transport out of the bundle.
|
|
|
|
import * as server from "./messages.js";
|
|
import * as nostr from "./nostr-transport.js";
|
|
|
|
const TRANSPORT = (import.meta.env.VITE_TRANSPORT ?? "server") as "server" | "nostr";
|
|
|
|
const impl = TRANSPORT === "nostr" ? nostr : server;
|
|
|
|
export const sendMessage = impl.sendMessage;
|
|
export const pollInbox = impl.pollInbox;
|
|
export const streamInbox = impl.streamInbox;
|
|
export const decrypt = impl.decrypt;
|
|
|
|
export type { InboxMessage, StreamHandle, SealedEnvelope, MessagePlaintext } from "./messages.js";
|
|
|
|
/** Which transport this build is using — handy for a debug line in the UI. */
|
|
export const activeTransport = TRANSPORT;
|