# `http-check/http-check` _(no submodules)_ ## Purpose `createHttpCheck` returns a `CheckFn` that probes an HTTP endpoint and reports `healthy` when the response status appears in `expectedStatusCodes`. It is the standard building block for "is upstream X reachable?" probes — used to check downstream APIs, gateways, internal dependency surfaces, and anything else with a `/health` or `/status` endpoint. The factory accepts an injectable `fetchImpl` so tests never touch real network sockets, and an injectable `Clock` so `responseTime` is deterministic. ## Features - Method, headers, and expected-status-code overrides via the `HttpCheckConfig` argument. - AbortController-driven per-request timeout that maps to `responseTime` + the human-readable `"HTTP check timed out after Xms"` message. - Network errors are returned as `unhealthy` with `details.error` containing the raw message — not thrown. - Zod boundary validation: empty `url`, empty `method`, non-positive `timeout` all throw `HealthCheckError(INVALID_OPTIONS)`. - `fetchImpl` defaults to `globalThis.fetch` bound to `globalThis`; tests pass a stub. ## Usage: Basic ```ts import { createHttpCheck } from "@suaveplan/health-check"; const check = createHttpCheck({ url: "https://upstream.example/health" }); const result = await check(); ``` ## Usage: Advanced ```ts import { createHttpCheck } from "@suaveplan/health-check"; const check = createHttpCheck( { url: "https://internal.api/health", method: "HEAD", headers: { authorization: `Bearer ${token}` }, timeout: 1_500, expectedStatusCodes: [200, 204], fetchImpl: instrumentedFetch, }, { clock: () => performance.now() }, ); ``` ## API Reference - `createHttpCheck(config, options?)` → `CheckFn`. - `config: HttpCheckConfig` — `url` required; `method`, `headers`, `timeout`, `expectedStatusCodes`, `fetchImpl` optional. - `options.clock?: Clock` — overrides `Date.now` for response-time measurement. ## Implementation Notes The check never re-throws. Network errors, abort errors, and unexpected status codes are all funnelled into `CheckResult` objects so the `HealthChecker` can record them uniformly. Abort detection is case-insensitive on `"abort"` / `"timeout"` and also consults `controller.signal.aborted` so adapters that surface only a generic error message still classify correctly. The `responseTime` is measured between the clock readings around `fetchImpl` so it includes DNS, TCP, TLS, and the server's processing time — matching how operators read latency dashboards. The factory is pure: it validates options once and returns a closure that captures the normalised config, so the per-call cost is just the fetch + a small amount of bookkeeping.