@fluxstack/live-client 0.1.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/dist/index.d.ts +359 -0
- package/dist/index.js +1148 -0
- package/dist/index.js.map +1 -0
- package/dist/live-client.browser.global.js +1175 -0
- package/dist/live-client.browser.global.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection.ts","../src/component.ts","../src/rooms.ts","../src/upload.ts","../src/persistence.ts","../src/state-validator.ts"],"sourcesContent":["// @fluxstack/live-client - WebSocket Connection Manager\r\n//\r\n// Framework-agnostic WebSocket connection with auto-reconnect, heartbeat,\r\n// request-response pattern, and component message routing.\r\n\r\nimport type { WebSocketMessage, WebSocketResponse } from '@fluxstack/live'\r\n\r\n/** Auth credentials to send during WebSocket connection */\r\nexport interface LiveAuthOptions {\r\n /** JWT or opaque token */\r\n token?: string\r\n /** Provider name (if multiple auth providers configured) */\r\n provider?: string\r\n /** Additional credentials (publicKey, signature, etc.) */\r\n [key: string]: unknown\r\n}\r\n\r\nexport interface LiveConnectionOptions {\r\n /** WebSocket URL. Auto-detected from window.location if omitted. */\r\n url?: string\r\n /** Auth credentials to send on connection */\r\n auth?: LiveAuthOptions\r\n /** Auto-connect on creation. Default: true */\r\n autoConnect?: boolean\r\n /** Reconnect interval in ms. Default: 1000 */\r\n reconnectInterval?: number\r\n /** Max reconnect attempts. Default: 5 */\r\n maxReconnectAttempts?: number\r\n /** Heartbeat interval in ms. Default: 30000 */\r\n heartbeatInterval?: number\r\n /** Enable debug logging. Default: false */\r\n debug?: boolean\r\n}\r\n\r\nexport interface LiveConnectionState {\r\n connected: boolean\r\n connecting: boolean\r\n error: string | null\r\n connectionId: string | null\r\n authenticated: boolean\r\n}\r\n\r\ntype StateChangeCallback = (state: LiveConnectionState) => void\r\ntype ComponentCallback = (message: WebSocketResponse) => void\r\n\r\n/**\r\n * Framework-agnostic WebSocket connection manager.\r\n * Handles reconnection, heartbeat, request-response pattern, and message routing.\r\n */\r\nexport class LiveConnection {\r\n private ws: WebSocket | null = null\r\n private options: Required<Omit<LiveConnectionOptions, 'url' | 'auth'>> & { url?: string; auth?: LiveAuthOptions }\r\n private reconnectAttempts = 0\r\n private reconnectTimeout: ReturnType<typeof setTimeout> | null = null\r\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null\r\n private componentCallbacks = new Map<string, ComponentCallback>()\r\n private pendingRequests = new Map<string, {\r\n resolve: (value: any) => void\r\n reject: (error: any) => void\r\n timeout: ReturnType<typeof setTimeout>\r\n }>()\r\n private stateListeners = new Set<StateChangeCallback>()\r\n private _state: LiveConnectionState = {\r\n connected: false,\r\n connecting: false,\r\n error: null,\r\n connectionId: null,\r\n authenticated: false,\r\n }\r\n\r\n constructor(options: LiveConnectionOptions = {}) {\r\n this.options = {\r\n url: options.url,\r\n auth: options.auth,\r\n autoConnect: options.autoConnect ?? true,\r\n reconnectInterval: options.reconnectInterval ?? 1000,\r\n maxReconnectAttempts: options.maxReconnectAttempts ?? 5,\r\n heartbeatInterval: options.heartbeatInterval ?? 30000,\r\n debug: options.debug ?? false,\r\n }\r\n\r\n if (this.options.autoConnect) {\r\n this.connect()\r\n }\r\n }\r\n\r\n get state(): LiveConnectionState {\r\n return { ...this._state }\r\n }\r\n\r\n /** Subscribe to connection state changes */\r\n onStateChange(callback: StateChangeCallback): () => void {\r\n this.stateListeners.add(callback)\r\n return () => { this.stateListeners.delete(callback) }\r\n }\r\n\r\n private setState(patch: Partial<LiveConnectionState>) {\r\n this._state = { ...this._state, ...patch }\r\n for (const cb of this.stateListeners) {\r\n cb(this._state)\r\n }\r\n }\r\n\r\n private getWebSocketUrl(): string {\r\n const auth = this.options.auth\r\n let baseUrl: string\r\n\r\n if (this.options.url) {\r\n baseUrl = this.options.url\r\n } else if (typeof window === 'undefined') {\r\n baseUrl = 'ws://localhost:3000/api/live/ws'\r\n } else {\r\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'\r\n baseUrl = `${protocol}//${window.location.host}/api/live/ws`\r\n }\r\n\r\n if (auth?.token) {\r\n const separator = baseUrl.includes('?') ? '&' : '?'\r\n return `${baseUrl}${separator}token=${encodeURIComponent(auth.token)}`\r\n }\r\n\r\n return baseUrl\r\n }\r\n\r\n private log(message: string, data?: any) {\r\n if (this.options.debug) {\r\n console.log(`[LiveConnection] ${message}`, data || '')\r\n }\r\n }\r\n\r\n /** Generate unique request ID */\r\n generateRequestId(): string {\r\n return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`\r\n }\r\n\r\n /** Connect to WebSocket server */\r\n connect(): void {\r\n if (this.ws?.readyState === WebSocket.CONNECTING) {\r\n this.log('Already connecting, skipping...')\r\n return\r\n }\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.log('Already connected, skipping...')\r\n return\r\n }\r\n\r\n this.setState({ connecting: true, error: null })\r\n const url = this.getWebSocketUrl()\r\n this.log('Connecting...', { url })\r\n\r\n try {\r\n const ws = new WebSocket(url)\r\n this.ws = ws\r\n\r\n ws.onopen = () => {\r\n this.log('Connected')\r\n this.setState({ connected: true, connecting: false })\r\n this.reconnectAttempts = 0\r\n this.startHeartbeat()\r\n }\r\n\r\n ws.onmessage = (event) => {\r\n try {\r\n const response: WebSocketResponse = JSON.parse(event.data)\r\n this.log('Received', { type: response.type, componentId: response.componentId })\r\n this.handleMessage(response)\r\n } catch {\r\n this.log('Failed to parse message')\r\n this.setState({ error: 'Failed to parse message' })\r\n }\r\n }\r\n\r\n ws.onclose = () => {\r\n this.log('Disconnected')\r\n this.setState({ connected: false, connecting: false, connectionId: null })\r\n this.stopHeartbeat()\r\n this.attemptReconnect()\r\n }\r\n\r\n ws.onerror = () => {\r\n this.log('WebSocket error')\r\n this.setState({ error: 'WebSocket connection error', connecting: false })\r\n }\r\n } catch (error) {\r\n this.setState({\r\n connecting: false,\r\n error: error instanceof Error ? error.message : 'Connection failed',\r\n })\r\n }\r\n }\r\n\r\n /** Disconnect from WebSocket server */\r\n disconnect(): void {\r\n if (this.reconnectTimeout) {\r\n clearTimeout(this.reconnectTimeout)\r\n this.reconnectTimeout = null\r\n }\r\n this.stopHeartbeat()\r\n if (this.ws) {\r\n this.ws.close()\r\n this.ws = null\r\n }\r\n this.reconnectAttempts = this.options.maxReconnectAttempts\r\n this.setState({ connected: false, connecting: false, connectionId: null })\r\n }\r\n\r\n /** Manual reconnect */\r\n reconnect(): void {\r\n this.disconnect()\r\n this.reconnectAttempts = 0\r\n setTimeout(() => this.connect(), 100)\r\n }\r\n\r\n private attemptReconnect(): void {\r\n if (this.reconnectAttempts < this.options.maxReconnectAttempts) {\r\n this.reconnectAttempts++\r\n this.log(`Reconnecting... (${this.reconnectAttempts}/${this.options.maxReconnectAttempts})`)\r\n this.reconnectTimeout = setTimeout(() => this.connect(), this.options.reconnectInterval)\r\n } else {\r\n this.setState({ error: 'Max reconnection attempts reached' })\r\n }\r\n }\r\n\r\n private startHeartbeat(): void {\r\n this.stopHeartbeat()\r\n this.heartbeatInterval = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n for (const componentId of this.componentCallbacks.keys()) {\r\n this.sendMessage({\r\n type: 'COMPONENT_PING',\r\n componentId,\r\n timestamp: Date.now(),\r\n }).catch(() => {})\r\n }\r\n }\r\n }, this.options.heartbeatInterval)\r\n }\r\n\r\n private stopHeartbeat(): void {\r\n if (this.heartbeatInterval) {\r\n clearInterval(this.heartbeatInterval)\r\n this.heartbeatInterval = null\r\n }\r\n }\r\n\r\n private handleMessage(response: WebSocketResponse): void {\r\n // Handle connection established\r\n if (response.type === 'CONNECTION_ESTABLISHED') {\r\n this.setState({\r\n connectionId: response.connectionId || null,\r\n authenticated: (response as any).authenticated || false,\r\n })\r\n\r\n // If auth credentials provided but not via token query, send AUTH message\r\n const auth = this.options.auth\r\n if (auth && !auth.token && Object.keys(auth).some(k => auth[k])) {\r\n this.sendMessageAndWait({ type: 'AUTH', payload: auth } as any)\r\n .then(authResp => {\r\n if ((authResp as any).authenticated) {\r\n this.setState({ authenticated: true })\r\n }\r\n })\r\n .catch(() => {})\r\n }\r\n }\r\n\r\n // Handle auth response\r\n if (response.type === 'AUTH_RESPONSE') {\r\n this.setState({ authenticated: (response as any).authenticated || false })\r\n }\r\n\r\n // Handle pending requests (request-response pattern)\r\n if (response.requestId && this.pendingRequests.has(response.requestId)) {\r\n const request = this.pendingRequests.get(response.requestId)!\r\n clearTimeout(request.timeout)\r\n this.pendingRequests.delete(response.requestId)\r\n\r\n if (response.success !== false) {\r\n request.resolve(response)\r\n } else {\r\n if (response.error?.includes?.('COMPONENT_REHYDRATION_REQUIRED')) {\r\n request.resolve(response)\r\n } else {\r\n request.reject(new Error(response.error || 'Request failed'))\r\n }\r\n }\r\n return\r\n }\r\n\r\n // Broadcast messages go to ALL components (not just sender)\r\n if (response.type === 'BROADCAST') {\r\n this.componentCallbacks.forEach((callback, compId) => {\r\n if (compId !== response.componentId) {\r\n callback(response)\r\n }\r\n })\r\n return\r\n }\r\n\r\n // Route message to specific component\r\n if (response.componentId) {\r\n const callback = this.componentCallbacks.get(response.componentId)\r\n if (callback) {\r\n callback(response)\r\n } else {\r\n this.log('No callback registered for component:', response.componentId)\r\n }\r\n }\r\n }\r\n\r\n /** Send message without waiting for response */\r\n async sendMessage(message: WebSocketMessage): Promise<void> {\r\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\r\n throw new Error('WebSocket is not connected')\r\n }\r\n const messageWithTimestamp = { ...message, timestamp: Date.now() }\r\n this.ws.send(JSON.stringify(messageWithTimestamp))\r\n this.log('Sent', { type: message.type, componentId: message.componentId })\r\n }\r\n\r\n /** Send message and wait for response */\r\n async sendMessageAndWait(message: WebSocketMessage, timeout = 10000): Promise<WebSocketResponse> {\r\n return new Promise((resolve, reject) => {\r\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\r\n reject(new Error('WebSocket is not connected'))\r\n return\r\n }\r\n\r\n const requestId = this.generateRequestId()\r\n\r\n const timeoutHandle = setTimeout(() => {\r\n this.pendingRequests.delete(requestId)\r\n reject(new Error(`Request timeout after ${timeout}ms`))\r\n }, timeout)\r\n\r\n this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle })\r\n\r\n try {\r\n const messageWithRequestId = {\r\n ...message,\r\n requestId,\r\n expectResponse: true,\r\n timestamp: Date.now(),\r\n }\r\n this.ws.send(JSON.stringify(messageWithRequestId))\r\n this.log('Sent with requestId', { requestId, type: message.type })\r\n } catch (error) {\r\n clearTimeout(timeoutHandle)\r\n this.pendingRequests.delete(requestId)\r\n reject(error)\r\n }\r\n })\r\n }\r\n\r\n /** Send binary data and wait for response (for file uploads) */\r\n async sendBinaryAndWait(data: ArrayBuffer, requestId: string, timeout = 10000): Promise<WebSocketResponse> {\r\n return new Promise((resolve, reject) => {\r\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\r\n reject(new Error('WebSocket is not connected'))\r\n return\r\n }\r\n\r\n const timeoutHandle = setTimeout(() => {\r\n this.pendingRequests.delete(requestId)\r\n reject(new Error(`Binary request timeout after ${timeout}ms`))\r\n }, timeout)\r\n\r\n this.pendingRequests.set(requestId, { resolve, reject, timeout: timeoutHandle })\r\n\r\n try {\r\n this.ws.send(data)\r\n this.log('Sent binary', { requestId, size: data.byteLength })\r\n } catch (error) {\r\n clearTimeout(timeoutHandle)\r\n this.pendingRequests.delete(requestId)\r\n reject(error)\r\n }\r\n })\r\n }\r\n\r\n /** Register a component message callback */\r\n registerComponent(componentId: string, callback: ComponentCallback): () => void {\r\n this.log('Registering component', componentId)\r\n this.componentCallbacks.set(componentId, callback)\r\n return () => {\r\n this.componentCallbacks.delete(componentId)\r\n this.log('Unregistered component', componentId)\r\n }\r\n }\r\n\r\n /** Unregister a component */\r\n unregisterComponent(componentId: string): void {\r\n this.componentCallbacks.delete(componentId)\r\n }\r\n\r\n /** Authenticate (or re-authenticate) the WebSocket connection */\r\n async authenticate(credentials: LiveAuthOptions): Promise<boolean> {\r\n try {\r\n const response = await this.sendMessageAndWait(\r\n { type: 'AUTH', payload: credentials } as any,\r\n 5000\r\n )\r\n const success = (response as any).authenticated || false\r\n this.setState({ authenticated: success })\r\n return success\r\n } catch {\r\n return false\r\n }\r\n }\r\n\r\n /** Get the raw WebSocket instance */\r\n getWebSocket(): WebSocket | null {\r\n return this.ws\r\n }\r\n\r\n /** Destroy the connection and clean up all resources */\r\n destroy(): void {\r\n this.disconnect()\r\n this.componentCallbacks.clear()\r\n for (const [, req] of this.pendingRequests) {\r\n clearTimeout(req.timeout)\r\n req.reject(new Error('Connection destroyed'))\r\n }\r\n this.pendingRequests.clear()\r\n this.stateListeners.clear()\r\n }\r\n}\r\n","// @fluxstack/live-client - LiveComponentHandle\r\n//\r\n// High-level vanilla JS wrapper for live components.\r\n// Equivalent to Live.use() in @fluxstack/live-react but without React.\r\n//\r\n// Usage:\r\n// const connection = new LiveConnection({ url: 'ws://...' })\r\n// const counter = new LiveComponentHandle(connection, 'Counter', { count: 0 })\r\n// counter.onStateChange((state) => updateUI(state))\r\n// await counter.mount()\r\n// await counter.call('increment')\r\n\r\nimport type { WebSocketResponse } from '@fluxstack/live'\r\nimport type { LiveConnection } from './connection'\r\n\r\nexport interface LiveComponentOptions<TState = Record<string, any>> {\r\n /** Initial state to merge with server defaults */\r\n initialState?: Partial<TState>\r\n /** Room to join on mount */\r\n room?: string\r\n /** User ID for component isolation */\r\n userId?: string\r\n /** Auto-mount when connection is ready. Default: true */\r\n autoMount?: boolean\r\n /** Enable debug logging. Default: false */\r\n debug?: boolean\r\n}\r\n\r\ntype StateChangeCallback<TState> = (state: TState, delta: Partial<TState> | null) => void\r\ntype ErrorCallback = (error: string) => void\r\n\r\n/**\r\n * High-level handle for a live component instance.\r\n * Manages mount lifecycle, state sync, and action calling.\r\n * Framework-agnostic — works with vanilla JS, Vue, Svelte, etc.\r\n */\r\nexport class LiveComponentHandle<TState extends Record<string, any> = Record<string, any>> {\r\n private connection: LiveConnection\r\n private componentName: string\r\n private options: Required<Omit<LiveComponentOptions<TState>, 'initialState' | 'room' | 'userId'>> & {\r\n initialState: Partial<TState>\r\n room?: string\r\n userId?: string\r\n }\r\n\r\n private _componentId: string | null = null\r\n private _state: TState\r\n private _mounted = false\r\n private _mounting = false\r\n private _error: string | null = null\r\n\r\n private stateListeners = new Set<StateChangeCallback<TState>>()\r\n private errorListeners = new Set<ErrorCallback>()\r\n private unregisterComponent: (() => void) | null = null\r\n private unsubConnection: (() => void) | null = null\r\n\r\n constructor(\r\n connection: LiveConnection,\r\n componentName: string,\r\n options: LiveComponentOptions<TState> = {},\r\n ) {\r\n this.connection = connection\r\n this.componentName = componentName\r\n this._state = (options.initialState ?? {}) as TState\r\n\r\n this.options = {\r\n initialState: options.initialState ?? {},\r\n room: options.room,\r\n userId: options.userId,\r\n autoMount: options.autoMount ?? true,\r\n debug: options.debug ?? false,\r\n }\r\n\r\n // Auto-mount when connection is ready\r\n if (this.options.autoMount) {\r\n if (this.connection.state.connected) {\r\n this.mount()\r\n }\r\n this.unsubConnection = this.connection.onStateChange((connState) => {\r\n if (connState.connected && !this._mounted && !this._mounting) {\r\n this.mount()\r\n }\r\n })\r\n }\r\n }\r\n\r\n // ── Getters ──\r\n\r\n /** Current component state */\r\n get state(): Readonly<TState> { return this._state }\r\n\r\n /** Server-assigned component ID (null before mount) */\r\n get componentId(): string | null { return this._componentId }\r\n\r\n /** Whether the component has been mounted */\r\n get mounted(): boolean { return this._mounted }\r\n\r\n /** Whether the component is currently mounting */\r\n get mounting(): boolean { return this._mounting }\r\n\r\n /** Last error message */\r\n get error(): string | null { return this._error }\r\n\r\n // ── Lifecycle ──\r\n\r\n /** Mount the component on the server */\r\n async mount(): Promise<void> {\r\n if (this._mounted || this._mounting) return\r\n if (!this.connection.state.connected) {\r\n throw new Error('Cannot mount: not connected')\r\n }\r\n\r\n this._mounting = true\r\n this._error = null\r\n this.log('Mounting...')\r\n\r\n try {\r\n const response = await this.connection.sendMessageAndWait({\r\n type: 'COMPONENT_MOUNT',\r\n componentId: `mount-${this.componentName}`,\r\n payload: {\r\n component: this.componentName,\r\n props: this.options.initialState,\r\n room: this.options.room,\r\n userId: this.options.userId,\r\n },\r\n })\r\n\r\n if (!response.success) {\r\n throw new Error(response.error || 'Mount failed')\r\n }\r\n\r\n const result = (response as any).result\r\n this._componentId = result.componentId\r\n this._mounted = true\r\n this._mounting = false\r\n\r\n // Merge initial state from server\r\n const serverState = result.initialState || {}\r\n this._state = { ...this._state, ...serverState }\r\n\r\n // Register for component messages (state updates, deltas, errors)\r\n this.unregisterComponent = this.connection.registerComponent(\r\n this._componentId!,\r\n (msg) => this.handleServerMessage(msg),\r\n )\r\n\r\n this.log('Mounted', { componentId: this._componentId })\r\n this.notifyStateChange(this._state, null)\r\n } catch (err) {\r\n this._mounting = false\r\n const errorMsg = err instanceof Error ? err.message : String(err)\r\n this._error = errorMsg\r\n this.notifyError(errorMsg)\r\n throw err\r\n }\r\n }\r\n\r\n /** Unmount the component from the server */\r\n async unmount(): Promise<void> {\r\n if (!this._mounted || !this._componentId) return\r\n\r\n this.log('Unmounting...')\r\n\r\n try {\r\n await this.connection.sendMessage({\r\n type: 'COMPONENT_UNMOUNT',\r\n componentId: this._componentId,\r\n })\r\n } catch {\r\n // Ignore unmount errors (connection may already be closed)\r\n }\r\n\r\n this.cleanup()\r\n }\r\n\r\n /** Destroy the handle and clean up all resources */\r\n destroy(): void {\r\n this.unmount().catch(() => {})\r\n if (this.unsubConnection) {\r\n this.unsubConnection()\r\n this.unsubConnection = null\r\n }\r\n this.stateListeners.clear()\r\n this.errorListeners.clear()\r\n }\r\n\r\n // ── Actions ──\r\n\r\n /**\r\n * Call an action on the server component.\r\n * Returns the action's return value.\r\n */\r\n async call<R = any>(action: string, payload: Record<string, any> = {}): Promise<R> {\r\n if (!this._mounted || !this._componentId) {\r\n throw new Error(`Cannot call '${action}': component not mounted`)\r\n }\r\n\r\n this.log(`Calling action: ${action}`, payload)\r\n\r\n const response = await this.connection.sendMessageAndWait({\r\n type: 'CALL_ACTION',\r\n componentId: this._componentId,\r\n action,\r\n payload,\r\n })\r\n\r\n if (!response.success) {\r\n const errorMsg = response.error || `Action '${action}' failed`\r\n this._error = errorMsg\r\n this.notifyError(errorMsg)\r\n throw new Error(errorMsg)\r\n }\r\n\r\n return (response as any).result\r\n }\r\n\r\n // ── State ──\r\n\r\n /**\r\n * Subscribe to state changes.\r\n * Callback receives the full new state and the delta (or null for full updates).\r\n * Returns an unsubscribe function.\r\n */\r\n onStateChange(callback: StateChangeCallback<TState>): () => void {\r\n this.stateListeners.add(callback)\r\n return () => { this.stateListeners.delete(callback) }\r\n }\r\n\r\n /**\r\n * Subscribe to errors.\r\n * Returns an unsubscribe function.\r\n */\r\n onError(callback: ErrorCallback): () => void {\r\n this.errorListeners.add(callback)\r\n return () => { this.errorListeners.delete(callback) }\r\n }\r\n\r\n // ── Internal ──\r\n\r\n private handleServerMessage(msg: WebSocketResponse): void {\r\n switch (msg.type) {\r\n case 'STATE_UPDATE': {\r\n const newState = (msg as any).payload?.state\r\n if (newState) {\r\n this._state = { ...this._state, ...newState }\r\n this.notifyStateChange(this._state, null)\r\n }\r\n break\r\n }\r\n\r\n case 'STATE_DELTA': {\r\n const delta = (msg as any).payload?.delta\r\n if (delta) {\r\n this._state = { ...this._state, ...delta }\r\n this.notifyStateChange(this._state, delta)\r\n }\r\n break\r\n }\r\n\r\n case 'ERROR': {\r\n const error = (msg as any).error || 'Unknown error'\r\n this._error = error\r\n this.notifyError(error)\r\n break\r\n }\r\n\r\n default:\r\n this.log('Unhandled message type:', msg.type)\r\n }\r\n }\r\n\r\n private notifyStateChange(state: TState, delta: Partial<TState> | null): void {\r\n for (const cb of this.stateListeners) {\r\n cb(state, delta)\r\n }\r\n }\r\n\r\n private notifyError(error: string): void {\r\n for (const cb of this.errorListeners) {\r\n cb(error)\r\n }\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.unregisterComponent) {\r\n this.unregisterComponent()\r\n this.unregisterComponent = null\r\n }\r\n this._componentId = null\r\n this._mounted = false\r\n this._mounting = false\r\n }\r\n\r\n private log(message: string, data?: any): void {\r\n if (this.options.debug) {\r\n console.log(`[Live:${this.componentName}] ${message}`, data ?? '')\r\n }\r\n }\r\n}\r\n","// @fluxstack/live-client - Room Manager (Client-side)\r\n//\r\n// Framework-agnostic room system for managing multi-room WebSocket communication.\r\n// Used by framework-specific adapters (React, Vue, etc.).\r\n\r\ntype EventHandler<T = any> = (data: T) => void\r\ntype Unsubscribe = () => void\r\n\r\n/** Message from client to server */\r\nexport interface RoomClientMessage {\r\n type: 'ROOM_JOIN' | 'ROOM_LEAVE' | 'ROOM_EMIT' | 'ROOM_STATE_GET' | 'ROOM_STATE_SET'\r\n componentId: string\r\n roomId: string\r\n event?: string\r\n data?: any\r\n timestamp: number\r\n}\r\n\r\n/** Message from server to client */\r\nexport interface RoomServerMessage {\r\n type: 'ROOM_EVENT' | 'ROOM_STATE' | 'ROOM_SYSTEM' | 'ROOM_JOINED' | 'ROOM_LEFT'\r\n componentId: string\r\n roomId: string\r\n event: string\r\n data: any\r\n timestamp: number\r\n}\r\n\r\n/** Interface of an individual room handle */\r\nexport interface RoomHandle<TState = any, TEvents extends Record<string, any> = Record<string, any>> {\r\n readonly id: string\r\n readonly joined: boolean\r\n readonly state: TState\r\n join: (initialState?: TState) => Promise<void>\r\n leave: () => Promise<void>\r\n emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => void\r\n on: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>) => Unsubscribe\r\n onSystem: (event: string, handler: EventHandler) => Unsubscribe\r\n setState: (updates: Partial<TState>) => void\r\n}\r\n\r\n/** Proxy interface for $room - callable as function or object */\r\nexport interface RoomProxy<TState = any, TEvents extends Record<string, any> = Record<string, any>> {\r\n (roomId: string): RoomHandle<TState, TEvents>\r\n readonly id: string | null\r\n readonly joined: boolean\r\n readonly state: TState\r\n join: (initialState?: TState) => Promise<void>\r\n leave: () => Promise<void>\r\n emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => void\r\n on: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>) => Unsubscribe\r\n onSystem: (event: string, handler: EventHandler) => Unsubscribe\r\n setState: (updates: Partial<TState>) => void\r\n}\r\n\r\nexport interface RoomManagerOptions {\r\n componentId: string | null\r\n defaultRoom?: string\r\n sendMessage: (msg: any) => void\r\n sendMessageAndWait: (msg: any, timeout?: number) => Promise<any>\r\n onMessage: (handler: (msg: RoomServerMessage) => void) => Unsubscribe\r\n}\r\n\r\n/** Client-side room manager. Framework-agnostic. */\r\nexport class RoomManager<TState = any, TEvents extends Record<string, any> = Record<string, any>> {\r\n private componentId: string | null\r\n private defaultRoom: string | null\r\n private rooms = new Map<string, {\r\n joined: boolean\r\n state: TState\r\n handlers: Map<string, Set<EventHandler>>\r\n }>()\r\n private handles = new Map<string, RoomHandle<TState, TEvents>>()\r\n private sendMessage: (msg: any) => void\r\n private sendMessageAndWait: (msg: any, timeout?: number) => Promise<any>\r\n private globalUnsubscribe: Unsubscribe | null = null\r\n\r\n constructor(options: RoomManagerOptions) {\r\n this.componentId = options.componentId\r\n this.defaultRoom = options.defaultRoom || null\r\n this.sendMessage = options.sendMessage\r\n this.sendMessageAndWait = options.sendMessageAndWait\r\n this.globalUnsubscribe = options.onMessage((msg) => this.handleServerMessage(msg))\r\n }\r\n\r\n private handleServerMessage(msg: RoomServerMessage): void {\r\n if (msg.componentId !== this.componentId) return\r\n\r\n const room = this.rooms.get(msg.roomId)\r\n if (!room) return\r\n\r\n switch (msg.type) {\r\n case 'ROOM_EVENT':\r\n case 'ROOM_SYSTEM': {\r\n const handlers = room.handlers.get(msg.event)\r\n if (handlers) {\r\n for (const handler of handlers) {\r\n try { handler(msg.data) } catch (error) {\r\n console.error(`[Room:${msg.roomId}] Handler error for '${msg.event}':`, error)\r\n }\r\n }\r\n }\r\n break\r\n }\r\n\r\n case 'ROOM_STATE': {\r\n room.state = { ...room.state, ...msg.data }\r\n const stateHandlers = room.handlers.get('$state:change')\r\n if (stateHandlers) {\r\n for (const handler of stateHandlers) handler(msg.data)\r\n }\r\n break\r\n }\r\n\r\n case 'ROOM_JOINED':\r\n room.joined = true\r\n if (msg.data?.state) room.state = msg.data.state\r\n break\r\n\r\n case 'ROOM_LEFT':\r\n room.joined = false\r\n break\r\n }\r\n }\r\n\r\n private getOrCreateRoom(roomId: string) {\r\n if (!this.rooms.has(roomId)) {\r\n this.rooms.set(roomId, {\r\n joined: false,\r\n state: {} as TState,\r\n handlers: new Map(),\r\n })\r\n }\r\n return this.rooms.get(roomId)!\r\n }\r\n\r\n /** Create handle for a specific room (cached) */\r\n createHandle(roomId: string): RoomHandle<TState, TEvents> {\r\n if (this.handles.has(roomId)) return this.handles.get(roomId)!\r\n\r\n const room = this.getOrCreateRoom(roomId)\r\n\r\n const handle: RoomHandle<TState, TEvents> = {\r\n get id() { return roomId },\r\n get joined() { return room.joined },\r\n get state() { return room.state },\r\n\r\n join: async (initialState?: TState) => {\r\n if (!this.componentId) throw new Error('Component not mounted')\r\n if (room.joined) return\r\n\r\n if (initialState) room.state = initialState\r\n\r\n const response = await this.sendMessageAndWait({\r\n type: 'ROOM_JOIN',\r\n componentId: this.componentId,\r\n roomId,\r\n data: { initialState: room.state },\r\n timestamp: Date.now(),\r\n }, 5000)\r\n\r\n if (response?.success) {\r\n room.joined = true\r\n if (response.state) room.state = response.state\r\n }\r\n },\r\n\r\n leave: async () => {\r\n if (!this.componentId || !room.joined) return\r\n\r\n await this.sendMessageAndWait({\r\n type: 'ROOM_LEAVE',\r\n componentId: this.componentId,\r\n roomId,\r\n timestamp: Date.now(),\r\n }, 5000)\r\n\r\n room.joined = false\r\n room.handlers.clear()\r\n },\r\n\r\n emit: <K extends keyof TEvents>(event: K, data: TEvents[K]) => {\r\n if (!this.componentId) return\r\n this.sendMessage({\r\n type: 'ROOM_EMIT',\r\n componentId: this.componentId,\r\n roomId,\r\n event: event as string,\r\n data,\r\n timestamp: Date.now(),\r\n })\r\n },\r\n\r\n on: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): Unsubscribe => {\r\n const eventKey = event as string\r\n if (!room.handlers.has(eventKey)) room.handlers.set(eventKey, new Set())\r\n room.handlers.get(eventKey)!.add(handler)\r\n return () => { room.handlers.get(eventKey)?.delete(handler) }\r\n },\r\n\r\n onSystem: (event: string, handler: EventHandler): Unsubscribe => {\r\n const eventKey = `$${event}`\r\n if (!room.handlers.has(eventKey)) room.handlers.set(eventKey, new Set())\r\n room.handlers.get(eventKey)!.add(handler)\r\n return () => { room.handlers.get(eventKey)?.delete(handler) }\r\n },\r\n\r\n setState: (updates: Partial<TState>) => {\r\n if (!this.componentId) return\r\n room.state = { ...room.state, ...updates }\r\n this.sendMessage({\r\n type: 'ROOM_STATE_SET',\r\n componentId: this.componentId,\r\n roomId,\r\n data: updates,\r\n timestamp: Date.now(),\r\n })\r\n },\r\n }\r\n\r\n this.handles.set(roomId, handle)\r\n return handle\r\n }\r\n\r\n /** Create the $room proxy */\r\n createProxy(): RoomProxy<TState, TEvents> {\r\n const self = this\r\n\r\n const proxyFn = function(roomId: string): RoomHandle<TState, TEvents> {\r\n return self.createHandle(roomId)\r\n } as RoomProxy<TState, TEvents>\r\n\r\n const defaultHandle = this.defaultRoom ? this.createHandle(this.defaultRoom) : null\r\n\r\n Object.defineProperties(proxyFn, {\r\n id: { get: () => this.defaultRoom },\r\n joined: { get: () => defaultHandle?.joined ?? false },\r\n state: { get: () => defaultHandle?.state ?? ({} as TState) },\r\n join: {\r\n value: async (initialState?: TState) => {\r\n if (!defaultHandle) throw new Error('No default room set')\r\n return defaultHandle.join(initialState)\r\n },\r\n },\r\n leave: {\r\n value: async () => {\r\n if (!defaultHandle) throw new Error('No default room set')\r\n return defaultHandle.leave()\r\n },\r\n },\r\n emit: {\r\n value: <K extends keyof TEvents>(event: K, data: TEvents[K]) => {\r\n if (!defaultHandle) throw new Error('No default room set')\r\n return defaultHandle.emit(event, data)\r\n },\r\n },\r\n on: {\r\n value: <K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): Unsubscribe => {\r\n if (!defaultHandle) throw new Error('No default room set')\r\n return defaultHandle.on(event, handler)\r\n },\r\n },\r\n onSystem: {\r\n value: (event: string, handler: EventHandler): Unsubscribe => {\r\n if (!defaultHandle) throw new Error('No default room set')\r\n return defaultHandle.onSystem(event, handler)\r\n },\r\n },\r\n setState: {\r\n value: (updates: Partial<TState>) => {\r\n if (!defaultHandle) throw new Error('No default room set')\r\n return defaultHandle.setState(updates)\r\n },\r\n },\r\n })\r\n\r\n return proxyFn\r\n }\r\n\r\n /** List of rooms currently joined */\r\n getJoinedRooms(): string[] {\r\n const joined: string[] = []\r\n for (const [id, room] of this.rooms) {\r\n if (room.joined) joined.push(id)\r\n }\r\n return joined\r\n }\r\n\r\n /** Update componentId (when component mounts) */\r\n setComponentId(id: string | null): void {\r\n this.componentId = id\r\n }\r\n\r\n /** Cleanup */\r\n destroy(): void {\r\n this.globalUnsubscribe?.()\r\n for (const [, room] of this.rooms) {\r\n room.handlers.clear()\r\n }\r\n this.rooms.clear()\r\n this.handles.clear()\r\n }\r\n}\r\n\r\nexport type { EventHandler, Unsubscribe }\r\n","// @fluxstack/live-client - Chunked Upload Manager\r\n//\r\n// Framework-agnostic chunked file upload with adaptive sizing and binary protocol.\r\n\r\nimport type {\r\n FileUploadStartMessage,\r\n FileUploadChunkMessage,\r\n FileUploadCompleteMessage,\r\n FileUploadProgressResponse,\r\n FileUploadCompleteResponse,\r\n BinaryChunkHeader,\r\n} from '@fluxstack/live'\r\n\r\n// ===== Adaptive Chunk Sizer =====\r\n\r\nexport interface AdaptiveChunkConfig {\r\n minChunkSize: number\r\n maxChunkSize: number\r\n initialChunkSize: number\r\n targetLatency: number\r\n adjustmentFactor: number\r\n measurementWindow: number\r\n}\r\n\r\nexport interface ChunkMetrics {\r\n chunkIndex: number\r\n chunkSize: number\r\n startTime: number\r\n endTime: number\r\n latency: number\r\n throughput: number\r\n success: boolean\r\n}\r\n\r\nexport class AdaptiveChunkSizer {\r\n private config: Required<AdaptiveChunkConfig>\r\n private currentChunkSize: number\r\n private metrics: ChunkMetrics[] = []\r\n private consecutiveErrors = 0\r\n private consecutiveSuccesses = 0\r\n\r\n constructor(config: Partial<AdaptiveChunkConfig> = {}) {\r\n this.config = {\r\n minChunkSize: config.minChunkSize ?? 16 * 1024,\r\n maxChunkSize: config.maxChunkSize ?? 1024 * 1024,\r\n initialChunkSize: config.initialChunkSize ?? 64 * 1024,\r\n targetLatency: config.targetLatency ?? 200,\r\n adjustmentFactor: config.adjustmentFactor ?? 1.5,\r\n measurementWindow: config.measurementWindow ?? 3,\r\n }\r\n this.currentChunkSize = this.config.initialChunkSize\r\n }\r\n\r\n getChunkSize(): number {\r\n return this.currentChunkSize\r\n }\r\n\r\n recordChunkStart(_chunkIndex: number): number {\r\n return Date.now()\r\n }\r\n\r\n recordChunkComplete(chunkIndex: number, chunkSize: number, startTime: number, success: boolean): void {\r\n const endTime = Date.now()\r\n const latency = endTime - startTime\r\n const throughput = success ? (chunkSize / latency) * 1000 : 0\r\n\r\n this.metrics.push({ chunkIndex, chunkSize, startTime, endTime, latency, throughput, success })\r\n\r\n if (this.metrics.length > this.config.measurementWindow * 2) {\r\n this.metrics = this.metrics.slice(-this.config.measurementWindow * 2)\r\n }\r\n\r\n if (success) {\r\n this.consecutiveSuccesses++\r\n this.consecutiveErrors = 0\r\n this.adjustUp(latency)\r\n } else {\r\n this.consecutiveErrors++\r\n this.consecutiveSuccesses = 0\r\n this.adjustDown()\r\n }\r\n }\r\n\r\n private adjustUp(latency: number): void {\r\n if (this.consecutiveSuccesses < 2) return\r\n if (latency > this.config.targetLatency) return\r\n\r\n const latencyRatio = this.config.targetLatency / latency\r\n let newSize = Math.floor(this.currentChunkSize * Math.min(latencyRatio, this.config.adjustmentFactor))\r\n newSize = Math.min(newSize, this.config.maxChunkSize)\r\n if (newSize > this.currentChunkSize) this.currentChunkSize = newSize\r\n }\r\n\r\n private adjustDown(): void {\r\n const decreaseFactor = this.consecutiveErrors > 1 ? 2 : this.config.adjustmentFactor\r\n let newSize = Math.floor(this.currentChunkSize / decreaseFactor)\r\n newSize = Math.max(newSize, this.config.minChunkSize)\r\n if (newSize < this.currentChunkSize) this.currentChunkSize = newSize\r\n }\r\n\r\n getAverageThroughput(): number {\r\n const recent = this.metrics.slice(-this.config.measurementWindow).filter(m => m.success)\r\n if (recent.length === 0) return 0\r\n return recent.reduce((sum, m) => sum + m.throughput, 0) / recent.length\r\n }\r\n\r\n getStats() {\r\n return {\r\n currentChunkSize: this.currentChunkSize,\r\n averageThroughput: this.getAverageThroughput(),\r\n consecutiveSuccesses: this.consecutiveSuccesses,\r\n consecutiveErrors: this.consecutiveErrors,\r\n totalMeasurements: this.metrics.length,\r\n }\r\n }\r\n\r\n reset(): void {\r\n this.currentChunkSize = this.config.initialChunkSize\r\n this.metrics = []\r\n this.consecutiveErrors = 0\r\n this.consecutiveSuccesses = 0\r\n }\r\n}\r\n\r\n// ===== Binary Protocol =====\r\n\r\n/**\r\n * Creates a binary message with header + data\r\n * Format: [4 bytes header length LE][JSON header][binary data]\r\n */\r\nexport function createBinaryChunkMessage(header: BinaryChunkHeader, chunkData: Uint8Array): ArrayBuffer {\r\n const headerJson = JSON.stringify(header)\r\n const headerBytes = new TextEncoder().encode(headerJson)\r\n\r\n const totalSize = 4 + headerBytes.length + chunkData.length\r\n const buffer = new ArrayBuffer(totalSize)\r\n const view = new DataView(buffer)\r\n const uint8View = new Uint8Array(buffer)\r\n\r\n view.setUint32(0, headerBytes.length, true)\r\n uint8View.set(headerBytes, 4)\r\n uint8View.set(chunkData, 4 + headerBytes.length)\r\n\r\n return buffer\r\n}\r\n\r\n// ===== Chunked Uploader =====\r\n\r\nexport interface ChunkedUploadOptions {\r\n chunkSize?: number\r\n maxFileSize?: number\r\n allowedTypes?: string[]\r\n sendMessageAndWait: (message: any, timeout?: number) => Promise<any>\r\n sendBinaryAndWait?: (data: ArrayBuffer, requestId: string, timeout?: number) => Promise<any>\r\n onProgress?: (progress: number, bytesUploaded: number, totalBytes: number) => void\r\n onComplete?: (response: FileUploadCompleteResponse) => void\r\n onError?: (error: string) => void\r\n adaptiveChunking?: boolean\r\n adaptiveConfig?: Partial<AdaptiveChunkConfig>\r\n useBinaryProtocol?: boolean\r\n}\r\n\r\nexport interface ChunkedUploadState {\r\n uploading: boolean\r\n progress: number\r\n error: string | null\r\n uploadId: string | null\r\n bytesUploaded: number\r\n totalBytes: number\r\n}\r\n\r\n/**\r\n * Framework-agnostic chunked file uploader.\r\n * Manages the upload lifecycle without any UI framework dependency.\r\n */\r\nexport class ChunkedUploader {\r\n private options: Required<Pick<ChunkedUploadOptions, 'chunkSize' | 'maxFileSize' | 'allowedTypes' | 'useBinaryProtocol' | 'adaptiveChunking'>> & ChunkedUploadOptions\r\n private abortController: AbortController | null = null\r\n private adaptiveSizer: AdaptiveChunkSizer | null = null\r\n private _state: ChunkedUploadState = {\r\n uploading: false,\r\n progress: 0,\r\n error: null,\r\n uploadId: null,\r\n bytesUploaded: 0,\r\n totalBytes: 0,\r\n }\r\n private stateListeners = new Set<(state: ChunkedUploadState) => void>()\r\n\r\n constructor(\r\n private componentId: string,\r\n options: ChunkedUploadOptions,\r\n ) {\r\n this.options = {\r\n chunkSize: options.chunkSize ?? 64 * 1024,\r\n maxFileSize: options.maxFileSize ?? 50 * 1024 * 1024,\r\n allowedTypes: options.allowedTypes ?? [],\r\n useBinaryProtocol: options.useBinaryProtocol ?? true,\r\n adaptiveChunking: options.adaptiveChunking ?? false,\r\n ...options,\r\n }\r\n\r\n if (this.options.adaptiveChunking) {\r\n this.adaptiveSizer = new AdaptiveChunkSizer({\r\n initialChunkSize: this.options.chunkSize,\r\n minChunkSize: this.options.chunkSize,\r\n maxChunkSize: 1024 * 1024,\r\n ...options.adaptiveConfig,\r\n })\r\n }\r\n }\r\n\r\n get state(): ChunkedUploadState {\r\n return { ...this._state }\r\n }\r\n\r\n onStateChange(callback: (state: ChunkedUploadState) => void): () => void {\r\n this.stateListeners.add(callback)\r\n return () => { this.stateListeners.delete(callback) }\r\n }\r\n\r\n private setState(patch: Partial<ChunkedUploadState>) {\r\n this._state = { ...this._state, ...patch }\r\n for (const cb of this.stateListeners) cb(this._state)\r\n }\r\n\r\n async uploadFile(file: File): Promise<void> {\r\n const { allowedTypes, maxFileSize, chunkSize, sendMessageAndWait, sendBinaryAndWait, useBinaryProtocol } = this.options\r\n const canUseBinary = useBinaryProtocol && sendBinaryAndWait\r\n\r\n // Validate\r\n if (allowedTypes.length > 0 && !allowedTypes.includes(file.type)) {\r\n const error = `Invalid file type: ${file.type}. Allowed: ${allowedTypes.join(', ')}`\r\n this.setState({ error })\r\n this.options.onError?.(error)\r\n return\r\n }\r\n\r\n if (file.size > maxFileSize) {\r\n const error = `File too large: ${file.size} bytes. Max: ${maxFileSize} bytes`\r\n this.setState({ error })\r\n this.options.onError?.(error)\r\n return\r\n }\r\n\r\n try {\r\n const uploadId = `upload-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`\r\n this.abortController = new AbortController()\r\n this.adaptiveSizer?.reset()\r\n\r\n this.setState({ uploading: true, progress: 0, error: null, uploadId, bytesUploaded: 0, totalBytes: file.size })\r\n\r\n const initialChunkSize = this.adaptiveSizer?.getChunkSize() ?? chunkSize\r\n\r\n // Start upload\r\n const startMessage: FileUploadStartMessage = {\r\n type: 'FILE_UPLOAD_START',\r\n componentId: this.componentId,\r\n uploadId,\r\n filename: file.name,\r\n fileType: file.type,\r\n fileSize: file.size,\r\n chunkSize,\r\n requestId: `start-${uploadId}`,\r\n }\r\n\r\n const startResponse = await sendMessageAndWait(startMessage, 10000)\r\n if (!startResponse?.success) throw new Error(startResponse?.error || 'Failed to start upload')\r\n\r\n let offset = 0\r\n let chunkIndex = 0\r\n const estimatedTotalChunks = Math.ceil(file.size / initialChunkSize)\r\n\r\n while (offset < file.size) {\r\n if (this.abortController?.signal.aborted) throw new Error('Upload cancelled')\r\n\r\n const currentChunkSize = this.adaptiveSizer?.getChunkSize() ?? chunkSize\r\n const chunkEnd = Math.min(offset + currentChunkSize, file.size)\r\n const sliceBuffer = await file.slice(offset, chunkEnd).arrayBuffer()\r\n const chunkBytes = new Uint8Array(sliceBuffer)\r\n const chunkStartTime = this.adaptiveSizer?.recordChunkStart(chunkIndex) ?? 0\r\n const requestId = `chunk-${uploadId}-${chunkIndex}`\r\n\r\n try {\r\n let progressResponse: FileUploadProgressResponse | undefined\r\n\r\n if (canUseBinary) {\r\n const header: BinaryChunkHeader = {\r\n type: 'FILE_UPLOAD_CHUNK',\r\n componentId: this.componentId,\r\n uploadId,\r\n chunkIndex,\r\n totalChunks: estimatedTotalChunks,\r\n requestId,\r\n }\r\n const binaryMessage = createBinaryChunkMessage(header, chunkBytes)\r\n progressResponse = await sendBinaryAndWait!(binaryMessage, requestId, 10000) as FileUploadProgressResponse\r\n } else {\r\n let binary = ''\r\n for (let j = 0; j < chunkBytes.length; j++) binary += String.fromCharCode(chunkBytes[j])\r\n\r\n const chunkMessage: FileUploadChunkMessage = {\r\n type: 'FILE_UPLOAD_CHUNK',\r\n componentId: this.componentId,\r\n uploadId,\r\n chunkIndex,\r\n totalChunks: estimatedTotalChunks,\r\n data: btoa(binary),\r\n requestId,\r\n }\r\n progressResponse = await sendMessageAndWait!(chunkMessage, 10000) as FileUploadProgressResponse\r\n }\r\n\r\n if (progressResponse) {\r\n this.setState({ progress: progressResponse.progress, bytesUploaded: progressResponse.bytesUploaded })\r\n this.options.onProgress?.(progressResponse.progress, progressResponse.bytesUploaded, file.size)\r\n }\r\n\r\n this.adaptiveSizer?.recordChunkComplete(chunkIndex, chunkBytes.length, chunkStartTime, true)\r\n } catch (error) {\r\n this.adaptiveSizer?.recordChunkComplete(chunkIndex, chunkBytes.length, chunkStartTime, false)\r\n throw error\r\n }\r\n\r\n offset += chunkBytes.length\r\n chunkIndex++\r\n\r\n if (!this.options.adaptiveChunking) {\r\n await new Promise(resolve => setTimeout(resolve, 10))\r\n }\r\n }\r\n\r\n // Complete\r\n const completeMessage: FileUploadCompleteMessage = {\r\n type: 'FILE_UPLOAD_COMPLETE',\r\n componentId: this.componentId,\r\n uploadId,\r\n requestId: `complete-${uploadId}`,\r\n }\r\n\r\n const completeResponse = await sendMessageAndWait(completeMessage, 10000) as FileUploadCompleteResponse\r\n\r\n if (completeResponse?.success) {\r\n this.setState({ uploading: false, progress: 100, bytesUploaded: file.size })\r\n this.options.onComplete?.(completeResponse)\r\n } else {\r\n throw new Error(completeResponse?.error || 'Upload completion failed')\r\n }\r\n } catch (error: any) {\r\n this.setState({ uploading: false, error: error.message })\r\n this.options.onError?.(error.message)\r\n }\r\n }\r\n\r\n cancelUpload(): void {\r\n if (this.abortController) {\r\n this.abortController.abort()\r\n this.setState({ uploading: false, error: 'Upload cancelled' })\r\n }\r\n }\r\n\r\n reset(): void {\r\n this._state = { uploading: false, progress: 0, error: null, uploadId: null, bytesUploaded: 0, totalBytes: 0 }\r\n for (const cb of this.stateListeners) cb(this._state)\r\n }\r\n}\r\n","// @fluxstack/live-client - State Persistence\r\n//\r\n// Utilities for persisting and recovering component state via localStorage.\r\n\r\nconst STORAGE_KEY_PREFIX = 'fluxstack_component_'\r\nconst STATE_MAX_AGE = 24 * 60 * 60 * 1000 // 24 hours\r\n\r\nexport interface PersistedState {\r\n componentName: string\r\n signedState: any\r\n room?: string\r\n userId?: string\r\n lastUpdate: number\r\n}\r\n\r\nexport function persistState(\r\n enabled: boolean,\r\n name: string,\r\n signedState: any,\r\n room?: string,\r\n userId?: string,\r\n): void {\r\n if (!enabled) return\r\n try {\r\n localStorage.setItem(`${STORAGE_KEY_PREFIX}${name}`, JSON.stringify({\r\n componentName: name, signedState, room, userId, lastUpdate: Date.now(),\r\n }))\r\n } catch {}\r\n}\r\n\r\nexport function getPersistedState(enabled: boolean, name: string): PersistedState | null {\r\n if (!enabled) return null\r\n try {\r\n const stored = localStorage.getItem(`${STORAGE_KEY_PREFIX}${name}`)\r\n if (!stored) return null\r\n const state: PersistedState = JSON.parse(stored)\r\n if (Date.now() - state.lastUpdate > STATE_MAX_AGE) {\r\n localStorage.removeItem(`${STORAGE_KEY_PREFIX}${name}`)\r\n return null\r\n }\r\n return state\r\n } catch { return null }\r\n}\r\n\r\nexport function clearPersistedState(enabled: boolean, name: string): void {\r\n if (!enabled) return\r\n try { localStorage.removeItem(`${STORAGE_KEY_PREFIX}${name}`) } catch {}\r\n}\r\n","// @fluxstack/live-client - State Validation Utilities\r\n\r\nexport interface StateValidation {\r\n checksum: string\r\n version: number\r\n timestamp: number\r\n source: 'client' | 'server' | 'mount'\r\n}\r\n\r\nexport interface StateConflict {\r\n property: string\r\n clientValue: any\r\n serverValue: any\r\n timestamp: number\r\n resolved: boolean\r\n}\r\n\r\nexport interface HybridState<T> {\r\n data: T\r\n validation: StateValidation\r\n status: 'synced' | 'pending' | 'conflict'\r\n}\r\n\r\nexport class StateValidator {\r\n static generateChecksum(state: any): string {\r\n const json = JSON.stringify(state, Object.keys(state).sort())\r\n let hash = 0\r\n for (let i = 0; i < json.length; i++) {\r\n const char = json.charCodeAt(i)\r\n hash = ((hash << 5) - hash) + char\r\n hash = hash & hash\r\n }\r\n return Math.abs(hash).toString(16)\r\n }\r\n\r\n static createValidation(\r\n state: any,\r\n source: 'client' | 'server' | 'mount' = 'client',\r\n ): StateValidation {\r\n return {\r\n checksum: this.generateChecksum(state),\r\n version: Date.now(),\r\n timestamp: Date.now(),\r\n source,\r\n }\r\n }\r\n\r\n static detectConflicts<T>(\r\n clientState: T,\r\n serverState: T,\r\n excludeFields: string[] = ['lastUpdated', 'version'],\r\n ): StateConflict[] {\r\n const conflicts: StateConflict[] = []\r\n const clientKeys = Object.keys(clientState as any)\r\n const serverKeys = Object.keys(serverState as any)\r\n const allKeys = Array.from(new Set([...clientKeys, ...serverKeys]))\r\n\r\n for (const key of allKeys) {\r\n if (excludeFields.includes(key)) continue\r\n const clientValue = (clientState as any)?.[key]\r\n const serverValue = (serverState as any)?.[key]\r\n if (JSON.stringify(clientValue) !== JSON.stringify(serverValue)) {\r\n conflicts.push({\r\n property: key,\r\n clientValue,\r\n serverValue,\r\n timestamp: Date.now(),\r\n resolved: false,\r\n })\r\n }\r\n }\r\n\r\n return conflicts\r\n }\r\n\r\n static mergeStates<T>(\r\n clientState: T,\r\n serverState: T,\r\n conflicts: StateConflict[],\r\n strategy: 'client' | 'server' | 'smart' = 'smart',\r\n ): T {\r\n const merged = { ...clientState }\r\n\r\n for (const conflict of conflicts) {\r\n switch (strategy) {\r\n case 'client':\r\n break\r\n case 'server':\r\n (merged as any)[conflict.property] = conflict.serverValue\r\n break\r\n case 'smart':\r\n if (conflict.property === 'lastUpdated') {\r\n (merged as any)[conflict.property] = conflict.serverValue\r\n } else if (typeof conflict.serverValue === 'number' && typeof conflict.clientValue === 'number') {\r\n (merged as any)[conflict.property] = Math.max(conflict.serverValue, conflict.clientValue)\r\n } else {\r\n (merged as any)[conflict.property] = conflict.serverValue\r\n }\r\n break\r\n }\r\n }\r\n\r\n return merged\r\n }\r\n\r\n static validateState<T>(hybridState: HybridState<T>): boolean {\r\n const currentChecksum = this.generateChecksum(hybridState.data)\r\n return currentChecksum === hybridState.validation.checksum\r\n }\r\n\r\n static updateValidation<T>(\r\n hybridState: HybridState<T>,\r\n source: 'client' | 'server' | 'mount' = 'client',\r\n ): HybridState<T> {\r\n return {\r\n ...hybridState,\r\n validation: this.createValidation(hybridState.data, source),\r\n status: 'synced',\r\n }\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|