Files
CLIProxyAPI/docs/sdk-usage.md
Luis Pater a4767fdd8e feat(auth, docs): add SDK guides and local password support for management
- Added extensive SDK usage guides for `cliproxy`, `sdk/access`, and watcher integration.
- Introduced `--password` flag for specifying local management access passwords.
- Enhanced management API with local password checks to secure localhost requests.
- Updated documentation to reflect the new password functionality.
2025-09-25 11:32:14 +08:00

5.0 KiB
Raw Permalink Blame History

CLI Proxy SDK Guide

The sdk/cliproxy module exposes the proxy as a reusable Go library so external programs can embed the routing, authentication, hotreload, and translation layers without depending on the CLI binary.

Install & Import

go get github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy
import (
    "context"
    "errors"
    "time"

    "github.com/router-for-me/CLIProxyAPI/v6/internal/config"
    "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy"
)

Note the /v6 module path.

Minimal Embed

cfg, err := config.LoadConfig("config.yaml")
if err != nil { panic(err) }

svc, err := cliproxy.NewBuilder().
    WithConfig(cfg).
    WithConfigPath("config.yaml"). // absolute or working-dir relative
    Build()
if err != nil { panic(err) }

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if err := svc.Run(ctx); err != nil && !errors.Is(err, context.Canceled) {
    panic(err)
}

The service manages config/auth watching, background token refresh, and graceful shutdown. Cancel the context to stop it.

Server Options (middleware, routes, logs)

The server accepts options via WithServerOptions:

svc, _ := cliproxy.NewBuilder().
  WithConfig(cfg).
  WithConfigPath("config.yaml").
  WithServerOptions(
    // Add global middleware
    cliproxy.WithMiddleware(func(c *gin.Context) { c.Header("X-Embed", "1"); c.Next() }),
    // Tweak gin engine early (CORS, trusted proxies, etc.)
    cliproxy.WithEngineConfigurator(func(e *gin.Engine) { e.ForwardedByClientIP = true }),
    // Add your own routes after defaults
    cliproxy.WithRouterConfigurator(func(e *gin.Engine, _ *handlers.BaseAPIHandler, _ *config.Config) {
      e.GET("/healthz", func(c *gin.Context) { c.String(200, "ok") })
    }),
    // Override request log writer/dir
    cliproxy.WithRequestLoggerFactory(func(cfg *config.Config, cfgPath string) logging.RequestLogger {
      return logging.NewFileRequestLogger(true, "logs", filepath.Dir(cfgPath))
    }),
  ).
  Build()

These options mirror the internals used by the CLI server.

Management API (when embedded)

  • Management endpoints are mounted only when remote-management.secret-key is set in config.yaml.
  • Remote access additionally requires remote-management.allow-remote: true.
  • See MANAGEMENT_API.md for endpoints. Your embedded server exposes them under /v0/management on the configured port.

Using the Core Auth Manager

The service uses a core auth.Manager for selection, execution, and autorefresh. When embedding, you can provide your own manager to customize transports or hooks:

core := coreauth.NewManager(coreauth.NewFileStore(cfg.AuthDir), nil, nil)
core.SetRoundTripperProvider(myRTProvider) // perauth *http.Transport

svc, _ := cliproxy.NewBuilder().
    WithConfig(cfg).
    WithConfigPath("config.yaml").
    WithCoreAuthManager(core).
    Build()

Implement a custom perauth transport:

type myRTProvider struct{}
func (myRTProvider) RoundTripperFor(a *coreauth.Auth) http.RoundTripper {
    if a == nil || a.ProxyURL == "" { return nil }
    u, _ := url.Parse(a.ProxyURL)
    return &http.Transport{ Proxy: http.ProxyURL(u) }
}

Programmatic execution is available on the manager:

// Nonstreaming
resp, err := core.Execute(ctx, []string{"gemini"}, req, opts)

// Streaming
chunks, err := core.ExecuteStream(ctx, []string{"gemini"}, req, opts)
for ch := range chunks { /* ... */ }

Note: Builtin provider executors are wired automatically when you run the Service. If you want to use Manager standalone without the HTTP server, you must register your own executors that implement auth.ProviderExecutor.

Custom Client Sources

Replace the default loaders if your creds live outside the local filesystem:

type memoryTokenProvider struct{}
func (p *memoryTokenProvider) Load(ctx context.Context, cfg *config.Config) (*cliproxy.TokenClientResult, error) {
    // Populate from memory/remote store and return counts
    return &cliproxy.TokenClientResult{}, nil
}

svc, _ := cliproxy.NewBuilder().
  WithConfig(cfg).
  WithConfigPath("config.yaml").
  WithTokenClientProvider(&memoryTokenProvider{}).
  WithAPIKeyClientProvider(cliproxy.NewAPIKeyClientProvider()).
  Build()

Hooks

Observe lifecycle without patching internals:

hooks := cliproxy.Hooks{
  OnBeforeStart: func(cfg *config.Config) { log.Infof("starting on :%d", cfg.Port) },
  OnAfterStart:  func(s *cliproxy.Service) { log.Info("ready") },
}
svc, _ := cliproxy.NewBuilder().WithConfig(cfg).WithConfigPath("config.yaml").WithHooks(hooks).Build()

Shutdown

Run defers Shutdown, so cancelling the parent context is enough. To stop manually:

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

Notes

  • Hot reload: changes to config.yaml and auths/ are picked up automatically.
  • Request logging can be toggled at runtime via the Management API.
  • Gemini Web features (gemini-web.*) are honored in the embedded server.