@cloudflare/vitest-pool-workers 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pool/index.mjs +675 -3
- package/dist/pool/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/pool/index.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import assert from "node:assert";
|
|
3
|
-
import crypto from "node:crypto";
|
|
4
|
-
import fs, { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import crypto, { createHash } from "node:crypto";
|
|
4
|
+
import fs, { accessSync, chmodSync, constants, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import path, { dirname, isAbsolute, join, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
7
|
import util from "node:util";
|
|
8
|
-
import os from "node:os";
|
|
8
|
+
import os, { arch } from "node:os";
|
|
9
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
10
|
+
import { fetch } from "undici";
|
|
9
11
|
import net from "node:net";
|
|
10
12
|
import { Log, LogLevel, Miniflare, ModuleRuleTypeSchema, PLUGINS, Response, compileModuleRules, formatZodError, getNodeCompat, getRootPath, kCurrentWorker, kUnsafeEphemeralUniqueKey, maybeApply, mergeWorkerOptions, parseWithRootPath, structuredSerializableReducers, structuredSerializableRevivers, testRegExps } from "miniflare";
|
|
11
13
|
import { experimental_readRawConfig } from "wrangler";
|
|
@@ -3412,6 +3414,113 @@ var require_mod_cjs3 = __commonJS({ "../../node_modules/.pnpm/xdg-app-paths@8.3.
|
|
|
3412
3414
|
var node_js_1 = require_node3();
|
|
3413
3415
|
module$1.exports = XDGAppPaths_js_1.Adapt(node_js_1.adapter).XDGAppPaths;
|
|
3414
3416
|
} });
|
|
3417
|
+
var require_command_exists = __commonJS({ "../../node_modules/.pnpm/command-exists@1.2.9/node_modules/command-exists/lib/command-exists.js"(exports$1, module$1) {
|
|
3418
|
+
var exec = __require("child_process").exec;
|
|
3419
|
+
var execSync = __require("child_process").execSync;
|
|
3420
|
+
var fs2 = __require("fs");
|
|
3421
|
+
var path4 = __require("path");
|
|
3422
|
+
var access = fs2.access;
|
|
3423
|
+
var accessSync2 = fs2.accessSync;
|
|
3424
|
+
var constants2 = fs2.constants || fs2;
|
|
3425
|
+
var isUsingWindows = process.platform == "win32";
|
|
3426
|
+
var fileNotExists = /* @__PURE__ */ __name(function(commandName, callback) {
|
|
3427
|
+
access(commandName, constants2.F_OK, function(err) {
|
|
3428
|
+
callback(!err);
|
|
3429
|
+
});
|
|
3430
|
+
}, "fileNotExists");
|
|
3431
|
+
var fileNotExistsSync = /* @__PURE__ */ __name(function(commandName) {
|
|
3432
|
+
try {
|
|
3433
|
+
accessSync2(commandName, constants2.F_OK);
|
|
3434
|
+
return false;
|
|
3435
|
+
} catch (e2) {
|
|
3436
|
+
return true;
|
|
3437
|
+
}
|
|
3438
|
+
}, "fileNotExistsSync");
|
|
3439
|
+
var localExecutable = /* @__PURE__ */ __name(function(commandName, callback) {
|
|
3440
|
+
access(commandName, constants2.F_OK | constants2.X_OK, function(err) {
|
|
3441
|
+
callback(null, !err);
|
|
3442
|
+
});
|
|
3443
|
+
}, "localExecutable");
|
|
3444
|
+
var localExecutableSync = /* @__PURE__ */ __name(function(commandName) {
|
|
3445
|
+
try {
|
|
3446
|
+
accessSync2(commandName, constants2.F_OK | constants2.X_OK);
|
|
3447
|
+
return true;
|
|
3448
|
+
} catch (e2) {
|
|
3449
|
+
return false;
|
|
3450
|
+
}
|
|
3451
|
+
}, "localExecutableSync");
|
|
3452
|
+
var commandExistsUnix = /* @__PURE__ */ __name(function(commandName, cleanedCommandName, callback) {
|
|
3453
|
+
fileNotExists(commandName, function(isFile$1) {
|
|
3454
|
+
if (!isFile$1) {
|
|
3455
|
+
exec("command -v " + cleanedCommandName + " 2>/dev/null && { echo >&1 " + cleanedCommandName + "; exit 0; }", function(error, stdout, stderr) {
|
|
3456
|
+
callback(null, !!stdout);
|
|
3457
|
+
});
|
|
3458
|
+
return;
|
|
3459
|
+
}
|
|
3460
|
+
localExecutable(commandName, callback);
|
|
3461
|
+
});
|
|
3462
|
+
}, "commandExistsUnix");
|
|
3463
|
+
var commandExistsWindows = /* @__PURE__ */ __name(function(commandName, cleanedCommandName, callback) {
|
|
3464
|
+
if (!/^(?!(?:.*\s|.*\.|\W+)$)(?:[a-zA-Z]:)?(?:(?:[^<>:"\|\?\*\n])+(?:\/\/|\/|\\\\|\\)?)+$/m.test(commandName)) {
|
|
3465
|
+
callback(null, false);
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
exec("where " + cleanedCommandName, function(error) {
|
|
3469
|
+
if (error !== null) callback(null, false);
|
|
3470
|
+
else callback(null, true);
|
|
3471
|
+
});
|
|
3472
|
+
}, "commandExistsWindows");
|
|
3473
|
+
var commandExistsUnixSync = /* @__PURE__ */ __name(function(commandName, cleanedCommandName) {
|
|
3474
|
+
if (fileNotExistsSync(commandName)) try {
|
|
3475
|
+
return !!execSync("command -v " + cleanedCommandName + " 2>/dev/null && { echo >&1 " + cleanedCommandName + "; exit 0; }");
|
|
3476
|
+
} catch (error) {
|
|
3477
|
+
return false;
|
|
3478
|
+
}
|
|
3479
|
+
return localExecutableSync(commandName);
|
|
3480
|
+
}, "commandExistsUnixSync");
|
|
3481
|
+
var commandExistsWindowsSync = /* @__PURE__ */ __name(function(commandName, cleanedCommandName, callback) {
|
|
3482
|
+
if (!/^(?!(?:.*\s|.*\.|\W+)$)(?:[a-zA-Z]:)?(?:(?:[^<>:"\|\?\*\n])+(?:\/\/|\/|\\\\|\\)?)+$/m.test(commandName)) return false;
|
|
3483
|
+
try {
|
|
3484
|
+
return !!execSync("where " + cleanedCommandName, { stdio: [] });
|
|
3485
|
+
} catch (error) {
|
|
3486
|
+
return false;
|
|
3487
|
+
}
|
|
3488
|
+
}, "commandExistsWindowsSync");
|
|
3489
|
+
var cleanInput = /* @__PURE__ */ __name(function(s) {
|
|
3490
|
+
if (/[^A-Za-z0-9_\/:=-]/.test(s)) {
|
|
3491
|
+
s = "'" + s.replace(/'/g, "'\\''") + "'";
|
|
3492
|
+
s = s.replace(/^(?:'')+/g, "").replace(/\\'''/g, "\\'");
|
|
3493
|
+
}
|
|
3494
|
+
return s;
|
|
3495
|
+
}, "cleanInput");
|
|
3496
|
+
if (isUsingWindows) cleanInput = /* @__PURE__ */ __name(function(s) {
|
|
3497
|
+
if (/[\\]/.test(s)) {
|
|
3498
|
+
var dirname2 = "\"" + path4.dirname(s) + "\"";
|
|
3499
|
+
var basename = "\"" + path4.basename(s) + "\"";
|
|
3500
|
+
return dirname2 + ":" + basename;
|
|
3501
|
+
}
|
|
3502
|
+
return "\"" + s + "\"";
|
|
3503
|
+
}, "cleanInput");
|
|
3504
|
+
module$1.exports = /* @__PURE__ */ __name(function commandExists(commandName, callback) {
|
|
3505
|
+
var cleanedCommandName = cleanInput(commandName);
|
|
3506
|
+
if (!callback && typeof Promise !== "undefined") return new Promise(function(resolve$2, reject) {
|
|
3507
|
+
commandExists(commandName, function(error, output) {
|
|
3508
|
+
if (output) resolve$2(commandName);
|
|
3509
|
+
else reject(error);
|
|
3510
|
+
});
|
|
3511
|
+
});
|
|
3512
|
+
if (isUsingWindows) commandExistsWindows(commandName, cleanedCommandName, callback);
|
|
3513
|
+
else commandExistsUnix(commandName, cleanedCommandName, callback);
|
|
3514
|
+
}, "commandExists");
|
|
3515
|
+
module$1.exports.sync = function(commandName) {
|
|
3516
|
+
var cleanedCommandName = cleanInput(commandName);
|
|
3517
|
+
if (isUsingWindows) return commandExistsWindowsSync(commandName, cleanedCommandName);
|
|
3518
|
+
else return commandExistsUnixSync(commandName, cleanedCommandName);
|
|
3519
|
+
};
|
|
3520
|
+
} });
|
|
3521
|
+
var require_command_exists2 = __commonJS({ "../../node_modules/.pnpm/command-exists@1.2.9/node_modules/command-exists/index.js"(exports$1, module$1) {
|
|
3522
|
+
module$1.exports = require_command_exists();
|
|
3523
|
+
} });
|
|
3415
3524
|
var defaultWranglerConfig = {
|
|
3416
3525
|
configPath: void 0,
|
|
3417
3526
|
userConfigPath: void 0,
|
|
@@ -9775,6 +9884,569 @@ Pages requires Durable Object bindings to specify the name of the Worker where t
|
|
|
9775
9884
|
}
|
|
9776
9885
|
}
|
|
9777
9886
|
__name(validateDurableObjectBinding2, "validateDurableObjectBinding");
|
|
9887
|
+
var import_command_exists = __toESM(require_command_exists2());
|
|
9888
|
+
var UPDATE_SERVICE_URL = "https://update.argotunnel.com";
|
|
9889
|
+
var CLOUDFLARED_VERSION_PATTERN = /^\d{4}\.\d+\.\d+$/;
|
|
9890
|
+
function sha256Hex(buffer) {
|
|
9891
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
9892
|
+
}
|
|
9893
|
+
__name(sha256Hex, "sha256Hex");
|
|
9894
|
+
function getGoArch() {
|
|
9895
|
+
const nodeArch = arch();
|
|
9896
|
+
switch (nodeArch) {
|
|
9897
|
+
case "x64": return "amd64";
|
|
9898
|
+
case "arm64": return "arm64";
|
|
9899
|
+
case "arm": return "arm";
|
|
9900
|
+
default: throw new UserError(`Unsupported architecture for cloudflared: ${nodeArch}
|
|
9901
|
+
|
|
9902
|
+
cloudflared supports: x64 (amd64), arm64, arm
|
|
9903
|
+
|
|
9904
|
+
You can manually install cloudflared and set the CLOUDFLARED_PATH environment variable.
|
|
9905
|
+
Download instructions: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/`);
|
|
9906
|
+
}
|
|
9907
|
+
}
|
|
9908
|
+
__name(getGoArch, "getGoArch");
|
|
9909
|
+
function getGoOS() {
|
|
9910
|
+
switch (process.platform) {
|
|
9911
|
+
case "darwin": return "darwin";
|
|
9912
|
+
case "linux": return "linux";
|
|
9913
|
+
case "win32": return "windows";
|
|
9914
|
+
default: throw new UserError(`Unsupported platform for cloudflared: ${process.platform}
|
|
9915
|
+
|
|
9916
|
+
cloudflared supports: darwin (macOS), linux, win32 (Windows)
|
|
9917
|
+
|
|
9918
|
+
You can manually install cloudflared and set the CLOUDFLARED_PATH environment variable.
|
|
9919
|
+
Download instructions: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/`);
|
|
9920
|
+
}
|
|
9921
|
+
}
|
|
9922
|
+
__name(getGoOS, "getGoOS");
|
|
9923
|
+
var GITHUB_RELEASE_BASE = "https://github.com/cloudflare/cloudflared/releases/download";
|
|
9924
|
+
function getAssetFilename(goOS, goArch) {
|
|
9925
|
+
if (goOS === "windows") return `cloudflared-${goOS}-${goArch}.exe`;
|
|
9926
|
+
if (goOS === "darwin") return `cloudflared-${goOS}-${goArch}.tgz`;
|
|
9927
|
+
return `cloudflared-${goOS}-${goArch}`;
|
|
9928
|
+
}
|
|
9929
|
+
__name(getAssetFilename, "getAssetFilename");
|
|
9930
|
+
async function queryUpdateService(goOS, goArch, options) {
|
|
9931
|
+
const { logger } = options ?? {};
|
|
9932
|
+
const url = new URL(UPDATE_SERVICE_URL);
|
|
9933
|
+
url.searchParams.set("os", goOS);
|
|
9934
|
+
url.searchParams.set("arch", goArch);
|
|
9935
|
+
logger?.debug(`Checking for latest cloudflared: ${url.toString()}`);
|
|
9936
|
+
let response;
|
|
9937
|
+
try {
|
|
9938
|
+
response = await fetch(url.toString(), { headers: { "User-Agent": "wrangler" } });
|
|
9939
|
+
} catch (e2) {
|
|
9940
|
+
logger?.debug(`Failed to reach update service: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
9941
|
+
return null;
|
|
9942
|
+
}
|
|
9943
|
+
if (!response.ok) {
|
|
9944
|
+
logger?.debug(`Update service returned ${response.status} for ${goOS}/${goArch}`);
|
|
9945
|
+
return null;
|
|
9946
|
+
}
|
|
9947
|
+
let data;
|
|
9948
|
+
try {
|
|
9949
|
+
data = await response.json();
|
|
9950
|
+
} catch (e2) {
|
|
9951
|
+
logger?.debug(`Update service returned non-JSON response: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
9952
|
+
return null;
|
|
9953
|
+
}
|
|
9954
|
+
if (typeof data.version === "string" && !CLOUDFLARED_VERSION_PATTERN.test(data.version)) throw new Error(`[cloudflared] Invalid cloudflared version returned by update service: ${data.version}`);
|
|
9955
|
+
if (data.error || !data.url || !data.version) return data.version ? data : null;
|
|
9956
|
+
return data;
|
|
9957
|
+
}
|
|
9958
|
+
__name(queryUpdateService, "queryUpdateService");
|
|
9959
|
+
async function getLatestVersionInfo(options) {
|
|
9960
|
+
const { logger } = options ?? {};
|
|
9961
|
+
const goOS = getGoOS();
|
|
9962
|
+
const goArch = getGoArch();
|
|
9963
|
+
const primary = await queryUpdateService(goOS, goArch, { logger });
|
|
9964
|
+
if (primary && primary.url && primary.version) return primary;
|
|
9965
|
+
logger?.debug(`Update worker had no result for ${goOS}/${goArch}, falling back to GitHub release URL`);
|
|
9966
|
+
const fallback = await queryUpdateService("linux", "amd64", { logger });
|
|
9967
|
+
if (!fallback?.version) throw new UserError(`[cloudflared] Failed to determine the latest cloudflared version.
|
|
9968
|
+
|
|
9969
|
+
The update service did not return results for ${goOS}/${goArch},
|
|
9970
|
+
and the fallback query also failed.
|
|
9971
|
+
|
|
9972
|
+
You can manually install cloudflared from:
|
|
9973
|
+
https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/`);
|
|
9974
|
+
const version = fallback.version;
|
|
9975
|
+
const filename = getAssetFilename(goOS, goArch);
|
|
9976
|
+
return {
|
|
9977
|
+
url: `${GITHUB_RELEASE_BASE}/${version}/${filename}`,
|
|
9978
|
+
version,
|
|
9979
|
+
checksum: "",
|
|
9980
|
+
compressed: filename.endsWith(".tgz"),
|
|
9981
|
+
shouldUpdate: true,
|
|
9982
|
+
userMessage: "",
|
|
9983
|
+
error: ""
|
|
9984
|
+
};
|
|
9985
|
+
}
|
|
9986
|
+
__name(getLatestVersionInfo, "getLatestVersionInfo");
|
|
9987
|
+
function getCacheDir(version) {
|
|
9988
|
+
return join(getGlobalWranglerConfigPath(), "cloudflared", version);
|
|
9989
|
+
}
|
|
9990
|
+
__name(getCacheDir, "getCacheDir");
|
|
9991
|
+
function getCloudflaredBinPath(version) {
|
|
9992
|
+
const binName = process.platform === "win32" ? "cloudflared.exe" : "cloudflared";
|
|
9993
|
+
return join(getCacheDir(version), binName);
|
|
9994
|
+
}
|
|
9995
|
+
__name(getCloudflaredBinPath, "getCloudflaredBinPath");
|
|
9996
|
+
function isBinaryExecutable(binPath) {
|
|
9997
|
+
try {
|
|
9998
|
+
accessSync(binPath, constants.X_OK);
|
|
9999
|
+
return true;
|
|
10000
|
+
} catch {
|
|
10001
|
+
return false;
|
|
10002
|
+
}
|
|
10003
|
+
}
|
|
10004
|
+
__name(isBinaryExecutable, "isBinaryExecutable");
|
|
10005
|
+
function validateBinary(binPath, options) {
|
|
10006
|
+
const { logger } = options ?? {};
|
|
10007
|
+
try {
|
|
10008
|
+
const output = execFileSync(binPath, ["--version"], {
|
|
10009
|
+
stdio: [
|
|
10010
|
+
"pipe",
|
|
10011
|
+
"pipe",
|
|
10012
|
+
"pipe"
|
|
10013
|
+
],
|
|
10014
|
+
timeout: 1e4,
|
|
10015
|
+
encoding: "utf8"
|
|
10016
|
+
}).trim();
|
|
10017
|
+
logger?.debug(`cloudflared version: ${output}`);
|
|
10018
|
+
} catch {
|
|
10019
|
+
let errorMessage = `[cloudflared] Failed to validate cloudflared binary at ${binPath}
|
|
10020
|
+
|
|
10021
|
+
`;
|
|
10022
|
+
errorMessage += `This usually means:
|
|
10023
|
+
`;
|
|
10024
|
+
errorMessage += ` - The binary is corrupted or incomplete
|
|
10025
|
+
`;
|
|
10026
|
+
errorMessage += ` - You're missing required system libraries
|
|
10027
|
+
`;
|
|
10028
|
+
if (process.platform === "linux") {
|
|
10029
|
+
errorMessage += `
|
|
10030
|
+
On Linux, make sure you have the required dependencies:
|
|
10031
|
+
`;
|
|
10032
|
+
errorMessage += ` - glibc (GNU C Library)
|
|
10033
|
+
`;
|
|
10034
|
+
errorMessage += ` - For Debian/Ubuntu: sudo apt-get install libc6
|
|
10035
|
+
`;
|
|
10036
|
+
}
|
|
10037
|
+
const cacheDir = join(getGlobalWranglerConfigPath(), "cloudflared");
|
|
10038
|
+
errorMessage += `
|
|
10039
|
+
You can try:
|
|
10040
|
+
`;
|
|
10041
|
+
errorMessage += ` 1. Deleting the cache directory: rm -rf ${cacheDir}
|
|
10042
|
+
`;
|
|
10043
|
+
errorMessage += ` 2. Running the command again to re-download
|
|
10044
|
+
`;
|
|
10045
|
+
errorMessage += ` 3. Manually installing cloudflared: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/
|
|
10046
|
+
`;
|
|
10047
|
+
errorMessage += ` 4. Setting CLOUDFLARED_PATH to point to your cloudflared binary`;
|
|
10048
|
+
throw new UserError(errorMessage);
|
|
10049
|
+
}
|
|
10050
|
+
}
|
|
10051
|
+
__name(validateBinary, "validateBinary");
|
|
10052
|
+
function redactCloudflaredArgsForLogging(args) {
|
|
10053
|
+
const redacted = [...args];
|
|
10054
|
+
for (let i = 0; i < redacted.length; i++) {
|
|
10055
|
+
const arg = redacted[i];
|
|
10056
|
+
if (arg === "--token" && i + 1 < redacted.length) redacted[i + 1] = "[REDACTED]";
|
|
10057
|
+
if (arg.startsWith("--token=")) redacted[i] = "--token=[REDACTED]";
|
|
10058
|
+
}
|
|
10059
|
+
return redacted;
|
|
10060
|
+
}
|
|
10061
|
+
__name(redactCloudflaredArgsForLogging, "redactCloudflaredArgsForLogging");
|
|
10062
|
+
function tryGetCloudflaredFromPath(options) {
|
|
10063
|
+
const { logger } = options ?? {};
|
|
10064
|
+
if (!(0, import_command_exists.sync)("cloudflared")) return null;
|
|
10065
|
+
try {
|
|
10066
|
+
validateBinary("cloudflared", { logger });
|
|
10067
|
+
return "cloudflared";
|
|
10068
|
+
} catch (e2) {
|
|
10069
|
+
logger?.debug("cloudflared found in PATH but failed validation", e2);
|
|
10070
|
+
return null;
|
|
10071
|
+
}
|
|
10072
|
+
}
|
|
10073
|
+
__name(tryGetCloudflaredFromPath, "tryGetCloudflaredFromPath");
|
|
10074
|
+
function getInstalledVersion(binPath) {
|
|
10075
|
+
try {
|
|
10076
|
+
const match = execFileSync(binPath, ["--version"], {
|
|
10077
|
+
stdio: [
|
|
10078
|
+
"pipe",
|
|
10079
|
+
"pipe",
|
|
10080
|
+
"pipe"
|
|
10081
|
+
],
|
|
10082
|
+
timeout: 1e4,
|
|
10083
|
+
encoding: "utf8"
|
|
10084
|
+
}).match(/(\d+\.\d+\.\d+)/);
|
|
10085
|
+
return match ? match[1] : null;
|
|
10086
|
+
} catch {
|
|
10087
|
+
return null;
|
|
10088
|
+
}
|
|
10089
|
+
}
|
|
10090
|
+
__name(getInstalledVersion, "getInstalledVersion");
|
|
10091
|
+
function isVersionOutdated(installed, latest) {
|
|
10092
|
+
const parse$2 = /* @__PURE__ */ __name((v) => v.split(".").map(Number), "parse");
|
|
10093
|
+
const [iYear, iMonth, iPatch] = parse$2(installed);
|
|
10094
|
+
const [lYear, lMonth, lPatch] = parse$2(latest);
|
|
10095
|
+
if (iYear !== lYear) return iYear < lYear;
|
|
10096
|
+
if (iMonth !== lMonth) return iMonth < lMonth;
|
|
10097
|
+
return iPatch < lPatch;
|
|
10098
|
+
}
|
|
10099
|
+
__name(isVersionOutdated, "isVersionOutdated");
|
|
10100
|
+
async function warnIfOutdated(binPath, options) {
|
|
10101
|
+
const { logger } = options ?? {};
|
|
10102
|
+
try {
|
|
10103
|
+
const installed = getInstalledVersion(binPath);
|
|
10104
|
+
if (!installed) return;
|
|
10105
|
+
const latestVersion = (await queryUpdateService(getGoOS(), getGoArch(), { logger }) ?? await queryUpdateService("linux", "amd64", { logger }))?.version;
|
|
10106
|
+
if (!latestVersion) return;
|
|
10107
|
+
if (isVersionOutdated(installed, latestVersion)) logger?.warn(`Your cloudflared (${installed}) is outdated. Latest version is ${latestVersion}.
|
|
10108
|
+
Update: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/`);
|
|
10109
|
+
} catch (e2) {
|
|
10110
|
+
logger?.debug("Failed to check cloudflared version", e2);
|
|
10111
|
+
}
|
|
10112
|
+
}
|
|
10113
|
+
__name(warnIfOutdated, "warnIfOutdated");
|
|
10114
|
+
function writeFileAtomic(filePath, contents) {
|
|
10115
|
+
const tmpPath = join(dirname(filePath), `.tmp-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
10116
|
+
try {
|
|
10117
|
+
writeFileSync(tmpPath, contents);
|
|
10118
|
+
renameSync(tmpPath, filePath);
|
|
10119
|
+
} finally {
|
|
10120
|
+
try {
|
|
10121
|
+
if (existsSync(tmpPath)) unlinkSync(tmpPath);
|
|
10122
|
+
} catch {}
|
|
10123
|
+
}
|
|
10124
|
+
}
|
|
10125
|
+
__name(writeFileAtomic, "writeFileAtomic");
|
|
10126
|
+
async function downloadCloudflared(versionInfo, binPath, options) {
|
|
10127
|
+
const { logger } = options ?? {};
|
|
10128
|
+
const { url, version, checksum, compressed } = versionInfo;
|
|
10129
|
+
logger?.log(`Downloading cloudflared ${version}...`);
|
|
10130
|
+
logger?.debug(`Download URL: ${url}`);
|
|
10131
|
+
const cacheDir = dirname(binPath);
|
|
10132
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
10133
|
+
let response;
|
|
10134
|
+
try {
|
|
10135
|
+
response = await fetch(url, { headers: { "User-Agent": "wrangler" } });
|
|
10136
|
+
} catch (e2) {
|
|
10137
|
+
throw new UserError(`[cloudflared] Failed to download cloudflared from ${url}
|
|
10138
|
+
|
|
10139
|
+
Network error: ${e2 instanceof Error ? e2.message : String(e2)}
|
|
10140
|
+
|
|
10141
|
+
Please check your internet connection and try again.
|
|
10142
|
+
If you're behind a proxy, make sure it's configured correctly.`);
|
|
10143
|
+
}
|
|
10144
|
+
if (!response.ok) throw new UserError(`[cloudflared] Failed to download cloudflared from ${url}
|
|
10145
|
+
|
|
10146
|
+
HTTP ${response.status}: ${response.statusText}
|
|
10147
|
+
|
|
10148
|
+
You can manually download cloudflared from:
|
|
10149
|
+
https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/`);
|
|
10150
|
+
try {
|
|
10151
|
+
if (compressed) await downloadAndExtractTarball(response, checksum, binPath, cacheDir);
|
|
10152
|
+
else await downloadBinary(response, checksum, binPath);
|
|
10153
|
+
} catch (e2) {
|
|
10154
|
+
try {
|
|
10155
|
+
if (existsSync(binPath)) unlinkSync(binPath);
|
|
10156
|
+
} catch {}
|
|
10157
|
+
if (e2 instanceof UserError) throw e2;
|
|
10158
|
+
throw new UserError(`[cloudflared] Failed to save cloudflared binary
|
|
10159
|
+
|
|
10160
|
+
Error: ${e2 instanceof Error ? e2.message : String(e2)}
|
|
10161
|
+
|
|
10162
|
+
Please ensure you have write permissions to: ${cacheDir}`);
|
|
10163
|
+
}
|
|
10164
|
+
if (process.platform !== "win32") chmodSync(binPath, 493);
|
|
10165
|
+
logger?.log(`cloudflared ${version} installed`);
|
|
10166
|
+
logger?.debug(`Binary location: ${binPath}`);
|
|
10167
|
+
}
|
|
10168
|
+
__name(downloadCloudflared, "downloadCloudflared");
|
|
10169
|
+
async function downloadAndExtractTarball(response, expectedChecksum, binPath, cacheDir) {
|
|
10170
|
+
const tempTarPath = join(cacheDir, "cloudflared.tgz");
|
|
10171
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
10172
|
+
if (expectedChecksum) {
|
|
10173
|
+
const actualSha256 = sha256Hex(buffer);
|
|
10174
|
+
if (actualSha256 !== expectedChecksum) throw new UserError(`[cloudflared] SHA256 mismatch for downloaded cloudflared tarball.
|
|
10175
|
+
|
|
10176
|
+
Expected: ${expectedChecksum}
|
|
10177
|
+
Actual: ${actualSha256}`);
|
|
10178
|
+
}
|
|
10179
|
+
writeFileSync(tempTarPath, buffer);
|
|
10180
|
+
try {
|
|
10181
|
+
execFileSync("tar", [
|
|
10182
|
+
"-xzf",
|
|
10183
|
+
tempTarPath,
|
|
10184
|
+
"-C",
|
|
10185
|
+
cacheDir
|
|
10186
|
+
], { stdio: "ignore" });
|
|
10187
|
+
const extractedPath = join(cacheDir, "cloudflared");
|
|
10188
|
+
if (extractedPath !== binPath && existsSync(extractedPath)) renameSync(extractedPath, binPath);
|
|
10189
|
+
} finally {
|
|
10190
|
+
try {
|
|
10191
|
+
if (existsSync(tempTarPath)) unlinkSync(tempTarPath);
|
|
10192
|
+
} catch {}
|
|
10193
|
+
}
|
|
10194
|
+
}
|
|
10195
|
+
__name(downloadAndExtractTarball, "downloadAndExtractTarball");
|
|
10196
|
+
async function downloadBinary(response, expectedChecksum, binPath) {
|
|
10197
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
10198
|
+
if (expectedChecksum) {
|
|
10199
|
+
const actualSha256 = sha256Hex(buffer);
|
|
10200
|
+
if (actualSha256 !== expectedChecksum) throw new UserError(`[cloudflared] SHA256 mismatch for downloaded cloudflared binary.
|
|
10201
|
+
|
|
10202
|
+
Expected: ${expectedChecksum}
|
|
10203
|
+
Actual: ${actualSha256}`);
|
|
10204
|
+
}
|
|
10205
|
+
writeFileAtomic(binPath, buffer);
|
|
10206
|
+
}
|
|
10207
|
+
__name(downloadBinary, "downloadBinary");
|
|
10208
|
+
async function getCloudflaredPath(options) {
|
|
10209
|
+
const logger = options?.logger;
|
|
10210
|
+
const envPath = getCloudflaredPathFromEnv();
|
|
10211
|
+
if (envPath) {
|
|
10212
|
+
if (!existsSync(envPath)) throw new UserError(`CLOUDFLARED_PATH is set to "${envPath}" but the file does not exist.
|
|
10213
|
+
|
|
10214
|
+
Please ensure the path points to a valid cloudflared binary.`);
|
|
10215
|
+
logger?.debug(`Using cloudflared from CLOUDFLARED_PATH: ${envPath}`);
|
|
10216
|
+
return envPath;
|
|
10217
|
+
}
|
|
10218
|
+
const pathBin = tryGetCloudflaredFromPath({ logger });
|
|
10219
|
+
if (pathBin) {
|
|
10220
|
+
logger?.debug("Using cloudflared from PATH");
|
|
10221
|
+
if (!options?.skipVersionCheck) await warnIfOutdated(pathBin, { logger });
|
|
10222
|
+
return pathBin;
|
|
10223
|
+
}
|
|
10224
|
+
const versionInfo = await getLatestVersionInfo({ logger });
|
|
10225
|
+
const binPath = getCloudflaredBinPath(versionInfo.version);
|
|
10226
|
+
let needsDownload = !isBinaryExecutable(binPath);
|
|
10227
|
+
if (!needsDownload) try {
|
|
10228
|
+
validateBinary(binPath, { logger });
|
|
10229
|
+
logger?.debug(`Using cached cloudflared ${versionInfo.version}: ${binPath}`);
|
|
10230
|
+
return binPath;
|
|
10231
|
+
} catch (e2) {
|
|
10232
|
+
logger?.debug("Cached cloudflared failed validation; re-downloading", e2);
|
|
10233
|
+
needsDownload = true;
|
|
10234
|
+
}
|
|
10235
|
+
if (!(await options?.confirmDownload?.(`cloudflared (${versionInfo.version}) is needed but not installed. Download to ${binPath}?`) ?? true)) throw new UserError(`cloudflared is required to run this command.
|
|
10236
|
+
|
|
10237
|
+
You can install it manually from:
|
|
10238
|
+
https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/
|
|
10239
|
+
|
|
10240
|
+
Then either add it to your PATH or set CLOUDFLARED_PATH.`);
|
|
10241
|
+
if (existsSync(binPath)) {
|
|
10242
|
+
const cacheDir = removeCloudflaredCache(versionInfo.version);
|
|
10243
|
+
if (cacheDir) logger?.log(`Removed cloudflared cache: ${cacheDir}`);
|
|
10244
|
+
}
|
|
10245
|
+
await downloadCloudflared(versionInfo, binPath, { logger });
|
|
10246
|
+
validateBinary(binPath, { logger });
|
|
10247
|
+
return binPath;
|
|
10248
|
+
}
|
|
10249
|
+
__name(getCloudflaredPath, "getCloudflaredPath");
|
|
10250
|
+
async function spawnCloudflared(args, options) {
|
|
10251
|
+
const logger = options?.logger;
|
|
10252
|
+
const binPath = await getCloudflaredPath({
|
|
10253
|
+
skipVersionCheck: options?.skipVersionCheck,
|
|
10254
|
+
confirmDownload: options?.confirmDownload,
|
|
10255
|
+
logger
|
|
10256
|
+
});
|
|
10257
|
+
logger?.debug(`Spawning cloudflared: ${binPath} ${redactCloudflaredArgsForLogging(args).join(" ")}`);
|
|
10258
|
+
return spawn(binPath, args, {
|
|
10259
|
+
stdio: options?.stdio ?? "inherit",
|
|
10260
|
+
env: options?.env ? {
|
|
10261
|
+
...process.env,
|
|
10262
|
+
...options.env
|
|
10263
|
+
} : void 0
|
|
10264
|
+
});
|
|
10265
|
+
}
|
|
10266
|
+
__name(spawnCloudflared, "spawnCloudflared");
|
|
10267
|
+
function removeCloudflaredCache(version) {
|
|
10268
|
+
const cacheDir = version ? getCacheDir(version) : join(getGlobalWranglerConfigPath(), "cloudflared");
|
|
10269
|
+
if (existsSync(cacheDir)) {
|
|
10270
|
+
removeDirSync(cacheDir);
|
|
10271
|
+
return cacheDir;
|
|
10272
|
+
}
|
|
10273
|
+
return null;
|
|
10274
|
+
}
|
|
10275
|
+
__name(removeCloudflaredCache, "removeCloudflaredCache");
|
|
10276
|
+
var TUNNEL_STARTUP_TIMEOUT_MS = 3e4;
|
|
10277
|
+
var TUNNEL_FORCE_KILL_TIMEOUT_MS = 5e3;
|
|
10278
|
+
var DEFAULT_TUNNEL_EXPIRY_MS = 3600 * 1e3;
|
|
10279
|
+
var DEFAULT_TUNNEL_EXTENSION_MS = 3600 * 1e3;
|
|
10280
|
+
var DEFAULT_TUNNEL_MAX_REMAINING_MS = 10800 * 1e3;
|
|
10281
|
+
var DEFAULT_TUNNEL_REMINDER_INTERVAL_MS = 600 * 1e3;
|
|
10282
|
+
var QUICK_TUNNEL_URL_REGEX = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
|
|
10283
|
+
function startTunnel(options) {
|
|
10284
|
+
let disposed = false;
|
|
10285
|
+
let reminderInterval;
|
|
10286
|
+
let expiryTimeout;
|
|
10287
|
+
let expiresAt = 0;
|
|
10288
|
+
let cloudflaredProcess;
|
|
10289
|
+
const logger = options.logger;
|
|
10290
|
+
const timeoutMs = options.timeoutMs ?? TUNNEL_STARTUP_TIMEOUT_MS;
|
|
10291
|
+
const reminderIntervalMs = options.reminderIntervalMs ?? DEFAULT_TUNNEL_REMINDER_INTERVAL_MS;
|
|
10292
|
+
const defaultExpiryMs = options.expiryMs ?? DEFAULT_TUNNEL_EXPIRY_MS;
|
|
10293
|
+
const timeFormatter = new Intl.DateTimeFormat(void 0, { timeStyle: "short" });
|
|
10294
|
+
const readyPromise = spawnCloudflared([
|
|
10295
|
+
"tunnel",
|
|
10296
|
+
"--no-autoupdate",
|
|
10297
|
+
"--url",
|
|
10298
|
+
options.origin.href
|
|
10299
|
+
], {
|
|
10300
|
+
stdio: "pipe",
|
|
10301
|
+
skipVersionCheck: true,
|
|
10302
|
+
logger
|
|
10303
|
+
}).then((process2) => {
|
|
10304
|
+
cloudflaredProcess = process2;
|
|
10305
|
+
if (disposed) terminateCloudflared(process2);
|
|
10306
|
+
return process2;
|
|
10307
|
+
}).then((process2) => waitForQuickTunnelReady(process2, timeoutMs, {
|
|
10308
|
+
logger,
|
|
10309
|
+
origin: options.origin
|
|
10310
|
+
})).then((result) => {
|
|
10311
|
+
expiresAt = Date.now() + defaultExpiryMs;
|
|
10312
|
+
scheduleExpiryTimeout();
|
|
10313
|
+
scheduleReminder(result.publicUrl.origin);
|
|
10314
|
+
return result;
|
|
10315
|
+
});
|
|
10316
|
+
function disposeTunnel() {
|
|
10317
|
+
disposed = true;
|
|
10318
|
+
clearTunnelTimers();
|
|
10319
|
+
if (cloudflaredProcess) terminateCloudflared(cloudflaredProcess);
|
|
10320
|
+
}
|
|
10321
|
+
__name(disposeTunnel, "disposeTunnel");
|
|
10322
|
+
function clearTunnelTimers() {
|
|
10323
|
+
if (expiryTimeout) {
|
|
10324
|
+
clearTimeout(expiryTimeout);
|
|
10325
|
+
expiryTimeout = void 0;
|
|
10326
|
+
}
|
|
10327
|
+
if (reminderInterval) {
|
|
10328
|
+
clearInterval(reminderInterval);
|
|
10329
|
+
reminderInterval = void 0;
|
|
10330
|
+
}
|
|
10331
|
+
}
|
|
10332
|
+
__name(clearTunnelTimers, "clearTunnelTimers");
|
|
10333
|
+
function scheduleReminder(publicURL) {
|
|
10334
|
+
if (reminderIntervalMs > 0) {
|
|
10335
|
+
reminderInterval = setInterval(() => {
|
|
10336
|
+
if (disposed) return;
|
|
10337
|
+
const remainingMs = expiresAt - Date.now();
|
|
10338
|
+
if (remainingMs <= 0) return;
|
|
10339
|
+
logger?.log(`The tunnel is still open at ${publicURL}. It expires in ${formatTunnelDuration(remainingMs)}. ${options.extendHint ?? ""}`);
|
|
10340
|
+
}, reminderIntervalMs);
|
|
10341
|
+
reminderInterval.unref?.();
|
|
10342
|
+
}
|
|
10343
|
+
}
|
|
10344
|
+
__name(scheduleReminder, "scheduleReminder");
|
|
10345
|
+
function scheduleExpiryTimeout() {
|
|
10346
|
+
if (disposed) return;
|
|
10347
|
+
if (expiryTimeout) clearTimeout(expiryTimeout);
|
|
10348
|
+
expiryTimeout = setTimeout(() => {
|
|
10349
|
+
if (disposed) return;
|
|
10350
|
+
logger?.log("Tunnel expired. Closing tunnel.");
|
|
10351
|
+
disposeTunnel();
|
|
10352
|
+
}, Math.max(0, expiresAt - Date.now()));
|
|
10353
|
+
expiryTimeout.unref();
|
|
10354
|
+
}
|
|
10355
|
+
__name(scheduleExpiryTimeout, "scheduleExpiryTimeout");
|
|
10356
|
+
function extendExpiry(ms = DEFAULT_TUNNEL_EXTENSION_MS) {
|
|
10357
|
+
if (disposed || !expiryTimeout || ms <= 0) return;
|
|
10358
|
+
const now = Date.now();
|
|
10359
|
+
const previousExpiresAt = expiresAt;
|
|
10360
|
+
expiresAt = Math.min(now + DEFAULT_TUNNEL_MAX_REMAINING_MS, Math.max(expiresAt, now) + ms);
|
|
10361
|
+
const extendedByMs = expiresAt - previousExpiresAt;
|
|
10362
|
+
if (extendedByMs < ms) {
|
|
10363
|
+
logger?.log(`Tunnel expiry extended to the ${formatTunnelDuration(DEFAULT_TUNNEL_MAX_REMAINING_MS)} limit. It now expires at ${timeFormatter.format(new Date(expiresAt))}.`);
|
|
10364
|
+
scheduleExpiryTimeout();
|
|
10365
|
+
return;
|
|
10366
|
+
}
|
|
10367
|
+
logger?.log(`Tunnel expiry extended by ${formatTunnelDuration(extendedByMs)}. It now expires at ${timeFormatter.format(new Date(expiresAt))}.`);
|
|
10368
|
+
scheduleExpiryTimeout();
|
|
10369
|
+
}
|
|
10370
|
+
__name(extendExpiry, "extendExpiry");
|
|
10371
|
+
return {
|
|
10372
|
+
ready: /* @__PURE__ */ __name(() => readyPromise, "ready"),
|
|
10373
|
+
dispose: disposeTunnel,
|
|
10374
|
+
extendExpiry
|
|
10375
|
+
};
|
|
10376
|
+
}
|
|
10377
|
+
__name(startTunnel, "startTunnel");
|
|
10378
|
+
function formatTunnelDuration(durationMs) {
|
|
10379
|
+
const totalMinutes = Math.max(1, Math.ceil(durationMs / 6e4));
|
|
10380
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
10381
|
+
const minutes = totalMinutes % 60;
|
|
10382
|
+
if (hours === 0) return `${minutes}m`;
|
|
10383
|
+
if (minutes === 0) return `${hours}h`;
|
|
10384
|
+
return `${hours}h ${minutes}m`;
|
|
10385
|
+
}
|
|
10386
|
+
__name(formatTunnelDuration, "formatTunnelDuration");
|
|
10387
|
+
function terminateCloudflared(cloudflared) {
|
|
10388
|
+
if (cloudflared.killed) return;
|
|
10389
|
+
cloudflared.unref();
|
|
10390
|
+
cloudflared.kill("SIGTERM");
|
|
10391
|
+
setTimeout(() => {
|
|
10392
|
+
if (!cloudflared.killed) cloudflared.kill("SIGKILL");
|
|
10393
|
+
}, TUNNEL_FORCE_KILL_TIMEOUT_MS).unref();
|
|
10394
|
+
}
|
|
10395
|
+
__name(terminateCloudflared, "terminateCloudflared");
|
|
10396
|
+
function waitForQuickTunnelReady(cloudflared, timeoutMs, options) {
|
|
10397
|
+
return new Promise((resolve$2, reject) => {
|
|
10398
|
+
let resolved = false;
|
|
10399
|
+
let stderrOutput = "";
|
|
10400
|
+
const logger = options?.logger;
|
|
10401
|
+
const origin = options?.origin;
|
|
10402
|
+
const timeoutId = setTimeout(() => {
|
|
10403
|
+
if (!resolved) {
|
|
10404
|
+
resolved = true;
|
|
10405
|
+
terminateCloudflared(cloudflared);
|
|
10406
|
+
reject(createTunnelStartupError(`Timed out waiting for cloudflared to start (${timeoutMs / 1e3}s).`, stderrOutput, origin));
|
|
10407
|
+
}
|
|
10408
|
+
}, timeoutMs);
|
|
10409
|
+
timeoutId.unref();
|
|
10410
|
+
if (cloudflared.stderr) cloudflared.stderr.on("data", (data) => {
|
|
10411
|
+
const chunk = data.toString();
|
|
10412
|
+
stderrOutput += chunk;
|
|
10413
|
+
logger?.debug("[cloudflared]", chunk.trimEnd());
|
|
10414
|
+
const match = QUICK_TUNNEL_URL_REGEX.exec(stderrOutput);
|
|
10415
|
+
if (match && !resolved) {
|
|
10416
|
+
resolved = true;
|
|
10417
|
+
clearTimeout(timeoutId);
|
|
10418
|
+
resolve$2({ publicUrl: new URL(match[0]) });
|
|
10419
|
+
}
|
|
10420
|
+
});
|
|
10421
|
+
cloudflared.on("error", (error) => {
|
|
10422
|
+
if (!resolved) {
|
|
10423
|
+
resolved = true;
|
|
10424
|
+
clearTimeout(timeoutId);
|
|
10425
|
+
reject(/* @__PURE__ */ new Error(`Failed to start cloudflared: ${error.message}`));
|
|
10426
|
+
}
|
|
10427
|
+
});
|
|
10428
|
+
cloudflared.on("exit", (code, signal) => {
|
|
10429
|
+
if (!resolved) {
|
|
10430
|
+
resolved = true;
|
|
10431
|
+
clearTimeout(timeoutId);
|
|
10432
|
+
reject(createTunnelStartupError(`cloudflared ${signal ? `terminated by signal ${signal}` : `exited with code ${code}`} before the tunnel was ready.`, stderrOutput, origin));
|
|
10433
|
+
}
|
|
10434
|
+
});
|
|
10435
|
+
});
|
|
10436
|
+
}
|
|
10437
|
+
__name(waitForQuickTunnelReady, "waitForQuickTunnelReady");
|
|
10438
|
+
function createTunnelStartupError(message, stderrOutput, origin) {
|
|
10439
|
+
const isQuickTunnelRateLimited = stderrOutput.includes("429 Too Many Requests");
|
|
10440
|
+
const errorMessage = `${message}
|
|
10441
|
+
cloudflared output:
|
|
10442
|
+
${stderrOutput || "(no output)"}
|
|
10443
|
+
|
|
10444
|
+
The local dev server started at ${origin.href}.
|
|
10445
|
+
` + (isQuickTunnelRateLimited ? "Cloudflare Quick Tunnel creation was rate limited. Try again in a few minutes, or use a named tunnel if you need more reliable access." : `Check the cloudflared output above for more details, and verify that ${origin.href} is reachable from this machine if this keeps happening.`);
|
|
10446
|
+
if (isQuickTunnelRateLimited) return new UserError(errorMessage);
|
|
10447
|
+
return new Error(errorMessage);
|
|
10448
|
+
}
|
|
10449
|
+
__name(createTunnelStartupError, "createTunnelStartupError");
|
|
9778
10450
|
|
|
9779
10451
|
//#endregion
|
|
9780
10452
|
//#region ../../node_modules/.pnpm/devalue@5.6.3/node_modules/devalue/src/utils.js
|