create-fluxstack 1.9.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 (259) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LIVE_COMPONENTS_REVIEW.md +781 -0
  4. package/LLMD/INDEX.md +64 -0
  5. package/LLMD/MAINTENANCE.md +197 -0
  6. package/LLMD/MIGRATION.md +156 -0
  7. package/LLMD/config/.gitkeep +1 -0
  8. package/LLMD/config/declarative-system.md +268 -0
  9. package/LLMD/config/environment-vars.md +327 -0
  10. package/LLMD/config/runtime-reload.md +401 -0
  11. package/LLMD/core/.gitkeep +1 -0
  12. package/LLMD/core/build-system.md +599 -0
  13. package/LLMD/core/framework-lifecycle.md +229 -0
  14. package/LLMD/core/plugin-system.md +451 -0
  15. package/LLMD/patterns/.gitkeep +1 -0
  16. package/LLMD/patterns/anti-patterns.md +297 -0
  17. package/LLMD/patterns/project-structure.md +264 -0
  18. package/LLMD/patterns/type-safety.md +440 -0
  19. package/LLMD/reference/.gitkeep +1 -0
  20. package/LLMD/reference/cli-commands.md +250 -0
  21. package/LLMD/reference/plugin-hooks.md +357 -0
  22. package/LLMD/reference/routing.md +39 -0
  23. package/LLMD/reference/troubleshooting.md +364 -0
  24. package/LLMD/resources/.gitkeep +1 -0
  25. package/LLMD/resources/controllers.md +465 -0
  26. package/LLMD/resources/live-components.md +703 -0
  27. package/LLMD/resources/live-rooms.md +482 -0
  28. package/LLMD/resources/live-upload.md +130 -0
  29. package/LLMD/resources/plugins-external.md +617 -0
  30. package/LLMD/resources/routes-eden.md +254 -0
  31. package/README.md +37 -17
  32. package/app/client/index.html +0 -1
  33. package/app/client/src/App.tsx +109 -156
  34. package/app/client/src/components/AppLayout.tsx +68 -0
  35. package/app/client/src/components/BackButton.tsx +13 -0
  36. package/app/client/src/components/DemoPage.tsx +20 -0
  37. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  38. package/app/client/src/lib/eden-api.ts +85 -65
  39. package/app/client/src/live/ChatDemo.tsx +107 -0
  40. package/app/client/src/live/CounterDemo.tsx +206 -0
  41. package/app/client/src/live/FormDemo.tsx +119 -0
  42. package/app/client/src/live/RoomChatDemo.tsx +242 -0
  43. package/app/client/src/live/UploadDemo.tsx +21 -0
  44. package/app/client/src/main.tsx +13 -10
  45. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  46. package/app/client/src/pages/HomePage.tsx +76 -0
  47. package/app/client/src/vite-env.d.ts +1 -1
  48. package/app/server/app.ts +1 -4
  49. package/app/server/controllers/users.controller.ts +36 -44
  50. package/app/server/index.ts +24 -107
  51. package/app/server/live/LiveChat.ts +77 -0
  52. package/app/server/live/LiveCounter.ts +67 -0
  53. package/app/server/live/LiveForm.ts +63 -0
  54. package/app/server/live/LiveLocalCounter.ts +32 -0
  55. package/app/server/live/LiveRoomChat.ts +285 -0
  56. package/app/server/live/LiveUpload.ts +81 -0
  57. package/app/server/live/register-components.ts +19 -19
  58. package/app/server/routes/index.ts +3 -1
  59. package/app/server/routes/room.routes.ts +117 -0
  60. package/app/server/routes/users.routes.ts +35 -27
  61. package/app/shared/types/index.ts +14 -2
  62. package/config/app.config.ts +2 -62
  63. package/config/client.config.ts +2 -95
  64. package/config/database.config.ts +2 -99
  65. package/config/fluxstack.config.ts +25 -45
  66. package/config/index.ts +57 -38
  67. package/config/monitoring.config.ts +2 -114
  68. package/config/plugins.config.ts +2 -80
  69. package/config/server.config.ts +2 -68
  70. package/config/services.config.ts +2 -130
  71. package/config/system/app.config.ts +29 -0
  72. package/config/system/build.config.ts +49 -0
  73. package/config/system/client.config.ts +68 -0
  74. package/config/system/database.config.ts +17 -0
  75. package/config/system/fluxstack.config.ts +114 -0
  76. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  77. package/config/system/monitoring.config.ts +114 -0
  78. package/config/system/plugins.config.ts +84 -0
  79. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  80. package/config/system/server.config.ts +68 -0
  81. package/config/system/services.config.ts +46 -0
  82. package/config/{system.config.ts → system/system.config.ts} +1 -1
  83. package/core/build/bundler.ts +4 -1
  84. package/core/build/flux-plugins-generator.ts +325 -325
  85. package/core/build/index.ts +159 -27
  86. package/core/build/live-components-generator.ts +70 -3
  87. package/core/build/optimizer.ts +235 -235
  88. package/core/cli/command-registry.ts +6 -4
  89. package/core/cli/commands/build.ts +79 -0
  90. package/core/cli/commands/create.ts +54 -0
  91. package/core/cli/commands/dev.ts +101 -0
  92. package/core/cli/commands/help.ts +34 -0
  93. package/core/cli/commands/index.ts +34 -0
  94. package/core/cli/commands/make-plugin.ts +90 -0
  95. package/core/cli/commands/plugin-add.ts +197 -0
  96. package/core/cli/commands/plugin-deps.ts +2 -2
  97. package/core/cli/commands/plugin-list.ts +208 -0
  98. package/core/cli/commands/plugin-remove.ts +170 -0
  99. package/core/cli/generators/component.ts +769 -769
  100. package/core/cli/generators/controller.ts +1 -1
  101. package/core/cli/generators/index.ts +146 -146
  102. package/core/cli/generators/interactive.ts +227 -227
  103. package/core/cli/generators/plugin.ts +2 -2
  104. package/core/cli/generators/prompts.ts +82 -82
  105. package/core/cli/generators/route.ts +6 -6
  106. package/core/cli/generators/service.ts +2 -2
  107. package/core/cli/generators/template-engine.ts +4 -3
  108. package/core/cli/generators/types.ts +2 -2
  109. package/core/cli/generators/utils.ts +191 -191
  110. package/core/cli/index.ts +115 -558
  111. package/core/cli/plugin-discovery.ts +2 -2
  112. package/core/client/LiveComponentsProvider.tsx +63 -17
  113. package/core/client/api/eden.ts +183 -0
  114. package/core/client/api/index.ts +11 -0
  115. package/core/client/components/Live.tsx +104 -0
  116. package/core/client/fluxstack.ts +1 -9
  117. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
  118. package/core/client/hooks/state-validator.ts +1 -1
  119. package/core/client/hooks/useAuth.ts +48 -48
  120. package/core/client/hooks/useChunkedUpload.ts +170 -69
  121. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  122. package/core/client/hooks/useLiveComponent.ts +800 -0
  123. package/core/client/hooks/useLiveUpload.ts +71 -0
  124. package/core/client/hooks/useRoom.ts +409 -0
  125. package/core/client/hooks/useRoomProxy.ts +382 -0
  126. package/core/client/index.ts +18 -51
  127. package/core/client/standalone-entry.ts +8 -0
  128. package/core/client/standalone.ts +74 -53
  129. package/core/client/state/createStore.ts +192 -192
  130. package/core/client/state/index.ts +14 -14
  131. package/core/config/index.ts +70 -291
  132. package/core/config/schema.ts +42 -723
  133. package/core/framework/client.ts +131 -131
  134. package/core/framework/index.ts +7 -7
  135. package/core/framework/server.ts +227 -47
  136. package/core/framework/types.ts +2 -2
  137. package/core/index.ts +23 -4
  138. package/core/live/ComponentRegistry.ts +7 -3
  139. package/core/live/types.ts +77 -0
  140. package/core/plugins/built-in/index.ts +134 -131
  141. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1074
  142. package/core/plugins/built-in/live-components/index.ts +1 -1
  143. package/core/plugins/built-in/monitoring/index.ts +111 -47
  144. package/core/plugins/built-in/static/index.ts +1 -1
  145. package/core/plugins/built-in/swagger/index.ts +68 -265
  146. package/core/plugins/built-in/vite/index.ts +94 -306
  147. package/core/plugins/built-in/vite/vite-dev.ts +82 -0
  148. package/core/plugins/config.ts +9 -7
  149. package/core/plugins/dependency-manager.ts +31 -1
  150. package/core/plugins/discovery.ts +19 -7
  151. package/core/plugins/executor.ts +2 -2
  152. package/core/plugins/index.ts +203 -203
  153. package/core/plugins/manager.ts +27 -39
  154. package/core/plugins/module-resolver.ts +19 -8
  155. package/core/plugins/registry.ts +309 -21
  156. package/core/plugins/types.ts +106 -55
  157. package/core/server/framework.ts +66 -43
  158. package/core/server/index.ts +15 -16
  159. package/core/server/live/ComponentRegistry.ts +91 -75
  160. package/core/server/live/FileUploadManager.ts +41 -31
  161. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  162. package/core/server/live/LiveRoomManager.ts +261 -0
  163. package/core/server/live/RoomEventBus.ts +234 -0
  164. package/core/server/live/RoomStateManager.ts +172 -0
  165. package/core/server/live/StateSignature.ts +643 -643
  166. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  167. package/core/server/live/auto-generated-components.ts +41 -26
  168. package/core/server/live/index.ts +14 -0
  169. package/core/server/live/websocket-plugin.ts +233 -72
  170. package/core/server/middleware/elysia-helpers.ts +7 -2
  171. package/core/server/middleware/errorHandling.ts +1 -1
  172. package/core/server/middleware/index.ts +31 -31
  173. package/core/server/plugins/database.ts +180 -180
  174. package/core/server/plugins/static-files-plugin.ts +69 -260
  175. package/core/server/plugins/swagger.ts +33 -33
  176. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  177. package/core/server/rooms/RoomSystem.ts +463 -0
  178. package/core/server/rooms/index.ts +13 -0
  179. package/core/server/services/BaseService.ts +1 -1
  180. package/core/server/services/ServiceContainer.ts +1 -1
  181. package/core/server/services/index.ts +8 -8
  182. package/core/templates/create-project.ts +12 -12
  183. package/core/testing/index.ts +9 -9
  184. package/core/testing/setup.ts +73 -73
  185. package/core/types/api.ts +168 -168
  186. package/core/types/build.ts +219 -218
  187. package/core/types/config.ts +56 -26
  188. package/core/types/index.ts +4 -4
  189. package/core/types/plugin.ts +107 -99
  190. package/core/types/types.ts +490 -14
  191. package/core/utils/build-logger.ts +324 -324
  192. package/core/utils/config-schema.ts +480 -480
  193. package/core/utils/env.ts +2 -8
  194. package/core/utils/errors/codes.ts +114 -114
  195. package/core/utils/errors/handlers.ts +36 -1
  196. package/core/utils/errors/index.ts +49 -5
  197. package/core/utils/errors/middleware.ts +113 -113
  198. package/core/utils/helpers.ts +6 -16
  199. package/core/utils/index.ts +17 -17
  200. package/core/utils/logger/colors.ts +114 -114
  201. package/core/utils/logger/config.ts +13 -9
  202. package/core/utils/logger/formatter.ts +82 -82
  203. package/core/utils/logger/group-logger.ts +101 -101
  204. package/core/utils/logger/index.ts +6 -1
  205. package/core/utils/logger/stack-trace.ts +3 -1
  206. package/core/utils/logger/startup-banner.ts +82 -66
  207. package/core/utils/logger/winston-logger.ts +152 -152
  208. package/core/utils/monitoring/index.ts +211 -211
  209. package/core/utils/sync-version.ts +66 -66
  210. package/core/utils/version.ts +1 -1
  211. package/create-fluxstack.ts +8 -7
  212. package/eslint.config.js +23 -23
  213. package/package.json +14 -15
  214. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  215. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  216. package/plugins/crypto-auth/client/components/index.ts +11 -11
  217. package/plugins/crypto-auth/client/index.ts +11 -11
  218. package/plugins/crypto-auth/config/index.ts +1 -1
  219. package/plugins/crypto-auth/index.ts +4 -4
  220. package/plugins/crypto-auth/package.json +65 -65
  221. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  222. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  223. package/plugins/crypto-auth/server/index.ts +21 -21
  224. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  225. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  226. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  227. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  228. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  229. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  230. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  231. package/tsconfig.api-strict.json +16 -0
  232. package/tsconfig.json +10 -14
  233. package/{app/client/tsconfig.node.json → tsconfig.node.json} +1 -1
  234. package/types/global.d.ts +29 -29
  235. package/types/vitest.d.ts +8 -8
  236. package/vite.config.ts +38 -62
  237. package/vitest.config.live.ts +10 -9
  238. package/vitest.config.ts +29 -17
  239. package/workspace.json +5 -5
  240. package/app/client/README.md +0 -69
  241. package/app/client/SIMPLIFICATION.md +0 -140
  242. package/app/client/frontend-only.ts +0 -12
  243. package/app/client/tsconfig.app.json +0 -44
  244. package/app/client/tsconfig.json +0 -7
  245. package/app/client/zustand-setup.md +0 -65
  246. package/app/server/backend-only.ts +0 -18
  247. package/app/server/live/LiveClockComponent.ts +0 -215
  248. package/app/server/routes/env-test.ts +0 -110
  249. package/core/client/hooks/index.ts +0 -7
  250. package/core/client/hooks/useHybridLiveComponent.ts +0 -631
  251. package/core/client/hooks/useWebSocket.ts +0 -373
  252. package/core/config/env.ts +0 -546
  253. package/core/config/loader.ts +0 -522
  254. package/core/config/runtime-config.ts +0 -327
  255. package/core/config/validator.ts +0 -540
  256. package/core/server/backend-entry.ts +0 -51
  257. package/core/server/standalone.ts +0 -106
  258. package/core/utils/regenerate-files.ts +0 -69
  259. 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,63 +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
+ // Chunked Upload Hook
22
23
  export { useChunkedUpload } from './hooks/useChunkedUpload'
23
- export { StateValidator } from './hooks/state-validator'
24
-
25
- // Re-export types from core/types/types.ts for convenience
26
- export type {
27
- // Live Components types
28
- LiveMessage,
29
- ComponentState,
30
- LiveComponentInstance,
31
- WebSocketData,
32
- ComponentDefinition,
33
- BroadcastMessage,
34
- LiveComponent,
35
-
36
- // WebSocket types
37
- WebSocketMessage,
38
- WebSocketResponse,
39
-
40
- // Hybrid Live Component types
41
- HybridState,
42
- StateValidation,
43
- StateConflict,
44
- HybridComponentOptions,
45
-
46
- // File Upload types
47
- FileChunkData,
48
- FileUploadStartMessage,
49
- FileUploadChunkMessage,
50
- FileUploadCompleteMessage,
51
- FileUploadProgressResponse,
52
- FileUploadCompleteResponse,
53
- ActiveUpload,
54
-
55
- // Utility types
56
- ComponentActions,
57
- ComponentProps,
58
- ActionParameters,
59
- ActionReturnType
60
- } from '../types/types'
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'
61
28
 
62
- // Hook return types
63
- export type { UseHybridLiveComponentReturn } from './hooks/useHybridLiveComponent'
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
+ }