Files
uniweb/app.md
T
agent 3f52167b04 feat: browser-native client — wire SPA to the SDK, delete the Go gateway
Phase 2 of issue 0001. uniweb becomes a pure frontend (web/ only), like
unibus_android: the SPA talks directly to the bus and the Go gateway is gone.

- busService.ts: the new data layer over the bus SDK, replacing the old api module.
  It holds the user's wallet identity and a connected BusClient IN THE BROWSER and
  opens the session locally — the private key is never sent anywhere (closes the
  gateway-era hole where the browser POSTed its private key to /api/session).
- Wire account/App/ChatShell/ChatPanel/WalletLogin/Recover/Join to busService;
  subscribeRoom replaces the SSE streamRoom; ApiError -> SessionError.
- SDK: ControlPlane.createRoom + listMemberRooms, and fetchRoom mapped to the real
  control-plane wire shape (snake_case, no id) — all verified by the live round-trip.
- Delete cmd/webgw, go.mod, go.sum, src/api.ts and the orphan operator Login. uniweb
  now has zero Go and no dependency on unibus as a module.
- vite: drop the /api proxy, dev server on 5173 to match the bus CORS allowlist; add
  vite-env typings. app.md: lang ts, no uses_functions, e2e_checks are now web-only.
  Bump 0.3.0.

Onboarding by token is now admin-side (the bus has no self-register endpoint; the
gateway only mocked it). tsc + pnpm build + 19/19 unit green.
2026-06-14 11:39:06 +02:00

7.8 KiB

name, lang, domain, version, description, tags, uses_functions, uses_types, framework, entry_point, dir_path, repo_url, icon, e2e_checks
name lang domain version description tags uses_functions uses_types framework entry_point dir_path repo_url icon e2e_checks
uniweb ts infra 0.3.0 Cliente web browser-nativo del bus unibus: SPA de chat (React+Mantine) con wallet por usuario (BIP39) que habla DIRECTO al bus (nats.ws + control-plane HTTPS firmado), sin gateway. La clave privada nunca sale del navegador.
messaging
web
frontend
e2e
react web/src/main.tsx projects/message_bus/apps/uniweb https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/uniweb
phosphor accent
chats-circle #6366f1
id cmd timeout_s
typecheck cd web && pnpm install --frozen-lockfile && pnpm exec tsc --noEmit -p tsconfig.app.json 180
id cmd timeout_s
unit cd web && pnpm test 120
id cmd timeout_s
web_build cd web && pnpm build 180

Qué es

uniweb es el cliente web browser-nativo del bus unibus: la interfaz que un humano usa desde el navegador para hablar por el bus. Es solo frontend (web/) — una SPA, sin backend Go, sin gateway. Habla directamente con el bus, igual que unibus_android lo hace en Kotlin:

  • Control plane — HTTPS firmado al membershipd (rooms, claves, miembros). Cada request lleva la firma Ed25519 del usuario (cabeceras X-Unibus-*).
  • Data plane — NATS sobre WebSocket (nats.ws), autenticado con el nkey derivado de la identidad del usuario.

Stack: React 18 + Vite + Mantine v9. La identidad criptográfica de cada usuario se deriva de forma determinista de una frase BIP39 de 12 palabras y se cifra at-rest en el dispositivo (AES-256-GCM). La clave privada nunca sale del navegador: firma, sella y descifra en el cliente. No hay servidor al que enviarla.

El SDK del bus (web/src/bus/)

El protocolo y el cifrado E2E del bus están portados a TypeScript, validados byte a byte contra la implementación Go de referencia (vectores de unibus cmd/busvectors):

  • crypto.ts — Ed25519, ChaCha20-Poly1305, sealed box (nonce BLAKE2b, igual que Go).
  • frame.ts — wire format = encoding/json de Go byte a byte.
  • room.ts — Policy (ModeNATS / ModeMatrix).
  • busauth.ts — nkey NATS (base32 + crc16) + firma de requests del control-plane.
  • client.ts — envelope de room + BusClient + ControlPlane HTTP firmado.
  • wstransport.ts — transporte nats.ws.

busService.ts es la capa de datos de la SPA sobre el SDK (reemplazó al viejo módulo api que hablaba con el gateway). Ya no depende de unibus como módulo Go: el desacople es total.

Ejemplo

# El bus ya corre (cluster unibus con WebSocket habilitado, --ws-port). Apunta la SPA a un
# nodo y arráncala en dev (puerto 5173, que coincide con la CORS allowlist del cluster):
cd web && pnpm install
VITE_BUS_HTTP=https://<nodo>:8470 VITE_BUS_WS=wss://<nodo>:8480 pnpm dev
# Navegador: http://localhost:5173

# Producción: build estático y sirve web/dist con cualquier static server.
cd web && pnpm build   # genera web/dist

Cuándo usarla

Cuando quieras que un humano hable por el bus desde un navegador, o cuando trabajes en la UI de chat / el onboarding wallet. Para la lógica del bus en sí (membresía, claves, peers programáticos) ve a unibus; uniweb es el cliente web encima.

Gotchas

  • wss:// con CA self-signed: el cluster sirve el WebSocket con el cert del bus (CA propia). Un navegador rechaza wss:// self-signed salvo que se importe la CA o se ponga un reverse proxy con cert válido (Let's Encrypt). En dev se puede aceptar el cert a mano.
  • Onboarding admin-side: el bus no tiene endpoint de auto-registro (el viejo gateway lo mockeaba). En enforce, una identidad nueva debe ser autorizada por un admin (membershipd user add) antes de poder abrir sesión; el flujo de Join muestra la clave pública del usuario para que un admin la autorice.
  • CORS: el dev server corre en http://localhost:5173 para coincidir con la --cors-origins del cluster. Otro origen necesita añadirse a esa allowlist.
  • La passphrase del wallet nunca se guarda ni se envía; perderla en un dispositivo sin la mnemónica BIP39 = identidad irrecuperable en ese dispositivo (recuperable en otro con las 12 palabras).

Capability growth log

  • v0.3.0 (2026-06-14) — uniweb se vuelve cliente browser-nativo puro (issue 0001, Fase 2): la SPA se cablea al SDK del bus (busService.ts reemplaza el módulo api) y se elimina el gateway Go (cmd/webgw, go.mod, go.sum). uniweb queda como solo web/, sin nada de Go, sin dependencia de unibus como módulo. La clave privada se usa solo en el navegador (saveAndOpen/unlockAndOpen abren la sesión localmente; ya NO se hace POST /api/session con la privada — se cierra el agujero E2E del modelo gateway). Validado end-to-end contra el cluster descentralizado real (Fase 3): identidad registrada conecta por nats.ws y hace round-trip de un mensaje cifrado (crear room → publicar → recibir descifrado + firma verificada). El onboarding por token queda admin-side (el bus no tiene auto-registro). tsc + pnpm build + 19/19 unit verdes.

  • v0.2.0 (2026-06-13) — SDK del bus en TypeScript (web/src/bus/), issue 0001 Fase 1: el protocolo y el cifrado E2E del bus portados al navegador para que uniweb deje de depender del gateway Go. Módulos: crypto.ts (Ed25519, ChaCha20-Poly1305, sealed box con nonce BLAKE2b igual que Go), frame.ts (wire format = encoding/json de Go byte a byte), room.ts (Policy), busauth.ts (nkey NATS + firma de requests del control-plane), client.ts (envelope de room puro + BusClient sobre una interfaz de transporte + cliente HTTP firmado) y wstransport.ts (adaptador nats.ws). Paridad cross-language verificada contra vectores Go (cmd/busvectors): 19/19 tests verdes — endpoint id, firma Ed25519, AEAD, sealed box, frame marshal/sign, nkey y canonical request. La clave privada del usuario nunca se serializa hacia la red. La conexión nats.ws + control-plane reales se validan en la Fase 3 (E2E) por requerir un unibus vivo con WebSocket.

  • v0.1.0 (2026-06-13) — scaffold inicial: extracción de la SPA (web/) y el gateway (cmd/webgw) desde unibus v0.13.0 a su propia app/sub-repo. Sin cambios de capacidad respecto a lo que ya vivía en unibus 0.12.0 (wallet BIP39 + sesiones por usuario); solo cambia la ubicación y el módulo Go. go build/vet/test + pnpm build verdes en la nueva ubicación con los replace cross-repo.

  • v0.2.0 (2026-06-13) — SDK del bus en TypeScript (web/src/bus/), issue 0001 Fase 1: el protocolo y el cifrado E2E del bus portados al navegador para que uniweb deje de depender del gateway Go. Módulos: crypto.ts (Ed25519, ChaCha20-Poly1305, sealed box con nonce BLAKE2b igual que Go), frame.ts (wire format = encoding/json de Go byte a byte), room.ts (Policy), busauth.ts (nkey NATS + firma de requests del control-plane), client.ts (envelope de room puro + BusClient sobre una interfaz de transporte + cliente HTTP firmado) y wstransport.ts (adaptador nats.ws). Paridad cross-language verificada contra vectores Go (cmd/busvectors): 19/19 tests verdes — endpoint id, firma Ed25519, AEAD, sealed box, frame marshal/sign, nkey y canonical request. La clave privada del usuario nunca se serializa hacia la red. La conexión nats.ws + control-plane reales se validan en la Fase 3 (E2E) por requerir un unibus vivo con WebSocket.

  • v0.1.0 (2026-06-13) — scaffold inicial: extracción de la SPA (web/) y el gateway (cmd/webgw) desde unibus v0.13.0 a su propia app/sub-repo. Sin cambios de capacidad respecto a lo que ya vivía en unibus 0.12.0 (wallet BIP39 + sesiones por usuario); solo cambia la ubicación y el módulo Go. go build/vet/test + pnpm build verdes en la nueva ubicación con los replace cross-repo.