Yarn >=4.16 npmMinimalAgeGate (default 1d) карантинит версии <24ч на КЛИЕНТЕ — независимый от auth gate #2 (после 401). Серверного карантина в verdaccio нет; первичная гипотеза опровергнута пруфом из yarn.js. Глобальный config (per-scope не работает), fix npmMinimalAgeGate:0. Backlink из verdaccio-token-lifecycle + index/log. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.7 KiB
title, type, tags, sources, updated
| title | type | tags | sources | updated | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Yarn 4.16 npmMinimalAgeGate — YN0016 "quarantined" на свежих пакетах | concept |
|
2026-06-11 |
Yarn 4.16 npmMinimalAgeGate — клиентский «карантин» свежих версий
Симптом
yarn install (Yarn Berry ≥4.16) падает на резолве:
@snolla/site-schema-gen@npm:^0.5.0: All versions satisfying "^0.5.0" are quarantined
Код ошибки — YN0016. Версия физически есть в реестре, dist-tags.latest указывает на неё, токен валиден (whoami отдаёт юзера) — но yarn её не берёт.
Root cause — клиентский age-gate, НЕ сервер
Yarn 4.16 ввёл настройку npmMinimalAgeGate (supply-chain мера против свежезалитых вредоносных версий, по следам атак на npm 2025). Из бинаря ~/AppData/Local/node/corepack/v1/yarn/4.16.0/yarn.js:
npmMinimalAgeGate: { type: "DURATION", unit: "m", default: "1d" } # = 1440 минут
Фильтр перед резолвом отсеивает версию, если:
- у неё нет даты публикации в packument-поле
time, или (now − publishDate) < npmMinimalAgeGate.
Если после фильтра кандидатов не осталось → throw YN0016 "...are quarantined".
Карантин целиком на стороне yarn-клиента. На сервере verdaccio никакого карантина нет (нет в config.yaml, plugins-папка пустая) — серверная проверка пакумента его не видит. Реестр отдаёт версию чисто любому валидному read-токену.
Версионная разница (почему «у одних работает»)
| yarn | npmMinimalAgeGate default |
|---|---|
| ≤ 4.14 (напр. snolla 4.14.1) | 0 — гейта нет |
| ≥ 4.16 | 1d (1440 мин) |
Проект на 4.14 «просто работает», на 4.16 тот же канон ловит YN0016 первые 24 ч после публикации пакета.
Два независимых последовательных гейта
Важно не путать с auth — это разные стены, в таком порядке:
- auth — кривой/протухший токен →
YN0041 Invalid authentication(это 401, см. verdaccio-token-lifecycle). - age-gate — валидный токен, но версия моложе порога →
YN0016 …quarantined.
Решающий признак: если на валидном токене (auth прошёл, 401 нет) всё равно падает — это гейт #2, не auth. Token-fix его НЕ снимает.
Fix
# .yarnrc.yml — глобально:
npmMinimalAgeGate: 0
# либо разово, per-invocation (сохраняет защитный дефолт для обычных install'ов):
YARN_NPM_MINIMAL_AGE_GATE=0 yarn install
Нюанс: гейт читается ГЛОБАЛЬНО, не per-scope
В фильтре — configuration.get("npmMinimalAgeGate") (глобальный config), не scope-aware lookup. Поэтому npmMinimalAgeGate под npmScopes.@snolla.* игнорируется — нельзя ослабить гейт только для доверенного приватного скоупа. Глобальный 0 снимает age-защиту и с публичных npmjs-пакетов, которые verdaccio проксирует через uplink. Это реальный security trade-off — в этом и смысл фичи.
Рекомендация: не коммитить 0 в общий канон бездумно. Для CI / чужих проектов — разовый YARN_NPM_MINIMAL_AGE_GATE=0 под осознанный install сразу после своей публикации. Для тесного publish→consume dev-loop своих пакетов (напр. pilonuxt) глобальный 0 оправдан — реестр один доверенный, DX важнее. Финальный risk-call — за владельцем экосистемы.
Ecosystem heads-up
Любой потребитель на yarn ≥4.16, тянущий свежеопубликованные @snolla/@snollajs пакеты, будет ловить YN0016 первые 24 ч. Когда snolla-монореп/проекты переедут на 4.16+ — решить, добавлять ли npmMinimalAgeGate: 0 в snolla-канон .yarnrc.yml или держать override on-demand.
Применено / источник
Диагностировано 2026-06-11 совместно с сессией pilonuxt (миграция pnpm→yarn 4.16). Первичная ошибочная гипотеза «карантин = серверный дефект verdaccio» опровергнута: пруф — строка are quarantined + npmMinimalAgeGate в yarn.js 4.16.0, и YN0016 воспроизводится на валидном vitya-токене, снимается только npmMinimalAgeGate: 0.
Связанные
- verdaccio-token-lifecycle — гейт #1 (auth / JWT / 401), соседняя стена
- verdaccio-restore-packument-desync — почему версии вообще пришлось republish (disaster-restore)
- ../entities/vds-kzntsv — хост verdaccio