mirror of
https://github.com/LukeHagar/usage-statistics.git
synced 2025-12-06 04:21:55 +00:00
113 lines
4.3 KiB
JavaScript
113 lines
4.3 KiB
JavaScript
/**
|
|
* NPM package statistics collector with enhanced metrics
|
|
*/
|
|
const PlatformSettings = {
|
|
name: 'NPM',
|
|
};
|
|
const BASE_URL = 'https://api.npmjs.org/downloads/range';
|
|
const CHUNK_DAYS = 540; // 18 months max per request
|
|
const START_DATE = new Date('2015-01-10'); // Earliest NPM data
|
|
function formatDate(date) {
|
|
return date.toISOString().split('T')[0];
|
|
}
|
|
function addDays(date, days) {
|
|
const result = new Date(date);
|
|
result.setDate(result.getDate() + days);
|
|
return result;
|
|
}
|
|
async function fetchChunk(start, end, packageName) {
|
|
const url = `${BASE_URL}/${formatDate(start)}:${formatDate(end)}/${packageName}`;
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
throw new Error(`Failed to fetch data: ${res.status} ${res.statusText}`);
|
|
}
|
|
const json = await res.json();
|
|
return json.downloads;
|
|
}
|
|
async function getFullDownloadHistory(packageName, startDate) {
|
|
const today = new Date();
|
|
let currentStart = new Date(startDate);
|
|
let allDownloads = [];
|
|
while (currentStart < today) {
|
|
const currentEnd = addDays(currentStart, CHUNK_DAYS - 1);
|
|
const end = currentEnd > today ? today : currentEnd;
|
|
console.log(`Fetching ${formatDate(currentStart)} to ${formatDate(end)}...`);
|
|
const chunk = await fetchChunk(currentStart, end, packageName);
|
|
allDownloads = allDownloads.concat(chunk);
|
|
currentStart = addDays(end, 1); // move to next chunk
|
|
}
|
|
return Array.from(new Set(allDownloads));
|
|
}
|
|
export async function collectNpm(packageName) {
|
|
try {
|
|
// Get package info from npm registry
|
|
const packageUrl = `https://registry.npmjs.org/${packageName}`;
|
|
const packageResponse = await fetch(packageUrl);
|
|
const packageData = await packageResponse.json();
|
|
// Get download statistics
|
|
let downloadsMonthly;
|
|
let downloadsWeekly;
|
|
let downloadsDaily;
|
|
try {
|
|
// Monthly downloads
|
|
const monthlyUrl = `https://api.npmjs.org/downloads/point/last-month/${packageName}`;
|
|
const monthlyResponse = await fetch(monthlyUrl);
|
|
const monthlyData = await monthlyResponse.json();
|
|
downloadsMonthly = monthlyData.downloads || null;
|
|
}
|
|
catch (error) {
|
|
console.warn(`Could not fetch NPM monthly downloads for ${packageName}:`, error);
|
|
}
|
|
try {
|
|
// Weekly downloads
|
|
const weeklyUrl = `https://api.npmjs.org/downloads/point/last-week/${packageName}`;
|
|
const weeklyResponse = await fetch(weeklyUrl);
|
|
const weeklyData = await weeklyResponse.json();
|
|
downloadsWeekly = weeklyData.downloads || null;
|
|
}
|
|
catch (error) {
|
|
console.warn(`Could not fetch NPM weekly downloads for ${packageName}:`, error);
|
|
}
|
|
try {
|
|
// Daily downloads
|
|
const dailyUrl = `https://api.npmjs.org/downloads/point/last-day/${packageName}`;
|
|
const dailyResponse = await fetch(dailyUrl);
|
|
const dailyData = await dailyResponse.json();
|
|
downloadsDaily = dailyData.downloads || null;
|
|
}
|
|
catch (error) {
|
|
console.warn(`Could not fetch NPM daily downloads for ${packageName}:`, error);
|
|
}
|
|
const downloadsRange = await getFullDownloadHistory(packageName, new Date(packageData.time?.created || START_DATE));
|
|
const downloadsTotal = downloadsRange.reduce((acc, curr) => acc + curr.downloads, 0);
|
|
return {
|
|
platform: PlatformSettings.name,
|
|
name: packageName,
|
|
timestamp: new Date().toISOString(),
|
|
metrics: {
|
|
downloadsTotal,
|
|
downloadsMonthly,
|
|
downloadsWeekly,
|
|
downloadsDaily,
|
|
downloadsRange,
|
|
}
|
|
};
|
|
}
|
|
catch (error) {
|
|
return {
|
|
platform: PlatformSettings.name,
|
|
name: packageName,
|
|
timestamp: new Date().toISOString(),
|
|
metrics: {},
|
|
error: error instanceof Error ? error.message : String(error)
|
|
};
|
|
}
|
|
}
|
|
export async function collectNpmBatch(packageNames) {
|
|
const resultPromises = [];
|
|
for (const packageName of packageNames) {
|
|
resultPromises.push(collectNpm(packageName));
|
|
}
|
|
return Promise.all(resultPromises);
|
|
}
|