A merge left the v0.2.0 and v0.1.0 growth-log entries duplicated. Keep one entry per version in descending order and add the v0.5.0 line covering this release: readable handles in messages, sidebar with real last message/time, and the documented `pnpm dev` setup. Frontmatter version 0.4.0 -> 0.5.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.2 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.5.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. |
|
react | web/src/main.tsx | projects/message_bus/apps/uniweb | https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/uniweb |
|
|
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 (cabecerasX-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/jsonde 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+ControlPlaneHTTP firmado.wstransport.ts— transportenats.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
# Producción: SPA same-origin detrás de Caddy, que sirve la SPA + /api + /nats.
# Build estático y despliegue de web/dist:
cd web && pnpm install
pnpm build # genera web/dist (se despliega a magnus:/opt/uniweb/dist)
# Dev (`pnpm dev`): el dev server NO tiene el proxy de Caddy, así que /api y /nats no
# existen en localhost. Apunta la SPA a un nodo real del cluster con las env vars
# (overrides del default same-origin). El dev server corre en el puerto 5174:
VITE_BUS_HTTP=https://<nodo>:8470 VITE_BUS_WS=wss://<nodo>:8480 pnpm dev
# Navegador: http://localhost:5174
# (Añade http://localhost:5174 a la --cors-origins del nodo, o el control-plane
# rechazará la petición por CORS.)
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 rechazawss://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 / same-origin: en producción la SPA es same-origin detrás de Caddy (
/apiy/natsproxyados), así que no hay CORS. En dev (pnpm dev, puerto 5174) esos paths relativos no existen: hay que apuntar a un nodo conVITE_BUS_HTTP/VITE_BUS_WSy añadirhttp://localhost:5174a la--cors-originsdel nodo. El puerto 5173 está reservado a otra app local; si 5174 está ocupado, Vite usa el siguiente libre. - 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.5.0 (2026-06-14) — nombres legibles en mensajes + sidebar con último mensaje/hora
reales +
pnpm devdocumentado. (1) Los mensajes muestran el handle del remitente en vez del endpoint id:ControlPlane.fetchDirectory()pega al control-planeGET /api/directory(firmado) ybusServicemantiene un mapaendpoint -> handle(cargado al abrir sesión, refrescado trascreateRoom); el resolverbus.displayName(endpoint)devuelve el handle o un id corto de fallback (nunca el endpoint largo), usado en la cabecera y el avatar deChatPanel(el endpoint queda en untitlepara depurar). Resiliente: si el endpoint aún no existe en el cluster (404) el mapa queda vacío y el chat funciona igual que antes. (2) El sidebar muestra el último mensaje y la hora reales:busServiceposee un store de rooms con una suscripción de metadatos por room (último mensaje/hora + unread de rooms no activas);Sidebarya no pinta el "01:00" de epoch-0. (3)pnpm devqueda usable tras el cambio a same-origin: apunta a un nodo conVITE_BUS_HTTP/VITE_BUS_WSy el dev server corre en el puerto 5174 (documentado enapp.md+vite.config.ts).tsc+ 19/19 unit +pnpm buildverdes. - v0.3.0 (2026-06-14) —
uniwebse vuelve cliente browser-nativo puro (issue 0001, Fase 2): la SPA se cablea al SDK del bus (busService.tsreemplaza el móduloapi) y se elimina el gateway Go (cmd/webgw,go.mod,go.sum).uniwebqueda como soloweb/, sin nada de Go, sin dependencia deunibuscomo módulo. La clave privada se usa solo en el navegador (saveAndOpen/unlockAndOpenabren la sesión localmente; ya NO se hacePOST /api/sessioncon la privada — se cierra el agujero E2E del modelo gateway). Validado end-to-end contra el cluster descentralizado real (Fase 3): identidad registrada conecta pornats.wsy 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 queuniwebdeje 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/jsonde Go byte a byte),room.ts(Policy),busauth.ts(nkey NATS + firma de requests del control-plane),client.ts(envelope de room puro +BusClientsobre una interfaz de transporte + cliente HTTP firmado) ywstransport.ts(adaptadornats.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ónnats.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) desdeunibusv0.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 losreplacecross-repo.