# `react-auth-metrics` _(no submodules)_ ## Purpose `react-auth-metrics.ts` builds the OTel instrument set for `@suaveplan/react-auth`. Instruments are constructed lazily through `metrics.getMeter("suaveplan.react-auth")` so consumers without a registered `MeterProvider` pay zero overhead — the OTel API ships a no-op meter by default. The module exposes five counters (`react_auth.sign_in.total`, `react_auth.sign_up.total`, `react_auth.sign_out.total`, `react_auth.guard.allow.total`, `react_auth.guard.deny.total`) and one histogram (`react_auth.session_fetch.duration_ms`), plus helper functions that record the corresponding event with a typed attribute payload. The helpers also push every event into an in-memory `state` ring so spec-conformance tests can assert exact attribute payloads without standing up a full SDK pipeline. `resetReactAuthMetricsState()` clears the ring between tests. ## Features - Lazy OTel instrument construction; no-op until a `MeterProvider` is registered. - 5 counters + 1 histogram covering the wave-1 production paths. - Typed `outcome`/`predicate` attributes per record helper. - In-memory `state` ring (`getReactAuthMetricsState`) for assertion-friendly tests. - `resetReactAuthMetricsState()` test-only helper. ## Usage: Basic ```ts import { recordSignIn } from "@suaveplan/react-auth"; await client.signIn(credentials); recordSignIn("success"); ``` ## Usage: Advanced Wire a real `MeterProvider` (e.g. for shipping metrics to Prometheus) and assert via the in-memory ring in tests: ```ts import { metrics } from "@opentelemetry/api"; import { MeterProvider } from "@opentelemetry/sdk-metrics"; import { getReactAuthMetricsState, recordSessionFetchDuration, resetReactAuthMetricsState, } from "@suaveplan/react-auth"; const provider = new MeterProvider(); metrics.setGlobalMeterProvider(provider); resetReactAuthMetricsState(); recordSessionFetchDuration(42, "success"); const state = getReactAuthMetricsState(); expect(state.sessionFetchDurationMs).toEqual([ { attributes: { outcome: "success" }, value: 42 }, ]); ``` ## API Reference - `interface ReactAuthMetricSample` — `{ attributes: Record; value?: number }`. - `interface ReactAuthMetricsState` — `{ signInTotal; signUpTotal; signOutTotal; guardAllowTotal; guardDenyTotal; sessionFetchDurationMs }` arrays. - `function getReactAuthMetrics()` — returns the cached instrument bundle. - `function recordSignIn(outcome: "success" | "failure"): void`. - `function recordSignUp(outcome: "success" | "failure"): void`. - `function recordSignOut(outcome: "success" | "failure"): void`. - `function recordGuardAllow(predicate: string): void`. - `function recordGuardDeny(predicate: string): void`. - `function recordSessionFetchDuration(durationMs: number, outcome: "success" | "failure"): void`. - `function getReactAuthMetricsState(): ReactAuthMetricsState`. - `function resetReactAuthMetricsState(): void`. ## Implementation Notes The OTel API exposes a global no-op `MeterProvider` until the application opts in by calling `setGlobalMeterProvider(...)`; this means the helpers are safe to call from production paths without any registration ceremony. The in-memory state ring is unbounded by design — it is intended only for tests and the package's own conformance checks. A long-running process would never call `getReactAuthMetricsState()` directly, so leak risk is bounded by test scope. The cached instrument bundle is module-level (`let cached: CachedInstruments | undefined`) so the meter is resolved at most once per process; the lazy build means importing the module is free.