@probelabs/probe
Version:
Node.js wrapper for the probe code search tool
1,302 lines (1,298 loc) • 6.18 MB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name14 in all)
__defProp(target, name14, { get: all[name14], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/dotenv/package.json
var require_package = __commonJS({
"node_modules/dotenv/package.json"(exports2, module2) {
module2.exports = {
name: "dotenv",
version: "16.6.1",
description: "Loads environment variables from .env file",
main: "lib/main.js",
types: "lib/main.d.ts",
exports: {
".": {
types: "./lib/main.d.ts",
require: "./lib/main.js",
default: "./lib/main.js"
},
"./config": "./config.js",
"./config.js": "./config.js",
"./lib/env-options": "./lib/env-options.js",
"./lib/env-options.js": "./lib/env-options.js",
"./lib/cli-options": "./lib/cli-options.js",
"./lib/cli-options.js": "./lib/cli-options.js",
"./package.json": "./package.json"
},
scripts: {
"dts-check": "tsc --project tests/types/tsconfig.json",
lint: "standard",
pretest: "npm run lint && npm run dts-check",
test: "tap run --allow-empty-coverage --disable-coverage --timeout=60000",
"test:coverage": "tap run --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",
prerelease: "npm test",
release: "standard-version"
},
repository: {
type: "git",
url: "git://github.com/motdotla/dotenv.git"
},
homepage: "https://github.com/motdotla/dotenv#readme",
funding: "https://dotenvx.com",
keywords: [
"dotenv",
"env",
".env",
"environment",
"variables",
"config",
"settings"
],
readmeFilename: "README.md",
license: "BSD-2-Clause",
devDependencies: {
"@types/node": "^18.11.3",
decache: "^4.6.2",
sinon: "^14.0.1",
standard: "^17.0.0",
"standard-version": "^9.5.0",
tap: "^19.2.0",
typescript: "^4.8.4"
},
engines: {
node: ">=12"
},
browser: {
fs: false
}
};
}
});
// node_modules/dotenv/lib/main.js
var require_main = __commonJS({
"node_modules/dotenv/lib/main.js"(exports2, module2) {
var fs7 = require("fs");
var path7 = require("path");
var os3 = require("os");
var crypto2 = require("crypto");
var packageJson = require_package();
var version = packageJson.version;
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
function parse6(src) {
const obj = {};
let lines = src.toString();
lines = lines.replace(/\r\n?/mg, "\n");
let match2;
while ((match2 = LINE.exec(lines)) != null) {
const key = match2[1];
let value = match2[2] || "";
value = value.trim();
const maybeQuote = value[0];
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, "$2");
if (maybeQuote === '"') {
value = value.replace(/\\n/g, "\n");
value = value.replace(/\\r/g, "\r");
}
obj[key] = value;
}
return obj;
}
function _parseVault(options) {
options = options || {};
const vaultPath = _vaultPath(options);
options.path = vaultPath;
const result = DotenvModule.configDotenv(options);
if (!result.parsed) {
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`);
err.code = "MISSING_DATA";
throw err;
}
const keys2 = _dotenvKey(options).split(",");
const length = keys2.length;
let decrypted;
for (let i3 = 0; i3 < length; i3++) {
try {
const key = keys2[i3].trim();
const attrs = _instructions(result, key);
decrypted = DotenvModule.decrypt(attrs.ciphertext, attrs.key);
break;
} catch (error2) {
if (i3 + 1 >= length) {
throw error2;
}
}
}
return DotenvModule.parse(decrypted);
}
function _warn(message) {
console.log(`[dotenv@${version}][WARN] ${message}`);
}
function _debug(message) {
console.log(`[dotenv@${version}][DEBUG] ${message}`);
}
function _log(message) {
console.log(`[dotenv@${version}] ${message}`);
}
function _dotenvKey(options) {
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
return options.DOTENV_KEY;
}
if (process.env.DOTENV_KEY && process.env.DOTENV_KEY.length > 0) {
return process.env.DOTENV_KEY;
}
return "";
}
function _instructions(result, dotenvKey) {
let uri;
try {
uri = new URL(dotenvKey);
} catch (error2) {
if (error2.code === "ERR_INVALID_URL") {
const err = new Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");
err.code = "INVALID_DOTENV_KEY";
throw err;
}
throw error2;
}
const key = uri.password;
if (!key) {
const err = new Error("INVALID_DOTENV_KEY: Missing key part");
err.code = "INVALID_DOTENV_KEY";
throw err;
}
const environment = uri.searchParams.get("environment");
if (!environment) {
const err = new Error("INVALID_DOTENV_KEY: Missing environment part");
err.code = "INVALID_DOTENV_KEY";
throw err;
}
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`;
const ciphertext = result.parsed[environmentKey];
if (!ciphertext) {
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`);
err.code = "NOT_FOUND_DOTENV_ENVIRONMENT";
throw err;
}
return { ciphertext, key };
}
function _vaultPath(options) {
let possibleVaultPath = null;
if (options && options.path && options.path.length > 0) {
if (Array.isArray(options.path)) {
for (const filepath of options.path) {
if (fs7.existsSync(filepath)) {
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
}
}
} else {
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
}
} else {
possibleVaultPath = path7.resolve(process.cwd(), ".env.vault");
}
if (fs7.existsSync(possibleVaultPath)) {
return possibleVaultPath;
}
return null;
}
function _resolveHome(envPath) {
return envPath[0] === "~" ? path7.join(os3.homedir(), envPath.slice(1)) : envPath;
}
function _configVault(options) {
const debug = Boolean(options && options.debug);
const quiet = options && "quiet" in options ? options.quiet : true;
if (debug || !quiet) {
_log("Loading env from encrypted .env.vault");
}
const parsed = DotenvModule._parseVault(options);
let processEnv = process.env;
if (options && options.processEnv != null) {
processEnv = options.processEnv;
}
DotenvModule.populate(processEnv, parsed, options);
return { parsed };
}
function configDotenv(options) {
const dotenvPath = path7.resolve(process.cwd(), ".env");
let encoding = "utf8";
const debug = Boolean(options && options.debug);
const quiet = options && "quiet" in options ? options.quiet : true;
if (options && options.encoding) {
encoding = options.encoding;
} else {
if (debug) {
_debug("No encoding is specified. UTF-8 is used by default");
}
}
let optionPaths = [dotenvPath];
if (options && options.path) {
if (!Array.isArray(options.path)) {
optionPaths = [_resolveHome(options.path)];
} else {
optionPaths = [];
for (const filepath of options.path) {
optionPaths.push(_resolveHome(filepath));
}
}
}
let lastError;
const parsedAll = {};
for (const path8 of optionPaths) {
try {
const parsed = DotenvModule.parse(fs7.readFileSync(path8, { encoding }));
DotenvModule.populate(parsedAll, parsed, options);
} catch (e3) {
if (debug) {
_debug(`Failed to load ${path8} ${e3.message}`);
}
lastError = e3;
}
}
let processEnv = process.env;
if (options && options.processEnv != null) {
processEnv = options.processEnv;
}
DotenvModule.populate(processEnv, parsedAll, options);
if (debug || !quiet) {
const keysCount = Object.keys(parsedAll).length;
const shortPaths = [];
for (const filePath of optionPaths) {
try {
const relative = path7.relative(process.cwd(), filePath);
shortPaths.push(relative);
} catch (e3) {
if (debug) {
_debug(`Failed to load ${filePath} ${e3.message}`);
}
lastError = e3;
}
}
_log(`injecting env (${keysCount}) from ${shortPaths.join(",")}`);
}
if (lastError) {
return { parsed: parsedAll, error: lastError };
} else {
return { parsed: parsedAll };
}
}
function config(options) {
if (_dotenvKey(options).length === 0) {
return DotenvModule.configDotenv(options);
}
const vaultPath = _vaultPath(options);
if (!vaultPath) {
_warn(`You set DOTENV_KEY but you are missing a .env.vault file at ${vaultPath}. Did you forget to build it?`);
return DotenvModule.configDotenv(options);
}
return DotenvModule._configVault(options);
}
function decrypt(encrypted, keyStr) {
const key = Buffer.from(keyStr.slice(-64), "hex");
let ciphertext = Buffer.from(encrypted, "base64");
const nonce = ciphertext.subarray(0, 12);
const authTag = ciphertext.subarray(-16);
ciphertext = ciphertext.subarray(12, -16);
try {
const aesgcm = crypto2.createDecipheriv("aes-256-gcm", key, nonce);
aesgcm.setAuthTag(authTag);
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
} catch (error2) {
const isRange = error2 instanceof RangeError;
const invalidKeyLength = error2.message === "Invalid key length";
const decryptionFailed = error2.message === "Unsupported state or unable to authenticate data";
if (isRange || invalidKeyLength) {
const err = new Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");
err.code = "INVALID_DOTENV_KEY";
throw err;
} else if (decryptionFailed) {
const err = new Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");
err.code = "DECRYPTION_FAILED";
throw err;
} else {
throw error2;
}
}
}
function populate(processEnv, parsed, options = {}) {
const debug = Boolean(options && options.debug);
const override = Boolean(options && options.override);
if (typeof parsed !== "object") {
const err = new Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");
err.code = "OBJECT_REQUIRED";
throw err;
}
for (const key of Object.keys(parsed)) {
if (Object.prototype.hasOwnProperty.call(processEnv, key)) {
if (override === true) {
processEnv[key] = parsed[key];
}
if (debug) {
if (override === true) {
_debug(`"${key}" is already defined and WAS overwritten`);
} else {
_debug(`"${key}" is already defined and was NOT overwritten`);
}
}
} else {
processEnv[key] = parsed[key];
}
}
}
var DotenvModule = {
configDotenv,
_configVault,
_parseVault,
config,
decrypt,
parse: parse6,
populate
};
module2.exports.configDotenv = DotenvModule.configDotenv;
module2.exports._configVault = DotenvModule._configVault;
module2.exports._parseVault = DotenvModule._parseVault;
module2.exports.config = DotenvModule.config;
module2.exports.decrypt = DotenvModule.decrypt;
module2.exports.parse = DotenvModule.parse;
module2.exports.populate = DotenvModule.populate;
module2.exports = DotenvModule;
}
});
// src/directory-resolver.js
async function getPackageBinDir() {
const debug = process.env.DEBUG === "1" || process.env.VERBOSE === "1";
if (debug) {
console.log("DEBUG: Starting probe binary directory resolution");
}
if (process.env.PROBE_BINARY_PATH) {
if (debug) {
console.log(`DEBUG: Checking PROBE_BINARY_PATH: ${process.env.PROBE_BINARY_PATH}`);
}
const binaryPath = process.env.PROBE_BINARY_PATH;
if (await import_fs_extra.default.pathExists(binaryPath)) {
const binDir = import_path.default.dirname(binaryPath);
if (await canWriteToDirectory(binDir)) {
if (debug) {
console.log(`DEBUG: Using PROBE_BINARY_PATH directory: ${binDir}`);
}
return binDir;
}
} else {
console.warn(`Warning: PROBE_BINARY_PATH ${binaryPath} does not exist`);
}
}
if (process.env.PROBE_CACHE_DIR) {
if (debug) {
console.log(`DEBUG: Checking PROBE_CACHE_DIR: ${process.env.PROBE_CACHE_DIR}`);
}
const cacheDir = import_path.default.join(process.env.PROBE_CACHE_DIR, "bin");
if (await ensureDirectory(cacheDir)) {
if (debug) {
console.log(`DEBUG: Using PROBE_CACHE_DIR: ${cacheDir}`);
}
return cacheDir;
}
}
const packageRoot = await findPackageRoot();
if (packageRoot) {
if (debug) {
console.log(`DEBUG: Found package root: ${packageRoot}`);
}
const packageBinDir = import_path.default.join(packageRoot, "bin");
if (await ensureDirectory(packageBinDir) && await canWriteToDirectory(packageBinDir)) {
if (debug) {
console.log(`DEBUG: Using package bin directory: ${packageBinDir}`);
}
return packageBinDir;
} else if (debug) {
console.log(`DEBUG: Package bin directory ${packageBinDir} not writable, trying fallbacks`);
}
}
const homeCache = import_path.default.join(import_os.default.homedir(), ".probe", "bin");
if (debug) {
console.log(`DEBUG: Trying home cache directory: ${homeCache}`);
}
if (await ensureDirectory(homeCache)) {
if (debug) {
console.log(`DEBUG: Using home cache directory: ${homeCache}`);
}
return homeCache;
}
const tempCache = import_path.default.join(import_os.default.tmpdir(), "probe-cache", "bin");
if (debug) {
console.log(`DEBUG: Trying temp cache directory: ${tempCache}`);
}
if (await ensureDirectory(tempCache)) {
if (debug) {
console.log(`DEBUG: Using temp cache directory: ${tempCache}`);
}
return tempCache;
}
const errorMessage = [
"Could not find a writable directory for probe binary.",
"Tried the following locations:",
packageRoot ? `- Package bin directory: ${import_path.default.join(packageRoot, "bin")}` : "- Package root not found",
`- Home cache directory: ${homeCache}`,
`- Temp cache directory: ${tempCache}`,
"",
"You can override the location using environment variables:",
"- PROBE_BINARY_PATH=/path/to/probe (direct path to binary)",
"- PROBE_CACHE_DIR=/path/to/cache (cache directory, binary will be in /bin subdirectory)"
].join("\n");
throw new Error(errorMessage);
}
async function findPackageRoot() {
const debug = process.env.DEBUG === "1" || process.env.VERBOSE === "1";
let currentDir = __dirname;
const rootDir = import_path.default.parse(currentDir).root;
if (debug) {
console.log(`DEBUG: Starting package root search from: ${currentDir}`);
}
while (currentDir !== rootDir) {
const packageJsonPath = import_path.default.join(currentDir, "package.json");
try {
if (await import_fs_extra.default.pathExists(packageJsonPath)) {
const packageJson = await import_fs_extra.default.readJson(packageJsonPath);
if (debug) {
console.log(`DEBUG: Found package.json at ${packageJsonPath}, name: ${packageJson.name}`);
}
if (packageJson.name === "@probelabs/probe") {
if (debug) {
console.log(`DEBUG: Found probe package root: ${currentDir}`);
}
return currentDir;
}
}
} catch (err) {
if (debug) {
console.log(`DEBUG: Error reading package.json at ${packageJsonPath}: ${err.message}`);
}
}
currentDir = import_path.default.dirname(currentDir);
}
if (debug) {
console.log("DEBUG: Package root not found, reached filesystem root");
}
return null;
}
async function ensureDirectory(dirPath) {
const debug = process.env.DEBUG === "1" || process.env.VERBOSE === "1";
try {
await import_fs_extra.default.ensureDir(dirPath);
const testFile = import_path.default.join(dirPath, ".probe-write-test");
await import_fs_extra.default.writeFile(testFile, "test");
await import_fs_extra.default.remove(testFile);
if (debug) {
console.log(`DEBUG: Directory ${dirPath} is writable`);
}
return true;
} catch (error2) {
if (debug) {
console.log(`DEBUG: Directory ${dirPath} not writable: ${error2.message}`);
}
return false;
}
}
async function canWriteToDirectory(dirPath) {
const debug = process.env.DEBUG === "1" || process.env.VERBOSE === "1";
try {
const exists = await import_fs_extra.default.pathExists(dirPath);
if (!exists) {
if (debug) {
console.log(`DEBUG: Directory ${dirPath} does not exist`);
}
return false;
}
const testFile = import_path.default.join(dirPath, ".probe-write-test");
await import_fs_extra.default.writeFile(testFile, "test");
await import_fs_extra.default.remove(testFile);
if (debug) {
console.log(`DEBUG: Directory ${dirPath} is writable`);
}
return true;
} catch (error2) {
if (debug) {
console.log(`DEBUG: Directory ${dirPath} not writable: ${error2.message}`);
}
return false;
}
}
var import_path, import_os, import_fs_extra, import_url, __filename, __dirname;
var init_directory_resolver = __esm({
"src/directory-resolver.js"() {
"use strict";
import_path = __toESM(require("path"), 1);
import_os = __toESM(require("os"), 1);
import_fs_extra = __toESM(require("fs-extra"), 1);
import_url = require("url");
__filename = (0, import_url.fileURLToPath)("file:///");
__dirname = import_path.default.dirname(__filename);
}
});
// src/downloader.js
function sanitizeError(err) {
try {
const status = err?.response?.status;
const statusText = err?.response?.statusText;
const url = err?.config?.url || err?.response?.config?.url;
const code = err?.code;
const serverMsg = typeof err?.response?.data === "string" ? err.response.data.slice(0, 500) : typeof err?.response?.data?.message === "string" ? err.response.data.message : void 0;
const base = err?.message || String(err);
const parts = [base];
if (status || statusText) parts.push(`[${status ?? ""} ${statusText ?? ""}]`.trim());
if (code) parts.push(`code=${code}`);
if (url) parts.push(`url=${url}`);
if (serverMsg) parts.push(`server="${String(serverMsg).replace(/\s+/g, " ").trim()}"`);
const e3 = new Error(parts.filter(Boolean).join(" "));
if (status) e3.status = status;
if (code) e3.code = code;
if (url) e3.url = url;
return e3;
} catch (_2) {
return new Error(err?.message || String(err));
}
}
async function acquireFileLock(lockPath, version) {
const lockData = {
version,
pid: process.pid,
timestamp: Date.now()
};
try {
await import_fs_extra2.default.writeFile(lockPath, JSON.stringify(lockData), { flag: "wx" });
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Acquired file lock: ${lockPath}`);
}
return true;
} catch (error2) {
if (error2.code === "EEXIST") {
try {
const existingLock = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
const lockAge = Date.now() - existingLock.timestamp;
if (lockAge > LOCK_TIMEOUT_MS) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Removing stale lock file (age: ${Math.round(lockAge / 1e3)}s, pid: ${existingLock.pid})`);
}
await import_fs_extra2.default.remove(lockPath);
return false;
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Download in progress by process ${existingLock.pid}, waiting...`);
}
return false;
} catch (readError) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Lock file corrupted, removing: ${readError.message}`);
}
try {
await import_fs_extra2.default.remove(lockPath);
} catch {
}
return false;
}
}
if (error2.code === "EACCES" || error2.code === "EPERM" || error2.code === "EROFS") {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Cannot create lock file (${error2.code}): ${lockPath}`);
console.log(`File-based locking unavailable, will proceed without cross-process coordination`);
}
return null;
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Unexpected error creating lock file: ${error2.message}`);
console.log(`Proceeding without file-based lock`);
}
return null;
}
}
async function releaseFileLock(lockPath) {
try {
await import_fs_extra2.default.remove(lockPath);
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Released file lock: ${lockPath}`);
}
} catch (error2) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Warning: Could not release lock file: ${error2.message}`);
}
}
}
async function waitForFileLock(lockPath, binaryPath) {
const startTime = Date.now();
while (Date.now() - startTime < MAX_LOCK_WAIT_MS) {
if (await import_fs_extra2.default.pathExists(binaryPath)) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Binary now available at ${binaryPath}, download completed by another process`);
}
return true;
}
const lockExists = await import_fs_extra2.default.pathExists(lockPath);
if (!lockExists) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Lock file removed but binary not found - download may have failed`);
}
return false;
}
try {
const lockData = JSON.parse(await import_fs_extra2.default.readFile(lockPath, "utf-8"));
const lockAge = Date.now() - lockData.timestamp;
if (lockAge > LOCK_TIMEOUT_MS) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Lock expired (age: ${Math.round(lockAge / 1e3)}s), will retry download`);
}
return false;
}
} catch {
}
await new Promise((resolve5) => setTimeout(resolve5, LOCK_POLL_INTERVAL_MS));
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Timeout waiting for file lock`);
}
return false;
}
async function withDownloadLock(version, downloadFn) {
const lockKey = version || "latest";
if (downloadLocks.has(lockKey)) {
const lock = downloadLocks.get(lockKey);
const lockAge = Date.now() - lock.timestamp;
if (lockAge > LOCK_TIMEOUT_MS) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`In-memory lock for version ${lockKey} expired (age: ${Math.round(lockAge / 1e3)}s), removing stale lock`);
}
downloadLocks.delete(lockKey);
} else {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Download already in progress in this process for version ${lockKey}, waiting...`);
}
try {
return await lock.promise;
} catch (error2) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`In-memory locked download failed, will retry: ${error2.message}`);
}
}
}
}
const downloadPromise = Promise.race([
downloadFn(),
new Promise(
(_2, reject2) => setTimeout(() => reject2(new Error(`Download timeout after ${LOCK_TIMEOUT_MS / 1e3}s`)), LOCK_TIMEOUT_MS)
)
]);
downloadLocks.set(lockKey, {
promise: downloadPromise,
timestamp: Date.now()
});
try {
const result = await downloadPromise;
return result;
} finally {
downloadLocks.delete(lockKey);
}
}
function detectOsArch() {
const osType = import_os2.default.platform();
const archType = import_os2.default.arch();
let osInfo;
let archInfo;
switch (osType) {
case "linux":
osInfo = {
type: "linux",
keywords: ["linux", "Linux", "musl", "gnu"]
};
break;
case "darwin":
osInfo = {
type: "darwin",
keywords: ["darwin", "Darwin", "mac", "Mac", "apple", "Apple", "osx", "OSX"]
};
break;
case "win32":
osInfo = {
type: "windows",
keywords: ["windows", "Windows", "msvc", "pc-windows"]
};
break;
default:
throw new Error(`Unsupported operating system: ${osType}`);
}
switch (archType) {
case "x64":
archInfo = {
type: "x86_64",
keywords: ["x86_64", "amd64", "x64", "64bit", "64-bit"]
};
break;
case "arm64":
archInfo = {
type: "aarch64",
keywords: ["arm64", "aarch64", "arm", "ARM"]
};
break;
default:
throw new Error(`Unsupported architecture: ${archType}`);
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Detected OS: ${osInfo.type}, Architecture: ${archInfo.type}`);
}
return { os: osInfo, arch: archInfo };
}
function constructAssetInfo(version, osInfo, archInfo) {
let platform;
let extension;
switch (osInfo.type) {
case "linux":
platform = `${archInfo.type}-unknown-linux-musl`;
extension = "tar.gz";
break;
case "darwin":
platform = `${archInfo.type}-apple-darwin`;
extension = "tar.gz";
break;
case "windows":
platform = `${archInfo.type}-pc-windows-msvc`;
extension = "zip";
break;
default:
throw new Error(`Unsupported OS type: ${osInfo.type}`);
}
const assetName = `probe-v${version}-${platform}.${extension}`;
const checksumName = `${assetName}.sha256`;
const baseUrl = `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${version}`;
const assetUrl = `${baseUrl}/${assetName}`;
const checksumUrl = `${baseUrl}/${checksumName}`;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Constructed asset URL: ${assetUrl}`);
}
return {
name: assetName,
url: assetUrl,
checksumName,
checksumUrl
};
}
async function getLatestRelease(version) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log("Fetching release information...");
}
try {
let releaseUrl;
if (version) {
releaseUrl = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases/tags/v${version}`;
} else {
releaseUrl = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases`;
}
const response = await import_axios.default.get(releaseUrl);
if (response.status !== 200) {
throw new Error(`Failed to fetch release information: ${response.statusText}`);
}
let releaseData;
if (version) {
releaseData = response.data;
} else {
if (!Array.isArray(response.data) || response.data.length === 0) {
throw new Error("No releases found");
}
releaseData = response.data[0];
}
const tag2 = releaseData.tag_name;
const assets = releaseData.assets.map((asset) => ({
name: asset.name,
url: asset.browser_download_url
}));
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found release: ${tag2} with ${assets.length} assets`);
}
return { tag: tag2, assets };
} catch (error2) {
if (import_axios.default.isAxiosError(error2) && error2.response?.status === 404) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Release v${version} not found, trying to fetch all releases...`);
}
const response = await import_axios.default.get(`https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/releases`);
if (response.data.length === 0) {
throw new Error("No releases found");
}
let bestRelease = response.data[0];
if (version && version !== "0.0.0") {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Looking for releases matching version: ${version}`);
console.log(`Available releases: ${response.data.slice(0, 5).map((r3) => r3.tag_name).join(", ")}...`);
}
for (const release of response.data) {
const releaseTag = release.tag_name.startsWith("v") ? release.tag_name.substring(1) : release.tag_name;
if (releaseTag === version) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found exact matching release: ${release.tag_name}`);
}
bestRelease = release;
break;
}
}
if (bestRelease === response.data[0]) {
const versionParts = version.split(/[\.-]/);
const majorMinor = versionParts.slice(0, 2).join(".");
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Looking for releases matching major.minor: ${majorMinor}`);
}
for (const release of response.data) {
const releaseTag = release.tag_name.startsWith("v") ? release.tag_name.substring(1) : release.tag_name;
const releaseVersionParts = releaseTag.split(/[\.-]/);
const releaseMajorMinor = releaseVersionParts.slice(0, 2).join(".");
if (releaseMajorMinor === majorMinor) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found matching major.minor release: ${release.tag_name}`);
}
bestRelease = release;
break;
}
}
}
}
const tag2 = bestRelease.tag_name;
const assets = bestRelease.assets.map((asset) => ({
name: asset.name,
url: asset.browser_download_url
}));
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Using release: ${tag2} with ${assets.length} assets`);
}
return { tag: tag2, assets };
}
throw sanitizeError(error2);
}
}
function findBestAsset(assets, osInfo, archInfo) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Finding appropriate binary for ${osInfo.type} ${archInfo.type}...`);
}
let bestAsset = null;
let bestScore = 0;
for (const asset of assets) {
if (asset.name.endsWith(".sha256") || asset.name.endsWith(".md5") || asset.name.endsWith(".asc")) {
continue;
}
if (osInfo.type === "windows" && asset.name.match(/darwin|linux/)) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Skipping non-Windows binary: ${asset.name}`);
}
continue;
} else if (osInfo.type === "darwin" && asset.name.match(/windows|msvc|linux/)) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Skipping non-macOS binary: ${asset.name}`);
}
continue;
} else if (osInfo.type === "linux" && asset.name.match(/darwin|windows|msvc/)) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Skipping non-Linux binary: ${asset.name}`);
}
continue;
}
let score = 0;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Evaluating asset: ${asset.name}`);
}
let osMatched = false;
for (const keyword of osInfo.keywords) {
if (asset.name.includes(keyword)) {
score += 10;
osMatched = true;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(` OS match found (${keyword}): +10, score = ${score}`);
}
break;
}
}
for (const keyword of archInfo.keywords) {
if (asset.name.includes(keyword)) {
score += 5;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(` Arch match found (${keyword}): +5, score = ${score}`);
}
break;
}
}
if (asset.name.startsWith(`${BINARY_NAME}-`)) {
score += 3;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(` Binary name match: +3, score = ${score}`);
}
}
if (osMatched && score >= 15) {
score += 5;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(` OS+Arch bonus: +5, score = ${score}`);
}
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(` Final score for ${asset.name}: ${score}`);
}
if (score === 23) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found perfect match: ${asset.name}`);
}
return asset;
}
if (score > bestScore) {
bestScore = score;
bestAsset = asset;
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(` New best asset: ${asset.name} (score: ${score})`);
}
}
}
if (!bestAsset) {
throw new Error(`Could not find a suitable binary for ${osInfo.type} ${archInfo.type}`);
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Selected asset: ${bestAsset.name} (score: ${bestScore})`);
}
return bestAsset;
}
async function downloadAsset(asset, outputDir) {
await import_fs_extra2.default.ensureDir(outputDir);
const assetPath = import_path2.default.join(outputDir, asset.name);
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Downloading ${asset.name}...`);
}
const assetResponse = await import_axios.default.get(asset.url, { responseType: "arraybuffer" });
await import_fs_extra2.default.writeFile(assetPath, Buffer.from(assetResponse.data));
const checksumUrl = asset.checksumUrl || `${asset.url}.sha256`;
const checksumFileName = asset.checksumName || `${asset.name}.sha256`;
let checksumPath = null;
try {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Downloading checksum...`);
}
const checksumResponse = await import_axios.default.get(checksumUrl);
checksumPath = import_path2.default.join(outputDir, checksumFileName);
await import_fs_extra2.default.writeFile(checksumPath, checksumResponse.data);
} catch (error2) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log("No checksum file found, skipping verification");
}
}
return { assetPath, checksumPath };
}
async function verifyChecksum(assetPath, checksumPath) {
if (!checksumPath) {
return true;
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Verifying checksum...`);
}
const checksumContent = await import_fs_extra2.default.readFile(checksumPath, "utf-8");
const expectedChecksum = checksumContent.trim().split(" ")[0];
const fileBuffer = await import_fs_extra2.default.readFile(assetPath);
const actualChecksum = (0, import_crypto.createHash)("sha256").update(fileBuffer).digest("hex");
if (expectedChecksum !== actualChecksum) {
console.error(`Checksum verification failed!`);
console.error(`Expected: ${expectedChecksum}`);
console.error(`Actual: ${actualChecksum}`);
return false;
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Checksum verified successfully`);
}
return true;
}
async function extractBinary(assetPath, outputDir) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Extracting ${import_path2.default.basename(assetPath)}...`);
}
const assetName = import_path2.default.basename(assetPath);
const isWindows = import_os2.default.platform() === "win32";
const binaryName = isWindows ? `${BINARY_NAME}.exe` : `${BINARY_NAME}-binary`;
const binaryPath = import_path2.default.join(outputDir, binaryName);
try {
const extractDir = import_path2.default.join(outputDir, "temp_extract");
await import_fs_extra2.default.ensureDir(extractDir);
if (assetName.endsWith(".tar.gz") || assetName.endsWith(".tgz")) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Extracting tar.gz to ${extractDir}...`);
}
await import_tar.default.extract({
file: assetPath,
cwd: extractDir
});
} else if (assetName.endsWith(".zip")) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Extracting zip to ${extractDir}...`);
}
await exec(`unzip -q "${assetPath}" -d "${extractDir}"`);
} else {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Copying binary directly to ${binaryPath}`);
}
await import_fs_extra2.default.copyFile(assetPath, binaryPath);
if (!isWindows) {
await import_fs_extra2.default.chmod(binaryPath, 493);
}
await import_fs_extra2.default.remove(extractDir);
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Binary installed to ${binaryPath}`);
}
return binaryPath;
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Searching for binary in extracted files...`);
}
const findBinary = async (dir) => {
const entries = await import_fs_extra2.default.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = import_path2.default.join(dir, entry.name);
if (entry.isDirectory()) {
const result = await findBinary(fullPath);
if (result) return result;
} else if (entry.isFile()) {
if (entry.name === binaryName || entry.name === BINARY_NAME || isWindows && entry.name.endsWith(".exe")) {
return fullPath;
}
}
}
return null;
};
const binaryFilePath = await findBinary(extractDir);
if (!binaryFilePath) {
const allFiles = await import_fs_extra2.default.readdir(extractDir, { recursive: true });
console.error(`Binary not found in extracted files. Found: ${allFiles.join(", ")}`);
throw new Error(`Binary not found in the archive.`);
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found binary at ${binaryFilePath}`);
console.log(`Copying binary to ${binaryPath}`);
}
await import_fs_extra2.default.copyFile(binaryFilePath, binaryPath);
if (!isWindows) {
await import_fs_extra2.default.chmod(binaryPath, 493);
}
await import_fs_extra2.default.remove(extractDir);
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Binary successfully installed to ${binaryPath}`);
}
return binaryPath;
} catch (error2) {
console.error(`Error extracting binary: ${error2 instanceof Error ? error2.message : String(error2)}`);
throw sanitizeError(error2);
}
}
async function getVersionInfo(binDir) {
try {
const versionInfoPath = import_path2.default.join(binDir, "version-info.json");
if (await import_fs_extra2.default.pathExists(versionInfoPath)) {
const content = await import_fs_extra2.default.readFile(versionInfoPath, "utf-8");
return JSON.parse(content);
}
return null;
} catch (error2) {
console.warn(`Warning: Could not read version info: ${error2}`);
return null;
}
}
async function saveVersionInfo(version, binDir) {
const versionInfo = {
version,
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
};
const versionInfoPath = import_path2.default.join(binDir, "version-info.json");
await import_fs_extra2.default.writeFile(versionInfoPath, JSON.stringify(versionInfo, null, 2));
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Version info saved: ${version} at ${versionInfoPath}`);
}
}
async function getPackageVersion() {
try {
const possiblePaths = [
import_path2.default.resolve(__dirname2, "..", "package.json"),
// When installed from npm: src/../package.json
import_path2.default.resolve(__dirname2, "..", "..", "package.json")
// In development: src/../../package.json
];
for (const packageJsonPath of possiblePaths) {
try {
if (import_fs_extra2.default.existsSync(packageJsonPath)) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found package.json at: ${packageJsonPath}`);
}
const packageJson = JSON.parse(import_fs_extra2.default.readFileSync(packageJsonPath, "utf-8"));
if (packageJson.version) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Using version from package.json: ${packageJson.version}`);
}
return packageJson.version;
}
}
} catch (err) {
console.error(`Error reading package.json at ${packageJsonPath}:`, err);
}
}
return "0.0.0";
} catch (error2) {
console.error("Error getting package version:", error2);
return "0.0.0";
}
}
async function doDownload(version) {
const localDir = await getPackageBinDir();
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Downloading probe binary (version: ${version || "latest"})...`);
console.log(`Using binary directory: ${localDir}`);
}
const isWindows = import_os2.default.platform() === "win32";
const binaryName = isWindows ? `${BINARY_NAME}.exe` : `${BINARY_NAME}-binary`;
const binaryPath = import_path2.default.join(localDir, binaryName);
const { os: osInfo, arch: archInfo } = detectOsArch();
let versionToUse = version;
let bestAsset;
let tagVersion;
if (!versionToUse || versionToUse === "0.0.0") {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log("No specific version requested, will use the latest release");
}
const { tag: tag2, assets } = await getLatestRelease(void 0);
tagVersion = tag2.startsWith("v") ? tag2.substring(1) : tag2;
bestAsset = findBestAsset(assets, osInfo, archInfo);
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Found release version: ${tagVersion}`);
}
} else {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Direct download for version: ${versionToUse}`);
}
tagVersion = versionToUse;
bestAsset = constructAssetInfo(versionToUse, osInfo, archInfo);
}
const { assetPath, checksumPath } = await downloadAsset(bestAsset, localDir);
const checksumValid = await verifyChecksum(assetPath, checksumPath);
if (!checksumValid) {
throw new Error("Checksum verification failed");
}
const extractedBinaryPath = await extractBinary(assetPath, localDir);
await saveVersionInfo(tagVersion, localDir);
try {
await import_fs_extra2.default.remove(assetPath);
if (checksumPath) {
await import_fs_extra2.default.remove(checksumPath);
}
} catch (err) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Warning: Could not clean up temporary files: ${err}`);
}
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Binary successfully installed at ${extractedBinaryPath} (version: ${tagVersion})`);
}
return extractedBinaryPath;
}
async function downloadProbeBinary(version) {
try {
const localDir = await getPackageBinDir();
if (!version || version === "0.0.0") {
version = await getPackageVersion();
}
const isWindows = import_os2.default.platform() === "win32";
const binaryName = isWindows ? `${BINARY_NAME}.exe` : `${BINARY_NAME}-binary`;
const binaryPath = import_path2.default.join(localDir, binaryName);
if (await import_fs_extra2.default.pathExists(binaryPath)) {
const versionInfo = await getVersionInfo(localDir);
if (versionInfo && versionInfo.version === version) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Using existing binary at ${binaryPath} (version: ${versionInfo.version})`);
}
return binaryPath;
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Existing binary version (${versionInfo?.version || "unknown"}) doesn't match requested version (${version}). Downloading new version...`);
}
}
const lockPath = import_path2.default.join(localDir, `.probe-download-${version}.lock`);
const maxRetries = 3;
for (let retry = 0; retry < maxRetries; retry++) {
const lockAcquired = await acquireFileLock(lockPath, version);
if (lockAcquired === true) {
try {
const result = await withDownloadLock(version, () => doDownload(version));
return result;
} finally {
await releaseFileLock(lockPath);
}
}
if (lockAcquired === null) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`File-based locking unavailable, downloading without cross-process coordination`);
}
return await withDownloadLock(version, () => doDownload(version));
}
const downloadCompleted = await waitForFileLock(lockPath, binaryPath);
if (downloadCompleted) {
return binaryPath;
}
if (retry < maxRetries - 1) {
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`Retrying download (attempt ${retry + 2}/${maxRetries})...`);
}
}
}
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
console.log(`All lock attempts exhausted, attempting direct download`);
}
return await withDownloadLock(version, () => doDownload(version));
} catch (error2) {
console.error("Error downloading probe binary:", error2?.message || String(error2));
throw sanitizeError(error2);
}
}
var import_axios, import_fs_extra2, import_path2, import_crypto, import_util, import_child_process, import_tar, import_os2, import_url2, exec, REPO_OWNER, REPO_NAME, BINARY_NAME, __filename2, __dirname2, downloadLocks, LOCK_TIMEOUT_MS, LOCK_POLL_INTERVAL_MS, MAX_LOCK_WAIT_MS;
var init_downloader = __esm({
"src/downloader.js"() {
"use strict";
import_axios = __toESM(require("axios"), 1);
import_fs_extra2 = __toESM(require("fs-extra"), 1);
import_path2 = __toESM(require("path"), 1);
import_crypto = require("crypto");
import_util = require("util");
import_child_process = require("child_process");
import_tar = __toESM(require("tar"), 1);
import_os2 = __toESM(require("os"), 1);
import_url2 = require("url");
init_utils();
init_directory_resolver();
exec = (0, import_util.promisify)(import_child_process.exec);
REPO_OWNER = "probelabs";
REPO_NAME = "probe";
BINARY_NAME = "probe";
__filename2 = (0, import_url2.fileURLToPath)("file:///");
__dirname2 = import_path2.default.dirname(__filename2);
downloadLocks = /* @__PURE__