create-fluxstack 1.10.1 → 1.12.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 (257) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LLMD/INDEX.md +64 -0
  4. package/LLMD/MAINTENANCE.md +197 -0
  5. package/LLMD/MIGRATION.md +156 -0
  6. package/LLMD/config/.gitkeep +1 -0
  7. package/LLMD/config/declarative-system.md +268 -0
  8. package/LLMD/config/environment-vars.md +327 -0
  9. package/LLMD/config/runtime-reload.md +401 -0
  10. package/LLMD/core/.gitkeep +1 -0
  11. package/LLMD/core/build-system.md +599 -0
  12. package/LLMD/core/framework-lifecycle.md +229 -0
  13. package/LLMD/core/plugin-system.md +451 -0
  14. package/LLMD/patterns/.gitkeep +1 -0
  15. package/LLMD/patterns/anti-patterns.md +297 -0
  16. package/LLMD/patterns/project-structure.md +264 -0
  17. package/LLMD/patterns/type-safety.md +440 -0
  18. package/LLMD/reference/.gitkeep +1 -0
  19. package/LLMD/reference/cli-commands.md +250 -0
  20. package/LLMD/reference/plugin-hooks.md +357 -0
  21. package/LLMD/reference/routing.md +39 -0
  22. package/LLMD/reference/troubleshooting.md +364 -0
  23. package/LLMD/resources/.gitkeep +1 -0
  24. package/LLMD/resources/controllers.md +465 -0
  25. package/LLMD/resources/live-components.md +703 -0
  26. package/LLMD/resources/live-rooms.md +482 -0
  27. package/LLMD/resources/live-upload.md +130 -0
  28. package/LLMD/resources/plugins-external.md +617 -0
  29. package/LLMD/resources/routes-eden.md +254 -0
  30. package/README.md +37 -17
  31. package/app/client/index.html +0 -1
  32. package/app/client/src/App.tsx +107 -150
  33. package/app/client/src/components/AppLayout.tsx +68 -0
  34. package/app/client/src/components/BackButton.tsx +13 -0
  35. package/app/client/src/components/DemoPage.tsx +20 -0
  36. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  37. package/app/client/src/lib/eden-api.ts +85 -60
  38. package/app/client/src/live/ChatDemo.tsx +107 -0
  39. package/app/client/src/live/CounterDemo.tsx +206 -0
  40. package/app/client/src/live/FormDemo.tsx +119 -0
  41. package/app/client/src/live/RoomChatDemo.tsx +242 -0
  42. package/app/client/src/live/UploadDemo.tsx +21 -0
  43. package/app/client/src/main.tsx +4 -1
  44. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  45. package/app/client/src/pages/HomePage.tsx +76 -0
  46. package/app/server/app.ts +1 -4
  47. package/app/server/controllers/users.controller.ts +36 -44
  48. package/app/server/index.ts +25 -35
  49. package/app/server/live/LiveChat.ts +77 -0
  50. package/app/server/live/LiveCounter.ts +67 -0
  51. package/app/server/live/LiveForm.ts +63 -0
  52. package/app/server/live/LiveLocalCounter.ts +32 -0
  53. package/app/server/live/LiveRoomChat.ts +285 -0
  54. package/app/server/live/LiveUpload.ts +81 -0
  55. package/app/server/routes/index.ts +3 -1
  56. package/app/server/routes/room.routes.ts +117 -0
  57. package/app/server/routes/users.routes.ts +35 -27
  58. package/app/shared/types/index.ts +14 -2
  59. package/config/app.config.ts +2 -62
  60. package/config/client.config.ts +2 -95
  61. package/config/database.config.ts +2 -99
  62. package/config/fluxstack.config.ts +25 -45
  63. package/config/index.ts +57 -38
  64. package/config/monitoring.config.ts +2 -114
  65. package/config/plugins.config.ts +2 -80
  66. package/config/server.config.ts +2 -68
  67. package/config/services.config.ts +2 -130
  68. package/config/system/app.config.ts +29 -0
  69. package/config/system/build.config.ts +49 -0
  70. package/config/system/client.config.ts +68 -0
  71. package/config/system/database.config.ts +17 -0
  72. package/config/system/fluxstack.config.ts +114 -0
  73. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  74. package/config/system/monitoring.config.ts +114 -0
  75. package/config/system/plugins.config.ts +84 -0
  76. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  77. package/config/system/server.config.ts +68 -0
  78. package/config/system/services.config.ts +46 -0
  79. package/config/{system.config.ts → system/system.config.ts} +1 -1
  80. package/core/build/flux-plugins-generator.ts +325 -325
  81. package/core/build/index.ts +39 -27
  82. package/core/build/live-components-generator.ts +3 -3
  83. package/core/build/optimizer.ts +235 -235
  84. package/core/cli/command-registry.ts +6 -4
  85. package/core/cli/commands/build.ts +79 -0
  86. package/core/cli/commands/create.ts +54 -0
  87. package/core/cli/commands/dev.ts +101 -0
  88. package/core/cli/commands/help.ts +34 -0
  89. package/core/cli/commands/index.ts +34 -0
  90. package/core/cli/commands/make-plugin.ts +90 -0
  91. package/core/cli/commands/plugin-add.ts +197 -0
  92. package/core/cli/commands/plugin-deps.ts +2 -2
  93. package/core/cli/commands/plugin-list.ts +208 -0
  94. package/core/cli/commands/plugin-remove.ts +170 -0
  95. package/core/cli/generators/component.ts +769 -769
  96. package/core/cli/generators/controller.ts +1 -1
  97. package/core/cli/generators/index.ts +146 -146
  98. package/core/cli/generators/interactive.ts +227 -227
  99. package/core/cli/generators/plugin.ts +2 -2
  100. package/core/cli/generators/prompts.ts +82 -82
  101. package/core/cli/generators/route.ts +6 -6
  102. package/core/cli/generators/service.ts +2 -2
  103. package/core/cli/generators/template-engine.ts +4 -3
  104. package/core/cli/generators/types.ts +2 -2
  105. package/core/cli/generators/utils.ts +191 -191
  106. package/core/cli/index.ts +115 -686
  107. package/core/cli/plugin-discovery.ts +2 -2
  108. package/core/client/LiveComponentsProvider.tsx +60 -8
  109. package/core/client/api/eden.ts +183 -0
  110. package/core/client/api/index.ts +11 -0
  111. package/core/client/components/Live.tsx +104 -0
  112. package/core/client/fluxstack.ts +1 -9
  113. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
  114. package/core/client/hooks/state-validator.ts +1 -1
  115. package/core/client/hooks/useAuth.ts +48 -48
  116. package/core/client/hooks/useChunkedUpload.ts +85 -35
  117. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  118. package/core/client/hooks/useLiveComponent.ts +800 -0
  119. package/core/client/hooks/useLiveUpload.ts +71 -0
  120. package/core/client/hooks/useRoom.ts +409 -0
  121. package/core/client/hooks/useRoomProxy.ts +382 -0
  122. package/core/client/index.ts +17 -68
  123. package/core/client/standalone-entry.ts +8 -0
  124. package/core/client/standalone.ts +74 -53
  125. package/core/client/state/createStore.ts +192 -192
  126. package/core/client/state/index.ts +14 -14
  127. package/core/config/index.ts +70 -291
  128. package/core/config/schema.ts +42 -723
  129. package/core/framework/client.ts +131 -131
  130. package/core/framework/index.ts +7 -7
  131. package/core/framework/server.ts +47 -40
  132. package/core/framework/types.ts +2 -2
  133. package/core/index.ts +23 -4
  134. package/core/live/ComponentRegistry.ts +3 -3
  135. package/core/live/types.ts +77 -0
  136. package/core/plugins/built-in/index.ts +134 -134
  137. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1066
  138. package/core/plugins/built-in/live-components/index.ts +1 -1
  139. package/core/plugins/built-in/monitoring/index.ts +111 -47
  140. package/core/plugins/built-in/static/index.ts +1 -1
  141. package/core/plugins/built-in/swagger/index.ts +68 -265
  142. package/core/plugins/built-in/vite/index.ts +85 -185
  143. package/core/plugins/built-in/vite/vite-dev.ts +10 -16
  144. package/core/plugins/config.ts +9 -7
  145. package/core/plugins/dependency-manager.ts +31 -1
  146. package/core/plugins/discovery.ts +19 -7
  147. package/core/plugins/executor.ts +2 -2
  148. package/core/plugins/index.ts +203 -203
  149. package/core/plugins/manager.ts +27 -39
  150. package/core/plugins/module-resolver.ts +19 -8
  151. package/core/plugins/registry.ts +255 -19
  152. package/core/plugins/types.ts +20 -53
  153. package/core/server/framework.ts +66 -43
  154. package/core/server/index.ts +15 -15
  155. package/core/server/live/ComponentRegistry.ts +78 -71
  156. package/core/server/live/FileUploadManager.ts +23 -10
  157. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  158. package/core/server/live/LiveRoomManager.ts +261 -0
  159. package/core/server/live/RoomEventBus.ts +234 -0
  160. package/core/server/live/RoomStateManager.ts +172 -0
  161. package/core/server/live/StateSignature.ts +643 -643
  162. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  163. package/core/server/live/auto-generated-components.ts +21 -9
  164. package/core/server/live/index.ts +14 -0
  165. package/core/server/live/websocket-plugin.ts +214 -67
  166. package/core/server/middleware/elysia-helpers.ts +7 -2
  167. package/core/server/middleware/errorHandling.ts +1 -1
  168. package/core/server/middleware/index.ts +31 -31
  169. package/core/server/plugins/database.ts +180 -180
  170. package/core/server/plugins/static-files-plugin.ts +69 -69
  171. package/core/server/plugins/swagger.ts +1 -1
  172. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  173. package/core/server/rooms/RoomSystem.ts +463 -0
  174. package/core/server/rooms/index.ts +13 -0
  175. package/core/server/services/BaseService.ts +1 -1
  176. package/core/server/services/ServiceContainer.ts +1 -1
  177. package/core/server/services/index.ts +8 -8
  178. package/core/templates/create-project.ts +12 -12
  179. package/core/testing/index.ts +9 -9
  180. package/core/testing/setup.ts +73 -73
  181. package/core/types/api.ts +168 -168
  182. package/core/types/build.ts +219 -219
  183. package/core/types/config.ts +56 -26
  184. package/core/types/index.ts +4 -4
  185. package/core/types/plugin.ts +107 -107
  186. package/core/types/types.ts +353 -14
  187. package/core/utils/build-logger.ts +324 -324
  188. package/core/utils/config-schema.ts +480 -480
  189. package/core/utils/env.ts +2 -8
  190. package/core/utils/errors/codes.ts +114 -114
  191. package/core/utils/errors/handlers.ts +36 -1
  192. package/core/utils/errors/index.ts +49 -5
  193. package/core/utils/errors/middleware.ts +113 -113
  194. package/core/utils/helpers.ts +6 -16
  195. package/core/utils/index.ts +17 -17
  196. package/core/utils/logger/colors.ts +114 -114
  197. package/core/utils/logger/config.ts +13 -9
  198. package/core/utils/logger/formatter.ts +82 -82
  199. package/core/utils/logger/group-logger.ts +101 -101
  200. package/core/utils/logger/index.ts +6 -1
  201. package/core/utils/logger/stack-trace.ts +3 -1
  202. package/core/utils/logger/startup-banner.ts +82 -82
  203. package/core/utils/logger/winston-logger.ts +152 -152
  204. package/core/utils/monitoring/index.ts +211 -211
  205. package/core/utils/sync-version.ts +66 -66
  206. package/core/utils/version.ts +1 -1
  207. package/create-fluxstack.ts +8 -7
  208. package/package.json +12 -13
  209. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  210. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  211. package/plugins/crypto-auth/client/components/index.ts +11 -11
  212. package/plugins/crypto-auth/client/index.ts +11 -11
  213. package/plugins/crypto-auth/config/index.ts +1 -1
  214. package/plugins/crypto-auth/index.ts +4 -4
  215. package/plugins/crypto-auth/package.json +65 -65
  216. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  217. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  218. package/plugins/crypto-auth/server/index.ts +21 -21
  219. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  220. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  221. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  222. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  223. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  224. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  225. package/tsconfig.api-strict.json +16 -0
  226. package/tsconfig.json +48 -52
  227. package/{app/client/tsconfig.node.json → tsconfig.node.json} +25 -25
  228. package/types/global.d.ts +29 -29
  229. package/types/vitest.d.ts +8 -8
  230. package/vite.config.ts +38 -62
  231. package/vitest.config.live.ts +10 -9
  232. package/vitest.config.ts +29 -17
  233. package/app/client/README.md +0 -69
  234. package/app/client/SIMPLIFICATION.md +0 -140
  235. package/app/client/frontend-only.ts +0 -12
  236. package/app/client/src/live/FileUploadExample.tsx +0 -359
  237. package/app/client/src/live/MinimalLiveClock.tsx +0 -47
  238. package/app/client/src/live/QuickUploadTest.tsx +0 -193
  239. package/app/client/tsconfig.app.json +0 -45
  240. package/app/client/tsconfig.json +0 -7
  241. package/app/client/zustand-setup.md +0 -65
  242. package/app/server/backend-only.ts +0 -18
  243. package/app/server/live/LiveClockComponent.ts +0 -215
  244. package/app/server/live/LiveFileUploadComponent.ts +0 -77
  245. package/app/server/routes/env-test.ts +0 -110
  246. package/core/client/hooks/index.ts +0 -7
  247. package/core/client/hooks/useHybridLiveComponent.ts +0 -685
  248. package/core/client/hooks/useTypedLiveComponent.ts +0 -133
  249. package/core/client/hooks/useWebSocket.ts +0 -361
  250. package/core/config/env.ts +0 -546
  251. package/core/config/loader.ts +0 -522
  252. package/core/config/runtime-config.ts +0 -327
  253. package/core/config/validator.ts +0 -540
  254. package/core/server/backend-entry.ts +0 -51
  255. package/core/server/standalone.ts +0 -106
  256. package/core/utils/regenerate-files.ts +0 -69
  257. package/fluxstack.config.ts +0 -354
@@ -0,0 +1,382 @@
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 }
@@ -1,81 +1,30 @@
1
1
  // 🔥 FluxStack Client Core - Main Export
2
2
 
3
+ // API Client (Eden Treaty)
4
+ export {
5
+ createEdenClient,
6
+ getErrorMessage,
7
+ getDefaultBaseUrl,
8
+ treaty,
9
+ type EdenClientOptions
10
+ } from './api'
11
+
3
12
  // Live Components Provider (Singleton WebSocket Connection)
4
13
  export {
5
14
  LiveComponentsProvider,
6
- useLiveComponents,
7
- // Deprecated exports for backward compatibility
8
- WebSocketProvider,
9
- useWebSocketContext
15
+ useLiveComponents
10
16
  } from './LiveComponentsProvider'
11
17
  export type {
12
18
  LiveComponentsProviderProps,
13
- LiveComponentsContextValue,
14
- // Deprecated types for backward compatibility
15
- WebSocketProviderProps,
16
- WebSocketContextValue
19
+ LiveComponentsContextValue
17
20
  } from './LiveComponentsProvider'
18
21
 
19
- // Hooks
20
- export { useWebSocket } from './hooks/useWebSocket'
21
- export { useHybridLiveComponent } from './hooks/useHybridLiveComponent'
22
- export { useTypedLiveComponent, createTypedLiveComponentHook } from './hooks/useTypedLiveComponent'
22
+ // Chunked Upload Hook
23
23
  export { useChunkedUpload } from './hooks/useChunkedUpload'
24
- export { AdaptiveChunkSizer } from './hooks/AdaptiveChunkSizer'
25
- export { StateValidator } from './hooks/state-validator'
26
-
27
- // Hook types
28
- export type { AdaptiveChunkConfig, ChunkMetrics } from './hooks/AdaptiveChunkSizer'
29
24
  export type { ChunkedUploadOptions, ChunkedUploadState } from './hooks/useChunkedUpload'
25
+ export { useLiveChunkedUpload } from './hooks/useLiveChunkedUpload'
26
+ export type { LiveChunkedUploadOptions } from './hooks/useLiveChunkedUpload'
27
+ export { useLiveUpload } from './hooks/useLiveUpload'
30
28
 
31
- // Re-export types from core/types/types.ts for convenience
32
- export type {
33
- // Live Components types
34
- LiveMessage,
35
- ComponentState,
36
- LiveComponentInstance,
37
- WebSocketData,
38
- ComponentDefinition,
39
- BroadcastMessage,
40
- LiveComponent,
41
-
42
- // WebSocket types
43
- WebSocketMessage,
44
- WebSocketResponse,
45
-
46
- // Hybrid Live Component types
47
- HybridState,
48
- StateValidation,
49
- StateConflict,
50
- HybridComponentOptions,
51
-
52
- // File Upload types
53
- FileChunkData,
54
- FileUploadStartMessage,
55
- FileUploadChunkMessage,
56
- FileUploadCompleteMessage,
57
- FileUploadProgressResponse,
58
- FileUploadCompleteResponse,
59
- ActiveUpload,
60
-
61
- // Utility types
62
- ComponentActions,
63
- ComponentProps,
64
- ActionParameters,
65
- ActionReturnType,
66
-
67
- // Type inference system (similar to Eden Treaty)
68
- ExtractActions,
69
- ActionNames,
70
- ActionPayload,
71
- ActionReturn,
72
- InferComponentState,
73
- TypedCall,
74
- TypedCallAndWait,
75
- TypedSetValue,
76
- UseTypedLiveComponentReturn
77
- } from '../types/types'
78
-
79
- // Hook return types
80
- export type { UseHybridLiveComponentReturn } from './hooks/useHybridLiveComponent'
81
- export type { ComponentRegistry } from './hooks/useTypedLiveComponent'
29
+ // Live Component Hook (API principal)
30
+ export { Live } from './components/Live'
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Frontend Standalone Entry Point
3
+ * Roda apenas Vite, sem Elysia backend
4
+ */
5
+
6
+ import { startFrontendOnly } from "./standalone"
7
+
8
+ await startFrontendOnly()
@@ -1,57 +1,78 @@
1
- // Standalone frontend development
2
- import { spawn } from "bun"
3
- import { join } from "path"
4
-
5
- export const startFrontendOnly = (config: any = {}) => {
6
- const clientPath = config.clientPath || "app/client"
7
- const port = config.vitePort || process.env.FRONTEND_PORT || 5173
8
- const apiUrl = config.apiUrl || process.env.API_URL || 'http://localhost:3000/api'
9
-
10
- console.log(`⚛️ FluxStack Frontend`)
11
- console.log(`🌐 http://${process.env.HOST || 'localhost'}:${port}`)
12
- console.log(`🔗 API: ${apiUrl}`)
1
+ /**
2
+ * Standalone Frontend Development
3
+ * Starts Vite dev server directly without Elysia backend
4
+ */
5
+
6
+ import { clientConfig } from '@config'
7
+ import type { LogLevel } from 'vite'
8
+
9
+ type ViteDevServer = Awaited<ReturnType<typeof import('vite')['createServer']>>
10
+
11
+ let viteServer: ViteDevServer | null = null
12
+
13
+ export const startFrontendOnly = async (config: any = {}) => {
14
+ const port = config.vitePort || clientConfig.vite.port || 5173
15
+ const host = config.viteHost || clientConfig.vite.host || 'localhost'
16
+ const logLevel = (config.logLevel || clientConfig.vite.logLevel || 'info') as LogLevel
17
+
18
+ console.log(`⚛️ FluxStack Frontend Only`)
19
+ console.log(`🌐 http://${host}:${port}`)
13
20
  console.log()
14
-
15
- const viteProcess = spawn({
16
- cmd: ["bun", "run", "dev"],
17
- cwd: join(process.cwd(), clientPath),
18
- stdout: "pipe",
19
- stderr: "pipe",
20
- env: {
21
- ...process.env,
22
- VITE_API_URL: apiUrl,
23
- PORT: port.toString(),
24
- HOST: process.env.HOST || 'localhost'
25
- }
26
- })
27
-
28
- if (viteProcess.stdout) {
29
- viteProcess.stdout.pipeTo(new WritableStream({
30
- write(chunk) {
31
- const output = new TextDecoder().decode(chunk)
32
- // Filtrar mensagens desnecessárias do Vite
33
- if (!output.includes("hmr update") && !output.includes("Local:")) {
34
- console.log(output)
35
- }
36
- }
37
- })).catch(() => {}) // Ignore pipe errors
38
- }
39
21
 
40
- if (viteProcess.stderr) {
41
- viteProcess.stderr.pipeTo(new WritableStream({
42
- write(chunk) {
43
- const error = new TextDecoder().decode(chunk)
44
- console.error(error)
22
+ try {
23
+ // Dynamic import of vite
24
+ const { createServer } = await import('vite')
25
+
26
+ // Start Vite dev server programmatically
27
+ viteServer = await createServer({
28
+ configFile: './vite.config.ts',
29
+ server: {
30
+ port,
31
+ host,
32
+ strictPort: clientConfig.vite.strictPort
33
+ },
34
+ logLevel
35
+ })
36
+
37
+ await viteServer.listen()
38
+
39
+ console.log(`✅ Frontend server ready!`)
40
+ console.log()
41
+
42
+ // Setup cleanup on process exit
43
+ const cleanup = async () => {
44
+ if (viteServer) {
45
+ console.log('\n🛑 Stopping frontend...')
46
+ await viteServer.close()
47
+ viteServer = null
48
+ process.exit(0)
45
49
  }
46
- })).catch(() => {}) // Ignore pipe errors
47
- }
50
+ }
51
+
52
+ process.on('SIGINT', cleanup)
53
+ process.on('SIGTERM', cleanup)
54
+ process.on('exit', cleanup)
48
55
 
49
- // Cleanup ao sair
50
- process.on("SIGINT", () => {
51
- console.log("\n🛑 Stopping frontend...")
52
- viteProcess.kill()
53
- process.exit(0)
54
- })
55
-
56
- return viteProcess
57
- }
56
+ return viteServer
57
+
58
+ } catch (error) {
59
+ // Check if error is related to port already in use
60
+ const errorMessage = error instanceof Error ? error.message : String(error)
61
+ const isPortInUse = errorMessage.includes('EADDRINUSE') ||
62
+ errorMessage.includes('address already in use') ||
63
+ (errorMessage.includes('Port') && errorMessage.includes('is in use'))
64
+
65
+ if (isPortInUse) {
66
+ console.error(`❌ Failed to start Vite: Port ${port} is already in use`)
67
+ console.log(`💡 Try one of these solutions:`)
68
+ console.log(` 1. Stop the process using port ${port}`)
69
+ console.log(` 2. Change VITE_PORT in your .env file`)
70
+ console.log(` 3. Kill the process: ${process.platform === 'win32' ? `netstat -ano | findstr :${port}` : `lsof -ti:${port} | xargs kill -9`}`)
71
+ process.exit(1)
72
+ } else {
73
+ console.error('❌ Failed to start Vite server:', errorMessage)
74
+ console.error('Full error:', error)
75
+ process.exit(1)
76
+ }
77
+ }
78
+ }