@firebreak/vitals 2.2.0 → 3.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.
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. A configurable depth policy controls whether callers get a lightweight "alive" response or full diagnostic results.
3
+ Structured healthcheck endpoints for Node.js services. Register health checks, run them concurrently with timeouts, and expose them via Express or Next.js. Health checks always run — a configurable detail policy controls whether callers see a summary status or full diagnostic results.
4
4
 
5
5
  ## Install
6
6
 
@@ -35,13 +35,13 @@ registry.add('api', httpCheck('https://api.example.com/health'));
35
35
  const app = express();
36
36
  app.get('/vitals', createHealthcheckMiddleware({
37
37
  registry,
38
- resolveDepth: (req) => {
38
+ resolveDetail: (req) => {
39
39
  const token = extractToken({
40
40
  queryParams: req.queryParams as Record<string, string>,
41
41
  authorizationHeader: req.authorizationHeader as string | null,
42
42
  });
43
- if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
44
- return 'shallow';
43
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'full';
44
+ return 'summary';
45
45
  },
46
46
  metadata: {
47
47
  build: process.env.BUILD_SHA,
@@ -50,13 +50,13 @@ app.get('/vitals', createHealthcheckMiddleware({
50
50
  }));
51
51
  ```
52
52
 
53
- Hit `/vitals` without a valid token to get a shallow response:
53
+ Hit `/vitals` without a valid token to get a summary response with real health status:
54
54
 
55
55
  ```json
56
- { "status": "ok", "timestamp": "...", "build": "stg-45d76e5", "buildTimestamp": "2025-02-25T19:41:56Z" }
56
+ { "status": "healthy", "timestamp": "...", "build": "stg-45d76e5", "buildTimestamp": "2025-02-25T19:41:56Z" }
57
57
  ```
58
58
 
59
- When `resolveDepth` returns `'deep'`, the full deep response with check results is returned.
59
+ When `resolveDetail` returns `'full'`, the full response with check results is returned.
60
60
 
61
61
  ## Quick Start (Next.js)
62
62
 
@@ -76,13 +76,13 @@ registry.add('api', httpCheck(`${process.env.API_BASE_URL}/health`));
76
76
 
77
77
  export const GET = createNextHandler({
78
78
  registry,
79
- resolveDepth: (req) => {
79
+ resolveDetail: (req) => {
80
80
  const token = extractToken({
81
81
  queryParams: req.queryParams as Record<string, string>,
82
82
  authorizationHeader: req.authorizationHeader as string | null,
83
83
  });
84
- if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
85
- return 'shallow';
84
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'full';
85
+ return 'summary';
86
86
  },
87
87
  metadata: {
88
88
  build: process.env.BUILD_SHA,
@@ -221,15 +221,15 @@ import { createHealthcheckMiddleware } from '@firebreak/vitals/express';
221
221
 
222
222
  app.get('/vitals', createHealthcheckMiddleware({
223
223
  registry,
224
- resolveDepth: (req) => { // optional — omit for always-shallow
224
+ resolveDetail: (req) => { // optional — omit for always-summary
225
225
  const token = extractToken({
226
226
  queryParams: req.queryParams as Record<string, string>,
227
227
  authorizationHeader: req.authorizationHeader as string | null,
228
228
  });
229
- if (token && verifyToken(token, 'my-secret-token')) return 'deep';
230
- return 'shallow';
229
+ if (token && verifyToken(token, 'my-secret-token')) return 'full';
230
+ return 'summary';
231
231
  },
232
- metadata: { // optional — included in shallow & deep responses
232
+ metadata: { // optional — included in summary & full responses
233
233
  build: 'stg-45d76e5',
234
234
  },
235
235
  }));
@@ -242,13 +242,13 @@ import { createNextHandler } from '@firebreak/vitals/next';
242
242
 
243
243
  export const GET = createNextHandler({
244
244
  registry,
245
- resolveDepth: (req) => {
245
+ resolveDetail: (req) => {
246
246
  const token = extractToken({
247
247
  queryParams: req.queryParams as Record<string, string>,
248
248
  authorizationHeader: req.authorizationHeader as string | null,
249
249
  });
250
- if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
251
- return 'shallow';
250
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'full';
251
+ return 'summary';
252
252
  },
253
253
  metadata: { build: process.env.BUILD_SHA },
254
254
  });
@@ -263,52 +263,52 @@ import { createHealthcheckHandler, extractToken, verifyToken } from '@firebreak/
263
263
 
264
264
  const handle = createHealthcheckHandler({
265
265
  registry,
266
- resolveDepth: (req) => {
266
+ resolveDetail: (req) => {
267
267
  const token = extractToken({
268
268
  queryParams: req.queryParams as Record<string, string>,
269
269
  authorizationHeader: req.authorizationHeader as string | null,
270
270
  });
271
- if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'deep';
272
- return 'shallow';
271
+ if (token && verifyToken(token, process.env.VITALS_TOKEN!)) return 'full';
272
+ return 'summary';
273
273
  },
274
274
  metadata: { build: 'stg-45d76e5' },
275
275
  });
276
276
 
277
- // resolveDepth returns 'shallow' → shallow response
278
- const shallow = await handle({});
279
- // { status: 200, body: { status: 'ok', timestamp: '...', build: 'stg-45d76e5' } }
277
+ // resolveDetail returns 'summary' → summary response (real status, no checks)
278
+ const summary = await handle({});
279
+ // { status: 200, body: { status: 'healthy', timestamp: '...', build: 'stg-45d76e5' } }
280
280
 
281
- // resolveDepth returns 'deep' → deep response
282
- const deep = await handle({ queryParams: { token: '...' } });
281
+ // resolveDetail returns 'full' → full response with check details
282
+ const full = await handle({ queryParams: { token: '...' } });
283
283
  // { status: 200, body: { status: 'healthy', timestamp: '...', build: 'stg-45d76e5', checks: { ... } } }
284
284
  ```
285
285
 
286
- ### Shallow / Deep Responses
286
+ ### Summary / Full Responses
287
287
 
288
- The endpoint serves two tiers from a single route, controlled by the `resolveDepth` option:
288
+ Health checks always run. The `resolveDetail` option controls how much detail is exposed in the response:
289
289
 
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 |
290
+ | `resolveDetail` returns | Response |
291
+ |-------------------------|----------|
292
+ | `'summary'` (or omitted) | **Summary** — real HTTP status with `{ status: "healthy"/"degraded"/"outage", timestamp, ...metadata }` |
293
+ | `'full'` | **Full** — real HTTP status with check results + metadata |
294
294
 
295
- When `resolveDepth` is not provided, the handler always returns a shallow response.
295
+ When `resolveDetail` is not provided, the handler returns a summary response.
296
296
 
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:
297
+ The `resolveDetail` function receives the request object (`{ ip, headers, queryParams, authorizationHeader }`) and returns `'full'` or `'summary'` (or a promise of either). This lets you implement any detail policy — token-based, IP-based, header-based, or always-full for internal services:
298
298
 
299
299
  ```typescript
300
- // Always deep (internal service behind a private network)
300
+ // Always full (internal service behind a private network)
301
301
  createHealthcheckHandler({
302
302
  registry,
303
- resolveDepth: () => 'deep',
303
+ resolveDetail: () => 'full',
304
304
  });
305
305
  ```
306
306
 
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.
307
+ Both summary and full responses reflect real health status and return the correct HTTP status code (200 for healthy, 503 for degraded/outage). The summary response lets load balancers and uptime monitors get real health status without exposing internal check details. The full response adds the `checks` object with per-check diagnostics.
308
308
 
309
309
  ### Metadata
310
310
 
311
- Attach static key-value pairs that appear in both shallow and deep responses:
311
+ Attach static key-value pairs that appear in both summary and full responses:
312
312
 
313
313
  ```typescript
314
314
  createHealthcheckHandler({
@@ -323,9 +323,9 @@ createHealthcheckHandler({
323
323
 
324
324
  Metadata values can be `string`, `number`, or `boolean`. Keys `status`, `timestamp`, `checks`, and `cachedAt` are reserved -- passing them throws at handler creation time.
325
325
 
326
- #### `shallowMetadata`
326
+ #### `summaryMetadata`
327
327
 
328
- By default, shallow responses include all `metadata` fields. Use `shallowMetadata` to override what appears in shallow responses while keeping `metadata` for deep responses:
328
+ By default, summary responses include all `metadata` fields. Use `summaryMetadata` to override what appears in summary responses while keeping `metadata` for full responses:
329
329
 
330
330
  ```typescript
331
331
  createHealthcheckHandler({
@@ -335,8 +335,8 @@ createHealthcheckHandler({
335
335
  buildTimestamp: '2025-02-25T19:41:56Z',
336
336
  region: 'us-east-1',
337
337
  },
338
- // Shallow responses only include status + timestamp (no build info)
339
- shallowMetadata: {},
338
+ // Summary responses only include status + timestamp (no build info)
339
+ summaryMetadata: {},
340
340
  });
341
341
  ```
342
342
 
@@ -346,16 +346,16 @@ You can also include a subset of fields:
346
346
  createHealthcheckHandler({
347
347
  registry,
348
348
  metadata: { build: 'stg-45d76e5', region: 'us-east-1', version: '1.0.0' },
349
- // Shallow responses include only version
350
- shallowMetadata: { version: '1.0.0' },
349
+ // Summary responses include only version
350
+ summaryMetadata: { version: '1.0.0' },
351
351
  });
352
352
  ```
353
353
 
354
- When `shallowMetadata` is omitted, shallow responses fall back to using `metadata` (existing behavior).
354
+ When `summaryMetadata` is omitted, summary responses fall back to using `metadata`.
355
355
 
356
356
  ### Utilities
357
357
 
358
- `extractToken` and `verifyToken` are exported helpers for use inside your `resolveDepth` function.
358
+ `extractToken` and `verifyToken` are exported helpers for use inside your `resolveDetail` function.
359
359
 
360
360
  ```typescript
361
361
  import { verifyToken, extractToken } from '@firebreak/vitals';
@@ -372,18 +372,18 @@ verifyToken('provided-token', 'expected-token'); // boolean
372
372
 
373
373
  ## Response Format
374
374
 
375
- **Shallow response** (`resolveDepth` returns `'shallow'` or is omitted):
375
+ **Summary response** (`resolveDetail` returns `'summary'` or is omitted):
376
376
 
377
377
  ```json
378
378
  {
379
- "status": "ok",
379
+ "status": "healthy",
380
380
  "timestamp": "2025-02-26T12:00:00.000Z",
381
381
  "build": "stg-45d76e5",
382
382
  "buildTimestamp": "2025-02-25T19:41:56Z"
383
383
  }
384
384
  ```
385
385
 
386
- **Deep response** (`resolveDepth` returns `'deep'`):
386
+ **Full response** (`resolveDetail` returns `'full'`):
387
387
 
388
388
  ```json
389
389
  {
@@ -406,12 +406,13 @@ verifyToken('provided-token', 'expected-token'); // boolean
406
406
  }
407
407
  ```
408
408
 
409
- | Condition | HTTP Code | Status |
410
- |-----------|-----------|--------|
411
- | Shallow | `200` | `"ok"` |
412
- | Deep — healthy | `200` | `"healthy"` |
413
- | Deep — degraded | `503` | `"degraded"` |
414
- | Deep — outage | `503` | `"outage"` |
409
+ Both summary and full responses return real HTTP status codes:
410
+
411
+ | Status | HTTP Code |
412
+ |--------|-----------|
413
+ | `"healthy"` | `200` |
414
+ | `"degraded"` | `503` |
415
+ | `"outage"` | `503` |
415
416
 
416
417
  ## Requirements
417
418
 
@@ -32,11 +32,12 @@ var Status = {
32
32
  };
33
33
 
34
34
  // src/checks/databricks.ts
35
- function databricksCheck(client) {
35
+ function databricksCheck(clientOrFactory) {
36
36
  return async () => {
37
37
  let session;
38
38
  let op;
39
39
  try {
40
+ const client = typeof clientOrFactory === "function" ? await clientOrFactory() : clientOrFactory;
40
41
  session = await client.openSession();
41
42
  op = await session.executeStatement("SELECT 1");
42
43
  return { status: Status.HEALTHY, message: "" };
@@ -14,10 +14,11 @@ interface DatabricksSession {
14
14
  interface DatabricksOperation {
15
15
  close(): Promise<void>;
16
16
  }
17
+ type DatabricksClientOrFactory = DatabricksClient | (() => DatabricksClient | Promise<DatabricksClient>);
17
18
  /**
18
19
  * Creates a healthcheck function that opens a session on an existing
19
20
  * Databricks SQL client, runs `SELECT 1`, and closes the session.
20
21
  */
21
- declare function databricksCheck(client: DatabricksClient): AsyncCheckFn;
22
+ declare function databricksCheck(clientOrFactory: DatabricksClientOrFactory): AsyncCheckFn;
22
23
 
23
- export { AsyncCheckFn, type DatabricksClient, type DatabricksOperation, type DatabricksSession, databricksCheck };
24
+ export { AsyncCheckFn, type DatabricksClient, type DatabricksClientOrFactory, type DatabricksOperation, type DatabricksSession, databricksCheck };
@@ -14,10 +14,11 @@ interface DatabricksSession {
14
14
  interface DatabricksOperation {
15
15
  close(): Promise<void>;
16
16
  }
17
+ type DatabricksClientOrFactory = DatabricksClient | (() => DatabricksClient | Promise<DatabricksClient>);
17
18
  /**
18
19
  * Creates a healthcheck function that opens a session on an existing
19
20
  * Databricks SQL client, runs `SELECT 1`, and closes the session.
20
21
  */
21
- declare function databricksCheck(client: DatabricksClient): AsyncCheckFn;
22
+ declare function databricksCheck(clientOrFactory: DatabricksClientOrFactory): AsyncCheckFn;
22
23
 
23
- export { AsyncCheckFn, type DatabricksClient, type DatabricksOperation, type DatabricksSession, databricksCheck };
24
+ export { AsyncCheckFn, type DatabricksClient, type DatabricksClientOrFactory, type DatabricksOperation, type DatabricksSession, databricksCheck };
@@ -6,11 +6,12 @@ var Status = {
6
6
  };
7
7
 
8
8
  // src/checks/databricks.ts
9
- function databricksCheck(client) {
9
+ function databricksCheck(clientOrFactory) {
10
10
  return async () => {
11
11
  let session;
12
12
  let op;
13
13
  try {
14
+ const client = typeof clientOrFactory === "function" ? await clientOrFactory() : clientOrFactory;
14
15
  session = await client.openSession();
15
16
  op = await session.executeStatement("SELECT 1");
16
17
  return { status: Status.HEALTHY, message: "" };
@@ -0,0 +1,21 @@
1
+ import { b as HealthcheckRegistry, H as HealthcheckResponseJson, d as StatusLabel } from './core-Bee03bJm.js';
2
+
3
+ type ResolveDetailFn = (req: Record<string, unknown>) => 'full' | 'summary' | Promise<'full' | 'summary'>;
4
+ interface HealthcheckHandlerOptions {
5
+ registry: HealthcheckRegistry;
6
+ resolveDetail?: ResolveDetailFn;
7
+ metadata?: Record<string, string | number | boolean>;
8
+ summaryMetadata?: Record<string, string | number | boolean>;
9
+ }
10
+ interface SummaryResponseJson {
11
+ status: StatusLabel;
12
+ timestamp: string;
13
+ [key: string]: string | number | boolean;
14
+ }
15
+ interface HealthcheckHandlerResult {
16
+ status: number;
17
+ body: HealthcheckResponseJson | SummaryResponseJson;
18
+ }
19
+ declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: Record<string, unknown>) => Promise<HealthcheckHandlerResult>;
20
+
21
+ export { type HealthcheckHandlerOptions as H, type ResolveDetailFn as R, type SummaryResponseJson as S, type HealthcheckHandlerResult as a, createHealthcheckHandler as c };
@@ -0,0 +1,21 @@
1
+ import { b as HealthcheckRegistry, H as HealthcheckResponseJson, d as StatusLabel } from './core-Bee03bJm.cjs';
2
+
3
+ type ResolveDetailFn = (req: Record<string, unknown>) => 'full' | 'summary' | Promise<'full' | 'summary'>;
4
+ interface HealthcheckHandlerOptions {
5
+ registry: HealthcheckRegistry;
6
+ resolveDetail?: ResolveDetailFn;
7
+ metadata?: Record<string, string | number | boolean>;
8
+ summaryMetadata?: Record<string, string | number | boolean>;
9
+ }
10
+ interface SummaryResponseJson {
11
+ status: StatusLabel;
12
+ timestamp: string;
13
+ [key: string]: string | number | boolean;
14
+ }
15
+ interface HealthcheckHandlerResult {
16
+ status: number;
17
+ body: HealthcheckResponseJson | SummaryResponseJson;
18
+ }
19
+ declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: Record<string, unknown>) => Promise<HealthcheckHandlerResult>;
20
+
21
+ export { type HealthcheckHandlerOptions as H, type ResolveDetailFn as R, type SummaryResponseJson as S, type HealthcheckHandlerResult as a, createHealthcheckHandler as c };
package/dist/index.cjs CHANGED
@@ -207,8 +207,8 @@ function extractToken(options) {
207
207
  const { queryParams, authorizationHeader, queryParamName = "token" } = options;
208
208
  if (queryParams) {
209
209
  const value = queryParams[queryParamName];
210
- const str = Array.isArray(value) ? value[0] : value;
211
- if (str) return str;
210
+ const raw = Array.isArray(value) ? value[0] : value;
211
+ if (raw) return String(raw);
212
212
  }
213
213
  if (authorizationHeader?.startsWith("Bearer ")) {
214
214
  const token = authorizationHeader.slice("Bearer ".length);
@@ -220,8 +220,8 @@ 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, resolveDepth, metadata = {}, shallowMetadata } = options;
224
- for (const bag of [metadata, shallowMetadata ?? {}]) {
223
+ const { registry, resolveDetail, metadata = {}, summaryMetadata } = options;
224
+ for (const bag of [metadata, summaryMetadata ?? {}]) {
225
225
  for (const key of Object.keys(bag)) {
226
226
  if (RESERVED_METADATA_KEYS.includes(key)) {
227
227
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
@@ -229,29 +229,29 @@ function createHealthcheckHandler(options) {
229
229
  }
230
230
  }
231
231
  return async (req) => {
232
- let depth = "shallow";
233
- if (resolveDepth) {
232
+ let detail = "summary";
233
+ if (resolveDetail) {
234
234
  try {
235
- const result = await resolveDepth(req);
236
- if (result === "deep" || result === "shallow") {
237
- depth = result;
235
+ const result = await resolveDetail(req);
236
+ if (result === "full" || result === "summary") {
237
+ detail = result;
238
238
  }
239
239
  } catch {
240
240
  }
241
241
  }
242
- if (depth === "deep") {
243
- const response = await registry.run();
242
+ const response = await registry.run();
243
+ if (detail === "full") {
244
244
  return {
245
245
  status: httpStatusCode(response.status),
246
246
  body: { ...metadata, ...toJson(response) }
247
247
  };
248
248
  }
249
249
  const body = {
250
- status: "ok",
251
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
252
- ...shallowMetadata ?? metadata
250
+ status: statusToLabel(response.status),
251
+ timestamp: response.timestamp,
252
+ ...summaryMetadata ?? metadata
253
253
  };
254
- return { status: 200, body };
254
+ return { status: httpStatusCode(response.status), body };
255
255
  };
256
256
  }
257
257
 
@@ -262,7 +262,6 @@ function escapeHtml(str) {
262
262
  function statusColor(status) {
263
263
  switch (status) {
264
264
  case "healthy":
265
- case "ok":
266
265
  return "#22C55E";
267
266
  case "degraded":
268
267
  return "#F59E0B";
@@ -274,10 +273,10 @@ function statusColor(status) {
274
273
  }
275
274
  var DEEP_KNOWN_KEYS = /* @__PURE__ */ new Set(["status", "timestamp", "checks", "cachedAt"]);
276
275
  function isDeepResponse(body) {
277
- return "checks" in body && "status" in body && body.status !== "ok";
276
+ return "checks" in body && "status" in body;
278
277
  }
279
- function isShallowResponse(body) {
280
- return "status" in body && body.status === "ok";
278
+ function isSummaryResponse(body) {
279
+ return "status" in body && !("checks" in body) && !("error" in body);
281
280
  }
282
281
  function isErrorResponse(body) {
283
282
  return "error" in body && !("status" in body);
@@ -436,9 +435,9 @@ function renderHealthcheckHtml(body) {
436
435
  ">${escapeHtml(body.error)}</div>`
437
436
  );
438
437
  }
439
- if (isShallowResponse(body)) {
440
- const color = statusColor("ok");
441
- const { status: _, timestamp, ...rest } = body;
438
+ if (isSummaryResponse(body)) {
439
+ const color = statusColor(body.status);
440
+ const { status, timestamp, ...rest } = body;
442
441
  const metadataItems = Object.entries(rest).map(
443
442
  ([k, v]) => [k, String(v)]
444
443
  );
@@ -455,7 +454,7 @@ function renderHealthcheckHtml(body) {
455
454
  font-weight: 700;
456
455
  color: #E4E4E7;
457
456
  ">Healthcheck</span>
458
- ${renderStatusBadge("OK", color)}
457
+ ${renderStatusBadge(status, color)}
459
458
  </div>
460
459
  ${renderMetadataItems(allItems)}`
461
460
  );
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-C3eTDuSQ.cjs';
4
- export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, R as ResolveDepthFn, c as createHealthcheckHandler } from './handler-C3eTDuSQ.cjs';
3
+ import { S as SummaryResponseJson } from './handler-MWB6zBBG.cjs';
4
+ export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, R as ResolveDetailFn, c as createHealthcheckHandler } from './handler-MWB6zBBG.cjs';
5
5
 
6
6
  declare function verifyToken(provided: string, expected: string): boolean;
7
7
  declare function extractToken(options: {
@@ -10,9 +10,9 @@ declare function extractToken(options: {
10
10
  queryParamName?: string;
11
11
  }): string | null;
12
12
 
13
- type HealthcheckBody = HealthcheckResponseJson | ShallowResponseJson | {
13
+ type HealthcheckBody = HealthcheckResponseJson | SummaryResponseJson | {
14
14
  error: string;
15
15
  };
16
16
  declare function renderHealthcheckHtml(body: HealthcheckBody): string;
17
17
 
18
- export { HealthcheckResponseJson, ShallowResponseJson, extractToken, renderHealthcheckHtml, verifyToken };
18
+ export { HealthcheckResponseJson, SummaryResponseJson, extractToken, renderHealthcheckHtml, verifyToken };
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-DaFJivGK.js';
4
- export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, R as ResolveDepthFn, c as createHealthcheckHandler } from './handler-DaFJivGK.js';
3
+ import { S as SummaryResponseJson } from './handler-B1Omp5VP.js';
4
+ export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, R as ResolveDetailFn, c as createHealthcheckHandler } from './handler-B1Omp5VP.js';
5
5
 
6
6
  declare function verifyToken(provided: string, expected: string): boolean;
7
7
  declare function extractToken(options: {
@@ -10,9 +10,9 @@ declare function extractToken(options: {
10
10
  queryParamName?: string;
11
11
  }): string | null;
12
12
 
13
- type HealthcheckBody = HealthcheckResponseJson | ShallowResponseJson | {
13
+ type HealthcheckBody = HealthcheckResponseJson | SummaryResponseJson | {
14
14
  error: string;
15
15
  };
16
16
  declare function renderHealthcheckHtml(body: HealthcheckBody): string;
17
17
 
18
- export { HealthcheckResponseJson, ShallowResponseJson, extractToken, renderHealthcheckHtml, verifyToken };
18
+ export { HealthcheckResponseJson, SummaryResponseJson, extractToken, renderHealthcheckHtml, verifyToken };
package/dist/index.mjs CHANGED
@@ -171,8 +171,8 @@ function extractToken(options) {
171
171
  const { queryParams, authorizationHeader, queryParamName = "token" } = options;
172
172
  if (queryParams) {
173
173
  const value = queryParams[queryParamName];
174
- const str = Array.isArray(value) ? value[0] : value;
175
- if (str) return str;
174
+ const raw = Array.isArray(value) ? value[0] : value;
175
+ if (raw) return String(raw);
176
176
  }
177
177
  if (authorizationHeader?.startsWith("Bearer ")) {
178
178
  const token = authorizationHeader.slice("Bearer ".length);
@@ -184,8 +184,8 @@ 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, resolveDepth, metadata = {}, shallowMetadata } = options;
188
- for (const bag of [metadata, shallowMetadata ?? {}]) {
187
+ const { registry, resolveDetail, metadata = {}, summaryMetadata } = options;
188
+ for (const bag of [metadata, summaryMetadata ?? {}]) {
189
189
  for (const key of Object.keys(bag)) {
190
190
  if (RESERVED_METADATA_KEYS.includes(key)) {
191
191
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
@@ -193,29 +193,29 @@ function createHealthcheckHandler(options) {
193
193
  }
194
194
  }
195
195
  return async (req) => {
196
- let depth = "shallow";
197
- if (resolveDepth) {
196
+ let detail = "summary";
197
+ if (resolveDetail) {
198
198
  try {
199
- const result = await resolveDepth(req);
200
- if (result === "deep" || result === "shallow") {
201
- depth = result;
199
+ const result = await resolveDetail(req);
200
+ if (result === "full" || result === "summary") {
201
+ detail = result;
202
202
  }
203
203
  } catch {
204
204
  }
205
205
  }
206
- if (depth === "deep") {
207
- const response = await registry.run();
206
+ const response = await registry.run();
207
+ if (detail === "full") {
208
208
  return {
209
209
  status: httpStatusCode(response.status),
210
210
  body: { ...metadata, ...toJson(response) }
211
211
  };
212
212
  }
213
213
  const body = {
214
- status: "ok",
215
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
216
- ...shallowMetadata ?? metadata
214
+ status: statusToLabel(response.status),
215
+ timestamp: response.timestamp,
216
+ ...summaryMetadata ?? metadata
217
217
  };
218
- return { status: 200, body };
218
+ return { status: httpStatusCode(response.status), body };
219
219
  };
220
220
  }
221
221
 
@@ -226,7 +226,6 @@ function escapeHtml(str) {
226
226
  function statusColor(status) {
227
227
  switch (status) {
228
228
  case "healthy":
229
- case "ok":
230
229
  return "#22C55E";
231
230
  case "degraded":
232
231
  return "#F59E0B";
@@ -238,10 +237,10 @@ function statusColor(status) {
238
237
  }
239
238
  var DEEP_KNOWN_KEYS = /* @__PURE__ */ new Set(["status", "timestamp", "checks", "cachedAt"]);
240
239
  function isDeepResponse(body) {
241
- return "checks" in body && "status" in body && body.status !== "ok";
240
+ return "checks" in body && "status" in body;
242
241
  }
243
- function isShallowResponse(body) {
244
- return "status" in body && body.status === "ok";
242
+ function isSummaryResponse(body) {
243
+ return "status" in body && !("checks" in body) && !("error" in body);
245
244
  }
246
245
  function isErrorResponse(body) {
247
246
  return "error" in body && !("status" in body);
@@ -400,9 +399,9 @@ function renderHealthcheckHtml(body) {
400
399
  ">${escapeHtml(body.error)}</div>`
401
400
  );
402
401
  }
403
- if (isShallowResponse(body)) {
404
- const color = statusColor("ok");
405
- const { status: _, timestamp, ...rest } = body;
402
+ if (isSummaryResponse(body)) {
403
+ const color = statusColor(body.status);
404
+ const { status, timestamp, ...rest } = body;
406
405
  const metadataItems = Object.entries(rest).map(
407
406
  ([k, v]) => [k, String(v)]
408
407
  );
@@ -419,7 +418,7 @@ function renderHealthcheckHtml(body) {
419
418
  font-weight: 700;
420
419
  color: #E4E4E7;
421
420
  ">Healthcheck</span>
422
- ${renderStatusBadge("OK", color)}
421
+ ${renderStatusBadge(status, color)}
423
422
  </div>
424
423
  ${renderMetadataItems(allItems)}`
425
424
  );
@@ -61,8 +61,8 @@ function httpStatusCode(status) {
61
61
  // src/handler.ts
62
62
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
63
63
  function createHealthcheckHandler(options) {
64
- const { registry, resolveDepth, metadata = {}, shallowMetadata } = options;
65
- for (const bag of [metadata, shallowMetadata ?? {}]) {
64
+ const { registry, resolveDetail, metadata = {}, summaryMetadata } = options;
65
+ for (const bag of [metadata, summaryMetadata ?? {}]) {
66
66
  for (const key of Object.keys(bag)) {
67
67
  if (RESERVED_METADATA_KEYS.includes(key)) {
68
68
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
@@ -70,29 +70,29 @@ function createHealthcheckHandler(options) {
70
70
  }
71
71
  }
72
72
  return async (req) => {
73
- let depth = "shallow";
74
- if (resolveDepth) {
73
+ let detail = "summary";
74
+ if (resolveDetail) {
75
75
  try {
76
- const result = await resolveDepth(req);
77
- if (result === "deep" || result === "shallow") {
78
- depth = result;
76
+ const result = await resolveDetail(req);
77
+ if (result === "full" || result === "summary") {
78
+ detail = result;
79
79
  }
80
80
  } catch {
81
81
  }
82
82
  }
83
- if (depth === "deep") {
84
- const response = await registry.run();
83
+ const response = await registry.run();
84
+ if (detail === "full") {
85
85
  return {
86
86
  status: httpStatusCode(response.status),
87
87
  body: { ...metadata, ...toJson(response) }
88
88
  };
89
89
  }
90
90
  const body = {
91
- status: "ok",
92
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
93
- ...shallowMetadata ?? metadata
91
+ status: statusToLabel(response.status),
92
+ timestamp: response.timestamp,
93
+ ...summaryMetadata ?? metadata
94
94
  };
95
- return { status: 200, body };
95
+ return { status: httpStatusCode(response.status), body };
96
96
  };
97
97
  }
98
98
 
@@ -103,7 +103,6 @@ function escapeHtml(str) {
103
103
  function statusColor(status) {
104
104
  switch (status) {
105
105
  case "healthy":
106
- case "ok":
107
106
  return "#22C55E";
108
107
  case "degraded":
109
108
  return "#F59E0B";
@@ -115,10 +114,10 @@ function statusColor(status) {
115
114
  }
116
115
  var DEEP_KNOWN_KEYS = /* @__PURE__ */ new Set(["status", "timestamp", "checks", "cachedAt"]);
117
116
  function isDeepResponse(body) {
118
- return "checks" in body && "status" in body && body.status !== "ok";
117
+ return "checks" in body && "status" in body;
119
118
  }
120
- function isShallowResponse(body) {
121
- return "status" in body && body.status === "ok";
119
+ function isSummaryResponse(body) {
120
+ return "status" in body && !("checks" in body) && !("error" in body);
122
121
  }
123
122
  function isErrorResponse(body) {
124
123
  return "error" in body && !("status" in body);
@@ -277,9 +276,9 @@ function renderHealthcheckHtml(body) {
277
276
  ">${escapeHtml(body.error)}</div>`
278
277
  );
279
278
  }
280
- if (isShallowResponse(body)) {
281
- const color = statusColor("ok");
282
- const { status: _, timestamp, ...rest } = body;
279
+ if (isSummaryResponse(body)) {
280
+ const color = statusColor(body.status);
281
+ const { status, timestamp, ...rest } = body;
283
282
  const metadataItems = Object.entries(rest).map(
284
283
  ([k, v]) => [k, String(v)]
285
284
  );
@@ -296,7 +295,7 @@ function renderHealthcheckHtml(body) {
296
295
  font-weight: 700;
297
296
  color: #E4E4E7;
298
297
  ">Healthcheck</span>
299
- ${renderStatusBadge("OK", color)}
298
+ ${renderStatusBadge(status, color)}
300
299
  </div>
301
300
  ${renderMetadataItems(allItems)}`
302
301
  );
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler } from 'express';
2
- import { H as HealthcheckHandlerOptions } from '../handler-C3eTDuSQ.cjs';
2
+ import { H as HealthcheckHandlerOptions } from '../handler-MWB6zBBG.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-DaFJivGK.js';
2
+ import { H as HealthcheckHandlerOptions } from '../handler-B1Omp5VP.js';
3
3
  import '../core-Bee03bJm.js';
4
4
 
5
5
  type HealthcheckMiddlewareOptions = HealthcheckHandlerOptions;
@@ -35,8 +35,8 @@ function httpStatusCode(status) {
35
35
  // src/handler.ts
36
36
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
37
37
  function createHealthcheckHandler(options) {
38
- const { registry, resolveDepth, metadata = {}, shallowMetadata } = options;
39
- for (const bag of [metadata, shallowMetadata ?? {}]) {
38
+ const { registry, resolveDetail, metadata = {}, summaryMetadata } = options;
39
+ for (const bag of [metadata, summaryMetadata ?? {}]) {
40
40
  for (const key of Object.keys(bag)) {
41
41
  if (RESERVED_METADATA_KEYS.includes(key)) {
42
42
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
@@ -44,29 +44,29 @@ function createHealthcheckHandler(options) {
44
44
  }
45
45
  }
46
46
  return async (req) => {
47
- let depth = "shallow";
48
- if (resolveDepth) {
47
+ let detail = "summary";
48
+ if (resolveDetail) {
49
49
  try {
50
- const result = await resolveDepth(req);
51
- if (result === "deep" || result === "shallow") {
52
- depth = result;
50
+ const result = await resolveDetail(req);
51
+ if (result === "full" || result === "summary") {
52
+ detail = result;
53
53
  }
54
54
  } catch {
55
55
  }
56
56
  }
57
- if (depth === "deep") {
58
- const response = await registry.run();
57
+ const response = await registry.run();
58
+ if (detail === "full") {
59
59
  return {
60
60
  status: httpStatusCode(response.status),
61
61
  body: { ...metadata, ...toJson(response) }
62
62
  };
63
63
  }
64
64
  const body = {
65
- status: "ok",
66
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
67
- ...shallowMetadata ?? metadata
65
+ status: statusToLabel(response.status),
66
+ timestamp: response.timestamp,
67
+ ...summaryMetadata ?? metadata
68
68
  };
69
- return { status: 200, body };
69
+ return { status: httpStatusCode(response.status), body };
70
70
  };
71
71
  }
72
72
 
@@ -77,7 +77,6 @@ function escapeHtml(str) {
77
77
  function statusColor(status) {
78
78
  switch (status) {
79
79
  case "healthy":
80
- case "ok":
81
80
  return "#22C55E";
82
81
  case "degraded":
83
82
  return "#F59E0B";
@@ -89,10 +88,10 @@ function statusColor(status) {
89
88
  }
90
89
  var DEEP_KNOWN_KEYS = /* @__PURE__ */ new Set(["status", "timestamp", "checks", "cachedAt"]);
91
90
  function isDeepResponse(body) {
92
- return "checks" in body && "status" in body && body.status !== "ok";
91
+ return "checks" in body && "status" in body;
93
92
  }
94
- function isShallowResponse(body) {
95
- return "status" in body && body.status === "ok";
93
+ function isSummaryResponse(body) {
94
+ return "status" in body && !("checks" in body) && !("error" in body);
96
95
  }
97
96
  function isErrorResponse(body) {
98
97
  return "error" in body && !("status" in body);
@@ -251,9 +250,9 @@ function renderHealthcheckHtml(body) {
251
250
  ">${escapeHtml(body.error)}</div>`
252
251
  );
253
252
  }
254
- if (isShallowResponse(body)) {
255
- const color = statusColor("ok");
256
- const { status: _, timestamp, ...rest } = body;
253
+ if (isSummaryResponse(body)) {
254
+ const color = statusColor(body.status);
255
+ const { status, timestamp, ...rest } = body;
257
256
  const metadataItems = Object.entries(rest).map(
258
257
  ([k, v]) => [k, String(v)]
259
258
  );
@@ -270,7 +269,7 @@ function renderHealthcheckHtml(body) {
270
269
  font-weight: 700;
271
270
  color: #E4E4E7;
272
271
  ">Healthcheck</span>
273
- ${renderStatusBadge("OK", color)}
272
+ ${renderStatusBadge(status, color)}
274
273
  </div>
275
274
  ${renderMetadataItems(allItems)}`
276
275
  );
@@ -61,8 +61,8 @@ function httpStatusCode(status) {
61
61
  // src/handler.ts
62
62
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
63
63
  function createHealthcheckHandler(options) {
64
- const { registry, resolveDepth, metadata = {}, shallowMetadata } = options;
65
- for (const bag of [metadata, shallowMetadata ?? {}]) {
64
+ const { registry, resolveDetail, metadata = {}, summaryMetadata } = options;
65
+ for (const bag of [metadata, summaryMetadata ?? {}]) {
66
66
  for (const key of Object.keys(bag)) {
67
67
  if (RESERVED_METADATA_KEYS.includes(key)) {
68
68
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
@@ -70,29 +70,29 @@ function createHealthcheckHandler(options) {
70
70
  }
71
71
  }
72
72
  return async (req) => {
73
- let depth = "shallow";
74
- if (resolveDepth) {
73
+ let detail = "summary";
74
+ if (resolveDetail) {
75
75
  try {
76
- const result = await resolveDepth(req);
77
- if (result === "deep" || result === "shallow") {
78
- depth = result;
76
+ const result = await resolveDetail(req);
77
+ if (result === "full" || result === "summary") {
78
+ detail = result;
79
79
  }
80
80
  } catch {
81
81
  }
82
82
  }
83
- if (depth === "deep") {
84
- const response = await registry.run();
83
+ const response = await registry.run();
84
+ if (detail === "full") {
85
85
  return {
86
86
  status: httpStatusCode(response.status),
87
87
  body: { ...metadata, ...toJson(response) }
88
88
  };
89
89
  }
90
90
  const body = {
91
- status: "ok",
92
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
93
- ...shallowMetadata ?? metadata
91
+ status: statusToLabel(response.status),
92
+ timestamp: response.timestamp,
93
+ ...summaryMetadata ?? metadata
94
94
  };
95
- return { status: 200, body };
95
+ return { status: httpStatusCode(response.status), body };
96
96
  };
97
97
  }
98
98
 
@@ -103,7 +103,6 @@ function escapeHtml(str) {
103
103
  function statusColor(status) {
104
104
  switch (status) {
105
105
  case "healthy":
106
- case "ok":
107
106
  return "#22C55E";
108
107
  case "degraded":
109
108
  return "#F59E0B";
@@ -115,10 +114,10 @@ function statusColor(status) {
115
114
  }
116
115
  var DEEP_KNOWN_KEYS = /* @__PURE__ */ new Set(["status", "timestamp", "checks", "cachedAt"]);
117
116
  function isDeepResponse(body) {
118
- return "checks" in body && "status" in body && body.status !== "ok";
117
+ return "checks" in body && "status" in body;
119
118
  }
120
- function isShallowResponse(body) {
121
- return "status" in body && body.status === "ok";
119
+ function isSummaryResponse(body) {
120
+ return "status" in body && !("checks" in body) && !("error" in body);
122
121
  }
123
122
  function isErrorResponse(body) {
124
123
  return "error" in body && !("status" in body);
@@ -277,9 +276,9 @@ function renderHealthcheckHtml(body) {
277
276
  ">${escapeHtml(body.error)}</div>`
278
277
  );
279
278
  }
280
- if (isShallowResponse(body)) {
281
- const color = statusColor("ok");
282
- const { status: _, timestamp, ...rest } = body;
279
+ if (isSummaryResponse(body)) {
280
+ const color = statusColor(body.status);
281
+ const { status, timestamp, ...rest } = body;
283
282
  const metadataItems = Object.entries(rest).map(
284
283
  ([k, v]) => [k, String(v)]
285
284
  );
@@ -296,7 +295,7 @@ function renderHealthcheckHtml(body) {
296
295
  font-weight: 700;
297
296
  color: #E4E4E7;
298
297
  ">Healthcheck</span>
299
- ${renderStatusBadge("OK", color)}
298
+ ${renderStatusBadge(status, color)}
300
299
  </div>
301
300
  ${renderMetadataItems(allItems)}`
302
301
  );
@@ -1,4 +1,4 @@
1
- import { H as HealthcheckHandlerOptions } from '../handler-C3eTDuSQ.cjs';
1
+ import { H as HealthcheckHandlerOptions } from '../handler-MWB6zBBG.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
- * resolveDepth: (req) => req.ip === '10.0.0.1' ? 'deep' : 'shallow',
18
+ * resolveDetail: (req) => req.ip === '10.0.0.1' ? 'full' : 'summary',
19
19
  * });
20
20
  * ```
21
21
  */
@@ -1,4 +1,4 @@
1
- import { H as HealthcheckHandlerOptions } from '../handler-DaFJivGK.js';
1
+ import { H as HealthcheckHandlerOptions } from '../handler-B1Omp5VP.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
- * resolveDepth: (req) => req.ip === '10.0.0.1' ? 'deep' : 'shallow',
18
+ * resolveDetail: (req) => req.ip === '10.0.0.1' ? 'full' : 'summary',
19
19
  * });
20
20
  * ```
21
21
  */
@@ -35,8 +35,8 @@ function httpStatusCode(status) {
35
35
  // src/handler.ts
36
36
  var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks", "cachedAt"];
37
37
  function createHealthcheckHandler(options) {
38
- const { registry, resolveDepth, metadata = {}, shallowMetadata } = options;
39
- for (const bag of [metadata, shallowMetadata ?? {}]) {
38
+ const { registry, resolveDetail, metadata = {}, summaryMetadata } = options;
39
+ for (const bag of [metadata, summaryMetadata ?? {}]) {
40
40
  for (const key of Object.keys(bag)) {
41
41
  if (RESERVED_METADATA_KEYS.includes(key)) {
42
42
  throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
@@ -44,29 +44,29 @@ function createHealthcheckHandler(options) {
44
44
  }
45
45
  }
46
46
  return async (req) => {
47
- let depth = "shallow";
48
- if (resolveDepth) {
47
+ let detail = "summary";
48
+ if (resolveDetail) {
49
49
  try {
50
- const result = await resolveDepth(req);
51
- if (result === "deep" || result === "shallow") {
52
- depth = result;
50
+ const result = await resolveDetail(req);
51
+ if (result === "full" || result === "summary") {
52
+ detail = result;
53
53
  }
54
54
  } catch {
55
55
  }
56
56
  }
57
- if (depth === "deep") {
58
- const response = await registry.run();
57
+ const response = await registry.run();
58
+ if (detail === "full") {
59
59
  return {
60
60
  status: httpStatusCode(response.status),
61
61
  body: { ...metadata, ...toJson(response) }
62
62
  };
63
63
  }
64
64
  const body = {
65
- status: "ok",
66
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
67
- ...shallowMetadata ?? metadata
65
+ status: statusToLabel(response.status),
66
+ timestamp: response.timestamp,
67
+ ...summaryMetadata ?? metadata
68
68
  };
69
- return { status: 200, body };
69
+ return { status: httpStatusCode(response.status), body };
70
70
  };
71
71
  }
72
72
 
@@ -77,7 +77,6 @@ function escapeHtml(str) {
77
77
  function statusColor(status) {
78
78
  switch (status) {
79
79
  case "healthy":
80
- case "ok":
81
80
  return "#22C55E";
82
81
  case "degraded":
83
82
  return "#F59E0B";
@@ -89,10 +88,10 @@ function statusColor(status) {
89
88
  }
90
89
  var DEEP_KNOWN_KEYS = /* @__PURE__ */ new Set(["status", "timestamp", "checks", "cachedAt"]);
91
90
  function isDeepResponse(body) {
92
- return "checks" in body && "status" in body && body.status !== "ok";
91
+ return "checks" in body && "status" in body;
93
92
  }
94
- function isShallowResponse(body) {
95
- return "status" in body && body.status === "ok";
93
+ function isSummaryResponse(body) {
94
+ return "status" in body && !("checks" in body) && !("error" in body);
96
95
  }
97
96
  function isErrorResponse(body) {
98
97
  return "error" in body && !("status" in body);
@@ -251,9 +250,9 @@ function renderHealthcheckHtml(body) {
251
250
  ">${escapeHtml(body.error)}</div>`
252
251
  );
253
252
  }
254
- if (isShallowResponse(body)) {
255
- const color = statusColor("ok");
256
- const { status: _, timestamp, ...rest } = body;
253
+ if (isSummaryResponse(body)) {
254
+ const color = statusColor(body.status);
255
+ const { status, timestamp, ...rest } = body;
257
256
  const metadataItems = Object.entries(rest).map(
258
257
  ([k, v]) => [k, String(v)]
259
258
  );
@@ -270,7 +269,7 @@ function renderHealthcheckHtml(body) {
270
269
  font-weight: 700;
271
270
  color: #E4E4E7;
272
271
  ">Healthcheck</span>
273
- ${renderStatusBadge("OK", color)}
272
+ ${renderStatusBadge(status, color)}
274
273
  </div>
275
274
  ${renderMetadataItems(allItems)}`
276
275
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firebreak/vitals",
3
- "version": "2.2.0",
3
+ "version": "3.0.0",
4
4
  "description": "Deep healthcheck endpoints following the HEALTHCHECK_SPEC format",
5
5
  "type": "module",
6
6
  "exports": {
@@ -107,6 +107,7 @@
107
107
  "build": "tsup",
108
108
  "test": "vitest run",
109
109
  "test:watch": "vitest",
110
+ "test:coverage": "vitest run --coverage",
110
111
  "lint": "tsc --noEmit"
111
112
  },
112
113
  "peerDependencies": {
@@ -130,6 +131,7 @@
130
131
  "@types/node": "^22.0.0",
131
132
  "@types/pg": "^8.0.0",
132
133
  "@types/supertest": "^6.0.0",
134
+ "@vitest/coverage-v8": "^2.1.9",
133
135
  "express": "^4.21.0",
134
136
  "ioredis": "^5.0.0",
135
137
  "pg": "^8.13.0",
@@ -1,21 +0,0 @@
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
- shallowMetadata?: Record<string, string | number | boolean>;
9
- }
10
- interface ShallowResponseJson {
11
- status: 'ok';
12
- timestamp: string;
13
- [key: string]: string | number | boolean;
14
- }
15
- interface HealthcheckHandlerResult {
16
- status: number;
17
- body: HealthcheckResponseJson | ShallowResponseJson;
18
- }
19
- declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: Record<string, unknown>) => Promise<HealthcheckHandlerResult>;
20
-
21
- export { type HealthcheckHandlerOptions as H, type ResolveDepthFn as R, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, createHealthcheckHandler as c };
@@ -1,21 +0,0 @@
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
- shallowMetadata?: Record<string, string | number | boolean>;
9
- }
10
- interface ShallowResponseJson {
11
- status: 'ok';
12
- timestamp: string;
13
- [key: string]: string | number | boolean;
14
- }
15
- interface HealthcheckHandlerResult {
16
- status: number;
17
- body: HealthcheckResponseJson | ShallowResponseJson;
18
- }
19
- declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: Record<string, unknown>) => Promise<HealthcheckHandlerResult>;
20
-
21
- export { type HealthcheckHandlerOptions as H, type ResolveDepthFn as R, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, createHealthcheckHandler as c };