A private registry is only useful if the things that need packages can find it.
Rather than make every module hand-configure a URL and a token, Celilo’s
npm-cache-node will publish an npm_registry capability. A module that needs
npm just declares requires: npm_registry, and the framework injects the
resolved registry URL and auth into its hook context — the same
capability-discovery pattern Celilo already uses for DNS, firewalls, and web
ingress.
What the capability carries
The capability exposes both a url_external (for consumers reaching the cache
across the firewall via NAT) and a url_internal (for consumers already on the
LAN, avoiding a hairpin), so each declares by vantage and gets the right one. It
also advertises allowed_publish_scopes — the npm scopes the node accepts
publishes for — and whether read access needs a token. Split-horizon DNS backs
the two URLs with npm.<fqdn> and npm-internal.<fqdn> names.
Tokens on demand
The capability provides issue_publish_token and revoke_publish_token
functions, so a consumer can mint a short-lived, scope-limited publish token at
deploy time and have it revoked when the module is uninstalled. A CI runner, for
example, gets a token scoped to @celilo written into its .npmrc — it never
needs standing npm credentials of its own.
Scopes that extend themselves
If a consumer declares it needs to publish a scope the node doesn’t yet accept,
a managed_scope ensure fires the cross-module config interview to add it —
no manual edit to the cache node’s config. The runner declaring
requires: npm_registry, scope: "@celilo" is enough to teach the cache to
accept @celilo publishes the first time it deploys.