@fluxstack/live-client 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/connection.ts CHANGED
@@ -245,16 +245,32 @@ export class LiveConnection {
245
245
  }
246
246
  }
247
247
 
248
+ private consecutiveHeartbeatFailures = 0
249
+ private static readonly MAX_HEARTBEAT_FAILURES = 3
250
+
248
251
  private startHeartbeat(): void {
249
252
  this.stopHeartbeat()
253
+ this.consecutiveHeartbeatFailures = 0
250
254
  this.heartbeatInterval = setInterval(() => {
251
255
  if (this.ws?.readyState === WebSocket.OPEN) {
256
+ let failed = false
252
257
  for (const componentId of this.componentCallbacks.keys()) {
253
258
  this.sendMessage({
254
259
  type: 'COMPONENT_PING',
255
260
  componentId,
256
261
  timestamp: Date.now(),
257
- }).catch(() => {})
262
+ }).catch(() => { failed = true })
263
+ }
264
+ if (failed) {
265
+ this.consecutiveHeartbeatFailures++
266
+ this.log(`Heartbeat failed (${this.consecutiveHeartbeatFailures}/${LiveConnection.MAX_HEARTBEAT_FAILURES})`)
267
+ if (this.consecutiveHeartbeatFailures >= LiveConnection.MAX_HEARTBEAT_FAILURES) {
268
+ this.log('Too many heartbeat failures, reconnecting...')
269
+ this.setState({ error: 'Heartbeat failed' })
270
+ this.reconnect()
271
+ }
272
+ } else {
273
+ this.consecutiveHeartbeatFailures = 0
258
274
  }
259
275
  }
260
276
  }, this.options.heartbeatInterval)
@@ -25,7 +25,11 @@ export function persistState(
25
25
  localStorage.setItem(`${STORAGE_KEY_PREFIX}${name}`, JSON.stringify({
26
26
  componentName: name, signedState, room, userId, lastUpdate: Date.now(),
27
27
  }))
28
- } catch {}
28
+ } catch (e) {
29
+ if (typeof console !== 'undefined') {
30
+ console.warn(`[fluxstack] Failed to persist state for '${name}':`, e instanceof Error ? e.message : e)
31
+ }
32
+ }
29
33
  }
30
34
 
31
35
  export function getPersistedState(enabled: boolean, name: string): PersistedState | null {
package/src/rooms.ts CHANGED
@@ -18,6 +18,10 @@ function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>,
18
18
  const result = { ...target }
19
19
  for (const key of Object.keys(source) as Array<keyof T>) {
20
20
  const newVal = source[key]
21
+ if (newVal === null) {
22
+ delete result[key]
23
+ continue
24
+ }
21
25
  const oldVal = result[key]
22
26
  if (isPlainObject(oldVal) && isPlainObject(newVal)) {
23
27
  result[key] = deepMerge(oldVal as any, newVal as any, seen)