Есть картинка npm, которая сидит у меня в голове уже много лет. Это Software Galaxies Андрея Кащи: весь реестр, нарисованный облаком звёзд. Мне хотелось ту же картинку, но в движении, кадр на год, чтобы увидеть, как эта штука растёт. Его данные по npm заканчиваются снимком ноября 2020 года, так что пришлось строить свою.
Мнение у меня тоже было готово до того, как я что-то посчитал. В 2019 году Циммерманн с соавторами написали, что 20 аккаунтов мейнтейнеров достают больше чем до половины npm. Я всегда относил это к годам left-pad. С тех пор реестр вырос с неполного миллиона пакетов примерно до 4,5 миллиона и я решил, что власть расползлась вместе с ним. Я ни разу это не проверял, мне просто нравилось, как это звучит.
Как я считал
8 октября 2026 года эндпойнт репликации реестра отдал 4465309 имён пакетов. Скачать все было нереально, поэтому я взял случайную выборку из 30000 имён и скачал их полные документы. На каждый год с 2011 по 2026 я брал самую высокую по номеру версию из существовавших на 31 декабря этого года вместе с её dependencies. 2026 год обрезан по началу 8 октября. Дальше я шёл по этим зависимостям вниз, пока недостающих не осталось. В итоге понадобилось 98736 документов пакетов.
Для каждого числа ниже важны такие правила. Пакет существует в году, если у него есть версия с датой до среза. Ребро это одна строка в dependencies этой версии, без dev и peer зависимостей. Числа для всего реестра это выборка, умноженная на 4465309 / 30000. Сам счёт написан на голом Python 3.12. Раскладку гифки делал networkx 3.6, рисовал matplotlib 3.11, сжимал gifsicle 1.94.
Прежде чем этому верить, я сравнил результат со старыми статьями. У Циммерманна было 1,3 прямой зависимости на пакет в 2011 году и 2,8 в 2018, у меня 1,26 и 2,91. В статье Робинсона с соавторами 2026 года у 61,3 процента пакетов есть хотя бы 1 зависимость, у меня 60,7. Достаточно близко, чтобы идти дальше.
Узлы и рёбра
На конец 2011 года выборка даёт около 2800 пакетов и 3600 рёбер. На 8 октября 2026 года это 4,45 миллиона пакетов и 19,4 миллиона рёбер. До 2024 года рёбра каждый год растут быстрее узлов, это видели ещё Кикас с соавторами в 2017 году. В 2025 и 2026 годах наоборот.
Потом наступил 2024 год и я решил, что у меня баг. Рёбер за 1 год стало вдвое больше, с 8,1 миллиона до 16,1 миллиона, а пакетов прибавилось на 28 процентов. Среднее число зависимостей прыгнуло с 3,24 до 5,02.
Это был не баг. Пакетов, созданных в 2024 году, в выборке 4724 и на них приходится 53391 ребро, то есть 41 процент всех рёбер 2026 года. У 431 из них 20 и больше зависимостей и 81 процент их рёбер ведёт к другим пакетам, созданным в 2024 году или позже. Пакеты, на которые они ссылаются, называются вроде gain-pleasant-prepare и anywhere-dream. Я открыл тарболы этих 431, прочитать удалось 430. В 52 лежит tea.yaml, файл протокола вознаграждений tea.xyz. Среди 1376 пакетов, созданных в 2023 году и имеющих хотя бы 1 зависимость, таких не нашлось ни одного. Значит, часть этого накрутка ради наград того протокола, а остальное я объяснить не могу.
Нашёл я их неприятным способом. Докачка замыкания не заканчивалась. Проход за проходом не хватало от 16 до 18 имён, потому что cadutdudut_128 зависит от cadutdudut_127, тот от cadutdudut_126 и так далее. Я остановился на 15 нескачанных именах. 11 из них это следующее звено такой пронумерованной цепочки, остальные 4 висят на пакетах тех же месяцев, с марта по май 2024 года. Они немного меняют размеры замыканий у спама и больше ничего.
Кто держит граф
Сначала прямые рёбра. В 2015 году 100 самых используемых пакетов получали 43 процента всех рёбер выборки. В 2018 году было 34 процента, в 2023 году 28, в 2026 году 20. Часть последнего падения дал спам 2024 года, потому что его рёбра ведут друг к другу. И всё же по этой мерке моё мнение подтвердилось и граф расползся.
Потом транзитивная картина, а она и важна, если аккаунт украдут. Для каждого пакета выборки я собрал всё, что он подтягивает через зависимости, а потом все аккаунты из списков мейнтейнеров этих версий. Потом спросил, до скольких пакетов достаёт каждый аккаунт.
Первый по охвату аккаунт доставал до 35 процентов всех пакетов в 2015 году (substack), до 33 процентов в 2018 (isaacs) и до 25 процентов в 2026 (sindresorhus). Здесь все пакеты считаются вместе с теми 39 процентами, у которых зависимостей нет вообще и до которых не достанет никто. Среди пакетов хотя бы с 1 зависимостью с 2021 года каждый год хватает 2 аккаунтов на половину из них.
До половины всего, если брать аккаунты в том же жадном порядке, что у Циммерманна, достают 11 аккаунтов в 2018 году и 17 в 2026. Я бы не стал верить этим числам с точностью до единицы. Когда я разбил выборку на 2 половины, вышло 10 и 12 для 2018 года и 14 и 19 для 2026, так что честный ответ на сегодня “от 14 до 19”. Доля первого аккаунта устойчива, 25,0 и 25,5 процента на 2 половинах.
Мой счёт не совпадает с их счётом. Они брали весь реестр до апреля 2018 года, я выборку и самую высокую версию каждого пакета. Мои 11 за 2018 год против их 20 могут объясняться этой разницей и больше я бы в это не вчитывался.
Итого с 2015 года доля 100 главных пакетов в прямых рёбрах упала вдвое, а охват первого аккаунта снизился всего с 35 до 25 процентов. Четверть npm по-прежнему зависит от одного аккаунта. Некоторые из 17 аккаунтов вообще не люди: types стоит почти за каждым пакетом @types, а react-bot, судя по имени, релизный бот React.
Чего я не проверял
- “Мейнтейнер” здесь это список в документе версии. Наличие в списке ничего не говорит о том, кто публикует, у кого включена 2FA и кто перешёл на trusted publishing.
- Снятых и удалённых пакетов в реестре сегодня нет, поэтому ранние годы занижены. Насколько, я не знаю.
- Одна версия на пакет на год, диапазон версий у родителя я не разрешал. Настоящая установка может подтянуть другую версию с другими зависимостями.
- Одна случайная выборка, один прогон. Ранние годы стоят на очень немногих пакетах, 104 в 2012 году и 754 в 2014, поэтому из них я бы не вычитывал ничего, кроме тренда.
Я так и не понял, что делать с этими аккаунтами, а их от 14 до 19. Большинство из них люди, которые ничего плохого не сделали: они рано написали маленькие пакеты и от них теперь зависят все.