create-fluxstack 1.10.1 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +161 -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 +127 -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
@@ -1,12 +1,13 @@
1
1
  // 🔥 FluxStack Live Components - Enhanced Component Registry
2
2
 
3
- import type {
4
- LiveComponent,
5
- LiveMessage,
6
- BroadcastMessage,
3
+ import type {
4
+ LiveComponent,
5
+ LiveMessage,
6
+ BroadcastMessage,
7
7
  ComponentDefinition,
8
- WebSocketData
9
- } from '@/core/plugins/types'
8
+ FluxStackWebSocket,
9
+ FluxStackWSData
10
+ } from '@core/plugins/types'
10
11
  import { stateSignature, type SignedState } from './StateSignature'
11
12
  import { performanceMonitor } from './LiveComponentPerformanceMonitor'
12
13
 
@@ -65,14 +66,14 @@ export interface ServiceContainer {
65
66
 
66
67
  export class ComponentRegistry {
67
68
  private components = new Map<string, LiveComponent>()
68
- private definitions = new Map<string, ComponentDefinition>()
69
+ private definitions = new Map<string, ComponentDefinition<any>>()
69
70
  private metadata = new Map<string, ComponentMetadata>()
70
71
  private rooms = new Map<string, Set<string>>() // roomId -> componentIds
71
- private wsConnections = new Map<string, any>() // componentId -> websocket
72
- private autoDiscoveredComponents = new Map<string, any>() // Auto-discovered component classes
72
+ private wsConnections = new Map<string, FluxStackWebSocket>() // componentId -> websocket
73
+ private autoDiscoveredComponents = new Map<string, new (initialState: any, ws: FluxStackWebSocket, options?: { room?: string; userId?: string }) => LiveComponent<any>>() // Auto-discovered component classes
73
74
  private dependencies = new Map<string, ComponentDependency[]>()
74
75
  private services: ServiceContainer
75
- private healthCheckInterval: NodeJS.Timeout
76
+ private healthCheckInterval!: NodeJS.Timeout
76
77
  private recoveryStrategies = new Map<string, () => Promise<void>>()
77
78
 
78
79
  constructor() {
@@ -141,7 +142,7 @@ export class ComponentRegistry {
141
142
  }
142
143
 
143
144
  // Register component class dynamically
144
- registerComponentClass(name: string, componentClass: any) {
145
+ registerComponentClass(name: string, componentClass: new (initialState: any, ws: FluxStackWebSocket, options?: { room?: string; userId?: string }) => LiveComponent<any>) {
145
146
  this.autoDiscoveredComponents.set(name, componentClass)
146
147
  // Logging is handled by autoDiscoverComponents
147
148
  }
@@ -151,11 +152,11 @@ export class ComponentRegistry {
151
152
  try {
152
153
  const fs = await import('fs')
153
154
  const path = await import('path')
154
- const { startGroup, endGroup, logInGroup, groupSummary } = await import('@/core/utils/logger/group-logger')
155
+ const { startGroup, endGroup, logInGroup, groupSummary } = await import('@core/utils/logger/group-logger')
155
156
 
156
157
  if (!fs.existsSync(componentsPath)) {
157
158
  // In production, components are already bundled - no need to auto-discover
158
- const { appConfig } = await import('@/config/app.config')
159
+ const { appConfig } = await import('@config')
159
160
  if (appConfig.env !== 'production') {
160
161
  console.log(`⚠️ Components path not found: ${componentsPath}`)
161
162
  }
@@ -215,11 +216,11 @@ export class ComponentRegistry {
215
216
 
216
217
  // Enhanced component mounting with lifecycle management
217
218
  async mountComponent(
218
- ws: any,
219
- componentName: string,
220
- props: any = {},
219
+ ws: FluxStackWebSocket,
220
+ componentName: string,
221
+ props: Record<string, unknown> = {},
221
222
  options?: { room?: string; userId?: string; version?: string }
222
- ): Promise<{ componentId: string; initialState: any; signedState: any }> {
223
+ ): Promise<{ componentId: string; initialState: unknown; signedState: unknown }> {
223
224
  const startTime = Date.now()
224
225
 
225
226
  try {
@@ -227,38 +228,38 @@ export class ComponentRegistry {
227
228
  await this.validateDependencies(componentName)
228
229
 
229
230
  // Try to find component definition first
230
- let definition = this.definitions.get(componentName)
231
- let ComponentClass: any = null
232
- let initialState: any = {}
231
+ const definition = this.definitions.get(componentName)
232
+ let ComponentClass: (new (initialState: any, ws: FluxStackWebSocket, options?: { room?: string; userId?: string }) => LiveComponent<any>) | null = null
233
+ let initialState: Record<string, unknown> = {}
233
234
 
234
235
  if (definition) {
235
236
  // Use registered definition
236
- ComponentClass = definition.component
237
- initialState = definition.initialState
238
- } else {
239
- // Try auto-discovered components
240
- ComponentClass = this.autoDiscoveredComponents.get(componentName)
241
- if (!ComponentClass) {
242
- // Try variations of the name
243
- const variations = [
244
- componentName + 'Component',
245
- componentName.charAt(0).toUpperCase() + componentName.slice(1) + 'Component',
246
- componentName.charAt(0).toUpperCase() + componentName.slice(1)
247
- ]
248
-
249
- for (const variation of variations) {
250
- ComponentClass = this.autoDiscoveredComponents.get(variation)
251
- if (ComponentClass) break
237
+ ComponentClass = definition.component
238
+ initialState = definition.initialState as Record<string, unknown>
239
+ } else {
240
+ // Try auto-discovered components
241
+ ComponentClass = this.autoDiscoveredComponents.get(componentName) ?? null
242
+ if (!ComponentClass) {
243
+ // Try variations of the name
244
+ const variations = [
245
+ componentName + 'Component',
246
+ componentName.charAt(0).toUpperCase() + componentName.slice(1) + 'Component',
247
+ componentName.charAt(0).toUpperCase() + componentName.slice(1)
248
+ ]
249
+
250
+ for (const variation of variations) {
251
+ ComponentClass = this.autoDiscoveredComponents.get(variation) ?? null
252
+ if (ComponentClass) break
253
+ }
254
+ }
255
+
256
+ if (!ComponentClass) {
257
+ const availableComponents = [
258
+ ...Array.from(this.definitions.keys()),
259
+ ...Array.from(this.autoDiscoveredComponents.keys())
260
+ ]
261
+ throw new Error(`Component '${componentName}' not found. Available: ${availableComponents.join(', ')}`)
252
262
  }
253
- }
254
-
255
- if (!ComponentClass) {
256
- const availableComponents = [
257
- ...Array.from(this.definitions.keys()),
258
- ...Array.from(this.autoDiscoveredComponents.keys())
259
- ]
260
- throw new Error(`Component '${componentName}' not found. Available: ${availableComponents.join(', ')}`)
261
- }
262
263
 
263
264
  // Create a default initial state for auto-discovered components
264
265
  initialState = {}
@@ -306,13 +307,16 @@ export class ComponentRegistry {
306
307
  if (!ws || typeof ws !== 'object') {
307
308
  throw new Error('Invalid WebSocket object provided')
308
309
  }
309
-
310
+
311
+ // Ensure data object exists with proper structure
310
312
  if (!ws.data) {
311
- ws.data = {
313
+ (ws as { data: FluxStackWSData }).data = {
314
+ connectionId: `ws-${Date.now()}`,
312
315
  components: new Map(),
313
316
  subscriptions: new Set(),
317
+ connectedAt: new Date(),
314
318
  userId: options?.userId
315
- } as WebSocketData
319
+ }
316
320
  }
317
321
 
318
322
  // Ensure components map exists
@@ -358,9 +362,9 @@ export class ComponentRegistry {
358
362
  // Re-hydrate component with signed client state
359
363
  async rehydrateComponent(
360
364
  componentId: string,
361
- componentName: string,
365
+ componentName: string,
362
366
  signedState: SignedState,
363
- ws: any,
367
+ ws: FluxStackWebSocket,
364
368
  options?: { room?: string; userId?: string }
365
369
  ): Promise<{ success: boolean; newComponentId?: string; error?: string }> {
366
370
  console.log('🔄 Attempting component re-hydration:', {
@@ -385,17 +389,17 @@ export class ComponentRegistry {
385
389
  }
386
390
 
387
391
  // Try to find component definition (same logic as mountComponent)
388
- let definition = this.definitions.get(componentName)
389
- let ComponentClass: any = null
390
- let initialState: any = {}
392
+ const definition = this.definitions.get(componentName)
393
+ let ComponentClass: (new (initialState: any, ws: FluxStackWebSocket, options?: { room?: string; userId?: string }) => LiveComponent<any>) | null = null
394
+ let initialState: Record<string, unknown> = {}
391
395
 
392
396
  if (definition) {
393
397
  // Use registered definition
394
398
  ComponentClass = definition.component
395
- initialState = definition.initialState
399
+ initialState = definition.initialState as Record<string, unknown>
396
400
  } else {
397
401
  // Try auto-discovered components
398
- ComponentClass = this.autoDiscoveredComponents.get(componentName)
402
+ ComponentClass = this.autoDiscoveredComponents.get(componentName) ?? null
399
403
  if (!ComponentClass) {
400
404
  // Try variations of the name
401
405
  const variations = [
@@ -403,13 +407,13 @@ export class ComponentRegistry {
403
407
  componentName.charAt(0).toUpperCase() + componentName.slice(1) + 'Component',
404
408
  componentName.charAt(0).toUpperCase() + componentName.slice(1)
405
409
  ]
406
-
410
+
407
411
  for (const variation of variations) {
408
- ComponentClass = this.autoDiscoveredComponents.get(variation)
412
+ ComponentClass = this.autoDiscoveredComponents.get(variation) ?? null
409
413
  if (ComponentClass) break
410
414
  }
411
415
  }
412
-
416
+
413
417
  if (!ComponentClass) {
414
418
  const availableComponents = [
415
419
  ...Array.from(this.definitions.keys()),
@@ -440,11 +444,13 @@ export class ComponentRegistry {
440
444
 
441
445
  // Initialize WebSocket data
442
446
  if (!ws.data) {
443
- ws.data = {
447
+ (ws as { data: FluxStackWSData }).data = {
448
+ connectionId: `ws-${Date.now()}`,
444
449
  components: new Map(),
445
450
  subscriptions: new Set(),
451
+ connectedAt: new Date(),
446
452
  userId: options?.userId
447
- } as WebSocketData
453
+ }
448
454
  }
449
455
 
450
456
  // Ensure components map exists
@@ -467,7 +473,8 @@ export class ComponentRegistry {
467
473
  signedState.version + 1
468
474
  )
469
475
 
470
- component.emit('STATE_REHYDRATED', {
476
+ // Use type assertion to access protected emit method
477
+ ;(component as unknown as { emit: (type: string, payload: unknown) => void }).emit('STATE_REHYDRATED', {
471
478
  state: component.getSerializableState(),
472
479
  signedState: newSignedState,
473
480
  oldComponentId: componentId,
@@ -494,8 +501,8 @@ export class ComponentRegistry {
494
501
  if (!component) return
495
502
 
496
503
  // Cleanup
497
- component.destroy()
498
-
504
+ component.destroy?.()
505
+
499
506
  // Remove from room subscriptions
500
507
  this.unsubscribeFromAllRooms(componentId)
501
508
 
@@ -516,7 +523,7 @@ export class ComponentRegistry {
516
523
  }
517
524
 
518
525
  try {
519
- return await component.executeAction(action, payload)
526
+ return await component.executeAction?.(action, payload)
520
527
  } catch (error: any) {
521
528
  console.error(`❌ Error executing action '${action}' on component '${componentId}':`, error.message)
522
529
  throw error
@@ -532,7 +539,7 @@ export class ComponentRegistry {
532
539
 
533
540
  // Update state
534
541
  const updates = { [property]: value }
535
- component.setState(updates)
542
+ component.setState?.(updates)
536
543
 
537
544
  console.log(`📝 Updated property '${property}' on component '${componentId}'`)
538
545
  }
@@ -606,7 +613,7 @@ export class ComponentRegistry {
606
613
  }
607
614
 
608
615
  // Handle WebSocket message with enhanced metrics and lifecycle tracking
609
- async handleMessage(ws: any, message: LiveMessage): Promise<any> {
616
+ async handleMessage(ws: FluxStackWebSocket, message: LiveMessage): Promise<{ success: boolean; result?: unknown; error?: string } | null> {
610
617
  const startTime = Date.now()
611
618
 
612
619
  try {
@@ -698,7 +705,7 @@ export class ComponentRegistry {
698
705
  }
699
706
 
700
707
  // Cleanup when WebSocket disconnects
701
- cleanupConnection(ws: any) {
708
+ cleanupConnection(ws: FluxStackWebSocket) {
702
709
  if (!ws.data?.components) return
703
710
 
704
711
  const componentsToCleanup = Array.from(ws.data.components.keys()) as string[]
@@ -926,11 +933,11 @@ export class ComponentRegistry {
926
933
  try {
927
934
  console.log(`🔄 Migrating component ${componentId} from v${fromVersion} to v${toVersion}`)
928
935
 
929
- const oldState = component.getSerializableState()
936
+ const oldState = component.getSerializableState?.()
930
937
  const newState = migrationFn(oldState)
931
-
938
+
932
939
  // Update component state
933
- component.setState(newState)
940
+ component.setState?.(newState)
934
941
 
935
942
  // Record migration
936
943
  const migration: StateMigration = {
@@ -1006,7 +1013,7 @@ export class ComponentRegistry {
1006
1013
 
1007
1014
  if (component) {
1008
1015
  try {
1009
- component.destroy()
1016
+ component.destroy?.()
1010
1017
  } catch (error) {
1011
1018
  console.error(`❌ Error destroying component ${componentId}:`, error)
1012
1019
  }
@@ -8,7 +8,7 @@ import type {
8
8
  FileUploadCompleteMessage,
9
9
  FileUploadProgressResponse,
10
10
  FileUploadCompleteResponse
11
- } from '@/core/plugins/types'
11
+ } from '@core/types/types'
12
12
 
13
13
  export class FileUploadManager {
14
14
  private activeUploads = new Map<string, ActiveUpload>()
@@ -71,7 +71,7 @@ export class FileUploadManager {
71
71
  }
72
72
  }
73
73
 
74
- async receiveChunk(message: FileUploadChunkMessage, ws: any): Promise<FileUploadProgressResponse | null> {
74
+ async receiveChunk(message: FileUploadChunkMessage, ws: any, binaryData: Buffer | null = null): Promise<FileUploadProgressResponse | null> {
75
75
  try {
76
76
  const { uploadId, chunkIndex, totalChunks, data } = message
77
77
 
@@ -89,15 +89,23 @@ export class FileUploadManager {
89
89
  if (upload.receivedChunks.has(chunkIndex)) {
90
90
  console.log(`📦 Chunk ${chunkIndex} already received for upload ${uploadId}`)
91
91
  } else {
92
- // Store chunk data
93
- upload.receivedChunks.set(chunkIndex, data)
94
- upload.lastChunkTime = Date.now()
92
+ // Store chunk data - use binary data if available, otherwise use base64 string
93
+ let chunkBytes: number
94
+
95
+ if (binaryData) {
96
+ // Binary protocol: store Buffer directly (more efficient)
97
+ upload.receivedChunks.set(chunkIndex, binaryData)
98
+ chunkBytes = binaryData.length
99
+ } else {
100
+ // JSON protocol: store base64 string (legacy support)
101
+ upload.receivedChunks.set(chunkIndex, data as string)
102
+ chunkBytes = Buffer.from(data as string, 'base64').length
103
+ }
95
104
 
96
- // Track actual bytes received (decode base64 to get real size)
97
- const chunkBytes = Buffer.from(data, 'base64').length
105
+ upload.lastChunkTime = Date.now()
98
106
  upload.bytesReceived += chunkBytes
99
107
 
100
- console.log(`📦 Received chunk ${chunkIndex + 1}/${totalChunks} for upload ${uploadId} (${chunkBytes} bytes, total: ${upload.bytesReceived}/${upload.fileSize})`)
108
+ console.log(`📦 Received chunk ${chunkIndex + 1}/${totalChunks} for upload ${uploadId} (${chunkBytes} bytes, total: ${upload.bytesReceived}/${upload.fileSize})${binaryData ? ' [binary]' : ' [base64]'}`)
101
109
  }
102
110
 
103
111
  // Calculate progress based on actual bytes received (supports adaptive chunking)
@@ -213,7 +221,12 @@ export class FileUploadManager {
213
221
  for (let i = 0; i < upload.totalChunks; i++) {
214
222
  const chunkData = upload.receivedChunks.get(i)
215
223
  if (chunkData) {
216
- chunks.push(Buffer.from(chunkData, 'base64'))
224
+ // Handle both Buffer (binary protocol) and string (base64 JSON protocol)
225
+ if (Buffer.isBuffer(chunkData)) {
226
+ chunks.push(chunkData)
227
+ } else {
228
+ chunks.push(Buffer.from(chunkData, 'base64'))
229
+ }
217
230
  }
218
231
  }
219
232
 
@@ -266,4 +279,4 @@ export class FileUploadManager {
266
279
  }
267
280
 
268
281
  // Global instance
269
- export const fileUploadManager = new FileUploadManager()
282
+ export const fileUploadManager = new FileUploadManager()
@@ -136,7 +136,7 @@ export class LiveComponentPerformanceMonitor extends EventEmitter {
136
136
  private alerts = new Map<string, PerformanceAlert[]>() // componentId -> alerts
137
137
  private suggestions = new Map<string, OptimizationSuggestion[]>()
138
138
  private config: MonitoringConfig
139
- private dashboardUpdateInterval: NodeJS.Timeout
139
+ private dashboardUpdateInterval!: NodeJS.Timeout
140
140
  private alertCooldowns = new Map<string, number>() // alertType -> lastAlertTime
141
141
  private performanceObserver?: any
142
142
 
@@ -0,0 +1,261 @@
1
+ // 🔥 FluxStack Live Room Manager - Gerencia salas para LiveComponents
2
+
3
+ import { roomEvents } from './RoomEventBus'
4
+ import type { FluxStackWebSocket } from '@core/types/types'
5
+
6
+ export interface RoomMessage {
7
+ type: 'ROOM_JOIN' | 'ROOM_LEAVE' | 'ROOM_EMIT' | 'ROOM_STATE_SET' | 'ROOM_STATE_GET'
8
+ componentId: string
9
+ roomId: string
10
+ event?: string
11
+ data?: any
12
+ requestId?: string
13
+ timestamp: number
14
+ }
15
+
16
+ interface RoomMember {
17
+ componentId: string
18
+ ws: FluxStackWebSocket
19
+ joinedAt: number
20
+ }
21
+
22
+ interface Room<TState = any> {
23
+ id: string
24
+ state: TState
25
+ members: Map<string, RoomMember>
26
+ createdAt: number
27
+ lastActivity: number
28
+ }
29
+
30
+ class LiveRoomManager {
31
+ private rooms = new Map<string, Room>()
32
+ private componentRooms = new Map<string, Set<string>>() // componentId -> roomIds
33
+
34
+ /**
35
+ * Componente entra em uma sala
36
+ */
37
+ joinRoom<TState = any>(componentId: string, roomId: string, ws: FluxStackWebSocket, initialState?: TState): { state: TState } {
38
+ // Criar sala se não existir
39
+ if (!this.rooms.has(roomId)) {
40
+ this.rooms.set(roomId, {
41
+ id: roomId,
42
+ state: initialState || {},
43
+ members: new Map(),
44
+ createdAt: Date.now(),
45
+ lastActivity: Date.now()
46
+ })
47
+ console.log(`🏠 Room '${roomId}' created`)
48
+ }
49
+
50
+ const room = this.rooms.get(roomId)!
51
+
52
+ // Adicionar membro
53
+ room.members.set(componentId, {
54
+ componentId,
55
+ ws,
56
+ joinedAt: Date.now()
57
+ })
58
+ room.lastActivity = Date.now()
59
+
60
+ // Rastrear salas do componente
61
+ if (!this.componentRooms.has(componentId)) {
62
+ this.componentRooms.set(componentId, new Set())
63
+ }
64
+ this.componentRooms.get(componentId)!.add(roomId)
65
+
66
+ console.log(`👋 Component '${componentId}' joined room '${roomId}' (${room.members.size} members)`)
67
+
68
+ // Notificar outros membros
69
+ this.broadcastToRoom(roomId, {
70
+ type: 'ROOM_SYSTEM',
71
+ componentId,
72
+ roomId,
73
+ event: '$sub:join',
74
+ data: {
75
+ subscriberId: componentId,
76
+ count: room.members.size
77
+ },
78
+ timestamp: Date.now()
79
+ }, componentId)
80
+
81
+ return { state: room.state }
82
+ }
83
+
84
+ /**
85
+ * Componente sai de uma sala
86
+ */
87
+ leaveRoom(componentId: string, roomId: string): void {
88
+ const room = this.rooms.get(roomId)
89
+ if (!room) return
90
+
91
+ // Remover membro
92
+ room.members.delete(componentId)
93
+ room.lastActivity = Date.now()
94
+
95
+ // Remover do rastreamento
96
+ this.componentRooms.get(componentId)?.delete(roomId)
97
+
98
+ console.log(`🚶 Component '${componentId}' left room '${roomId}' (${room.members.size} members)`)
99
+
100
+ // Notificar outros membros
101
+ this.broadcastToRoom(roomId, {
102
+ type: 'ROOM_SYSTEM',
103
+ componentId,
104
+ roomId,
105
+ event: '$sub:leave',
106
+ data: {
107
+ subscriberId: componentId,
108
+ count: room.members.size
109
+ },
110
+ timestamp: Date.now()
111
+ })
112
+
113
+ // Cleanup sala vazia após delay
114
+ if (room.members.size === 0) {
115
+ setTimeout(() => {
116
+ const currentRoom = this.rooms.get(roomId)
117
+ if (currentRoom && currentRoom.members.size === 0) {
118
+ this.rooms.delete(roomId)
119
+ console.log(`🗑️ Room '${roomId}' destroyed (empty)`)
120
+ }
121
+ }, 5 * 60 * 1000) // 5 minutos
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Componente desconecta - sai de todas as salas
127
+ */
128
+ cleanupComponent(componentId: string): void {
129
+ const rooms = this.componentRooms.get(componentId)
130
+ if (!rooms) return
131
+
132
+ for (const roomId of rooms) {
133
+ this.leaveRoom(componentId, roomId)
134
+ }
135
+
136
+ this.componentRooms.delete(componentId)
137
+ }
138
+
139
+ /**
140
+ * Emitir evento para todos na sala
141
+ * - Envia via WebSocket para frontends dos outros membros
142
+ * - Também dispara eventos no RoomEventBus para handlers server-side
143
+ */
144
+ emitToRoom(roomId: string, event: string, data: any, excludeComponentId?: string): number {
145
+ const room = this.rooms.get(roomId)
146
+ if (!room) return 0
147
+
148
+ room.lastActivity = Date.now()
149
+
150
+ // 1. Emitir no RoomEventBus para handlers server-side (outros LiveComponents)
151
+ // Isso permite que componentes do servidor reajam a eventos de outros componentes
152
+ // Usa 'room' como tipo genérico (mesmo usado em $room.on)
153
+ roomEvents.emit('room', roomId, event, data, excludeComponentId)
154
+
155
+ // 2. Broadcast via WebSocket para frontends
156
+ return this.broadcastToRoom(roomId, {
157
+ type: 'ROOM_EVENT',
158
+ componentId: '',
159
+ roomId,
160
+ event,
161
+ data,
162
+ timestamp: Date.now()
163
+ }, excludeComponentId)
164
+ }
165
+
166
+ /**
167
+ * Atualizar estado da sala
168
+ */
169
+ setRoomState(roomId: string, updates: any, excludeComponentId?: string): void {
170
+ const room = this.rooms.get(roomId)
171
+ if (!room) return
172
+
173
+ // Merge estado
174
+ room.state = { ...room.state, ...updates }
175
+ room.lastActivity = Date.now()
176
+
177
+ // Notificar todos os membros
178
+ this.broadcastToRoom(roomId, {
179
+ type: 'ROOM_STATE',
180
+ componentId: '',
181
+ roomId,
182
+ event: '$state:update',
183
+ data: { state: updates },
184
+ timestamp: Date.now()
185
+ }, excludeComponentId)
186
+ }
187
+
188
+ /**
189
+ * Obter estado da sala
190
+ */
191
+ getRoomState<TState = any>(roomId: string): TState {
192
+ return (this.rooms.get(roomId)?.state || {}) as TState
193
+ }
194
+
195
+ /**
196
+ * Broadcast para todos os membros da sala
197
+ */
198
+ private broadcastToRoom(roomId: string, message: any, excludeComponentId?: string): number {
199
+ const room = this.rooms.get(roomId)
200
+ if (!room) return 0
201
+
202
+ let sent = 0
203
+ for (const [componentId, member] of room.members) {
204
+ if (excludeComponentId && componentId === excludeComponentId) continue
205
+
206
+ try {
207
+ if (member.ws && member.ws.readyState === 1) {
208
+ member.ws.send(JSON.stringify({
209
+ ...message,
210
+ componentId
211
+ }))
212
+ sent++
213
+ }
214
+ } catch (error) {
215
+ console.error(`Failed to send to ${componentId}:`, error)
216
+ }
217
+ }
218
+
219
+ return sent
220
+ }
221
+
222
+ /**
223
+ * Verificar se componente está em uma sala
224
+ */
225
+ isInRoom(componentId: string, roomId: string): boolean {
226
+ return this.rooms.get(roomId)?.members.has(componentId) ?? false
227
+ }
228
+
229
+ /**
230
+ * Obter salas de um componente
231
+ */
232
+ getComponentRooms(componentId: string): string[] {
233
+ return Array.from(this.componentRooms.get(componentId) || [])
234
+ }
235
+
236
+ /**
237
+ * Estatísticas
238
+ */
239
+ getStats(): {
240
+ totalRooms: number
241
+ rooms: Record<string, { members: number; createdAt: number; lastActivity: number }>
242
+ } {
243
+ const rooms: Record<string, { members: number; createdAt: number; lastActivity: number }> = {}
244
+
245
+ for (const [id, room] of this.rooms) {
246
+ rooms[id] = {
247
+ members: room.members.size,
248
+ createdAt: room.createdAt,
249
+ lastActivity: room.lastActivity
250
+ }
251
+ }
252
+
253
+ return {
254
+ totalRooms: this.rooms.size,
255
+ rooms
256
+ }
257
+ }
258
+ }
259
+
260
+ export const liveRoomManager = new LiveRoomManager()
261
+ export type { Room, RoomMember }