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.
- package/.dockerignore +1 -2
- package/Dockerfile +8 -8
- package/LIVE_COMPONENTS_REVIEW.md +781 -0
- package/LLMD/INDEX.md +64 -0
- package/LLMD/MAINTENANCE.md +197 -0
- package/LLMD/MIGRATION.md +156 -0
- package/LLMD/config/.gitkeep +1 -0
- package/LLMD/config/declarative-system.md +268 -0
- package/LLMD/config/environment-vars.md +327 -0
- package/LLMD/config/runtime-reload.md +401 -0
- package/LLMD/core/.gitkeep +1 -0
- package/LLMD/core/build-system.md +599 -0
- package/LLMD/core/framework-lifecycle.md +229 -0
- package/LLMD/core/plugin-system.md +451 -0
- package/LLMD/patterns/.gitkeep +1 -0
- package/LLMD/patterns/anti-patterns.md +297 -0
- package/LLMD/patterns/project-structure.md +264 -0
- package/LLMD/patterns/type-safety.md +440 -0
- package/LLMD/reference/.gitkeep +1 -0
- package/LLMD/reference/cli-commands.md +250 -0
- package/LLMD/reference/plugin-hooks.md +357 -0
- package/LLMD/reference/routing.md +39 -0
- package/LLMD/reference/troubleshooting.md +364 -0
- package/LLMD/resources/.gitkeep +1 -0
- package/LLMD/resources/controllers.md +465 -0
- package/LLMD/resources/live-components.md +703 -0
- package/LLMD/resources/live-rooms.md +482 -0
- package/LLMD/resources/live-upload.md +130 -0
- package/LLMD/resources/plugins-external.md +617 -0
- package/LLMD/resources/routes-eden.md +254 -0
- package/README.md +37 -17
- package/app/client/index.html +0 -1
- package/app/client/src/App.tsx +109 -156
- package/app/client/src/components/AppLayout.tsx +68 -0
- package/app/client/src/components/BackButton.tsx +13 -0
- package/app/client/src/components/DemoPage.tsx +20 -0
- package/app/client/src/components/LiveUploadWidget.tsx +204 -0
- package/app/client/src/lib/eden-api.ts +85 -65
- package/app/client/src/live/ChatDemo.tsx +107 -0
- package/app/client/src/live/CounterDemo.tsx +206 -0
- package/app/client/src/live/FormDemo.tsx +119 -0
- package/app/client/src/live/RoomChatDemo.tsx +242 -0
- package/app/client/src/live/UploadDemo.tsx +21 -0
- package/app/client/src/main.tsx +13 -10
- package/app/client/src/pages/ApiTestPage.tsx +108 -0
- package/app/client/src/pages/HomePage.tsx +76 -0
- package/app/client/src/vite-env.d.ts +1 -1
- package/app/server/app.ts +1 -4
- package/app/server/controllers/users.controller.ts +36 -44
- package/app/server/index.ts +24 -107
- package/app/server/live/LiveChat.ts +77 -0
- package/app/server/live/LiveCounter.ts +67 -0
- package/app/server/live/LiveForm.ts +63 -0
- package/app/server/live/LiveLocalCounter.ts +32 -0
- package/app/server/live/LiveRoomChat.ts +285 -0
- package/app/server/live/LiveUpload.ts +81 -0
- package/app/server/live/register-components.ts +19 -19
- package/app/server/routes/index.ts +3 -1
- package/app/server/routes/room.routes.ts +117 -0
- package/app/server/routes/users.routes.ts +35 -27
- package/app/shared/types/index.ts +14 -2
- package/config/app.config.ts +2 -62
- package/config/client.config.ts +2 -95
- package/config/database.config.ts +2 -99
- package/config/fluxstack.config.ts +25 -45
- package/config/index.ts +57 -38
- package/config/monitoring.config.ts +2 -114
- package/config/plugins.config.ts +2 -80
- package/config/server.config.ts +2 -68
- package/config/services.config.ts +2 -130
- package/config/system/app.config.ts +29 -0
- package/config/system/build.config.ts +49 -0
- package/config/system/client.config.ts +68 -0
- package/config/system/database.config.ts +17 -0
- package/config/system/fluxstack.config.ts +114 -0
- package/config/{logger.config.ts → system/logger.config.ts} +3 -1
- package/config/system/monitoring.config.ts +114 -0
- package/config/system/plugins.config.ts +84 -0
- package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
- package/config/system/server.config.ts +68 -0
- package/config/system/services.config.ts +46 -0
- package/config/{system.config.ts → system/system.config.ts} +1 -1
- package/core/build/bundler.ts +4 -1
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +159 -27
- package/core/build/live-components-generator.ts +70 -3
- package/core/build/optimizer.ts +235 -235
- package/core/cli/command-registry.ts +6 -4
- package/core/cli/commands/build.ts +79 -0
- package/core/cli/commands/create.ts +54 -0
- package/core/cli/commands/dev.ts +101 -0
- package/core/cli/commands/help.ts +34 -0
- package/core/cli/commands/index.ts +34 -0
- package/core/cli/commands/make-plugin.ts +90 -0
- package/core/cli/commands/plugin-add.ts +197 -0
- package/core/cli/commands/plugin-deps.ts +2 -2
- package/core/cli/commands/plugin-list.ts +208 -0
- package/core/cli/commands/plugin-remove.ts +170 -0
- package/core/cli/generators/component.ts +769 -769
- package/core/cli/generators/controller.ts +1 -1
- package/core/cli/generators/index.ts +146 -146
- package/core/cli/generators/interactive.ts +227 -227
- package/core/cli/generators/plugin.ts +2 -2
- package/core/cli/generators/prompts.ts +82 -82
- package/core/cli/generators/route.ts +6 -6
- package/core/cli/generators/service.ts +2 -2
- package/core/cli/generators/template-engine.ts +4 -3
- package/core/cli/generators/types.ts +2 -2
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +115 -558
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/LiveComponentsProvider.tsx +63 -17
- package/core/client/api/eden.ts +183 -0
- package/core/client/api/index.ts +11 -0
- package/core/client/components/Live.tsx +104 -0
- package/core/client/fluxstack.ts +1 -9
- package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/hooks/useChunkedUpload.ts +170 -69
- package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
- package/core/client/hooks/useLiveComponent.ts +800 -0
- package/core/client/hooks/useLiveUpload.ts +71 -0
- package/core/client/hooks/useRoom.ts +409 -0
- package/core/client/hooks/useRoomProxy.ts +382 -0
- package/core/client/index.ts +18 -51
- package/core/client/standalone-entry.ts +8 -0
- package/core/client/standalone.ts +74 -53
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +70 -291
- package/core/config/schema.ts +42 -723
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +227 -47
- package/core/framework/types.ts +2 -2
- package/core/index.ts +23 -4
- package/core/live/ComponentRegistry.ts +7 -3
- package/core/live/types.ts +77 -0
- package/core/plugins/built-in/index.ts +134 -131
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1074
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +111 -47
- package/core/plugins/built-in/static/index.ts +1 -1
- package/core/plugins/built-in/swagger/index.ts +68 -265
- package/core/plugins/built-in/vite/index.ts +94 -306
- package/core/plugins/built-in/vite/vite-dev.ts +82 -0
- package/core/plugins/config.ts +9 -7
- package/core/plugins/dependency-manager.ts +31 -1
- package/core/plugins/discovery.ts +19 -7
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +203 -203
- package/core/plugins/manager.ts +27 -39
- package/core/plugins/module-resolver.ts +19 -8
- package/core/plugins/registry.ts +309 -21
- package/core/plugins/types.ts +106 -55
- package/core/server/framework.ts +66 -43
- package/core/server/index.ts +15 -16
- package/core/server/live/ComponentRegistry.ts +91 -75
- package/core/server/live/FileUploadManager.ts +41 -31
- package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
- package/core/server/live/LiveRoomManager.ts +261 -0
- package/core/server/live/RoomEventBus.ts +234 -0
- package/core/server/live/RoomStateManager.ts +172 -0
- package/core/server/live/StateSignature.ts +643 -643
- package/core/server/live/WebSocketConnectionManager.ts +30 -19
- package/core/server/live/auto-generated-components.ts +41 -26
- package/core/server/live/index.ts +14 -0
- package/core/server/live/websocket-plugin.ts +233 -72
- package/core/server/middleware/elysia-helpers.ts +7 -2
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +180 -180
- package/core/server/plugins/static-files-plugin.ts +69 -260
- package/core/server/plugins/swagger.ts +33 -33
- package/core/server/rooms/RoomBroadcaster.ts +357 -0
- package/core/server/rooms/RoomSystem.ts +463 -0
- package/core/server/rooms/index.ts +13 -0
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +12 -12
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/build.ts +219 -218
- package/core/types/config.ts +56 -26
- package/core/types/index.ts +4 -4
- package/core/types/plugin.ts +107 -99
- package/core/types/types.ts +490 -14
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +2 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +36 -1
- package/core/utils/errors/index.ts +49 -5
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +6 -16
- package/core/utils/index.ts +17 -17
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +13 -9
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +6 -1
- package/core/utils/logger/stack-trace.ts +3 -1
- package/core/utils/logger/startup-banner.ts +82 -66
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +66 -66
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +8 -7
- package/eslint.config.js +23 -23
- package/package.json +14 -15
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/config/index.ts +1 -1
- package/plugins/crypto-auth/index.ts +4 -4
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/index.ts +21 -21
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/tsconfig.api-strict.json +16 -0
- package/tsconfig.json +10 -14
- package/{app/client/tsconfig.node.json → tsconfig.node.json} +1 -1
- package/types/global.d.ts +29 -29
- package/types/vitest.d.ts +8 -8
- package/vite.config.ts +38 -62
- package/vitest.config.live.ts +10 -9
- package/vitest.config.ts +29 -17
- package/workspace.json +5 -5
- package/app/client/README.md +0 -69
- package/app/client/SIMPLIFICATION.md +0 -140
- package/app/client/frontend-only.ts +0 -12
- package/app/client/tsconfig.app.json +0 -44
- package/app/client/tsconfig.json +0 -7
- package/app/client/zustand-setup.md +0 -65
- package/app/server/backend-only.ts +0 -18
- package/app/server/live/LiveClockComponent.ts +0 -215
- package/app/server/routes/env-test.ts +0 -110
- package/core/client/hooks/index.ts +0 -7
- package/core/client/hooks/useHybridLiveComponent.ts +0 -631
- package/core/client/hooks/useWebSocket.ts +0 -373
- package/core/config/env.ts +0 -546
- package/core/config/loader.ts +0 -522
- package/core/config/runtime-config.ts +0 -327
- package/core/config/validator.ts +0 -540
- package/core/server/backend-entry.ts +0 -51
- package/core/server/standalone.ts +0 -106
- package/core/utils/regenerate-files.ts +0 -69
- package/fluxstack.config.ts +0 -354
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Advanced connection management with pooling, load balancing, and health monitoring
|
|
3
3
|
|
|
4
4
|
import { EventEmitter } from 'events'
|
|
5
|
+
import type { FluxStackWebSocket } from '@core/types/types'
|
|
5
6
|
|
|
6
7
|
export interface ConnectionConfig {
|
|
7
8
|
maxConnections: number
|
|
@@ -56,11 +57,11 @@ export interface LoadBalancerStats {
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
export class WebSocketConnectionManager extends EventEmitter {
|
|
59
|
-
private connections = new Map<string,
|
|
60
|
+
private connections = new Map<string, FluxStackWebSocket>() // connectionId -> websocket
|
|
60
61
|
private connectionMetrics = new Map<string, ConnectionMetrics>()
|
|
61
62
|
private connectionPools = new Map<string, Set<string>>() // poolId -> connectionIds
|
|
62
63
|
private messageQueues = new Map<string, QueuedMessage[]>() // connectionId -> queued messages
|
|
63
|
-
private healthCheckInterval
|
|
64
|
+
private healthCheckInterval!: NodeJS.Timeout
|
|
64
65
|
private config: ConnectionConfig
|
|
65
66
|
private loadBalancerIndex = 0
|
|
66
67
|
|
|
@@ -89,7 +90,7 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
89
90
|
/**
|
|
90
91
|
* Register a new WebSocket connection
|
|
91
92
|
*/
|
|
92
|
-
registerConnection(ws:
|
|
93
|
+
registerConnection(ws: FluxStackWebSocket, connectionId: string, poolId?: string): void {
|
|
93
94
|
if (this.connections.size >= this.config.maxConnections) {
|
|
94
95
|
throw new Error('Maximum connections exceeded')
|
|
95
96
|
}
|
|
@@ -129,26 +130,33 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
129
130
|
/**
|
|
130
131
|
* Setup connection event handlers
|
|
131
132
|
*/
|
|
132
|
-
private setupConnectionHandlers(ws:
|
|
133
|
+
private setupConnectionHandlers(ws: FluxStackWebSocket, connectionId: string): void {
|
|
133
134
|
const metrics = this.connectionMetrics.get(connectionId)
|
|
134
135
|
if (!metrics) return
|
|
135
136
|
|
|
136
137
|
// Handle incoming messages
|
|
138
|
+
// Note: Bun/Elysia WebSockets use different event handling patterns
|
|
139
|
+
// This code provides compatibility layer for both Node.js style (on/addListener) and browser style (addEventListener)
|
|
140
|
+
const wsAny = ws as any
|
|
137
141
|
const addListener = (event: string, handler: (...args: any[]) => void) => {
|
|
138
|
-
if (typeof
|
|
139
|
-
|
|
140
|
-
} else if (typeof
|
|
141
|
-
|
|
142
|
-
} else if (typeof
|
|
143
|
-
|
|
142
|
+
if (typeof wsAny.on === 'function') {
|
|
143
|
+
wsAny.on(event, handler)
|
|
144
|
+
} else if (typeof wsAny.addEventListener === 'function') {
|
|
145
|
+
wsAny.addEventListener(event, handler)
|
|
146
|
+
} else if (typeof wsAny.addListener === 'function') {
|
|
147
|
+
wsAny.addListener(event, handler)
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
addListener('message', (data: any) => {
|
|
148
152
|
metrics.messagesReceived++
|
|
149
153
|
metrics.lastActivity = new Date()
|
|
150
|
-
|
|
151
|
-
|
|
154
|
+
if (typeof data === 'string') {
|
|
155
|
+
metrics.bytesTransferred += Buffer.byteLength(data)
|
|
156
|
+
} else if (data instanceof Buffer) {
|
|
157
|
+
metrics.bytesTransferred += data.length
|
|
158
|
+
}
|
|
159
|
+
|
|
152
160
|
this.emit('messageReceived', { connectionId, data })
|
|
153
161
|
})
|
|
154
162
|
|
|
@@ -168,10 +176,10 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
168
176
|
// Handle pong responses for latency measurement
|
|
169
177
|
addListener('pong', () => {
|
|
170
178
|
const now = Date.now()
|
|
171
|
-
const pingTime =
|
|
179
|
+
const pingTime = wsAny._pingTime
|
|
172
180
|
if (pingTime) {
|
|
173
181
|
metrics.latency = now - pingTime
|
|
174
|
-
delete
|
|
182
|
+
delete wsAny._pingTime
|
|
175
183
|
}
|
|
176
184
|
})
|
|
177
185
|
}
|
|
@@ -205,7 +213,7 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
205
213
|
* Send message with load balancing and queuing
|
|
206
214
|
*/
|
|
207
215
|
async sendMessage(
|
|
208
|
-
message: any,
|
|
216
|
+
message: any,
|
|
209
217
|
target?: { connectionId?: string; poolId?: string },
|
|
210
218
|
options?: { priority?: number; maxRetries?: number; queueIfOffline?: boolean }
|
|
211
219
|
): Promise<boolean> {
|
|
@@ -243,7 +251,7 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
243
251
|
* Send message to specific connection
|
|
244
252
|
*/
|
|
245
253
|
private async sendToConnection(
|
|
246
|
-
connectionId: string,
|
|
254
|
+
connectionId: string,
|
|
247
255
|
message: any,
|
|
248
256
|
options: { priority: number; maxRetries: number; queueIfOffline: boolean }
|
|
249
257
|
): Promise<boolean> {
|
|
@@ -288,7 +296,7 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
288
296
|
* Queue message for offline delivery
|
|
289
297
|
*/
|
|
290
298
|
private queueMessage(
|
|
291
|
-
connectionId: string,
|
|
299
|
+
connectionId: string,
|
|
292
300
|
message: any,
|
|
293
301
|
options: { priority: number; maxRetries: number }
|
|
294
302
|
): boolean {
|
|
@@ -494,8 +502,11 @@ export class WebSocketConnectionManager extends EventEmitter {
|
|
|
494
502
|
for (const [connectionId, ws] of this.connections) {
|
|
495
503
|
if (ws.readyState === 1) { // WebSocket.OPEN
|
|
496
504
|
try {
|
|
497
|
-
|
|
498
|
-
|
|
505
|
+
const wsAny = ws as any
|
|
506
|
+
wsAny._pingTime = Date.now()
|
|
507
|
+
if (typeof wsAny.ping === 'function') {
|
|
508
|
+
wsAny.ping()
|
|
509
|
+
}
|
|
499
510
|
} catch (error) {
|
|
500
511
|
console.error(`❌ Heartbeat failed for ${connectionId}:`, error)
|
|
501
512
|
}
|
|
@@ -1,26 +1,41 @@
|
|
|
1
|
-
// 🔥 Auto-generated Live Components Registration
|
|
2
|
-
// This file is automatically generated during build time - DO NOT EDIT MANUALLY
|
|
3
|
-
// Generated at:
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
// 🔥 Auto-generated Live Components Registration
|
|
2
|
+
// This file is automatically generated during build time - DO NOT EDIT MANUALLY
|
|
3
|
+
// Generated at: 2026-02-09T22:13:45.496Z
|
|
4
|
+
|
|
5
|
+
import { LiveChat } from "@app/server/live/LiveChat"
|
|
6
|
+
import { LiveCounter } from "@app/server/live/LiveCounter"
|
|
7
|
+
import { LiveForm } from "@app/server/live/LiveForm"
|
|
8
|
+
import { LiveLocalCounter } from "@app/server/live/LiveLocalCounter"
|
|
9
|
+
import { LiveRoomChat } from "@app/server/live/LiveRoomChat"
|
|
10
|
+
import { LiveUpload } from "@app/server/live/LiveUpload"
|
|
11
|
+
import { componentRegistry } from "@core/server/live/ComponentRegistry"
|
|
12
|
+
|
|
13
|
+
// Register all components statically for production bundle
|
|
14
|
+
function registerAllComponents() {
|
|
15
|
+
try {
|
|
16
|
+
// Auto-generated component registrations
|
|
17
|
+
componentRegistry.registerComponentClass('LiveChat', LiveChat)
|
|
18
|
+
componentRegistry.registerComponentClass('LiveCounter', LiveCounter)
|
|
19
|
+
componentRegistry.registerComponentClass('LiveForm', LiveForm)
|
|
20
|
+
componentRegistry.registerComponentClass('LiveLocalCounter', LiveLocalCounter)
|
|
21
|
+
componentRegistry.registerComponentClass('LiveRoomChat', LiveRoomChat)
|
|
22
|
+
componentRegistry.registerComponentClass('LiveUpload', LiveUpload)
|
|
23
|
+
|
|
24
|
+
console.log('📝 Live components registered successfully! (6 components)')
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.warn('⚠️ Error registering components:', error)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Auto-register components
|
|
31
|
+
registerAllComponents()
|
|
32
|
+
|
|
33
|
+
// Export all components to ensure they're included in the bundle
|
|
34
|
+
export {
|
|
35
|
+
LiveChat,
|
|
36
|
+
LiveCounter,
|
|
37
|
+
LiveForm,
|
|
38
|
+
LiveLocalCounter,
|
|
39
|
+
LiveRoomChat,
|
|
40
|
+
LiveUpload
|
|
41
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// 🔥 FluxStack Live - Server Exports
|
|
2
|
+
|
|
3
|
+
export { roomState, createTypedRoomState } from './RoomStateManager'
|
|
4
|
+
export type { RoomStateData, RoomInfo } from './RoomStateManager'
|
|
5
|
+
|
|
6
|
+
export { roomEvents, createTypedRoomEventBus } from './RoomEventBus'
|
|
7
|
+
export type { EventHandler, RoomSubscription } from './RoomEventBus'
|
|
8
|
+
|
|
9
|
+
export { componentRegistry } from './ComponentRegistry'
|
|
10
|
+
export { liveComponentsPlugin } from './websocket-plugin'
|
|
11
|
+
export { connectionManager } from './WebSocketConnectionManager'
|
|
12
|
+
export { fileUploadManager } from './FileUploadManager'
|
|
13
|
+
export { stateSignature } from './StateSignature'
|
|
14
|
+
export { performanceMonitor } from './LiveComponentPerformanceMonitor'
|
|
@@ -4,8 +4,9 @@ import { componentRegistry } from './ComponentRegistry'
|
|
|
4
4
|
import { fileUploadManager } from './FileUploadManager'
|
|
5
5
|
import { connectionManager } from './WebSocketConnectionManager'
|
|
6
6
|
import { performanceMonitor } from './LiveComponentPerformanceMonitor'
|
|
7
|
-
import
|
|
8
|
-
import type {
|
|
7
|
+
import { liveRoomManager, type RoomMessage } from './LiveRoomManager'
|
|
8
|
+
import type { LiveMessage, FileUploadStartMessage, FileUploadChunkMessage, FileUploadCompleteMessage, BinaryChunkHeader, FluxStackWebSocket, FluxStackWSData } from '@core/types/types'
|
|
9
|
+
import type { Plugin, PluginContext } from '@core/index'
|
|
9
10
|
import { t, Elysia } from 'elysia'
|
|
10
11
|
import path from 'path'
|
|
11
12
|
|
|
@@ -131,46 +132,38 @@ export const liveComponentsPlugin: Plugin = {
|
|
|
131
132
|
|
|
132
133
|
// Create grouped routes for Live Components with documentation
|
|
133
134
|
const liveRoutes = new Elysia({ prefix: '/api/live', tags: ['Live Components'] })
|
|
134
|
-
// WebSocket route
|
|
135
|
+
// WebSocket route - supports both JSON and binary messages
|
|
135
136
|
.ws('/ws', {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
action: t.Optional(t.String()),
|
|
140
|
-
payload: t.Optional(t.Any()),
|
|
141
|
-
timestamp: t.Optional(t.Number()),
|
|
142
|
-
userId: t.Optional(t.String()),
|
|
143
|
-
room: t.Optional(t.String()),
|
|
144
|
-
requestId: t.Optional(t.String()),
|
|
145
|
-
expectResponse: t.Optional(t.Boolean()),
|
|
146
|
-
// File upload specific fields
|
|
147
|
-
uploadId: t.Optional(t.String()),
|
|
148
|
-
filename: t.Optional(t.String()),
|
|
149
|
-
fileType: t.Optional(t.String()),
|
|
150
|
-
fileSize: t.Optional(t.Number()),
|
|
151
|
-
chunkSize: t.Optional(t.Number()),
|
|
152
|
-
chunkIndex: t.Optional(t.Number()),
|
|
153
|
-
totalChunks: t.Optional(t.Number()),
|
|
154
|
-
data: t.Optional(t.String()),
|
|
155
|
-
hash: t.Optional(t.String())
|
|
156
|
-
}),
|
|
137
|
+
// Use t.Any() to allow both JSON objects and binary data
|
|
138
|
+
// Binary messages will be ArrayBuffer/Uint8Array, JSON will be parsed objects
|
|
139
|
+
body: t.Any(),
|
|
157
140
|
|
|
158
141
|
open(ws) {
|
|
142
|
+
const socket = ws as unknown as FluxStackWebSocket
|
|
159
143
|
const connectionId = `ws-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
|
160
144
|
console.log(`🔌 Live Components WebSocket connected: ${connectionId}`)
|
|
161
|
-
|
|
145
|
+
|
|
162
146
|
// Register connection with enhanced connection manager
|
|
163
|
-
connectionManager.registerConnection(ws, connectionId, 'live-components')
|
|
164
|
-
|
|
147
|
+
connectionManager.registerConnection(ws as unknown as FluxStackWebSocket, connectionId, 'live-components')
|
|
148
|
+
|
|
165
149
|
// Initialize and store connection data in ws.data
|
|
166
|
-
|
|
167
|
-
|
|
150
|
+
const wsData: FluxStackWSData = {
|
|
151
|
+
connectionId,
|
|
152
|
+
components: new Map(),
|
|
153
|
+
subscriptions: new Set(),
|
|
154
|
+
connectedAt: new Date()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Assign data to websocket (Elysia creates ws.data from context)
|
|
158
|
+
if (!socket.data) {
|
|
159
|
+
(socket as { data: FluxStackWSData }).data = wsData
|
|
160
|
+
} else {
|
|
161
|
+
socket.data.connectionId = connectionId
|
|
162
|
+
socket.data.components = new Map()
|
|
163
|
+
socket.data.subscriptions = new Set()
|
|
164
|
+
socket.data.connectedAt = new Date()
|
|
168
165
|
}
|
|
169
|
-
|
|
170
|
-
ws.data.components = new Map()
|
|
171
|
-
ws.data.subscriptions = new Set()
|
|
172
|
-
ws.data.connectedAt = new Date()
|
|
173
|
-
|
|
166
|
+
|
|
174
167
|
// Send connection confirmation
|
|
175
168
|
ws.send(JSON.stringify({
|
|
176
169
|
type: 'CONNECTION_ESTABLISHED',
|
|
@@ -185,50 +178,96 @@ export const liveComponentsPlugin: Plugin = {
|
|
|
185
178
|
}))
|
|
186
179
|
},
|
|
187
180
|
|
|
188
|
-
async message(ws,
|
|
181
|
+
async message(ws: unknown, rawMessage: LiveMessage | ArrayBuffer | Uint8Array) {
|
|
182
|
+
const socket = ws as FluxStackWebSocket
|
|
189
183
|
try {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
184
|
+
let message: LiveMessage
|
|
185
|
+
let binaryChunkData: Buffer | null = null
|
|
186
|
+
|
|
187
|
+
// Check if this is a binary message (file upload chunk)
|
|
188
|
+
if (rawMessage instanceof ArrayBuffer || rawMessage instanceof Uint8Array) {
|
|
189
|
+
// Binary protocol: [4 bytes header length][JSON header][binary data]
|
|
190
|
+
const buffer = rawMessage instanceof ArrayBuffer
|
|
191
|
+
? Buffer.from(rawMessage)
|
|
192
|
+
: Buffer.from(rawMessage.buffer, rawMessage.byteOffset, rawMessage.byteLength)
|
|
193
|
+
|
|
194
|
+
// Read header length (first 4 bytes, little-endian)
|
|
195
|
+
const headerLength = buffer.readUInt32LE(0)
|
|
196
|
+
|
|
197
|
+
// Extract and parse JSON header
|
|
198
|
+
const headerJson = buffer.slice(4, 4 + headerLength).toString('utf-8')
|
|
199
|
+
const header = JSON.parse(headerJson) as BinaryChunkHeader
|
|
200
|
+
|
|
201
|
+
// Extract binary chunk data
|
|
202
|
+
binaryChunkData = buffer.slice(4 + headerLength)
|
|
203
|
+
|
|
204
|
+
console.log(`📦 Binary chunk received: ${binaryChunkData.length} bytes for upload ${header.uploadId}`)
|
|
205
|
+
|
|
206
|
+
// Create message with binary data attached
|
|
207
|
+
message = {
|
|
208
|
+
...header,
|
|
209
|
+
data: binaryChunkData, // Buffer instead of base64 string
|
|
210
|
+
timestamp: Date.now()
|
|
211
|
+
} as unknown as LiveMessage
|
|
212
|
+
} else {
|
|
213
|
+
// Regular JSON message
|
|
214
|
+
message = rawMessage as LiveMessage
|
|
215
|
+
message.timestamp = Date.now()
|
|
216
|
+
}
|
|
217
|
+
|
|
193
218
|
console.log(`📨 Received message:`, {
|
|
194
219
|
type: message.type,
|
|
195
220
|
componentId: message.componentId,
|
|
196
221
|
action: message.action,
|
|
197
|
-
requestId: message.requestId
|
|
222
|
+
requestId: message.requestId,
|
|
223
|
+
isBinary: binaryChunkData !== null
|
|
198
224
|
})
|
|
199
225
|
|
|
200
226
|
// Handle different message types
|
|
201
227
|
switch (message.type) {
|
|
202
228
|
case 'COMPONENT_MOUNT':
|
|
203
|
-
await handleComponentMount(
|
|
229
|
+
await handleComponentMount(socket, message)
|
|
204
230
|
break
|
|
205
231
|
case 'COMPONENT_REHYDRATE':
|
|
206
|
-
await handleComponentRehydrate(
|
|
232
|
+
await handleComponentRehydrate(socket, message)
|
|
207
233
|
break
|
|
208
234
|
case 'COMPONENT_UNMOUNT':
|
|
209
|
-
await handleComponentUnmount(
|
|
235
|
+
await handleComponentUnmount(socket, message)
|
|
210
236
|
break
|
|
211
237
|
case 'CALL_ACTION':
|
|
212
|
-
await handleActionCall(
|
|
238
|
+
await handleActionCall(socket, message)
|
|
213
239
|
break
|
|
214
240
|
case 'PROPERTY_UPDATE':
|
|
215
|
-
await handlePropertyUpdate(
|
|
241
|
+
await handlePropertyUpdate(socket, message)
|
|
216
242
|
break
|
|
217
243
|
case 'COMPONENT_PING':
|
|
218
|
-
await handleComponentPing(
|
|
244
|
+
await handleComponentPing(socket, message)
|
|
219
245
|
break
|
|
220
246
|
case 'FILE_UPLOAD_START':
|
|
221
|
-
await handleFileUploadStart(
|
|
247
|
+
await handleFileUploadStart(socket, message as FileUploadStartMessage)
|
|
222
248
|
break
|
|
223
249
|
case 'FILE_UPLOAD_CHUNK':
|
|
224
|
-
await handleFileUploadChunk(
|
|
250
|
+
await handleFileUploadChunk(socket, message as FileUploadChunkMessage, binaryChunkData)
|
|
225
251
|
break
|
|
226
252
|
case 'FILE_UPLOAD_COMPLETE':
|
|
227
|
-
await handleFileUploadComplete(
|
|
253
|
+
await handleFileUploadComplete(socket, message as unknown as FileUploadCompleteMessage)
|
|
254
|
+
break
|
|
255
|
+
// Room system messages
|
|
256
|
+
case 'ROOM_JOIN':
|
|
257
|
+
await handleRoomJoin(socket, message as unknown as RoomMessage)
|
|
258
|
+
break
|
|
259
|
+
case 'ROOM_LEAVE':
|
|
260
|
+
await handleRoomLeave(socket, message as unknown as RoomMessage)
|
|
261
|
+
break
|
|
262
|
+
case 'ROOM_EMIT':
|
|
263
|
+
await handleRoomEmit(socket, message as unknown as RoomMessage)
|
|
264
|
+
break
|
|
265
|
+
case 'ROOM_STATE_SET':
|
|
266
|
+
await handleRoomStateSet(socket, message as unknown as RoomMessage)
|
|
228
267
|
break
|
|
229
268
|
default:
|
|
230
269
|
console.warn(`❌ Unknown message type: ${message.type}`)
|
|
231
|
-
|
|
270
|
+
socket.send(JSON.stringify({
|
|
232
271
|
type: 'ERROR',
|
|
233
272
|
error: `Unknown message type: ${message.type}`,
|
|
234
273
|
timestamp: Date.now()
|
|
@@ -236,7 +275,7 @@ export const liveComponentsPlugin: Plugin = {
|
|
|
236
275
|
}
|
|
237
276
|
} catch (error) {
|
|
238
277
|
console.error('❌ WebSocket message error:', error)
|
|
239
|
-
|
|
278
|
+
socket.send(JSON.stringify({
|
|
240
279
|
type: 'ERROR',
|
|
241
280
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
242
281
|
timestamp: Date.now()
|
|
@@ -245,16 +284,17 @@ export const liveComponentsPlugin: Plugin = {
|
|
|
245
284
|
},
|
|
246
285
|
|
|
247
286
|
close(ws) {
|
|
248
|
-
const
|
|
287
|
+
const socket = ws as unknown as FluxStackWebSocket
|
|
288
|
+
const connectionId = socket.data?.connectionId
|
|
249
289
|
console.log(`🔌 Live Components WebSocket disconnected: ${connectionId}`)
|
|
250
|
-
|
|
290
|
+
|
|
251
291
|
// Cleanup connection in connection manager
|
|
252
292
|
if (connectionId) {
|
|
253
293
|
connectionManager.cleanupConnection(connectionId)
|
|
254
294
|
}
|
|
255
|
-
|
|
295
|
+
|
|
256
296
|
// Cleanup components for this connection
|
|
257
|
-
componentRegistry.cleanupConnection(
|
|
297
|
+
componentRegistry.cleanupConnection(socket)
|
|
258
298
|
}
|
|
259
299
|
})
|
|
260
300
|
|
|
@@ -456,9 +496,9 @@ export const liveComponentsPlugin: Plugin = {
|
|
|
456
496
|
}
|
|
457
497
|
|
|
458
498
|
// Handler functions for WebSocket messages
|
|
459
|
-
async function handleComponentMount(ws:
|
|
499
|
+
async function handleComponentMount(ws: FluxStackWebSocket, message: LiveMessage) {
|
|
460
500
|
const result = await componentRegistry.handleMessage(ws, message)
|
|
461
|
-
|
|
501
|
+
|
|
462
502
|
if (result !== null) {
|
|
463
503
|
const response = {
|
|
464
504
|
type: 'COMPONENT_MOUNTED',
|
|
@@ -473,7 +513,7 @@ async function handleComponentMount(ws: any, message: LiveMessage) {
|
|
|
473
513
|
}
|
|
474
514
|
}
|
|
475
515
|
|
|
476
|
-
async function handleComponentRehydrate(ws:
|
|
516
|
+
async function handleComponentRehydrate(ws: FluxStackWebSocket, message: LiveMessage) {
|
|
477
517
|
console.log('🔄 Processing component re-hydration request:', {
|
|
478
518
|
componentId: message.componentId,
|
|
479
519
|
payload: message.payload
|
|
@@ -532,7 +572,7 @@ async function handleComponentRehydrate(ws: any, message: LiveMessage) {
|
|
|
532
572
|
}
|
|
533
573
|
}
|
|
534
574
|
|
|
535
|
-
async function handleComponentUnmount(ws:
|
|
575
|
+
async function handleComponentUnmount(ws: FluxStackWebSocket, message: LiveMessage) {
|
|
536
576
|
const result = await componentRegistry.handleMessage(ws, message)
|
|
537
577
|
|
|
538
578
|
if (result !== null) {
|
|
@@ -547,7 +587,7 @@ async function handleComponentUnmount(ws: any, message: LiveMessage) {
|
|
|
547
587
|
}
|
|
548
588
|
}
|
|
549
589
|
|
|
550
|
-
async function handleActionCall(ws:
|
|
590
|
+
async function handleActionCall(ws: FluxStackWebSocket, message: LiveMessage) {
|
|
551
591
|
const result = await componentRegistry.handleMessage(ws, message)
|
|
552
592
|
|
|
553
593
|
if (result !== null) {
|
|
@@ -565,7 +605,7 @@ async function handleActionCall(ws: any, message: LiveMessage) {
|
|
|
565
605
|
}
|
|
566
606
|
}
|
|
567
607
|
|
|
568
|
-
async function handlePropertyUpdate(ws:
|
|
608
|
+
async function handlePropertyUpdate(ws: FluxStackWebSocket, message: LiveMessage) {
|
|
569
609
|
const result = await componentRegistry.handleMessage(ws, message)
|
|
570
610
|
|
|
571
611
|
if (result !== null) {
|
|
@@ -582,7 +622,7 @@ async function handlePropertyUpdate(ws: any, message: LiveMessage) {
|
|
|
582
622
|
}
|
|
583
623
|
}
|
|
584
624
|
|
|
585
|
-
async function handleComponentPing(ws:
|
|
625
|
+
async function handleComponentPing(ws: FluxStackWebSocket, message: LiveMessage) {
|
|
586
626
|
// Update component's last activity timestamp
|
|
587
627
|
const updated = componentRegistry.updateComponentActivity(message.componentId)
|
|
588
628
|
|
|
@@ -599,7 +639,7 @@ async function handleComponentPing(ws: any, message: LiveMessage) {
|
|
|
599
639
|
}
|
|
600
640
|
|
|
601
641
|
// File Upload Handler Functions
|
|
602
|
-
async function handleFileUploadStart(ws:
|
|
642
|
+
async function handleFileUploadStart(ws: FluxStackWebSocket, message: FileUploadStartMessage) {
|
|
603
643
|
console.log('📤 Starting file upload:', message.uploadId)
|
|
604
644
|
|
|
605
645
|
const result = await fileUploadManager.startUpload(message)
|
|
@@ -617,13 +657,19 @@ async function handleFileUploadStart(ws: any, message: FileUploadStartMessage) {
|
|
|
617
657
|
ws.send(JSON.stringify(response))
|
|
618
658
|
}
|
|
619
659
|
|
|
620
|
-
async function handleFileUploadChunk(ws:
|
|
621
|
-
console.log(`📦 Receiving chunk ${message.chunkIndex + 1} for upload ${message.uploadId}`)
|
|
622
|
-
|
|
623
|
-
const progressResponse = await fileUploadManager.receiveChunk(message, ws)
|
|
624
|
-
|
|
660
|
+
async function handleFileUploadChunk(ws: FluxStackWebSocket, message: FileUploadChunkMessage, binaryData: Buffer | null = null) {
|
|
661
|
+
console.log(`📦 Receiving chunk ${message.chunkIndex + 1} for upload ${message.uploadId}${binaryData ? ' (binary)' : ' (base64)'}`)
|
|
662
|
+
|
|
663
|
+
const progressResponse = await fileUploadManager.receiveChunk(message, ws, binaryData)
|
|
664
|
+
|
|
625
665
|
if (progressResponse) {
|
|
626
|
-
|
|
666
|
+
// Add requestId to response so client can correlate it
|
|
667
|
+
const responseWithRequestId = {
|
|
668
|
+
...progressResponse,
|
|
669
|
+
requestId: message.requestId,
|
|
670
|
+
success: true
|
|
671
|
+
}
|
|
672
|
+
ws.send(JSON.stringify(responseWithRequestId))
|
|
627
673
|
} else {
|
|
628
674
|
// Send error response
|
|
629
675
|
const errorResponse = {
|
|
@@ -632,15 +678,130 @@ async function handleFileUploadChunk(ws: any, message: FileUploadChunkMessage) {
|
|
|
632
678
|
uploadId: message.uploadId,
|
|
633
679
|
error: 'Failed to process chunk',
|
|
634
680
|
requestId: message.requestId,
|
|
681
|
+
success: false,
|
|
635
682
|
timestamp: Date.now()
|
|
636
683
|
}
|
|
637
684
|
ws.send(JSON.stringify(errorResponse))
|
|
638
685
|
}
|
|
639
686
|
}
|
|
640
687
|
|
|
641
|
-
async function handleFileUploadComplete(ws:
|
|
688
|
+
async function handleFileUploadComplete(ws: FluxStackWebSocket, message: FileUploadCompleteMessage) {
|
|
642
689
|
console.log('✅ Completing file upload:', message.uploadId)
|
|
643
|
-
|
|
690
|
+
|
|
644
691
|
const completeResponse = await fileUploadManager.completeUpload(message)
|
|
645
|
-
|
|
646
|
-
|
|
692
|
+
|
|
693
|
+
// Add requestId to response so client can correlate it
|
|
694
|
+
const responseWithRequestId = {
|
|
695
|
+
...completeResponse,
|
|
696
|
+
requestId: message.requestId
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
ws.send(JSON.stringify(responseWithRequestId))
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// ===== Room System Handlers =====
|
|
703
|
+
|
|
704
|
+
async function handleRoomJoin(ws: FluxStackWebSocket, message: RoomMessage) {
|
|
705
|
+
console.log(`🚪 Component ${message.componentId} joining room ${message.roomId}`)
|
|
706
|
+
|
|
707
|
+
try {
|
|
708
|
+
const result = liveRoomManager.joinRoom(
|
|
709
|
+
message.componentId,
|
|
710
|
+
message.roomId,
|
|
711
|
+
ws,
|
|
712
|
+
message.data?.initialState
|
|
713
|
+
)
|
|
714
|
+
|
|
715
|
+
const response = {
|
|
716
|
+
type: 'ROOM_JOINED',
|
|
717
|
+
componentId: message.componentId,
|
|
718
|
+
roomId: message.roomId,
|
|
719
|
+
success: true,
|
|
720
|
+
state: result.state,
|
|
721
|
+
requestId: message.requestId,
|
|
722
|
+
timestamp: Date.now()
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
ws.send(JSON.stringify(response))
|
|
726
|
+
} catch (error: any) {
|
|
727
|
+
ws.send(JSON.stringify({
|
|
728
|
+
type: 'ERROR',
|
|
729
|
+
componentId: message.componentId,
|
|
730
|
+
roomId: message.roomId,
|
|
731
|
+
error: error.message,
|
|
732
|
+
requestId: message.requestId,
|
|
733
|
+
timestamp: Date.now()
|
|
734
|
+
}))
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
async function handleRoomLeave(ws: FluxStackWebSocket, message: RoomMessage) {
|
|
739
|
+
console.log(`🚶 Component ${message.componentId} leaving room ${message.roomId}`)
|
|
740
|
+
|
|
741
|
+
try {
|
|
742
|
+
liveRoomManager.leaveRoom(message.componentId, message.roomId)
|
|
743
|
+
|
|
744
|
+
const response = {
|
|
745
|
+
type: 'ROOM_LEFT',
|
|
746
|
+
componentId: message.componentId,
|
|
747
|
+
roomId: message.roomId,
|
|
748
|
+
success: true,
|
|
749
|
+
requestId: message.requestId,
|
|
750
|
+
timestamp: Date.now()
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
ws.send(JSON.stringify(response))
|
|
754
|
+
} catch (error: any) {
|
|
755
|
+
ws.send(JSON.stringify({
|
|
756
|
+
type: 'ERROR',
|
|
757
|
+
componentId: message.componentId,
|
|
758
|
+
roomId: message.roomId,
|
|
759
|
+
error: error.message,
|
|
760
|
+
requestId: message.requestId,
|
|
761
|
+
timestamp: Date.now()
|
|
762
|
+
}))
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
async function handleRoomEmit(ws: FluxStackWebSocket, message: RoomMessage) {
|
|
767
|
+
console.log(`📡 Component ${message.componentId} emitting '${message.event}' to room ${message.roomId}`)
|
|
768
|
+
|
|
769
|
+
try {
|
|
770
|
+
const count = liveRoomManager.emitToRoom(
|
|
771
|
+
message.roomId,
|
|
772
|
+
message.event!,
|
|
773
|
+
message.data,
|
|
774
|
+
message.componentId // Excluir quem enviou
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
console.log(` → Notified ${count} components`)
|
|
778
|
+
} catch (error: any) {
|
|
779
|
+
ws.send(JSON.stringify({
|
|
780
|
+
type: 'ERROR',
|
|
781
|
+
componentId: message.componentId,
|
|
782
|
+
roomId: message.roomId,
|
|
783
|
+
error: error.message,
|
|
784
|
+
timestamp: Date.now()
|
|
785
|
+
}))
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
async function handleRoomStateSet(ws: FluxStackWebSocket, message: RoomMessage) {
|
|
790
|
+
console.log(`📝 Component ${message.componentId} updating state in room ${message.roomId}`)
|
|
791
|
+
|
|
792
|
+
try {
|
|
793
|
+
liveRoomManager.setRoomState(
|
|
794
|
+
message.roomId,
|
|
795
|
+
message.data ?? {},
|
|
796
|
+
message.componentId // Excluir quem enviou
|
|
797
|
+
)
|
|
798
|
+
} catch (error: any) {
|
|
799
|
+
ws.send(JSON.stringify({
|
|
800
|
+
type: 'ERROR',
|
|
801
|
+
componentId: message.componentId,
|
|
802
|
+
roomId: message.roomId,
|
|
803
|
+
error: error.message,
|
|
804
|
+
timestamp: Date.now()
|
|
805
|
+
}))
|
|
806
|
+
}
|
|
807
|
+
}
|