From eb13e83fca4313ad567f928e4793486865b5e17c Mon Sep 17 00:00:00 2001 From: Anna Tsukanova Date: Fri, 10 Jul 2026 17:46:28 +0200 Subject: [PATCH 1/4] feat: hasWasmSupport util --- package.json | 7 +++++-- src/index.ts | 1 + src/wasm-info.spec.ts | 24 ++++++++++++++++++++++++ src/wasm-info.ts | 10 ++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/wasm-info.spec.ts create mode 100644 src/wasm-info.ts diff --git a/package.json b/package.json index 16dbedd..80771d9 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,11 @@ "module": "dist/esm/index.js", "types": "dist/types/index.d.ts", "exports": { - "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js" + ".": { + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js" + } }, "scripts": { "build": "run-s clean compile", diff --git a/src/index.ts b/src/index.ts index ac1bd5d..bfee768 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export * from './browser-info'; export * from './cpu-info'; export * from './system-info'; +export * from './wasm-info'; export * from './web-capabilities'; diff --git a/src/wasm-info.spec.ts b/src/wasm-info.spec.ts new file mode 100644 index 0000000..751a147 --- /dev/null +++ b/src/wasm-info.spec.ts @@ -0,0 +1,24 @@ +import { hasWasmSupport } from './wasm-info'; + +describe('hasWasmSupport', () => { + const originalWebAssembly = globalThis.WebAssembly; + + afterEach(() => { + // Restore the WebAssembly global mutated by individual cases. + (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly = originalWebAssembly; + }); + + it('should return true when the WebAssembly runtime is available', () => { + expect.assertions(1); + + expect(hasWasmSupport()).toBe(true); + }); + + it('should return false when the WebAssembly runtime is hard-disabled', () => { + expect.assertions(1); + + delete (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly; + + expect(hasWasmSupport()).toBe(false); + }); +}); diff --git a/src/wasm-info.ts b/src/wasm-info.ts new file mode 100644 index 0000000..600c068 --- /dev/null +++ b/src/wasm-info.ts @@ -0,0 +1,10 @@ +/** + * Checks whether the WebAssembly runtime is available, without throwing when it is not. + * + * Returns false only when WebAssembly is hard-disabled, such as Chromium jitless mode where the + * global is removed entirely. + * + * @returns True if the WebAssembly runtime is present, false if it is hard-disabled. + */ +export const hasWasmSupport = (): boolean => + typeof WebAssembly === 'object' && typeof WebAssembly.validate === 'function'; From 91a22d7230aae3de84fb582446c880b25cd6b659 Mon Sep 17 00:00:00 2001 From: Anna Tsukanova Date: Fri, 10 Jul 2026 17:58:31 +0200 Subject: [PATCH 2/4] chore: simplify exports --- package.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 80771d9..fbfffbc 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,9 @@ "module": "dist/esm/index.js", "types": "dist/types/index.d.ts", "exports": { - ".": { - "types": "./dist/types/index.d.ts", - "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js" - } + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js" }, "scripts": { "build": "run-s clean compile", From 791fd12973fb9e6870ce8784cc47ea87a0f02503 Mon Sep 17 00:00:00 2001 From: Anna Tsukanova Date: Fri, 10 Jul 2026 18:13:55 +0200 Subject: [PATCH 3/4] refactor: update logic --- src/index.ts | 1 - src/wasm-info.spec.ts | 24 ------------------------ src/wasm-info.ts | 10 ---------- src/web-capabilities.spec.ts | 32 ++++++++++++++++++++++++++++++++ src/web-capabilities.ts | 17 +++++++++++++++++ 5 files changed, 49 insertions(+), 35 deletions(-) delete mode 100644 src/wasm-info.spec.ts delete mode 100644 src/wasm-info.ts diff --git a/src/index.ts b/src/index.ts index bfee768..ac1bd5d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ export * from './browser-info'; export * from './cpu-info'; export * from './system-info'; -export * from './wasm-info'; export * from './web-capabilities'; diff --git a/src/wasm-info.spec.ts b/src/wasm-info.spec.ts deleted file mode 100644 index 751a147..0000000 --- a/src/wasm-info.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { hasWasmSupport } from './wasm-info'; - -describe('hasWasmSupport', () => { - const originalWebAssembly = globalThis.WebAssembly; - - afterEach(() => { - // Restore the WebAssembly global mutated by individual cases. - (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly = originalWebAssembly; - }); - - it('should return true when the WebAssembly runtime is available', () => { - expect.assertions(1); - - expect(hasWasmSupport()).toBe(true); - }); - - it('should return false when the WebAssembly runtime is hard-disabled', () => { - expect.assertions(1); - - delete (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly; - - expect(hasWasmSupport()).toBe(false); - }); -}); diff --git a/src/wasm-info.ts b/src/wasm-info.ts deleted file mode 100644 index 600c068..0000000 --- a/src/wasm-info.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Checks whether the WebAssembly runtime is available, without throwing when it is not. - * - * Returns false only when WebAssembly is hard-disabled, such as Chromium jitless mode where the - * global is removed entirely. - * - * @returns True if the WebAssembly runtime is present, false if it is hard-disabled. - */ -export const hasWasmSupport = (): boolean => - typeof WebAssembly === 'object' && typeof WebAssembly.validate === 'function'; diff --git a/src/web-capabilities.spec.ts b/src/web-capabilities.spec.ts index 9e5b8b2..3aa7de1 100644 --- a/src/web-capabilities.spec.ts +++ b/src/web-capabilities.spec.ts @@ -41,6 +41,17 @@ describe('WebCapabilities', () => { expect(WebCapabilities.isCapableOfReceiving1080pVideo()).toBe(CapabilityState.CAPABLE); expect(WebCapabilities.isCapableOfSending1080pVideo()).toBe(CapabilityState.CAPABLE); }); + it('should return NOT_CAPABLE for background noise removal when WebAssembly is hard-disabled', () => { + expect.assertions(1); + const originalWebAssembly = globalThis.WebAssembly; + jest.spyOn(CpuInfo, 'getNumLogicalCores').mockReturnValue(8); + delete (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly; + + expect(WebCapabilities.isCapableOfBackgroundNoiseRemoval()).toBe(CapabilityState.NOT_CAPABLE); + + (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly = originalWebAssembly; + }); + describe('supportsEncodedStreamTransforms', () => { afterEach(() => { // Clean up window modifications @@ -249,6 +260,27 @@ describe('WebCapabilities', () => { }); }); + describe('supportsWasm', () => { + const originalWebAssembly = globalThis.WebAssembly; + + afterEach(() => { + // Restore the WebAssembly global mutated by individual cases. + (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly = originalWebAssembly; + }); + + it('should return CAPABLE when the WebAssembly runtime is available', () => { + expect.assertions(1); + expect(WebCapabilities.supportsWasm()).toBe(CapabilityState.CAPABLE); + }); + + it('should return NOT_CAPABLE when the WebAssembly runtime is hard-disabled', () => { + expect.assertions(1); + delete (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly; + + expect(WebCapabilities.supportsWasm()).toBe(CapabilityState.NOT_CAPABLE); + }); + }); + describe('supportsEncodingCodec', () => { let isChromeSpy: jest.SpyInstance; let isEdgeSpy: jest.SpyInstance; diff --git a/src/web-capabilities.ts b/src/web-capabilities.ts index 9d4fa54..8836f66 100644 --- a/src/web-capabilities.ts +++ b/src/web-capabilities.ts @@ -23,6 +23,11 @@ export class WebCapabilities { * @returns A {@link CapabilityState}. */ static isCapableOfBackgroundNoiseRemoval(): CapabilityState { + // Background noise removal runs as a WebAssembly module, so it cannot work at all when the + // runtime is hard-disabled (such as Chromium jitless mode). + if (WebCapabilities.supportsWasm() === CapabilityState.NOT_CAPABLE) { + return CapabilityState.NOT_CAPABLE; + } const numCores = CpuInfo.getNumLogicalCores(); if (numCores === undefined) { return CapabilityState.UNKNOWN; @@ -112,6 +117,18 @@ export class WebCapabilities { : CapabilityState.NOT_CAPABLE; } + /** + * Checks whether the browser supports the WebAssembly runtime. Some environments hard-disable it, + * such as Chromium jitless mode, where the WebAssembly global is removed entirely. + * + * @returns A {@link CapabilityState}. + */ + static supportsWasm(): CapabilityState { + return typeof WebAssembly === 'object' && typeof WebAssembly.validate === 'function' + ? CapabilityState.CAPABLE + : CapabilityState.NOT_CAPABLE; + } + /** * Checks whether the browser supports RTCPeerConnection. This is needed, * because some users install browser extensions that remove RTCPeerConnection. From be8d02a096939a7839784f10b3776693ede8bec4 Mon Sep 17 00:00:00 2001 From: Anna Tsukanova Date: Fri, 10 Jul 2026 21:00:14 +0200 Subject: [PATCH 4/4] refactor: update logic for isCapableOfVirtualBackground --- src/web-capabilities.spec.ts | 11 +++++++++++ src/web-capabilities.ts | 9 +++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/web-capabilities.spec.ts b/src/web-capabilities.spec.ts index 3aa7de1..a605481 100644 --- a/src/web-capabilities.spec.ts +++ b/src/web-capabilities.spec.ts @@ -52,6 +52,17 @@ describe('WebCapabilities', () => { (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly = originalWebAssembly; }); + it('should return NOT_CAPABLE for virtual background when WebAssembly is hard-disabled', () => { + expect.assertions(1); + const originalWebAssembly = globalThis.WebAssembly; + jest.spyOn(CpuInfo, 'getNumLogicalCores').mockReturnValue(8); + delete (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly; + + expect(WebCapabilities.isCapableOfVirtualBackground()).toBe(CapabilityState.NOT_CAPABLE); + + (globalThis as { WebAssembly?: typeof WebAssembly }).WebAssembly = originalWebAssembly; + }); + describe('supportsEncodedStreamTransforms', () => { afterEach(() => { // Clean up window modifications diff --git a/src/web-capabilities.ts b/src/web-capabilities.ts index 8836f66..a486abf 100644 --- a/src/web-capabilities.ts +++ b/src/web-capabilities.ts @@ -44,6 +44,11 @@ export class WebCapabilities { * @returns A {@link CapabilityState}. */ static isCapableOfVirtualBackground(): CapabilityState { + // Virtual background runs as a WebAssembly module, so it cannot work at all when the runtime + // is hard-disabled (such as Chromium jitless mode). + if (WebCapabilities.supportsWasm() === CapabilityState.NOT_CAPABLE) { + return CapabilityState.NOT_CAPABLE; + } const numCores = CpuInfo.getNumLogicalCores(); if (numCores === undefined) { return CapabilityState.UNKNOWN; @@ -118,8 +123,8 @@ export class WebCapabilities { } /** - * Checks whether the browser supports the WebAssembly runtime. Some environments hard-disable it, - * such as Chromium jitless mode, where the WebAssembly global is removed entirely. + * Checks whether the browser supports the WebAssembly runtime, which some environments + * hard-disable (such as Chromium jitless mode). * * @returns A {@link CapabilityState}. */