create-fluxstack 1.14.0 → 1.16.0

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.
Files changed (76) hide show
  1. package/LLMD/INDEX.md +4 -3
  2. package/LLMD/resources/live-binary-delta.md +507 -0
  3. package/LLMD/resources/live-components.md +208 -12
  4. package/LLMD/resources/live-rooms.md +731 -333
  5. package/app/client/.live-stubs/LiveAdminPanel.js +5 -0
  6. package/app/client/.live-stubs/LiveCounter.js +9 -0
  7. package/app/client/.live-stubs/LiveForm.js +11 -0
  8. package/app/client/.live-stubs/LiveLocalCounter.js +8 -0
  9. package/app/client/.live-stubs/LivePingPong.js +10 -0
  10. package/app/client/.live-stubs/LiveRoomChat.js +11 -0
  11. package/app/client/.live-stubs/LiveSharedCounter.js +10 -0
  12. package/app/client/.live-stubs/LiveUpload.js +15 -0
  13. package/app/client/src/App.tsx +19 -7
  14. package/app/client/src/components/AppLayout.tsx +18 -10
  15. package/app/client/src/live/PingPongDemo.tsx +199 -0
  16. package/app/client/src/live/RoomChatDemo.tsx +187 -22
  17. package/app/client/src/live/SharedCounterDemo.tsx +142 -0
  18. package/app/server/auth/DevAuthProvider.ts +2 -2
  19. package/app/server/auth/JWTAuthProvider.example.ts +2 -2
  20. package/app/server/index.ts +2 -2
  21. package/app/server/live/LiveAdminPanel.ts +1 -1
  22. package/app/server/live/LivePingPong.ts +61 -0
  23. package/app/server/live/LiveProtectedChat.ts +1 -1
  24. package/app/server/live/LiveRoomChat.ts +106 -38
  25. package/app/server/live/LiveSharedCounter.ts +73 -0
  26. package/app/server/live/rooms/ChatRoom.ts +68 -0
  27. package/app/server/live/rooms/CounterRoom.ts +51 -0
  28. package/app/server/live/rooms/DirectoryRoom.ts +42 -0
  29. package/app/server/live/rooms/PingRoom.ts +40 -0
  30. package/app/server/routes/room.routes.ts +1 -2
  31. package/core/build/live-components-generator.ts +11 -2
  32. package/core/build/vite-plugins.ts +28 -0
  33. package/core/client/hooks/useLiveUpload.ts +3 -4
  34. package/core/client/index.ts +25 -35
  35. package/core/framework/server.ts +1 -1
  36. package/core/server/index.ts +1 -2
  37. package/core/server/live/auto-generated-components.ts +5 -8
  38. package/core/server/live/index.ts +90 -21
  39. package/core/server/live/websocket-plugin.ts +54 -1079
  40. package/core/types/types.ts +76 -1025
  41. package/core/utils/version.ts +1 -1
  42. package/create-fluxstack.ts +1 -1
  43. package/package.json +100 -95
  44. package/plugins/crypto-auth/index.ts +1 -1
  45. package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +2 -2
  46. package/tsconfig.json +4 -1
  47. package/vite.config.ts +40 -12
  48. package/app/client/src/live/ChatDemo.tsx +0 -107
  49. package/app/client/src/live/LiveDebuggerPanel.tsx +0 -779
  50. package/app/server/live/LiveChat.ts +0 -78
  51. package/core/client/LiveComponentsProvider.tsx +0 -531
  52. package/core/client/components/Live.tsx +0 -111
  53. package/core/client/components/LiveDebugger.tsx +0 -1324
  54. package/core/client/hooks/AdaptiveChunkSizer.ts +0 -215
  55. package/core/client/hooks/state-validator.ts +0 -130
  56. package/core/client/hooks/useChunkedUpload.ts +0 -359
  57. package/core/client/hooks/useLiveChunkedUpload.ts +0 -87
  58. package/core/client/hooks/useLiveComponent.ts +0 -853
  59. package/core/client/hooks/useLiveDebugger.ts +0 -392
  60. package/core/client/hooks/useRoom.ts +0 -409
  61. package/core/client/hooks/useRoomProxy.ts +0 -382
  62. package/core/server/live/ComponentRegistry.ts +0 -1128
  63. package/core/server/live/FileUploadManager.ts +0 -446
  64. package/core/server/live/LiveComponentPerformanceMonitor.ts +0 -931
  65. package/core/server/live/LiveDebugger.ts +0 -462
  66. package/core/server/live/LiveLogger.ts +0 -144
  67. package/core/server/live/LiveRoomManager.ts +0 -278
  68. package/core/server/live/RoomEventBus.ts +0 -234
  69. package/core/server/live/RoomStateManager.ts +0 -172
  70. package/core/server/live/SingleConnectionManager.ts +0 -0
  71. package/core/server/live/StateSignature.ts +0 -705
  72. package/core/server/live/WebSocketConnectionManager.ts +0 -710
  73. package/core/server/live/auth/LiveAuthContext.ts +0 -71
  74. package/core/server/live/auth/LiveAuthManager.ts +0 -304
  75. package/core/server/live/auth/index.ts +0 -19
  76. package/core/server/live/auth/types.ts +0 -179
@@ -1,409 +0,0 @@
1
- // 🔥 FluxStack useRoom - Hook para conectar a salas do backend
2
-
3
- import { useState, useEffect, useCallback, useRef } from 'react'
4
-
5
- // Tipos de mensagens do servidor
6
- interface RoomMessage {
7
- type: 'room:event' | 'room:state' | 'room:system'
8
- roomId: string
9
- event: string
10
- data: any
11
- timestamp: number
12
- senderId?: string
13
- }
14
-
15
- // Mensagens do cliente para o servidor
16
- interface ClientMessage {
17
- type: 'room:join' | 'room:leave' | 'room:emit'
18
- roomId: string
19
- event?: string
20
- data?: any
21
- timestamp: number
22
- }
23
-
24
- // Opções do hook
25
- interface UseRoomOptions<TState> {
26
- initialState: TState
27
- autoJoin?: boolean
28
- onConnect?: () => void
29
- onDisconnect?: () => void
30
- onError?: (error: string) => void
31
- onStateChange?: (state: TState, prevState: TState) => void
32
- }
33
-
34
- // Retorno do hook
35
- interface UseRoomReturn<TState, TEvents extends Record<string, any>> {
36
- // Estado
37
- state: TState
38
-
39
- // Status
40
- connected: boolean
41
- joined: boolean
42
- roomId: string | null
43
-
44
- // Ações
45
- join: (roomId: string) => void
46
- leave: () => void
47
- emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => void
48
-
49
- // Listeners
50
- on: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => () => void
51
- onSystem: (event: string, handler: (data: any) => void) => () => void
52
- }
53
-
54
- // Gerenciador de conexão WebSocket (singleton por URL)
55
- class RoomWebSocketManager {
56
- private static instances = new Map<string, RoomWebSocketManager>()
57
-
58
- private ws: WebSocket | null = null
59
- private url: string
60
- private reconnectAttempts = 0
61
- private maxReconnectAttempts = 5
62
- private reconnectDelay = 1000
63
- private listeners = new Map<string, Set<(msg: RoomMessage) => void>>()
64
- private connectionListeners = new Set<{
65
- onConnect?: () => void
66
- onDisconnect?: () => void
67
- onError?: (error: string) => void
68
- }>()
69
- private messageQueue: ClientMessage[] = []
70
- private isConnected = false
71
-
72
- static getInstance(url: string): RoomWebSocketManager {
73
- if (!this.instances.has(url)) {
74
- this.instances.set(url, new RoomWebSocketManager(url))
75
- }
76
- return this.instances.get(url)!
77
- }
78
-
79
- private constructor(url: string) {
80
- this.url = url
81
- this.connect()
82
- }
83
-
84
- private connect(): void {
85
- try {
86
- this.ws = new WebSocket(this.url)
87
-
88
- this.ws.onopen = () => {
89
- console.log('[RoomWS] Connected')
90
- this.isConnected = true
91
- this.reconnectAttempts = 0
92
-
93
- // Enviar mensagens em fila
94
- for (const msg of this.messageQueue) {
95
- this.send(msg)
96
- }
97
- this.messageQueue = []
98
-
99
- // Notificar listeners
100
- for (const listener of this.connectionListeners) {
101
- listener.onConnect?.()
102
- }
103
- }
104
-
105
- this.ws.onmessage = (event) => {
106
- try {
107
- const msg: RoomMessage = JSON.parse(event.data)
108
- this.handleMessage(msg)
109
- } catch (error) {
110
- console.error('[RoomWS] Failed to parse message:', error)
111
- }
112
- }
113
-
114
- this.ws.onclose = () => {
115
- console.log('[RoomWS] Disconnected')
116
- this.isConnected = false
117
-
118
- for (const listener of this.connectionListeners) {
119
- listener.onDisconnect?.()
120
- }
121
-
122
- // Tentar reconectar
123
- if (this.reconnectAttempts < this.maxReconnectAttempts) {
124
- this.reconnectAttempts++
125
- const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1)
126
- console.log(`[RoomWS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`)
127
- setTimeout(() => this.connect(), delay)
128
- }
129
- }
130
-
131
- this.ws.onerror = (error) => {
132
- console.error('[RoomWS] Error:', error)
133
- for (const listener of this.connectionListeners) {
134
- listener.onError?.('WebSocket error')
135
- }
136
- }
137
- } catch (error) {
138
- console.error('[RoomWS] Failed to connect:', error)
139
- }
140
- }
141
-
142
- private handleMessage(msg: RoomMessage): void {
143
- // Chave para listeners: roomId:event
144
- const key = `${msg.roomId}:${msg.event}`
145
- const listeners = this.listeners.get(key)
146
-
147
- if (listeners) {
148
- for (const handler of listeners) {
149
- try {
150
- handler(msg)
151
- } catch (error) {
152
- console.error('[RoomWS] Handler error:', error)
153
- }
154
- }
155
- }
156
-
157
- // Também notificar listeners de todos eventos da sala
158
- const roomKey = `${msg.roomId}:*`
159
- const roomListeners = this.listeners.get(roomKey)
160
- if (roomListeners) {
161
- for (const handler of roomListeners) {
162
- try {
163
- handler(msg)
164
- } catch (error) {
165
- console.error('[RoomWS] Handler error:', error)
166
- }
167
- }
168
- }
169
- }
170
-
171
- send(message: ClientMessage): void {
172
- if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) {
173
- this.ws.send(JSON.stringify(message))
174
- } else {
175
- this.messageQueue.push(message)
176
- }
177
- }
178
-
179
- subscribe(roomId: string, event: string, handler: (msg: RoomMessage) => void): () => void {
180
- const key = `${roomId}:${event}`
181
-
182
- if (!this.listeners.has(key)) {
183
- this.listeners.set(key, new Set())
184
- }
185
- this.listeners.get(key)!.add(handler)
186
-
187
- return () => {
188
- this.listeners.get(key)?.delete(handler)
189
- if (this.listeners.get(key)?.size === 0) {
190
- this.listeners.delete(key)
191
- }
192
- }
193
- }
194
-
195
- addConnectionListener(listener: {
196
- onConnect?: () => void
197
- onDisconnect?: () => void
198
- onError?: (error: string) => void
199
- }): () => void {
200
- this.connectionListeners.add(listener)
201
-
202
- // Se já conectado, chamar onConnect imediatamente
203
- if (this.isConnected) {
204
- listener.onConnect?.()
205
- }
206
-
207
- return () => {
208
- this.connectionListeners.delete(listener)
209
- }
210
- }
211
-
212
- getConnectionStatus(): boolean {
213
- return this.isConnected
214
- }
215
- }
216
-
217
- // Hook principal
218
- export function useRoom<
219
- TDef extends { state: any; events: Record<string, any> }
220
- >(
221
- wsUrl: string,
222
- options: UseRoomOptions<TDef['state']>
223
- ): UseRoomReturn<TDef['state'], TDef['events']> {
224
- const [state, setState] = useState<TDef['state']>(options.initialState)
225
- const [connected, setConnected] = useState(false)
226
- const [joined, setJoined] = useState(false)
227
- const [roomId, setRoomId] = useState<string | null>(null)
228
-
229
- const wsManager = useRef<RoomWebSocketManager | null>(null)
230
- const eventHandlers = useRef<Map<string, Set<(data: any) => void>>>(new Map())
231
- const unsubscribes = useRef<(() => void)[]>([])
232
-
233
- // Inicializar WebSocket manager
234
- useEffect(() => {
235
- wsManager.current = RoomWebSocketManager.getInstance(wsUrl)
236
-
237
- const unsub = wsManager.current.addConnectionListener({
238
- onConnect: () => {
239
- setConnected(true)
240
- options.onConnect?.()
241
- },
242
- onDisconnect: () => {
243
- setConnected(false)
244
- setJoined(false)
245
- options.onDisconnect?.()
246
- },
247
- onError: options.onError
248
- })
249
-
250
- setConnected(wsManager.current.getConnectionStatus())
251
-
252
- return () => {
253
- unsub()
254
- // Limpar todas as subscriptions
255
- for (const unsub of unsubscribes.current) {
256
- unsub()
257
- }
258
- }
259
- }, [wsUrl])
260
-
261
- // Join room
262
- const join = useCallback((newRoomId: string) => {
263
- if (!wsManager.current) return
264
-
265
- // Sair da sala anterior se existir
266
- if (roomId && roomId !== newRoomId) {
267
- leave()
268
- }
269
-
270
- setRoomId(newRoomId)
271
-
272
- // Enviar mensagem de join
273
- wsManager.current.send({
274
- type: 'room:join',
275
- roomId: newRoomId,
276
- data: { initialState: options.initialState },
277
- timestamp: Date.now()
278
- })
279
-
280
- // Subscrever em todos os eventos da sala
281
- const unsub = wsManager.current.subscribe(newRoomId, '*', (msg) => {
282
- // Atualizar estado
283
- if (msg.event === '$state:sync' || msg.event === '$state:update') {
284
- setState(prev => {
285
- const newState = { ...prev, ...msg.data.state }
286
- options.onStateChange?.(newState, prev)
287
- return newState
288
- })
289
- } else if (msg.event === '$state:change') {
290
- setState(prev => {
291
- const newState = { ...prev, [msg.data.path]: msg.data.newValue }
292
- options.onStateChange?.(newState, prev)
293
- return newState
294
- })
295
- }
296
-
297
- // Chamar handlers registrados
298
- const handlers = eventHandlers.current.get(msg.event)
299
- if (handlers) {
300
- for (const handler of handlers) {
301
- handler(msg.data)
302
- }
303
- }
304
- })
305
-
306
- unsubscribes.current.push(unsub)
307
- setJoined(true)
308
- }, [roomId, options.initialState])
309
-
310
- // Leave room
311
- const leave = useCallback(() => {
312
- if (!wsManager.current || !roomId) return
313
-
314
- wsManager.current.send({
315
- type: 'room:leave',
316
- roomId,
317
- timestamp: Date.now()
318
- })
319
-
320
- // Limpar subscriptions
321
- for (const unsub of unsubscribes.current) {
322
- unsub()
323
- }
324
- unsubscribes.current = []
325
- eventHandlers.current.clear()
326
-
327
- setJoined(false)
328
- setRoomId(null)
329
- setState(options.initialState)
330
- }, [roomId, options.initialState])
331
-
332
- // Emit event
333
- const emit = useCallback(<K extends keyof TDef['events']>(
334
- event: K,
335
- data: TDef['events'][K]
336
- ) => {
337
- if (!wsManager.current || !roomId) return
338
-
339
- wsManager.current.send({
340
- type: 'room:emit',
341
- roomId,
342
- event: event as string,
343
- data,
344
- timestamp: Date.now()
345
- })
346
- }, [roomId])
347
-
348
- // Subscribe to event
349
- const on = useCallback(<K extends keyof TDef['events']>(
350
- event: K,
351
- handler: (data: TDef['events'][K]) => void
352
- ): (() => void) => {
353
- const eventKey = event as string
354
-
355
- if (!eventHandlers.current.has(eventKey)) {
356
- eventHandlers.current.set(eventKey, new Set())
357
- }
358
- eventHandlers.current.get(eventKey)!.add(handler)
359
-
360
- return () => {
361
- eventHandlers.current.get(eventKey)?.delete(handler)
362
- }
363
- }, [])
364
-
365
- // Subscribe to system event
366
- const onSystem = useCallback((
367
- event: string,
368
- handler: (data: any) => void
369
- ): (() => void) => {
370
- const eventKey = `$${event}`
371
-
372
- if (!eventHandlers.current.has(eventKey)) {
373
- eventHandlers.current.set(eventKey, new Set())
374
- }
375
- eventHandlers.current.get(eventKey)!.add(handler)
376
-
377
- return () => {
378
- eventHandlers.current.get(eventKey)?.delete(handler)
379
- }
380
- }, [])
381
-
382
- // Auto-join
383
- useEffect(() => {
384
- if (options.autoJoin && connected && !joined && roomId) {
385
- join(roomId)
386
- }
387
- }, [options.autoJoin, connected, joined, roomId, join])
388
-
389
- return {
390
- state,
391
- connected,
392
- joined,
393
- roomId,
394
- join,
395
- leave,
396
- emit,
397
- on,
398
- onSystem
399
- }
400
- }
401
-
402
- // Helper para criar hook tipado
403
- export function createRoomHook<
404
- TDef extends { state: any; events: Record<string, any> }
405
- >(wsUrl: string) {
406
- return (options: UseRoomOptions<TDef['state']>) => useRoom<TDef>(wsUrl, options)
407
- }
408
-
409
- export type { UseRoomOptions, UseRoomReturn, RoomMessage, ClientMessage }