From cb0257bfc2f805d1d3121109cd59afd2950d32d4 Mon Sep 17 00:00:00 2001 From: Milosz Filimowski Date: Mon, 23 Feb 2026 14:02:29 +0100 Subject: [PATCH 1/3] add DOMException polyfill --- packages/react-client/src/devices/mediaInitializer.ts | 4 ++-- packages/react-client/src/utils/errors.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-client/src/devices/mediaInitializer.ts b/packages/react-client/src/devices/mediaInitializer.ts index 60154002..855e47b9 100644 --- a/packages/react-client/src/devices/mediaInitializer.ts +++ b/packages/react-client/src/devices/mediaInitializer.ts @@ -26,7 +26,7 @@ const getSingleMedia = async ( const stream = await navigator.mediaDevices.getUserMedia({ ...baseConstraints, [type]: constraints }); return [stream, null]; } catch (err) { - if (!(err instanceof DOMException)) return [null, UNHANDLED_ERROR]; + if (!(err instanceof Error)) return [null, UNHANDLED_ERROR]; return [null, errorMap[err.name] ?? UNHANDLED_ERROR]; } @@ -50,7 +50,7 @@ export const getAvailableMedia = async ( try { return { stream: await navigator.mediaDevices.getUserMedia(constraints), errors }; } catch (err: unknown) { - if (err instanceof DOMException) { + if (err instanceof Error) { switch (err.name) { case errors.audio?.name: case errors.video?.name: diff --git a/packages/react-client/src/utils/errors.ts b/packages/react-client/src/utils/errors.ts index cc5afe25..1363a3ba 100644 --- a/packages/react-client/src/utils/errors.ts +++ b/packages/react-client/src/utils/errors.ts @@ -10,7 +10,7 @@ export const UNHANDLED_ERROR: DeviceError = { name: "UNHANDLED_ERROR" }; // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#exceptions // OverconstrainedError has higher priority than NotAllowedError export const parseUserMediaError = (error: unknown, logger: ReturnType): DeviceError => { - if (!(error instanceof DOMException)) { + if (!(error instanceof Error)) { logger.warn({ name: "Unhandled getUserMedia error", error }); return UNHANDLED_ERROR; } From a9f0bc7d5b80431a511bad008298f920db936ecd Mon Sep 17 00:00:00 2001 From: Milosz Filimowski Date: Mon, 23 Feb 2026 16:39:03 +0100 Subject: [PATCH 2/3] use error message directly --- .../src/devices/mediaInitializer.ts | 35 +++++++++---------- packages/react-client/src/utils/errors.ts | 23 ++++++------ 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/packages/react-client/src/devices/mediaInitializer.ts b/packages/react-client/src/devices/mediaInitializer.ts index 855e47b9..77c05135 100644 --- a/packages/react-client/src/devices/mediaInitializer.ts +++ b/packages/react-client/src/devices/mediaInitializer.ts @@ -26,9 +26,7 @@ const getSingleMedia = async ( const stream = await navigator.mediaDevices.getUserMedia({ ...baseConstraints, [type]: constraints }); return [stream, null]; } catch (err) { - if (!(err instanceof Error)) return [null, UNHANDLED_ERROR]; - - return [null, errorMap[err.name] ?? UNHANDLED_ERROR]; + return [null, errorMap[(err as Error).name] ?? UNHANDLED_ERROR]; } }; @@ -50,23 +48,22 @@ export const getAvailableMedia = async ( try { return { stream: await navigator.mediaDevices.getUserMedia(constraints), errors }; } catch (err: unknown) { - if (err instanceof Error) { - switch (err.name) { - case errors.audio?.name: - case errors.video?.name: - return { stream: null, errors }; - case "NotFoundError": - return tryToGetAudioOnlyThenVideoOnly(constraints, PERMISSION_DENIED); - case "OverconstrainedError": - return getAvailableMedia( - { audio: unspecifyDevice(constraints.audio), video: unspecifyDevice(constraints.video) }, - { audio: OVERCONSTRAINED_ERROR, video: OVERCONSTRAINED_ERROR }, - ); - case "NotAllowedError": - return tryToGetAudioOnlyThenVideoOnly(constraints, PERMISSION_DENIED); - } + switch ((err as Error).name) { + case errors.audio?.name: + case errors.video?.name: + return { stream: null, errors }; + case "NotFoundError": + return tryToGetAudioOnlyThenVideoOnly(constraints, PERMISSION_DENIED); + case "OverconstrainedError": + return getAvailableMedia( + { audio: unspecifyDevice(constraints.audio), video: unspecifyDevice(constraints.video) }, + { audio: OVERCONSTRAINED_ERROR, video: OVERCONSTRAINED_ERROR }, + ); + case "NotAllowedError": + return tryToGetAudioOnlyThenVideoOnly(constraints, PERMISSION_DENIED); + default: + return { stream: null, errors: { audio: UNHANDLED_ERROR, video: UNHANDLED_ERROR } }; } - return { stream: null, errors: { audio: UNHANDLED_ERROR, video: UNHANDLED_ERROR } }; } }; diff --git a/packages/react-client/src/utils/errors.ts b/packages/react-client/src/utils/errors.ts index 1363a3ba..b0e57e9e 100644 --- a/packages/react-client/src/utils/errors.ts +++ b/packages/react-client/src/utils/errors.ts @@ -10,18 +10,15 @@ export const UNHANDLED_ERROR: DeviceError = { name: "UNHANDLED_ERROR" }; // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#exceptions // OverconstrainedError has higher priority than NotAllowedError export const parseUserMediaError = (error: unknown, logger: ReturnType): DeviceError => { - if (!(error instanceof Error)) { - logger.warn({ name: "Unhandled getUserMedia error", error }); - return UNHANDLED_ERROR; + switch ((error as Error).name) { + case "NotAllowedError": + return PERMISSION_DENIED; + case "OverconstrainedError": + return OVERCONSTRAINED_ERROR; + case "NotFoundError": + return NOT_FOUND_ERROR; + default: + logger.warn({ name: "Unhandled getUserMedia error", error }); + return UNHANDLED_ERROR; } - - if (error.name === "NotAllowedError") { - return PERMISSION_DENIED; - } else if (error.name === "OverconstrainedError") { - return OVERCONSTRAINED_ERROR; - } else if (error.name === "NotFoundError") { - return NOT_FOUND_ERROR; - } - - return UNHANDLED_ERROR; }; From 470fde8681c6706f1c5de4eecacdcae0a9470ff0 Mon Sep 17 00:00:00 2001 From: Milosz Filimowski Date: Mon, 23 Feb 2026 16:48:50 +0100 Subject: [PATCH 3/3] implement copilot suggestion --- packages/react-client/src/devices/mediaInitializer.ts | 6 ++++-- packages/react-client/src/utils/errors.ts | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/react-client/src/devices/mediaInitializer.ts b/packages/react-client/src/devices/mediaInitializer.ts index 77c05135..6d2c9f89 100644 --- a/packages/react-client/src/devices/mediaInitializer.ts +++ b/packages/react-client/src/devices/mediaInitializer.ts @@ -26,7 +26,8 @@ const getSingleMedia = async ( const stream = await navigator.mediaDevices.getUserMedia({ ...baseConstraints, [type]: constraints }); return [stream, null]; } catch (err) { - return [null, errorMap[(err as Error).name] ?? UNHANDLED_ERROR]; + const name = err instanceof Error ? err.name : ""; + return [null, errorMap[name] ?? UNHANDLED_ERROR]; } }; @@ -48,7 +49,8 @@ export const getAvailableMedia = async ( try { return { stream: await navigator.mediaDevices.getUserMedia(constraints), errors }; } catch (err: unknown) { - switch ((err as Error).name) { + const name = err instanceof Error ? err.name : ""; + switch (name) { case errors.audio?.name: case errors.video?.name: return { stream: null, errors }; diff --git a/packages/react-client/src/utils/errors.ts b/packages/react-client/src/utils/errors.ts index b0e57e9e..73272796 100644 --- a/packages/react-client/src/utils/errors.ts +++ b/packages/react-client/src/utils/errors.ts @@ -10,7 +10,8 @@ export const UNHANDLED_ERROR: DeviceError = { name: "UNHANDLED_ERROR" }; // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#exceptions // OverconstrainedError has higher priority than NotAllowedError export const parseUserMediaError = (error: unknown, logger: ReturnType): DeviceError => { - switch ((error as Error).name) { + const name = error instanceof Error ? error.name : ""; + switch (name) { case "NotAllowedError": return PERMISSION_DENIED; case "OverconstrainedError":