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,463 @@
1
+ // 🔥 FluxStack Room System - Pub/Sub tipado para comunicação entre componentes
2
+
3
+ type EventHandler<T = any> = (data: T) => void
4
+ type Unsubscribe = () => void
5
+
6
+ // Eventos do sistema (prefixo $)
7
+ export type SystemEvents<TState> = {
8
+ '$room:created': { roomId: string; createdAt: number; initialState: TState }
9
+ '$room:destroyed': { roomId: string; reason: 'manual' | 'empty' | 'ttl'; finalState: TState }
10
+ '$sub:join': { subscriberId: string; event: string; count: number }
11
+ '$sub:leave': { subscriberId: string; event: string; count: number }
12
+ '$state:change': { path?: string; oldValue: any; newValue: any }
13
+ '$state:reset': { oldState: TState; newState: TState }
14
+ '$error': { error: Error; context: string }
15
+ }
16
+
17
+ // Combina eventos do usuário + sistema
18
+ type AllEvents<TState, TUserEvents> = TUserEvents & SystemEvents<TState>
19
+
20
+ // Subscription info
21
+ interface Subscription {
22
+ id: string
23
+ event: string
24
+ handler: EventHandler
25
+ }
26
+
27
+ // Room instance
28
+ export class Room<TState, TEvents extends Record<string, any>> {
29
+ public readonly id: string
30
+ public readonly createdAt: number
31
+
32
+ private _state: TState
33
+ private subscriptions = new Map<string, Set<Subscription>>()
34
+ private subscriberCounter = new Map<string, number>() // event -> count
35
+ private nextSubId = 0
36
+ private destroyed = false
37
+
38
+ // Callback para notificar o sistema global
39
+ private onSystemEvent?: (event: string, data: any) => void
40
+
41
+ constructor(
42
+ id: string,
43
+ initialState: TState,
44
+ onSystemEvent?: (event: string, data: any) => void
45
+ ) {
46
+ this.id = id
47
+ this.createdAt = Date.now()
48
+ this._state = structuredClone(initialState)
49
+ this.onSystemEvent = onSystemEvent
50
+ }
51
+
52
+ // ============================================
53
+ // Estado
54
+ // ============================================
55
+
56
+ get state(): Readonly<TState> {
57
+ return this._state
58
+ }
59
+
60
+ setState(partial: Partial<TState>): void {
61
+ this.checkDestroyed()
62
+ const oldState = this._state
63
+ this._state = { ...this._state, ...partial }
64
+
65
+ // Emitir evento de mudança para cada campo alterado
66
+ for (const key of Object.keys(partial) as (keyof TState)[]) {
67
+ if (oldState[key] !== partial[key]) {
68
+ this.emitSystem('$state:change', {
69
+ path: key as string,
70
+ oldValue: oldState[key],
71
+ newValue: partial[key]
72
+ })
73
+ }
74
+ }
75
+ }
76
+
77
+ updateState(updater: (prev: TState) => Partial<TState>): void {
78
+ this.checkDestroyed()
79
+ const updates = updater(this._state)
80
+ this.setState(updates)
81
+ }
82
+
83
+ resetState(newState: TState): void {
84
+ this.checkDestroyed()
85
+ const oldState = this._state
86
+ this._state = structuredClone(newState)
87
+
88
+ this.emitSystem('$state:reset', { oldState, newState })
89
+ }
90
+
91
+ // ============================================
92
+ // Eventos do usuário
93
+ // ============================================
94
+
95
+ on<K extends keyof AllEvents<TState, TEvents>>(
96
+ event: K,
97
+ handler: EventHandler<AllEvents<TState, TEvents>[K]>
98
+ ): Unsubscribe {
99
+ this.checkDestroyed()
100
+
101
+ const eventKey = event as string
102
+
103
+ if (!this.subscriptions.has(eventKey)) {
104
+ this.subscriptions.set(eventKey, new Set())
105
+ this.subscriberCounter.set(eventKey, 0)
106
+ }
107
+
108
+ const subId = `sub-${++this.nextSubId}`
109
+ const subscription: Subscription = {
110
+ id: subId,
111
+ event: eventKey,
112
+ handler
113
+ }
114
+
115
+ this.subscriptions.get(eventKey)!.add(subscription)
116
+ const count = (this.subscriberCounter.get(eventKey) || 0) + 1
117
+ this.subscriberCounter.set(eventKey, count)
118
+
119
+ // Emitir evento de sistema (só para eventos não-sistema)
120
+ if (!eventKey.startsWith('$')) {
121
+ this.emitSystem('$sub:join', {
122
+ subscriberId: subId,
123
+ event: eventKey,
124
+ count
125
+ })
126
+ }
127
+
128
+ return () => {
129
+ const subs = this.subscriptions.get(eventKey)
130
+ if (subs) {
131
+ subs.delete(subscription)
132
+ const newCount = Math.max(0, (this.subscriberCounter.get(eventKey) || 1) - 1)
133
+ this.subscriberCounter.set(eventKey, newCount)
134
+
135
+ if (!eventKey.startsWith('$')) {
136
+ this.emitSystem('$sub:leave', {
137
+ subscriberId: subId,
138
+ event: eventKey,
139
+ count: newCount
140
+ })
141
+ }
142
+
143
+ if (subs.size === 0) {
144
+ this.subscriptions.delete(eventKey)
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ emit<K extends keyof TEvents>(
151
+ event: K,
152
+ data: TEvents[K]
153
+ ): number {
154
+ this.checkDestroyed()
155
+ return this.emitInternal(event as string, data)
156
+ }
157
+
158
+ // Emitir para evento do sistema
159
+ private emitSystem<K extends keyof SystemEvents<TState>>(
160
+ event: K,
161
+ data: SystemEvents<TState>[K]
162
+ ): void {
163
+ // Emitir localmente
164
+ this.emitInternal(event as string, data)
165
+
166
+ // Notificar sistema global
167
+ this.onSystemEvent?.(event as string, { roomId: this.id, ...data })
168
+ }
169
+
170
+ private emitInternal(event: string, data: any): number {
171
+ const subs = this.subscriptions.get(event)
172
+ if (!subs || subs.size === 0) return 0
173
+
174
+ let notified = 0
175
+ for (const sub of subs) {
176
+ try {
177
+ sub.handler(data)
178
+ notified++
179
+ } catch (error) {
180
+ console.error(`[Room:${this.id}] Error in handler for '${event}':`, error)
181
+ this.emitSystem('$error', {
182
+ error: error as Error,
183
+ context: `Handler for event '${event}'`
184
+ })
185
+ }
186
+ }
187
+
188
+ return notified
189
+ }
190
+
191
+ // ============================================
192
+ // Utilitários
193
+ // ============================================
194
+
195
+ getSubscriberCount(event?: string): number {
196
+ if (event) {
197
+ return this.subscriberCounter.get(event) || 0
198
+ }
199
+ let total = 0
200
+ for (const count of this.subscriberCounter.values()) {
201
+ total += count
202
+ }
203
+ return total
204
+ }
205
+
206
+ getEvents(): string[] {
207
+ return Array.from(this.subscriptions.keys()).filter(e => !e.startsWith('$'))
208
+ }
209
+
210
+ destroy(reason: 'manual' | 'empty' | 'ttl' = 'manual'): void {
211
+ if (this.destroyed) return
212
+
213
+ this.emitSystem('$room:destroyed', {
214
+ roomId: this.id,
215
+ reason,
216
+ finalState: this._state
217
+ })
218
+
219
+ this.destroyed = true
220
+ this.subscriptions.clear()
221
+ this.subscriberCounter.clear()
222
+ }
223
+
224
+ isDestroyed(): boolean {
225
+ return this.destroyed
226
+ }
227
+
228
+ private checkDestroyed(): void {
229
+ if (this.destroyed) {
230
+ throw new Error(`Room '${this.id}' has been destroyed`)
231
+ }
232
+ }
233
+ }
234
+
235
+ // ============================================
236
+ // Room System (gerenciador global)
237
+ // ============================================
238
+
239
+ export interface RoomSystemOptions {
240
+ autoDestroy?: boolean // Destruir sala quando vazia
241
+ destroyDelay?: number // Delay antes de destruir (ms)
242
+ defaultTTL?: number // TTL padrão para salas
243
+ }
244
+
245
+ export class RoomSystem<TState, TEvents extends Record<string, any>> {
246
+ public readonly name: string
247
+ private rooms = new Map<string, Room<TState, TEvents>>()
248
+ private globalSubscriptions = new Map<string, Set<EventHandler>>()
249
+ private destroyTimers = new Map<string, ReturnType<typeof setTimeout>>()
250
+ private options: Required<RoomSystemOptions>
251
+
252
+ constructor(name: string, options: RoomSystemOptions = {}) {
253
+ this.name = name
254
+ this.options = {
255
+ autoDestroy: options.autoDestroy ?? false,
256
+ destroyDelay: options.destroyDelay ?? 5 * 60 * 1000, // 5 min
257
+ defaultTTL: options.defaultTTL ?? 0 // 0 = sem TTL
258
+ }
259
+ }
260
+
261
+ // ============================================
262
+ // Gerenciamento de salas
263
+ // ============================================
264
+
265
+ room(roomId: string, initialState: TState): Room<TState, TEvents> {
266
+ // Cancelar timer de destruição se existir
267
+ const timer = this.destroyTimers.get(roomId)
268
+ if (timer) {
269
+ clearTimeout(timer)
270
+ this.destroyTimers.delete(roomId)
271
+ }
272
+
273
+ // Retornar sala existente
274
+ const existing = this.rooms.get(roomId)
275
+ if (existing && !existing.isDestroyed()) {
276
+ return existing
277
+ }
278
+
279
+ // Criar nova sala
280
+ const room = new Room<TState, TEvents>(
281
+ roomId,
282
+ initialState,
283
+ (event, data) => this.handleSystemEvent(event, data)
284
+ )
285
+
286
+ this.rooms.set(roomId, room)
287
+
288
+ // Emitir evento global
289
+ this.emitGlobal('$room:created', {
290
+ roomId,
291
+ createdAt: room.createdAt,
292
+ initialState
293
+ })
294
+
295
+ // Configurar auto-destroy
296
+ if (this.options.autoDestroy) {
297
+ room.on('$sub:leave', ({ count }) => {
298
+ if (count === 0 && room.getSubscriberCount() === 0) {
299
+ this.scheduleDestroy(roomId)
300
+ }
301
+ })
302
+ }
303
+
304
+ // Configurar TTL
305
+ if (this.options.defaultTTL > 0) {
306
+ setTimeout(() => {
307
+ if (!room.isDestroyed()) {
308
+ this.destroyRoom(roomId, 'ttl')
309
+ }
310
+ }, this.options.defaultTTL)
311
+ }
312
+
313
+ return room
314
+ }
315
+
316
+ get(roomId: string): Room<TState, TEvents> | undefined {
317
+ const room = this.rooms.get(roomId)
318
+ return room && !room.isDestroyed() ? room : undefined
319
+ }
320
+
321
+ has(roomId: string): boolean {
322
+ const room = this.rooms.get(roomId)
323
+ return room !== undefined && !room.isDestroyed()
324
+ }
325
+
326
+ getOrCreate(roomId: string, initialState: TState): Room<TState, TEvents> {
327
+ return this.get(roomId) ?? this.room(roomId, initialState)
328
+ }
329
+
330
+ destroyRoom(roomId: string, reason: 'manual' | 'empty' | 'ttl' = 'manual'): boolean {
331
+ const room = this.rooms.get(roomId)
332
+ if (!room) return false
333
+
334
+ room.destroy(reason)
335
+ this.rooms.delete(roomId)
336
+
337
+ // Cancelar timer se existir
338
+ const timer = this.destroyTimers.get(roomId)
339
+ if (timer) {
340
+ clearTimeout(timer)
341
+ this.destroyTimers.delete(roomId)
342
+ }
343
+
344
+ return true
345
+ }
346
+
347
+ private scheduleDestroy(roomId: string): void {
348
+ // Cancelar timer anterior
349
+ const existing = this.destroyTimers.get(roomId)
350
+ if (existing) {
351
+ clearTimeout(existing)
352
+ }
353
+
354
+ const timer = setTimeout(() => {
355
+ const room = this.rooms.get(roomId)
356
+ if (room && room.getSubscriberCount() === 0) {
357
+ this.destroyRoom(roomId, 'empty')
358
+ }
359
+ this.destroyTimers.delete(roomId)
360
+ }, this.options.destroyDelay)
361
+
362
+ this.destroyTimers.set(roomId, timer)
363
+ }
364
+
365
+ // ============================================
366
+ // Eventos globais
367
+ // ============================================
368
+
369
+ on<K extends keyof SystemEvents<TState>>(
370
+ event: K,
371
+ handler: EventHandler<SystemEvents<TState>[K] & { roomId: string }>
372
+ ): Unsubscribe {
373
+ const eventKey = event as string
374
+
375
+ if (!this.globalSubscriptions.has(eventKey)) {
376
+ this.globalSubscriptions.set(eventKey, new Set())
377
+ }
378
+
379
+ this.globalSubscriptions.get(eventKey)!.add(handler)
380
+
381
+ return () => {
382
+ this.globalSubscriptions.get(eventKey)?.delete(handler)
383
+ }
384
+ }
385
+
386
+ private handleSystemEvent(event: string, data: any): void {
387
+ this.emitGlobal(event, data)
388
+ }
389
+
390
+ private emitGlobal(event: string, data: any): void {
391
+ const handlers = this.globalSubscriptions.get(event)
392
+ if (!handlers) return
393
+
394
+ for (const handler of handlers) {
395
+ try {
396
+ handler(data)
397
+ } catch (error) {
398
+ console.error(`[RoomSystem:${this.name}] Error in global handler for '${event}':`, error)
399
+ }
400
+ }
401
+ }
402
+
403
+ // ============================================
404
+ // Utilitários
405
+ // ============================================
406
+
407
+ getRooms(): string[] {
408
+ return Array.from(this.rooms.keys()).filter(id => !this.rooms.get(id)?.isDestroyed())
409
+ }
410
+
411
+ getRoomCount(): number {
412
+ return this.getRooms().length
413
+ }
414
+
415
+ getStats(): {
416
+ name: string
417
+ roomCount: number
418
+ rooms: Record<string, { subscriberCount: number; events: string[]; createdAt: number }>
419
+ } {
420
+ const rooms: Record<string, { subscriberCount: number; events: string[]; createdAt: number }> = {}
421
+
422
+ for (const [id, room] of this.rooms) {
423
+ if (!room.isDestroyed()) {
424
+ rooms[id] = {
425
+ subscriberCount: room.getSubscriberCount(),
426
+ events: room.getEvents(),
427
+ createdAt: room.createdAt
428
+ }
429
+ }
430
+ }
431
+
432
+ return {
433
+ name: this.name,
434
+ roomCount: Object.keys(rooms).length,
435
+ rooms
436
+ }
437
+ }
438
+
439
+ destroyAll(): void {
440
+ for (const roomId of this.rooms.keys()) {
441
+ this.destroyRoom(roomId, 'manual')
442
+ }
443
+ }
444
+ }
445
+
446
+ // ============================================
447
+ // Factory function
448
+ // ============================================
449
+
450
+ export function createRoomSystem<
451
+ TDef extends { state: any; events: Record<string, any> }
452
+ >(
453
+ name: string,
454
+ options?: RoomSystemOptions
455
+ ): RoomSystem<TDef['state'], TDef['events']> {
456
+ return new RoomSystem<TDef['state'], TDef['events']>(name, options)
457
+ }
458
+
459
+ // ============================================
460
+ // Exports
461
+ // ============================================
462
+
463
+ export type { EventHandler, Unsubscribe, Subscription }
@@ -0,0 +1,13 @@
1
+ // 🔥 FluxStack Room System - Exports
2
+
3
+ export { Room, RoomSystem, createRoomSystem } from './RoomSystem'
4
+ export type {
5
+ SystemEvents,
6
+ EventHandler,
7
+ Unsubscribe,
8
+ Subscription,
9
+ RoomSystemOptions
10
+ } from './RoomSystem'
11
+
12
+ export { RoomBroadcaster, createRoomBroadcaster } from './RoomBroadcaster'
13
+ export type { BroadcastMessage, RoomConnection } from './RoomBroadcaster'
@@ -8,7 +8,7 @@
8
8
  * - Service container integration
9
9
  */
10
10
 
11
- import type { Logger } from '@/core/utils/logger/index'
11
+ import type { Logger } from '@core/utils/logger/index'
12
12
 
13
13
  export interface ServiceContext {
14
14
  config: any
@@ -5,7 +5,7 @@
5
5
  * Provides service registration, resolution, and lifecycle management
6
6
  */
7
7
 
8
- import type { Logger } from '@/core/utils/logger/index'
8
+ import type { Logger } from '@core/utils/logger/index'
9
9
 
10
10
  export interface ServiceDefinition {
11
11
  factory: (container: ServiceContainer) => any
@@ -1,9 +1,9 @@
1
- /**
2
- * Core Server Services
3
- * FluxStack service infrastructure exports
4
- */
5
-
6
- export { BaseService } from './BaseService'
7
- export { ServiceContainer } from './ServiceContainer'
8
- export type { ServiceContext, ServiceContainer as IServiceContainer } from './BaseService'
1
+ /**
2
+ * Core Server Services
3
+ * FluxStack service infrastructure exports
4
+ */
5
+
6
+ export { BaseService } from './BaseService'
7
+ export { ServiceContainer } from './ServiceContainer'
8
+ export type { ServiceContext, ServiceContainer as IServiceContainer } from './BaseService'
9
9
  export type { ServiceDefinition } from './ServiceContainer'
@@ -212,10 +212,10 @@ export class ProjectCreator {
212
212
  baseUrl: ".",
213
213
  paths: {
214
214
  "@/*": ["./*"],
215
- "@/core/*": ["./core/*"],
216
- "@/app/*": ["./app/*"],
217
- "@/config/*": ["./config/*"],
218
- "@/shared/*": ["./app/shared/*"]
215
+ "@core/*": ["./core/*"],
216
+ "@app/*": ["./app/*"],
217
+ "@config/*": ["./config/*"],
218
+ "@shared/*": ["./app/shared/*"]
219
219
  },
220
220
  strict: true,
221
221
  skipLibCheck: true,
@@ -243,10 +243,10 @@ lockfile = true
243
243
  # Path mapping (alias support)
244
244
  [build.alias]
245
245
  "@" = "."
246
- "@/core" = "./core"
247
- "@/app" = "./app"
248
- "@/config" = "./config"
249
- "@/shared" = "./app/shared"
246
+ "@core" = "./core"
247
+ "@app" = "./app"
248
+ "@config" = "./config"
249
+ "@shared" = "./app/shared"
250
250
  `
251
251
 
252
252
  await Bun.write(join(this.targetDir, "bunfig.toml"), bunConfig)
@@ -261,10 +261,10 @@ export default defineConfig({
261
261
  resolve: {
262
262
  alias: {
263
263
  '@': resolve(__dirname, '.'),
264
- '@/core': resolve(__dirname, './core'),
265
- '@/app': resolve(__dirname, './app'),
266
- '@/config': resolve(__dirname, './config'),
267
- '@/shared': resolve(__dirname, './app/shared')
264
+ '@core': resolve(__dirname, './core'),
265
+ '@app': resolve(__dirname, './app'),
266
+ '@config': resolve(__dirname, './config'),
267
+ '@shared': resolve(__dirname, './app/shared')
268
268
  }
269
269
  },
270
270
  server: {
@@ -1,10 +1,10 @@
1
- /**
2
- * Core Testing Utilities
3
- * FluxStack testing infrastructure exports
4
- */
5
-
6
- export {
7
- setupFluxStackTests,
8
- createMockLogger,
9
- createMockServiceContext
1
+ /**
2
+ * Core Testing Utilities
3
+ * FluxStack testing infrastructure exports
4
+ */
5
+
6
+ export {
7
+ setupFluxStackTests,
8
+ createMockLogger,
9
+ createMockServiceContext
10
10
  } from './setup'