create-fluxstack 1.13.0 → 1.15.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 (96) hide show
  1. package/LLMD/patterns/anti-patterns.md +100 -0
  2. package/LLMD/reference/routing.md +39 -39
  3. package/LLMD/resources/live-auth.md +20 -2
  4. package/LLMD/resources/live-components.md +300 -21
  5. package/LLMD/resources/live-logging.md +95 -33
  6. package/LLMD/resources/live-upload.md +59 -8
  7. package/app/client/.live-stubs/LiveAdminPanel.js +5 -0
  8. package/app/client/.live-stubs/LiveChat.js +7 -0
  9. package/app/client/.live-stubs/LiveCounter.js +9 -0
  10. package/app/client/.live-stubs/LiveForm.js +11 -0
  11. package/app/client/.live-stubs/LiveLocalCounter.js +8 -0
  12. package/app/client/.live-stubs/LiveRoomChat.js +10 -0
  13. package/app/client/.live-stubs/LiveTodoList.js +9 -0
  14. package/app/client/.live-stubs/LiveUpload.js +15 -0
  15. package/app/client/index.html +2 -2
  16. package/app/client/public/favicon.svg +46 -0
  17. package/app/client/src/App.tsx +13 -1
  18. package/app/client/src/assets/fluxstack-static.svg +46 -0
  19. package/app/client/src/assets/fluxstack.svg +183 -0
  20. package/app/client/src/components/AppLayout.tsx +146 -9
  21. package/app/client/src/components/BackButton.tsx +13 -13
  22. package/app/client/src/components/DemoPage.tsx +4 -4
  23. package/app/client/src/live/AuthDemo.tsx +23 -21
  24. package/app/client/src/live/ChatDemo.tsx +2 -2
  25. package/app/client/src/live/CounterDemo.tsx +12 -12
  26. package/app/client/src/live/FormDemo.tsx +2 -2
  27. package/app/client/src/live/LiveDebuggerPanel.tsx +779 -0
  28. package/app/client/src/live/RoomChatDemo.tsx +24 -16
  29. package/app/client/src/live/TodoListDemo.tsx +158 -0
  30. package/app/client/src/main.tsx +13 -13
  31. package/app/client/src/pages/ApiTestPage.tsx +6 -6
  32. package/app/client/src/pages/HomePage.tsx +80 -52
  33. package/app/server/auth/DevAuthProvider.ts +2 -2
  34. package/app/server/auth/JWTAuthProvider.example.ts +2 -2
  35. package/app/server/index.ts +2 -2
  36. package/app/server/live/LiveAdminPanel.ts +2 -1
  37. package/app/server/live/LiveChat.ts +78 -77
  38. package/app/server/live/LiveCounter.ts +1 -1
  39. package/app/server/live/LiveForm.ts +1 -0
  40. package/app/server/live/LiveLocalCounter.ts +38 -37
  41. package/app/server/live/LiveProtectedChat.ts +2 -1
  42. package/app/server/live/LiveRoomChat.ts +1 -0
  43. package/app/server/live/LiveTodoList.ts +110 -0
  44. package/app/server/live/LiveUpload.ts +1 -0
  45. package/app/server/live/register-components.ts +19 -19
  46. package/app/server/routes/room.routes.ts +1 -2
  47. package/config/system/runtime.config.ts +4 -0
  48. package/core/build/live-components-generator.ts +1 -1
  49. package/core/build/optimizer.ts +235 -235
  50. package/core/build/vite-plugins.ts +28 -0
  51. package/core/client/components/LiveDebugger.tsx +1324 -0
  52. package/core/client/hooks/useLiveUpload.ts +3 -4
  53. package/core/client/index.ts +41 -21
  54. package/core/framework/server.ts +1 -1
  55. package/core/plugins/built-in/index.ts +134 -134
  56. package/core/plugins/built-in/live-components/commands/create-live-component.ts +4 -0
  57. package/core/plugins/built-in/vite/index.ts +75 -21
  58. package/core/server/index.ts +14 -15
  59. package/core/server/live/auto-generated-components.ts +6 -3
  60. package/core/server/live/index.ts +95 -21
  61. package/core/server/live/websocket-plugin.ts +27 -862
  62. package/core/server/plugins/static-files-plugin.ts +179 -69
  63. package/core/types/build.ts +219 -219
  64. package/core/types/plugin.ts +107 -107
  65. package/core/types/types.ts +77 -890
  66. package/core/utils/logger/startup-banner.ts +82 -82
  67. package/core/utils/version.ts +6 -6
  68. package/create-fluxstack.ts +1 -1
  69. package/package.json +5 -1
  70. package/plugins/crypto-auth/index.ts +1 -1
  71. package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +2 -2
  72. package/vite.config.ts +40 -12
  73. package/app/client/src/assets/react.svg +0 -1
  74. package/core/client/LiveComponentsProvider.tsx +0 -531
  75. package/core/client/components/Live.tsx +0 -105
  76. package/core/client/hooks/AdaptiveChunkSizer.ts +0 -215
  77. package/core/client/hooks/state-validator.ts +0 -130
  78. package/core/client/hooks/useChunkedUpload.ts +0 -359
  79. package/core/client/hooks/useLiveChunkedUpload.ts +0 -87
  80. package/core/client/hooks/useLiveComponent.ts +0 -843
  81. package/core/client/hooks/useRoom.ts +0 -409
  82. package/core/client/hooks/useRoomProxy.ts +0 -382
  83. package/core/server/live/ComponentRegistry.ts +0 -1099
  84. package/core/server/live/FileUploadManager.ts +0 -282
  85. package/core/server/live/LiveComponentPerformanceMonitor.ts +0 -931
  86. package/core/server/live/LiveLogger.ts +0 -111
  87. package/core/server/live/LiveRoomManager.ts +0 -262
  88. package/core/server/live/RoomEventBus.ts +0 -234
  89. package/core/server/live/RoomStateManager.ts +0 -172
  90. package/core/server/live/SingleConnectionManager.ts +0 -0
  91. package/core/server/live/StateSignature.ts +0 -645
  92. package/core/server/live/WebSocketConnectionManager.ts +0 -709
  93. package/core/server/live/auth/LiveAuthContext.ts +0 -71
  94. package/core/server/live/auth/LiveAuthManager.ts +0 -304
  95. package/core/server/live/auth/index.ts +0 -19
  96. package/core/server/live/auth/types.ts +0 -179
@@ -1,382 +0,0 @@
1
- // 🔥 FluxStack Room Proxy - Sistema de salas integrado ao LiveComponent
2
- //
3
- // Uso no frontend:
4
- // const chat = Live.use(LiveChat, { room: 'sala-principal' })
5
- //
6
- // // Sala padrão (definida no options.room)
7
- // chat.$room.emit('typing', { user: 'João' })
8
- // chat.$room.on('message:new', handler)
9
- // chat.$room.state
10
- //
11
- // // Outras salas
12
- // chat.$room('sala-vip').join()
13
- // chat.$room('sala-vip').emit('evento', data)
14
- // chat.$room('sala-vip').on('evento', handler)
15
- // chat.$room('sala-vip').leave()
16
- //
17
- // // Listar salas
18
- // chat.$rooms // ['sala-principal', 'sala-vip']
19
-
20
- type EventHandler<T = any> = (data: T) => void
21
- type Unsubscribe = () => void
22
-
23
- // Mensagem do cliente para o servidor
24
- export interface RoomClientMessage {
25
- type: 'ROOM_JOIN' | 'ROOM_LEAVE' | 'ROOM_EMIT' | 'ROOM_STATE_GET' | 'ROOM_STATE_SET'
26
- componentId: string
27
- roomId: string
28
- event?: string
29
- data?: any
30
- timestamp: number
31
- }
32
-
33
- // Mensagem do servidor para o cliente
34
- export interface RoomServerMessage {
35
- type: 'ROOM_EVENT' | 'ROOM_STATE' | 'ROOM_SYSTEM' | 'ROOM_JOINED' | 'ROOM_LEFT'
36
- componentId: string
37
- roomId: string
38
- event: string
39
- data: any
40
- timestamp: number
41
- }
42
-
43
- // Interface de uma sala individual
44
- export interface RoomHandle<TState = any, TEvents extends Record<string, any> = Record<string, any>> {
45
- /** ID da sala */
46
- readonly id: string
47
-
48
- /** Se está participando desta sala */
49
- readonly joined: boolean
50
-
51
- /** Estado compartilhado da sala */
52
- readonly state: TState
53
-
54
- /** Entrar na sala */
55
- join: (initialState?: TState) => Promise<void>
56
-
57
- /** Sair da sala */
58
- leave: () => Promise<void>
59
-
60
- /** Emitir evento para a sala */
61
- emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => void
62
-
63
- /** Escutar evento da sala */
64
- on: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>) => Unsubscribe
65
-
66
- /** Escutar evento do sistema ($state:change, $sub:join, etc) */
67
- onSystem: (event: string, handler: EventHandler) => Unsubscribe
68
-
69
- /** Atualizar estado da sala */
70
- setState: (updates: Partial<TState>) => void
71
- }
72
-
73
- // Interface do proxy $room
74
- export interface RoomProxy<TState = any, TEvents extends Record<string, any> = Record<string, any>> {
75
- // Quando chamado como função: $room('sala-id')
76
- (roomId: string): RoomHandle<TState, TEvents>
77
-
78
- // Quando acessado como objeto: $room.emit() (usa sala padrão)
79
- readonly id: string | null
80
- readonly joined: boolean
81
- readonly state: TState
82
- join: (initialState?: TState) => Promise<void>
83
- leave: () => Promise<void>
84
- emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => void
85
- on: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>) => Unsubscribe
86
- onSystem: (event: string, handler: EventHandler) => Unsubscribe
87
- setState: (updates: Partial<TState>) => void
88
- }
89
-
90
- // Opções para criar o RoomManager
91
- export interface RoomManagerOptions {
92
- componentId: string | null
93
- defaultRoom?: string
94
- sendMessage: (msg: any) => void
95
- sendMessageAndWait: (msg: any, timeout?: number) => Promise<any>
96
- onMessage: (handler: (msg: RoomServerMessage) => void) => Unsubscribe
97
- }
98
-
99
- // Classe interna para gerenciar salas
100
- export class RoomManager<TState = any, TEvents extends Record<string, any> = Record<string, any>> {
101
- private componentId: string | null
102
- private defaultRoom: string | null
103
- private rooms = new Map<string, {
104
- joined: boolean
105
- state: TState
106
- handlers: Map<string, Set<EventHandler>>
107
- }>()
108
- private handles = new Map<string, RoomHandle<TState, TEvents>>() // Cache de handles
109
- private sendMessage: (msg: any) => void
110
- private sendMessageAndWait: (msg: any, timeout?: number) => Promise<any>
111
- private globalUnsubscribe: Unsubscribe | null = null
112
-
113
- constructor(options: RoomManagerOptions) {
114
- this.componentId = options.componentId
115
- this.defaultRoom = options.defaultRoom || null
116
- this.sendMessage = options.sendMessage
117
- this.sendMessageAndWait = options.sendMessageAndWait
118
-
119
- // Escutar mensagens do servidor
120
- this.globalUnsubscribe = options.onMessage((msg) => this.handleServerMessage(msg))
121
- }
122
-
123
- private handleServerMessage(msg: RoomServerMessage): void {
124
- if (msg.componentId !== this.componentId) return
125
-
126
- const room = this.rooms.get(msg.roomId)
127
- if (!room) return
128
-
129
- switch (msg.type) {
130
- case 'ROOM_EVENT':
131
- case 'ROOM_SYSTEM':
132
- // Chamar handlers registrados
133
- const handlers = room.handlers.get(msg.event)
134
- if (handlers) {
135
- for (const handler of handlers) {
136
- try {
137
- handler(msg.data)
138
- } catch (error) {
139
- console.error(`[Room:${msg.roomId}] Handler error for '${msg.event}':`, error)
140
- }
141
- }
142
- }
143
- break
144
-
145
- case 'ROOM_STATE':
146
- // Atualizar estado local
147
- room.state = { ...room.state, ...msg.data }
148
- // Emitir evento de mudança
149
- const stateHandlers = room.handlers.get('$state:change')
150
- if (stateHandlers) {
151
- for (const handler of stateHandlers) {
152
- handler(msg.data)
153
- }
154
- }
155
- break
156
-
157
- case 'ROOM_JOINED':
158
- room.joined = true
159
- if (msg.data?.state) {
160
- room.state = msg.data.state
161
- }
162
- break
163
-
164
- case 'ROOM_LEFT':
165
- room.joined = false
166
- break
167
- }
168
- }
169
-
170
- private getOrCreateRoom(roomId: string): typeof this.rooms extends Map<string, infer V> ? V : never {
171
- if (!this.rooms.has(roomId)) {
172
- this.rooms.set(roomId, {
173
- joined: false,
174
- state: {} as TState,
175
- handlers: new Map()
176
- })
177
- }
178
- return this.rooms.get(roomId)!
179
- }
180
-
181
- // Criar handle para uma sala específica (com cache)
182
- createHandle(roomId: string): RoomHandle<TState, TEvents> {
183
- // Retornar handle cacheado se existir
184
- if (this.handles.has(roomId)) {
185
- return this.handles.get(roomId)!
186
- }
187
-
188
- const room = this.getOrCreateRoom(roomId)
189
-
190
- const handle: RoomHandle<TState, TEvents> = {
191
- get id() { return roomId },
192
- get joined() { return room.joined },
193
- get state() { return room.state },
194
-
195
- join: async (initialState?: TState) => {
196
- if (!this.componentId) throw new Error('Component not mounted')
197
- if (room.joined) return
198
-
199
- if (initialState) {
200
- room.state = initialState
201
- }
202
-
203
- const response = await this.sendMessageAndWait({
204
- type: 'ROOM_JOIN',
205
- componentId: this.componentId,
206
- roomId,
207
- data: { initialState: room.state },
208
- timestamp: Date.now()
209
- }, 5000)
210
-
211
- if (response?.success) {
212
- room.joined = true
213
- if (response.state) {
214
- room.state = response.state
215
- }
216
- }
217
- },
218
-
219
- leave: async () => {
220
- if (!this.componentId || !room.joined) return
221
-
222
- await this.sendMessageAndWait({
223
- type: 'ROOM_LEAVE',
224
- componentId: this.componentId,
225
- roomId,
226
- timestamp: Date.now()
227
- }, 5000)
228
-
229
- room.joined = false
230
- room.handlers.clear()
231
- },
232
-
233
- emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => {
234
- if (!this.componentId) return
235
-
236
- this.sendMessage({
237
- type: 'ROOM_EMIT',
238
- componentId: this.componentId,
239
- roomId,
240
- event: event as string,
241
- data,
242
- timestamp: Date.now()
243
- })
244
- },
245
-
246
- on: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): Unsubscribe => {
247
- const eventKey = event as string
248
-
249
- if (!room.handlers.has(eventKey)) {
250
- room.handlers.set(eventKey, new Set())
251
- }
252
- room.handlers.get(eventKey)!.add(handler)
253
-
254
- return () => {
255
- room.handlers.get(eventKey)?.delete(handler)
256
- }
257
- },
258
-
259
- onSystem: (event: string, handler: EventHandler): Unsubscribe => {
260
- const eventKey = `$${event}`
261
-
262
- if (!room.handlers.has(eventKey)) {
263
- room.handlers.set(eventKey, new Set())
264
- }
265
- room.handlers.get(eventKey)!.add(handler)
266
-
267
- return () => {
268
- room.handlers.get(eventKey)?.delete(handler)
269
- }
270
- },
271
-
272
- setState: (updates: Partial<TState>) => {
273
- if (!this.componentId) return
274
-
275
- // Atualiza localmente (otimista)
276
- room.state = { ...room.state, ...updates }
277
-
278
- // Envia para o servidor
279
- this.sendMessage({
280
- type: 'ROOM_STATE_SET',
281
- componentId: this.componentId,
282
- roomId,
283
- data: updates,
284
- timestamp: Date.now()
285
- })
286
- }
287
- }
288
-
289
- // Cachear handle
290
- this.handles.set(roomId, handle)
291
-
292
- return handle
293
- }
294
-
295
- // Criar o proxy $room
296
- createProxy(): RoomProxy<TState, TEvents> {
297
- const self = this
298
-
299
- // Função que também tem propriedades
300
- const proxyFn = function(roomId: string): RoomHandle<TState, TEvents> {
301
- return self.createHandle(roomId)
302
- } as RoomProxy<TState, TEvents>
303
-
304
- // Se tem sala padrão, expor métodos diretamente
305
- const defaultHandle = this.defaultRoom ? this.createHandle(this.defaultRoom) : null
306
-
307
- Object.defineProperties(proxyFn, {
308
- id: {
309
- get: () => this.defaultRoom
310
- },
311
- joined: {
312
- get: () => defaultHandle?.joined ?? false
313
- },
314
- state: {
315
- get: () => defaultHandle?.state ?? ({} as TState)
316
- },
317
- join: {
318
- value: async (initialState?: TState) => {
319
- if (!defaultHandle) throw new Error('No default room set')
320
- return defaultHandle.join(initialState)
321
- }
322
- },
323
- leave: {
324
- value: async () => {
325
- if (!defaultHandle) throw new Error('No default room set')
326
- return defaultHandle.leave()
327
- }
328
- },
329
- emit: {
330
- value: <K extends keyof TEvents>(event: K, data: TEvents[K]) => {
331
- if (!defaultHandle) throw new Error('No default room set')
332
- return defaultHandle.emit(event, data)
333
- }
334
- },
335
- on: {
336
- value: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): Unsubscribe => {
337
- if (!defaultHandle) throw new Error('No default room set')
338
- return defaultHandle.on(event, handler)
339
- }
340
- },
341
- onSystem: {
342
- value: (event: string, handler: EventHandler): Unsubscribe => {
343
- if (!defaultHandle) throw new Error('No default room set')
344
- return defaultHandle.onSystem(event, handler)
345
- }
346
- },
347
- setState: {
348
- value: (updates: Partial<TState>) => {
349
- if (!defaultHandle) throw new Error('No default room set')
350
- return defaultHandle.setState(updates)
351
- }
352
- }
353
- })
354
-
355
- return proxyFn
356
- }
357
-
358
- // Lista de salas que está participando
359
- getJoinedRooms(): string[] {
360
- const joined: string[] = []
361
- for (const [id, room] of this.rooms) {
362
- if (room.joined) joined.push(id)
363
- }
364
- return joined
365
- }
366
-
367
- // Atualizar componentId (quando monta)
368
- setComponentId(id: string | null): void {
369
- this.componentId = id
370
- }
371
-
372
- // Cleanup
373
- destroy(): void {
374
- this.globalUnsubscribe?.()
375
- for (const [, room] of this.rooms) {
376
- room.handlers.clear()
377
- }
378
- this.rooms.clear()
379
- }
380
- }
381
-
382
- export type { EventHandler, Unsubscribe }