create-fluxstack 1.9.1 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LIVE_COMPONENTS_REVIEW.md +781 -0
- package/app/client/src/App.tsx +39 -43
- package/app/client/src/lib/eden-api.ts +2 -7
- package/app/client/src/live/FileUploadExample.tsx +359 -0
- package/app/client/src/live/MinimalLiveClock.tsx +47 -0
- package/app/client/src/live/QuickUploadTest.tsx +193 -0
- package/app/client/src/main.tsx +10 -10
- package/app/client/src/vite-env.d.ts +1 -1
- package/app/client/tsconfig.app.json +45 -44
- package/app/client/tsconfig.node.json +25 -25
- package/app/server/index.ts +30 -103
- package/app/server/live/LiveFileUploadComponent.ts +77 -0
- package/app/server/live/register-components.ts +19 -19
- package/core/build/bundler.ts +4 -1
- package/core/build/index.ts +124 -4
- package/core/build/live-components-generator.ts +68 -1
- package/core/cli/index.ts +163 -35
- package/core/client/LiveComponentsProvider.tsx +3 -9
- package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
- package/core/client/hooks/useChunkedUpload.ts +112 -61
- package/core/client/hooks/useHybridLiveComponent.ts +80 -26
- package/core/client/hooks/useTypedLiveComponent.ts +133 -0
- package/core/client/hooks/useWebSocket.ts +4 -16
- package/core/client/index.ts +20 -2
- package/core/framework/server.ts +181 -8
- package/core/live/ComponentRegistry.ts +5 -1
- package/core/plugins/built-in/index.ts +8 -5
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +55 -63
- package/core/plugins/built-in/vite/index.ts +75 -187
- package/core/plugins/built-in/vite/vite-dev.ts +88 -0
- package/core/plugins/registry.ts +54 -2
- package/core/plugins/types.ts +86 -2
- package/core/server/index.ts +1 -2
- package/core/server/live/ComponentRegistry.ts +14 -5
- package/core/server/live/FileUploadManager.ts +22 -25
- package/core/server/live/auto-generated-components.ts +29 -26
- package/core/server/live/websocket-plugin.ts +19 -5
- package/core/server/plugins/static-files-plugin.ts +49 -240
- package/core/server/plugins/swagger.ts +33 -33
- package/core/types/build.ts +1 -0
- package/core/types/plugin.ts +9 -1
- package/core/types/types.ts +137 -0
- package/core/utils/logger/startup-banner.ts +20 -4
- package/core/utils/version.ts +1 -1
- package/eslint.config.js +23 -23
- package/package.json +3 -3
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/tsconfig.json +52 -52
- package/workspace.json +5 -5
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
# 📊 Análise da Documentação de Live Components
|
|
2
|
+
|
|
3
|
+
> **Data**: 2025-01-18
|
|
4
|
+
> **Revisão de**: `ai-context/development/live-components.md` e `ai-context/reference/live-components-api.md`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ✅ **PONTOS FORTES**
|
|
9
|
+
|
|
10
|
+
### 1. **API Reference Bem Estruturada** (`live-components-api.md`)
|
|
11
|
+
- ✅ Endpoints HTTP documentados com exemplos curl
|
|
12
|
+
- ✅ Tipos TypeScript completos para requests/responses
|
|
13
|
+
- ✅ Exemplos de código cliente/servidor funcionais
|
|
14
|
+
- ✅ Seção de troubleshooting com soluções práticas
|
|
15
|
+
- ✅ Coverage completo das mensagens WebSocket
|
|
16
|
+
- ✅ Exemplos de componentes completos (CounterComponent)
|
|
17
|
+
|
|
18
|
+
### 2. **Qualidade Técnica**
|
|
19
|
+
- ✅ Código está correto e alinhado com a implementação real
|
|
20
|
+
- ✅ Exemplos práticos que podem ser copiados diretamente
|
|
21
|
+
- ✅ TypeScript types ajudam developers a entender contratos
|
|
22
|
+
|
|
23
|
+
### 3. **Coverage Abrangente**
|
|
24
|
+
- ✅ Cobre HTTP endpoints, WebSocket, criação de componentes
|
|
25
|
+
- ✅ Inclui métricas de performance e monitoramento
|
|
26
|
+
- ✅ Documentação de connection pooling e escalabilidade
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## ❌ **PROBLEMAS CRÍTICOS**
|
|
31
|
+
|
|
32
|
+
### 1. **Falta de Quick Start para Iniciantes**
|
|
33
|
+
|
|
34
|
+
**Problema**: Não há um guia "Hello World" de 5 minutos para developers começarem rapidamente.
|
|
35
|
+
|
|
36
|
+
**Impacto**: Desenvolvedores iniciantes ficam perdidos e não sabem por onde começar.
|
|
37
|
+
|
|
38
|
+
**Sugestão**:
|
|
39
|
+
```markdown
|
|
40
|
+
# Quick Start - Live Components em 5 Minutos
|
|
41
|
+
|
|
42
|
+
## 1. Criar um Live Component Simples
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// app/server/live/HelloComponent.ts
|
|
46
|
+
import { LiveComponent } from '@/core/types/types'
|
|
47
|
+
|
|
48
|
+
export class HelloComponent extends LiveComponent {
|
|
49
|
+
state = { message: 'Hello, World!' }
|
|
50
|
+
|
|
51
|
+
async updateMessage(newMessage: string) {
|
|
52
|
+
this.state.message = newMessage
|
|
53
|
+
await this.emit('message-updated', { message: this.state.message })
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 2. Usar no Frontend (React)
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { useHybridLiveComponent } from '@/core/client/hooks/useHybridLiveComponent'
|
|
62
|
+
|
|
63
|
+
function HelloWorld() {
|
|
64
|
+
const { state, call } = useHybridLiveComponent('HelloComponent', {
|
|
65
|
+
message: 'Hello'
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div>
|
|
70
|
+
<h1>{state.message}</h1>
|
|
71
|
+
<button onClick={() => call('updateMessage', 'Olá!')}>
|
|
72
|
+
Change to Portuguese
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 3. Rodar e Testar
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
bun run dev # Backend + Frontend
|
|
83
|
+
# Acesse http://localhost:5173
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Pronto!** Você criou seu primeiro Live Component. 🎉
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### 2. **Hook `useHybridLiveComponent` Não Documentado**
|
|
92
|
+
|
|
93
|
+
**Problema**: O hook mais importante para developers frontend não tem documentação.
|
|
94
|
+
|
|
95
|
+
**Impacto**: Developers não sabem:
|
|
96
|
+
- Como usar o hook corretamente
|
|
97
|
+
- Quais são os parâmetros e opções
|
|
98
|
+
- Como funcionam features avançadas (rehydration, state persistence)
|
|
99
|
+
- Como tratar erros e estados de conexão
|
|
100
|
+
|
|
101
|
+
**Evidência**: Analisando o código real em `core/client/hooks/useHybridLiveComponent.ts`, o hook tem:
|
|
102
|
+
- State persistence automático com localStorage
|
|
103
|
+
- Rehydration após reconnection
|
|
104
|
+
- Support para `useControlledField` (não documentado)
|
|
105
|
+
- Status complexo: `'synced' | 'disconnected' | 'connecting' | 'reconnecting' | 'loading' | 'mounting' | 'error'`
|
|
106
|
+
|
|
107
|
+
**Sugestão**: Criar seção completa:
|
|
108
|
+
|
|
109
|
+
```markdown
|
|
110
|
+
# useHybridLiveComponent Hook - Guia Completo
|
|
111
|
+
|
|
112
|
+
## API
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const {
|
|
116
|
+
state, // Estado do componente (read-only)
|
|
117
|
+
loading, // Se está carregando
|
|
118
|
+
error, // Mensagem de erro (se houver)
|
|
119
|
+
connected, // Se WebSocket está conectado
|
|
120
|
+
componentId, // ID único do componente no servidor
|
|
121
|
+
status, // Status detalhado da conexão
|
|
122
|
+
call, // Chama action sem esperar resposta
|
|
123
|
+
callAndWait, // Chama action e espera resultado
|
|
124
|
+
mount, // Monta componente manualmente
|
|
125
|
+
unmount, // Desmonta componente manualmente
|
|
126
|
+
useControlledField // Helper para inputs controlados
|
|
127
|
+
} = useHybridLiveComponent<StateType>(
|
|
128
|
+
'ComponentName',
|
|
129
|
+
initialState,
|
|
130
|
+
{
|
|
131
|
+
autoMount: true, // Monta automaticamente? (default: true)
|
|
132
|
+
fallbackToLocal: true, // Usa estado local se servidor falhar? (default: true)
|
|
133
|
+
room: 'room-id', // Sala para broadcast (opcional)
|
|
134
|
+
userId: 'user-123', // ID do usuário (opcional)
|
|
135
|
+
debug: false // Ativa logs de debug? (default: false)
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Status da Conexão
|
|
141
|
+
|
|
142
|
+
| Status | Descrição |
|
|
143
|
+
|--------|-----------|
|
|
144
|
+
| `synced` | Conectado e sincronizado ✅ |
|
|
145
|
+
| `disconnected` | Desconectado ❌ |
|
|
146
|
+
| `connecting` | Conectando pela primeira vez 🔄 |
|
|
147
|
+
| `reconnecting` | Reconectando após desconexão 🔄 |
|
|
148
|
+
| `loading` | Carregando estado inicial ⏳ |
|
|
149
|
+
| `mounting` | Montando componente no servidor ⏳ |
|
|
150
|
+
| `error` | Erro durante operação ⚠️ |
|
|
151
|
+
|
|
152
|
+
## State Persistence e Rehydration
|
|
153
|
+
|
|
154
|
+
O hook automaticamente:
|
|
155
|
+
1. **Salva estado** no localStorage quando recebe updates do servidor
|
|
156
|
+
2. **Restaura estado** quando reconecta (se < 1 hora)
|
|
157
|
+
3. **Valida estado** usando assinatura criptográfica do servidor
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Exemplo: Estado persiste entre refreshes da página
|
|
161
|
+
const { state, status } = useHybridLiveComponent('TodoList', { todos: [] })
|
|
162
|
+
|
|
163
|
+
// Se você recarregar a página em < 1 hora:
|
|
164
|
+
// - Hook tenta rehydration automática
|
|
165
|
+
// - Se sucesso: restaura estado completo
|
|
166
|
+
// - Se falha: monta componente novo
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## useControlledField - Inputs Controlados
|
|
170
|
+
|
|
171
|
+
Helper para inputs que precisam de estado temporário antes de enviar ao servidor:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const { state, useControlledField } = useHybridLiveComponent('UserProfile', {
|
|
175
|
+
name: 'João',
|
|
176
|
+
email: 'joao@example.com'
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
function ProfileForm() {
|
|
180
|
+
const nameField = useControlledField('name', 'updateName')
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div>
|
|
184
|
+
<input
|
|
185
|
+
value={nameField.value}
|
|
186
|
+
onChange={(e) => nameField.setValue(e.target.value)}
|
|
187
|
+
onBlur={() => nameField.commit()} // Envia ao servidor
|
|
188
|
+
/>
|
|
189
|
+
{nameField.isDirty && <span>*</span>}
|
|
190
|
+
</div>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### 3. **Documentação `development/live-components.md` Muito Técnica**
|
|
199
|
+
|
|
200
|
+
**Problema**: O arquivo `development/live-components.md` é muito focado em implementação interna.
|
|
201
|
+
|
|
202
|
+
**Impacto**:
|
|
203
|
+
- Iniciantes não conseguem entender o conceito
|
|
204
|
+
- Falta narrativa de "quando usar"
|
|
205
|
+
- Muito jargão técnico (`ComponentRegistry`, `StateSignature`, etc.)
|
|
206
|
+
|
|
207
|
+
**Comparação**:
|
|
208
|
+
|
|
209
|
+
**Atual (muito técnico):**
|
|
210
|
+
```markdown
|
|
211
|
+
## Fluxo de Componentes
|
|
212
|
+
1. **Registro**: classes em `app/server/live/*.ts` estendem `LiveComponent`
|
|
213
|
+
(veja `core/types/types.ts`) e são descobertas automaticamente.
|
|
214
|
+
2. **Conexão WebSocket**: o cliente (React ou outra UI) abre `ws://localhost:3000/api/live/ws`.
|
|
215
|
+
3. **Mensagens**: `COMPONENT_MOUNT` → monta componente e devolve snapshot inicial...
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Deveria ser (mais acessível):**
|
|
219
|
+
```markdown
|
|
220
|
+
## O Que São Live Components?
|
|
221
|
+
|
|
222
|
+
Live Components são componentes React que se comunicam em tempo real com o servidor via WebSocket.
|
|
223
|
+
|
|
224
|
+
**Conceito**: Escreva lógica de negócio no backend, e a UI atualiza automaticamente.
|
|
225
|
+
|
|
226
|
+
**Inspiração**: Laravel Livewire, Phoenix LiveView
|
|
227
|
+
|
|
228
|
+
### Quando Usar?
|
|
229
|
+
|
|
230
|
+
✅ **Use Live Components para**:
|
|
231
|
+
- Dashboards em tempo real (preços, métricas)
|
|
232
|
+
- Chat e notificações
|
|
233
|
+
- Formulários com validação server-side
|
|
234
|
+
- Features colaborativas (editing simultâneo)
|
|
235
|
+
- Qualquer UI que precisa refletir mudanças server-side imediatamente
|
|
236
|
+
|
|
237
|
+
❌ **NÃO use Live Components para**:
|
|
238
|
+
- Páginas estáticas
|
|
239
|
+
- Lógica puramente client-side (animações, UI local)
|
|
240
|
+
- APIs públicas (use REST/GraphQL)
|
|
241
|
+
|
|
242
|
+
### Como Funciona?
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
[React Component] ←WebSocket→ [Live Component (Server)]
|
|
246
|
+
↓ ↓
|
|
247
|
+
UI Updates ←──────────── State Management + Business Logic
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
1. Component monta no servidor com estado inicial
|
|
251
|
+
2. Cliente recebe estado e renderiza UI
|
|
252
|
+
3. Usuário interage → Client envia action
|
|
253
|
+
4. Servidor processa action → Atualiza estado
|
|
254
|
+
5. Estado novo é enviado ao cliente automaticamente
|
|
255
|
+
6. UI re-renderiza com novo estado
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
### 4. **Falta Exemplo Real Documentado**
|
|
261
|
+
|
|
262
|
+
**Problema**: `LiveClockComponent.ts` é um exemplo real excelente no código, mas não está na documentação.
|
|
263
|
+
|
|
264
|
+
**Impacto**: Developers não veem exemplos de código real, apenas exemplos didáticos.
|
|
265
|
+
|
|
266
|
+
**Sugestão**: Adicionar seção "Exemplos Reais":
|
|
267
|
+
|
|
268
|
+
```markdown
|
|
269
|
+
# Exemplos Reais
|
|
270
|
+
|
|
271
|
+
## 1. Live Clock - Relógio em Tempo Real
|
|
272
|
+
|
|
273
|
+
Ver código completo: `app/server/live/LiveClockComponent.ts`
|
|
274
|
+
|
|
275
|
+
### Features Implementadas
|
|
276
|
+
|
|
277
|
+
- ✅ Atualização automática a cada segundo
|
|
278
|
+
- ✅ Broadcast para todos clientes conectados
|
|
279
|
+
- ✅ Formato 12h/24h
|
|
280
|
+
- ✅ Toggle de segundos e data
|
|
281
|
+
- ✅ Múltiplos timezones
|
|
282
|
+
- ✅ Uptime do servidor
|
|
283
|
+
- ✅ Cleanup automático de intervals
|
|
284
|
+
|
|
285
|
+
### Destaques de Implementação
|
|
286
|
+
|
|
287
|
+
**1. Interval Management**
|
|
288
|
+
```typescript
|
|
289
|
+
export class LiveClockComponent extends LiveComponent<LiveClockState> {
|
|
290
|
+
private clockInterval: NodeJS.Timeout | null = null
|
|
291
|
+
|
|
292
|
+
constructor(...) {
|
|
293
|
+
super(...)
|
|
294
|
+
this.startClock() // Inicia interval
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private startClock() {
|
|
298
|
+
this.clockInterval = setInterval(() => {
|
|
299
|
+
this.updateClock()
|
|
300
|
+
}, 1000)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public destroy() {
|
|
304
|
+
if (this.clockInterval) {
|
|
305
|
+
clearInterval(this.clockInterval) // ✅ CRÍTICO: limpar resources
|
|
306
|
+
}
|
|
307
|
+
super.destroy()
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**2. Broadcasting Updates**
|
|
313
|
+
```typescript
|
|
314
|
+
private updateClock() {
|
|
315
|
+
this.setState({ currentTime: timeString })
|
|
316
|
+
|
|
317
|
+
// Broadcast para TODOS clientes na mesma room
|
|
318
|
+
if (this.room) {
|
|
319
|
+
this.broadcast('CLOCK_TICK', {
|
|
320
|
+
currentTime: timeString,
|
|
321
|
+
timestamp: now.toISOString()
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**3. Actions com Validação**
|
|
328
|
+
```typescript
|
|
329
|
+
async setTimeFormat(payload: { format: '12h' | '24h' }) {
|
|
330
|
+
const { format } = payload
|
|
331
|
+
|
|
332
|
+
// ✅ Validação server-side
|
|
333
|
+
if (format !== '12h' && format !== '24h') {
|
|
334
|
+
throw new Error('Invalid time format. Use "12h" or "24h"')
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
this.setState({ format })
|
|
338
|
+
this.updateClock() // Re-renderiza imediatamente
|
|
339
|
+
|
|
340
|
+
return { success: true, format }
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Lições Aprendidas
|
|
345
|
+
|
|
346
|
+
1. **Sempre limpe resources**: `clearInterval`, `clearTimeout`, conexões DB
|
|
347
|
+
2. **Valide inputs**: Actions podem receber dados maliciosos
|
|
348
|
+
3. **Use broadcasting**: Para updates que afetam múltiplos clientes
|
|
349
|
+
4. **Return values**: Actions podem retornar dados para o cliente
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### 5. **Falta Guia de Boas Práticas Avançadas**
|
|
355
|
+
|
|
356
|
+
**Problema**: Não há orientações sobre patterns avançados.
|
|
357
|
+
|
|
358
|
+
**Impacto**: Developers cometem erros comuns:
|
|
359
|
+
- Memory leaks (não limpam intervals)
|
|
360
|
+
- Security issues (não validam inputs)
|
|
361
|
+
- Performance problems (state updates excessivos)
|
|
362
|
+
- Error handling inadequado
|
|
363
|
+
|
|
364
|
+
**Sugestão**: Criar seção "Best Practices":
|
|
365
|
+
|
|
366
|
+
```markdown
|
|
367
|
+
# Live Components - Boas Práticas
|
|
368
|
+
|
|
369
|
+
## 1. Resource Management (CRÍTICO)
|
|
370
|
+
|
|
371
|
+
### ❌ ERRADO - Memory Leak
|
|
372
|
+
```typescript
|
|
373
|
+
export class BadComponent extends LiveComponent {
|
|
374
|
+
constructor() {
|
|
375
|
+
super()
|
|
376
|
+
setInterval(() => {
|
|
377
|
+
this.updateData()
|
|
378
|
+
}, 1000)
|
|
379
|
+
// ❌ Interval nunca é limpo
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### ✅ CORRETO
|
|
385
|
+
```typescript
|
|
386
|
+
export class GoodComponent extends LiveComponent {
|
|
387
|
+
private interval: NodeJS.Timeout | null = null
|
|
388
|
+
|
|
389
|
+
constructor() {
|
|
390
|
+
super()
|
|
391
|
+
this.interval = setInterval(() => {
|
|
392
|
+
this.updateData()
|
|
393
|
+
}, 1000)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
public destroy() {
|
|
397
|
+
if (this.interval) {
|
|
398
|
+
clearInterval(this.interval) // ✅ Cleanup
|
|
399
|
+
}
|
|
400
|
+
super.destroy()
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## 2. Security - Validação de Inputs
|
|
406
|
+
|
|
407
|
+
### ❌ ERRADO - Vulnerável
|
|
408
|
+
```typescript
|
|
409
|
+
async deleteUser(payload: { userId: string }) {
|
|
410
|
+
// ❌ Sem validação - qualquer cliente pode deletar qualquer user
|
|
411
|
+
await db.users.delete(payload.userId)
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### ✅ CORRETO
|
|
416
|
+
```typescript
|
|
417
|
+
async deleteUser(payload: { userId: string }) {
|
|
418
|
+
// ✅ Valida propriedade
|
|
419
|
+
if (this.userId !== payload.userId) {
|
|
420
|
+
throw new Error('Unauthorized: Cannot delete other users')
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ✅ Valida formato
|
|
424
|
+
if (!payload.userId.match(/^[a-z0-9-]+$/)) {
|
|
425
|
+
throw new Error('Invalid user ID format')
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
await db.users.delete(payload.userId)
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## 3. Performance - Throttling de Updates
|
|
433
|
+
|
|
434
|
+
### ❌ ERRADO - Updates Excessivos
|
|
435
|
+
```typescript
|
|
436
|
+
async onMouseMove(payload: { x: number, y: number }) {
|
|
437
|
+
// ❌ Envia WebSocket message em CADA movimento do mouse
|
|
438
|
+
this.setState({ mouseX: payload.x, mouseY: payload.y })
|
|
439
|
+
await this.emit('mouse-moved', payload)
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### ✅ CORRETO - Throttled
|
|
444
|
+
```typescript
|
|
445
|
+
private lastEmit = 0
|
|
446
|
+
private EMIT_THROTTLE = 100 // 100ms
|
|
447
|
+
|
|
448
|
+
async onMouseMove(payload: { x: number, y: number }) {
|
|
449
|
+
this.setState({ mouseX: payload.x, mouseY: payload.y })
|
|
450
|
+
|
|
451
|
+
// ✅ Só emite a cada 100ms
|
|
452
|
+
const now = Date.now()
|
|
453
|
+
if (now - this.lastEmit > this.EMIT_THROTTLE) {
|
|
454
|
+
await this.emit('mouse-moved', payload)
|
|
455
|
+
this.lastEmit = now
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## 4. Error Handling
|
|
461
|
+
|
|
462
|
+
### ❌ ERRADO - Erro Mata Componente
|
|
463
|
+
```typescript
|
|
464
|
+
async fetchUserData(payload: { userId: string }) {
|
|
465
|
+
const user = await api.getUser(payload.userId) // ❌ Se falhar, quebra tudo
|
|
466
|
+
this.setState({ user })
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### ✅ CORRETO - Graceful Degradation
|
|
471
|
+
```typescript
|
|
472
|
+
async fetchUserData(payload: { userId: string }) {
|
|
473
|
+
try {
|
|
474
|
+
const user = await api.getUser(payload.userId)
|
|
475
|
+
this.setState({ user, error: null, loading: false })
|
|
476
|
+
} catch (error) {
|
|
477
|
+
console.error('Failed to fetch user:', error)
|
|
478
|
+
this.setState({
|
|
479
|
+
error: 'Failed to load user data',
|
|
480
|
+
loading: false
|
|
481
|
+
})
|
|
482
|
+
// ✅ Component continua funcionando
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
## 5. State Design
|
|
488
|
+
|
|
489
|
+
### ❌ ERRADO - Estado Duplicado
|
|
490
|
+
```typescript
|
|
491
|
+
state = {
|
|
492
|
+
users: [],
|
|
493
|
+
userCount: 0, // ❌ Derivado de users.length
|
|
494
|
+
hasUsers: false // ❌ Derivado de users.length > 0
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### ✅ CORRETO - Single Source of Truth
|
|
499
|
+
```typescript
|
|
500
|
+
state = {
|
|
501
|
+
users: [] // ✅ Única fonte de verdade
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Cálculos derivados no getter ou no cliente
|
|
505
|
+
get userCount() {
|
|
506
|
+
return this.state.users.length
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
## 6. Broadcasting - Use com Sabedoria
|
|
511
|
+
|
|
512
|
+
### ✅ QUANDO usar broadcast
|
|
513
|
+
- Updates globais (novo post no feed)
|
|
514
|
+
- Notificações para múltiplos users
|
|
515
|
+
- State compartilhado (collaborative editing)
|
|
516
|
+
|
|
517
|
+
### ❌ QUANDO NÃO usar broadcast
|
|
518
|
+
- State privado de um user
|
|
519
|
+
- Dados sensíveis
|
|
520
|
+
- Updates frequentes que não afetam outros users
|
|
521
|
+
|
|
522
|
+
```typescript
|
|
523
|
+
// ✅ BOM - Notificação global
|
|
524
|
+
async createPost(payload: { title: string, content: string }) {
|
|
525
|
+
const post = await db.posts.create(payload)
|
|
526
|
+
|
|
527
|
+
if (this.room) {
|
|
528
|
+
this.broadcast('new-post', { post }) // Todos veem
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// ❌ RUIM - Broadcast de dado privado
|
|
533
|
+
async updatePassword(payload: { oldPass: string, newPass: string }) {
|
|
534
|
+
await this.changePassword(payload)
|
|
535
|
+
|
|
536
|
+
// ❌ NUNCA faça broadcast de senha!
|
|
537
|
+
// this.broadcast('password-changed', payload)
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
### 6. **Fragmentação da Documentação**
|
|
545
|
+
|
|
546
|
+
**Problema**: Informação está dividida entre dois arquivos sem navegação clara.
|
|
547
|
+
|
|
548
|
+
**Impacto**: Developers não sabem qual arquivo ler primeiro.
|
|
549
|
+
|
|
550
|
+
**Estrutura Atual**:
|
|
551
|
+
```
|
|
552
|
+
ai-context/
|
|
553
|
+
├── development/live-components.md (técnico, interno)
|
|
554
|
+
├── reference/live-components-api.md (API reference)
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Sugestão**: Reorganizar com hierarquia clara:
|
|
558
|
+
|
|
559
|
+
```
|
|
560
|
+
ai-context/
|
|
561
|
+
├── development/
|
|
562
|
+
│ ├── live-components/
|
|
563
|
+
│ │ ├── 00-overview.md (O que são? Quando usar?)
|
|
564
|
+
│ │ ├── 01-quick-start.md (Hello World em 5min)
|
|
565
|
+
│ │ ├── 02-server-components.md (Criar componentes server)
|
|
566
|
+
│ │ ├── 03-client-hooks.md (useHybridLiveComponent)
|
|
567
|
+
│ │ ├── 04-advanced-patterns.md (Patterns avançados)
|
|
568
|
+
│ │ └── 05-best-practices.md (Security, performance)
|
|
569
|
+
│ └── live-components.md → [DEPRECADO - redirecionar para 00-overview.md]
|
|
570
|
+
└── reference/
|
|
571
|
+
└── live-components-api.md (Continua como API reference)
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
### 7. **Falta Comparação com Alternativas**
|
|
577
|
+
|
|
578
|
+
**Problema**: Developers não sabem quando usar Live Components vs REST API vs GraphQL.
|
|
579
|
+
|
|
580
|
+
**Sugestão**:
|
|
581
|
+
|
|
582
|
+
```markdown
|
|
583
|
+
# Live Components vs Alternativas
|
|
584
|
+
|
|
585
|
+
## Quando Usar Cada Abordagem?
|
|
586
|
+
|
|
587
|
+
### 🔥 Live Components
|
|
588
|
+
**Use para**: Real-time updates, interactive UIs, dashboards
|
|
589
|
+
|
|
590
|
+
**Pros**:
|
|
591
|
+
- ✅ Updates automáticos sem polling
|
|
592
|
+
- ✅ State management no servidor
|
|
593
|
+
- ✅ Menos código boilerplate
|
|
594
|
+
- ✅ Type-safe com Eden Treaty
|
|
595
|
+
|
|
596
|
+
**Cons**:
|
|
597
|
+
- ❌ Requer WebSocket (pode ter problemas com proxies)
|
|
598
|
+
- ❌ Stateful (não escala horizontalmente sem sticky sessions)
|
|
599
|
+
- ❌ Não ideal para APIs públicas
|
|
600
|
+
|
|
601
|
+
**Exemplo**: Dashboard de vendas em tempo real
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
### 🌐 REST API (Eden Treaty)
|
|
606
|
+
**Use para**: CRUD tradicional, APIs públicas, operações stateless
|
|
607
|
+
|
|
608
|
+
**Pros**:
|
|
609
|
+
- ✅ Stateless - escala facilmente
|
|
610
|
+
- ✅ Caching HTTP padrão
|
|
611
|
+
- ✅ Compatível com qualquer cliente
|
|
612
|
+
|
|
613
|
+
**Cons**:
|
|
614
|
+
- ❌ Sem updates automáticos (precisa polling)
|
|
615
|
+
- ❌ Mais código boilerplate
|
|
616
|
+
|
|
617
|
+
**Exemplo**: API de cadastro de usuários
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
### 📊 GraphQL
|
|
622
|
+
**Use para**: Queries complexas, mobile apps, agregação de dados
|
|
623
|
+
|
|
624
|
+
**Pros**:
|
|
625
|
+
- ✅ Cliente escolhe dados necessários
|
|
626
|
+
- ✅ Reduz over-fetching
|
|
627
|
+
|
|
628
|
+
**Cons**:
|
|
629
|
+
- ❌ FluxStack não tem GraphQL built-in (use REST)
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## Decision Matrix
|
|
634
|
+
|
|
635
|
+
| Feature | Live Components | REST API | GraphQL |
|
|
636
|
+
|---------|----------------|----------|---------|
|
|
637
|
+
| Real-time updates | ✅ Automático | ❌ Polling | ❌ Polling |
|
|
638
|
+
| Type Safety | ✅ Eden Treaty | ✅ Eden Treaty | ⚠️ Depende |
|
|
639
|
+
| Stateless | ❌ Stateful | ✅ Stateless | ✅ Stateless |
|
|
640
|
+
| Public APIs | ❌ Não ideal | ✅ Ideal | ✅ Ideal |
|
|
641
|
+
| Interactive UI | ✅ Ideal | ⚠️ OK | ⚠️ OK |
|
|
642
|
+
| Escalabilidade | ⚠️ Vertical | ✅ Horizontal | ✅ Horizontal |
|
|
643
|
+
| Caching | ❌ Difícil | ✅ HTTP Cache | ⚠️ Complexo |
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
### 8. **Falta Diagramas Visuais**
|
|
649
|
+
|
|
650
|
+
**Problema**: Documentação é 100% texto - faltam diagramas de arquitetura.
|
|
651
|
+
|
|
652
|
+
**Impacto**: Developers visuais têm dificuldade de entender fluxos.
|
|
653
|
+
|
|
654
|
+
**Sugestão**: Adicionar diagramas Mermaid:
|
|
655
|
+
|
|
656
|
+
```markdown
|
|
657
|
+
## Arquitetura de Live Components
|
|
658
|
+
|
|
659
|
+
```mermaid
|
|
660
|
+
graph TB
|
|
661
|
+
subgraph "Client (React)"
|
|
662
|
+
A[Component UI] --> B[useHybridLiveComponent]
|
|
663
|
+
B --> C[LiveComponentsProvider]
|
|
664
|
+
C --> D[WebSocket Client]
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
subgraph "Network"
|
|
668
|
+
D <-->|"WSS"| E[WebSocket Endpoint]
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
subgraph "Server (Elysia)"
|
|
672
|
+
E --> F[Connection Manager]
|
|
673
|
+
F --> G[Component Registry]
|
|
674
|
+
G --> H[LiveComponent Instance]
|
|
675
|
+
H --> I[Business Logic]
|
|
676
|
+
H --> J[State Management]
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
style A fill:#61dafb
|
|
680
|
+
style H fill:#ff6b6b
|
|
681
|
+
style C fill:#51cf66
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
## Fluxo de Mensagens
|
|
685
|
+
|
|
686
|
+
```mermaid
|
|
687
|
+
sequenceDiagram
|
|
688
|
+
participant C as Client
|
|
689
|
+
participant WS as WebSocket
|
|
690
|
+
participant S as Server
|
|
691
|
+
participant LC as LiveComponent
|
|
692
|
+
|
|
693
|
+
C->>WS: Connect
|
|
694
|
+
WS->>S: CONNECTION_ESTABLISHED
|
|
695
|
+
|
|
696
|
+
C->>WS: COMPONENT_MOUNT
|
|
697
|
+
WS->>S: Mount Request
|
|
698
|
+
S->>LC: new LiveComponent()
|
|
699
|
+
LC->>S: Initial State
|
|
700
|
+
S->>WS: COMPONENT_MOUNTED
|
|
701
|
+
WS->>C: Initial State + ID
|
|
702
|
+
|
|
703
|
+
C->>WS: CALL_ACTION (increment)
|
|
704
|
+
WS->>LC: Execute Action
|
|
705
|
+
LC->>LC: Update State
|
|
706
|
+
LC->>WS: STATE_UPDATE
|
|
707
|
+
WS->>C: New State
|
|
708
|
+
C->>C: Re-render UI
|
|
709
|
+
|
|
710
|
+
C->>WS: COMPONENT_UNMOUNT
|
|
711
|
+
WS->>LC: destroy()
|
|
712
|
+
LC->>S: Cleanup
|
|
713
|
+
```
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
## 📋 **SUMÁRIO DE RECOMENDAÇÕES**
|
|
719
|
+
|
|
720
|
+
### 🔴 **CRÍTICO - Implementar ASAP**
|
|
721
|
+
|
|
722
|
+
1. **Quick Start de 5 Minutos**
|
|
723
|
+
- Criar `ai-context/development/live-components/01-quick-start.md`
|
|
724
|
+
- Exemplo "Hello World" copy-paste
|
|
725
|
+
|
|
726
|
+
2. **Documentar `useHybridLiveComponent`**
|
|
727
|
+
- Criar `ai-context/development/live-components/03-client-hooks.md`
|
|
728
|
+
- Incluir todas opções, helpers, e state lifecycle
|
|
729
|
+
|
|
730
|
+
3. **Best Practices e Security**
|
|
731
|
+
- Criar `ai-context/development/live-components/05-best-practices.md`
|
|
732
|
+
- Incluir resource management, validation, error handling
|
|
733
|
+
|
|
734
|
+
### 🟡 **IMPORTANTE - Próxima Iteração**
|
|
735
|
+
|
|
736
|
+
4. **Overview Acessível**
|
|
737
|
+
- Reescrever `development/live-components.md` com foco em conceitos
|
|
738
|
+
- Adicionar seção "Quando Usar vs REST API"
|
|
739
|
+
|
|
740
|
+
5. **Exemplos Reais Documentados**
|
|
741
|
+
- Documentar `LiveClockComponent` como exemplo real
|
|
742
|
+
- Adicionar mais exemplos práticos (Chat, Dashboard)
|
|
743
|
+
|
|
744
|
+
6. **Reorganizar Estrutura**
|
|
745
|
+
- Criar subpasta `live-components/` com arquivos numerados
|
|
746
|
+
- Adicionar README.md como índice navegável
|
|
747
|
+
|
|
748
|
+
### 🟢 **NICE TO HAVE - Futuro**
|
|
749
|
+
|
|
750
|
+
7. **Diagramas Visuais**
|
|
751
|
+
- Adicionar diagramas Mermaid de arquitetura
|
|
752
|
+
- Diagramas de fluxo de mensagens
|
|
753
|
+
|
|
754
|
+
8. **Comparação com Alternativas**
|
|
755
|
+
- Decision matrix: Live Components vs REST vs GraphQL
|
|
756
|
+
- Guia de quando usar cada abordagem
|
|
757
|
+
|
|
758
|
+
---
|
|
759
|
+
|
|
760
|
+
## 🎯 **CONCLUSÃO**
|
|
761
|
+
|
|
762
|
+
### Nota Geral: **6.5/10**
|
|
763
|
+
|
|
764
|
+
**Resumo**:
|
|
765
|
+
- ✅ API Reference está **excelente** (8/10)
|
|
766
|
+
- ⚠️ Development Guide está **muito técnico** (5/10)
|
|
767
|
+
- ❌ **Falta** Quick Start para iniciantes (0/10)
|
|
768
|
+
- ❌ **Falta** documentação do hook principal (0/10)
|
|
769
|
+
- ❌ **Falta** best practices e security (0/10)
|
|
770
|
+
|
|
771
|
+
**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).
|
|
772
|
+
|
|
773
|
+
---
|
|
774
|
+
|
|
775
|
+
**Próximos Passos Sugeridos**:
|
|
776
|
+
|
|
777
|
+
1. Criar Quick Start primeiro (maior impacto)
|
|
778
|
+
2. Documentar `useHybridLiveComponent` (segundo maior impacto)
|
|
779
|
+
3. Best Practices (previne bugs e security issues)
|
|
780
|
+
4. Reorganizar estrutura (melhora navegação)
|
|
781
|
+
5. Adicionar diagramas (melhora compreensão)
|