diff --git a/app.md b/app.md index ff86143..8fbcc5f 100644 --- a/app.md +++ b/app.md @@ -2,7 +2,7 @@ name: uniweb lang: ts domain: infra -version: 0.5.0 +version: 0.6.0 description: "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." tags: [messaging, web, frontend, e2e] uses_functions: [] @@ -102,6 +102,19 @@ programáticos) ve a `unibus`; `uniweb` es el cliente web encima. ## Capability growth log +- v0.6.0 (2026-06-14) — carga el histórico de cada room (`GET /api/rooms/{id}/history`) al + abrirla, con dedup vs live; recargar ya no pierde los mensajes. `ControlPlane.fetchHistory` + pega al control-plane (firmado, mismas cabeceras `X-Unibus-*`) y decodifica cada frame de + base64-std; `BusClient.history` lo descifra/verifica con el MISMO camino de envelope que + `subscribe` (refactor: helper privado `openFrame` compartido por ambos). En `busService`, + `bus.subscribeRoom` (que usa `ChatPanel`) ahora siembra la room con su historia y sigue en + vivo: dedup por `frame.id` con un `Set` por room y los mensajes live se bufferean hasta que + la historia (oldest->newest) se entrega, garantizando el orden; si el endpoint falta + (404/500) cae a live-only como antes. El ts de cada mensaje se deriva del ULID `msgID` + (`ulidTime`, inverso de `newULID`) para que historia y live compartan reloj y ordenen bien; + `ChatPanel` ordena por ts. El sidebar siembra su preview con `history(id, 1)` (sin traer + todo), manteniendo el fallback "—" para rooms vacías. `tsc` + 23 unit (incluye `ulid.test.ts`) + + `pnpm build` verdes. - v0.5.0 (2026-06-14) — nombres legibles en mensajes + sidebar con último mensaje/hora reales + `pnpm dev` documentado. (1) Los mensajes muestran el **handle** del remitente en vez del endpoint id: `ControlPlane.fetchDirectory()` pega al control-plane