"use strict";
/* Socket Lib - Built with esbuild */
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 __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], 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);
var dlx_binary_exports = {};
__export(dlx_binary_exports, {
  cleanDlxCache: () => cleanDlxCache,
  dlxBinary: () => dlxBinary,
  downloadBinary: () => downloadBinary,
  executeBinary: () => executeBinary,
  getDlxCachePath: () => getDlxCachePath,
  listDlxCache: () => listDlxCache
});
module.exports = __toCommonJS(dlx_binary_exports);
var import_crypto = require("crypto");
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_platform = require("./constants/platform");
var import_time = require("./constants/time");
var import_dlx = require("./dlx");
var import_dlx_manifest = require("./dlx-manifest");
var import_http_request = require("./http-request");
var import_fs = require("./fs");
var import_objects = require("./objects");
var import_normalize = require("./paths/normalize");
var import_socket = require("./paths/socket");
var import_process_lock = require("./process-lock");
var import_spawn = require("./spawn");
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
  if (_fs === void 0) {
    _fs = require("node:fs");
  }
  return _fs;
}
function getMetadataPath(cacheEntryPath) {
  return import_path.default.join(cacheEntryPath, ".dlx-metadata.json");
}
async function isCacheValid(cacheEntryPath, cacheTtl) {
  const fs = /* @__PURE__ */ getFs();
  try {
    const metaPath = getMetadataPath(cacheEntryPath);
    if (!fs.existsSync(metaPath)) {
      return false;
    }
    const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
    if (!(0, import_objects.isObjectObject)(metadata)) {
      return false;
    }
    const now = Date.now();
    const timestamp = metadata["timestamp"];
    if (typeof timestamp !== "number" || timestamp <= 0) {
      return false;
    }
    const age = now - timestamp;
    return age < cacheTtl;
  } catch {
    return false;
  }
}
async function downloadBinaryFile(url, destPath, checksum) {
  const cacheEntryDir = import_path.default.dirname(destPath);
  const lockPath = import_path.default.join(cacheEntryDir, "concurrency.lock");
  return await import_process_lock.processLock.withLock(
    lockPath,
    async () => {
      const fs = /* @__PURE__ */ getFs();
      if (fs.existsSync(destPath)) {
        const stats = await fs.promises.stat(destPath);
        if (stats.size > 0) {
          const fileBuffer2 = await fs.promises.readFile(destPath);
          const hasher2 = (0, import_crypto.createHash)("sha256");
          hasher2.update(fileBuffer2);
          return hasher2.digest("hex");
        }
      }
      try {
        await (0, import_http_request.httpDownload)(url, destPath);
      } catch (e) {
        throw new Error(
          `Failed to download binary from ${url}
Destination: ${destPath}
Check your internet connection or verify the URL is accessible.`,
          { cause: e }
        );
      }
      const fileBuffer = await fs.promises.readFile(destPath);
      const hasher = (0, import_crypto.createHash)("sha256");
      hasher.update(fileBuffer);
      const actualChecksum = hasher.digest("hex");
      if (checksum && actualChecksum !== checksum) {
        await (0, import_fs.safeDelete)(destPath);
        throw new Error(
          `Checksum mismatch: expected ${checksum}, got ${actualChecksum}`
        );
      }
      if (!import_platform.WIN32) {
        await fs.promises.chmod(destPath, 493);
      }
      return actualChecksum;
    },
    {
      // Align with npm npx locking strategy.
      staleMs: 5e3,
      touchIntervalMs: 2e3
    }
  );
}
async function writeMetadata(cacheEntryPath, cacheKey, url, binaryName, checksum, size) {
  const metaPath = getMetadataPath(cacheEntryPath);
  const metadata = {
    version: "1.0.0",
    cache_key: cacheKey,
    timestamp: Date.now(),
    checksum,
    checksum_algorithm: "sha256",
    platform: import_os.default.platform(),
    arch: import_os.default.arch(),
    size,
    source: {
      type: "download",
      url
    }
  };
  const fs = /* @__PURE__ */ getFs();
  await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2));
  try {
    const spec = `${url}:${binaryName}`;
    await import_dlx_manifest.dlxManifest.setBinaryEntry(spec, cacheKey, {
      checksum,
      checksum_algorithm: "sha256",
      platform: import_os.default.platform(),
      arch: import_os.default.arch(),
      size,
      source: {
        type: "download",
        url
      }
    });
  } catch {
  }
}
async function cleanDlxCache(maxAge = import_time.DLX_BINARY_CACHE_TTL) {
  const cacheDir = getDlxCachePath();
  const fs = /* @__PURE__ */ getFs();
  if (!fs.existsSync(cacheDir)) {
    return 0;
  }
  let cleaned = 0;
  const now = Date.now();
  const entries = await fs.promises.readdir(cacheDir);
  for (const entry of entries) {
    const entryPath = import_path.default.join(cacheDir, entry);
    const metaPath = getMetadataPath(entryPath);
    try {
      if (!await (0, import_fs.isDir)(entryPath)) {
        continue;
      }
      const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
      if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
        continue;
      }
      const timestamp = metadata["timestamp"];
      const age = typeof timestamp === "number" && timestamp > 0 ? now - timestamp : Number.POSITIVE_INFINITY;
      if (age > maxAge) {
        await (0, import_fs.safeDelete)(entryPath, { force: true, recursive: true });
        cleaned += 1;
      }
    } catch {
      try {
        const contents = await fs.promises.readdir(entryPath);
        if (!contents.length) {
          await (0, import_fs.safeDelete)(entryPath);
          cleaned += 1;
        }
      } catch {
      }
    }
  }
  return cleaned;
}
async function dlxBinary(args, options, spawnExtra) {
  const {
    cacheTtl = import_time.DLX_BINARY_CACHE_TTL,
    checksum,
    force: userForce = false,
    name,
    spawnOptions,
    url,
    yes
  } = { __proto__: null, ...options };
  const force = yes === true ? true : userForce;
  const cacheDir = getDlxCachePath();
  const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`;
  const spec = `${url}:${binaryName}`;
  const cacheKey = (0, import_dlx.generateCacheKey)(spec);
  const cacheEntryDir = import_path.default.join(cacheDir, cacheKey);
  const binaryPath = (0, import_normalize.normalizePath)(import_path.default.join(cacheEntryDir, binaryName));
  const fs = /* @__PURE__ */ getFs();
  let downloaded = false;
  let computedChecksum = checksum;
  if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) {
    try {
      const metaPath = getMetadataPath(cacheEntryDir);
      const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
      if (metadata && typeof metadata === "object" && !Array.isArray(metadata) && typeof metadata["checksum"] === "string") {
        computedChecksum = metadata["checksum"];
      } else {
        downloaded = true;
      }
    } catch {
      downloaded = true;
    }
  } else {
    downloaded = true;
  }
  if (downloaded) {
    try {
      await (0, import_fs.safeMkdir)(cacheEntryDir);
    } catch (e) {
      const code = e.code;
      if (code === "EACCES" || code === "EPERM") {
        throw new Error(
          `Permission denied creating binary cache directory: ${cacheEntryDir}
Please check directory permissions or run with appropriate access.`,
          { cause: e }
        );
      }
      if (code === "EROFS") {
        throw new Error(
          `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
          { cause: e }
        );
      }
      throw new Error(
        `Failed to create binary cache directory: ${cacheEntryDir}`,
        { cause: e }
      );
    }
    computedChecksum = await downloadBinaryFile(url, binaryPath, checksum);
    const stats = await fs.promises.stat(binaryPath);
    await writeMetadata(
      cacheEntryDir,
      cacheKey,
      url,
      binaryName,
      computedChecksum || "",
      stats.size
    );
  }
  const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
  const finalSpawnOptions = needsShell ? {
    ...spawnOptions,
    env: {
      ...spawnOptions?.env,
      PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}`
    },
    shell: true
  } : spawnOptions;
  const spawnPromise = (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra);
  return {
    binaryPath,
    downloaded,
    spawnPromise
  };
}
async function downloadBinary(options) {
  const {
    cacheTtl = import_time.DLX_BINARY_CACHE_TTL,
    checksum,
    force = false,
    name,
    url
  } = { __proto__: null, ...options };
  const cacheDir = getDlxCachePath();
  const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`;
  const spec = `${url}:${binaryName}`;
  const cacheKey = (0, import_dlx.generateCacheKey)(spec);
  const cacheEntryDir = import_path.default.join(cacheDir, cacheKey);
  const binaryPath = (0, import_normalize.normalizePath)(import_path.default.join(cacheEntryDir, binaryName));
  const fs = /* @__PURE__ */ getFs();
  let downloaded = false;
  if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) {
    downloaded = false;
  } else {
    try {
      await (0, import_fs.safeMkdir)(cacheEntryDir);
    } catch (e) {
      const code = e.code;
      if (code === "EACCES" || code === "EPERM") {
        throw new Error(
          `Permission denied creating binary cache directory: ${cacheEntryDir}
Please check directory permissions or run with appropriate access.`,
          { cause: e }
        );
      }
      if (code === "EROFS") {
        throw new Error(
          `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
          { cause: e }
        );
      }
      throw new Error(
        `Failed to create binary cache directory: ${cacheEntryDir}`,
        { cause: e }
      );
    }
    const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum);
    const stats = await fs.promises.stat(binaryPath);
    await writeMetadata(
      cacheEntryDir,
      cacheKey,
      url,
      binaryName,
      computedChecksum || "",
      stats.size
    );
    downloaded = true;
  }
  return {
    binaryPath,
    downloaded
  };
}
function executeBinary(binaryPath, args, spawnOptions, spawnExtra) {
  const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
  const cacheEntryDir = import_path.default.dirname(binaryPath);
  const finalSpawnOptions = needsShell ? {
    ...spawnOptions,
    env: {
      ...spawnOptions?.env,
      PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}`
    },
    shell: true
  } : spawnOptions;
  return (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra);
}
function getDlxCachePath() {
  return (0, import_socket.getSocketDlxDir)();
}
async function listDlxCache() {
  const cacheDir = getDlxCachePath();
  const fs = /* @__PURE__ */ getFs();
  if (!fs.existsSync(cacheDir)) {
    return [];
  }
  const results = [];
  const now = Date.now();
  const entries = await fs.promises.readdir(cacheDir);
  for (const entry of entries) {
    const entryPath = import_path.default.join(cacheDir, entry);
    try {
      if (!await (0, import_fs.isDir)(entryPath)) {
        continue;
      }
      const metaPath = getMetadataPath(entryPath);
      const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
      if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
        continue;
      }
      const metaObj = metadata;
      const source = metaObj["source"];
      const url = source?.["url"] || metaObj["url"] || "";
      const files = await fs.promises.readdir(entryPath);
      const binaryFile = files.find((f) => !f.startsWith("."));
      if (binaryFile) {
        const binaryPath = import_path.default.join(entryPath, binaryFile);
        const binaryStats = await fs.promises.stat(binaryPath);
        results.push({
          age: now - (metaObj["timestamp"] || 0),
          arch: metaObj["arch"] || "unknown",
          checksum: metaObj["checksum"] || "",
          name: binaryFile,
          platform: metaObj["platform"] || "unknown",
          size: binaryStats.size,
          url
        });
      }
    } catch {
    }
  }
  return results;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  cleanDlxCache,
  dlxBinary,
  downloadBinary,
  executeBinary,
  getDlxCachePath,
  listDlxCache
});
