From 55bff3af0073fa8d173bcbca3b79c282ebc96f98 Mon Sep 17 00:00:00 2001 From: Carter Date: Fri, 6 Mar 2026 13:04:46 -0600 Subject: [PATCH 1/2] guarding component web socket a little better --- src/pages/Device.tsx | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/pages/Device.tsx b/src/pages/Device.tsx index 281842d..0fb59a9 100644 --- a/src/pages/Device.tsx +++ b/src/pages/Device.tsx @@ -172,15 +172,25 @@ export default function DevicePage() { // Streams all component changes for this device. // When the backend receives a new reading and updates a component, // this fires and updates the component in state without a page refresh. - useWebSocket<{ key: string; component: Component }>({ - path: `/v1/live/devices/${deviceID}/components`, + useWebSocket<{ key: string; component: Component } | null>({ + path: `/live/devices/${deviceID}/components`, parse: (e) => { - const raw = JSON.parse(e.data); - const comp = Component.any(raw); - return { key: comp.key(), component: comp }; + try { + const raw = JSON.parse(e.data); + const comp = Component.any(raw); + if (!comp?.settings) { + console.warn("[ws] received component without settings:", raw); + return null; + } + return { key: comp.key(), component: comp }; + } catch (err) { + console.warn("[ws] failed to parse component:", err); + return null; + } }, - onMessage: ({ key, component }) => { - // Functional update so we always work with the latest state + onMessage: (data) => { + if (!data) return; + const { key, component } = data; setComponents((prev) => { const updated = new Map(prev); updated.set(key, component); From 4546796db9d35bc5bfd66462ecea74f287be9121 Mon Sep 17 00:00:00 2001 From: Carter Date: Fri, 6 Mar 2026 13:05:30 -0600 Subject: [PATCH 2/2] guarding device web socket a little better --- src/pages/Device.tsx | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/pages/Device.tsx b/src/pages/Device.tsx index 0fb59a9..db9914e 100644 --- a/src/pages/Device.tsx +++ b/src/pages/Device.tsx @@ -203,10 +203,24 @@ export default function DevicePage() { // --- Real-time device updates (optional) --- // Updates device-level info (name, status, lastActive, etc.) - useWebSocket({ - path: `/v1/live/devices/${deviceID}`, - parse: (e) => Device.any(JSON.parse(e.data)), + useWebSocket({ + path: `/live/devices/${deviceID}`, + parse: (e) => { + try { + const raw = JSON.parse(e.data); + const dev = Device.any(raw); + if (!dev?.settings) { + console.warn("[ws] received device without settings:", raw); + return null; + } + return dev; + } catch (err) { + console.warn("[ws] failed to parse device:", err); + return null; + } + }, onMessage: (updatedDevice) => { + if (!updatedDevice) return; setDevice(updatedDevice); }, token,