From 2aed7b8e1f02b2ee1f998d4d61ae75d2d63c9313 Mon Sep 17 00:00:00 2001 From: rajashidattapy Date: Wed, 5 Aug 2026 00:38:30 +0530 Subject: [PATCH 1/2] test: add unit tests for resolveCloakBrowserVersion function --- .../runtime/local-cloak/cloak-version.test.ts | 25 +++++++++++++++++++ .../runtime/local-cloak/session-manager.ts | 19 +++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/browser/runtime/local-cloak/cloak-version.test.ts diff --git a/src/browser/runtime/local-cloak/cloak-version.test.ts b/src/browser/runtime/local-cloak/cloak-version.test.ts new file mode 100644 index 00000000..1c33f12a --- /dev/null +++ b/src/browser/runtime/local-cloak/cloak-version.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it, vi } from 'vitest'; + +// Isolated file: the version cache is module-level and populated by the first +// call in the process, so this must import a fresh copy to observe the read. +describe('resolveCloakBrowserVersion', () => { + it('resolves and reads cloakbrowser/package.json only once per process', async () => { + vi.resetModules(); + const fs = (await import('node:fs')).default; + // Import before spying: loading the module graph reads files of its own, + // and only reads made by resolveCloakBrowserVersion should be counted. + const { resolveCloakBrowserVersion } = await import('./session-manager.js'); + const readFileSync = vi.spyOn(fs, 'readFileSync'); + try { + const first = resolveCloakBrowserVersion(); + const second = resolveCloakBrowserVersion(); + const third = resolveCloakBrowserVersion(); + + expect(second).toBe(first); + expect(third).toBe(first); + expect(readFileSync).toHaveBeenCalledTimes(1); + } finally { + readFileSync.mockRestore(); + } + }); +}); diff --git a/src/browser/runtime/local-cloak/session-manager.ts b/src/browser/runtime/local-cloak/session-manager.ts index 1b8c3974..32fc3c84 100644 --- a/src/browser/runtime/local-cloak/session-manager.ts +++ b/src/browser/runtime/local-cloak/session-manager.ts @@ -10,15 +10,28 @@ import { normalizeProfileId, resolveCloakProfileDir } from './profiles.js'; import { CloakNetworkCapture } from './network.js'; import { findPackageRoot } from '../../../package-paths.js'; -/** Installed `cloakbrowser` npm package version, for doctor/status display. */ +const UNRESOLVED = Symbol('unresolved'); +let cachedCloakBrowserVersion: string | undefined | typeof UNRESOLVED = UNRESOLVED; + +/** + * Installed `cloakbrowser` npm package version, for doctor/status display. + * + * Resolved once per process. The version cannot change while we are running, and + * `profileStatuses()` calls this per profile, so an uncached read meant N+1 + * synchronous resolve-read-parse cycles on every status poll. The sentinel keeps + * a genuine `undefined` (the catch path) cached too, so an unresolvable + * `cloakbrowser` is not retried on every call. + */ export function resolveCloakBrowserVersion(): string | undefined { + if (cachedCloakBrowserVersion !== UNRESOLVED) return cachedCloakBrowserVersion; try { const entryPath = fileURLToPath(import.meta.resolve('cloakbrowser')); const pkg = JSON.parse(fs.readFileSync(path.join(findPackageRoot(entryPath), 'package.json'), 'utf-8')); - return typeof pkg.version === 'string' ? pkg.version : undefined; + cachedCloakBrowserVersion = typeof pkg.version === 'string' ? pkg.version : undefined; } catch { - return undefined; + cachedCloakBrowserVersion = undefined; } + return cachedCloakBrowserVersion; } export type LaunchPersistentContext = typeof cloakLaunchPersistentContext; From 1a50cc0b60dc46a8deb55e4bf58c85476a7b1570 Mon Sep 17 00:00:00 2001 From: rajashidattapy Date: Wed, 5 Aug 2026 02:56:12 +0530 Subject: [PATCH 2/2] fix: ensure correct type for package version in resolveCloakBrowserVersion --- src/browser/runtime/local-cloak/session-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/runtime/local-cloak/session-manager.ts b/src/browser/runtime/local-cloak/session-manager.ts index 32fc3c84..70e3476c 100644 --- a/src/browser/runtime/local-cloak/session-manager.ts +++ b/src/browser/runtime/local-cloak/session-manager.ts @@ -26,7 +26,7 @@ export function resolveCloakBrowserVersion(): string | undefined { if (cachedCloakBrowserVersion !== UNRESOLVED) return cachedCloakBrowserVersion; try { const entryPath = fileURLToPath(import.meta.resolve('cloakbrowser')); - const pkg = JSON.parse(fs.readFileSync(path.join(findPackageRoot(entryPath), 'package.json'), 'utf-8')); + const pkg = JSON.parse(fs.readFileSync(path.join(findPackageRoot(entryPath), 'package.json'), 'utf-8')) as { version?: unknown }; cachedCloakBrowserVersion = typeof pkg.version === 'string' ? pkg.version : undefined; } catch { cachedCloakBrowserVersion = undefined;