Skip to content

feat(npm): resolve versions over HTTP, groundwork for embedding aube - #11147

Merged
jdx merged 1 commit into
mainfrom
npm-http-registry
Jul 20, 2026
Merged

jdx merged 1 commit into
mainfrom
npm-http-registry

Conversation

@jdx

@jdx jdx commented Jul 20, 2026 •

Copy link
Copy Markdown
Owner

Summary

Version metadata queries for the npm: backend (mise ls-remote npm:*, resolving latest) now hit the npm registry directly over HTTP through a built-in packument client, instead of shelling out to npm view. This means node/npm no longer need to be installed to resolve npm: tool versions — only to actually install packages.

User-level ~/.npmrc (or NPM_CONFIG_USERCONFIG) and NPM_CONFIG_* environment variables are honored for the default registry, scoped registries (@scope:registry), and auth (_authToken / _auth / username+_password), matching what npm view resolved before. The full (non-corgi) packument route is used so the time map is available for minimum_release_age / release-date filtering.

Direction: embedding aube

This is step one of a larger plan to embed aube's library crates in mise — replacing not just npm view but eventually the aube/npm install subprocess for the npm backend.

The npmrc/packument logic here is ported inline from aube's aube-registry crate because the published crate currently can't be a dependency: it declares MSRV 1.93 (mise is pinned to 1.91 by distro packaging, and cargo's MSRV-aware resolver silently falls back to an ancient 1.0.0-beta.2), and its workspace features would leak global build side effects into mise via feature unification (reqwest/hickory-dns flips the default DNS resolver for every client in the binary, flate2/zlib-ng forces a cmake/C build onto cross targets, reqwest/rustls adds a second TLS stack).

aubepkg/aube#1068 fixes all of that upstream: MSRV 1.91 + backend-agnostic TLS/DNS/zlib features selected at the leaves. Once that lands and releases, the follow-up here is to replace this inline module with a real aube-registry = { version = "...", default-features = false, features = ["native-tls"] } dependency, and then evaluate embedding resolver/store/linker for installs.

Escape hatch

A new npm.use_npm_view setting (env: MISE_NPM_USE_NPM_VIEW) restores the previous npm view code path for environments that rely on npm-only configuration the built-in client doesn't model: cafile, client certificates, or an auth token helper. Proxies work either way via the standard HTTP(S)_PROXY env vars.

Why

  • Fixes stale/failed npm: version resolution when npm isn't installed (#10563)
  • Removes the npm dependency edge from version queries in get_dependencies (npm is now only pulled in when it may be the installer, or when use_npm_view is set)
  • Groundwork toward node-free npm: lockfile operations and, with the aube embedding, node-free installs

Behavior parity

Verified the HTTP path produces byte-identical ls-remote output (same versions, same semver-ascending order) vs. the npm view path for npm:prettier, npm:@angular/cli (582 versions, incl. backported patch lines), and npm:left-pad. Registry versions are strictly semver, so the packument's publish-order document is sorted semver-ascending to match what npm view versions returned (prefix resolution like npm:@angular/cli@19 depends on it).

Tests

  • New unit tests in src/backend/npm_registry.rs covering npmrc parsing (comments, line continuation, ${VAR} expansion, quote stripping), scoped registries, env-var precedence/translation, nerf-dart auth lookup (default-port collapse, prefix fallback, base64 username/password, bare tokens), and packument version ordering + missing-field tolerance.
  • test_backend_missing_deps: now asserts version listing works with npm absent; legacy warning path re-checked under MISE_NPM_USE_NPM_VIEW=1.
  • test_npm_shim_recursion_system_dir: pinned to MISE_NPM_USE_NPM_VIEW=1 since it specifically guards the npm view shim-recursion path.
  • Full local test_npm* suite passing.

🤖 Generated with Claude Code

…view

Version metadata queries (ls-remote, latest resolution) now hit the npm
registry directly over HTTP via a built-in packument client, so node/npm
no longer need to be installed to resolve npm: tool versions. User-level
.npmrc / NPM_CONFIG_* registry, scoped-registry, and auth settings are
honored; the config/packument logic is ported from jdx/aube's
aube-registry crate, trimmed to read-only metadata fetches.

The new npm.use_npm_view setting restores the old `npm view` code path for
setups relying on npm-only config (cafile, client certs, token helpers).

Fixes stale/failed npm: version resolution when npm is missing
(#10563) and removes the npm dependency edge from version queries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

npm version metadata resolution now defaults to direct registry HTTP requests, with npm CLI lookup retained behind use_npm_view. Registry configuration, authentication, packument parsing, backend dependency logic, tests, schema, settings, and documentation were updated.

Changes

npm version resolution

Layer / File(s) Summary
Registry client and configuration
settings.toml, schema/mise.json, src/backend/npm_registry.rs
Adds the use_npm_view setting and a registry client that reads npm configuration, resolves scoped registries, applies authentication, fetches packuments, and extracts version metadata.
Backend version and dependency integration
src/backend/mod.rs, src/backend/npm.rs
Adds cached packument fetching, switches between registry and npm view resolution, derives latest versions from registry metadata, and conditionally includes npm dependencies.
Behavior validation and documentation
docs/dev-tools/backends/npm.md, e2e/backend/test_backend_missing_deps, e2e/backend/test_npm_shim_recursion_system_dir
Documents registry and legacy lookup behavior and updates tests for missing npm, legacy mode, and shim recursion.©

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant NPMBackend
  participant NPM_REGISTRY_CONFIG
  participant npmRegistry
  User->>NPMBackend: Request npm versions
  NPMBackend->>NPMBackend: Check use_npm_view
  NPMBackend->>NPM_REGISTRY_CONFIG: Fetch packument
  NPM_REGISTRY_CONFIG->>npmRegistry: HTTP request
  npmRegistry-->>NPM_REGISTRY_CONFIG: Packument response
  NPM_REGISTRY_CONFIG-->>NPMBackend: Version metadata
  NPMBackend-->>User: Available versions
Loading

Possibly related PRs

  • jdx/mise#11146: Also changes the npm backend’s remote version listing path and intersects with npm CLI-based lookup.

Poem

I’m a bunny fetching versions with care,
From registry hops through the HTTP air.
No npm? No worry—I’ll still find the trail,
Unless legacy mode sends me to npm view’s tale.
Packuments bloom, and releases align! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title captures the main change: resolving npm versions over HTTP; the extra phrase is secondary but not misleading.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a1b8b90. Configure here.

}
if suffix.eq_ignore_ascii_case("registry") {
out.push(("registry".to_string(), value.clone()));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bare npm auth env ignored

Medium Severity

The built-in registry client’s npm_config_env_entries helper maps registry URLs and //host/:_authToken-style keys from the environment, but not bare _authToken or _auth suffixes (for example npm_config__authToken / NPM_CONFIG__AUTH_TOKEN). Those values still work with npm view, so private-registry auth that relies on a global token env var can succeed in legacy mode and fail on the default HTTP path.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a1b8b90. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 05c1ed5. npm_config_env_entries now translates bare _authToken/_auth env vars (both npm_config__authToken and NPM_CONFIG__AUTH_TOKEN spellings) to the default-registry auth, matching how apply already handled them from .npmrc. Added test_env_bare_auth_token + test_env_bare_auth_overrides_npmrc.

This reply was generated by an AI coding assistant.

pub fn registry_for(&self, name: &str) -> &str {
package_scope(name)
.and_then(|scope| self.scoped_registries.get(scope))
.unwrap_or(&self.registry)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scoped registry case mismatch

Low Severity

Scoped registry overrides are stored under lowercased scope keys, but registry_for looks up the scope taken verbatim from the package name. A tool like npm:@MyOrg/pkg with @myorg:registry in config resolves to the public default registry instead of the scoped one, unlike npm’s case-insensitive scope matching.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a1b8b90. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 05c1ed5. registry_for now lowercases the package scope before the lookup (keys are stored lowercased), so npm:@MyOrg/pkg resolves the @myorg:registry override. Added test_scoped_registry_lookup_is_case_insensitive.

This reply was generated by an AI coding assistant.

Comment thread src/backend/npm.rs
Ok(Arc::new(packument))
})
.await
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Packument never refreshes

Medium Severity

The npm backend caches the packument in a OnceCell for the lifetime of the backend instance. When the remote version cache expires or is refreshed, _list_remote_versions runs again but still reuses that first packument instead of hitting the registry, so version lists and dist-tag resolution can stay stale until a new process starts.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a1b8b90. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 05c1ed5. Removed the process-lifetime packument OnceCell. Both _list_remote_versions and latest_stable_version are already wrapped in their own TTL disk caches by the backend layer, so the memo was a redundant third layer that could shadow those TTLs with stale data — each now fetches directly and the disk caches handle dedup across invocations.

This reply was generated by an AI coding assistant.

@greptile-apps

greptile-apps Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR replaces the npm view shell-out for version metadata with a built-in npm registry HTTP client (npm_registry.rs), so node/npm no longer need to be installed to run mise ls-remote npm:* or resolve latest. A new npm.use_npm_view setting (env: MISE_NPM_USE_NPM_VIEW) preserves the old code path as an escape hatch for environments using npm-only TLS config or token helpers.

  • New src/backend/npm_registry.rs: ~680-line packument client handling .npmrc parsing (comments, line continuation, ${VAR} expansion, quote stripping), scoped registries, nerf-dart auth lookup (prefix fallback, base64 username/password, bearer tokens), and NPM_CONFIG_* env-var translation.
  • src/backend/npm.rs: _list_remote_versions and latest_stable_version dispatch to the HTTP path by default, falling back to the legacy npm view methods when use_npm_view is set; get_dependencies now omits npm when it is neither the installer nor the version-query tool.
  • Tests: Unit tests cover all npmrc parsing edge cases; e2e tests updated to assert version listing works without npm installed and that the legacy warning path is preserved under the flag.

Confidence Score: 4/5

The change is safe to merge. The new HTTP path is well-tested and the legacy npm view path is preserved intact behind a flag.

The implementation is thorough and the unit tests are comprehensive. The two gaps — bare NPM_CONFIG__AUTHTOKEN env vars not being extracted, and case-sensitive ${VAR} expansion on Windows — are edge cases that would surface only in specific user configurations, not in the default or common path.

src/backend/npm_registry.rs — the npm_config_env_entries function (lines 722-756) and substitute_env (lines 695-715) are the spots with the identified gaps.

Important Files Changed

Filename Overview
src/backend/npm_registry.rs New 682-line module implementing an npm registry HTTP client; well-structured with comprehensive unit tests. Two minor gaps: bare _authToken/_auth from NPM_CONFIG_* env vars are not extracted, and env-var expansion is case-sensitive (breaking on Windows).
src/backend/npm.rs Cleanly refactored to dispatch between HTTP packument path and legacy npm view path; packument is cached per-instance via OnceCell; get_dependencies logic now correctly omits npm for non-view, non-npm-pm cases.
e2e/backend/test_backend_missing_deps Tests updated to assert HTTP path works without npm installed, and legacy use_npm_view warning path is correctly gated behind the new env var.
e2e/backend/test_npm_shim_recursion_system_dir Correctly pinned to MISE_NPM_USE_NPM_VIEW=1 so the shim-recursion guard test continues to cover the code path it was written for.
settings.toml New npm.use_npm_view setting correctly defined with type Bool, default false, env var MISE_NPM_USE_NPM_VIEW, and clear documentation.
schema/mise.json JSON schema extended with use_npm_view boolean entry under npm; matches settings.toml definition.
docs/dev-tools/backends/npm.md Documentation accurately reflects the new HTTP-first approach, supported config sources, and the use_npm_view escape hatch.

Comments Outside Diff (2)

  1. src/backend/npm_registry.rs, line 722-756 (link)

    P2 Bare _authToken/_auth not extracted from NPM_CONFIG_* env vars

    npm_config_env_entries only translates registry, @scope:registry, and URI-prefixed auth keys (e.g. npm_config_//registry.example.com/:_authToken). The bare forms — NPM_CONFIG__AUTHTOKEN and NPM_CONFIG__AUTH (without a URI prefix) — are silently ignored, even though the PR description and docs claim that "NPM_CONFIG_* environment variables are honored for … auth (_authToken / _auth …)". Any user relying on these env vars (instead of .npmrc or per-URI env vars) will get unauthenticated requests and a confusing 401 from the registry.

    Fix in Claude Code

  2. src/backend/npm_registry.rs, line 695-715 (link)

    P2 ${VAR} expansion is case-sensitive; broken on Windows

    substitute_env compares variable names with *k == var_name (exact match). On Windows, environment variable names are case-insensitive, so .npmrc entries like //registry.example.com/:_authToken=${npm_token} will fail to expand if the actual env var is NPM_TOKEN. This is unlikely to affect most users but is a subtle platform difference worth documenting or addressing.

    Fix in Claude Code

Fix All in Claude Code

Reviews (1): Last reviewed commit: "feat(npm): resolve versions over HTTP in..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/backend/npm.rs (1)

562-571: 🚀 Performance & Scalability | 🔵 Trivial

Note the bandwidth cost of full packuments for large packages.

The default path fetches the full packument (rather than the abbreviated vnd.npm.install-v1+json corgi) because time is required — a deliberate and correct choice. For very large packages the full document can be tens of MB, versus the tiny npm view <pkg> versions time projection the legacy path returned. This is bounded by fetch_remote_versions_cache and the per-process OnceCell, so it's fine, but you may want to keep an eye on cold-fetch latency/bandwidth for ls-remote on heavyweight packages, or consider skipping the time fetch when no release-age filtering is configured.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/npm.rs` around lines 562 - 571, Review the fetch_packument path
and monitor cold-fetch latency and bandwidth for large packages, while
preserving the full packument request because release-age filtering requires
time data. If the surrounding configuration exposes whether release-age
filtering is enabled, avoid fetching time/full packuments when it is disabled;
otherwise retain the current behavior and caching through
fetch_remote_versions_cache and the per-process OnceCell.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/backend/npm.rs`:
- Around line 562-571: Review the fetch_packument path and monitor cold-fetch
latency and bandwidth for large packages, while preserving the full packument
request because release-age filtering requires time data. If the surrounding
configuration exposes whether release-age filtering is enabled, avoid fetching
time/full packuments when it is disabled; otherwise retain the current behavior
and caching through fetch_remote_versions_cache and the per-process OnceCell.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 4dcb58f2-9ef7-471d-9301-0f63cec12f0f

📥 Commits

Reviewing files that changed from the base of the PR and between e8bc49e and a1b8b90.

📒 Files selected for processing (8)
  • docs/dev-tools/backends/npm.md
  • e2e/backend/test_backend_missing_deps
  • e2e/backend/test_npm_shim_recursion_system_dir
  • schema/mise.json
  • settings.toml
  • src/backend/mod.rs
  • src/backend/npm.rs
  • src/backend/npm_registry.rs

@github-actions

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.11 x -- echo 18.6 ± 0.8 16.9 25.1 1.00
mise x -- echo 20.0 ± 1.2 18.2 34.5 1.07 ± 0.08

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.11 env 17.5 ± 0.9 15.9 22.8 1.00
mise env 18.8 ± 0.9 17.1 23.6 1.07 ± 0.08

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.11 hook-env 18.3 ± 0.9 16.8 22.7 1.00
mise hook-env 19.6 ± 0.9 17.8 23.9 1.07 ± 0.07

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.11 ls 15.6 ± 0.8 14.0 19.0 1.00
mise ls 16.9 ± 0.9 15.3 20.9 1.09 ± 0.08

xtasks/test/perf

Command mise-2026.7.11 mise Variance
install (cached) 154ms 163ms -5%
ls (cached) 57ms 59ms -3%
bin-paths (cached) 60ms 62ms -3%
task-ls (cached) 123ms 127ms -3%

@jdx jdx changed the title feat(npm): resolve versions over HTTP instead of shelling out to npm view feat(npm): resolve versions over HTTP, groundwork for embedding aube Jul 20, 2026
@jdx
jdx merged commit 7d039ed into main Jul 20, 2026
35 checks passed
@jdx
jdx deleted the npm-http-registry branch July 20, 2026 23:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant