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
@@ -1,108 +1,108 @@
1
- /**
2
- * Plugin system types
3
- * Comprehensive type definitions for the plugin system
4
- */
5
-
6
- // Import namespace for type alias
7
- import type { FluxStack } from "../plugins/types"
8
-
9
- // Re-export plugin types
10
- export type {
11
- FluxStack,
12
- PluginContext,
13
- PluginUtils,
14
- RequestContext,
15
- ResponseContext,
16
- ErrorContext,
17
- BuildContext,
18
- ConfigLoadContext,
19
- RouteContext,
20
- ValidationContext,
21
- TransformContext,
22
- BuildAssetContext,
23
- BuildErrorContext,
24
- PluginEventContext
25
- } from "../plugins/types"
26
-
27
- // Export Plugin as a standalone type for convenience
28
- export type Plugin = FluxStack.Plugin
29
-
30
- // Additional plugin-related types
31
- export interface PluginManifest {
32
- name: string
33
- version: string
34
- description: string
35
- author: string
36
- license: string
37
- homepage?: string
38
- repository?: string
39
- keywords: string[]
40
- dependencies: Record<string, string>
41
- peerDependencies?: Record<string, string>
42
- fluxstack: {
43
- version: string
44
- hooks: string[]
45
- config?: any
46
- }
47
- }
48
-
49
- export interface PluginLoadResult {
50
- success: boolean
51
- plugin?: Plugin
52
- error?: string
53
- warnings?: string[]
54
- }
55
-
56
- export interface PluginRegistryState {
57
- plugins: Map<string, Plugin>
58
- loadOrder: string[]
59
- dependencies: Map<string, string[]>
60
- conflicts: string[]
61
- }
62
-
63
- export interface PluginHookResult {
64
- success: boolean
65
- error?: Error
66
- duration: number
67
- plugin: string
68
- hook: string
69
- }
70
-
71
- export interface PluginMetrics {
72
- loadTime: number
73
- setupTime: number
74
- hookExecutions: Map<string, number>
75
- errors: number
76
- warnings: number
77
- }
78
-
79
- export type PluginHook =
80
- | 'setup'
81
- | 'onServerStart'
82
- | 'onServerStop'
83
- | 'onRequest'
84
- | 'onResponse'
85
- | 'onError'
86
-
87
- export type PluginPriority = 'highest' | 'high' | 'normal' | 'low' | 'lowest' | number
88
-
89
- export interface PluginConfigSchema {
90
- type: 'object'
91
- properties: Record<string, any>
92
- required?: string[]
93
- additionalProperties?: boolean
94
- }
95
-
96
- export interface PluginDiscoveryOptions {
97
- directories?: string[]
98
- patterns?: string[]
99
- includeBuiltIn?: boolean
100
- includeExternal?: boolean
101
- }
102
-
103
- export interface PluginInstallOptions {
104
- version?: string
105
- registry?: string
106
- force?: boolean
107
- dev?: boolean
1
+ /**
2
+ * Plugin system types
3
+ * Comprehensive type definitions for the plugin system
4
+ */
5
+
6
+ // Import namespace for type alias
7
+ import type { FluxStack } from "../plugins/types"
8
+
9
+ // Re-export plugin types
10
+ export type {
11
+ FluxStack,
12
+ PluginContext,
13
+ PluginUtils,
14
+ RequestContext,
15
+ ResponseContext,
16
+ ErrorContext,
17
+ BuildContext,
18
+ ConfigLoadContext,
19
+ RouteContext,
20
+ ValidationContext,
21
+ TransformContext,
22
+ BuildAssetContext,
23
+ BuildErrorContext,
24
+ PluginEventContext
25
+ } from "../plugins/types"
26
+
27
+ // Export Plugin as a standalone type for convenience
28
+ export type Plugin = FluxStack.Plugin
29
+
30
+ // Additional plugin-related types
31
+ export interface PluginManifest {
32
+ name: string
33
+ version: string
34
+ description: string
35
+ author: string
36
+ license: string
37
+ homepage?: string
38
+ repository?: string
39
+ keywords: string[]
40
+ dependencies: Record<string, string>
41
+ peerDependencies?: Record<string, string>
42
+ fluxstack: {
43
+ version: string
44
+ hooks: string[]
45
+ config?: any
46
+ }
47
+ }
48
+
49
+ export interface PluginLoadResult {
50
+ success: boolean
51
+ plugin?: Plugin
52
+ error?: string
53
+ warnings?: string[]
54
+ }
55
+
56
+ export interface PluginRegistryState {
57
+ plugins: Map<string, Plugin>
58
+ loadOrder: string[]
59
+ dependencies: Map<string, string[]>
60
+ conflicts: string[]
61
+ }
62
+
63
+ export interface PluginHookResult {
64
+ success: boolean
65
+ error?: Error
66
+ duration: number
67
+ plugin: string
68
+ hook: string
69
+ }
70
+
71
+ export interface PluginMetrics {
72
+ loadTime: number
73
+ setupTime: number
74
+ hookExecutions: Map<string, number>
75
+ errors: number
76
+ warnings: number
77
+ }
78
+
79
+ export type PluginHook =
80
+ | 'setup'
81
+ | 'onServerStart'
82
+ | 'onServerStop'
83
+ | 'onRequest'
84
+ | 'onResponse'
85
+ | 'onError'
86
+
87
+ export type PluginPriority = 'highest' | 'high' | 'normal' | 'low' | 'lowest' | number
88
+
89
+ export interface PluginConfigSchema {
90
+ type: 'object'
91
+ properties: Record<string, any>
92
+ required?: string[]
93
+ additionalProperties?: boolean
94
+ }
95
+
96
+ export interface PluginDiscoveryOptions {
97
+ directories?: string[]
98
+ patterns?: string[]
99
+ includeBuiltIn?: boolean
100
+ includeExternal?: boolean
101
+ }
102
+
103
+ export interface PluginInstallOptions {
104
+ version?: string
105
+ registry?: string
106
+ force?: boolean
107
+ dev?: boolean
108
108
  }
@@ -1,11 +1,56 @@
1
1
  // 🔥 FluxStack Live Components - Shared Types
2
2
 
3
+ import { roomEvents } from '@core/server/live/RoomEventBus'
4
+ import { liveRoomManager } from '@core/server/live/LiveRoomManager'
5
+ import type { ServerWebSocket } from 'bun'
6
+
7
+ // ============================================
8
+ // 🔌 WebSocket Types for Server-Side
9
+ // ============================================
10
+
11
+ /**
12
+ * WebSocket data stored on each connection
13
+ * This is attached to ws.data by the WebSocket plugin
14
+ */
15
+ export interface FluxStackWSData {
16
+ connectionId: string
17
+ components: Map<string, LiveComponent>
18
+ subscriptions: Set<string>
19
+ connectedAt: Date
20
+ userId?: string
21
+ }
22
+
23
+ /**
24
+ * Type-safe WebSocket interface for FluxStack Live Components
25
+ * Compatible with both Elysia's ElysiaWS and Bun's ServerWebSocket
26
+ */
27
+ export interface FluxStackWebSocket {
28
+ /** Send data to the client */
29
+ send(data: string | BufferSource, compress?: boolean): number
30
+ /** Close the connection */
31
+ close(code?: number, reason?: string): void
32
+ /** Connection data storage */
33
+ data: FluxStackWSData
34
+ /** Remote address of the client */
35
+ readonly remoteAddress: string
36
+ /** Current ready state */
37
+ readonly readyState: 0 | 1 | 2 | 3
38
+ }
39
+
40
+ /**
41
+ * Raw ServerWebSocket from Bun with FluxStack data
42
+ * Use this when you need access to all Bun WebSocket methods
43
+ */
44
+ export type FluxStackServerWebSocket = ServerWebSocket<FluxStackWSData>
45
+
3
46
  export interface LiveMessage {
4
47
  type: 'COMPONENT_MOUNT' | 'COMPONENT_UNMOUNT' |
5
48
  'COMPONENT_REHYDRATE' | 'COMPONENT_ACTION' | 'CALL_ACTION' |
6
49
  'ACTION_RESPONSE' | 'PROPERTY_UPDATE' | 'STATE_UPDATE' | 'STATE_REHYDRATED' |
7
50
  'ERROR' | 'BROADCAST' | 'FILE_UPLOAD_START' | 'FILE_UPLOAD_CHUNK' | 'FILE_UPLOAD_COMPLETE' |
8
- 'COMPONENT_PING' | 'COMPONENT_PONG'
51
+ 'COMPONENT_PING' | 'COMPONENT_PONG' |
52
+ // Room system messages
53
+ 'ROOM_JOIN' | 'ROOM_LEAVE' | 'ROOM_EMIT' | 'ROOM_STATE_SET' | 'ROOM_STATE_GET'
9
54
  componentId: string
10
55
  action?: string
11
56
  property?: string
@@ -34,6 +79,9 @@ export interface LiveComponentInstance<TState = ComponentState, TActions = Recor
34
79
  room?: string
35
80
  }
36
81
 
82
+ /**
83
+ * @deprecated Use FluxStackWSData instead
84
+ */
37
85
  export interface WebSocketData {
38
86
  components: Map<string, any>
39
87
  userId?: string
@@ -43,7 +91,7 @@ export interface WebSocketData {
43
91
  export interface ComponentDefinition<TState = ComponentState> {
44
92
  name: string
45
93
  initialState: TState
46
- component: new (initialState: TState, ws: any) => LiveComponent<TState>
94
+ component: new (initialState: TState, ws: FluxStackWebSocket, options?: { room?: string; userId?: string }) => LiveComponent<TState>
47
95
  }
48
96
 
49
97
  export interface BroadcastMessage {
@@ -69,7 +117,9 @@ export interface WebSocketMessage {
69
117
  }
70
118
 
71
119
  export interface WebSocketResponse {
72
- type: 'MESSAGE_RESPONSE' | 'CONNECTION_ESTABLISHED' | 'ERROR' | 'BROADCAST' | 'ACTION_RESPONSE' | 'COMPONENT_MOUNTED' | 'COMPONENT_REHYDRATED' | 'STATE_UPDATE' | 'STATE_REHYDRATED' | 'FILE_UPLOAD_PROGRESS' | 'FILE_UPLOAD_COMPLETE' | 'FILE_UPLOAD_ERROR' | 'FILE_UPLOAD_START_RESPONSE' | 'COMPONENT_PONG'
120
+ type: 'MESSAGE_RESPONSE' | 'CONNECTION_ESTABLISHED' | 'ERROR' | 'BROADCAST' | 'ACTION_RESPONSE' | 'COMPONENT_MOUNTED' | 'COMPONENT_REHYDRATED' | 'STATE_UPDATE' | 'STATE_REHYDRATED' | 'FILE_UPLOAD_PROGRESS' | 'FILE_UPLOAD_COMPLETE' | 'FILE_UPLOAD_ERROR' | 'FILE_UPLOAD_START_RESPONSE' | 'COMPONENT_PONG' |
121
+ // Room system responses
122
+ 'ROOM_EVENT' | 'ROOM_STATE' | 'ROOM_SYSTEM' | 'ROOM_JOINED' | 'ROOM_LEFT'
73
123
  originalType?: string
74
124
  componentId?: string
75
125
  success?: boolean
@@ -135,27 +185,214 @@ export interface HybridComponentOptions {
135
185
  onStateChange?: (newState: any, oldState: any) => void
136
186
  }
137
187
 
188
+ // Interface para handle de sala no servidor
189
+ export interface ServerRoomHandle<TState = any, TEvents extends Record<string, any> = Record<string, any>> {
190
+ readonly id: string
191
+ readonly state: TState
192
+ join: (initialState?: TState) => void
193
+ leave: () => void
194
+ emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => number
195
+ on: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => () => void
196
+ setState: (updates: Partial<TState>) => void
197
+ }
198
+
199
+ // Proxy para $room no servidor
200
+ export interface ServerRoomProxy<TState = any, TEvents extends Record<string, any> = Record<string, any>> {
201
+ (roomId: string): ServerRoomHandle<TState, TEvents>
202
+ readonly id: string | undefined
203
+ readonly state: TState
204
+ join: (initialState?: TState) => void
205
+ leave: () => void
206
+ emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => number
207
+ on: <K extends keyof TEvents>(event: K, handler: (data: TEvents[K]) => void) => () => void
208
+ setState: (updates: Partial<TState>) => void
209
+ }
210
+
138
211
  export abstract class LiveComponent<TState = ComponentState> {
212
+ /** Component name for registry lookup - must be defined in subclasses */
213
+ static componentName: string
214
+ /** Default state - must be defined in subclasses */
215
+ static defaultState: any
216
+
139
217
  public readonly id: string
140
- public state: TState
141
- protected ws: any
218
+ private _state: TState
219
+ public state: TState // Proxy wrapper
220
+ protected ws: FluxStackWebSocket
142
221
  public room?: string
143
222
  public userId?: string
144
223
  public broadcastToRoom: (message: BroadcastMessage) => void = () => {} // Will be injected by registry
145
224
 
146
- constructor(initialState: TState, ws: any, options?: { room?: string; userId?: string }) {
225
+ // Room event subscriptions (cleaned up on destroy)
226
+ private roomEventUnsubscribers: (() => void)[] = []
227
+ private joinedRooms: Set<string> = new Set()
228
+
229
+ // Room type for typed events (override in subclass)
230
+ protected roomType: string = 'default'
231
+
232
+ // Cached room handles
233
+ private roomHandles: Map<string, ServerRoomHandle> = new Map()
234
+
235
+ constructor(initialState: Partial<TState>, ws: FluxStackWebSocket, options?: { room?: string; userId?: string }) {
147
236
  this.id = this.generateId()
148
- this.state = initialState
237
+ // Merge defaultState with initialState - subclass defaultState takes precedence for missing fields
238
+ const ctor = this.constructor as typeof LiveComponent
239
+ this._state = { ...ctor.defaultState, ...initialState } as TState
240
+
241
+ // Create reactive proxy that auto-syncs on mutation
242
+ this.state = this.createStateProxy(this._state)
243
+
149
244
  this.ws = ws
150
245
  this.room = options?.room
151
246
  this.userId = options?.userId
247
+
248
+ // Auto-join default room if specified
249
+ if (this.room) {
250
+ this.joinedRooms.add(this.room)
251
+ liveRoomManager.joinRoom(this.id, this.room, this.ws)
252
+ }
253
+ }
254
+
255
+ // Create a Proxy that auto-emits STATE_UPDATE on any mutation
256
+ private createStateProxy(state: TState): TState {
257
+ const self = this
258
+ return new Proxy(state as object, {
259
+ set(target, prop, value) {
260
+ const oldValue = (target as any)[prop]
261
+ if (oldValue !== value) {
262
+ (target as any)[prop] = value
263
+ // Auto-sync to frontend
264
+ self.emit('STATE_UPDATE', { state: self._state })
265
+ }
266
+ return true
267
+ },
268
+ get(target, prop) {
269
+ return (target as any)[prop]
270
+ }
271
+ }) as TState
272
+ }
273
+
274
+ // ========================================
275
+ // 🔥 $room - Sistema de Salas Unificado
276
+ // ========================================
277
+
278
+ /**
279
+ * Acessa uma sala específica ou a sala padrão
280
+ * @example
281
+ * // Sala padrão
282
+ * this.$room.emit('typing', { user: 'João' })
283
+ * this.$room.on('message:new', handler)
284
+ *
285
+ * // Outra sala
286
+ * this.$room('sala-vip').join()
287
+ * this.$room('sala-vip').emit('typing', { user: 'João' })
288
+ */
289
+ public get $room(): ServerRoomProxy {
290
+ const self = this
291
+
292
+ const createHandle = (roomId: string): ServerRoomHandle => {
293
+ // Retornar handle cacheado
294
+ if (this.roomHandles.has(roomId)) {
295
+ return this.roomHandles.get(roomId)!
296
+ }
297
+
298
+ const handle: ServerRoomHandle = {
299
+ get id() { return roomId },
300
+ get state() { return liveRoomManager.getRoomState(roomId) },
301
+
302
+ join: (initialState?: any) => {
303
+ if (self.joinedRooms.has(roomId)) return
304
+ self.joinedRooms.add(roomId)
305
+ liveRoomManager.joinRoom(self.id, roomId, self.ws, initialState)
306
+ },
307
+
308
+ leave: () => {
309
+ if (!self.joinedRooms.has(roomId)) return
310
+ self.joinedRooms.delete(roomId)
311
+ liveRoomManager.leaveRoom(self.id, roomId)
312
+ },
313
+
314
+ emit: (event: string, data: any): number => {
315
+ return liveRoomManager.emitToRoom(roomId, event, data, self.id)
316
+ },
317
+
318
+ on: (event: string, handler: (data: any) => void): (() => void) => {
319
+ // Usar 'room' como tipo genérico e roomId como identificador
320
+ // Isso permite que emitToRoom encontre os handlers corretamente
321
+ const unsubscribe = roomEvents.on(
322
+ 'room', // Tipo genérico para todas as salas
323
+ roomId,
324
+ event,
325
+ self.id,
326
+ handler
327
+ )
328
+ self.roomEventUnsubscribers.push(unsubscribe)
329
+ return unsubscribe
330
+ },
331
+
332
+ setState: (updates: any) => {
333
+ liveRoomManager.setRoomState(roomId, updates, self.id)
334
+ }
335
+ }
336
+
337
+ this.roomHandles.set(roomId, handle)
338
+ return handle
339
+ }
340
+
341
+ // Criar proxy que funciona como função e objeto
342
+ const proxyFn = ((roomId: string) => createHandle(roomId)) as ServerRoomProxy
343
+
344
+ const defaultHandle = this.room ? createHandle(this.room) : null
345
+
346
+ Object.defineProperties(proxyFn, {
347
+ id: { get: () => self.room },
348
+ state: { get: () => defaultHandle?.state ?? {} },
349
+ join: {
350
+ value: (initialState?: any) => {
351
+ if (!defaultHandle) throw new Error('No default room set')
352
+ defaultHandle.join(initialState)
353
+ }
354
+ },
355
+ leave: {
356
+ value: () => {
357
+ if (!defaultHandle) throw new Error('No default room set')
358
+ defaultHandle.leave()
359
+ }
360
+ },
361
+ emit: {
362
+ value: (event: string, data: any) => {
363
+ if (!defaultHandle) throw new Error('No default room set')
364
+ return defaultHandle.emit(event, data)
365
+ }
366
+ },
367
+ on: {
368
+ value: (event: string, handler: (data: any) => void) => {
369
+ if (!defaultHandle) throw new Error('No default room set')
370
+ return defaultHandle.on(event, handler)
371
+ }
372
+ },
373
+ setState: {
374
+ value: (updates: any) => {
375
+ if (!defaultHandle) throw new Error('No default room set')
376
+ defaultHandle.setState(updates)
377
+ }
378
+ }
379
+ })
380
+
381
+ return proxyFn
382
+ }
383
+
384
+ /**
385
+ * Lista de IDs das salas que este componente está participando
386
+ */
387
+ public get $rooms(): string[] {
388
+ return Array.from(this.joinedRooms)
152
389
  }
153
390
 
154
- // State management
391
+ // State management (batch update - single emit)
155
392
  public setState(updates: Partial<TState> | ((prev: TState) => Partial<TState>)) {
156
- const newUpdates = typeof updates === 'function' ? updates(this.state) : updates
157
- this.state = { ...this.state, ...newUpdates }
158
- this.emit('STATE_UPDATE', { state: this.state })
393
+ const newUpdates = typeof updates === 'function' ? updates(this._state) : updates
394
+ Object.assign(this._state as object, newUpdates)
395
+ this.emit('STATE_UPDATE', { state: this._state })
159
396
  }
160
397
 
161
398
  // Generic setValue action - set any state key with type safety
@@ -204,8 +441,13 @@ export abstract class LiveComponent<TState = ComponentState> {
204
441
  }
205
442
  }
206
443
 
207
- // Broadcast to all clients in room
444
+ // Broadcast to all clients in room (via WebSocket)
208
445
  protected broadcast(type: string, payload: any, excludeCurrentUser = false) {
446
+ if (!this.room) {
447
+ console.warn(`⚠️ [${this.id}] Cannot broadcast '${type}' - no room set`)
448
+ return
449
+ }
450
+
209
451
  const message: BroadcastMessage = {
210
452
  type,
211
453
  payload,
@@ -213,10 +455,84 @@ export abstract class LiveComponent<TState = ComponentState> {
213
455
  excludeUser: excludeCurrentUser ? this.userId : undefined
214
456
  }
215
457
 
458
+ console.log(`📤 [${this.id}] Broadcasting '${type}' to room '${this.room}'`)
459
+
216
460
  // This will be handled by the registry
217
461
  this.broadcastToRoom(message)
218
462
  }
219
463
 
464
+ // ========================================
465
+ // 🔥 Room Events - Internal Server Events
466
+ // ========================================
467
+
468
+ /**
469
+ * Emite um evento para todos os componentes da sala (server-side)
470
+ * Cada componente inscrito pode reagir e atualizar seu próprio cliente
471
+ *
472
+ * @param event - Nome do evento
473
+ * @param data - Dados do evento
474
+ * @param notifySelf - Se true, este componente também recebe (default: false)
475
+ */
476
+ protected emitRoomEvent(event: string, data: any, notifySelf = false): number {
477
+ if (!this.room) {
478
+ console.warn(`⚠️ [${this.id}] Cannot emit room event '${event}' - no room set`)
479
+ return 0
480
+ }
481
+
482
+ const excludeId = notifySelf ? undefined : this.id
483
+ const notified = roomEvents.emit(this.roomType, this.room, event, data, excludeId)
484
+
485
+ console.log(`📡 [${this.id}] Room event '${event}' → ${notified} components`)
486
+ return notified
487
+ }
488
+
489
+ /**
490
+ * Inscreve este componente em um evento da sala
491
+ * Handler é chamado quando outro componente emite o evento
492
+ *
493
+ * @param event - Nome do evento para escutar
494
+ * @param handler - Função chamada quando evento é recebido
495
+ */
496
+ protected onRoomEvent<T = any>(event: string, handler: (data: T) => void): void {
497
+ if (!this.room) {
498
+ console.warn(`⚠️ [${this.id}] Cannot subscribe to room event '${event}' - no room set`)
499
+ return
500
+ }
501
+
502
+ const unsubscribe = roomEvents.on(
503
+ this.roomType,
504
+ this.room,
505
+ event,
506
+ this.id,
507
+ handler
508
+ )
509
+
510
+ // Guardar para cleanup no destroy
511
+ this.roomEventUnsubscribers.push(unsubscribe)
512
+
513
+ console.log(`👂 [${this.id}] Subscribed to room event '${event}'`)
514
+ }
515
+
516
+ /**
517
+ * Helper: Emite evento E atualiza estado local + envia pro cliente
518
+ * Útil para o componente que origina a ação
519
+ *
520
+ * @param event - Nome do evento
521
+ * @param data - Dados do evento
522
+ * @param stateUpdates - Atualizações de estado para aplicar localmente
523
+ */
524
+ protected emitRoomEventWithState(
525
+ event: string,
526
+ data: any,
527
+ stateUpdates: Partial<TState>
528
+ ): number {
529
+ // 1. Atualiza estado local (envia pro cliente deste componente)
530
+ this.setState(stateUpdates)
531
+
532
+ // 2. Emite evento para outros componentes da sala
533
+ return this.emitRoomEvent(event, data, false)
534
+ }
535
+
220
536
  // Subscribe to room for multi-user features
221
537
  protected async subscribeToRoom(roomId: string) {
222
538
  this.room = roomId
@@ -236,6 +552,19 @@ export abstract class LiveComponent<TState = ComponentState> {
236
552
 
237
553
  // Cleanup when component is destroyed
238
554
  public destroy() {
555
+ // Limpa todas as inscrições de room events
556
+ for (const unsubscribe of this.roomEventUnsubscribers) {
557
+ unsubscribe()
558
+ }
559
+ this.roomEventUnsubscribers = []
560
+
561
+ // Sai de todas as salas
562
+ for (const roomId of this.joinedRooms) {
563
+ liveRoomManager.leaveRoom(this.id, roomId)
564
+ }
565
+ this.joinedRooms.clear()
566
+ this.roomHandles.clear()
567
+
239
568
  this.unsubscribeFromRoom()
240
569
  // Override in subclasses for custom cleanup
241
570
  }
@@ -407,11 +736,21 @@ export interface FileUploadChunkMessage {
407
736
  uploadId: string
408
737
  chunkIndex: number
409
738
  totalChunks: number
410
- data: string // Base64 encoded chunk
739
+ data: string | Buffer // Base64 string (JSON) or Buffer (binary protocol)
411
740
  hash?: string
412
741
  requestId?: string
413
742
  }
414
743
 
744
+ // Binary protocol header for chunk uploads
745
+ export interface BinaryChunkHeader {
746
+ type: 'FILE_UPLOAD_CHUNK'
747
+ componentId: string
748
+ uploadId: string
749
+ chunkIndex: number
750
+ totalChunks: number
751
+ requestId?: string
752
+ }
753
+
415
754
  export interface FileUploadCompleteMessage {
416
755
  type: 'FILE_UPLOAD_COMPLETE'
417
756
  componentId: string
@@ -452,7 +791,7 @@ export interface ActiveUpload {
452
791
  fileType: string
453
792
  fileSize: number
454
793
  totalChunks: number
455
- receivedChunks: Map<number, string>
794
+ receivedChunks: Map<number, string | Buffer> // Base64 string or raw Buffer (binary protocol)
456
795
  bytesReceived: number // Track actual bytes received for adaptive chunking
457
796
  startTime: number
458
797
  lastChunkTime: number