# `metrics` _(no submodules)_ ## Purpose OpenTelemetry instrumentation surface for the JWS verify and sign hot paths. Every production code path records a histogram for wall-time latency and increments outcome-tagged counters; the error registry's `recordError` also fires once per typed throw so dashboards can pivot on `code` cardinality. The `outcome` attribute is bounded to a 4-value enum (`success | sig_invalid | alg_not_allowed | header_invalid`) so production observability backends do not blow up under attacker-controlled token streams. ## Features - `recordVerify(alg, outcome, durationMs)` — histogram + outcome counter. - `recordSign(alg, "success" | "error", durationMs)` — sign-side mirror. - `recordError(code)` — typed-error counter pivoted by code. - `resetMetricsForTesting()` — rebinds the cached instrument bag after a test installs a fresh `MeterProvider`. - `getInstrumentsForTesting()` — exposes the bag for assertion-time introspection. ## Usage: Basic Example ```ts import { metrics } from "@opentelemetry/api"; import { resetMetricsForTesting, compactVerify } from "@suaveplan/jws"; metrics.setGlobalMeterProvider(myInMemoryProvider); resetMetricsForTesting(); await compactVerify(token, key, { algorithms: ["HS256"] }); // `jws.verify_duration_ms{alg=HS256, outcome=success}` has 1 sample. ``` ## Usage: Advanced Example ```ts import { getInstrumentsForTesting, recordVerify, recordError, JWS_CODES } from "@suaveplan/jws"; const bag = getInstrumentsForTesting(); // bag.verifyDurationMs / bag.signDurationMs (Histogram) // bag.verifyTotal / bag.signTotal (Counter) // bag.errorTotal (Counter) // Bypass the pipeline for an ad-hoc observation: recordVerify("RS256", "sig_invalid", 4.2); recordError(JWS_CODES.SIG_INVALID); ``` ## API Reference - `recordVerify(alg: string, outcome: JwsVerifyOutcome, durationMs: number): void` - `recordSign(alg: string, outcome: "success" | "error", durationMs: number): void` - `recordError(code: string): void` - `nowMs(): number` - `resetMetricsForTesting(): void` - `getInstrumentsForTesting(): InstrumentBag` - `type JwsVerifyOutcome = "success" | "sig_invalid" | "alg_not_allowed" | "header_invalid"` ## Implementation Notes The instrument bag is cached in module scope so repeated invocations do not call `metrics.getMeter` on every request — that call has non-trivial overhead under the OTel SDK because it walks the provider's registry. Tests that install a fresh `MeterProvider` MUST call `resetMetricsForTesting()` in `beforeEach`; otherwise the cached bag stays bound to the original (no-op) provider and the test asserts against an empty histogram. The `outcome` enum's bounded cardinality is deliberate: an unbounded enum would let an adversarial token stream blow up the metrics backend's series count, and most OTel sinks bill by series.