Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions internal/handler/npm.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

const (
npmUpstream = "https://registry.npmjs.org"
npmAbbreviatedCT = "application/vnd.npm.install-v1+json"
npmAcceptDefault = "application/vnd.npm.install-v1+json;q=1.0, application/json;q=0.8"
scopedParts = 2 // scope + name in scoped packages
)

Expand Down Expand Up @@ -71,9 +71,12 @@ func (h *NPMHandler) handlePackageMetadata(w http.ResponseWriter, r *http.Reques

upstreamURL := fmt.Sprintf("%s/%s", h.upstreamURL, url.PathEscape(packageName))

// Use abbreviated metadata when cooldown is disabled — it's much smaller
// (e.g. drizzle-orm: 4MB vs 92MB) but lacks the time map needed for cooldown.
accept := npmAbbreviatedCT
// Prefer the smaller abbreviated packument format but include application/json
// as a fallback so upstreams that reject the abbreviated type (e.g. JFrog
// Artifactory, which returns 406) can still respond with full metadata.
// When cooldown is enabled we must use full metadata exclusively because the
// abbreviated format omits the "time" map required for version age filtering.
accept := npmAcceptDefault
if h.proxy.Cooldown != nil && h.proxy.Cooldown.Enabled() {
accept = contentTypeJSON
}
Expand Down
12 changes: 6 additions & 6 deletions internal/handler/npm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ func TestNPMHandlerUsesAbbreviatedMetadata(t *testing.T) {
}))
defer upstream.Close()

t.Run("no cooldown uses abbreviated metadata", func(t *testing.T) {
t.Run("no cooldown uses combined accept header", func(t *testing.T) {
h := &NPMHandler{
proxy: testProxy(),
upstreamURL: upstream.URL,
Expand All @@ -407,12 +407,12 @@ func TestNPMHandlerUsesAbbreviatedMetadata(t *testing.T) {
w := httptest.NewRecorder()
h.handlePackageMetadata(w, req)

if gotAccept != npmAbbreviatedCT {
t.Errorf("Accept = %q, want abbreviated metadata header", gotAccept)
if gotAccept != npmAcceptDefault {
t.Errorf("Accept = %q, want %q", gotAccept, npmAcceptDefault)
}
})

t.Run("cooldown enabled uses full metadata", func(t *testing.T) {
t.Run("cooldown enabled uses full metadata only", func(t *testing.T) {
proxy := testProxy()
proxy.Cooldown = &cooldown.Config{Default: "3d"}

Expand All @@ -426,8 +426,8 @@ func TestNPMHandlerUsesAbbreviatedMetadata(t *testing.T) {
w := httptest.NewRecorder()
h.handlePackageMetadata(w, req)

if gotAccept == npmAbbreviatedCT {
t.Error("cooldown enabled should use full metadata, not abbreviated")
if gotAccept != contentTypeJSON {
t.Errorf("Accept = %q, want %q (cooldown requires full metadata)", gotAccept, contentTypeJSON)
}
})
}
Expand Down