npmproxy

package
v0.2.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package npmproxy implements proxies.CacheProxy for the npm ecosystem.

It is a pull-through cache for the two request shapes an `npm install` makes, which are cached very differently:

GET /<pkg>                     packument (metadata)  — MUTABLE
GET /<pkg>/-/<pkg>-<ver>.tgz   package tarball       — IMMUTABLE

WHAT IS CACHED AND WHY

Tarballs are the bytes: a cold `npm ci` on a mid-sized project pulls hundreds of megabytes of them, and a published (name, version) tarball is never re-published with different content — npm's registry forbids it and every lockfile in the world pins its integrity hash. Those are cached permanently and never revalidated.

Packuments are NOT immutable. A packument gains a version every time anyone publishes, and `dist-tags.latest` moves. Caching one forever would pin every job on the node to whatever versions existed when the daemon started — a job asking for a version published an hour ago would get ETARGET. So packuments are cached with a SHORT TTL (default 5 minutes) and then revalidated with a conditional GET. npm's registry serves strong ETags, so the steady-state cost of a stale-but-unchanged packument is one 304, not a re-download.

WHY THE PACKUMENT IS REWRITTEN

Every packument carries ABSOLUTE tarball URLs (dist.tarball) pointing at the upstream registry. Left alone, npm would fetch metadata from the cache and then every byte straight from registry.npmjs.org — the cache would hold only the cheap part. dist.tarball is therefore rewritten to point at this proxy's artifact route. dist.integrity/dist.shasum are untouched and still verified by npm against the bytes we serve, so the rewrite cannot smuggle in a different tarball.

Index

Constants

View Source
const (
	// DefaultUpstream is the public npm registry.
	DefaultUpstream = "https://registry.npmjs.org"
	// DefaultPackumentTTL is how long a cached packument is served before
	// revalidation. Short by design: a dependency published minutes ago
	// must not be invisible to the node for an hour.
	DefaultPackumentTTL = 5 * time.Minute
)

Defaults. Kept here rather than in the config package so the proxy is usable (and testable) standalone.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// CacheDir is the on-disk cache root (e.g. <data>/cache/npm).
	CacheDir string
	// Upstream is the registry to pull through to.
	Upstream string
	// ListenAddr is the address to bind and advertise (e.g. "10.88.0.1:8084").
	ListenAddr string
	// PackumentTTL is the revalidation interval for packuments. Zero takes
	// DefaultPackumentTTL; negative means "revalidate every request".
	PackumentTTL time.Duration
	// MaxBytes is the cache disk budget. Zero takes pkgcache.DefaultMaxBytes.
	MaxBytes int64
	// AllowedHosts extends the artifact-fetch allowlist. The upstream's own
	// host is always allowed.
	AllowedHosts []string
	// Cleanup wipes the cache on Stop. Default false.
	Cleanup bool
	Log     *slog.Logger
}

Config for the npm caching proxy.

type Proxy

type Proxy struct {
	// contains filtered or unexported fields
}

Proxy is the npm registry caching proxy.

func New

func New(cfg Config) (*Proxy, error)

New creates an npm caching proxy. Call Start() to begin serving.

func (*Proxy) Addr

func (p *Proxy) Addr() string

Addr returns the bound address.

func (*Proxy) EnvVars

func (p *Proxy) EnvVars() []string

EnvVars returns the environment variables to inject into job containers.

  • npm_config_registry is npm's own config channel and needs no .npmrc. pnpm reads it too, and Yarn Classic (v1) picks it up through its npm config compatibility layer.
  • YARN_NPM_REGISTRY_SERVER is what Yarn Berry (v2+) reads instead; it ignores npm_config_* entirely.

NOT covered, and documented as such: a repo-committed .npmrc or .yarnrc.yml with an explicit `registry`, which wins over the environment; private/scoped registries with auth (this proxy forwards no credentials); and Yarn Berry's offline mirror / zero-installs, which bypasses the network altogether — all of those simply keep working, uncached.

func (*Proxy) Healthy

func (p *Proxy) Healthy() bool

Healthy reports whether the proxy answers its own health probe.

func (*Proxy) Name

func (p *Proxy) Name() string

Name returns the proxy name for logging.

func (*Proxy) Start

func (p *Proxy) Start() error

Start begins serving. Returns after the listener is bound.

func (*Proxy) Stop

func (p *Proxy) Stop() error

Stop shuts the proxy down.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL