116 lines
3.1 KiB
JavaScript
116 lines
3.1 KiB
JavaScript
'use strict';
|
|
|
|
// Inspired in part by
|
|
// * https://www.npmjs.com/package/npmjs-api
|
|
// * https://github.com/kevva/npm-user-packages/blob/master/index.js
|
|
|
|
// Official docs at
|
|
// * https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md#meta-endpoints
|
|
// * https://github.com/npm/registry/blob/master/docs/download-counts.md
|
|
|
|
var batchAsync = require('batchasync').batchAsync;
|
|
var request = require('@root/request');
|
|
request = require('util').promisify(request);
|
|
|
|
var hnai = exports;
|
|
hnai.packages = function(username) {
|
|
// I didn't bother to implement paging because... I didn't
|
|
return request({
|
|
url: 'https://api.npms.io/v2/search?q=author:' + username + '&size=250&from=0',
|
|
json: true
|
|
}).then(function(resp) {
|
|
// { total: 214, results: [ { package: { name: 'foobar' } } ] }
|
|
if (resp.total > 250) {
|
|
console.warn();
|
|
console.warn("You have more than 250 published packages, but I haven't implemented paging.");
|
|
console.warn("I'd say please open an issue, but you're ovbiously skilled, so please PR.");
|
|
console.warn();
|
|
}
|
|
return resp.body.results.map(function(result) {
|
|
return result.package.name;
|
|
});
|
|
});
|
|
};
|
|
|
|
hnai.downloads = function(pkgnames) {
|
|
// https://github.com/npm/registry/blob/master/docs/download-counts.md#bulk-queries
|
|
// FYI: Earliest date is January 10, 2015
|
|
// * One-off: https://api.npmjs.org/downloads/range/{period}[/{package}]
|
|
// * Bulk: https://api.npmjs.org/downloads/point/last-day/npm,express
|
|
|
|
// All the batching logic
|
|
var batches = [];
|
|
var batch = [];
|
|
pkgnames.forEach(function(pkgname) {
|
|
if ('@' === pkgname[0]) {
|
|
batches.push([pkgname]);
|
|
return;
|
|
}
|
|
if (batch.length >= 128) {
|
|
batches.push(batch);
|
|
batch = [];
|
|
}
|
|
batch.push(pkgname);
|
|
});
|
|
if (batch.length) {
|
|
batches.push(batch);
|
|
}
|
|
|
|
// do the batching
|
|
return batchAsync(4, batches, function(batch) {
|
|
if (1 === batch.length) {
|
|
return one(batch[0]);
|
|
} else {
|
|
return many(batch);
|
|
}
|
|
}).then(function(results) {
|
|
// transform the results
|
|
var all = [];
|
|
results.forEach(function(map) {
|
|
//#console.debug('batch size:', Object.keys(map).length);
|
|
Object.keys(map).forEach(function(key) {
|
|
if (!map[key]) {
|
|
// can be 'null' for just-published packages
|
|
map[key] = { downloads: 0 };
|
|
}
|
|
all.push({
|
|
package: key,
|
|
downloads: map[key].downloads
|
|
});
|
|
});
|
|
});
|
|
|
|
// get back one big happy list
|
|
return all;
|
|
});
|
|
};
|
|
|
|
// these need to be simplified and transformed
|
|
function one(pkgname) {
|
|
return request({
|
|
url: 'https://api.npmjs.org/downloads/range/last-month/' + pkgname,
|
|
json: true
|
|
}).then(function(resp) {
|
|
// { package: 'foobar', downloads: [{ downloads: 1, day: '2019-06-16' }] }
|
|
var result = {};
|
|
result[resp.body.package] = {
|
|
package: resp.body.package,
|
|
downloads: resp.body.downloads.reduce(function(sum, el) {
|
|
return el.downloads;
|
|
}, 0)
|
|
};
|
|
return result;
|
|
});
|
|
}
|
|
|
|
// these are exactly what we want, pretty much
|
|
function many(pkgnames) {
|
|
return request({
|
|
url: 'https://api.npmjs.org/downloads/point/last-month/' + pkgnames.join(','),
|
|
json: true
|
|
}).then(function(resp) {
|
|
// { foobar: { downloads: 12 } }
|
|
return resp.body;
|
|
});
|
|
}
|