@firebreak/vitals 1.3.0 → 2.0.0

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.
@@ -0,0 +1,20 @@
1
+ import { b as HealthcheckRegistry, H as HealthcheckResponseJson } from './core-Bee03bJm.js';
2
+
3
+ type ResolveDepthFn = (req: Record<string, unknown>) => 'deep' | 'shallow' | Promise<'deep' | 'shallow'>;
4
+ interface HealthcheckHandlerOptions {
5
+ registry: HealthcheckRegistry;
6
+ resolveDepth?: ResolveDepthFn;
7
+ metadata?: Record<string, string | number | boolean>;
8
+ }
9
+ interface ShallowResponseJson {
10
+ status: 'ok';
11
+ timestamp: string;
12
+ [key: string]: string | number | boolean;
13
+ }
14
+ interface HealthcheckHandlerResult {
15
+ status: number;
16
+ body: HealthcheckResponseJson | ShallowResponseJson;
17
+ }
18
+ declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: Record<string, unknown>) => Promise<HealthcheckHandlerResult>;
19
+
20
+ export { type HealthcheckHandlerOptions as H, type ResolveDepthFn as R, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, createHealthcheckHandler as c };
@@ -0,0 +1,20 @@
1
+ import { b as HealthcheckRegistry, H as HealthcheckResponseJson } from './core-Bee03bJm.cjs';
2
+
3
+ type ResolveDepthFn = (req: Record<string, unknown>) => 'deep' | 'shallow' | Promise<'deep' | 'shallow'>;
4
+ interface HealthcheckHandlerOptions {
5
+ registry: HealthcheckRegistry;
6
+ resolveDepth?: ResolveDepthFn;
7
+ metadata?: Record<string, string | number | boolean>;
8
+ }
9
+ interface ShallowResponseJson {
10
+ status: 'ok';
11
+ timestamp: string;
12
+ [key: string]: string | number | boolean;
13
+ }
14
+ interface HealthcheckHandlerResult {
15
+ status: number;
16
+ body: HealthcheckResponseJson | ShallowResponseJson;
17
+ }
18
+ declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: Record<string, unknown>) => Promise<HealthcheckHandlerResult>;
19
+
20
+ export { type HealthcheckHandlerOptions as H, type ResolveDepthFn as R, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, createHealthcheckHandler as c };
package/dist/index.cjs CHANGED
@@ -220,56 +220,36 @@ function extractToken(options) {
220
220
  // src/handler.ts
221
221
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
222
222
  function createHealthcheckHandler(options) {
223
- const { registry, token: rawToken, deep = false, queryParamName = "token", metadata = {} } = options;
224
- const isEmptyToken = typeof rawToken === "string" && rawToken.trim() === "";
225
- if (deep && isEmptyToken) {
226
- throw new Error(
227
- "Cannot use `deep: true` with an empty string token. This would expose deep healthcheck data without authentication. Either set a non-empty token or explicitly set `token: null`."
228
- );
229
- }
230
- const token = rawToken == null || isEmptyToken ? null : rawToken;
223
+ const { registry, resolveDepth, metadata = {} } = options;
231
224
  for (const key of Object.keys(metadata)) {
232
225
  if (RESERVED_METADATA_KEYS.includes(key)) {
233
226
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
234
227
  }
235
228
  }
236
229
  return async (req) => {
237
- if (token === null) {
238
- if (deep) {
239
- const response2 = await registry.run();
240
- return {
241
- status: httpStatusCode(response2.status),
242
- body: { ...metadata, ...toJson(response2) }
243
- };
230
+ let depth = "shallow";
231
+ if (resolveDepth) {
232
+ try {
233
+ const result = await resolveDepth(req);
234
+ if (result === "deep" || result === "shallow") {
235
+ depth = result;
236
+ }
237
+ } catch {
244
238
  }
245
- const body = {
246
- status: "ok",
247
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
248
- ...metadata
249
- };
250
- return { status: 200, body };
251
239
  }
252
- const provided = extractToken({
253
- queryParams: req.queryParams,
254
- authorizationHeader: req.authorizationHeader,
255
- queryParamName
256
- });
257
- if (provided === null) {
258
- const body = {
259
- status: "ok",
260
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
261
- ...metadata
240
+ if (depth === "deep") {
241
+ const response = await registry.run();
242
+ return {
243
+ status: httpStatusCode(response.status),
244
+ body: { ...metadata, ...toJson(response) }
262
245
  };
263
- return { status: 200, body };
264
- }
265
- if (!verifyToken(provided, token)) {
266
- return { status: 403, body: { error: "Forbidden" } };
267
246
  }
268
- const response = await registry.run();
269
- return {
270
- status: httpStatusCode(response.status),
271
- body: { ...metadata, ...toJson(response) }
247
+ const body = {
248
+ status: "ok",
249
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
250
+ ...metadata
272
251
  };
252
+ return { status: 200, body };
273
253
  };
274
254
  }
275
255
 
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { H as HealthcheckResponseJson } from './core-Bee03bJm.cjs';
2
2
  export { A as AsyncCheckFn, C as CheckInput, a as CheckResult, b as HealthcheckRegistry, c as HealthcheckResponse, 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-Bee03bJm.cjs';
3
- import { S as ShallowResponseJson } from './handler-COH7lot9.cjs';
4
- export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, b as HealthcheckRequest, c as createHealthcheckHandler } from './handler-COH7lot9.cjs';
3
+ import { S as ShallowResponseJson } from './handler-TZOgZvY7.cjs';
4
+ export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, R as ResolveDepthFn, c as createHealthcheckHandler } from './handler-TZOgZvY7.cjs';
5
5
 
6
6
  declare function verifyToken(provided: string, expected: string): boolean;
7
7
  declare function extractToken(options: {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { H as HealthcheckResponseJson } from './core-Bee03bJm.js';
2
2
  export { A as AsyncCheckFn, C as CheckInput, a as CheckResult, b as HealthcheckRegistry, c as HealthcheckResponse, 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-Bee03bJm.js';
3
- import { S as ShallowResponseJson } from './handler-CVYUad84.js';
4
- export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, b as HealthcheckRequest, c as createHealthcheckHandler } from './handler-CVYUad84.js';
3
+ import { S as ShallowResponseJson } from './handler-BvjN4Ot9.js';
4
+ export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, R as ResolveDepthFn, c as createHealthcheckHandler } from './handler-BvjN4Ot9.js';
5
5
 
6
6
  declare function verifyToken(provided: string, expected: string): boolean;
7
7
  declare function extractToken(options: {
package/dist/index.mjs CHANGED
@@ -184,56 +184,36 @@ function extractToken(options) {
184
184
  // src/handler.ts
185
185
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
186
186
  function createHealthcheckHandler(options) {
187
- const { registry, token: rawToken, deep = false, queryParamName = "token", metadata = {} } = options;
188
- const isEmptyToken = typeof rawToken === "string" && rawToken.trim() === "";
189
- if (deep && isEmptyToken) {
190
- throw new Error(
191
- "Cannot use `deep: true` with an empty string token. This would expose deep healthcheck data without authentication. Either set a non-empty token or explicitly set `token: null`."
192
- );
193
- }
194
- const token = rawToken == null || isEmptyToken ? null : rawToken;
187
+ const { registry, resolveDepth, metadata = {} } = options;
195
188
  for (const key of Object.keys(metadata)) {
196
189
  if (RESERVED_METADATA_KEYS.includes(key)) {
197
190
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
198
191
  }
199
192
  }
200
193
  return async (req) => {
201
- if (token === null) {
202
- if (deep) {
203
- const response2 = await registry.run();
204
- return {
205
- status: httpStatusCode(response2.status),
206
- body: { ...metadata, ...toJson(response2) }
207
- };
194
+ let depth = "shallow";
195
+ if (resolveDepth) {
196
+ try {
197
+ const result = await resolveDepth(req);
198
+ if (result === "deep" || result === "shallow") {
199
+ depth = result;
200
+ }
201
+ } catch {
208
202
  }
209
- const body = {
210
- status: "ok",
211
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
212
- ...metadata
213
- };
214
- return { status: 200, body };
215
203
  }
216
- const provided = extractToken({
217
- queryParams: req.queryParams,
218
- authorizationHeader: req.authorizationHeader,
219
- queryParamName
220
- });
221
- if (provided === null) {
222
- const body = {
223
- status: "ok",
224
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
225
- ...metadata
204
+ if (depth === "deep") {
205
+ const response = await registry.run();
206
+ return {
207
+ status: httpStatusCode(response.status),
208
+ body: { ...metadata, ...toJson(response) }
226
209
  };
227
- return { status: 200, body };
228
- }
229
- if (!verifyToken(provided, token)) {
230
- return { status: 403, body: { error: "Forbidden" } };
231
210
  }
232
- const response = await registry.run();
233
- return {
234
- status: httpStatusCode(response.status),
235
- body: { ...metadata, ...toJson(response) }
211
+ const body = {
212
+ status: "ok",
213
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
214
+ ...metadata
236
215
  };
216
+ return { status: 200, body };
237
217
  };
238
218
  }
239
219
 
@@ -24,28 +24,6 @@ __export(express_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(express_exports);
26
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
27
  // src/types.ts
50
28
  var Status = {
51
29
  HEALTHY: 2,
@@ -83,56 +61,36 @@ function httpStatusCode(status) {
83
61
  // src/handler.ts
84
62
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
85
63
  function createHealthcheckHandler(options) {
86
- const { registry, token: rawToken, deep = false, queryParamName = "token", metadata = {} } = options;
87
- const isEmptyToken = typeof rawToken === "string" && rawToken.trim() === "";
88
- if (deep && isEmptyToken) {
89
- throw new Error(
90
- "Cannot use `deep: true` with an empty string token. This would expose deep healthcheck data without authentication. Either set a non-empty token or explicitly set `token: null`."
91
- );
92
- }
93
- const token = rawToken == null || isEmptyToken ? null : rawToken;
64
+ const { registry, resolveDepth, metadata = {} } = options;
94
65
  for (const key of Object.keys(metadata)) {
95
66
  if (RESERVED_METADATA_KEYS.includes(key)) {
96
67
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
97
68
  }
98
69
  }
99
70
  return async (req) => {
100
- if (token === null) {
101
- if (deep) {
102
- const response2 = await registry.run();
103
- return {
104
- status: httpStatusCode(response2.status),
105
- body: { ...metadata, ...toJson(response2) }
106
- };
71
+ let depth = "shallow";
72
+ if (resolveDepth) {
73
+ try {
74
+ const result = await resolveDepth(req);
75
+ if (result === "deep" || result === "shallow") {
76
+ depth = result;
77
+ }
78
+ } catch {
107
79
  }
108
- const body = {
109
- status: "ok",
110
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
111
- ...metadata
112
- };
113
- return { status: 200, body };
114
80
  }
115
- const provided = extractToken({
116
- queryParams: req.queryParams,
117
- authorizationHeader: req.authorizationHeader,
118
- queryParamName
119
- });
120
- if (provided === null) {
121
- const body = {
122
- status: "ok",
123
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
124
- ...metadata
81
+ if (depth === "deep") {
82
+ const response = await registry.run();
83
+ return {
84
+ status: httpStatusCode(response.status),
85
+ body: { ...metadata, ...toJson(response) }
125
86
  };
126
- return { status: 200, body };
127
- }
128
- if (!verifyToken(provided, token)) {
129
- return { status: 403, body: { error: "Forbidden" } };
130
87
  }
131
- const response = await registry.run();
132
- return {
133
- status: httpStatusCode(response.status),
134
- body: { ...metadata, ...toJson(response) }
88
+ const body = {
89
+ status: "ok",
90
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
91
+ ...metadata
135
92
  };
93
+ return { status: 200, body };
136
94
  };
137
95
  }
138
96
 
@@ -376,6 +334,8 @@ function createHealthcheckMiddleware(options) {
376
334
  return async (req, res) => {
377
335
  try {
378
336
  const result = await handle({
337
+ ip: req.ip,
338
+ headers: req.headers,
379
339
  queryParams: req.query,
380
340
  authorizationHeader: req.headers.authorization ?? null
381
341
  });
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from 'express';
2
- import { H as HealthcheckHandlerOptions } from '../handler-COH7lot9.cjs';
2
+ import { H as HealthcheckHandlerOptions } from '../handler-TZOgZvY7.cjs';
3
3
  import '../core-Bee03bJm.cjs';
4
4
 
5
5
  type HealthcheckMiddlewareOptions = HealthcheckHandlerOptions;
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from 'express';
2
- import { H as HealthcheckHandlerOptions } from '../handler-CVYUad84.js';
2
+ import { H as HealthcheckHandlerOptions } from '../handler-BvjN4Ot9.js';
3
3
  import '../core-Bee03bJm.js';
4
4
 
5
5
  type HealthcheckMiddlewareOptions = HealthcheckHandlerOptions;
@@ -1,25 +1,3 @@
1
- // src/auth.ts
2
- import { createHash, timingSafeEqual } from "crypto";
3
- function verifyToken(provided, expected) {
4
- if (!provided || !expected) return false;
5
- const providedHash = createHash("sha256").update(provided).digest();
6
- const expectedHash = createHash("sha256").update(expected).digest();
7
- return timingSafeEqual(providedHash, expectedHash);
8
- }
9
- function extractToken(options) {
10
- const { queryParams, authorizationHeader, queryParamName = "token" } = options;
11
- if (queryParams) {
12
- const value = queryParams[queryParamName];
13
- const str = Array.isArray(value) ? value[0] : value;
14
- if (str) return str;
15
- }
16
- if (authorizationHeader?.startsWith("Bearer ")) {
17
- const token = authorizationHeader.slice("Bearer ".length);
18
- if (token) return token;
19
- }
20
- return null;
21
- }
22
-
23
1
  // src/types.ts
24
2
  var Status = {
25
3
  HEALTHY: 2,
@@ -57,56 +35,36 @@ function httpStatusCode(status) {
57
35
  // src/handler.ts
58
36
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
59
37
  function createHealthcheckHandler(options) {
60
- const { registry, token: rawToken, deep = false, queryParamName = "token", metadata = {} } = options;
61
- const isEmptyToken = typeof rawToken === "string" && rawToken.trim() === "";
62
- if (deep && isEmptyToken) {
63
- throw new Error(
64
- "Cannot use `deep: true` with an empty string token. This would expose deep healthcheck data without authentication. Either set a non-empty token or explicitly set `token: null`."
65
- );
66
- }
67
- const token = rawToken == null || isEmptyToken ? null : rawToken;
38
+ const { registry, resolveDepth, metadata = {} } = options;
68
39
  for (const key of Object.keys(metadata)) {
69
40
  if (RESERVED_METADATA_KEYS.includes(key)) {
70
41
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
71
42
  }
72
43
  }
73
44
  return async (req) => {
74
- if (token === null) {
75
- if (deep) {
76
- const response2 = await registry.run();
77
- return {
78
- status: httpStatusCode(response2.status),
79
- body: { ...metadata, ...toJson(response2) }
80
- };
45
+ let depth = "shallow";
46
+ if (resolveDepth) {
47
+ try {
48
+ const result = await resolveDepth(req);
49
+ if (result === "deep" || result === "shallow") {
50
+ depth = result;
51
+ }
52
+ } catch {
81
53
  }
82
- const body = {
83
- status: "ok",
84
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
85
- ...metadata
86
- };
87
- return { status: 200, body };
88
54
  }
89
- const provided = extractToken({
90
- queryParams: req.queryParams,
91
- authorizationHeader: req.authorizationHeader,
92
- queryParamName
93
- });
94
- if (provided === null) {
95
- const body = {
96
- status: "ok",
97
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
98
- ...metadata
55
+ if (depth === "deep") {
56
+ const response = await registry.run();
57
+ return {
58
+ status: httpStatusCode(response.status),
59
+ body: { ...metadata, ...toJson(response) }
99
60
  };
100
- return { status: 200, body };
101
- }
102
- if (!verifyToken(provided, token)) {
103
- return { status: 403, body: { error: "Forbidden" } };
104
61
  }
105
- const response = await registry.run();
106
- return {
107
- status: httpStatusCode(response.status),
108
- body: { ...metadata, ...toJson(response) }
62
+ const body = {
63
+ status: "ok",
64
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
65
+ ...metadata
109
66
  };
67
+ return { status: 200, body };
110
68
  };
111
69
  }
112
70
 
@@ -350,6 +308,8 @@ function createHealthcheckMiddleware(options) {
350
308
  return async (req, res) => {
351
309
  try {
352
310
  const result = await handle({
311
+ ip: req.ip,
312
+ headers: req.headers,
353
313
  queryParams: req.query,
354
314
  authorizationHeader: req.headers.authorization ?? null
355
315
  });
@@ -24,28 +24,6 @@ __export(next_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(next_exports);
26
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
27
  // src/types.ts
50
28
  var Status = {
51
29
  HEALTHY: 2,
@@ -83,56 +61,36 @@ function httpStatusCode(status) {
83
61
  // src/handler.ts
84
62
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
85
63
  function createHealthcheckHandler(options) {
86
- const { registry, token: rawToken, deep = false, queryParamName = "token", metadata = {} } = options;
87
- const isEmptyToken = typeof rawToken === "string" && rawToken.trim() === "";
88
- if (deep && isEmptyToken) {
89
- throw new Error(
90
- "Cannot use `deep: true` with an empty string token. This would expose deep healthcheck data without authentication. Either set a non-empty token or explicitly set `token: null`."
91
- );
92
- }
93
- const token = rawToken == null || isEmptyToken ? null : rawToken;
64
+ const { registry, resolveDepth, metadata = {} } = options;
94
65
  for (const key of Object.keys(metadata)) {
95
66
  if (RESERVED_METADATA_KEYS.includes(key)) {
96
67
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
97
68
  }
98
69
  }
99
70
  return async (req) => {
100
- if (token === null) {
101
- if (deep) {
102
- const response2 = await registry.run();
103
- return {
104
- status: httpStatusCode(response2.status),
105
- body: { ...metadata, ...toJson(response2) }
106
- };
71
+ let depth = "shallow";
72
+ if (resolveDepth) {
73
+ try {
74
+ const result = await resolveDepth(req);
75
+ if (result === "deep" || result === "shallow") {
76
+ depth = result;
77
+ }
78
+ } catch {
107
79
  }
108
- const body = {
109
- status: "ok",
110
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
111
- ...metadata
112
- };
113
- return { status: 200, body };
114
80
  }
115
- const provided = extractToken({
116
- queryParams: req.queryParams,
117
- authorizationHeader: req.authorizationHeader,
118
- queryParamName
119
- });
120
- if (provided === null) {
121
- const body = {
122
- status: "ok",
123
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
124
- ...metadata
81
+ if (depth === "deep") {
82
+ const response = await registry.run();
83
+ return {
84
+ status: httpStatusCode(response.status),
85
+ body: { ...metadata, ...toJson(response) }
125
86
  };
126
- return { status: 200, body };
127
- }
128
- if (!verifyToken(provided, token)) {
129
- return { status: 403, body: { error: "Forbidden" } };
130
87
  }
131
- const response = await registry.run();
132
- return {
133
- status: httpStatusCode(response.status),
134
- body: { ...metadata, ...toJson(response) }
88
+ const body = {
89
+ status: "ok",
90
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
91
+ ...metadata
135
92
  };
93
+ return { status: 200, body };
136
94
  };
137
95
  }
138
96
 
@@ -404,6 +362,8 @@ function createNextHandler(options) {
404
362
  const url = new URL(request.url);
405
363
  const queryParams = Object.fromEntries(url.searchParams);
406
364
  const result = await handle({
365
+ ip: request.headers.get("x-forwarded-for"),
366
+ headers: Object.fromEntries(request.headers),
407
367
  queryParams,
408
368
  authorizationHeader: request.headers.get("authorization")
409
369
  });
@@ -1,4 +1,4 @@
1
- import { H as HealthcheckHandlerOptions } from '../handler-COH7lot9.cjs';
1
+ import { H as HealthcheckHandlerOptions } from '../handler-TZOgZvY7.cjs';
2
2
  import '../core-Bee03bJm.cjs';
3
3
 
4
4
  type NextHealthcheckOptions = HealthcheckHandlerOptions;
@@ -15,7 +15,7 @@ type NextHealthcheckOptions = HealthcheckHandlerOptions;
15
15
  *
16
16
  * export const GET = createNextHandler({
17
17
  * registry,
18
- * token: process.env.VITALS_TOKEN,
18
+ * resolveDepth: (req) => req.ip === '10.0.0.1' ? 'deep' : 'shallow',
19
19
  * });
20
20
  * ```
21
21
  */
@@ -1,4 +1,4 @@
1
- import { H as HealthcheckHandlerOptions } from '../handler-CVYUad84.js';
1
+ import { H as HealthcheckHandlerOptions } from '../handler-BvjN4Ot9.js';
2
2
  import '../core-Bee03bJm.js';
3
3
 
4
4
  type NextHealthcheckOptions = HealthcheckHandlerOptions;
@@ -15,7 +15,7 @@ type NextHealthcheckOptions = HealthcheckHandlerOptions;
15
15
  *
16
16
  * export const GET = createNextHandler({
17
17
  * registry,
18
- * token: process.env.VITALS_TOKEN,
18
+ * resolveDepth: (req) => req.ip === '10.0.0.1' ? 'deep' : 'shallow',
19
19
  * });
20
20
  * ```
21
21
  */
@@ -1,25 +1,3 @@
1
- // src/auth.ts
2
- import { createHash, timingSafeEqual } from "crypto";
3
- function verifyToken(provided, expected) {
4
- if (!provided || !expected) return false;
5
- const providedHash = createHash("sha256").update(provided).digest();
6
- const expectedHash = createHash("sha256").update(expected).digest();
7
- return timingSafeEqual(providedHash, expectedHash);
8
- }
9
- function extractToken(options) {
10
- const { queryParams, authorizationHeader, queryParamName = "token" } = options;
11
- if (queryParams) {
12
- const value = queryParams[queryParamName];
13
- const str = Array.isArray(value) ? value[0] : value;
14
- if (str) return str;
15
- }
16
- if (authorizationHeader?.startsWith("Bearer ")) {
17
- const token = authorizationHeader.slice("Bearer ".length);
18
- if (token) return token;
19
- }
20
- return null;
21
- }
22
-
23
1
  // src/types.ts
24
2
  var Status = {
25
3
  HEALTHY: 2,
@@ -57,56 +35,36 @@ function httpStatusCode(status) {
57
35
  // src/handler.ts
58
36
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
59
37
  function createHealthcheckHandler(options) {
60
- const { registry, token: rawToken, deep = false, queryParamName = "token", metadata = {} } = options;
61
- const isEmptyToken = typeof rawToken === "string" && rawToken.trim() === "";
62
- if (deep && isEmptyToken) {
63
- throw new Error(
64
- "Cannot use `deep: true` with an empty string token. This would expose deep healthcheck data without authentication. Either set a non-empty token or explicitly set `token: null`."
65
- );
66
- }
67
- const token = rawToken == null || isEmptyToken ? null : rawToken;
38
+ const { registry, resolveDepth, metadata = {} } = options;
68
39
  for (const key of Object.keys(metadata)) {
69
40
  if (RESERVED_METADATA_KEYS.includes(key)) {
70
41
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
71
42
  }
72
43
  }
73
44
  return async (req) => {
74
- if (token === null) {
75
- if (deep) {
76
- const response2 = await registry.run();
77
- return {
78
- status: httpStatusCode(response2.status),
79
- body: { ...metadata, ...toJson(response2) }
80
- };
45
+ let depth = "shallow";
46
+ if (resolveDepth) {
47
+ try {
48
+ const result = await resolveDepth(req);
49
+ if (result === "deep" || result === "shallow") {
50
+ depth = result;
51
+ }
52
+ } catch {
81
53
  }
82
- const body = {
83
- status: "ok",
84
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
85
- ...metadata
86
- };
87
- return { status: 200, body };
88
54
  }
89
- const provided = extractToken({
90
- queryParams: req.queryParams,
91
- authorizationHeader: req.authorizationHeader,
92
- queryParamName
93
- });
94
- if (provided === null) {
95
- const body = {
96
- status: "ok",
97
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
98
- ...metadata
55
+ if (depth === "deep") {
56
+ const response = await registry.run();
57
+ return {
58
+ status: httpStatusCode(response.status),
59
+ body: { ...metadata, ...toJson(response) }
99
60
  };
100
- return { status: 200, body };
101
- }
102
- if (!verifyToken(provided, token)) {
103
- return { status: 403, body: { error: "Forbidden" } };
104
61
  }
105
- const response = await registry.run();
106
- return {
107
- status: httpStatusCode(response.status),
108
- body: { ...metadata, ...toJson(response) }
62
+ const body = {
63
+ status: "ok",
64
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
65
+ ...metadata
109
66
  };
67
+ return { status: 200, body };
110
68
  };
111
69
  }
112
70
 
@@ -378,6 +336,8 @@ function createNextHandler(options) {
378
336
  const url = new URL(request.url);
379
337
  const queryParams = Object.fromEntries(url.searchParams);
380
338
  const result = await handle({
339
+ ip: request.headers.get("x-forwarded-for"),
340
+ headers: Object.fromEntries(request.headers),
381
341
  queryParams,
382
342
  authorizationHeader: request.headers.get("authorization")
383
343
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firebreak/vitals",
3
- "version": "1.3.0",
3
+ "version": "2.0.0",
4
4
  "description": "Deep healthcheck endpoints following the HEALTHCHECK_SPEC format",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1,27 +0,0 @@
1
- import { b as HealthcheckRegistry, H as HealthcheckResponseJson } from './core-Bee03bJm.cjs';
2
-
3
- interface HealthcheckHandlerOptions {
4
- registry: HealthcheckRegistry;
5
- token?: string | null;
6
- deep?: boolean;
7
- queryParamName?: string;
8
- metadata?: Record<string, string | number | boolean>;
9
- }
10
- interface HealthcheckRequest {
11
- queryParams?: Record<string, string | string[] | undefined>;
12
- authorizationHeader?: string | null;
13
- }
14
- interface ShallowResponseJson {
15
- status: 'ok';
16
- timestamp: string;
17
- [key: string]: string | number | boolean;
18
- }
19
- interface HealthcheckHandlerResult {
20
- status: number;
21
- body: HealthcheckResponseJson | ShallowResponseJson | {
22
- error: string;
23
- };
24
- }
25
- declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: HealthcheckRequest) => Promise<HealthcheckHandlerResult>;
26
-
27
- export { type HealthcheckHandlerOptions as H, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
@@ -1,27 +0,0 @@
1
- import { b as HealthcheckRegistry, H as HealthcheckResponseJson } from './core-Bee03bJm.js';
2
-
3
- interface HealthcheckHandlerOptions {
4
- registry: HealthcheckRegistry;
5
- token?: string | null;
6
- deep?: boolean;
7
- queryParamName?: string;
8
- metadata?: Record<string, string | number | boolean>;
9
- }
10
- interface HealthcheckRequest {
11
- queryParams?: Record<string, string | string[] | undefined>;
12
- authorizationHeader?: string | null;
13
- }
14
- interface ShallowResponseJson {
15
- status: 'ok';
16
- timestamp: string;
17
- [key: string]: string | number | boolean;
18
- }
19
- interface HealthcheckHandlerResult {
20
- status: number;
21
- body: HealthcheckResponseJson | ShallowResponseJson | {
22
- error: string;
23
- };
24
- }
25
- declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: HealthcheckRequest) => Promise<HealthcheckHandlerResult>;
26
-
27
- export { type HealthcheckHandlerOptions as H, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };