// 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/secure/fetchPackageSecurityMetadata.ts
var REGISTRY_BASE = "https://registry.npmjs.org";
var DOWNLOADS_BASE = "https://api.npmjs.org/downloads/point/last-week";
var BULK_DOWNLOADS_CHUNK_SIZE = 100;
var SCOPED_DOWNLOADS_CONCURRENCY = 4;
var manifestCache = /* @__PURE__ */ new Map();
var downloadsCache = /* @__PURE__ */ new Map();
function packageUrlSegment(packageName) {
  return encodeURIComponent(packageName);
}
function isScopedPackageName(packageName) {
  return packageName.startsWith("@");
}
function chunks(items, size) {
  const result = [];
  for (let index = 0; index < items.length; index += size) {
    result.push(items.slice(index, index + size));
  }
  return result;
}
async function fetchManifestUncached(packageName) {
  try {
    const res = await fetch(`${REGISTRY_BASE}/${packageUrlSegment(packageName)}`, { headers: { Accept: "application/json" } });
    if (!res.ok) return void 0;
    const data = await res.json();
    return {
      distTags: data["dist-tags"] ?? {},
      time: data.time ?? {},
      versions: Object.keys(data.versions ?? {})
    };
  } catch {
    return void 0;
  }
}
function fetchSecureRegistryManifest(packageName) {
  const cached = manifestCache.get(packageName);
  if (cached) return cached;
  const pending = fetchManifestUncached(packageName);
  manifestCache.set(packageName, pending);
  return pending;
}
async function fetchDownloadsUncached(packageName) {
  try {
    const res = await fetch(`${DOWNLOADS_BASE}/${packageUrlSegment(packageName)}`);
    if (!res.ok) return void 0;
    const data = await res.json();
    return typeof data.downloads === "number" ? data.downloads : void 0;
  } catch {
    return void 0;
  }
}
function fetchSecureWeeklyDownloads(packageName) {
  const cached = downloadsCache.get(packageName);
  if (cached) return cached;
  const pending = fetchDownloadsUncached(packageName);
  downloadsCache.set(packageName, pending);
  return pending;
}
async function fetchBulkWeeklyDownloads(packageNames) {
  const results = /* @__PURE__ */ new Map();
  if (packageNames.length === 0) return results;
  try {
    const packageSegment = packageNames.map(packageUrlSegment).join(",");
    const res = await fetch(`${DOWNLOADS_BASE}/${packageSegment}`);
    if (!res.ok) {
      await runWithConcurrency(packageNames, SCOPED_DOWNLOADS_CONCURRENCY, async (name) => {
        results.set(name, await fetchSecureWeeklyDownloads(name));
      });
      return results;
    }
    const data = await res.json();
    for (const name of packageNames) {
      const downloads = data[name]?.downloads;
      results.set(name, typeof downloads === "number" ? downloads : void 0);
    }
  } catch {
    await runWithConcurrency(packageNames, SCOPED_DOWNLOADS_CONCURRENCY, async (name) => {
      results.set(name, await fetchSecureWeeklyDownloads(name));
    });
  }
  return results;
}
async function fetchAllSecureWeeklyDownloads(packageNames, concurrency = SCOPED_DOWNLOADS_CONCURRENCY) {
  const uniqueNames = [...new Set(packageNames)].toSorted();
  const unscopedNames = uniqueNames.filter((name) => !isScopedPackageName(name));
  const scopedNames = uniqueNames.filter(isScopedPackageName);
  const results = /* @__PURE__ */ new Map();
  await runWithConcurrency(chunks(unscopedNames, BULK_DOWNLOADS_CHUNK_SIZE), 1, async (chunk) => {
    const chunkResults = await fetchBulkWeeklyDownloads(chunk);
    for (const [name, downloads] of chunkResults) {
      results.set(name, downloads);
    }
  });
  const scopedConcurrency = Math.max(1, Math.min(concurrency, SCOPED_DOWNLOADS_CONCURRENCY));
  await runWithConcurrency(scopedNames, scopedConcurrency, async (name) => {
    results.set(name, await fetchSecureWeeklyDownloads(name));
  });
  return results;
}
async function fetchSecurePackageMetadata(packageName) {
  const [manifest, downloads] = await Promise.all([
    fetchSecureRegistryManifest(packageName),
    fetchSecureWeeklyDownloads(packageName)
  ]);
  return { downloads, manifest };
}
async function fetchAllSecurePackageMetadata(packageNames, concurrency = 16) {
  const uniqueNames = [...new Set(packageNames)].toSorted();
  const manifests = /* @__PURE__ */ new Map();
  const results = /* @__PURE__ */ new Map();
  await runWithConcurrency(uniqueNames, concurrency, async (name) => {
    manifests.set(name, await fetchSecureRegistryManifest(name));
  });
  const downloads = await fetchAllSecureWeeklyDownloads(uniqueNames, concurrency);
  for (const name of uniqueNames) {
    results.set(name, {
      downloads: downloads.get(name),
      manifest: manifests.get(name)
    });
  }
  return results;
}
function clearSecurePackageMetadataCache() {
  manifestCache.clear();
  downloadsCache.clear();
}
export {
  clearSecurePackageMetadataCache,
  fetchAllSecurePackageMetadata,
  fetchAllSecureWeeklyDownloads,
  fetchSecurePackageMetadata,
  fetchSecureRegistryManifest,
  fetchSecureWeeklyDownloads
};
//# sourceMappingURL=fetchPackageSecurityMetadata.mjs.map
