mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-16 20:02:45 +03:00
fix(providers): migrate web cookie TLS transport to wreq-js
This commit is contained in:
@@ -49,6 +49,7 @@ import fs from "node:fs/promises";
|
||||
import fsSync from "node:fs";
|
||||
import path from "node:path";
|
||||
import { colocateLlmlinguaOptionals, SEED_PACKAGES } from "./colocateOptionals.mjs";
|
||||
import { WREQ_JS_NATIVE_BINDINGS } from "./wreqJsNative.mjs";
|
||||
|
||||
/**
|
||||
* Check whether a path exists (async).
|
||||
@@ -121,6 +122,31 @@ const EXTRA_MODULE_ENTRIES = [
|
||||
src: ["node_modules", "wreq-js"],
|
||||
dest: ["node_modules", "wreq-js"],
|
||||
},
|
||||
...WREQ_JS_NATIVE_BINDINGS.map((binding) => ({
|
||||
label: `${binding.packageName} native binding`,
|
||||
src: ["node_modules", ...binding.packageName.split("/")],
|
||||
dest: ["node_modules", ...binding.packageName.split("/")],
|
||||
})),
|
||||
{
|
||||
label: "third-party notices",
|
||||
src: ["THIRD_PARTY_NOTICES.md"],
|
||||
dest: ["THIRD_PARTY_NOTICES.md"],
|
||||
},
|
||||
{
|
||||
label: "wreq-js native provenance manifest",
|
||||
src: ["config", "release", "wreq-js-native-manifest.json"],
|
||||
dest: ["config", "release", "wreq-js-native-manifest.json"],
|
||||
},
|
||||
{
|
||||
label: "wreq-js Rust license inventory",
|
||||
src: ["config", "release", "wreq-js-rust-license-inventory.json"],
|
||||
dest: ["config", "release", "wreq-js-rust-license-inventory.json"],
|
||||
},
|
||||
{
|
||||
label: "wreq-js Rust/native notice bundle",
|
||||
src: ["config", "release", "wreq-js-rust-notices.md"],
|
||||
dest: ["config", "release", "wreq-js-rust-notices.md"],
|
||||
},
|
||||
{
|
||||
label: "@swc/helpers",
|
||||
src: ["node_modules", "@swc", "helpers"],
|
||||
@@ -557,9 +583,7 @@ function stampServiceWorkerBuildId(resolvedOutDir) {
|
||||
const swDest = path.join(resolvedOutDir, "public", "sw.js");
|
||||
if (!fsSync.existsSync(swDest)) return;
|
||||
const buildId =
|
||||
process.env.OMNIROUTE_SW_BUILD_ID ||
|
||||
process.env.SOURCE_VERSION ||
|
||||
String(Date.now());
|
||||
process.env.OMNIROUTE_SW_BUILD_ID || process.env.SOURCE_VERSION || String(Date.now());
|
||||
let sw = fsSync.readFileSync(swDest, "utf8");
|
||||
sw = sw.replace(
|
||||
/^const CACHE_NAME = "omniroute-pwa-v2";$/m,
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* tls-client-node postinstall repair (#7802).
|
||||
*
|
||||
* tls-client-node's own postinstall.js fetches a platform-specific native
|
||||
* binary (.so/.dylib/.dll) from the bogdanfinn/tls-client GitHub Releases
|
||||
* API. That script is blocked by `npm ci --ignore-scripts` (the Dockerfile
|
||||
* builder stage runs with scripts disabled for supply-chain hygiene) and,
|
||||
* even when it does run, silently no-ops on a rate-limited/failed GitHub API
|
||||
* call instead of raising — so `node_modules/tls-client-node/bin/` can end
|
||||
* up empty with no visible signal until the first live request throws
|
||||
* TlsClientUnavailableError (claude-web/grok-web/lmarena/
|
||||
* perplexity-web all share this transport).
|
||||
*
|
||||
* This module:
|
||||
* 1. Copies an already-fetched root `bin/` into the standalone
|
||||
* `dist/node_modules/tls-client-node/bin/` bundle (same pattern as
|
||||
* fixWreqJsBinary), so the published npm package works even though its
|
||||
* own `files` allowlist never ships the binary.
|
||||
* 2. When the root `bin/` is empty (--ignore-scripts blocked it, or a
|
||||
* transient GitHub rate-limit ate the first attempt), retries the
|
||||
* module's own postinstall.js with exponential backoff instead of
|
||||
* giving up on the first failure.
|
||||
*
|
||||
* Best-effort throughout: a failure here never throws out of postinstall.mjs
|
||||
* — it only warns, matching the other fix*Binary() steps. The runtime layer
|
||||
* (perplexityTlsClient.ts and its 4 siblings) already surfaces a clear
|
||||
* TlsClientUnavailableError pointing at the missing binary, so an operator
|
||||
* who hits a still-empty bin/ after this repair gets an actionable message
|
||||
* rather than an opaque crash.
|
||||
*/
|
||||
|
||||
import { copyFileSync, existsSync, mkdirSync, readdirSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const DEFAULT_RETRY_DELAYS_MS = [1_000, 3_000, 8_000];
|
||||
|
||||
function hasAnyFile(dir) {
|
||||
if (!existsSync(dir)) return false;
|
||||
try {
|
||||
return readdirSync(dir).length > 0;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function copyBinDir(sourceDir, destDir) {
|
||||
mkdirSync(destDir, { recursive: true });
|
||||
for (const file of readdirSync(sourceDir)) {
|
||||
copyFileSync(join(sourceDir, file), join(destDir, file));
|
||||
}
|
||||
}
|
||||
|
||||
async function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-run tls-client-node's own postinstall.js in-process, retrying with
|
||||
* backoff when the attempt leaves `bin/` empty (covers transient GitHub API
|
||||
* rate-limiting — the upstream script itself never throws on failure, it
|
||||
* only warns, so "still empty after running it" is the only failure signal
|
||||
* available).
|
||||
*/
|
||||
async function downloadWithRetry(rootTlsClientDir, retryDelaysMs, log) {
|
||||
const postinstallScript = join(rootTlsClientDir, "scripts", "postinstall.js");
|
||||
const binDir = join(rootTlsClientDir, "bin");
|
||||
if (!existsSync(postinstallScript)) return false;
|
||||
|
||||
for (let attempt = 0; attempt <= retryDelaysMs.length; attempt++) {
|
||||
if (attempt > 0) {
|
||||
log(
|
||||
` ⏳ tls-client-node native binary still missing — retrying download ` +
|
||||
`(attempt ${attempt + 1}/${retryDelaysMs.length + 1}) after rate-limit/backoff...`
|
||||
);
|
||||
await sleep(retryDelaysMs[attempt - 1]);
|
||||
}
|
||||
|
||||
try {
|
||||
const { execFileSync } = await import("node:child_process");
|
||||
execFileSync(process.execPath, [postinstallScript], {
|
||||
cwd: rootTlsClientDir,
|
||||
stdio: "pipe",
|
||||
timeout: 30_000,
|
||||
});
|
||||
} catch (err) {
|
||||
log(` ⚠️ tls-client-node postinstall attempt failed: ${err.message.split("\n")[0]}`);
|
||||
}
|
||||
|
||||
if (hasAnyFile(binDir)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} opts
|
||||
* @param {string} opts.rootDir - repo root
|
||||
* @param {(msg: string) => void} [opts.log]
|
||||
* @param {number[]} [opts.retryDelaysMs] - override for tests (avoid real sleeps)
|
||||
*/
|
||||
export async function fixTlsClientNodeBinary({
|
||||
rootDir,
|
||||
log = (m) => console.log(m),
|
||||
retryDelaysMs = DEFAULT_RETRY_DELAYS_MS,
|
||||
} = {}) {
|
||||
const rootTlsClientDir = join(rootDir, "node_modules", "tls-client-node");
|
||||
const rootBinDir = join(rootTlsClientDir, "bin");
|
||||
const distTlsClientDir = join(rootDir, "dist", "node_modules", "tls-client-node");
|
||||
|
||||
if (!existsSync(rootTlsClientDir)) return;
|
||||
|
||||
if (!hasAnyFile(rootBinDir)) {
|
||||
log(
|
||||
"\n 🔧 tls-client-node native binary missing (blocked by --ignore-scripts or a " +
|
||||
"failed fetch) — attempting repair...\n"
|
||||
);
|
||||
const recovered = await downloadWithRetry(rootTlsClientDir, retryDelaysMs, log);
|
||||
if (!recovered) {
|
||||
console.warn(
|
||||
"\n ⚠️ Could not fetch tls-client-node's native binary " +
|
||||
"(GitHub API rate-limited or unreachable after retries)."
|
||||
);
|
||||
console.warn(
|
||||
" claude-web/grok-web/lmarena/perplexity-web will raise a clear " +
|
||||
"TlsClientUnavailableError on first use until this is resolved."
|
||||
);
|
||||
console.warn(
|
||||
` Manual fix: node ${join(rootTlsClientDir, "scripts", "postinstall.js")}\n`
|
||||
);
|
||||
return;
|
||||
}
|
||||
log(" ✅ tls-client-node native binary fetched successfully!\n");
|
||||
}
|
||||
|
||||
if (!existsSync(distTlsClientDir) || !hasAnyFile(rootBinDir)) return;
|
||||
|
||||
const distBinDir = join(distTlsClientDir, "bin");
|
||||
if (hasAnyFile(distBinDir)) return;
|
||||
|
||||
try {
|
||||
copyBinDir(rootBinDir, distBinDir);
|
||||
log(" ✅ tls-client-node native binary copied to standalone dist/node_modules.\n");
|
||||
} catch (err) {
|
||||
console.warn(` ⚠️ Could not copy tls-client-node binary into dist/: ${err.message}`);
|
||||
}
|
||||
}
|
||||
@@ -7,21 +7,26 @@
|
||||
* matrix leg. Everything except install-machine-forked optional packages is
|
||||
* platform-independent:
|
||||
*
|
||||
* - Bundled-for-all (verify only): koffi ships every triplet under
|
||||
* `build/koffi/<os>_<arch>`, better-sqlite3 v13 ships Node-API prebuilds for
|
||||
* 8 platforms, wreq-js ships `rust/wreq-js.<plat>-<arch>[-libc].node`, and
|
||||
* onnxruntime-node ships `bin/napi-v6/<os>/<arch>`.
|
||||
* - Bundled-for-all (verify only): better-sqlite3 v13 ships Node-API prebuilds
|
||||
* for 8 platforms, and onnxruntime-node ships `bin/napi-v6/<os>/<arch>`.
|
||||
* - Install-machine-forked (hydrate): `@img/sharp-*`, `@img/sharp-libvips-*`,
|
||||
* `@ngrok/ngrok-*` and macOS-only `fsevents` resolve to whichever platform
|
||||
* ran `npm ci`. The ubuntu-built tree carries the linux forks; each leg
|
||||
* replaces them with the forks from its OWN `npm ci`d node_modules.
|
||||
* `@ngrok/ngrok-*`, `@wreq-js/binding-*`, and macOS-only `fsevents` resolve
|
||||
* to whichever platform ran `npm ci`. The ubuntu-built tree carries the
|
||||
* linux forks; each leg replaces them with the forks from its OWN install.
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { resolveWreqJsNativeBinding } from "./wreqJsNative.mjs";
|
||||
|
||||
/** Scope prefixes whose members are install-machine-forked. */
|
||||
export const HYDRATED_SCOPES = ["@img/sharp-", "@img/sharp-libvips-", "@ngrok/ngrok-"];
|
||||
export const HYDRATED_SCOPES = [
|
||||
"@img/sharp-",
|
||||
"@img/sharp-libvips-",
|
||||
"@ngrok/ngrok-",
|
||||
"@wreq-js/binding-",
|
||||
];
|
||||
|
||||
/** Standalone packages that are not forked but must never be platform-forked. */
|
||||
export const HYDRATED_ROOT_PACKAGES = ["fsevents"];
|
||||
@@ -33,8 +38,7 @@ export const HYDRATED_ROOT_PACKAGES = ["fsevents"];
|
||||
export const BUNDLED_EXEMPTIONS = new Set(["onnxruntime-node:darwin-x64"]);
|
||||
|
||||
function platformTriple(platform, arch) {
|
||||
// koffi uses underscore triplets; better-sqlite3/wreq-js/onnx use dashes.
|
||||
return { koffi: `${platform}_${arch}`, dash: `${platform}-${arch}` };
|
||||
return { dash: `${platform}-${arch}` };
|
||||
}
|
||||
|
||||
function rmrf(target) {
|
||||
@@ -106,9 +110,6 @@ export function verifyBundledNatives({ nodeModulesDir, platform, arch }) {
|
||||
const errors = [];
|
||||
const triple = platformTriple(platform, arch);
|
||||
|
||||
const koffiDir = path.join(nodeModulesDir, "koffi", "build", "koffi", triple.koffi);
|
||||
if (!fs.existsSync(koffiDir)) errors.push(`koffi: missing bundled triplet ${triple.koffi}`);
|
||||
|
||||
const sqlitePrebuild = path.join(
|
||||
nodeModulesDir,
|
||||
"better-sqlite3",
|
||||
@@ -118,13 +119,23 @@ export function verifyBundledNatives({ nodeModulesDir, platform, arch }) {
|
||||
if (!fs.existsSync(sqlitePrebuild))
|
||||
errors.push(`better-sqlite3: missing prebuild ${triple.dash}.node`);
|
||||
|
||||
const wreqDir = path.join(nodeModulesDir, "wreq-js", "rust");
|
||||
const wreqNames = fs.existsSync(wreqDir)
|
||||
? fs
|
||||
.readdirSync(wreqDir)
|
||||
.filter((n) => n.startsWith(`wreq-js.${triple.dash}`) && n.endsWith(".node"))
|
||||
: [];
|
||||
if (wreqNames.length === 0) errors.push(`wreq-js: missing rust binary for ${triple.dash}`);
|
||||
const wreqBinding = resolveWreqJsNativeBinding({
|
||||
platform,
|
||||
arch,
|
||||
libc: platform === "linux" ? "gnu" : undefined,
|
||||
});
|
||||
if (!wreqBinding) {
|
||||
errors.push(`wreq-js: unsupported target ${triple.dash}`);
|
||||
} else {
|
||||
const wreqBinary = path.join(
|
||||
nodeModulesDir,
|
||||
...wreqBinding.packageName.split("/"),
|
||||
wreqBinding.fileName
|
||||
);
|
||||
if (!fs.existsSync(wreqBinary)) {
|
||||
errors.push(`wreq-js: missing ${wreqBinding.packageName}/${wreqBinding.fileName}`);
|
||||
}
|
||||
}
|
||||
|
||||
const exempt = BUNDLED_EXEMPTIONS.has(`onnxruntime-node:${triple.dash}`);
|
||||
if (!exempt) {
|
||||
|
||||
@@ -94,6 +94,9 @@ export const PACK_ARTIFACT_ROOT_ALLOWED_EXACT_PATHS: string[] = [
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"THIRD_PARTY_NOTICES.md",
|
||||
"config/release/wreq-js-native-manifest.json",
|
||||
"config/release/wreq-js-rust-license-inventory.json",
|
||||
"config/release/wreq-js-rust-notices.md",
|
||||
"bin/aliasResolver.mjs",
|
||||
"bin/chatgpt-web-codex-mcp.mjs",
|
||||
// #7808: ESM loader hook split out of bin/aliasResolver.mjs to silence CodeQL
|
||||
@@ -136,12 +139,10 @@ export const PACK_ARTIFACT_ROOT_ALLOWED_EXACT_PATHS: string[] = [
|
||||
"scripts/build/build-next-isolated.mjs",
|
||||
"scripts/check/check-supported-node-runtime.ts",
|
||||
"scripts/build/native-binary-compat.mjs",
|
||||
"scripts/build/wreqJsNative.mjs",
|
||||
"scripts/build/postinstall.mjs",
|
||||
"scripts/build/postinstallSupport.mjs",
|
||||
"scripts/build/colocateOptionals.mjs",
|
||||
// #7802: imported by scripts/build/postinstall.mjs to repair tls-client-node's
|
||||
// native binary (claude-web/grok-web/lmarena/perplexity-web transport).
|
||||
"scripts/build/fixTlsClientNodeBinary.mjs",
|
||||
// #8859: imported by scripts/build/postinstall.mjs to repair playwright-core's
|
||||
// browser resolution on Termux/Android (no glibc, no bundled browsers).
|
||||
"scripts/build/fixPlaywrightAndroid.mjs",
|
||||
@@ -222,13 +223,16 @@ export const PACK_ARTIFACT_REQUIRED_PATHS: string[] = [
|
||||
// or the CLI fails to boot — list them REQUIRED so a regression is loud.
|
||||
"bin/aliasResolver.mjs",
|
||||
"bin/aliasResolverHook.mjs",
|
||||
"config/release/wreq-js-native-manifest.json",
|
||||
"config/release/wreq-js-rust-license-inventory.json",
|
||||
"config/release/wreq-js-rust-notices.md",
|
||||
"package.json",
|
||||
"scripts/build/native-binary-compat.mjs",
|
||||
"scripts/build/postinstall.mjs",
|
||||
"scripts/build/postinstallSupport.mjs",
|
||||
"scripts/build/colocateOptionals.mjs",
|
||||
"scripts/build/fixTlsClientNodeBinary.mjs",
|
||||
"scripts/build/runtime-env.mjs",
|
||||
"scripts/build/wreqJsNative.mjs",
|
||||
// #10382: runtime imports of bin/cli/commands/packs.mjs (optional packs CLI) —
|
||||
// listed REQUIRED so their absence from the tarball fails loudly.
|
||||
"scripts/packs/optionalPackInstaller.mjs",
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
*
|
||||
* Modules repaired:
|
||||
* - better-sqlite3 (SQLite bindings)
|
||||
* - wreq-js (TLS client for OAuth providers)
|
||||
* - tls-client-node (TLS client for claude-web/grok-web/lmarena/perplexity-web)
|
||||
* - wreq-js (TLS client for OAuth and web-cookie providers)
|
||||
* - sql.js (WASM SQLite fallback runtime)
|
||||
* - node-machine-id (local CLI machine-token server runtime)
|
||||
*
|
||||
@@ -26,15 +25,7 @@
|
||||
* Fixes: https://github.com/diegosouzapw/OmniRoute/issues/7802
|
||||
*/
|
||||
|
||||
import {
|
||||
copyFileSync,
|
||||
cpSync,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
readdirSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -42,8 +33,8 @@ import { fileURLToPath } from "node:url";
|
||||
import { PUBLISHED_BUILD_ARCH, PUBLISHED_BUILD_PLATFORM } from "./native-binary-compat.mjs";
|
||||
import { hasStandaloneAppBundle, isTermux } from "./postinstallSupport.mjs";
|
||||
import { colocateLlmlinguaOptionals } from "./colocateOptionals.mjs";
|
||||
import { fixTlsClientNodeBinary } from "./fixTlsClientNodeBinary.mjs";
|
||||
import { fixPlaywrightAndroid } from "./fixPlaywrightAndroid.mjs";
|
||||
import { resolveWreqJsNativeBinding, WREQ_JS_VERSION } from "./wreqJsNative.mjs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
@@ -262,105 +253,60 @@ async function fixBetterSqliteBinary() {
|
||||
console.warn("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix wreq-js native binary for the standalone dist directory.
|
||||
*
|
||||
* wreq-js ships platform-specific .node binaries under rust/.
|
||||
* The standalone build may only contain Linux binaries from the CI.
|
||||
* This copies the correct platform binary from the root install.
|
||||
*
|
||||
* Fixes: https://github.com/diegosouzapw/OmniRoute/issues/1634
|
||||
*/
|
||||
/** Copy the current wreq-js 3.2 optional binding into the standalone dist tree. */
|
||||
async function fixWreqJsBinary() {
|
||||
// wreq-js native module is not loadable in Termux (libgcc path mismatch).
|
||||
// The runtime already falls back gracefully when wreq-js is unavailable.
|
||||
if (process.platform === "android" || isTermux()) {
|
||||
console.log(
|
||||
" [postinstall] wreq-js: skipped on Termux/Android " +
|
||||
"(libgcc not available — OAuth TLS fingerprinting will use the fallback path)"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const appWreqDir = join(ROOT, "dist", "node_modules", "wreq-js", "rust");
|
||||
const rootWreqDir = join(ROOT, "node_modules", "wreq-js", "rust");
|
||||
|
||||
if (!existsSync(join(ROOT, "dist", "node_modules", "wreq-js"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const binaryName = `wreq-js.${process.platform}-${process.arch}.node`;
|
||||
const appBinaryPath = join(appWreqDir, binaryName);
|
||||
const rootBinaryPath = join(rootWreqDir, binaryName);
|
||||
const runtimePlatform = isTermux() ? "android" : process.platform;
|
||||
const binding = resolveWreqJsNativeBinding({
|
||||
platform: runtimePlatform,
|
||||
arch: process.arch,
|
||||
});
|
||||
if (!binding) {
|
||||
console.warn(
|
||||
` ⚠️ wreq-js ${WREQ_JS_VERSION} has no native binding for ` +
|
||||
`${runtimePlatform}-${process.arch}.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const packageSegments = binding.packageName.split("/");
|
||||
const rootBindingDir = join(ROOT, "node_modules", ...packageSegments);
|
||||
const appBindingDir = join(ROOT, "dist", "node_modules", ...packageSegments);
|
||||
const rootBinaryPath = join(rootBindingDir, binding.fileName);
|
||||
const appBinaryPath = join(appBindingDir, binding.fileName);
|
||||
|
||||
// Check if the platform binary already exists and loads
|
||||
if (existsSync(appBinaryPath)) {
|
||||
try {
|
||||
process.dlopen({ exports: {} }, appBinaryPath);
|
||||
return; // Already working
|
||||
return;
|
||||
} catch (err) {
|
||||
console.warn(` ⚠️ wreq-js binary exists but failed to load: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n 🔧 Fixing wreq-js binary for ${process.platform}-${process.arch}...`);
|
||||
console.log(`\n 🔧 Fixing ${binding.packageName} for ${runtimePlatform}-${process.arch}...`);
|
||||
|
||||
// Strategy 1: Copy from root node_modules
|
||||
if (existsSync(rootBinaryPath)) {
|
||||
if (existsSync(rootBindingDir) && existsSync(rootBinaryPath)) {
|
||||
try {
|
||||
mkdirSync(appWreqDir, { recursive: true });
|
||||
copyFileSync(rootBinaryPath, appBinaryPath);
|
||||
mkdirSync(dirname(appBindingDir), { recursive: true });
|
||||
cpSync(rootBindingDir, appBindingDir, { recursive: true, force: true });
|
||||
process.dlopen({ exports: {} }, appBinaryPath);
|
||||
console.log(" ✅ wreq-js native module fixed successfully!\n");
|
||||
console.log(` ✅ ${binding.packageName} copied to standalone successfully!\n`);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.warn(` ⚠️ Copied wreq-js binary failed to load: ${err.message}`);
|
||||
console.warn(` ⚠️ Copied ${binding.packageName} failed to load: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 2: Copy entire rust/ directory from root (gets all platform binaries)
|
||||
if (existsSync(rootWreqDir)) {
|
||||
try {
|
||||
mkdirSync(appWreqDir, { recursive: true });
|
||||
const files = readdirSync(rootWreqDir);
|
||||
for (const file of files) {
|
||||
if (file.endsWith(".node")) {
|
||||
copyFileSync(join(rootWreqDir, file), join(appWreqDir, file));
|
||||
}
|
||||
}
|
||||
if (existsSync(appBinaryPath)) {
|
||||
process.dlopen({ exports: {} }, appBinaryPath);
|
||||
console.log(" ✅ wreq-js native module fixed (full copy) successfully!\n");
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(` ⚠️ wreq-js full copy failed: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 3: Rebuild wreq-js inside dist/
|
||||
console.log(" 📥 Attempting npm rebuild wreq-js...");
|
||||
try {
|
||||
const { execSync } = await import("node:child_process");
|
||||
execSync("npm rebuild wreq-js", {
|
||||
cwd: join(ROOT, "dist"),
|
||||
stdio: "inherit",
|
||||
timeout: 120_000,
|
||||
});
|
||||
if (existsSync(appBinaryPath)) {
|
||||
process.dlopen({ exports: {} }, appBinaryPath);
|
||||
console.log(" ✅ wreq-js native module rebuilt successfully!\n");
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(` ⚠️ wreq-js rebuild failed: ${err.message}`);
|
||||
}
|
||||
|
||||
console.warn(
|
||||
`\n ⚠️ Could not fix wreq-js native module for ${process.platform}-${process.arch}.`
|
||||
`\n ⚠️ Could not install ${binding.packageName}@${WREQ_JS_VERSION} for ` +
|
||||
`${runtimePlatform}-${process.arch}.`
|
||||
);
|
||||
console.warn(" OAuth-based providers (Codex, Cursor, etc.) may not work.");
|
||||
console.warn(` Manual fix: cd ${join(ROOT, "dist")} && npm install wreq-js --no-save\n`);
|
||||
console.warn(" Browser-TLS OAuth and web-cookie providers may not work.");
|
||||
console.warn(` Manual fix: npm install --include=optional wreq-js@${WREQ_JS_VERSION}\n`);
|
||||
}
|
||||
|
||||
async function ensureSwcHelpers() {
|
||||
@@ -470,7 +416,6 @@ async function ensureStandaloneRuntimePackages() {
|
||||
await verifyDevNativeModules();
|
||||
await fixBetterSqliteBinary();
|
||||
await fixWreqJsBinary();
|
||||
await fixTlsClientNodeBinary({ rootDir: ROOT });
|
||||
await fixPlaywrightAndroid({ rootDir: ROOT });
|
||||
await ensureSwcHelpers();
|
||||
await ensureStandaloneRuntimePackages();
|
||||
|
||||
131
scripts/build/wreqJsNative.mjs
Normal file
131
scripts/build/wreqJsNative.mjs
Normal file
@@ -0,0 +1,131 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
/** Exact native binding set published by wreq-js 3.2.0. */
|
||||
export const WREQ_JS_VERSION = "3.2.0";
|
||||
|
||||
export const WREQ_JS_NATIVE_BINDINGS = Object.freeze([
|
||||
{
|
||||
target: "android-arm64",
|
||||
packageName: "@wreq-js/binding-android-arm64",
|
||||
fileName: "wreq-js.android-arm64.node",
|
||||
platform: "android",
|
||||
arch: "arm64",
|
||||
},
|
||||
{
|
||||
target: "darwin-arm64",
|
||||
packageName: "@wreq-js/binding-darwin-arm64",
|
||||
fileName: "wreq-js.darwin-arm64.node",
|
||||
platform: "darwin",
|
||||
arch: "arm64",
|
||||
},
|
||||
{
|
||||
target: "darwin-x64",
|
||||
packageName: "@wreq-js/binding-darwin-x64",
|
||||
fileName: "wreq-js.darwin-x64.node",
|
||||
platform: "darwin",
|
||||
arch: "x64",
|
||||
},
|
||||
{
|
||||
target: "linux-arm64-gnu",
|
||||
packageName: "@wreq-js/binding-linux-arm64-gnu",
|
||||
fileName: "wreq-js.linux-arm64-gnu.node",
|
||||
platform: "linux",
|
||||
arch: "arm64",
|
||||
libc: "gnu",
|
||||
},
|
||||
{
|
||||
target: "linux-arm64-musl",
|
||||
packageName: "@wreq-js/binding-linux-arm64-musl",
|
||||
fileName: "wreq-js.linux-arm64-musl.node",
|
||||
platform: "linux",
|
||||
arch: "arm64",
|
||||
libc: "musl",
|
||||
},
|
||||
{
|
||||
target: "linux-x64-gnu",
|
||||
packageName: "@wreq-js/binding-linux-x64-gnu",
|
||||
fileName: "wreq-js.linux-x64-gnu.node",
|
||||
platform: "linux",
|
||||
arch: "x64",
|
||||
libc: "gnu",
|
||||
},
|
||||
{
|
||||
target: "linux-x64-musl",
|
||||
packageName: "@wreq-js/binding-linux-x64-musl",
|
||||
fileName: "wreq-js.linux-x64-musl.node",
|
||||
platform: "linux",
|
||||
arch: "x64",
|
||||
libc: "musl",
|
||||
},
|
||||
{
|
||||
target: "win32-arm64-msvc",
|
||||
packageName: "@wreq-js/binding-win32-arm64-msvc",
|
||||
fileName: "wreq-js.win32-arm64-msvc.node",
|
||||
platform: "win32",
|
||||
arch: "arm64",
|
||||
},
|
||||
{
|
||||
target: "win32-x64-msvc",
|
||||
packageName: "@wreq-js/binding-win32-x64-msvc",
|
||||
fileName: "wreq-js.win32-x64-msvc.node",
|
||||
platform: "win32",
|
||||
arch: "x64",
|
||||
},
|
||||
]);
|
||||
|
||||
function readSystemLdd() {
|
||||
const failures = [];
|
||||
for (const lddPath of ["/usr/bin/ldd", "/bin/ldd"]) {
|
||||
try {
|
||||
return readFileSync(lddPath, "utf8");
|
||||
} catch (error) {
|
||||
failures.push(error);
|
||||
}
|
||||
}
|
||||
throw failures[0] ?? new Error("ldd is unavailable");
|
||||
}
|
||||
|
||||
/** Detect the C library used by the current Linux runtime. */
|
||||
export function detectRuntimeLibc(options = {}) {
|
||||
const platform = options.platform ?? process.platform;
|
||||
if (platform !== "linux") return undefined;
|
||||
const getReport = options.getReport ?? (() => process.report?.getReport());
|
||||
const readLdd = options.readLdd ?? readSystemLdd;
|
||||
let reportError;
|
||||
try {
|
||||
const report = getReport();
|
||||
if (report?.header?.glibcVersionRuntime) return "gnu";
|
||||
if (report?.header) return "musl";
|
||||
} catch (error) {
|
||||
reportError = error;
|
||||
}
|
||||
|
||||
let lddError;
|
||||
try {
|
||||
const ldd = String(readLdd());
|
||||
if (/\bmusl\b/i.test(ldd)) return "musl";
|
||||
if (/\b(?:glibc|gnu libc|gnu c library)\b/i.test(ldd)) return "gnu";
|
||||
lddError = new Error("ldd output did not identify glibc or musl");
|
||||
} catch (error) {
|
||||
lddError = error;
|
||||
}
|
||||
|
||||
const detail = [reportError, lddError]
|
||||
.filter((error) => error instanceof Error)
|
||||
.map((error) => error.message)
|
||||
.join("; ");
|
||||
throw new Error(`Unable to detect Linux libc${detail ? `: ${detail}` : ""}`);
|
||||
}
|
||||
|
||||
/** Resolve the exact package and addon filename wreq-js 3.2.0 loads. */
|
||||
export function resolveWreqJsNativeBinding({ platform, arch, libc }) {
|
||||
const runtimeLibc = platform === "linux" ? (libc ?? detectRuntimeLibc()) : undefined;
|
||||
return (
|
||||
WREQ_JS_NATIVE_BINDINGS.find(
|
||||
(binding) =>
|
||||
binding.platform === platform &&
|
||||
binding.arch === arch &&
|
||||
(binding.libc === undefined || binding.libc === runtimeLibc)
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user