Rather than check the dozen npm stats sites, listing each of your modules one at a time, you want to know the total, all at once. Something like this:

npx how-npm-am-i johndoe

You have 2 modules on npm and get 6 downloads per month.
You're a little npm. Not bad.

Well, that didn't exist. But it does now. I'll show you the quick-n-easy, and then I'll show how I prototyped it.

TL;DR how-npm-am-i

Thanks to npm-user-packages, npmjs-api, and npms.io, I was finally able to track down the npmjs.org api and put together a little micro-lib for it myself.

npm install --global how-npm-am-i
how-npm-am-i isaacs --verbose
You've published 161 packages to npm and you get...

Package Name                             Downloads
@isaacs/example-automatic-publishing:            3
cluster-callresp:                               11
voxer-blog-demo:                                12
rimraf:                                 59,309,683
minimatch:                              63,109,081
yallist:                                66,527,785
lru-cache:                              77,627,756
glob:                                  109,654,115

1,423,623,087 downloads per month. Not bad!
You are *very* npm!


Surprisingly, NPM doesn't have some amazingly beautified API page. Instead, it's just some sparse docs on the npm registry github page.

I'm not even sure that they're entirely up-to-date.

I learned a bit from looking at the source of the aforementioned modules as well.

You see, I hate big dependencies for little tasks, so I just got the URLs that I needed and did my dirty work using only @root/request and batchasync, which are zero-dependency libraries I wrote for such small tasks.

Anyway, this is all I ended up using:

Finding packages by a user

Can show up to 250 packages at a time and supports paging via from.

'https://api.npms.io/v2/search?q=author:' + username + '&size=250&from=0';

This gives back a bunch of info, but I'll just highlight what was relevant.

{ total: 215, results: [ { package: 'foobar' } ] }

Info on packages (bulk)

This includes a sum of the downloads between and start and end date.

'https://api.npmjs.org/downloads/point/last-month/' + pkgnames.join(',');

The result looks something like this, but with many packages and maybe a few more properties.

{ foobar: { downloads: 12, start: '2019-06-16', end: '2019-07-15' } }

Info on scoped packages

Scoped packages can't be queried with the bulk API.

'https://api.npmjs.org/downloads/range/last-month/' + pkgname;

The singular API gives more granular detail, including a download count for each day in the selected time period. There are probably some other properties not relevant to the purpose-at-hand which I've left out.

{ package: 'foobar', downloads: [{ downloads: 1, day: '2019-06-16' }] }

Doing it in bash

When I first attempted this I actually banged it together with bash (still using some packages I found on npm).

npm-user-packages-cli gave me the list of packages.

npm install --global npm-user-packages-cli
npm-user-packages coolaj86 | cut -d ' ' -f1 | tee all-my-packages.txt

jq let me pluck just the downloads key from the json I got back.

brew install jq
curl -s -X GET https://api.npmjs.org/downloads/point/last-month/greenlock | jq .downloads

And with a little bit of half-bashed fu I was able to do everything I wanted, other than print out the final count at the end - which turns out to be pretty-much impossible due to how pipes (|) create a subshell, whose values cannot be passed back up to the parent shell without some wizarding trickery that... just wouldn't be worth it.

set -e

npm-user-packages coolaj86 | cut -d ' ' -f1 \
  | tee all-my-packages.txt \
  | while read pkg; do
  echo ""
  echo package: $pkg
  n=$(curl -s -X GET https://api.npmjs.org/downloads/point/last-month/$pkg | jq .downloads)
  printf "count: %'d\n" $n
  count=$((count + n))
  printf "total: %'d\n" $count
echo "Wow! That's way npm."

Bonus: Space-aligned Tables

One of the great benefits of how-npm-am-i written in JavaScript, compared to the bash approach, is how easy it was to create the aligned tables.

Hopefully it doesn't seem too fancy, it's actually quite easy to do with Math.max(), padStart (leftpad), padEnd (rightpad), and the lesser known .toLocaleString().

See https://coolaj86.com//articles/space-aligned-tables-30-lines-vanilla-js/ for more on that.

(originally I explained that here, but it was long and completly tangential, so I split this out into its own article)

By AJ ONeal

If you loved this and want more like it, sign up!

Did I make your day?
Buy me a coffeeBuy me a coffee  

(you can learn about the bigger picture I'm working towards on my patreon page )