From 58eead89d2e384ea48160fbed0e4c4b2709f74d0 Mon Sep 17 00:00:00 2001 From: CloakHQ Date: Thu, 8 Oct 2026 02:37:20 +0200 Subject: [PATCH] feat(js): support CommonJS require() via a default export condition Exports used only "import", so require('cloakbrowser') failed with ERR_PACKAGE_PATH_NOT_EXPORTED. A "default" condition lets Node's built-in require(esm) load all three subpaths. engines raised to ^20.19.0 || >=22.12.0, where require(esm) is on by default. --- CHANGELOG.md | 2 ++ js/package-lock.json | 2 +- js/package.json | 8 ++++---- js/tests/require.test.ts | 31 +++++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 js/tests/require.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c2db45e..70fd954 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ Changes are tagged: **[wrapper]** for Python/JS wrapper, **[binary]** for Chromi - **[binary]** CloakBrowser Pro Stable is now Chromium `154.0.8037.57.1` on every platform: Linux x64/ARM64, Windows x64, and macOS (Apple Silicon and Intel). macOS moves up from Chromium 151. - **[binary]** Linux preview channel (x64/ARM64) is now `154.0.8037.57.2`: much lower CPU in headed mode on GPU-less Linux, safer proxy handling, a more patient license connection with a new `--license-route=auto|direct|proxy` flag, and the Windows persona's system and code fonts now match real Windows by default. - **[wrapper]** `cloakserve`: a browser launched through `/json/version` or `/json/list` with no WebSocket client attaching now gets idle cleanup, instead of running forever when `--idle-timeout` is set (thanks [@dstosch](https://github.com/dstosch), #558) +- **[wrapper]** JavaScript: binary and GeoIP download status messages now go to stderr instead of stdout, so they no longer corrupt MCP stdio servers or tools that parse stdout on first run. Python and .NET already did this. +- **[wrapper]** JavaScript: CommonJS `require('cloakbrowser')` now works, including the `cloakbrowser/puppeteer` and `cloakbrowser/human` subpaths. Requires Node 20.19+ or 22.12+ (the npm package's `engines` field now says so). --- diff --git a/js/package-lock.json b/js/package-lock.json index 70248b0..2ceadd4 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -24,7 +24,7 @@ "vitest": "^5.0.1" }, "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { "mmdb-lib": ">=2.0.0", diff --git a/js/package.json b/js/package.json index 1ab1731..d760d05 100644 --- a/js/package.json +++ b/js/package.json @@ -8,15 +8,15 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js" + "default": "./dist/index.js" }, "./puppeteer": { "types": "./dist/puppeteer.d.ts", - "import": "./dist/puppeteer.js" + "default": "./dist/puppeteer.js" }, "./human": { "types": "./dist/human/index.d.ts", - "import": "./dist/human/index.js" + "default": "./dist/human/index.js" } }, "bin": { @@ -55,7 +55,7 @@ }, "homepage": "https://github.com/CloakHQ/cloakbrowser#javascript--nodejs", "engines": { - "node": ">=20.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { "mmdb-lib": ">=2.0.0", diff --git a/js/tests/require.test.ts b/js/tests/require.test.ts new file mode 100644 index 0000000..09ac676 --- /dev/null +++ b/js/tests/require.test.ts @@ -0,0 +1,31 @@ +import { describe, it, expect } from "vitest"; +import { execFile } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; + +// Loads the built dist/ (npm run build first, as CI does) through the package's +// own exports map, the way a consumer's require() or import resolves it. +const PKG_DIR = fileURLToPath(new URL("..", import.meta.url)); +const SUBPATHS = ["cloakbrowser", "cloakbrowser/puppeteer", "cloakbrowser/human"]; + +async function run(args: string[]): Promise { + const { stdout } = await promisify(execFile)(process.execPath, args, { cwd: PKG_DIR }); + return stdout.trim(); +} + +describe("package entry points", () => { + it.skipIf(!process.features.require_module)("CommonJS require() loads every subpath", async () => { + const script = `console.log(JSON.stringify(${JSON.stringify(SUBPATHS)}.map((m) => Object.keys(require(m)).length)));`; + const counts = JSON.parse(await run(["-e", script])) as number[]; + expect(counts.every((n) => n > 0)).toBe(true); + expect(await run(["-e", `console.log(typeof require("cloakbrowser").launch)`])).toBe("function"); + }); + + it("ESM import loads every subpath", async () => { + const script = + `const mods = await Promise.all(${JSON.stringify(SUBPATHS)}.map((m) => import(m)));` + + `console.log(JSON.stringify(mods.map((m) => Object.keys(m).length)));`; + const counts = JSON.parse(await run(["--input-type=module", "-e", script])) as number[]; + expect(counts.every((n) => n > 0)).toBe(true); + }); +});