"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('../_virtual/_rolldown/runtime.js');
const require_node_crypto = require('../node/crypto.js');
const require_crypto_hash = require('../crypto/hash.js');
const require_primordials_buffer = require('../primordials/buffer.js');
const require_primordials_error = require('../primordials/error.js');
const require_integrity = require('../integrity.js');
const require_constants_platform = require('../constants/platform.js');
const require_paths_normalize = require('../paths/normalize.js');
const require_node_fs = require('../node/fs.js');
const require_node_path = require('../node/path.js');
const require_fs_safe = require('../fs/safe.js');
const require_constants_time = require('../constants/time.js');
const require_dlx_binary_cache = require('./binary-cache.js');
const require_http_request_download = require('../http-request/download.js');
const require_process_lock_instance = require('../process/lock-instance.js');
const require_dlx_cache = require('./cache.js');
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process);

//#region src/dlx/binary-download.ts
/**
* @file Download helpers for dlx binaries — fetch tarballs from URLs, verify
*   integrity, cache to disk with concurrency locking.
*
*   - `downloadBinary` — high-level URL→cached-binary flow
*   - `downloadBinaryFile` — low-level fetch+verify with processLock Split out of
*     `dlx/binary.ts` for size hygiene.
*/
/**
* Download a binary from a URL with caching (without execution). Similar to
* downloadPackage from dlx/package.
*
* Returns `{binaryPath, downloaded, integrity}`. The `integrity` field is the
* SRI-formatted `sha512-<base64>` hash of the cached file — computed by the
* downloader on first fetch, persisted to cache metadata, and re-read on
* subsequent cache hits. This supports the trust-on-first-use pattern:
*
* // 1. First call — caller has no pinned integrity yet. const { integrity } =
* await downloadBinary({ url, name: 'tool' }) // Caller writes `integrity` back
* to external-tools.json or similar.
*
* // 2. Subsequent calls — caller pins the integrity for verification. await
* downloadBinary({ url, name: 'tool', hash: integrity })
*
* @example
*   ```typescript
*   const { binaryPath, integrity } = await downloadBinary({
*   url: 'https://example.com/tool-linux-x64',
*   name: 'tool',
*   })
*   console.log(`Binary at: ${binaryPath}, pin: ${integrity}`)
*   ```
*
* @returns `{binaryPath, downloaded, integrity}` — binary location, whether
*   this call fetched (vs. cache-hit), and the computed SRI integrity for
*   future pinning.
*/
async function downloadBinary(options) {
	const { cacheTtl = require_constants_time.DLX_BINARY_CACHE_TTL, force = false, hash: hashSpec, integrity: rawIntegrity, name, sha256: rawSha256, url } = {
		__proto__: null,
		...options
	};
	let integrity = rawIntegrity;
	let sha256 = rawSha256;
	if (hashSpec !== void 0) {
		const normalized = require_integrity.normalizeHash(hashSpec);
		if (normalized.type === "integrity") integrity = normalized.value;
		else sha256 = normalized.value;
	}
	const fs = /* @__PURE__ */ require_node_fs.getNodeFs();
	const path = /* @__PURE__ */ require_node_path.getNodePath();
	const cacheDir = require_dlx_binary_cache.getDlxCachePath();
	const binaryName = name || `binary-${node_process.default.platform}-${require_constants_platform.getArch()}`;
	const cacheKey = require_dlx_cache.generateCacheKey(`${url}:${binaryName}`);
	const cacheEntryDir = path.join(cacheDir, cacheKey);
	const binaryPath = /* @__PURE__ */ require_paths_normalize.normalizePath(path.join(cacheEntryDir, binaryName));
	let downloaded = false;
	let actualIntegrity = "";
	if (!force && fs.existsSync(cacheEntryDir) && await require_dlx_binary_cache.isBinaryCacheValid(cacheEntryDir, cacheTtl)) {
		downloaded = false;
		const cachedMeta = await require_dlx_binary_cache.readBinaryCacheMetadata(cacheEntryDir);
		if (cachedMeta?.integrity) actualIntegrity = cachedMeta.integrity;
		else actualIntegrity = `sha512-${/* @__PURE__ */ require_crypto_hash.hash("sha512", await fs.promises.readFile(binaryPath), "base64")}`;
	} else {
		try {
			await require_fs_safe.safeMkdir(cacheEntryDir);
		} catch (e) {
			const code = e.code;
			if (code === "EACCES" || code === "EPERM") throw new require_primordials_error.ErrorCtor(`Permission denied creating binary cache directory: ${cacheEntryDir}\nPlease check directory permissions or run with appropriate access.`, { cause: e });
			if (code === "EROFS") throw new require_primordials_error.ErrorCtor(`Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}\nEnsure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`, { cause: e });
			throw new require_primordials_error.ErrorCtor(`Failed to create binary cache directory: ${cacheEntryDir}`, { cause: e });
		}
		actualIntegrity = await downloadBinaryFile(url, binaryPath, integrity, sha256);
		const stats = await fs.promises.stat(binaryPath);
		await require_dlx_binary_cache.writeBinaryCacheMetadata(cacheEntryDir, cacheKey, url, actualIntegrity, stats.size);
		downloaded = true;
	}
	return {
		binaryPath,
		downloaded,
		integrity: actualIntegrity
	};
}
/**
* Download a file from a URL with integrity checking and concurrent download
* protection. Uses processLock to prevent multiple processes from downloading
* the same binary simultaneously.
*
* Supports two integrity verification methods:
*
* - Sha256: Hex SHA-256 checksum (verified inline during download via
*   httpDownload)
* - Integrity: SRI format sha512-<base64> (verified post-download)
*
* The sha256 option is preferred as it fails early during download if the
* checksum doesn't match.
*
* @example
*   ```typescript
*   const integrity = await downloadBinaryFile(
*   'https://example.com/tool-linux-x64',
*   '/tmp/dlx-cache/tool',
*   )
*   console.log(`Integrity: ${integrity}`)
*   ```
*/
async function downloadBinaryFile(url, destPath, integrity, sha256) {
	const crypto = /* @__PURE__ */ require_node_crypto.getNodeCrypto();
	const fs = /* @__PURE__ */ require_node_fs.getNodeFs();
	const path = /* @__PURE__ */ require_node_path.getNodePath();
	const cacheEntryDir = path.dirname(destPath);
	const lockPath = path.join(cacheEntryDir, "concurrency.lock");
	const verifyIntegrity = async (actualIntegrity) => {
		if (!integrity) return;
		if (!(actualIntegrity.length === integrity.length && crypto.timingSafeEqual(require_primordials_buffer.BufferFrom(actualIntegrity), Buffer.from(integrity)))) {
			await require_fs_safe.safeDelete(destPath);
			throw new require_primordials_error.ErrorCtor(`Integrity mismatch: expected ${integrity}, got ${actualIntegrity}`);
		}
	};
	const verifyCachedSha256 = async (fileBuffer) => {
		if (!sha256) return;
		const actualSha256 = /* @__PURE__ */ require_crypto_hash.hash("sha256", fileBuffer, "hex");
		if (!(actualSha256.length === sha256.length && crypto.timingSafeEqual(require_primordials_buffer.BufferFrom(actualSha256), Buffer.from(sha256.toLowerCase())))) {
			await require_fs_safe.safeDelete(destPath);
			throw new require_primordials_error.ErrorCtor(`SHA-256 mismatch: expected ${sha256}, got ${actualSha256}`);
		}
	};
	return await require_process_lock_instance.processLock.withLock(lockPath, async () => {
		if (fs.existsSync(destPath)) {
			if ((await fs.promises.stat(destPath)).size > 0) {
				const fileBuffer = await fs.promises.readFile(destPath);
				const actualIntegrity = `sha512-${/* @__PURE__ */ require_crypto_hash.hash("sha512", fileBuffer, "base64")}`;
				await verifyIntegrity(actualIntegrity);
				await verifyCachedSha256(fileBuffer);
				return actualIntegrity;
			}
		}
		try {
			await require_http_request_download.httpDownload(url, destPath, sha256 ? { sha256 } : void 0);
		} catch (e) {
			throw new require_primordials_error.ErrorCtor(`Failed to download binary from ${url}\nDestination: ${destPath}\nCheck your internet connection or verify the URL is accessible.`, { cause: e });
		}
		const actualIntegrity = `sha512-${/* @__PURE__ */ require_crypto_hash.hash("sha512", await fs.promises.readFile(destPath), "base64")}`;
		await verifyIntegrity(actualIntegrity);
		if (!require_constants_platform.WIN32) await fs.promises.chmod(destPath, 493);
		return actualIntegrity;
	}, {
		staleMs: 5e3,
		touchIntervalMs: 2e3
	});
}

//#endregion
exports.downloadBinary = downloadBinary;
exports.downloadBinaryFile = downloadBinaryFile;