Skip to content

Advanced Usage Examples

This page demonstrates advanced usage patterns and features of NPM Skills.

Advanced Client Configuration

The SDK builds and caches its *http.Client internally, so you tune behavior through options rather than injecting a client: SetTimeout, SetProxy, SetInsecureSkipVerify, SetUserAgent, and authentication via SetToken / SetBasicAuth.

go
package main

import (
    "context"
    "fmt"
    "time"

    "github.com/scagogogo/npm-skills/pkg/registry"
)

func main() {
    options := registry.NewOptions().
        SetRegistryURL("https://registry.npmjs.org").
        SetTimeout(30 * time.Second).
        SetUserAgent("MyApp/1.0 (contact@example.com)")
    // For internal hosts with self-signed certs only:
    //   .SetInsecureSkipVerify(true)

    client := registry.NewRegistry(options)
    ctx := context.Background()

    pkg, err := client.GetPackageInformation(ctx, "react")
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Package: %s, Version: %s\n", pkg.Name, pkg.DistTags["latest"])
}

Parallel Package Processing

go
package main

import (
    "context"
    "fmt"
    "sync"
    "time"

    "github.com/scagogogo/npm-skills/pkg/registry"
)

func main() {
    client := registry.NewRegistry()
    
    packages := []string{
        "react", "vue", "angular", "svelte", "solid-js",
        "lodash", "underscore", "ramda", "moment", "dayjs",
    }
    
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    
    type Result struct {
        Package string
        Version string
        Error   error
    }
    
    results := make(chan Result, len(packages))
    var wg sync.WaitGroup
    
    // Process packages concurrently
    for _, pkg := range packages {
        wg.Add(1)
        go func(packageName string) {
            defer wg.Done()
            
            info, err := client.GetPackageInformation(ctx, packageName)
            if err != nil {
                results <- Result{Package: packageName, Error: err}
                return
            }
            
            results <- Result{
                Package: packageName, 
                Version: info.DistTags["latest"],
            }
        }(pkg)
    }
    
    // Close results channel when all goroutines complete
    go func() {
        wg.Wait()
        close(results)
    }()
    
    // Collect and display results
    fmt.Println("Package Processing Results:")
    fmt.Println("==========================")
    
    for result := range results {
        if result.Error != nil {
            fmt.Printf("❌ %s: %v\n", result.Package, result.Error)
        } else {
            fmt.Printf("✅ %s: v%s\n", result.Package, result.Version)
        }
    }
}

Registry Health Check

A health check probes each registry with a lightweight request and drives failover — pick the first healthy mirror, fall back down the list on failure:

go
package main

import (
    "context"
    "fmt"
    "time"

    "github.com/scagogogo/npm-skills/pkg/registry"
)

func healthCheck(name string, client *registry.Registry) {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    start := time.Now()
    
    // Test basic connectivity
    info, err := client.GetRegistryInformation(ctx)
    if err != nil {
        fmt.Printf("🔴 %s: UNHEALTHY - %v\n", name, err)
        return
    }
    
    latency := time.Since(start)
    
    // Additional health checks
    _, err = client.GetPackageInformation(ctx, "lodash")
    if err != nil {
        fmt.Printf("🟡 %s: PARTIAL - Registry info OK but package query failed: %v\n", name, err)
        return
    }
    
    fmt.Printf("🟢 %s: HEALTHY - %d packages, latency: %v\n", 
        name, info.DocCount, latency)
}

func main() {
    registries := map[string]*registry.Registry{
        "NPM Official":   registry.NewRegistry(),
        "Taobao Mirror":  registry.NewTaoBaoRegistry(),
        "NPM Mirror":     registry.NewNpmMirrorRegistry(),
        "Huawei Cloud":   registry.NewHuaWeiCloudRegistry(),
    }
    
    fmt.Println("Registry Health Check Results:")
    fmt.Println("===============================")
    
    for name, client := range registries {
        healthCheck(name, client)
    }
}

Package Dependency Analysis

go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/scagogogo/npm-skills/pkg/registry"
)

func analyzeDependencies(client *registry.Registry, packageName, version string) {
    ctx := context.Background()
    
    ver, err := client.GetPackageVersion(ctx, packageName, version)
    if err != nil {
        log.Printf("Failed to get version info: %v\n", err)
        return
    }
    
    fmt.Printf("\n📦 Analyzing %s@%s\n", packageName, version)
    fmt.Printf("=====================================\n")
    
    // Runtime dependencies
    if len(ver.Dependencies) > 0 {
        fmt.Printf("\n🔗 Runtime Dependencies (%d):\n", len(ver.Dependencies))
        for dep, depVer := range ver.Dependencies {
            fmt.Printf("  ├─ %s: %s\n", dep, depVer)
        }
    }
    
    // Dev dependencies
    if len(ver.DevDependencies) > 0 {
        fmt.Printf("\n🛠️  Dev Dependencies (%d):\n", len(ver.DevDependencies))
        for dep, depVer := range ver.DevDependencies {
            fmt.Printf("  ├─ %s: %s\n", dep, depVer)
        }
    }
    
    // Optional dependencies
    if len(ver.OptionalDependencies) > 0 {
        fmt.Printf("\n🔧 Optional Dependencies (%d):\n", len(ver.OptionalDependencies))
        for dep, depVer := range ver.OptionalDependencies {
            fmt.Printf("  ├─ %s: %s\n", dep, depVer)
        }
    }
    
    // Peer dependencies
    if len(ver.PeerDependencies) > 0 {
        fmt.Printf("\n👥 Peer Dependencies (%d):\n", len(ver.PeerDependencies))
        for dep, depVer := range ver.PeerDependencies {
            fmt.Printf("  ├─ %s: %s\n", dep, depVer)
        }
    }
    
    // Bundle dependencies (field is interface{}; assert to []string when present)
    if bundle, ok := ver.BundleDependencies.([]string); ok && len(bundle) > 0 {
        fmt.Printf("\n📦 Bundled Dependencies (%d):\n", len(bundle))
        for _, dep := range bundle {
            fmt.Printf("  ├─ %s\n", dep)
        }
    }
}

func main() {
    client := registry.NewRegistry()
    
    // Analyze popular packages
    packages := []struct {
        name    string
        version string
    }{
        {"react", "18.2.0"},
        {"vue", "3.3.0"},
        {"express", "4.18.2"},
    }
    
    for _, pkg := range packages {
        analyzeDependencies(client, pkg.name, pkg.version)
    }
}

Package Download Trend Analysis

go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/scagogogo/npm-skills/pkg/registry"
)

func main() {
    client := registry.NewRegistry()
    ctx := context.Background()
    
    packages := []string{"react", "vue", "angular"}
    periods := []string{"last-day", "last-week", "last-month"}
    
    fmt.Println("📈 Package Download Trend Analysis")
    fmt.Println("==================================")
    
    for _, pkg := range packages {
        fmt.Printf("\n📦 Package: %s\n", pkg)
        fmt.Println("─────────────────────")
        
        var dailyDownloads, weeklyDownloads, monthlyDownloads int
        
        for _, period := range periods {
            stats, err := client.GetDownloadStats(ctx, pkg, period)
            if err != nil {
                log.Printf("Failed to get %s stats for %s: %v\n", period, pkg, err)
                continue
            }
            
            switch period {
            case "last-day":
                dailyDownloads = stats.Downloads
                fmt.Printf("📅 Last Day:   %10d downloads\n", stats.Downloads)
            case "last-week":
                weeklyDownloads = stats.Downloads
                fmt.Printf("📅 Last Week:  %10d downloads\n", stats.Downloads)
            case "last-month":
                monthlyDownloads = stats.Downloads
                fmt.Printf("📅 Last Month: %10d downloads\n", stats.Downloads)
            }
        }
        
        // Calculate trends
        if weeklyDownloads > 0 && dailyDownloads > 0 {
            avgDailyFromWeek := weeklyDownloads / 7
            trend := float64(dailyDownloads-avgDailyFromWeek) / float64(avgDailyFromWeek) * 100
            
            trendIndicator := "📊"
            if trend > 10 {
                trendIndicator = "📈"
            } else if trend < -10 {
                trendIndicator = "📉"
            }
            
            fmt.Printf("%s Trend:      %+.1f%% vs weekly average\n", trendIndicator, trend)
        }

        // Monthly context
        if monthlyDownloads > 0 {
            avgDailyFromMonth := monthlyDownloads / 30
            fmt.Printf("📅 Monthly Avg: %10d downloads/day\n", avgDailyFromMonth)
        }
    }
}

Next Steps

Released under the MIT License.