// src/lib/updo/fetchRegistryInfo.ts
import fs from "node:fs";
import os from "node:os";
import path from "node:path";

// src/lib/concurrency.ts
import { AsyncLocalStorage } from "node:async_hooks";
var outputStorage = new AsyncLocalStorage();
async function runWithConcurrency(items, concurrency, fn) {
  let next = 0;
  async function worker() {
    while (next < items.length) {
      const i = next++;
      await fn(items[i]);
    }
  }
  await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
}

// src/lib/initCwd.ts
function INIT_CWD() {
  return process.env.INIT_CWD ?? process.cwd();
}

// src/lib/updo/fetchRegistryInfo.ts
var REGISTRY_BASE = "https://registry.npmjs.org";
function parseNpmrc(filePath, into) {
  let text;
  try {
    text = fs.readFileSync(filePath, "utf8");
  } catch {
    return;
  }
  for (const rawLine of text.split("\n")) {
    const line = rawLine.trim();
    if (!line || line.startsWith("#") || line.startsWith(";")) continue;
    const tokenMatch = /^\/\/([^:]+?):_authToken=(.+)$/.exec(line);
    if (tokenMatch) {
      const hostPath = tokenMatch[1];
      const token = tokenMatch[2].trim().replaceAll(/^["']|["']$/g, "");
      const host = hostPath.split("/")[0];
      into.tokens.set(`https://${host}`, token);
      continue;
    }
    const scopeMatch = /^(@[^:]+):registry=(.+)$/.exec(line);
    if (scopeMatch) {
      into.scopeRegistries.set(scopeMatch[1], scopeMatch[2].trim().replace(/\/$/, ""));
    }
  }
}
var cachedConfig;
function loadNpmrcConfig() {
  if (cachedConfig) return cachedConfig;
  const config = { scopeRegistries: /* @__PURE__ */ new Map(), tokens: /* @__PURE__ */ new Map() };
  parseNpmrc(path.join(INIT_CWD(), ".npmrc"), config);
  parseNpmrc(path.join(os.homedir(), ".npmrc"), config);
  cachedConfig = config;
  return config;
}
function resolveRegistry(packageName, config) {
  if (packageName.startsWith("@")) {
    const scope = packageName.split("/")[0];
    const scoped = config.scopeRegistries.get(scope);
    if (scoped) return scoped;
  }
  return REGISTRY_BASE;
}
async function fetchRegistryInfo(packageName, options = {}) {
  try {
    const config = loadNpmrcConfig();
    const registry = resolveRegistry(packageName, config);
    const url = `${registry}/${packageName}`;
    const headers = {};
    if (!options.wantTimes) {
      headers.Accept = "application/vnd.npm.install-v1+json";
    }
    const token = config.tokens.get(registry);
    if (token) headers.Authorization = `Bearer ${token}`;
    const res = await fetch(url, { headers });
    if (!res.ok) {
      return { distTags: {}, versions: [] };
    }
    const data = await res.json();
    const versionKeys = Object.keys(data.versions ?? {});
    const result = {
      distTags: data["dist-tags"] ?? {},
      versions: versionKeys
    };
    if (options.wantTimes && data.time) {
      const publishTimes = {};
      for (const v of versionKeys) {
        const t = data.time[v];
        if (typeof t === "string") publishTimes[v] = t;
      }
      result.publishTimes = publishTimes;
    }
    return result;
  } catch {
    return { distTags: {}, versions: [] };
  }
}
async function fetchAllRegistryInfo(packageNames, options = {}) {
  const results = /* @__PURE__ */ new Map();
  const concurrency = options.concurrency ?? 16;
  let completed = 0;
  const total = packageNames.length;
  await runWithConcurrency(packageNames, concurrency, async (name) => {
    results.set(name, await fetchRegistryInfo(name, { wantTimes: options.wantTimes }));
    completed++;
    if (completed % 25 === 0 || completed === total) {
      process.stderr.write(`\r  Fetched ${completed}/${total} packages...`);
    }
  });
  if (total > 0) {
    process.stderr.write("\n");
  }
  return results;
}
export {
  fetchAllRegistryInfo,
  fetchRegistryInfo
};
//# sourceMappingURL=fetchRegistryInfo.mjs.map
