diff --git a/routers/api/packages/npm/api.go b/routers/api/packages/npm/api.go index ffde98b3faf..ec72a2b69f4 100644 --- a/routers/api/packages/npm/api.go +++ b/routers/api/packages/npm/api.go @@ -9,6 +9,7 @@ import ( "fmt" "net/url" "sort" + "time" packages_model "gitea.dev/models/packages" npm_module "gitea.dev/modules/packages/npm" @@ -22,8 +23,14 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac versions := make(map[string]*npm_module.PackageMetadataVersion) distTags := make(map[string]string) + times := make(map[string]time.Time) + firstPublished, lastPublished := pds[0].Version.CreatedUnix, pds[0].Version.CreatedUnix for _, pd := range pds { - versions[pd.SemVer.String()] = createPackageMetadataVersion(registryURL, pd) + semVer := pd.SemVer.String() + versions[semVer] = createPackageMetadataVersion(registryURL, pd) + times[semVer] = pd.Version.CreatedUnix.AsTimeInLocation(time.UTC) + firstPublished = min(firstPublished, pd.Version.CreatedUnix) + lastPublished = max(lastPublished, pd.Version.CreatedUnix) for _, pvp := range pd.VersionProperties { if pvp.Name == npm_module.TagProperty { @@ -32,6 +39,10 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac } } + // npm derives both from the versions currently served, so a deletion moves them + times["created"] = firstPublished.AsTimeInLocation(time.UTC) + times["modified"] = lastPublished.AsTimeInLocation(time.UTC) + latest := pds[len(pds)-1] metadata := latest.Metadata.(*npm_module.Metadata) @@ -42,7 +53,10 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac DistTags: distTags, Description: metadata.Description, Readme: metadata.Readme, + Maintainers: []npm_module.User{{Name: latest.Owner.Name}}, + Time: times, Homepage: metadata.ProjectURL, + Keywords: metadata.Keywords, Author: npm_module.User{Name: metadata.Author}, License: metadata.License, Versions: versions, @@ -61,8 +75,10 @@ func createPackageMetadataVersion(registryURL string, pd *packages_model.Package Version: pd.Version.Version, Description: metadata.Description, Author: npm_module.User{Name: metadata.Author}, + Maintainers: []npm_module.User{{Name: pd.Owner.Name}}, Homepage: metadata.ProjectURL, License: metadata.License, + Keywords: metadata.Keywords, Dependencies: metadata.Dependencies, BundleDependencies: metadata.BundleDependencies, DevDependencies: metadata.DevelopmentDependencies, diff --git a/routers/api/packages/npm/api_test.go b/routers/api/packages/npm/api_test.go new file mode 100644 index 00000000000..ab3a5821453 --- /dev/null +++ b/routers/api/packages/npm/api_test.go @@ -0,0 +1,46 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package npm + +import ( + "testing" + "time" + + packages_model "gitea.dev/models/packages" + user_model "gitea.dev/models/user" + npm_module "gitea.dev/modules/packages/npm" + "gitea.dev/modules/timeutil" + + "github.com/hashicorp/go-version" + "github.com/stretchr/testify/assert" +) + +func TestCreatePackageMetadataResponse(t *testing.T) { + descriptor := func(v string, publishedUnix int64) *packages_model.PackageDescriptor { + return &packages_model.PackageDescriptor{ + Package: &packages_model.Package{Name: "test"}, + Owner: &user_model.User{Name: "alice"}, + Version: &packages_model.PackageVersion{Version: v, CreatedUnix: timeutil.TimeStamp(publishedUnix)}, + SemVer: version.Must(version.NewVersion(v)), + Metadata: &npm_module.Metadata{Keywords: []string{"gitea"}}, + Files: []*packages_model.PackageFileDescriptor{{File: &packages_model.PackageFile{}, Blob: &packages_model.PackageBlob{}}}, + } + } + + result := createPackageMetadataResponse("https://gitea.dev/api/packages/alice/npm", []*packages_model.PackageDescriptor{ + descriptor("1.1.0", 1000), + descriptor("1.0.0", 2000), + }) + + assert.Equal(t, map[string]time.Time{ + "1.0.0": time.Unix(2000, 0).UTC(), + "1.1.0": time.Unix(1000, 0).UTC(), + "created": time.Unix(1000, 0).UTC(), + "modified": time.Unix(2000, 0).UTC(), + }, result.Time) + assert.Equal(t, []npm_module.User{{Name: "alice"}}, result.Maintainers) + assert.Equal(t, []string{"gitea"}, result.Keywords) + assert.Equal(t, []string{"gitea"}, result.Versions["1.0.0"].Keywords) + assert.Equal(t, []npm_module.User{{Name: "alice"}}, result.Versions["1.0.0"].Maintainers) +}