@firebreak/vitals 1.0.2 → 1.1.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.
@@ -34,7 +34,6 @@ __export(redis_exports, {
34
34
  ioredisClientCheck: () => ioredisClientCheck
35
35
  });
36
36
  module.exports = __toCommonJS(redis_exports);
37
- var import_node_perf_hooks = require("perf_hooks");
38
37
 
39
38
  // src/types.ts
40
39
  var Status = {
@@ -46,7 +45,6 @@ var Status = {
46
45
  // src/checks/redis.ts
47
46
  function ioredisCheck(url, options) {
48
47
  return async () => {
49
- const start = import_node_perf_hooks.performance.now();
50
48
  const { default: RedisClient } = await import("ioredis");
51
49
  const client = new RedisClient(url, {
52
50
  lazyConnect: true,
@@ -60,12 +58,10 @@ function ioredisCheck(url, options) {
60
58
  if (result !== "PONG") {
61
59
  throw new Error(`PING returned ${result}`);
62
60
  }
63
- const latencyMs = Math.round(import_node_perf_hooks.performance.now() - start);
64
- return { status: Status.HEALTHY, latencyMs, message: "" };
61
+ return { status: Status.HEALTHY, message: "" };
65
62
  } catch (error) {
66
- const latencyMs = Math.round(import_node_perf_hooks.performance.now() - start);
67
63
  const message = error instanceof Error ? error.message : String(error);
68
- return { status: Status.OUTAGE, latencyMs, message };
64
+ return { status: Status.OUTAGE, message };
69
65
  } finally {
70
66
  client.disconnect();
71
67
  }
@@ -73,18 +69,15 @@ function ioredisCheck(url, options) {
73
69
  }
74
70
  function ioredisClientCheck(client) {
75
71
  return async () => {
76
- const start = import_node_perf_hooks.performance.now();
77
72
  try {
78
73
  const result = await client.ping();
79
74
  if (result !== "PONG") {
80
75
  throw new Error(`PING returned ${result}`);
81
76
  }
82
- const latencyMs = Math.round(import_node_perf_hooks.performance.now() - start);
83
- return { status: Status.HEALTHY, latencyMs, message: "" };
77
+ return { status: Status.HEALTHY, message: "" };
84
78
  } catch (error) {
85
- const latencyMs = Math.round(import_node_perf_hooks.performance.now() - start);
86
79
  const message = error instanceof Error ? error.message : String(error);
87
- return { status: Status.OUTAGE, latencyMs, message };
80
+ return { status: Status.OUTAGE, message };
88
81
  }
89
82
  };
90
83
  }
@@ -1,4 +1,4 @@
1
- import { A as AsyncCheckFn } from '../core-9-MXAO0I.cjs';
1
+ import { A as AsyncCheckFn } from '../core-BJ2Z0rRi.cjs';
2
2
  import Redis from 'ioredis';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { A as AsyncCheckFn } from '../core-9-MXAO0I.js';
1
+ import { A as AsyncCheckFn } from '../core-BJ2Z0rRi.js';
2
2
  import Redis from 'ioredis';
3
3
 
4
4
  /**
@@ -1,6 +1,3 @@
1
- // src/checks/redis.ts
2
- import { performance } from "perf_hooks";
3
-
4
1
  // src/types.ts
5
2
  var Status = {
6
3
  HEALTHY: 2,
@@ -11,7 +8,6 @@ var Status = {
11
8
  // src/checks/redis.ts
12
9
  function ioredisCheck(url, options) {
13
10
  return async () => {
14
- const start = performance.now();
15
11
  const { default: RedisClient } = await import("ioredis");
16
12
  const client = new RedisClient(url, {
17
13
  lazyConnect: true,
@@ -25,12 +21,10 @@ function ioredisCheck(url, options) {
25
21
  if (result !== "PONG") {
26
22
  throw new Error(`PING returned ${result}`);
27
23
  }
28
- const latencyMs = Math.round(performance.now() - start);
29
- return { status: Status.HEALTHY, latencyMs, message: "" };
24
+ return { status: Status.HEALTHY, message: "" };
30
25
  } catch (error) {
31
- const latencyMs = Math.round(performance.now() - start);
32
26
  const message = error instanceof Error ? error.message : String(error);
33
- return { status: Status.OUTAGE, latencyMs, message };
27
+ return { status: Status.OUTAGE, message };
34
28
  } finally {
35
29
  client.disconnect();
36
30
  }
@@ -38,18 +32,15 @@ function ioredisCheck(url, options) {
38
32
  }
39
33
  function ioredisClientCheck(client) {
40
34
  return async () => {
41
- const start = performance.now();
42
35
  try {
43
36
  const result = await client.ping();
44
37
  if (result !== "PONG") {
45
38
  throw new Error(`PING returned ${result}`);
46
39
  }
47
- const latencyMs = Math.round(performance.now() - start);
48
- return { status: Status.HEALTHY, latencyMs, message: "" };
40
+ return { status: Status.HEALTHY, message: "" };
49
41
  } catch (error) {
50
- const latencyMs = Math.round(performance.now() - start);
51
42
  const message = error instanceof Error ? error.message : String(error);
52
- return { status: Status.OUTAGE, latencyMs, message };
43
+ return { status: Status.OUTAGE, message };
53
44
  }
54
45
  };
55
46
  }
@@ -7,6 +7,16 @@ type StatusValue = (typeof Status)[keyof typeof Status];
7
7
  type StatusLabel = 'healthy' | 'degraded' | 'outage';
8
8
  declare function statusToLabel(status: StatusValue): StatusLabel;
9
9
  declare function statusFromString(value: string): StatusValue;
10
+ /**
11
+ * What a check function returns. `latencyMs` is optional because the registry
12
+ * always measures wall-clock latency and overwrites this value.
13
+ */
14
+ interface CheckInput {
15
+ readonly status: StatusValue;
16
+ readonly latencyMs?: number;
17
+ readonly message: string;
18
+ }
19
+ /** The final result stored per-check after the registry measures latency. */
10
20
  interface CheckResult {
11
21
  readonly status: StatusValue;
12
22
  readonly latencyMs: number;
@@ -29,8 +39,8 @@ interface HealthcheckResponseJson {
29
39
  declare function toJson(response: HealthcheckResponse): HealthcheckResponseJson;
30
40
  declare function httpStatusCode(status: StatusValue): 200 | 503;
31
41
 
32
- type AsyncCheckFn = () => Promise<CheckResult>;
33
- type SyncCheckFn = () => CheckResult;
42
+ type AsyncCheckFn = () => Promise<CheckInput>;
43
+ type SyncCheckFn = () => CheckInput;
34
44
  interface RegistryOptions {
35
45
  defaultTimeout?: number;
36
46
  }
@@ -52,4 +62,4 @@ declare class HealthcheckRegistry {
52
62
  }
53
63
  declare function syncCheck(fn: SyncCheckFn): AsyncCheckFn;
54
64
 
55
- export { type AsyncCheckFn as A, type CheckResult as C, HealthcheckRegistry as H, Status as S, type HealthcheckResponse as a, type HealthcheckResponseJson as b, type StatusLabel as c, type StatusValue as d, type SyncCheckFn as e, statusToLabel as f, syncCheck as g, httpStatusCode as h, statusFromString as s, toJson as t };
65
+ export { type AsyncCheckFn as A, type CheckInput as C, HealthcheckRegistry as H, Status as S, type CheckResult as a, type HealthcheckResponse as b, type HealthcheckResponseJson as c, type StatusLabel as d, type StatusValue as e, type SyncCheckFn as f, statusToLabel as g, httpStatusCode as h, syncCheck as i, statusFromString as s, toJson as t };
@@ -7,6 +7,16 @@ type StatusValue = (typeof Status)[keyof typeof Status];
7
7
  type StatusLabel = 'healthy' | 'degraded' | 'outage';
8
8
  declare function statusToLabel(status: StatusValue): StatusLabel;
9
9
  declare function statusFromString(value: string): StatusValue;
10
+ /**
11
+ * What a check function returns. `latencyMs` is optional because the registry
12
+ * always measures wall-clock latency and overwrites this value.
13
+ */
14
+ interface CheckInput {
15
+ readonly status: StatusValue;
16
+ readonly latencyMs?: number;
17
+ readonly message: string;
18
+ }
19
+ /** The final result stored per-check after the registry measures latency. */
10
20
  interface CheckResult {
11
21
  readonly status: StatusValue;
12
22
  readonly latencyMs: number;
@@ -29,8 +39,8 @@ interface HealthcheckResponseJson {
29
39
  declare function toJson(response: HealthcheckResponse): HealthcheckResponseJson;
30
40
  declare function httpStatusCode(status: StatusValue): 200 | 503;
31
41
 
32
- type AsyncCheckFn = () => Promise<CheckResult>;
33
- type SyncCheckFn = () => CheckResult;
42
+ type AsyncCheckFn = () => Promise<CheckInput>;
43
+ type SyncCheckFn = () => CheckInput;
34
44
  interface RegistryOptions {
35
45
  defaultTimeout?: number;
36
46
  }
@@ -52,4 +62,4 @@ declare class HealthcheckRegistry {
52
62
  }
53
63
  declare function syncCheck(fn: SyncCheckFn): AsyncCheckFn;
54
64
 
55
- export { type AsyncCheckFn as A, type CheckResult as C, HealthcheckRegistry as H, Status as S, type HealthcheckResponse as a, type HealthcheckResponseJson as b, type StatusLabel as c, type StatusValue as d, type SyncCheckFn as e, statusToLabel as f, syncCheck as g, httpStatusCode as h, statusFromString as s, toJson as t };
65
+ export { type AsyncCheckFn as A, type CheckInput as C, HealthcheckRegistry as H, Status as S, type CheckResult as a, type HealthcheckResponse as b, type HealthcheckResponseJson as c, type StatusLabel as d, type StatusValue as e, type SyncCheckFn as f, statusToLabel as g, httpStatusCode as h, syncCheck as i, statusFromString as s, toJson as t };
@@ -0,0 +1,25 @@
1
+ import { H as HealthcheckRegistry, c as HealthcheckResponseJson } from './core-BJ2Z0rRi.cjs';
2
+
3
+ interface HealthcheckHandlerOptions {
4
+ registry: HealthcheckRegistry;
5
+ token?: string | null;
6
+ queryParamName?: string;
7
+ }
8
+ interface HealthcheckRequest {
9
+ queryParams?: Record<string, string | string[] | undefined>;
10
+ authorizationHeader?: string | null;
11
+ }
12
+ interface HealthcheckHandlerResult {
13
+ status: number;
14
+ body: HealthcheckResponseJson | {
15
+ error: string;
16
+ };
17
+ }
18
+ /**
19
+ * Framework-agnostic healthcheck handler. Takes a simple request object
20
+ * and returns a status code + JSON body. Framework integrations (Express,
21
+ * Next.js, etc.) are thin wrappers around this function.
22
+ */
23
+ declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: HealthcheckRequest) => Promise<HealthcheckHandlerResult>;
24
+
25
+ export { type HealthcheckHandlerOptions as H, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
@@ -0,0 +1,25 @@
1
+ import { H as HealthcheckRegistry, c as HealthcheckResponseJson } from './core-BJ2Z0rRi.js';
2
+
3
+ interface HealthcheckHandlerOptions {
4
+ registry: HealthcheckRegistry;
5
+ token?: string | null;
6
+ queryParamName?: string;
7
+ }
8
+ interface HealthcheckRequest {
9
+ queryParams?: Record<string, string | string[] | undefined>;
10
+ authorizationHeader?: string | null;
11
+ }
12
+ interface HealthcheckHandlerResult {
13
+ status: number;
14
+ body: HealthcheckResponseJson | {
15
+ error: string;
16
+ };
17
+ }
18
+ /**
19
+ * Framework-agnostic healthcheck handler. Takes a simple request object
20
+ * and returns a status code + JSON body. Framework integrations (Express,
21
+ * Next.js, etc.) are thin wrappers around this function.
22
+ */
23
+ declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: HealthcheckRequest) => Promise<HealthcheckHandlerResult>;
24
+
25
+ export { type HealthcheckHandlerOptions as H, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  HealthcheckRegistry: () => HealthcheckRegistry,
24
24
  Status: () => Status,
25
+ createHealthcheckHandler: () => createHealthcheckHandler,
25
26
  extractToken: () => extractToken,
26
27
  httpStatusCode: () => httpStatusCode,
27
28
  statusFromString: () => statusFromString,
@@ -186,10 +187,33 @@ function extractToken(options) {
186
187
  }
187
188
  return null;
188
189
  }
190
+
191
+ // src/handler.ts
192
+ function createHealthcheckHandler(options) {
193
+ const { registry, token = null, queryParamName = "token" } = options;
194
+ return async (req) => {
195
+ if (token !== null) {
196
+ const provided = extractToken({
197
+ queryParams: req.queryParams,
198
+ authorizationHeader: req.authorizationHeader,
199
+ queryParamName
200
+ });
201
+ if (provided === null || !verifyToken(provided, token)) {
202
+ return { status: 403, body: { error: "Forbidden" } };
203
+ }
204
+ }
205
+ const response = await registry.run();
206
+ return {
207
+ status: httpStatusCode(response.status),
208
+ body: toJson(response)
209
+ };
210
+ };
211
+ }
189
212
  // Annotate the CommonJS export names for ESM import in node:
190
213
  0 && (module.exports = {
191
214
  HealthcheckRegistry,
192
215
  Status,
216
+ createHealthcheckHandler,
193
217
  extractToken,
194
218
  httpStatusCode,
195
219
  statusFromString,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
- export { A as AsyncCheckFn, C as CheckResult, H as HealthcheckRegistry, a as HealthcheckResponse, b as HealthcheckResponseJson, S as Status, c as StatusLabel, d as StatusValue, e as SyncCheckFn, h as httpStatusCode, s as statusFromString, f as statusToLabel, g as syncCheck, t as toJson } from './core-9-MXAO0I.cjs';
1
+ export { A as AsyncCheckFn, C as CheckInput, a as CheckResult, H as HealthcheckRegistry, b as HealthcheckResponse, c as HealthcheckResponseJson, S as Status, d as StatusLabel, e as StatusValue, f as SyncCheckFn, h as httpStatusCode, s as statusFromString, g as statusToLabel, i as syncCheck, t as toJson } from './core-BJ2Z0rRi.cjs';
2
+ export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, b as HealthcheckRequest, c as createHealthcheckHandler } from './handler-Bccbso4b.cjs';
2
3
 
3
4
  declare function verifyToken(provided: string, expected: string): boolean;
4
5
  declare function extractToken(options: {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { A as AsyncCheckFn, C as CheckResult, H as HealthcheckRegistry, a as HealthcheckResponse, b as HealthcheckResponseJson, S as Status, c as StatusLabel, d as StatusValue, e as SyncCheckFn, h as httpStatusCode, s as statusFromString, f as statusToLabel, g as syncCheck, t as toJson } from './core-9-MXAO0I.js';
1
+ export { A as AsyncCheckFn, C as CheckInput, a as CheckResult, H as HealthcheckRegistry, b as HealthcheckResponse, c as HealthcheckResponseJson, S as Status, d as StatusLabel, e as StatusValue, f as SyncCheckFn, h as httpStatusCode, s as statusFromString, g as statusToLabel, i as syncCheck, t as toJson } from './core-BJ2Z0rRi.js';
2
+ export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, b as HealthcheckRequest, c as createHealthcheckHandler } from './handler-D0nYVQvu.js';
2
3
 
3
4
  declare function verifyToken(provided: string, expected: string): boolean;
4
5
  declare function extractToken(options: {
package/dist/index.mjs CHANGED
@@ -152,9 +152,32 @@ function extractToken(options) {
152
152
  }
153
153
  return null;
154
154
  }
155
+
156
+ // src/handler.ts
157
+ function createHealthcheckHandler(options) {
158
+ const { registry, token = null, queryParamName = "token" } = options;
159
+ return async (req) => {
160
+ if (token !== null) {
161
+ const provided = extractToken({
162
+ queryParams: req.queryParams,
163
+ authorizationHeader: req.authorizationHeader,
164
+ queryParamName
165
+ });
166
+ if (provided === null || !verifyToken(provided, token)) {
167
+ return { status: 403, body: { error: "Forbidden" } };
168
+ }
169
+ }
170
+ const response = await registry.run();
171
+ return {
172
+ status: httpStatusCode(response.status),
173
+ body: toJson(response)
174
+ };
175
+ };
176
+ }
155
177
  export {
156
178
  HealthcheckRegistry,
157
179
  Status,
180
+ createHealthcheckHandler,
158
181
  extractToken,
159
182
  httpStatusCode,
160
183
  statusFromString,
@@ -76,24 +76,38 @@ function httpStatusCode(status) {
76
76
  return status === Status.HEALTHY ? 200 : 503;
77
77
  }
78
78
 
79
+ // src/handler.ts
80
+ function createHealthcheckHandler(options) {
81
+ const { registry, token = null, queryParamName = "token" } = options;
82
+ return async (req) => {
83
+ if (token !== null) {
84
+ const provided = extractToken({
85
+ queryParams: req.queryParams,
86
+ authorizationHeader: req.authorizationHeader,
87
+ queryParamName
88
+ });
89
+ if (provided === null || !verifyToken(provided, token)) {
90
+ return { status: 403, body: { error: "Forbidden" } };
91
+ }
92
+ }
93
+ const response = await registry.run();
94
+ return {
95
+ status: httpStatusCode(response.status),
96
+ body: toJson(response)
97
+ };
98
+ };
99
+ }
100
+
79
101
  // src/integrations/express.ts
80
102
  function createHealthcheckMiddleware(options) {
81
- const { registry, token = null, queryParamName = "token" } = options;
103
+ const handle = createHealthcheckHandler(options);
82
104
  return async (req, res) => {
83
105
  try {
84
- if (token !== null) {
85
- const provided = extractToken({
86
- queryParams: req.query,
87
- authorizationHeader: req.headers.authorization ?? null,
88
- queryParamName
89
- });
90
- if (provided === null || !verifyToken(provided, token)) {
91
- res.status(403).json({ error: "Forbidden" });
92
- return;
93
- }
94
- }
95
- const response = await registry.run();
96
- res.status(httpStatusCode(response.status)).json(toJson(response));
106
+ const result = await handle({
107
+ queryParams: req.query,
108
+ authorizationHeader: req.headers.authorization ?? null
109
+ });
110
+ res.status(result.status).json(result.body);
97
111
  } catch {
98
112
  res.status(500).json({ error: "Internal Server Error" });
99
113
  }
@@ -1,11 +1,8 @@
1
1
  import { RequestHandler } from 'express';
2
- import { H as HealthcheckRegistry } from '../core-9-MXAO0I.cjs';
2
+ import { H as HealthcheckHandlerOptions } from '../handler-Bccbso4b.cjs';
3
+ import '../core-BJ2Z0rRi.cjs';
3
4
 
4
- interface HealthcheckMiddlewareOptions {
5
- registry: HealthcheckRegistry;
6
- token?: string | null;
7
- queryParamName?: string;
8
- }
5
+ type HealthcheckMiddlewareOptions = HealthcheckHandlerOptions;
9
6
  declare function createHealthcheckMiddleware(options: HealthcheckMiddlewareOptions): RequestHandler;
10
7
 
11
8
  export { type HealthcheckMiddlewareOptions, createHealthcheckMiddleware };
@@ -1,11 +1,8 @@
1
1
  import { RequestHandler } from 'express';
2
- import { H as HealthcheckRegistry } from '../core-9-MXAO0I.js';
2
+ import { H as HealthcheckHandlerOptions } from '../handler-D0nYVQvu.js';
3
+ import '../core-BJ2Z0rRi.js';
3
4
 
4
- interface HealthcheckMiddlewareOptions {
5
- registry: HealthcheckRegistry;
6
- token?: string | null;
7
- queryParamName?: string;
8
- }
5
+ type HealthcheckMiddlewareOptions = HealthcheckHandlerOptions;
9
6
  declare function createHealthcheckMiddleware(options: HealthcheckMiddlewareOptions): RequestHandler;
10
7
 
11
8
  export { type HealthcheckMiddlewareOptions, createHealthcheckMiddleware };
@@ -50,24 +50,38 @@ function httpStatusCode(status) {
50
50
  return status === Status.HEALTHY ? 200 : 503;
51
51
  }
52
52
 
53
+ // src/handler.ts
54
+ function createHealthcheckHandler(options) {
55
+ const { registry, token = null, queryParamName = "token" } = options;
56
+ return async (req) => {
57
+ if (token !== null) {
58
+ const provided = extractToken({
59
+ queryParams: req.queryParams,
60
+ authorizationHeader: req.authorizationHeader,
61
+ queryParamName
62
+ });
63
+ if (provided === null || !verifyToken(provided, token)) {
64
+ return { status: 403, body: { error: "Forbidden" } };
65
+ }
66
+ }
67
+ const response = await registry.run();
68
+ return {
69
+ status: httpStatusCode(response.status),
70
+ body: toJson(response)
71
+ };
72
+ };
73
+ }
74
+
53
75
  // src/integrations/express.ts
54
76
  function createHealthcheckMiddleware(options) {
55
- const { registry, token = null, queryParamName = "token" } = options;
77
+ const handle = createHealthcheckHandler(options);
56
78
  return async (req, res) => {
57
79
  try {
58
- if (token !== null) {
59
- const provided = extractToken({
60
- queryParams: req.query,
61
- authorizationHeader: req.headers.authorization ?? null,
62
- queryParamName
63
- });
64
- if (provided === null || !verifyToken(provided, token)) {
65
- res.status(403).json({ error: "Forbidden" });
66
- return;
67
- }
68
- }
69
- const response = await registry.run();
70
- res.status(httpStatusCode(response.status)).json(toJson(response));
80
+ const result = await handle({
81
+ queryParams: req.query,
82
+ authorizationHeader: req.headers.authorization ?? null
83
+ });
84
+ res.status(result.status).json(result.body);
71
85
  } catch {
72
86
  res.status(500).json({ error: "Internal Server Error" });
73
87
  }
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/integrations/next.ts
21
+ var next_exports = {};
22
+ __export(next_exports, {
23
+ createNextHandler: () => createNextHandler
24
+ });
25
+ module.exports = __toCommonJS(next_exports);
26
+
27
+ // src/auth.ts
28
+ var import_node_crypto = require("crypto");
29
+ function verifyToken(provided, expected) {
30
+ if (!provided || !expected) return false;
31
+ const providedHash = (0, import_node_crypto.createHash)("sha256").update(provided).digest();
32
+ const expectedHash = (0, import_node_crypto.createHash)("sha256").update(expected).digest();
33
+ return (0, import_node_crypto.timingSafeEqual)(providedHash, expectedHash);
34
+ }
35
+ function extractToken(options) {
36
+ const { queryParams, authorizationHeader, queryParamName = "token" } = options;
37
+ if (queryParams) {
38
+ const value = queryParams[queryParamName];
39
+ const str = Array.isArray(value) ? value[0] : value;
40
+ if (str) return str;
41
+ }
42
+ if (authorizationHeader?.startsWith("Bearer ")) {
43
+ const token = authorizationHeader.slice("Bearer ".length);
44
+ if (token) return token;
45
+ }
46
+ return null;
47
+ }
48
+
49
+ // src/types.ts
50
+ var Status = {
51
+ HEALTHY: 2,
52
+ DEGRADED: 1,
53
+ OUTAGE: 0
54
+ };
55
+ function statusToLabel(status) {
56
+ const labels = {
57
+ [Status.HEALTHY]: "healthy",
58
+ [Status.DEGRADED]: "degraded",
59
+ [Status.OUTAGE]: "outage"
60
+ };
61
+ return labels[status];
62
+ }
63
+ function toJson(response) {
64
+ return {
65
+ status: statusToLabel(response.status),
66
+ timestamp: response.timestamp,
67
+ checks: Object.fromEntries(
68
+ Object.entries(response.checks).map(([name, result]) => [
69
+ name,
70
+ { status: statusToLabel(result.status), latencyMs: result.latencyMs, message: result.message }
71
+ ])
72
+ )
73
+ };
74
+ }
75
+ function httpStatusCode(status) {
76
+ return status === Status.HEALTHY ? 200 : 503;
77
+ }
78
+
79
+ // src/handler.ts
80
+ function createHealthcheckHandler(options) {
81
+ const { registry, token = null, queryParamName = "token" } = options;
82
+ return async (req) => {
83
+ if (token !== null) {
84
+ const provided = extractToken({
85
+ queryParams: req.queryParams,
86
+ authorizationHeader: req.authorizationHeader,
87
+ queryParamName
88
+ });
89
+ if (provided === null || !verifyToken(provided, token)) {
90
+ return { status: 403, body: { error: "Forbidden" } };
91
+ }
92
+ }
93
+ const response = await registry.run();
94
+ return {
95
+ status: httpStatusCode(response.status),
96
+ body: toJson(response)
97
+ };
98
+ };
99
+ }
100
+
101
+ // src/integrations/next.ts
102
+ function createNextHandler(options) {
103
+ const handle = createHealthcheckHandler(options);
104
+ return async (request) => {
105
+ try {
106
+ const url = new URL(request.url);
107
+ const queryParams = Object.fromEntries(url.searchParams);
108
+ const result = await handle({
109
+ queryParams,
110
+ authorizationHeader: request.headers.get("authorization")
111
+ });
112
+ return Response.json(result.body, { status: result.status });
113
+ } catch {
114
+ return Response.json({ error: "Internal Server Error" }, { status: 500 });
115
+ }
116
+ };
117
+ }
118
+ // Annotate the CommonJS export names for ESM import in node:
119
+ 0 && (module.exports = {
120
+ createNextHandler
121
+ });
@@ -0,0 +1,24 @@
1
+ import { H as HealthcheckHandlerOptions } from '../handler-Bccbso4b.cjs';
2
+ import '../core-BJ2Z0rRi.cjs';
3
+
4
+ type NextHealthcheckOptions = HealthcheckHandlerOptions;
5
+ /**
6
+ * Creates a Next.js App Router GET handler for the healthcheck endpoint.
7
+ *
8
+ * Usage in `app/vitals/route.ts`:
9
+ * ```ts
10
+ * import { HealthcheckRegistry } from '@firebreak/vitals';
11
+ * import { createNextHandler } from '@firebreak/vitals/next';
12
+ *
13
+ * const registry = new HealthcheckRegistry();
14
+ * // ... register checks ...
15
+ *
16
+ * export const GET = createNextHandler({
17
+ * registry,
18
+ * token: process.env.VITALS_TOKEN,
19
+ * });
20
+ * ```
21
+ */
22
+ declare function createNextHandler(options: NextHealthcheckOptions): (request: Request) => Promise<Response>;
23
+
24
+ export { type NextHealthcheckOptions, createNextHandler };
@@ -0,0 +1,24 @@
1
+ import { H as HealthcheckHandlerOptions } from '../handler-D0nYVQvu.js';
2
+ import '../core-BJ2Z0rRi.js';
3
+
4
+ type NextHealthcheckOptions = HealthcheckHandlerOptions;
5
+ /**
6
+ * Creates a Next.js App Router GET handler for the healthcheck endpoint.
7
+ *
8
+ * Usage in `app/vitals/route.ts`:
9
+ * ```ts
10
+ * import { HealthcheckRegistry } from '@firebreak/vitals';
11
+ * import { createNextHandler } from '@firebreak/vitals/next';
12
+ *
13
+ * const registry = new HealthcheckRegistry();
14
+ * // ... register checks ...
15
+ *
16
+ * export const GET = createNextHandler({
17
+ * registry,
18
+ * token: process.env.VITALS_TOKEN,
19
+ * });
20
+ * ```
21
+ */
22
+ declare function createNextHandler(options: NextHealthcheckOptions): (request: Request) => Promise<Response>;
23
+
24
+ export { type NextHealthcheckOptions, createNextHandler };