Files
admin/.wiki/concepts/verdaccio-prune-semantics.md

81 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Verdaccio prune semantics — proxied vs locally-published
type: concept
tags: [verdaccio, npm, storage, gc, gotcha]
sources: []
updated: 2026-05-21
---
# Verdaccio prune — proxied vs locally-published
Прежде чем удалять `.tgz` из verdaccio storage, надо отличать proxied (cached from upstream — безопасно удалить, можно re-fetch) от locally-published (authoritative copy — удаление = permanent loss).
## Storage layout
`/storage/data/<package>/`:
- `package.json` — packument (metadata, дешёвый)
- `<package>-<version>.tgz` — binary tarballs (дорогие)
Для scoped: `/storage/data/<scope>/<package>/...`. Scope в filename `.tgz` **НЕ** включается — `@snollajs/snolla/snolla-0.2.4.tgz`.
## Detection rule
В `package.json` есть три relevant fields:
```yaml
_uplinks: { npmjs: { etag, fetched } } # upstream registries verdaccio queried
_distfiles: { "<pkg>-<v>.tgz": { url, sha, registry } } # ключи — ИМЯ tarball, не version
_attachments: { "<pkg>-<v>.tgz": { shasum } } # cached + locally-uploaded tarballs
```
**Detection**:
- `_distfiles[<tgzName>]` defined → **proxied**, tarball mirrored from upstream URL. Удалять `.tgz` файл безопасно — verdaccio re-fetch'нет при следующем `npm install pkg@v`.
- `_distfiles[<tgzName>]` undefined, but `_attachments[<tgzName>]` defined и `.tgz` есть на диске → **locally-published** (`npm publish` в verdaccio через `verdaccio` registry). **НЕ удалять** — это единственная копия.
## Gotcha: keying
Ключи `_distfiles` — это **filename** (`lodash-0.1.0.tgz`), **НЕ** version string (`0.1.0`). Lookup `_distfiles["0.1.0"]` всегда возвращает undefined, ложно классифицируя ВСЕ versions как locally-published.
Easy mistake: первый draft prune скрипта проверял `_distfiles[v]` → dry-run показал 4597/7021 packages "защищены" (на самом деле ВСЕ proxied lodash/react/etc). Fix: `_distfiles[<tgzBase>-<v>.tgz]` где `tgzBase = name.replace(/^@[^/]+\//, '')` (strip scope для filename).
## Safe prune algorithm
```
для каждого package:
keepSet = dist-tagged versions # {latest, next, beta, ...}
others = versions keepSet, отсортированные по time[v] desc
keepSet += first (N - |keepSet|) из others # N = 10
для v в (versions keepSet):
tgzName = "<scope-stripped-name>-<v>.tgz"
if _distfiles[tgzName] undefined:
continue # locally-published, skip
if .tgz file exists: delete file
if _attachments[tgzName] exists: delete entry
если что-то изменили в _attachments:
bump _rev (`<num+1>-<random_hex>`)
atomic rewrite package.json (tmp + rename)
```
## Atomic write + _rev
`package.json` rewrite через `fs.writeFileSync(tmp); fs.renameSync(tmp, real)` — atomic on POSIX same-fs. Race window между «file gone» и «package.json updated» ничтожен.
`_rev` field в формате `<num>-<hash>` (CouchDB-style). Verdaccio проверяет его для optimistic concurrency. Bump = increment number + new random hex. Это invalidates npm client packument cache.
Дополнительная подстраховка от race: **stop verdaccio перед prune, start после** (~1 min downtime weekly). Альтернатива — atomic rewrite без stop — допустима, но cache invalidation менее clean.
## Что НЕ трогать
- `versions{}` и `time{}` — оставляем metadata in-place даже после удаления tarballs. Для proxied packages npm re-fetch'нет tgz при request; metadata лёгкая (~KB).
- `_uplinks{}` — agent-level state о fetch timestamps; не относится к individual versions.
- `readme`, `users`, `_id` — irrelevant для prune.
## Применено
[`vds-gc-cron`](../../.tasks/vds-gc-cron.md) — weekly cron Sun 03:30 MSK на VDS. Smoke 2026-05-21: 8.5G→6.8G freed, 4524 tgz deleted, 73 locally-published versions защищены (`@snollajs/*` + ~40 другие internal packages).
## Ссылки
- Verdaccio local-storage docs: https://verdaccio.org/docs/configuration#storage
- Algorithm в репо: `/opt/stacks/gc/scripts/verdaccio-prune.js` на VDS.