@firebreak/vitals 2.0.0 → 2.0.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.
Files changed (2) hide show
  1. package/README.md +67 -52
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Vitals (Node.js)
2
2
 
3
- Structured healthcheck endpoints for Node.js services with shallow and deep response tiers. Register health checks, run them concurrently with timeouts, and expose them via Express or Next.js. Unauthenticated callers get a lightweight "alive" response with optional metadata; authenticated callers get full diagnostic results.
3
+ Structured healthcheck endpoints for Node.js services with shallow and deep response tiers. Register health checks, run them concurrently with timeouts, and expose them via Express or Next.js. A configurable depth policy controls whether callers get a lightweight "alive" response or full diagnostic results.
4
4
 
5
5
  ## Install
6
6
 
@@ -19,7 +19,7 @@ npm install express # for Express integration
19
19
  ## Quick Start (Express)
20
20
 
21
21
  ```typescript
22
- import { HealthcheckRegistry } from '@firebreak/vitals';
22
+ import { HealthcheckRegistry, extractToken, verifyToken } from '@firebreak/vitals';
23
23
  import { createHealthcheckMiddleware } from '@firebreak/vitals/express';
24
24
  import { pgPoolCheck } from '@firebreak/vitals/checks/postgres';
25
25
  import { ioredisClientCheck } from '@firebreak/vitals/checks/redis';
@@ -35,7 +35,14 @@ registry.add('api', httpCheck('https://api.example.com/health'));
35
35
  const app = express();
36
36
  app.get('/vitals', createHealthcheckMiddleware({
37
37
  registry,
38
- token: process.env.VITALS_TOKEN,
38
+ resolveDepth: (req) => {
39
+ const token = extractToken({
40
+ queryParams: req.queryParams as Record<string, string>,
41
+ authorizationHeader: req.authorizationHeader as string | null,
42
+ });
43
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
44
+ return 'shallow';
45
+ },
39
46
  metadata: {
40
47
  build: process.env.BUILD_SHA,
41
48
  buildTimestamp: process.env.BUILD_TIMESTAMP,
@@ -43,19 +50,19 @@ app.get('/vitals', createHealthcheckMiddleware({
43
50
  }));
44
51
  ```
45
52
 
46
- Hit `/vitals` without a token to get a shallow response:
53
+ Hit `/vitals` without a valid token to get a shallow response:
47
54
 
48
55
  ```json
49
56
  { "status": "ok", "timestamp": "...", "build": "stg-45d76e5", "buildTimestamp": "2025-02-25T19:41:56Z" }
50
57
  ```
51
58
 
52
- Provide the token (`?token=...` or `Authorization: Bearer ...`) to get the full deep response with check results.
59
+ When `resolveDepth` returns `'deep'`, the full deep response with check results is returned.
53
60
 
54
61
  ## Quick Start (Next.js)
55
62
 
56
63
  ```typescript
57
64
  // app/vitals/route.ts
58
- import { HealthcheckRegistry } from '@firebreak/vitals';
65
+ import { HealthcheckRegistry, extractToken, verifyToken } from '@firebreak/vitals';
59
66
  import { createNextHandler } from '@firebreak/vitals/next';
60
67
  import { pgClientCheck } from '@firebreak/vitals/checks/postgres';
61
68
  import { httpCheck } from '@firebreak/vitals/checks/http';
@@ -69,7 +76,14 @@ registry.add('api', httpCheck(`${process.env.API_BASE_URL}/health`));
69
76
 
70
77
  export const GET = createNextHandler({
71
78
  registry,
72
- token: process.env.VITALS_TOKEN,
79
+ resolveDepth: (req) => {
80
+ const token = extractToken({
81
+ queryParams: req.queryParams as Record<string, string>,
82
+ authorizationHeader: req.authorizationHeader as string | null,
83
+ });
84
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
85
+ return 'shallow';
86
+ },
73
87
  metadata: {
74
88
  build: process.env.BUILD_SHA,
75
89
  },
@@ -207,8 +221,14 @@ import { createHealthcheckMiddleware } from '@firebreak/vitals/express';
207
221
 
208
222
  app.get('/vitals', createHealthcheckMiddleware({
209
223
  registry,
210
- token: 'my-secret-token', // optional — omit to disable auth
211
- queryParamName: 'token', // default: 'token'
224
+ resolveDepth: (req) => { // optional — omit for always-shallow
225
+ const token = extractToken({
226
+ queryParams: req.queryParams as Record<string, string>,
227
+ authorizationHeader: req.authorizationHeader as string | null,
228
+ });
229
+ if (token && verifyToken(token, 'my-secret-token')) return 'deep';
230
+ return 'shallow';
231
+ },
212
232
  metadata: { // optional — included in shallow & deep responses
213
233
  build: 'stg-45d76e5',
214
234
  },
@@ -222,7 +242,14 @@ import { createNextHandler } from '@firebreak/vitals/next';
222
242
 
223
243
  export const GET = createNextHandler({
224
244
  registry,
225
- token: process.env.VITALS_TOKEN,
245
+ resolveDepth: (req) => {
246
+ const token = extractToken({
247
+ queryParams: req.queryParams as Record<string, string>,
248
+ authorizationHeader: req.authorizationHeader as string | null,
249
+ });
250
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
251
+ return 'shallow';
252
+ },
226
253
  metadata: { build: process.env.BUILD_SHA },
227
254
  });
228
255
  ```
@@ -232,59 +259,52 @@ export const GET = createNextHandler({
232
259
  For other frameworks, use the generic handler directly:
233
260
 
234
261
  ```typescript
235
- import { createHealthcheckHandler } from '@firebreak/vitals';
262
+ import { createHealthcheckHandler, extractToken, verifyToken } from '@firebreak/vitals';
236
263
 
237
264
  const handle = createHealthcheckHandler({
238
265
  registry,
239
- token: process.env.VITALS_TOKEN,
266
+ resolveDepth: (req) => {
267
+ const token = extractToken({
268
+ queryParams: req.queryParams as Record<string, string>,
269
+ authorizationHeader: req.authorizationHeader as string | null,
270
+ });
271
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
272
+ return 'shallow';
273
+ },
240
274
  metadata: { build: 'stg-45d76e5' },
241
275
  });
242
276
 
243
- // No token → shallow response
277
+ // resolveDepth returns 'shallow' → shallow response
244
278
  const shallow = await handle({});
245
279
  // { status: 200, body: { status: 'ok', timestamp: '...', build: 'stg-45d76e5' } }
246
280
 
247
- // Valid token → deep response
281
+ // resolveDepth returns 'deep' → deep response
248
282
  const deep = await handle({ queryParams: { token: '...' } });
249
283
  // { status: 200, body: { status: 'healthy', timestamp: '...', build: 'stg-45d76e5', checks: { ... } } }
250
284
  ```
251
285
 
252
286
  ### Shallow / Deep Responses
253
287
 
254
- When a `token` is configured, the endpoint serves two tiers from a single route:
255
-
256
- | Request | Response |
257
- |---------|----------|
258
- | No token provided | **Shallow** — `200` with `{ status: "ok", timestamp, ...metadata }` |
259
- | Valid token provided | **Deep** — `200`/`503` with full check results + metadata |
260
- | Invalid token provided | `403 Forbidden` |
261
- | No token configured | **Shallow** by default (see `deep` option below) |
288
+ The endpoint serves two tiers from a single route, controlled by the `resolveDepth` option:
262
289
 
263
- The shallow response lets load balancers and uptime monitors confirm the process is alive without needing a secret. The deep response is a superset of shallow — it includes everything shallow returns plus the `checks` object and a real health status.
290
+ | `resolveDepth` returns | Response |
291
+ |------------------------|----------|
292
+ | `'shallow'` (or omitted) | **Shallow** — `200` with `{ status: "ok", timestamp, ...metadata }` |
293
+ | `'deep'` | **Deep** — `200`/`503` with full check results + metadata |
264
294
 
265
- #### The `deep` Option
295
+ When `resolveDepth` is not provided, the handler always returns a shallow response.
266
296
 
267
- When no `token` is configured, the handler returns a **shallow** response by default. To expose full healthcheck results without requiring token authentication, set `deep: true`:
297
+ The `resolveDepth` function receives the request object (`{ ip, headers, queryParams, authorizationHeader }`) and returns `'deep'` or `'shallow'` (or a promise of either). This lets you implement any depth policy token-based, IP-based, header-based, or always-deep for internal services:
268
298
 
269
299
  ```typescript
300
+ // Always deep (internal service behind a private network)
270
301
  createHealthcheckHandler({
271
302
  registry,
272
- deep: true, // no token → always return deep response
303
+ resolveDepth: () => 'deep',
273
304
  });
274
305
  ```
275
306
 
276
- This is useful for internal services behind a private network where token auth is unnecessary. The `deep` option defaults to `false`.
277
-
278
- > **Security note:** Using `deep: true` with an empty string token (e.g. `token: ''`) will throw an error at handler creation time. This prevents misconfigured environments (e.g. `VITALS_TOKEN=""`) from silently exposing deep healthcheck data. If you intend to run without authentication, explicitly omit the `token` option or set it to `null`.
279
-
280
- When both `token` and `deep` are set, the `token` takes precedence — callers must still authenticate to see deep results:
281
-
282
- | Configuration | No token in request | Valid token | Invalid token |
283
- |---------------|---------------------|-------------|---------------|
284
- | `token` set, `deep` unset | Shallow | Deep | 403 |
285
- | `token` set, `deep: true` | Shallow | Deep | 403 |
286
- | No `token`, `deep` unset | Shallow | — | — |
287
- | No `token`, `deep: true` | Deep | — | — |
307
+ The shallow response lets load balancers and uptime monitors confirm the process is alive without needing a secret. The deep response is a superset of shallow — it includes everything shallow returns plus the `checks` object and a real health status.
288
308
 
289
309
  ### Metadata
290
310
 
@@ -293,7 +313,6 @@ Attach static key-value pairs that appear in both shallow and deep responses:
293
313
  ```typescript
294
314
  createHealthcheckHandler({
295
315
  registry,
296
- token: process.env.VITALS_TOKEN,
297
316
  metadata: {
298
317
  build: 'stg-45d76e5',
299
318
  buildTimestamp: '2025-02-25T19:41:56Z',
@@ -304,29 +323,26 @@ createHealthcheckHandler({
304
323
 
305
324
  Metadata values can be `string`, `number`, or `boolean`. Keys `status`, `timestamp`, and `checks` are reserved — passing them throws at handler creation time.
306
325
 
307
- ### Authentication
308
-
309
- Tokens can be provided via:
310
- - Query parameter: `?token=my-secret-token`
311
- - Bearer header: `Authorization: Bearer my-secret-token`
326
+ ### Utilities
312
327
 
313
- Tokens are compared using timing-safe SHA-256 comparison.
328
+ `extractToken` and `verifyToken` are exported helpers for use inside your `resolveDepth` function.
314
329
 
315
330
  ```typescript
316
331
  import { verifyToken, extractToken } from '@firebreak/vitals';
317
332
 
318
- verifyToken('provided-token', 'expected-token'); // boolean
319
-
333
+ // Extract a token from query params (?token=...) or Authorization header
320
334
  const token = extractToken({
321
335
  queryParams: { token: 'abc' },
322
336
  authorizationHeader: 'Bearer abc',
323
- queryParamName: 'token',
324
337
  });
338
+
339
+ // Timing-safe SHA-256 comparison
340
+ verifyToken('provided-token', 'expected-token'); // boolean
325
341
  ```
326
342
 
327
343
  ## Response Format
328
344
 
329
- **Shallow response** (no token provided):
345
+ **Shallow response** (`resolveDepth` returns `'shallow'` or is omitted):
330
346
 
331
347
  ```json
332
348
  {
@@ -337,7 +353,7 @@ const token = extractToken({
337
353
  }
338
354
  ```
339
355
 
340
- **Deep response** (valid token provided):
356
+ **Deep response** (`resolveDepth` returns `'deep'`):
341
357
 
342
358
  ```json
343
359
  {
@@ -362,11 +378,10 @@ const token = extractToken({
362
378
 
363
379
  | Condition | HTTP Code | Status |
364
380
  |-----------|-----------|--------|
365
- | Shallow (no token) | `200` | `"ok"` |
381
+ | Shallow | `200` | `"ok"` |
366
382
  | Deep — healthy | `200` | `"healthy"` |
367
383
  | Deep — degraded | `503` | `"degraded"` |
368
384
  | Deep — outage | `503` | `"outage"` |
369
- | Invalid token | `403` | — |
370
385
 
371
386
  ## Requirements
372
387
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firebreak/vitals",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Deep healthcheck endpoints following the HEALTHCHECK_SPEC format",
5
5
  "type": "module",
6
6
  "exports": {