Skip to content

Registry 客户端

Registry 客户端是 NPM Skills 的核心组件,提供与 NPM 注册表交互的所有功能。

组件架构

Registry 持有一份 OptionsOptions 内部用 sync.Once 惰性构建并缓存 *http.Client,从而在多次请求间复用底层 TCP 连接池:

请求生命周期

GetPackageInformation 为例,一次调用经历如下阶段——context 贯穿始终,可随时取消或超时:

创建客户端

NewRegistry(options ...*Options) *Registry

创建一个新的 Registry 客户端实例。

参数:

  • options - 可选的配置选项

示例:

go
// 使用默认配置
client := registry.NewRegistry()

// 使用自定义配置
options := registry.NewOptions().
    SetRegistryURL("https://registry.npmjs.org").
    SetProxy("http://proxy.example.com:8080")
client := registry.NewRegistry(options)

核心方法

GetPackageInformation(ctx context.Context, packageName string) (*models.Package, error)

获取指定 NPM 包的详细信息。

参数:

  • ctx - 上下文,用于取消和超时控制
  • packageName - 要查询的包名称

返回值:

  • *models.Package - 完整的包信息
  • error - 如果请求失败则返回错误

示例:

go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

pkg, err := client.GetPackageInformation(ctx, "lodash")
if err != nil {
    return fmt.Errorf("获取包信息失败: %w", err)
}

// 访问包数据
fmt.Printf("名称: %s\n", pkg.Name)
fmt.Printf("最新版本: %s\n", pkg.DistTags["latest"])
fmt.Printf("作者: %s\n", pkg.Author.Name)

// 访问特定版本
if version, exists := pkg.Versions["4.17.21"]; exists {
    fmt.Printf("版本 4.17.21 依赖: %+v\n", version.Dependencies)
}

GetRegistryInformation(ctx context.Context) (*models.RegistryInformation, error)

获取 NPM 注册表的状态和元数据信息。

参数:

  • ctx - 上下文,用于取消和超时控制

返回值:

  • *models.RegistryInformation - 注册表状态信息
  • error - 如果请求失败则返回错误

示例:

go
info, err := client.GetRegistryInformation(ctx)
if err != nil {
    return fmt.Errorf("获取注册表信息失败: %w", err)
}

fmt.Printf("注册表: %s\n", info.DbName)
fmt.Printf("包总数: %d\n", info.DocCount)
fmt.Printf("数据库大小: %d 字节\n", info.DataSize)
fmt.Printf("磁盘使用: %d 字节\n", info.DiskSize)

SearchPackages(ctx context.Context, query string, limit int) (*models.SearchResult, error)

搜索 NPM 包。

参数:

  • ctx - 上下文
  • query - 搜索关键字
  • limit - 返回结果数量限制,默认为 20

返回值:

  • *models.SearchResult - 搜索结果
  • error - 如果请求失败则返回错误

示例:

go
result, err := client.SearchPackages(ctx, "react", 10)
if err != nil {
    return fmt.Errorf("搜索失败: %w", err)
}

fmt.Printf("找到 %d 个结果\n", result.Total)
for _, obj := range result.Objects {
    pkg := obj.Package
    fmt.Printf("包名: %s\n", pkg.Name)
    fmt.Printf("版本: %s\n", pkg.Version)
    fmt.Printf("描述: %s\n", pkg.Description)
    fmt.Printf("评分: %.2f\n", obj.Score.Final)
    fmt.Println("---")
}

GetPackageVersion(ctx context.Context, packageName, version string) (*models.Version, error)

获取指定包的特定版本信息。

参数:

  • ctx - 上下文
  • packageName - 包名称
  • version - 版本号或标签(如 "1.0.0" 或 "latest")

返回值:

  • *models.Version - 版本详细信息
  • error - 如果请求失败则返回错误

示例:

go
version, err := client.GetPackageVersion(ctx, "react", "18.2.0")
if err != nil {
    return fmt.Errorf("获取版本信息失败: %w", err)
}

fmt.Printf("版本: %s\n", version.Version)
fmt.Printf("描述: %s\n", version.Description)
fmt.Printf("依赖: %+v\n", version.Dependencies)
fmt.Printf("开发依赖: %+v\n", version.DevDependencies)

GetDownloadStats(ctx context.Context, packageName, period string) (*models.DownloadStats, error)

获取指定包的下载统计信息。

参数:

  • ctx - 上下文
  • packageName - 包名称
  • period - 统计周期("last-day", "last-week", "last-month")

返回值:

  • *models.DownloadStats - 下载统计信息
  • error - 如果请求失败则返回错误

示例:

go
stats, err := client.GetDownloadStats(ctx, "react", "last-week")
if err != nil {
    return fmt.Errorf("获取下载统计失败: %w", err)
}

fmt.Printf("包: %s\n", stats.Package)
fmt.Printf("下载次数: %d\n", stats.Downloads)
fmt.Printf("统计周期: %s%s\n", stats.Start, stats.End)

DownloadTarball(ctx context.Context, packageName, version, destPath string) error

下载指定 NPM 包的 tarball 文件到本地路径。

参数:

  • ctx - 上下文,用于取消和超时控制
  • packageName - 要下载的包名称,例如 "react"、"lodash" 等
  • version - 要下载的版本号,例如 "18.0.0"、"latest" 等
  • destPath - 目标文件保存路径,例如 "./downloads/react-18.0.0.tgz"

返回值:

  • error - 如果下载失败则返回错误

示例:

go
ctx := context.Background()

// 下载 react 18.0.0 版本到本地文件
err := client.DownloadTarball(ctx, "react", "18.0.0", "./react.tgz")
if err != nil {
    return fmt.Errorf("下载 tarball 失败: %w", err)
}

// 使用 latest 下载最新版本
err = client.DownloadTarball(ctx, "vue", "latest", "./vue.tgz")
if err != nil {
    return fmt.Errorf("下载 tarball 失败: %w", err)
}

// 验证下载的文件
info, err := os.Stat("./react.tgz")
if err != nil {
    return err
}
fmt.Printf("文件大小: %d bytes\n", info.Size())

使用 CNPM 镜像下载示例:

go
// 使用国内镜像下载,速度更快
options := registry.NewOptions().SetRegistryURL(registry.RegistryUrlCnpm)
client := registry.NewRegistry(options)

err := client.DownloadTarball(ctx, "axios", "1.0.0", "/tmp/axios.tgz")
if err != nil {
    log.Fatalf("下载失败: %v", err)
}

fmt.Println("下载成功!")

GetOptions() *Options

返回当前注册表客户端的配置选项。

返回值:

  • *Options - 当前配置选项

方法索引(76 个)

下面按功能域列出全部 76 个方法。ctx 均为 context.Context;标注 🔒 的写操作需要服务端配置有效 token(Options.Token)。

只读请求直接走镜像/代理发往 Registry;写操作则在请求头注入 Authorization: Bearer <token>,由 Registry 鉴权后写入:

包元数据(只读)

方法签名说明
GetPackageInformation(ctx, name) → *models.Package, error完整包元数据(可能很大,10MB+)
GetPackageInformationSummary(ctx, name) → *models.Package, error轻量摘要(推荐)
GetAbbreviatedPackageInformation(ctx, name) → *models.Package, error缩写元数据
GetPackageVersion(ctx, name, version) → *models.Version, error特定版本元数据
GetPackageVersions(ctx, name) → []string, error所有版本号
GetPackageVersionCount(ctx, name) → int, error版本总数
GetPackageLatestVersion(ctx, name) → string, error最新版本号(仅查 dist-tags)

dist-tags

方法签名说明
GetDistTags(ctx, name) → map[string]string, error全部 dist-tags
GetDistTagsAbbreviated(ctx, name) → map[string]string, error缩写形式 dist-tags
GetDistTag(ctx, name, tag) → string, error单个 tag 指向的版本
SetDistTag 🔒(ctx, name, tag, version) → error设置单个 dist-tag
SetDistTags 🔒(ctx, name, tags) → error批量设置 dist-tags
DeleteDistTag 🔒(ctx, name, tag) → error删除 dist-tag

搜索

方法签名说明
SearchPackages(ctx, query, limit) → *models.SearchResult, error关键字搜索(分页)
SearchPackagesWithOptions(ctx, query, opts SearchOptions) → *models.SearchResult, error加权 / 偏移等高级搜索

下载统计(始终查 api.npmjs.org

方法签名说明
GetDownloadStats(ctx, name, period) → *models.DownloadStats, error区间下载总量
GetDownloadStatsByDateRange(ctx, name, start, end) → *models.DownloadStats, error自定义日期区间
GetDownloadRangeStats(ctx, name, period) → *models.DownloadRangeStats, error每日下载趋势
GetDownloadRangeStatsByDateRange(ctx, name, start, end) → *models.DownloadRangeStats, error自定义区间每日趋势
GetBulkDownloadStats(ctx, names []string, period) → map[string]*models.DownloadStats, error批量包下载总量
GetBulkDownloadStatsByDateRange(ctx, names, start, end) → map[string]*models.DownloadStats, error批量自定义区间
GetBulkDownloadRangeStats(ctx, names, period) → map[string]*models.DownloadRangeStats, error批量每日趋势
GetBulkDownloadRangeStatsByDateRange(ctx, names, start, end) → map[string]*models.DownloadRangeStats, error批量自定义区间每日趋势

下载 tarball

方法签名说明
DownloadTarball(ctx, name, version, destPath) → error下载 tarball 到本地路径

安全审计(只读)

方法签名说明
QuickAudit(ctx, payload *models.QuickAuditRequest) → *models.QuickAuditResult, error快速审计(name→version)
BulkAudit(ctx, advisories map[string][]string) → map[string][]models.Advisory, error批量审计
GetAdvisory(ctx, advisoryID int) → *models.Advisory, error按 ID 查公告
ListAdvisories(ctx, opts models.AdvisoryListOptions) → []models.Advisory, error公告列表

Stars(只读)

方法签名说明
GetStarredByPackage(ctx, name) → []string, errorstar 了某包的用户
GetStarredByUser(ctx, username) → []string, error某用户 star 的包
StarPackage 🔒(ctx, name) → errorstar 包
UnstarPackage 🔒(ctx, name) → errorunstar 包

访问控制与协作者

方法签名说明
GetPackageAccess 🔒(ctx, name) → *models.PackageAccess, error包访问设置
SetPackageAccess 🔒(ctx, name, access *models.PackageAccessUpdate) → error更新包访问设置
GrantAccess 🔒(ctx, name, user, permission) → error授予协作者权限
RevokeAccess 🔒(ctx, name, user) → error移除协作者
ListCollaborators 🔒(ctx, name) → []models.Collaborator, error协作者列表

发布与弃用

方法签名说明
PublishPackage 🔒(ctx, pkg *models.Package) → error发布包
PublishPackageFromTarball 🔒(ctx, name, version string, tarball []byte, meta *models.PublishMetadata) → error从 tarball 发布
DeprecateVersion 🔒(ctx, name, version, message) → error弃用某版本
UnpublishPackage 🔒(ctx, name) → error取消发布整个包(危险)
UnpublishPackageVersion 🔒(ctx, name, version) → error取消发布某版本

Token 管理(需 token)

方法签名说明
ListTokens(ctx) → []models.Token, errortoken 列表
GetToken(ctx, tokenID) → *models.Token, error单个 token 详情
CreateToken 🔒(ctx, opts *models.TokenCreation) → *models.Token, error创建 token
DeleteToken 🔒(ctx, tokenID) → error删除 token

用户与认证

方法签名说明
WhoAmI(ctx) → string, error当前认证用户名
GetUser 🔒(ctx, name) → *models.UserProfile, error用户资料
Login(ctx, name, password) → *models.LoginResult, error登录
CreateUser(ctx, user *models.UserCreation) → *models.LoginResult, error注册

组织与团队(需 token)

方法签名说明
GetOrg(ctx, orgName) → *models.Organization, error组织详情
ListOrgMembers(ctx, orgName) → []string, error组织成员
ListOrgPackages(ctx, orgName) → []string, error组织包
CreateOrg 🔒(ctx, orgName) → *models.Organization, error创建组织
DeleteOrg 🔒(ctx, orgName) → error删除组织
AddOrgMember 🔒(ctx, orgName, username) → error添加组织成员
RemoveOrgMember 🔒(ctx, orgName, username) → error移除组织成员
ListTeams(ctx, orgName) → []models.Team, error团队列表
ListTeamMembers(ctx, orgName, teamName) → []string, error团队成员
ListTeamPackages(ctx, orgName, teamName) → []string, error团队包
CreateTeam 🔒(ctx, orgName, teamName) → *models.Team, error创建团队
DeleteTeam 🔒(ctx, orgName, teamName) → error删除团队
AddTeamMember 🔒(ctx, orgName, teamName, username) → error添加团队成员
RemoveTeamMember 🔒(ctx, orgName, teamName, username) → error移除团队成员

Webhooks(需 token)

方法签名说明
ListHooks(ctx, opts models.HookListOptions) → []models.Hook, errorwebhook 列表
GetHook(ctx, hookID) → *models.Hook, errorwebhook 详情
CreateHook 🔒(ctx, hook *models.HookCreation) → *models.Hook, error创建 webhook
UpdateHook 🔒(ctx, hookID, hook *models.HookUpdate) → *models.Hook, error更新 webhook
DeleteHook 🔒(ctx, hookID) → error删除 webhook

CouchDB 视图与变更流(高级,用于镜像 / 增量同步)

方法签名说明
GetRegistryInformation(ctx) → *models.RegistryInformation, error注册表状态与统计
RegistryHealthCheck(ctx) → bool, error注册表健康检查
IsPrivateRegistry() → bool是否私有注册表
GetChanges(ctx, opts models.ChangesOptions) → *models.ChangesResult, error变更 feed
GetAllDocs(ctx, opts models.AllDocsOptions) → *models.AllDocsResult, error全量文档
GetView(ctx, viewName, opts models.ViewOptions) → *models.ViewResult, error视图查询

配置

方法签名说明
GetOptions() → *Options当前配置选项

镜像源

NPM Skills 内置支持多种镜像源,特别适合中国大陆用户:

官方镜像

go
// NPM 官方注册表 (全球)
client := registry.NewRegistry()

// Yarn 官方镜像 (全球)
client := registry.NewYarnRegistry()

中国镜像源

go
// 淘宝 NPM 镜像 (中国)
client := registry.NewTaoBaoRegistry()

// NPM Mirror (中国)
client := registry.NewNpmMirrorRegistry()

// 华为云镜像 (中国)
client := registry.NewHuaWeiCloudRegistry()

// 腾讯云镜像 (中国)
client := registry.NewTencentRegistry()

// CNPM 镜像 (中国)
client := registry.NewCnpmRegistry()

// NPM CouchDB 镜像
client := registry.NewNpmjsComRegistry()

最佳实践

超时控制

go
// 设置合理的超时时间
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

pkg, err := client.GetPackageInformation(ctx, "package-name")

错误处理

go
pkg, err := client.GetPackageInformation(ctx, "package-name")
if err != nil {
    // 检查是否是网络错误
    if strings.Contains(err.Error(), "timeout") {
        log.Printf("请求超时,请检查网络连接")
    }
    // 检查是否是包不存在
    if strings.Contains(err.Error(), "404") {
        log.Printf("包不存在: %s", packageName)
    }
    return fmt.Errorf("获取包信息失败: %w", err)
}

并发访问

由于 *http.Client 被缓存且并发安全,多个 goroutine 可共享同一个 Registry 实例并发请求,底层连接池自动复用:

go
// 使用 goroutine 并发获取多个包信息
packages := []string{"react", "vue", "angular"}
results := make(chan *models.Package, len(packages))

for _, pkg := range packages {
    go func(packageName string) {
        info, err := client.GetPackageInformation(ctx, packageName)
        if err != nil {
            log.Printf("获取 %s 失败: %v", packageName, err)
            results <- nil
            return
        }
        results <- info
    }(pkg)
}

// 收集结果
for i := 0; i < len(packages); i++ {
    result := <-results
    if result != nil {
        fmt.Printf("包: %s, 版本: %s\n", result.Name, result.DistTags["latest"])
    }
}

下一步

基于 MIT 协议发布。