You are working on `git.codelab.vc/pkg/httpx`, a Go 1.24 HTTP client/server library with zero external dependencies. ## Architecture - Client middleware: `func(http.RoundTripper) http.RoundTripper` — compose with `middleware.Chain` - Server middleware: `func(http.Handler) http.Handler` — compose with `server.Chain` - All configuration uses functional options pattern (`WithXxx` functions) - Chain order for client: Logging → User MW → Retry → Circuit Breaker → Balancer → Transport ## Package structure - `httpx` (root) — Client, request builders (NewJSONRequest, NewFormRequest), error types - `middleware/` — client-side middleware (Logging, Recovery, Auth, Headers, RequestID) - `retry/` — retry middleware with exponential backoff and Retry-After support - `circuitbreaker/` — per-host circuit breaker (sync.Map of host → Breaker) - `balancer/` — load balancing with health checking (RoundRobin, Weighted, Failover) - `server/` — Server, Router, server middleware (RequestID, Recovery, Logging, CORS, RateLimit, MaxBodySize, Timeout), response helpers (WriteJSON, WriteError) - `internal/requestid/` — shared context key (avoids circular import between server and middleware) - `internal/clock/` — deterministic time for tests ## Code conventions - Zero external dependencies — stdlib only, do not add imports outside the module - Functional options: `type Option func(*options)` with `With` constructors - Test with stdlib only: `testing`, `httptest`, `net/http`. No testify/gomock - Client test helper: `mockTransport(fn)` wrapping `middleware.RoundTripperFunc` - Server test helper: `httptest.NewRecorder`, `httptest.NewRequest`, `waitForAddr(t, srv)` - Thread safety with `sync.Mutex`, `sync.Map`, or `atomic` - Use `internal/clock` for time-dependent tests, not `time.Now()` directly - Sentinel errors in sub-packages, re-exported as aliases in root package ## When writing new code - Client middleware → file in `middleware/`, return `middleware.Middleware` - Server middleware → file in `server/middleware_.go`, return `server.Middleware` - New option → add field to options struct, create `With` func, apply in constructor - Do NOT import `server` from `middleware` or vice versa (use `internal/requestid` for shared context) - Client.Close() must be called when using WithEndpoints() (stops health checker goroutine) - Request bodies must have GetBody set for retry — use NewJSONRequest/NewFormRequest ## Commands ```bash go build ./... # compile go test ./... # test go test -race ./... # test with race detector go vet ./... # static analysis ```