Data: 2025-01-18 Revisão de:
ai-context/development/live-components.mdeai-context/reference/live-components-api.md
- ✅ Endpoints HTTP documentados com exemplos curl
- ✅ Tipos TypeScript completos para requests/responses
- ✅ Exemplos de código cliente/servidor funcionais
- ✅ Seção de troubleshooting com soluções práticas
- ✅ Coverage completo das mensagens WebSocket
- ✅ Exemplos de componentes completos (CounterComponent)
- ✅ Código está correto e alinhado com a implementação real
- ✅ Exemplos práticos que podem ser copiados diretamente
- ✅ TypeScript types ajudam developers a entender contratos
- ✅ Cobre HTTP endpoints, WebSocket, criação de componentes
- ✅ Inclui métricas de performance e monitoramento
- ✅ Documentação de connection pooling e escalabilidade
Problema: Não há um guia "Hello World" de 5 minutos para developers começarem rapidamente.
Impacto: Desenvolvedores iniciantes ficam perdidos e não sabem por onde começar.
Sugestão:
# Quick Start - Live Components em 5 Minutos
## 1. Criar um Live Component Simples
```typescript
// app/server/live/HelloComponent.ts
import { LiveComponent } from '@/core/types/types'
export class HelloComponent extends LiveComponent {
state = { message: 'Hello, World!' }
async updateMessage(newMessage: string) {
this.state.message = newMessage
await this.emit('message-updated', { message: this.state.message })
}
}import { useHybridLiveComponent } from '@/core/client/hooks/useHybridLiveComponent'
function HelloWorld() {
const { state, call } = useHybridLiveComponent('HelloComponent', {
message: 'Hello'
})
return (
<div>
<h1>{state.message}</h1>
<button onClick={() => call('updateMessage', 'Olá!')}>
Change to Portuguese
</button>
</div>
)
}bun run dev # Backend + Frontend
# Acesse http://localhost:5173Pronto! Você criou seu primeiro Live Component. 🎉
---
### 2. **Hook `useHybridLiveComponent` Não Documentado**
**Problema**: O hook mais importante para developers frontend não tem documentação.
**Impacto**: Developers não sabem:
- Como usar o hook corretamente
- Quais são os parâmetros e opções
- Como funcionam features avançadas (rehydration, state persistence)
- Como tratar erros e estados de conexão
**Evidência**: Analisando o código real em `core/client/hooks/useHybridLiveComponent.ts`, o hook tem:
- State persistence automático com localStorage
- Rehydration após reconnection
- Support para `useControlledField` (não documentado)
- Status complexo: `'synced' | 'disconnected' | 'connecting' | 'reconnecting' | 'loading' | 'mounting' | 'error'`
**Sugestão**: Criar seção completa:
```markdown
# useHybridLiveComponent Hook - Guia Completo
## API
```typescript
const {
state, // Estado do componente (read-only)
loading, // Se está carregando
error, // Mensagem de erro (se houver)
connected, // Se WebSocket está conectado
componentId, // ID único do componente no servidor
status, // Status detalhado da conexão
call, // Chama action sem esperar resposta
callAndWait, // Chama action e espera resultado
mount, // Monta componente manualmente
unmount, // Desmonta componente manualmente
useControlledField // Helper para inputs controlados
} = useHybridLiveComponent<StateType>(
'ComponentName',
initialState,
{
autoMount: true, // Monta automaticamente? (default: true)
fallbackToLocal: true, // Usa estado local se servidor falhar? (default: true)
room: 'room-id', // Sala para broadcast (opcional)
userId: 'user-123', // ID do usuário (opcional)
debug: false // Ativa logs de debug? (default: false)
}
)
| Status | Descrição |
|---|---|
synced |
Conectado e sincronizado ✅ |
disconnected |
Desconectado ❌ |
connecting |
Conectando pela primeira vez 🔄 |
reconnecting |
Reconectando após desconexão 🔄 |
loading |
Carregando estado inicial ⏳ |
mounting |
Montando componente no servidor ⏳ |
error |
Erro durante operação |
O hook automaticamente:
- Salva estado no localStorage quando recebe updates do servidor
- Restaura estado quando reconecta (se < 1 hora)
- Valida estado usando assinatura criptográfica do servidor
// Exemplo: Estado persiste entre refreshes da página
const { state, status } = useHybridLiveComponent('TodoList', { todos: [] })
// Se você recarregar a página em < 1 hora:
// - Hook tenta rehydration automática
// - Se sucesso: restaura estado completo
// - Se falha: monta componente novoHelper para inputs que precisam de estado temporário antes de enviar ao servidor:
const { state, useControlledField } = useHybridLiveComponent('UserProfile', {
name: 'João',
email: 'joao@example.com'
})
function ProfileForm() {
const nameField = useControlledField('name', 'updateName')
return (
<div>
<input
value={nameField.value}
onChange={(e) => nameField.setValue(e.target.value)}
onBlur={() => nameField.commit()} // Envia ao servidor
/>
{nameField.isDirty && <span>*</span>}
</div>
)
}
---
### 3. **Documentação `development/live-components.md` Muito Técnica**
**Problema**: O arquivo `development/live-components.md` é muito focado em implementação interna.
**Impacto**:
- Iniciantes não conseguem entender o conceito
- Falta narrativa de "quando usar"
- Muito jargão técnico (`ComponentRegistry`, `StateSignature`, etc.)
**Comparação**:
**Atual (muito técnico):**
```markdown
## Fluxo de Componentes
1. **Registro**: classes em `app/server/live/*.ts` estendem `LiveComponent`
(veja `core/types/types.ts`) e são descobertas automaticamente.
2. **Conexão WebSocket**: o cliente (React ou outra UI) abre `ws://localhost:3000/api/live/ws`.
3. **Mensagens**: `COMPONENT_MOUNT` → monta componente e devolve snapshot inicial...
Deveria ser (mais acessível):
## O Que São Live Components?
Live Components são componentes React que se comunicam em tempo real com o servidor via WebSocket.
**Conceito**: Escreva lógica de negócio no backend, e a UI atualiza automaticamente.
**Inspiração**: Laravel Livewire, Phoenix LiveView
### Quando Usar?
✅ **Use Live Components para**:
- Dashboards em tempo real (preços, métricas)
- Chat e notificações
- Formulários com validação server-side
- Features colaborativas (editing simultâneo)
- Qualquer UI que precisa refletir mudanças server-side imediatamente
❌ **NÃO use Live Components para**:
- Páginas estáticas
- Lógica puramente client-side (animações, UI local)
- APIs públicas (use REST/GraphQL)
### Como Funciona?
[React Component] ←WebSocket→ [Live Component (Server)] ↓ ↓ UI Updates ←──────────── State Management + Business Logic
1. Component monta no servidor com estado inicial
2. Cliente recebe estado e renderiza UI
3. Usuário interage → Client envia action
4. Servidor processa action → Atualiza estado
5. Estado novo é enviado ao cliente automaticamente
6. UI re-renderiza com novo estado
Problema: LiveClockComponent.ts é um exemplo real excelente no código, mas não está na documentação.
Impacto: Developers não veem exemplos de código real, apenas exemplos didáticos.
Sugestão: Adicionar seção "Exemplos Reais":
# Exemplos Reais
## 1. Live Clock - Relógio em Tempo Real
Ver código completo: `app/server/live/LiveClockComponent.ts`
### Features Implementadas
- ✅ Atualização automática a cada segundo
- ✅ Broadcast para todos clientes conectados
- ✅ Formato 12h/24h
- ✅ Toggle de segundos e data
- ✅ Múltiplos timezones
- ✅ Uptime do servidor
- ✅ Cleanup automático de intervals
### Destaques de Implementação
**1. Interval Management**
```typescript
export class LiveClockComponent extends LiveComponent<LiveClockState> {
private clockInterval: NodeJS.Timeout | null = null
constructor(...) {
super(...)
this.startClock() // Inicia interval
}
private startClock() {
this.clockInterval = setInterval(() => {
this.updateClock()
}, 1000)
}
public destroy() {
if (this.clockInterval) {
clearInterval(this.clockInterval) // ✅ CRÍTICO: limpar resources
}
super.destroy()
}
}2. Broadcasting Updates
private updateClock() {
this.setState({ currentTime: timeString })
// Broadcast para TODOS clientes na mesma room
if (this.room) {
this.broadcast('CLOCK_TICK', {
currentTime: timeString,
timestamp: now.toISOString()
})
}
}3. Actions com Validação
async setTimeFormat(payload: { format: '12h' | '24h' }) {
const { format } = payload
// ✅ Validação server-side
if (format !== '12h' && format !== '24h') {
throw new Error('Invalid time format. Use "12h" or "24h"')
}
this.setState({ format })
this.updateClock() // Re-renderiza imediatamente
return { success: true, format }
}- Sempre limpe resources:
clearInterval,clearTimeout, conexões DB - Valide inputs: Actions podem receber dados maliciosos
- Use broadcasting: Para updates que afetam múltiplos clientes
- Return values: Actions podem retornar dados para o cliente
---
### 5. **Falta Guia de Boas Práticas Avançadas**
**Problema**: Não há orientações sobre patterns avançados.
**Impacto**: Developers cometem erros comuns:
- Memory leaks (não limpam intervals)
- Security issues (não validam inputs)
- Performance problems (state updates excessivos)
- Error handling inadequado
**Sugestão**: Criar seção "Best Practices":
```markdown
# Live Components - Boas Práticas
## 1. Resource Management (CRÍTICO)
### ❌ ERRADO - Memory Leak
```typescript
export class BadComponent extends LiveComponent {
constructor() {
super()
setInterval(() => {
this.updateData()
}, 1000)
// ❌ Interval nunca é limpo
}
}
export class GoodComponent extends LiveComponent {
private interval: NodeJS.Timeout | null = null
constructor() {
super()
this.interval = setInterval(() => {
this.updateData()
}, 1000)
}
public destroy() {
if (this.interval) {
clearInterval(this.interval) // ✅ Cleanup
}
super.destroy()
}
}async deleteUser(payload: { userId: string }) {
// ❌ Sem validação - qualquer cliente pode deletar qualquer user
await db.users.delete(payload.userId)
}async deleteUser(payload: { userId: string }) {
// ✅ Valida propriedade
if (this.userId !== payload.userId) {
throw new Error('Unauthorized: Cannot delete other users')
}
// ✅ Valida formato
if (!payload.userId.match(/^[a-z0-9-]+$/)) {
throw new Error('Invalid user ID format')
}
await db.users.delete(payload.userId)
}async onMouseMove(payload: { x: number, y: number }) {
// ❌ Envia WebSocket message em CADA movimento do mouse
this.setState({ mouseX: payload.x, mouseY: payload.y })
await this.emit('mouse-moved', payload)
}private lastEmit = 0
private EMIT_THROTTLE = 100 // 100ms
async onMouseMove(payload: { x: number, y: number }) {
this.setState({ mouseX: payload.x, mouseY: payload.y })
// ✅ Só emite a cada 100ms
const now = Date.now()
if (now - this.lastEmit > this.EMIT_THROTTLE) {
await this.emit('mouse-moved', payload)
this.lastEmit = now
}
}async fetchUserData(payload: { userId: string }) {
const user = await api.getUser(payload.userId) // ❌ Se falhar, quebra tudo
this.setState({ user })
}async fetchUserData(payload: { userId: string }) {
try {
const user = await api.getUser(payload.userId)
this.setState({ user, error: null, loading: false })
} catch (error) {
console.error('Failed to fetch user:', error)
this.setState({
error: 'Failed to load user data',
loading: false
})
// ✅ Component continua funcionando
}
}state = {
users: [],
userCount: 0, // ❌ Derivado de users.length
hasUsers: false // ❌ Derivado de users.length > 0
}state = {
users: [] // ✅ Única fonte de verdade
}
// Cálculos derivados no getter ou no cliente
get userCount() {
return this.state.users.length
}- Updates globais (novo post no feed)
- Notificações para múltiplos users
- State compartilhado (collaborative editing)
- State privado de um user
- Dados sensíveis
- Updates frequentes que não afetam outros users
// ✅ BOM - Notificação global
async createPost(payload: { title: string, content: string }) {
const post = await db.posts.create(payload)
if (this.room) {
this.broadcast('new-post', { post }) // Todos veem
}
}
// ❌ RUIM - Broadcast de dado privado
async updatePassword(payload: { oldPass: string, newPass: string }) {
await this.changePassword(payload)
// ❌ NUNCA faça broadcast de senha!
// this.broadcast('password-changed', payload)
}
---
### 6. **Fragmentação da Documentação**
**Problema**: Informação está dividida entre dois arquivos sem navegação clara.
**Impacto**: Developers não sabem qual arquivo ler primeiro.
**Estrutura Atual**:
ai-context/ ├── development/live-components.md (técnico, interno) ├── reference/live-components-api.md (API reference)
**Sugestão**: Reorganizar com hierarquia clara:
ai-context/ ├── development/ │ ├── live-components/ │ │ ├── 00-overview.md (O que são? Quando usar?) │ │ ├── 01-quick-start.md (Hello World em 5min) │ │ ├── 02-server-components.md (Criar componentes server) │ │ ├── 03-client-hooks.md (useHybridLiveComponent) │ │ ├── 04-advanced-patterns.md (Patterns avançados) │ │ └── 05-best-practices.md (Security, performance) │ └── live-components.md → [DEPRECADO - redirecionar para 00-overview.md] └── reference/ └── live-components-api.md (Continua como API reference)
---
### 7. **Falta Comparação com Alternativas**
**Problema**: Developers não sabem quando usar Live Components vs REST API vs GraphQL.
**Sugestão**:
```markdown
# Live Components vs Alternativas
## Quando Usar Cada Abordagem?
### 🔥 Live Components
**Use para**: Real-time updates, interactive UIs, dashboards
**Pros**:
- ✅ Updates automáticos sem polling
- ✅ State management no servidor
- ✅ Menos código boilerplate
- ✅ Type-safe com Eden Treaty
**Cons**:
- ❌ Requer WebSocket (pode ter problemas com proxies)
- ❌ Stateful (não escala horizontalmente sem sticky sessions)
- ❌ Não ideal para APIs públicas
**Exemplo**: Dashboard de vendas em tempo real
---
### 🌐 REST API (Eden Treaty)
**Use para**: CRUD tradicional, APIs públicas, operações stateless
**Pros**:
- ✅ Stateless - escala facilmente
- ✅ Caching HTTP padrão
- ✅ Compatível com qualquer cliente
**Cons**:
- ❌ Sem updates automáticos (precisa polling)
- ❌ Mais código boilerplate
**Exemplo**: API de cadastro de usuários
---
### 📊 GraphQL
**Use para**: Queries complexas, mobile apps, agregação de dados
**Pros**:
- ✅ Cliente escolhe dados necessários
- ✅ Reduz over-fetching
**Cons**:
- ❌ FluxStack não tem GraphQL built-in (use REST)
---
## Decision Matrix
| Feature | Live Components | REST API | GraphQL |
|---------|----------------|----------|---------|
| Real-time updates | ✅ Automático | ❌ Polling | ❌ Polling |
| Type Safety | ✅ Eden Treaty | ✅ Eden Treaty | ⚠️ Depende |
| Stateless | ❌ Stateful | ✅ Stateless | ✅ Stateless |
| Public APIs | ❌ Não ideal | ✅ Ideal | ✅ Ideal |
| Interactive UI | ✅ Ideal | ⚠️ OK | ⚠️ OK |
| Escalabilidade | ⚠️ Vertical | ✅ Horizontal | ✅ Horizontal |
| Caching | ❌ Difícil | ✅ HTTP Cache | ⚠️ Complexo |
Problema: Documentação é 100% texto - faltam diagramas de arquitetura.
Impacto: Developers visuais têm dificuldade de entender fluxos.
Sugestão: Adicionar diagramas Mermaid:
## Arquitetura de Live Components
```mermaid
graph TB
subgraph "Client (React)"
A[Component UI] --> B[useHybridLiveComponent]
B --> C[LiveComponentsProvider]
C --> D[WebSocket Client]
end
subgraph "Network"
D <-->|"WSS"| E[WebSocket Endpoint]
end
subgraph "Server (Elysia)"
E --> F[Connection Manager]
F --> G[Component Registry]
G --> H[LiveComponent Instance]
H --> I[Business Logic]
H --> J[State Management]
end
style A fill:#61dafb
style H fill:#ff6b6b
style C fill:#51cf66sequenceDiagram
participant C as Client
participant WS as WebSocket
participant S as Server
participant LC as LiveComponent
C->>WS: Connect
WS->>S: CONNECTION_ESTABLISHED
C->>WS: COMPONENT_MOUNT
WS->>S: Mount Request
S->>LC: new LiveComponent()
LC->>S: Initial State
S->>WS: COMPONENT_MOUNTED
WS->>C: Initial State + ID
C->>WS: CALL_ACTION (increment)
WS->>LC: Execute Action
LC->>LC: Update State
LC->>WS: STATE_UPDATE
WS->>C: New State
C->>C: Re-render UI
C->>WS: COMPONENT_UNMOUNT
WS->>LC: destroy()
LC->>S: Cleanup
---
## 📋 **SUMÁRIO DE RECOMENDAÇÕES**
### 🔴 **CRÍTICO - Implementar ASAP**
1. **Quick Start de 5 Minutos**
- Criar `ai-context/development/live-components/01-quick-start.md`
- Exemplo "Hello World" copy-paste
2. **Documentar `useHybridLiveComponent`**
- Criar `ai-context/development/live-components/03-client-hooks.md`
- Incluir todas opções, helpers, e state lifecycle
3. **Best Practices e Security**
- Criar `ai-context/development/live-components/05-best-practices.md`
- Incluir resource management, validation, error handling
### 🟡 **IMPORTANTE - Próxima Iteração**
4. **Overview Acessível**
- Reescrever `development/live-components.md` com foco em conceitos
- Adicionar seção "Quando Usar vs REST API"
5. **Exemplos Reais Documentados**
- Documentar `LiveClockComponent` como exemplo real
- Adicionar mais exemplos práticos (Chat, Dashboard)
6. **Reorganizar Estrutura**
- Criar subpasta `live-components/` com arquivos numerados
- Adicionar README.md como índice navegável
### 🟢 **NICE TO HAVE - Futuro**
7. **Diagramas Visuais**
- Adicionar diagramas Mermaid de arquitetura
- Diagramas de fluxo de mensagens
8. **Comparação com Alternativas**
- Decision matrix: Live Components vs REST vs GraphQL
- Guia de quando usar cada abordagem
---
## 🎯 **CONCLUSÃO**
### Nota Geral: **6.5/10**
**Resumo**:
- ✅ API Reference está **excelente** (8/10)
- ⚠️ Development Guide está **muito técnico** (5/10)
- ❌ **Falta** Quick Start para iniciantes (0/10)
- ❌ **Falta** documentação do hook principal (0/10)
- ❌ **Falta** best practices e security (0/10)
**Recomendação**: A documentação está **funcional mas incompleta**. Developers experientes conseguem usar, mas iniciantes vão ter dificuldade. Implementar as sugestões **CRÍTICAS** vai melhorar drasticamente a DX (Developer Experience).
---
**Próximos Passos Sugeridos**:
1. Criar Quick Start primeiro (maior impacto)
2. Documentar `useHybridLiveComponent` (segundo maior impacto)
3. Best Practices (previne bugs e security issues)
4. Reorganizar estrutura (melhora navegação)
5. Adicionar diagramas (melhora compreensão)