@nexusts/metrics 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ This module is part of the NexusTS monorepo. Each module is published as its own
15
15
  Most apps start with just the core:
16
16
 
17
17
  ```bash
18
- bun add @nexusts/core reflect-metadata zod hono
18
+ bun add @nexusts/core
19
19
  ```
20
20
 
21
21
  Then add this module only if you need it:
@@ -26,7 +26,7 @@ bun add @nexusts/metrics
26
26
 
27
27
  ## Peer dependencies
28
28
 
29
- None. This module is fully self-contained.
29
+ **None.** No external dependencies.
30
30
 
31
31
  ## Usage
32
32
 
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `MetricsController` — exposes `GET /metrics` for Prometheus
3
+ * scrapers. Supports content negotiation: the response format is
4
+ * `text/plain` (Prometheus 0.0.4) by default, or
5
+ * `application/openmetrics-text` if the request asks for it.
6
+ *
7
+ * The controller is auto-mounted by `MetricsModule.forRoot()`. If
8
+ * you want to mount it manually (e.g. on a different path), call
9
+ * `MetricsController.handler(service)` and wire it up yourself.
10
+ */
11
+ import type { Context } from "hono";
12
+ import type { MetricsService } from "./service.js";
13
+ export declare class MetricsController {
14
+ static readonly PATH = "/metrics";
15
+ /**
16
+ * Returns a Hono handler that serves the /metrics endpoint.
17
+ *
18
+ * @example
19
+ * app.get("/metrics", MetricsController.handler(svc));
20
+ */
21
+ static handler(service: MetricsService): (c: Context) => Response & import("hono").TypedResponse<string, 200, "body">;
22
+ /** Mount the controller on the given Hono app at `path`. */
23
+ static mount(app: {
24
+ get: (path: string, ...handlers: unknown[]) => unknown;
25
+ }, service: MetricsService, path?: string): void;
26
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `Counter` — monotonically increasing value.
3
+ *
4
+ * Counters can only go up (use `Gauge` for values that can decrease).
5
+ * They're ideal for: request counts, error counts, bytes sent, etc.
6
+ *
7
+ * The standard Prometheus naming convention is to suffix counters
8
+ * with `_total`.
9
+ *
10
+ * Example:
11
+ * const c = new Counter({ name: "http_requests_total" });
12
+ * c.inc();
13
+ * c.incBy(5, { method: "GET" });
14
+ */
15
+ import type { CounterOptions, Counter as ICounter, MetricSample } from "./types.js";
16
+ /** Internal helper used by all metric types. */
17
+ export declare function renderLabels(declared: string[], values: Record<string, string>): string;
18
+ export declare class CounterImpl implements ICounter {
19
+ readonly name: string;
20
+ readonly help?: string;
21
+ readonly labelNames: string[];
22
+ /** Map from "label1=value1,label2=value2" -> value. */
23
+ private values;
24
+ constructor(opts: CounterOptions);
25
+ inc(labels?: Record<string, string>): void;
26
+ incBy(n: number, labels?: Record<string, string>): void;
27
+ reset(): void;
28
+ getSamples(): MetricSample[];
29
+ /** Render this counter in Prometheus exposition format. */
30
+ renderPrometheus(): string;
31
+ private assertLabels;
32
+ private key;
33
+ private parseKey;
34
+ }
35
+ export declare function escapeLabelValue(v: string): string;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@Counted()` — class-method decorator that increments a counter
3
+ * on each call.
4
+ *
5
+ * Usage:
6
+ * class UserController {
7
+ * @Counted('http_requests_total', { labels: () => ({ method: 'GET' }) })
8
+ * list() { ... }
9
+ * }
10
+ *
11
+ * The decorator reads the `MetricsService` from the global registry
12
+ * (set by `MetricsModule.forRoot()`). When no service is registered
13
+ * the decorator is a pass-through.
14
+ */
15
+ export interface CountedOptions {
16
+ /** Optional label values, computed at call time. */
17
+ labels?: () => Record<string, string>;
18
+ }
19
+ /**
20
+ * Method decorator: increment a counter on each invocation.
21
+ *
22
+ * The counter is registered lazily the first time the method is
23
+ * called, using the service from the global registry.
24
+ */
25
+ export declare function Counted(metricName: string, options?: CountedOptions): (_target: object, _propertyKey: string | symbol, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,2 @@
1
+ export { Counted, type CountedOptions } from "./counted.js";
2
+ export { Timed, type TimedOptions } from "./timed.js";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `@Timed()` — class-method decorator that records a method's
3
+ * duration in a histogram.
4
+ *
5
+ * Usage:
6
+ * class UserController {
7
+ * @Timed('http_request_duration_seconds', { labels: () => ({ method: 'GET' }) })
8
+ * list() { ... }
9
+ * }
10
+ *
11
+ * The decorator reads the `MetricsService` from the global registry.
12
+ * When no service is registered the decorator is a pass-through.
13
+ */
14
+ export interface TimedOptions {
15
+ /** Optional buckets override. */
16
+ buckets?: number[];
17
+ /** Optional label values, computed at call time. */
18
+ labels?: () => Record<string, string>;
19
+ }
20
+ /**
21
+ * Method decorator: observe a method's duration (in seconds) in a
22
+ * histogram. Async methods are timed across their full await.
23
+ */
24
+ export declare function Timed(metricName: string, options?: TimedOptions): (_target: object, _propertyKey: string | symbol, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * `Gauge` — point-in-time value that can go up or down.
3
+ *
4
+ * Ideal for: queue size, memory usage, active connections, in-flight
5
+ * requests, etc.
6
+ *
7
+ * The value is stored per label combination. `inc()` and `dec()` are
8
+ * convenience helpers; `set()` replaces the value outright.
9
+ *
10
+ * Example:
11
+ * const g = new Gauge({
12
+ * name: "active_connections",
13
+ * collect: () => { return; },
14
+ * });
15
+ * g.inc();
16
+ * g.dec(2);
17
+ * g.set(42);
18
+ */
19
+ import type { GaugeOptions, Gauge as IGauge, MetricSample } from "./types.js";
20
+ export declare class GaugeImpl implements IGauge {
21
+ readonly name: string;
22
+ readonly help?: string;
23
+ readonly labelNames: string[];
24
+ private values;
25
+ constructor(opts: GaugeOptions);
26
+ set(value: number, labels?: Record<string, string>): void;
27
+ inc(n?: number, labels?: Record<string, string>): void;
28
+ dec(n?: number, labels?: Record<string, string>): void;
29
+ setToCurrentTime(labels?: Record<string, string>): void;
30
+ reset(): void;
31
+ getSamples(): MetricSample[];
32
+ /** Render this gauge in Prometheus exposition format. */
33
+ renderPrometheus(): string;
34
+ private assertLabels;
35
+ private key;
36
+ private parseKey;
37
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `Histogram` — distribution of observed values into buckets.
3
+ *
4
+ * Each `observe()` adds the value to every bucket whose upper bound
5
+ * is >= value. The metric exposes:
6
+ * - `<name>_bucket{le="..."}` — cumulative count per bucket
7
+ * - `<name>_sum` — total sum of all observed values
8
+ * - `<name>_count` — total count
9
+ *
10
+ * Default buckets (Prometheus convention): [0.005, 0.01, 0.025,
11
+ * 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10] seconds.
12
+ *
13
+ * Example:
14
+ * const h = new Histogram({ name: "http_duration_seconds" });
15
+ * h.observe(0.123);
16
+ * await h.time(async () => fetch("/slow"));
17
+ */
18
+ import type { HistogramOptions, Histogram as IHistogram, MetricSample } from "./types.js";
19
+ /** Prometheus default buckets (seconds). */
20
+ export declare const DEFAULT_BUCKETS: number[];
21
+ interface HistogramState {
22
+ buckets: number[];
23
+ sum: number;
24
+ count: number;
25
+ }
26
+ export declare class HistogramImpl implements IHistogram {
27
+ readonly name: string;
28
+ readonly help?: string;
29
+ readonly labelNames: string[];
30
+ private readonly upperBounds;
31
+ /** Map from "label1=v1,label2=v2" -> state. */
32
+ private states;
33
+ constructor(opts: HistogramOptions);
34
+ observe(value: number, labels?: Record<string, string>): void;
35
+ time<T>(fn: (start: number) => Promise<T> | T, labels?: Record<string, string>): Promise<T>;
36
+ reset(): void;
37
+ getSamples(): MetricSample[];
38
+ /** Render this histogram in Prometheus exposition format. */
39
+ renderPrometheus(): string;
40
+ /** Internal: produce Prometheus-formatted lines for a single state. */
41
+ renderState(labels: Record<string, string>, state: HistogramState): string;
42
+ /** Internal: enumerate all states for the registry. */
43
+ enumerateStates(): Array<{
44
+ labels: Record<string, string>;
45
+ state: HistogramState;
46
+ }>;
47
+ private assertLabels;
48
+ private key;
49
+ private parseKey;
50
+ }
51
+ export {};
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `nexusjs/metrics` — Prometheus-compatible metrics collection.
3
+ *
4
+ * Public API:
5
+ * - `MetricsService` — main DI-friendly service
6
+ * - `MetricsModule.forRoot()` — wires up default metrics, mounts /metrics
7
+ * - `MetricsController.handler(service)` — Hono handler for /metrics
8
+ * - `MetricsService#counter/gauge/histogram/summary()` — register metrics
9
+ * - `@Counted()`, `@Timed()` decorators — auto-record on method calls
10
+ * - `MetricsService#expose()` — serialize to Prometheus / OpenMetrics
11
+ *
12
+ * Zero external dependencies. ~5kb gzipped.
13
+ *
14
+ * @Module({
15
+ * imports: [
16
+ * MetricsModule.forRoot({
17
+ * enableDefaultMetrics: true,
18
+ * path: "/metrics",
19
+ * globalLabels: { service: "my-app" },
20
+ * }),
21
+ * ],
22
+ * })
23
+ * class AppModule {}
24
+ */
25
+ export { CounterImpl } from "./counter.js";
26
+ export { GaugeImpl } from "./gauge.js";
27
+ export { HistogramImpl, DEFAULT_BUCKETS } from "./histogram.js";
28
+ export { SummaryImpl, DEFAULT_PERCENTILES } from "./summary.js";
29
+ export { MetricsRegistry } from "./registry.js";
30
+ export { MetricsService, METRICS_SERVICE_TOKEN, setMetricsService, getMetricsService, } from "./service.js";
31
+ export { MetricsModule } from "./module.js";
32
+ export { MetricsController } from "./controller.js";
33
+ export { Counted, Timed, type CountedOptions, type TimedOptions } from "./decorators/index.js";
34
+ export type { Counter, CounterOptions, Gauge, GaugeOptions, Histogram, HistogramOptions, Summary, SummaryOptions, MetricSample, MetricsConfig, ExpositionFormat, ExpositionResult, } from "./types.js";
package/dist/index.js CHANGED
@@ -675,7 +675,7 @@ class MetricsService {
675
675
  }
676
676
  }
677
677
  // packages/metrics/src/module.ts
678
- import { Module } from "@nexusts/core/decorators/module.js";
678
+ import { Module } from "@nexusts/core";
679
679
 
680
680
  // packages/metrics/src/controller.ts
681
681
  class MetricsController {
@@ -942,5 +942,5 @@ export {
942
942
  Counted
943
943
  };
944
944
 
945
- //# debugId=FBFB8DC36D7055E964756E2164756E21
945
+ //# debugId=CF072CA419117E5264756E2164756E21
946
946
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -8,12 +8,12 @@
8
8
  "/**\n * `Summary` — quantile estimation over a sliding window of values.\n *\n * Summary is similar to Histogram but computes client-side quantiles\n * (via t-digest-style sorting). It's useful when you need a small\n * number of percentiles (50/90/99) without the storage cost of\n * histograms.\n *\n * Quantile computation uses a simple sorted-window approach: each\n * label combination keeps a circular buffer of the last N values.\n *\n * Example:\n * const s = new Summary({\n * name: \"http_request_size_bytes\",\n * percentiles: [0.5, 0.9, 0.99],\n * });\n * s.observe(1024);\n */\n\nimport type { SummaryOptions, Summary as ISummary, MetricSample } from \"./types.js\";\nimport { escapeLabelValue, renderLabels } from \"./counter.js\";\n\n/** Default percentiles. */\nexport const DEFAULT_PERCENTILES = [0.5, 0.9, 0.99];\n/** Default sliding window size. */\nexport const DEFAULT_MAX_AGE_SECONDS = 600;\nexport const DEFAULT_AGE_BUCKETS = 5;\n\ninterface SummaryState {\n\t/** For each age bucket, an array of (sum, count) pairs. */\n\tbuckets: Array<{ values: number[]; sum: number; count: number }>;\n\t/** Index of the next bucket to rotate. */\n\tcurrentBucket: number;\n\t/** Last rotation time. */\n\tlastRotation: number;\n}\n\nexport class SummaryImpl implements ISummary {\n\treadonly name: string;\n\treadonly help?: string;\n\treadonly labelNames: string[];\n\tprivate readonly percentiles: number[];\n\tprivate readonly maxAgeSeconds: number;\n\tprivate readonly ageBuckets: number;\n\tprivate readonly bucketSize: number;\n\t/** Map from \"label1=v1,label2=v2\" -> state. */\n\tprivate states = new Map<string, SummaryState>();\n\n\tconstructor(opts: SummaryOptions) {\n\t\tthis.name = opts.name;\n\t\tthis.help = opts.help;\n\t\tthis.labelNames = opts.labelNames ?? [];\n\t\tthis.percentiles = opts.percentiles ?? DEFAULT_PERCENTILES;\n\t\tthis.maxAgeSeconds = opts.maxAgeSeconds ?? DEFAULT_MAX_AGE_SECONDS;\n\t\tthis.ageBuckets = opts.ageBuckets ?? DEFAULT_AGE_BUCKETS;\n\t\tthis.bucketSize = Math.ceil(this.maxAgeSeconds / this.ageBuckets);\n\t}\n\n\tobserve(value: number, labels?: Record<string, string>): void {\n\t\tthis.assertLabels(labels);\n\t\tconst k = this.key(labels);\n\t\tlet s = this.states.get(k);\n\t\tif (!s) {\n\t\t\ts = this.newState();\n\t\t\tthis.states.set(k, s);\n\t\t}\n\t\tthis.maybeRotate(s);\n\t\tconst b = s.buckets[s.currentBucket];\n\t\tb.values.push(value);\n\t\tb.sum += value;\n\t\tb.count++;\n\t}\n\n\tasync time<T>(\n\t\tfn: () => Promise<T> | T,\n\t\tlabels?: Record<string, string>,\n\t): Promise<T> {\n\t\tconst start = performance.now();\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tconst elapsedMs = performance.now() - start;\n\t\t\tthis.observe(elapsedMs / 1000, labels);\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.states.clear();\n\t}\n\n\tgetSamples(): MetricSample[] {\n\t\tconst out: MetricSample[] = [];\n\t\tfor (const [k] of this.states) {\n\t\t\tout.push({ labels: this.parseKey(k), value: 0 });\n\t\t}\n\t\treturn out;\n\t}\n\n\t/** Render this summary in Prometheus exposition format. */\n\trenderPrometheus(): string {\n\t\tconst lines: string[] = [];\n\t\tif (this.help) lines.push(`# HELP ${this.name} ${this.help}`);\n\t\tlines.push(`# TYPE ${this.name} summary`);\n\n\t\tfor (const [k, s] of this.states) {\n\t\t\tconst labels = this.parseKey(k);\n\t\t\tthis.maybeRotate(s);\n\t\t\tconst totals = this.totals(s);\n\n\t\t\tfor (const q of this.percentiles) {\n\t\t\t\tconst qval = this.quantile(s, q);\n\t\t\t\tconst qstr = clampQuantileLabel(q);\n\t\t\t\t// The \"quantile\" label is always present, even if no\n\t\t\t\t// labelNames are declared. It's a special summary label.\n\t\t\t\tconst fullLabels: Record<string, string> = { ...labels, quantile: qstr };\n\t\t\t\tconst baseStr = renderLabels(this.labelNames, fullLabels);\n\t\t\t\tconst lbl = baseStr ? `${baseStr},quantile=\"${qstr}\"` : `quantile=\"${qstr}\"`;\n\t\t\t\tlines.push(`${this.name}{${lbl}} ${qval}`);\n\t\t\t}\n\t\t\t{\n\t\t\t\tconst lbl = renderLabels(this.labelNames, labels);\n\t\t\t\tlines.push(`${this.name}_sum${lbl ? `{${lbl}}` : \"\"} ${totals.sum}`);\n\t\t\t\tlines.push(`${this.name}_count${lbl ? `{${lbl}}` : \"\"} ${totals.count}`);\n\t\t\t}\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\t/* ----------------- internals ----------------- */\n\n\tprivate newState(): SummaryState {\n\t\tconst buckets: SummaryState[\"buckets\"] = [];\n\t\tfor (let i = 0; i < this.ageBuckets; i++) {\n\t\t\tbuckets.push({ values: [], sum: 0, count: 0 });\n\t\t}\n\t\treturn { buckets, currentBucket: 0, lastRotation: Date.now() };\n\t}\n\n\tprivate maybeRotate(s: SummaryState): void {\n\t\tconst now = Date.now();\n\t\tconst elapsed = (now - s.lastRotation) / 1000;\n\t\tif (elapsed >= this.bucketSize) {\n\t\t\tconst rotations = Math.floor(elapsed / this.bucketSize);\n\t\t\tfor (let i = 0; i < rotations; i++) {\n\t\t\t\ts.currentBucket = (s.currentBucket + 1) % this.ageBuckets;\n\t\t\t\ts.buckets[s.currentBucket] = { values: [], sum: 0, count: 0 };\n\t\t\t}\n\t\t\ts.lastRotation = now;\n\t\t}\n\t}\n\n\tprivate totals(s: SummaryState): { sum: number; count: number } {\n\t\tlet sum = 0;\n\t\tlet count = 0;\n\t\tfor (const b of s.buckets) {\n\t\t\tsum += b.sum;\n\t\t\tcount += b.count;\n\t\t}\n\t\treturn { sum, count };\n\t}\n\n\tprivate quantile(s: SummaryState, q: number): number {\n\t\t// Collect all values across buckets\n\t\tconst all: number[] = [];\n\t\tfor (const b of s.buckets) {\n\t\t\tfor (const v of b.values) all.push(v);\n\t\t}\n\t\tif (all.length === 0) return 0;\n\t\tall.sort((a, b) => a - b);\n\t\tconst idx = Math.min(all.length - 1, Math.max(0, Math.floor(q * all.length)));\n\t\treturn all[idx];\n\t}\n\n\tprivate assertLabels(labels?: Record<string, string>): void {\n\t\tif (!labels && this.labelNames.length === 0) return;\n\t\tif (this.labelNames.length === 0) {\n\t\t\tthrow new Error(`Summary ${this.name} has no labels declared`);\n\t\t}\n\t\tif (!labels) {\n\t\t\tthrow new Error(`Summary ${this.name} requires labels: ${this.labelNames.join(\", \")}`);\n\t\t}\n\t\tfor (const required of this.labelNames) {\n\t\t\tif (!(required in labels)) {\n\t\t\t\tthrow new Error(`Summary ${this.name} missing label \"${required}\"`);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate key(labels?: Record<string, string>): string {\n\t\tif (!labels) return \"\";\n\t\treturn this.labelNames.map((n) => `${n}=${escapeLabelValue(labels[n] ?? \"\")}`).join(\",\");\n\t}\n\n\tprivate parseKey(key: string): Record<string, string> {\n\t\tif (!key) return {};\n\t\tconst out: Record<string, string> = {};\n\t\tfor (const part of key.split(\",\")) {\n\t\t\tconst [k, ...rest] = part.split(\"=\");\n\t\t\tout[k] = rest.join(\"=\");\n\t\t}\n\t\treturn out;\n\t}\n}\n\nfunction clampQuantileLabel(q: number): string {\n\t// Use Number's default string representation, which handles JS\n\t// float precision better than toFixed(17). E.g. 0.9 -> \"0.9\",\n\t// 0.99 -> \"0.99\", 0.5 -> \"0.5\".\n\tconst s = String(q);\n\t// If JS gives us a long decimal like \"0.90000000000000002\",\n\t// round it to a reasonable precision.\n\tif (s.includes(\".\") && s.length > 8) {\n\t\treturn q.toFixed(6).replace(/0+$/, \"\").replace(/\\.$/, \"\");\n\t}\n\treturn s;\n}\n",
9
9
  "/**\n * `MetricsRegistry` — collection of all metrics registered in the app.\n *\n * The registry is the source of truth for `MetricsService`. It:\n * - Holds every metric (counter / gauge / histogram / summary) by name.\n * - Serializes them to the Prometheus text exposition format.\n * - Supports content negotiation (OpenMetrics vs. Prometheus).\n *\n * Each metric is stored as a unified `RegisteredMetric` so the\n * registry can iterate and call `renderPrometheus()` on each.\n */\n\nimport { CounterImpl } from \"./counter.js\";\nimport { GaugeImpl } from \"./gauge.js\";\nimport { HistogramImpl } from \"./histogram.js\";\nimport { SummaryImpl } from \"./summary.js\";\nimport type {\n\tCounter,\n\tCounterOptions,\n\tExpositionFormat,\n\tExpositionResult,\n\tGauge,\n\tGaugeOptions,\n\tHistogram,\n\tHistogramOptions,\n\tSummary,\n\tSummaryOptions,\n} from \"./types.js\";\n\ninterface RegisteredMetric {\n\tname: string;\n\ttype: \"counter\" | \"gauge\" | \"histogram\" | \"summary\";\n\timpl: { renderPrometheus(): string; reset(): void };\n}\n\nexport class MetricsRegistry {\n\tprivate metrics = new Map<string, RegisteredMetric>();\n\tprivate globalLabels: Record<string, string> = {};\n\n\t/** Add a global label that's prepended to every metric line. */\n\tsetGlobalLabels(labels: Record<string, string>): void {\n\t\tthis.globalLabels = { ...labels };\n\t}\n\n\tgetGlobalLabels(): Record<string, string> {\n\t\treturn { ...this.globalLabels };\n\t}\n\n\t/** Register a counter; returns the same instance for chaining. */\n\tregisterCounter(opts: CounterOptions): Counter {\n\t\tif (this.metrics.has(opts.name)) {\n\t\t\tthrow new Error(`Metric ${opts.name} is already registered`);\n\t\t}\n\t\tconst c = new CounterImpl(opts);\n\t\tthis.metrics.set(opts.name, { name: opts.name, type: \"counter\", impl: c });\n\t\treturn c;\n\t}\n\n\tregisterGauge(opts: GaugeOptions): Gauge {\n\t\tif (this.metrics.has(opts.name)) {\n\t\t\tthrow new Error(`Metric ${opts.name} is already registered`);\n\t\t}\n\t\tconst g = new GaugeImpl(opts);\n\t\tthis.metrics.set(opts.name, { name: opts.name, type: \"gauge\", impl: g });\n\t\treturn g;\n\t}\n\n\tregisterHistogram(opts: HistogramOptions): Histogram {\n\t\tif (this.metrics.has(opts.name)) {\n\t\t\tthrow new Error(`Metric ${opts.name} is already registered`);\n\t\t}\n\t\tconst h = new HistogramImpl(opts);\n\t\tthis.metrics.set(opts.name, { name: opts.name, type: \"histogram\", impl: h });\n\t\treturn h;\n\t}\n\n\tregisterSummary(opts: SummaryOptions): Summary {\n\t\tif (this.metrics.has(opts.name)) {\n\t\t\tthrow new Error(`Metric ${opts.name} is already registered`);\n\t\t}\n\t\tconst s = new SummaryImpl(opts);\n\t\tthis.metrics.set(opts.name, { name: opts.name, type: \"summary\", impl: s });\n\t\treturn s;\n\t}\n\n\t/** Return a metric by name, regardless of type. */\n\tget(name: string): RegisteredMetric | undefined {\n\t\treturn this.metrics.get(name);\n\t}\n\n\t/** Return a counter by name. Throws if it isn't a counter. */\n\tgetCounter(name: string): Counter {\n\t\tconst m = this.metrics.get(name);\n\t\tif (!m) throw new Error(`Counter ${name} is not registered`);\n\t\tif (m.type !== \"counter\") throw new Error(`Metric ${name} is a ${m.type}, not a counter`);\n\t\treturn m.impl as unknown as Counter;\n\t}\n\n\t/** Return a gauge by name. */\n\tgetGauge(name: string): Gauge {\n\t\tconst m = this.metrics.get(name);\n\t\tif (!m) throw new Error(`Gauge ${name} is not registered`);\n\t\tif (m.type !== \"gauge\") throw new Error(`Metric ${name} is a ${m.type}, not a gauge`);\n\t\treturn m.impl as unknown as Gauge;\n\t}\n\n\t/** Return a histogram by name. */\n\tgetHistogram(name: string): Histogram {\n\t\tconst m = this.metrics.get(name);\n\t\tif (!m) throw new Error(`Histogram ${name} is not registered`);\n\t\tif (m.type !== \"histogram\") throw new Error(`Metric ${name} is a ${m.type}, not a histogram`);\n\t\treturn m.impl as unknown as Histogram;\n\t}\n\n\t/** Return a summary by name. */\n\tgetSummary(name: string): Summary {\n\t\tconst m = this.metrics.get(name);\n\t\tif (!m) throw new Error(`Summary ${name} is not registered`);\n\t\tif (m.type !== \"summary\") throw new Error(`Metric ${name} is a ${m.type}, not a summary`);\n\t\treturn m.impl as unknown as Summary;\n\t}\n\n\t/** Number of registered metrics. */\n\tget size(): number {\n\t\treturn this.metrics.size;\n\t}\n\n\t/** Names of all registered metrics, sorted. */\n\tnames(): string[] {\n\t\treturn [...this.metrics.keys()].sort();\n\t}\n\n\t/** Reset all metrics (clear values). */\n\tresetAll(): void {\n\t\tfor (const m of this.metrics.values()) {\n\t\t\tm.impl.reset();\n\t\t}\n\t}\n\n\t/** Serialize all metrics to the requested exposition format. */\n\texpose(format: ExpositionFormat = \"prometheus\"): ExpositionResult {\n\t\tconst sections: string[] = [];\n\t\tconst globalLabelsStr = renderGlobalLabels(this.globalLabels);\n\n\t\tfor (const m of this.metrics.values()) {\n\t\t\tconst out = m.impl.renderPrometheus();\n\t\t\tif (globalLabelsStr) {\n\t\t\t\tsections.push(applyGlobalLabels(out, this.globalLabels));\n\t\t\t} else {\n\t\t\t\tsections.push(out);\n\t\t\t}\n\t\t}\n\n\t\tconst body = sections.filter((s) => s.length > 0).join(\"\\n\\n\");\n\t\tconst contentType =\n\t\t\tformat === \"openmetrics\"\n\t\t\t\t? \"application/openmetrics-text; version=1.0.0; charset=utf-8\"\n\t\t\t\t: \"text/plain; version=0.0.4; charset=utf-8\";\n\t\treturn { body: body + (body.endsWith(\"\\n\") ? \"\" : \"\\n\"), contentType };\n\t}\n}\n\nfunction renderGlobalLabels(labels: Record<string, string>): string {\n\tconst keys = Object.keys(labels);\n\tif (keys.length === 0) return \"\";\n\treturn keys.map((k) => `${k}=\"${labels[k]}\"`).join(\",\");\n}\n\nfunction applyGlobalLabels(block: string, labels: Record<string, string>): string {\n\tconst keys = Object.keys(labels);\n\tif (keys.length === 0) return block;\n\tconst prefix = keys.map((k) => `${k}=\"${labels[k]}\"`).join(\",\");\n\treturn block\n\t\t.split(\"\\n\")\n\t\t.map((line) => {\n\t\t\tif (line.startsWith(\"#\")) return line;\n\t\t\tconst openBrace = line.indexOf(\"{\");\n\t\t\tif (openBrace === -1) {\n\t\t\t\tconst space = line.indexOf(\" \");\n\t\t\t\tif (space === -1) return line;\n\t\t\t\tconst metric = line.slice(0, space);\n\t\t\t\tconst rest = line.slice(space);\n\t\t\t\treturn `${metric}{${prefix}}${rest}`;\n\t\t\t}\n\t\t\tconst closeBrace = line.indexOf(\"}\", openBrace);\n\t\t\tif (closeBrace === -1) return line;\n\t\t\tconst existing = line.slice(openBrace + 1, closeBrace);\n\t\t\treturn `${line.slice(0, openBrace + 1)}${prefix},${existing}${line.slice(closeBrace)}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n",
10
10
  "/**\n * `MetricsService` — DI-friendly facade over `MetricsRegistry`.\n *\n * The service is always available; you can call `counter()`,\n * `gauge()`, `histogram()`, `summary()` at any time. Registered\n * metrics live for the lifetime of the application.\n *\n * Default Node.js process metrics are registered when\n * `MetricsModule.forRoot({ enableDefaultMetrics: true })` is\n * called. Without `forRoot()`, the service is fully functional\n * but no default metrics are registered.\n */\n\nimport { MetricsRegistry } from \"./registry.js\";\nimport type {\n\tCounter,\n\tCounterOptions,\n\tExpositionFormat,\n\tExpositionResult,\n\tGauge,\n\tGaugeOptions,\n\tHistogram,\n\tHistogramOptions,\n\tSummary,\n\tSummaryOptions,\n} from \"./types.js\";\n\nexport const METRICS_SERVICE_TOKEN = Symbol.for(\"nexus:MetricsService\");\n\n/**\n * Global registry of the active `MetricsService` instance.\n * Set by `MetricsModule.forRoot()`. Read by `@Counted()` and\n * `@Timed()` decorators.\n */\nlet _current: MetricsService | undefined;\n\nexport function setMetricsService(service: MetricsService): void {\n\t_current = service;\n}\n\nexport function getMetricsService(): MetricsService | undefined {\n\treturn _current;\n}\n\nexport class MetricsService {\n\treadonly registry: MetricsRegistry = new MetricsRegistry();\n\n\t/* ---------------- factory methods ---------------- */\n\n\tcounter(opts: CounterOptions): Counter {\n\t\treturn this.registry.registerCounter(opts);\n\t}\n\n\tgauge(opts: GaugeOptions): Gauge {\n\t\treturn this.registry.registerGauge(opts);\n\t}\n\n\thistogram(opts: HistogramOptions): Histogram {\n\t\treturn this.registry.registerHistogram(opts);\n\t}\n\n\tsummary(opts: SummaryOptions): Summary {\n\t\treturn this.registry.registerSummary(opts);\n\t}\n\n\t/* ---------------- lookup ---------------- */\n\n\tgetCounter(name: string): Counter {\n\t\treturn this.registry.getCounter(name);\n\t}\n\n\t/**\n\t * Get an existing counter or create a new one with the given\n\t * label names. Used by the `@Counted()` decorator.\n\t */\n\tgetOrCreateCounter(name: string, help: string | undefined, labelNames: string[] | undefined): Counter {\n\t\ttry {\n\t\t\treturn this.registry.getCounter(name);\n\t\t} catch {\n\t\t\treturn this.registry.registerCounter({ name, help, labelNames });\n\t\t}\n\t}\n\n\t/**\n\t * Get an existing histogram or create a new one. Used by the\n\t * `@Timed()` decorator.\n\t */\n\tgetOrCreateHistogram(name: string, help: string | undefined, labelNames: string[] | undefined, buckets: number[] | undefined): Histogram {\n\t\ttry {\n\t\t\treturn this.registry.getHistogram(name);\n\t\t} catch {\n\t\t\treturn this.registry.registerHistogram({ name, help, labelNames, buckets });\n\t\t}\n\t}\n\n\tgetGauge(name: string): Gauge {\n\t\treturn this.registry.getGauge(name);\n\t}\n\n\tgetHistogram(name: string): Histogram {\n\t\treturn this.registry.getHistogram(name);\n\t}\n\n\tgetSummary(name: string): Summary {\n\t\treturn this.registry.getSummary(name);\n\t}\n\n\t/* ---------------- exposition ---------------- */\n\n\texpose(format: ExpositionFormat = \"prometheus\"): ExpositionResult {\n\t\treturn this.registry.expose(format);\n\t}\n\n\t/** Number of registered metrics. */\n\tget size(): number {\n\t\treturn this.registry.size;\n\t}\n}\n",
11
- "/**\n * `MetricsModule` — wires up the metrics service into the DI\n * container, registers default Node.js process metrics, and mounts\n * the `GET /metrics` controller.\n *\n * Usage:\n * @Module({\n * imports: [\n * MetricsModule.forRoot({\n * enableDefaultMetrics: true,\n * path: \"/metrics\",\n * globalLabels: { service: \"my-app\" },\n * }),\n * ],\n * })\n * class AppModule {}\n *\n * Without `forRoot()`, `MetricsService` is still available (it's\n * a no-op-friendly singleton), but no metrics are pre-registered\n * and the controller is not mounted. Apps can register their own\n * metrics and mount the controller manually.\n */\n\nimport { Module } from \"@nexusts/core/decorators/module.js\";\nimport { MetricsService, METRICS_SERVICE_TOKEN } from \"./service.js\";\nimport { MetricsController } from \"./controller.js\";\nimport type { MetricsConfig } from \"./types.js\";\n\n@Module({\n\tproviders: [\n\t\tMetricsService,\n\t\t{ provide: METRICS_SERVICE_TOKEN, useExisting: MetricsService },\n\t],\n\texports: [MetricsService, METRICS_SERVICE_TOKEN],\n})\nexport class MetricsModule {\n\tstatic forRoot(config: MetricsConfig = {}) {\n\t\tconst fullConfig: Required<MetricsConfig> = {\n\t\t\tdefaultBuckets: config.defaultBuckets ?? [],\n\t\t\tdefaultPercentiles: config.defaultPercentiles ?? [],\n\t\t\tpath: config.path ?? \"/metrics\",\n\t\t\tenableDefaultMetrics: config.enableDefaultMetrics ?? true,\n\t\t\tmountController: config.mountController ?? true,\n\t\t\tglobalLabels: config.globalLabels ?? {},\n\t\t};\n\n\t\t@Module({\n\t\t\tproviders: [\n\t\t\t\tMetricsService,\n\t\t\t\t{ provide: METRICS_SERVICE_TOKEN, useExisting: MetricsService },\n\t\t\t\t{ provide: \"METRICS_CONFIG\", useValue: fullConfig },\n\t\t\t],\n\t\t\texports: [MetricsService, METRICS_SERVICE_TOKEN, \"METRICS_CONFIG\"],\n\t\t})\n\t\tclass ConfiguredMetricsModule {\n\t\t\tconstructor(private svc: MetricsService = new MetricsService()) {\n\t\t\t\tif (Object.keys(fullConfig.globalLabels).length > 0) {\n\t\t\t\t\tsvc.registry.setGlobalLabels(fullConfig.globalLabels);\n\t\t\t\t}\n\t\t\t\tif (fullConfig.enableDefaultMetrics) {\n\t\t\t\t\tregisterDefaultMetrics(svc);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic get path(): string {\n\t\t\t\treturn fullConfig.path;\n\t\t\t}\n\n\t\t\tstatic get service(): MetricsService {\n\t\t\t\treturn new MetricsService();\n\t\t\t}\n\n\t\t\tstatic get controllerPath(): string {\n\t\t\t\treturn fullConfig.path;\n\t\t\t}\n\t\t}\n\t\tObject.defineProperty(ConfiguredMetricsModule, \"name\", {\n\t\t\tvalue: \"ConfiguredMetricsModule\",\n\t\t});\n\n\t\t// Attach helpers as static methods on the module class.\n\t\t(ConfiguredMetricsModule as unknown as { mount: (app: unknown, service: MetricsService) => void }).mount = (\n\t\t\tapp: unknown,\n\t\t\tservice: MetricsService,\n\t\t) => {\n\t\t\tMetricsController.mount(\n\t\t\t\tapp as { get: (path: string, ...handlers: unknown[]) => unknown },\n\t\t\t\tservice,\n\t\t\t\tfullConfig.path,\n\t\t\t);\n\t\t};\n\n\t\treturn ConfiguredMetricsModule as unknown as typeof MetricsModule & {\n\t\t\tmount: (app: unknown, service: MetricsService) => void;\n\t\t\tpath: string;\n\t\t\tcontrollerPath: string;\n\t\t\tservice: MetricsService;\n\t\t};\n\t}\n}\n\n/* ------------------------------------------------------------------ *\n * Default Node.js process metrics\n * ------------------------------------------------------------------ */\n\nfunction registerDefaultMetrics(service: MetricsService): void {\n\t// Process metrics\n\tconst processStartTime = service.gauge({\n\t\tname: \"process_start_time_seconds\",\n\t\thelp: \"Start time of the process since unix epoch in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tprocessStartTime.set(Math.floor(Date.now() / 1000));\n\t\t},\n\t});\n\n\tconst processResidentMemory = service.gauge({\n\t\tname: \"process_resident_memory_bytes\",\n\t\thelp: \"Resident memory size in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessResidentMemory.set(mem.rss);\n\t\t},\n\t});\n\n\tconst processHeapUsed = service.gauge({\n\t\tname: \"nodejs_heap_size_used_bytes\",\n\t\thelp: \"Node.js heap size used in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessHeapUsed.set(mem.heapUsed);\n\t\t},\n\t});\n\n\tconst processHeapTotal = service.gauge({\n\t\tname: \"nodejs_heap_size_total_bytes\",\n\t\thelp: \"Node.js heap size total in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessHeapTotal.set(mem.heapTotal);\n\t\t},\n\t});\n\n\tconst processExternalMemory = service.gauge({\n\t\tname: \"nodejs_external_memory_bytes\",\n\t\thelp: \"Node.js external memory size in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessExternalMemory.set(mem.external);\n\t\t},\n\t});\n\n\tconst processCpuUser = service.gauge({\n\t\tname: \"process_cpu_user_seconds_total\",\n\t\thelp: \"Total user CPU time spent in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst cpu = process.cpuUsage();\n\t\t\tprocessCpuUser.set(cpu.user / 1_000_000);\n\t\t},\n\t});\n\n\tconst processCpuSystem = service.gauge({\n\t\tname: \"process_cpu_system_seconds_total\",\n\t\thelp: \"Total system CPU time spent in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst cpu = process.cpuUsage();\n\t\t\tprocessCpuSystem.set(cpu.system / 1_000_000);\n\t\t},\n\t});\n\n\tconst eventLoopLag = service.gauge({\n\t\tname: \"nodejs_eventloop_lag_seconds\",\n\t\thelp: \"Lag of the event loop in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\t// Sample event loop lag using a setImmediate.\n\t\t\tconst start = process.hrtime.bigint();\n\t\t\tsetImmediate(() => {\n\t\t\t\tconst lagNs = Number(process.hrtime.bigint() - start);\n\t\t\t\teventLoopLag.set(lagNs / 1e9);\n\t\t\t});\n\t\t},\n\t});\n\n\tconst processActiveHandles = service.gauge({\n\t\tname: \"nodejs_active_handles_total\",\n\t\thelp: \"Number of active handles.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\t// @ts-ignore - Bun may or may not expose this\n\t\t\tconst handles = (process as any)._getActiveHandles?.() ?? [];\n\t\t\tprocessActiveHandles.set(handles.length);\n\t\t},\n\t});\n\n\tconst processActiveRequests = service.gauge({\n\t\tname: \"nodejs_active_requests_total\",\n\t\thelp: \"Number of active requests.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\t// @ts-ignore - Bun may or may not expose this\n\t\t\tconst reqs = (process as any)._getActiveRequests?.() ?? [];\n\t\t\tprocessActiveRequests.set(reqs.length);\n\t\t},\n\t});\n\n\t// Touch all gauges to make sure they're eagerly evaluated once\n\tvoid processStartTime;\n\tvoid processResidentMemory;\n\tvoid processHeapUsed;\n\tvoid processHeapTotal;\n\tvoid processExternalMemory;\n\tvoid processCpuUser;\n\tvoid processCpuSystem;\n\tvoid eventLoopLag;\n\tvoid processActiveHandles;\n\tvoid processActiveRequests;\n}\n",
11
+ "/**\n * `MetricsModule` — wires up the metrics service into the DI\n * container, registers default Node.js process metrics, and mounts\n * the `GET /metrics` controller.\n *\n * Usage:\n * @Module({\n * imports: [\n * MetricsModule.forRoot({\n * enableDefaultMetrics: true,\n * path: \"/metrics\",\n * globalLabels: { service: \"my-app\" },\n * }),\n * ],\n * })\n * class AppModule {}\n *\n * Without `forRoot()`, `MetricsService` is still available (it's\n * a no-op-friendly singleton), but no metrics are pre-registered\n * and the controller is not mounted. Apps can register their own\n * metrics and mount the controller manually.\n */\n\nimport { Module } from \"@nexusts/core\";\nimport { MetricsService, METRICS_SERVICE_TOKEN } from \"./service.js\";\nimport { MetricsController } from \"./controller.js\";\nimport type { MetricsConfig } from \"./types.js\";\n\n@Module({\n\tproviders: [\n\t\tMetricsService,\n\t\t{ provide: METRICS_SERVICE_TOKEN, useExisting: MetricsService },\n\t],\n\texports: [MetricsService, METRICS_SERVICE_TOKEN],\n})\nexport class MetricsModule {\n\tstatic forRoot(config: MetricsConfig = {}) {\n\t\tconst fullConfig: Required<MetricsConfig> = {\n\t\t\tdefaultBuckets: config.defaultBuckets ?? [],\n\t\t\tdefaultPercentiles: config.defaultPercentiles ?? [],\n\t\t\tpath: config.path ?? \"/metrics\",\n\t\t\tenableDefaultMetrics: config.enableDefaultMetrics ?? true,\n\t\t\tmountController: config.mountController ?? true,\n\t\t\tglobalLabels: config.globalLabels ?? {},\n\t\t};\n\n\t\t@Module({\n\t\t\tproviders: [\n\t\t\t\tMetricsService,\n\t\t\t\t{ provide: METRICS_SERVICE_TOKEN, useExisting: MetricsService },\n\t\t\t\t{ provide: \"METRICS_CONFIG\", useValue: fullConfig },\n\t\t\t],\n\t\t\texports: [MetricsService, METRICS_SERVICE_TOKEN, \"METRICS_CONFIG\"],\n\t\t})\n\t\tclass ConfiguredMetricsModule {\n\t\t\tconstructor(private svc: MetricsService = new MetricsService()) {\n\t\t\t\tif (Object.keys(fullConfig.globalLabels).length > 0) {\n\t\t\t\t\tsvc.registry.setGlobalLabels(fullConfig.globalLabels);\n\t\t\t\t}\n\t\t\t\tif (fullConfig.enableDefaultMetrics) {\n\t\t\t\t\tregisterDefaultMetrics(svc);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic get path(): string {\n\t\t\t\treturn fullConfig.path;\n\t\t\t}\n\n\t\t\tstatic get service(): MetricsService {\n\t\t\t\treturn new MetricsService();\n\t\t\t}\n\n\t\t\tstatic get controllerPath(): string {\n\t\t\t\treturn fullConfig.path;\n\t\t\t}\n\t\t}\n\t\tObject.defineProperty(ConfiguredMetricsModule, \"name\", {\n\t\t\tvalue: \"ConfiguredMetricsModule\",\n\t\t});\n\n\t\t// Attach helpers as static methods on the module class.\n\t\t(ConfiguredMetricsModule as unknown as { mount: (app: unknown, service: MetricsService) => void }).mount = (\n\t\t\tapp: unknown,\n\t\t\tservice: MetricsService,\n\t\t) => {\n\t\t\tMetricsController.mount(\n\t\t\t\tapp as { get: (path: string, ...handlers: unknown[]) => unknown },\n\t\t\t\tservice,\n\t\t\t\tfullConfig.path,\n\t\t\t);\n\t\t};\n\n\t\treturn ConfiguredMetricsModule as unknown as typeof MetricsModule & {\n\t\t\tmount: (app: unknown, service: MetricsService) => void;\n\t\t\tpath: string;\n\t\t\tcontrollerPath: string;\n\t\t\tservice: MetricsService;\n\t\t};\n\t}\n}\n\n/* ------------------------------------------------------------------ *\n * Default Node.js process metrics\n * ------------------------------------------------------------------ */\n\nfunction registerDefaultMetrics(service: MetricsService): void {\n\t// Process metrics\n\tconst processStartTime = service.gauge({\n\t\tname: \"process_start_time_seconds\",\n\t\thelp: \"Start time of the process since unix epoch in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tprocessStartTime.set(Math.floor(Date.now() / 1000));\n\t\t},\n\t});\n\n\tconst processResidentMemory = service.gauge({\n\t\tname: \"process_resident_memory_bytes\",\n\t\thelp: \"Resident memory size in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessResidentMemory.set(mem.rss);\n\t\t},\n\t});\n\n\tconst processHeapUsed = service.gauge({\n\t\tname: \"nodejs_heap_size_used_bytes\",\n\t\thelp: \"Node.js heap size used in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessHeapUsed.set(mem.heapUsed);\n\t\t},\n\t});\n\n\tconst processHeapTotal = service.gauge({\n\t\tname: \"nodejs_heap_size_total_bytes\",\n\t\thelp: \"Node.js heap size total in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessHeapTotal.set(mem.heapTotal);\n\t\t},\n\t});\n\n\tconst processExternalMemory = service.gauge({\n\t\tname: \"nodejs_external_memory_bytes\",\n\t\thelp: \"Node.js external memory size in bytes.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst mem = process.memoryUsage();\n\t\t\tprocessExternalMemory.set(mem.external);\n\t\t},\n\t});\n\n\tconst processCpuUser = service.gauge({\n\t\tname: \"process_cpu_user_seconds_total\",\n\t\thelp: \"Total user CPU time spent in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst cpu = process.cpuUsage();\n\t\t\tprocessCpuUser.set(cpu.user / 1_000_000);\n\t\t},\n\t});\n\n\tconst processCpuSystem = service.gauge({\n\t\tname: \"process_cpu_system_seconds_total\",\n\t\thelp: \"Total system CPU time spent in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\tconst cpu = process.cpuUsage();\n\t\t\tprocessCpuSystem.set(cpu.system / 1_000_000);\n\t\t},\n\t});\n\n\tconst eventLoopLag = service.gauge({\n\t\tname: \"nodejs_eventloop_lag_seconds\",\n\t\thelp: \"Lag of the event loop in seconds.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\t// Sample event loop lag using a setImmediate.\n\t\t\tconst start = process.hrtime.bigint();\n\t\t\tsetImmediate(() => {\n\t\t\t\tconst lagNs = Number(process.hrtime.bigint() - start);\n\t\t\t\teventLoopLag.set(lagNs / 1e9);\n\t\t\t});\n\t\t},\n\t});\n\n\tconst processActiveHandles = service.gauge({\n\t\tname: \"nodejs_active_handles_total\",\n\t\thelp: \"Number of active handles.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\t// @ts-ignore - Bun may or may not expose this\n\t\t\tconst handles = (process as any)._getActiveHandles?.() ?? [];\n\t\t\tprocessActiveHandles.set(handles.length);\n\t\t},\n\t});\n\n\tconst processActiveRequests = service.gauge({\n\t\tname: \"nodejs_active_requests_total\",\n\t\thelp: \"Number of active requests.\",\n\t\tlabelNames: [],\n\t\tcollect: () => {\n\t\t\t// @ts-ignore - Bun may or may not expose this\n\t\t\tconst reqs = (process as any)._getActiveRequests?.() ?? [];\n\t\t\tprocessActiveRequests.set(reqs.length);\n\t\t},\n\t});\n\n\t// Touch all gauges to make sure they're eagerly evaluated once\n\tvoid processStartTime;\n\tvoid processResidentMemory;\n\tvoid processHeapUsed;\n\tvoid processHeapTotal;\n\tvoid processExternalMemory;\n\tvoid processCpuUser;\n\tvoid processCpuSystem;\n\tvoid eventLoopLag;\n\tvoid processActiveHandles;\n\tvoid processActiveRequests;\n}\n",
12
12
  "/**\n * `MetricsController` — exposes `GET /metrics` for Prometheus\n * scrapers. Supports content negotiation: the response format is\n * `text/plain` (Prometheus 0.0.4) by default, or\n * `application/openmetrics-text` if the request asks for it.\n *\n * The controller is auto-mounted by `MetricsModule.forRoot()`. If\n * you want to mount it manually (e.g. on a different path), call\n * `MetricsController.handler(service)` and wire it up yourself.\n */\n\nimport type { Context } from \"hono\";\nimport type { MetricsService } from \"./service.js\";\n\nexport class MetricsController {\n\tstatic readonly PATH = \"/metrics\";\n\n\t/**\n\t * Returns a Hono handler that serves the /metrics endpoint.\n\t *\n\t * @example\n\t * app.get(\"/metrics\", MetricsController.handler(svc));\n\t */\n\tstatic handler(service: MetricsService) {\n\t\treturn (c: Context) => {\n\t\t\tconst accept = c.req.header(\"accept\") ?? \"\";\n\t\t\tconst format = accept.includes(\"application/openmetrics-text\") ? \"openmetrics\" : \"prometheus\";\n\t\t\tconst { contentType, body } = service.expose(format);\n\t\t\treturn c.body(body, 200, {\n\t\t\t\t\"content-type\": contentType,\n\t\t\t\t\"cache-control\": \"no-store\",\n\t\t\t});\n\t\t};\n\t}\n\n\t/** Mount the controller on the given Hono app at `path`. */\n\tstatic mount(app: { get: (path: string, ...handlers: unknown[]) => unknown }, service: MetricsService, path: string = MetricsController.PATH): void {\n\t\tapp.get(path, MetricsController.handler(service));\n\t}\n}",
13
13
  "/**\n * `@Counted()` — class-method decorator that increments a counter\n * on each call.\n *\n * Usage:\n * class UserController {\n * @Counted('http_requests_total', { labels: () => ({ method: 'GET' }) })\n * list() { ... }\n * }\n *\n * The decorator reads the `MetricsService` from the global registry\n * (set by `MetricsModule.forRoot()`). When no service is registered\n * the decorator is a pass-through.\n */\n\nimport { getMetricsService } from \"../service.js\";\n\nexport interface CountedOptions {\n\t/** Optional label values, computed at call time. */\n\tlabels?: () => Record<string, string>;\n}\n\n/**\n * Method decorator: increment a counter on each invocation.\n *\n * The counter is registered lazily the first time the method is\n * called, using the service from the global registry.\n */\nexport function Counted(metricName: string, options: CountedOptions = {}) {\n\treturn function (_target: object, _propertyKey: string | symbol, descriptor: PropertyDescriptor) {\n\t\tconst original = descriptor.value as (...args: unknown[]) => unknown;\n\t\tif (typeof original !== \"function\") {\n\t\t\tthrow new Error(`@Counted() can only be applied to methods, got ${typeof original}`);\n\t\t}\n\n\t\tconst isAsync = (original as any).constructor?.name === \"AsyncFunction\";\n\n\t\tif (isAsync) {\n\t\t\tdescriptor.value = async function wrapped(this: unknown, ...args: unknown[]) {\n\t\t\t\tconst svc = getMetricsService();\n\t\t\t\tif (svc) {\n\t\t\t\t\tconst labels = options.labels?.();\n\t\t\t\t\tsvc.getOrCreateCounter(\n\t\t\t\t\t\tmetricName,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tlabels ? Object.keys(labels) : undefined,\n\t\t\t\t\t).inc(labels);\n\t\t\t\t}\n\t\t\t\treturn original.apply(this, args);\n\t\t\t};\n\t\t} else {\n\t\t\tdescriptor.value = function wrapped(this: unknown, ...args: unknown[]) {\n\t\t\t\tconst svc = getMetricsService();\n\t\t\t\tif (svc) {\n\t\t\t\t\tconst labels = options.labels?.();\n\t\t\t\t\tsvc.getOrCreateCounter(\n\t\t\t\t\t\tmetricName,\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\tlabels ? Object.keys(labels) : undefined,\n\t\t\t\t\t).inc(labels);\n\t\t\t\t}\n\t\t\t\treturn original.apply(this, args);\n\t\t\t};\n\t\t}\n\t\treturn descriptor;\n\t};\n}",
14
14
  "/**\n * `@Timed()` — class-method decorator that records a method's\n * duration in a histogram.\n *\n * Usage:\n * class UserController {\n * @Timed('http_request_duration_seconds', { labels: () => ({ method: 'GET' }) })\n * list() { ... }\n * }\n *\n * The decorator reads the `MetricsService` from the global registry.\n * When no service is registered the decorator is a pass-through.\n */\n\nimport { getMetricsService } from \"../service.js\";\n\nexport interface TimedOptions {\n\t/** Optional buckets override. */\n\tbuckets?: number[];\n\t/** Optional label values, computed at call time. */\n\tlabels?: () => Record<string, string>;\n}\n\n/**\n * Method decorator: observe a method's duration (in seconds) in a\n * histogram. Async methods are timed across their full await.\n */\nexport function Timed(metricName: string, options: TimedOptions = {}) {\n\treturn function (_target: object, _propertyKey: string | symbol, descriptor: PropertyDescriptor) {\n\t\tconst original = descriptor.value as (...args: unknown[]) => unknown;\n\t\tif (typeof original !== \"function\") {\n\t\t\tthrow new Error(`@Timed() can only be applied to methods, got ${typeof original}`);\n\t\t}\n\n\t\tconst isAsync = (original as any).constructor?.name === \"AsyncFunction\";\n\n\t\tif (isAsync) {\n\t\t\tdescriptor.value = async function wrapped(this: unknown, ...args: unknown[]) {\n\t\t\t\tconst svc = getMetricsService();\n\t\t\t\tconst start = performance.now();\n\t\t\t\ttry {\n\t\t\t\t\treturn await original.apply(this, args);\n\t\t\t\t} finally {\n\t\t\t\t\tif (svc) {\n\t\t\t\t\t\tconst elapsedMs = performance.now() - start;\n\t\t\t\t\t\tconst labels = options.labels?.();\n\t\t\t\t\t\tsvc.getOrCreateHistogram(\n\t\t\t\t\t\t\tmetricName,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tlabels ? Object.keys(labels) : undefined,\n\t\t\t\t\t\t\toptions.buckets,\n\t\t\t\t\t\t).observe(elapsedMs / 1000, labels);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t} else {\n\t\t\tdescriptor.value = function wrapped(this: unknown, ...args: unknown[]) {\n\t\t\t\tconst svc = getMetricsService();\n\t\t\t\tconst start = performance.now();\n\t\t\t\ttry {\n\t\t\t\t\treturn original.apply(this, args);\n\t\t\t\t} finally {\n\t\t\t\t\tif (svc) {\n\t\t\t\t\t\tconst elapsedMs = performance.now() - start;\n\t\t\t\t\t\tconst labels = options.labels?.();\n\t\t\t\t\t\tsvc.getOrCreateHistogram(\n\t\t\t\t\t\t\tmetricName,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tlabels ? Object.keys(labels) : undefined,\n\t\t\t\t\t\t\toptions.buckets,\n\t\t\t\t\t\t).observe(elapsedMs / 1000, labels);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\treturn descriptor;\n\t};\n}\n"
15
15
  ],
16
16
  "mappings": "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",
17
- "debugId": "FBFB8DC36D7055E964756E2164756E21",
17
+ "debugId": "CF072CA419117E5264756E2164756E21",
18
18
  "names": []
19
19
  }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `MetricsModule` — wires up the metrics service into the DI
3
+ * container, registers default Node.js process metrics, and mounts
4
+ * the `GET /metrics` controller.
5
+ *
6
+ * Usage:
7
+ * @Module({
8
+ * imports: [
9
+ * MetricsModule.forRoot({
10
+ * enableDefaultMetrics: true,
11
+ * path: "/metrics",
12
+ * globalLabels: { service: "my-app" },
13
+ * }),
14
+ * ],
15
+ * })
16
+ * class AppModule {}
17
+ *
18
+ * Without `forRoot()`, `MetricsService` is still available (it's
19
+ * a no-op-friendly singleton), but no metrics are pre-registered
20
+ * and the controller is not mounted. Apps can register their own
21
+ * metrics and mount the controller manually.
22
+ */
23
+ import { MetricsService } from "./service.js";
24
+ import type { MetricsConfig } from "./types.js";
25
+ export declare class MetricsModule {
26
+ static forRoot(config?: MetricsConfig): typeof MetricsModule & {
27
+ mount: (app: unknown, service: MetricsService) => void;
28
+ path: string;
29
+ controllerPath: string;
30
+ service: MetricsService;
31
+ };
32
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `MetricsRegistry` — collection of all metrics registered in the app.
3
+ *
4
+ * The registry is the source of truth for `MetricsService`. It:
5
+ * - Holds every metric (counter / gauge / histogram / summary) by name.
6
+ * - Serializes them to the Prometheus text exposition format.
7
+ * - Supports content negotiation (OpenMetrics vs. Prometheus).
8
+ *
9
+ * Each metric is stored as a unified `RegisteredMetric` so the
10
+ * registry can iterate and call `renderPrometheus()` on each.
11
+ */
12
+ import type { Counter, CounterOptions, ExpositionFormat, ExpositionResult, Gauge, GaugeOptions, Histogram, HistogramOptions, Summary, SummaryOptions } from "./types.js";
13
+ interface RegisteredMetric {
14
+ name: string;
15
+ type: "counter" | "gauge" | "histogram" | "summary";
16
+ impl: {
17
+ renderPrometheus(): string;
18
+ reset(): void;
19
+ };
20
+ }
21
+ export declare class MetricsRegistry {
22
+ private metrics;
23
+ private globalLabels;
24
+ /** Add a global label that's prepended to every metric line. */
25
+ setGlobalLabels(labels: Record<string, string>): void;
26
+ getGlobalLabels(): Record<string, string>;
27
+ /** Register a counter; returns the same instance for chaining. */
28
+ registerCounter(opts: CounterOptions): Counter;
29
+ registerGauge(opts: GaugeOptions): Gauge;
30
+ registerHistogram(opts: HistogramOptions): Histogram;
31
+ registerSummary(opts: SummaryOptions): Summary;
32
+ /** Return a metric by name, regardless of type. */
33
+ get(name: string): RegisteredMetric | undefined;
34
+ /** Return a counter by name. Throws if it isn't a counter. */
35
+ getCounter(name: string): Counter;
36
+ /** Return a gauge by name. */
37
+ getGauge(name: string): Gauge;
38
+ /** Return a histogram by name. */
39
+ getHistogram(name: string): Histogram;
40
+ /** Return a summary by name. */
41
+ getSummary(name: string): Summary;
42
+ /** Number of registered metrics. */
43
+ get size(): number;
44
+ /** Names of all registered metrics, sorted. */
45
+ names(): string[];
46
+ /** Reset all metrics (clear values). */
47
+ resetAll(): void;
48
+ /** Serialize all metrics to the requested exposition format. */
49
+ expose(format?: ExpositionFormat): ExpositionResult;
50
+ }
51
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `MetricsService` — DI-friendly facade over `MetricsRegistry`.
3
+ *
4
+ * The service is always available; you can call `counter()`,
5
+ * `gauge()`, `histogram()`, `summary()` at any time. Registered
6
+ * metrics live for the lifetime of the application.
7
+ *
8
+ * Default Node.js process metrics are registered when
9
+ * `MetricsModule.forRoot({ enableDefaultMetrics: true })` is
10
+ * called. Without `forRoot()`, the service is fully functional
11
+ * but no default metrics are registered.
12
+ */
13
+ import { MetricsRegistry } from "./registry.js";
14
+ import type { Counter, CounterOptions, ExpositionFormat, ExpositionResult, Gauge, GaugeOptions, Histogram, HistogramOptions, Summary, SummaryOptions } from "./types.js";
15
+ export declare const METRICS_SERVICE_TOKEN: unique symbol;
16
+ export declare function setMetricsService(service: MetricsService): void;
17
+ export declare function getMetricsService(): MetricsService | undefined;
18
+ export declare class MetricsService {
19
+ readonly registry: MetricsRegistry;
20
+ counter(opts: CounterOptions): Counter;
21
+ gauge(opts: GaugeOptions): Gauge;
22
+ histogram(opts: HistogramOptions): Histogram;
23
+ summary(opts: SummaryOptions): Summary;
24
+ getCounter(name: string): Counter;
25
+ /**
26
+ * Get an existing counter or create a new one with the given
27
+ * label names. Used by the `@Counted()` decorator.
28
+ */
29
+ getOrCreateCounter(name: string, help: string | undefined, labelNames: string[] | undefined): Counter;
30
+ /**
31
+ * Get an existing histogram or create a new one. Used by the
32
+ * `@Timed()` decorator.
33
+ */
34
+ getOrCreateHistogram(name: string, help: string | undefined, labelNames: string[] | undefined, buckets: number[] | undefined): Histogram;
35
+ getGauge(name: string): Gauge;
36
+ getHistogram(name: string): Histogram;
37
+ getSummary(name: string): Summary;
38
+ expose(format?: ExpositionFormat): ExpositionResult;
39
+ /** Number of registered metrics. */
40
+ get size(): number;
41
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * `Summary` — quantile estimation over a sliding window of values.
3
+ *
4
+ * Summary is similar to Histogram but computes client-side quantiles
5
+ * (via t-digest-style sorting). It's useful when you need a small
6
+ * number of percentiles (50/90/99) without the storage cost of
7
+ * histograms.
8
+ *
9
+ * Quantile computation uses a simple sorted-window approach: each
10
+ * label combination keeps a circular buffer of the last N values.
11
+ *
12
+ * Example:
13
+ * const s = new Summary({
14
+ * name: "http_request_size_bytes",
15
+ * percentiles: [0.5, 0.9, 0.99],
16
+ * });
17
+ * s.observe(1024);
18
+ */
19
+ import type { SummaryOptions, Summary as ISummary, MetricSample } from "./types.js";
20
+ /** Default percentiles. */
21
+ export declare const DEFAULT_PERCENTILES: number[];
22
+ /** Default sliding window size. */
23
+ export declare const DEFAULT_MAX_AGE_SECONDS = 600;
24
+ export declare const DEFAULT_AGE_BUCKETS = 5;
25
+ export declare class SummaryImpl implements ISummary {
26
+ readonly name: string;
27
+ readonly help?: string;
28
+ readonly labelNames: string[];
29
+ private readonly percentiles;
30
+ private readonly maxAgeSeconds;
31
+ private readonly ageBuckets;
32
+ private readonly bucketSize;
33
+ /** Map from "label1=v1,label2=v2" -> state. */
34
+ private states;
35
+ constructor(opts: SummaryOptions);
36
+ observe(value: number, labels?: Record<string, string>): void;
37
+ time<T>(fn: () => Promise<T> | T, labels?: Record<string, string>): Promise<T>;
38
+ reset(): void;
39
+ getSamples(): MetricSample[];
40
+ /** Render this summary in Prometheus exposition format. */
41
+ renderPrometheus(): string;
42
+ private newState;
43
+ private maybeRotate;
44
+ private totals;
45
+ private quantile;
46
+ private assertLabels;
47
+ private key;
48
+ private parseKey;
49
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Public types for `nexusjs/metrics`.
3
+ *
4
+ * `nexusjs/metrics` is a Prometheus-compatible metrics collection
5
+ * library. It implements the four standard metric types (counter,
6
+ * gauge, histogram, summary), label support, and the Prometheus /
7
+ * OpenMetrics text exposition formats.
8
+ *
9
+ * No external dependencies. ~5kb gzipped.
10
+ */
11
+ /** A single sample recorded against a metric. */
12
+ export interface MetricSample {
13
+ /** Optional label values. The keys must match the metric's `labelNames`. */
14
+ labels?: Record<string, string>;
15
+ /** Numeric value. */
16
+ value: number;
17
+ /** Optional timestamp (epoch ms). */
18
+ timestamp?: number;
19
+ }
20
+ export interface CounterOptions {
21
+ /** Human-readable metric name (e.g. "http_requests_total"). */
22
+ name: string;
23
+ /** Help text shown in /metrics. */
24
+ help?: string;
25
+ /** Label names (dimensions). Order is significant. */
26
+ labelNames?: string[];
27
+ }
28
+ export interface Counter {
29
+ /** Read-only metric name. */
30
+ readonly name: string;
31
+ /** Increment by 1. */
32
+ inc(labels?: Record<string, string>): void;
33
+ /** Increment by `n` (must be >= 0). */
34
+ incBy(n: number, labels?: Record<string, string>): void;
35
+ /** Reset to 0. */
36
+ reset(): void;
37
+ /** Return all samples. */
38
+ getSamples(): MetricSample[];
39
+ }
40
+ export interface GaugeOptions {
41
+ name: string;
42
+ help?: string;
43
+ labelNames?: string[];
44
+ /** Optional collect() callback for time-varying values. */
45
+ collect?: () => void;
46
+ }
47
+ export interface Gauge {
48
+ readonly name: string;
49
+ /** Set the value. */
50
+ set(value: number, labels?: Record<string, string>): void;
51
+ /** Increment by `n` (can be negative). */
52
+ inc(n?: number, labels?: Record<string, string>): void;
53
+ /** Decrement by `n` (defaults to 1). */
54
+ dec(n?: number, labels?: Record<string, string>): void;
55
+ /** Set the value to current unix epoch seconds. */
56
+ setToCurrentTime(labels?: Record<string, string>): void;
57
+ reset(): void;
58
+ getSamples(): MetricSample[];
59
+ }
60
+ export interface HistogramOptions {
61
+ name: string;
62
+ help?: string;
63
+ labelNames?: string[];
64
+ /** Bucket upper bounds. Default: Prometheus default. */
65
+ buckets?: number[];
66
+ }
67
+ export interface Histogram {
68
+ readonly name: string;
69
+ /** Observe a value. */
70
+ observe(value: number, labels?: Record<string, string>): void;
71
+ /** Time an async function and observe its duration in seconds. */
72
+ time<T>(fn: (start: number) => Promise<T> | T, labels?: Record<string, string>): Promise<T>;
73
+ reset(): void;
74
+ getSamples(): MetricSample[];
75
+ }
76
+ export interface SummaryOptions {
77
+ name: string;
78
+ help?: string;
79
+ labelNames?: string[];
80
+ /** Percentiles to compute. Default: [0.5, 0.9, 0.99]. */
81
+ percentiles?: number[];
82
+ /** Max number of samples to keep per label combination. Default: 100. */
83
+ maxAgeSeconds?: number;
84
+ /** Number of buckets for sliding window. Default: 5. */
85
+ ageBuckets?: number;
86
+ }
87
+ export interface Summary {
88
+ readonly name: string;
89
+ observe(value: number, labels?: Record<string, string>): void;
90
+ time<T>(fn: () => Promise<T> | T, labels?: Record<string, string>): Promise<T>;
91
+ reset(): void;
92
+ getSamples(): MetricSample[];
93
+ }
94
+ export interface MetricsConfig {
95
+ /** Default histogram buckets. Default: Prometheus default. */
96
+ defaultBuckets?: number[];
97
+ /** Default summary percentiles. Default: [0.5, 0.9, 0.99]. */
98
+ defaultPercentiles?: number[];
99
+ /** Mount path for the /metrics endpoint. Default: "/metrics". */
100
+ path?: string;
101
+ /** Whether to collect default Node.js process metrics. Default: true. */
102
+ enableDefaultMetrics?: boolean;
103
+ /** Whether to auto-mount the controller. Default: true. */
104
+ mountController?: boolean;
105
+ /** Custom labels added to every metric. */
106
+ globalLabels?: Record<string, string>;
107
+ }
108
+ export type ExpositionFormat = "prometheus" | "openmetrics";
109
+ export interface ExpositionResult {
110
+ /** Content type for the HTTP response. */
111
+ contentType: string;
112
+ /** Body. */
113
+ body: string;
114
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexusts/metrics",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Prometheus / OpenMetrics counters and gauges",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -12,20 +12,15 @@
12
12
  "import": "./dist/index.js"
13
13
  }
14
14
  },
15
- "files": [
16
- "dist",
17
- "README.md"
18
- ],
15
+ "files": ["dist", "README.md"],
19
16
  "scripts": {
20
17
  "build": "bun run ../../build.ts"
21
18
  },
22
- "keywords": [
23
- "nexusts",
24
- "framework",
25
- "bun"
26
- ],
19
+ "keywords": ["nexusts", "framework", "bun"],
27
20
  "license": "MIT",
21
+
22
+
28
23
  "dependencies": {
29
- "@nexusts/core": "^0.7.0"
24
+ "@nexusts/core": "file:../core"
30
25
  }
31
26
  }