@firebreak/vitals 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -14
- package/dist/{handler-Bccbso4b.d.cts → handler-Bvf66wzh.d.cts} +8 -7
- package/dist/{handler-D0nYVQvu.d.ts → handler-R2U3ygLo.d.ts} +8 -7
- package/dist/index.cjs +17 -3
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +17 -3
- package/dist/integrations/express.cjs +17 -3
- package/dist/integrations/express.d.cts +1 -1
- package/dist/integrations/express.d.ts +1 -1
- package/dist/integrations/express.mjs +17 -3
- package/dist/integrations/next.cjs +17 -3
- package/dist/integrations/next.d.cts +1 -1
- package/dist/integrations/next.d.ts +1 -1
- package/dist/integrations/next.mjs +17 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vitals (Node.js)
|
|
2
2
|
|
|
3
|
-
Structured
|
|
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.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -36,9 +36,21 @@ const app = express();
|
|
|
36
36
|
app.get('/vitals', createHealthcheckMiddleware({
|
|
37
37
|
registry,
|
|
38
38
|
token: process.env.VITALS_TOKEN,
|
|
39
|
+
metadata: {
|
|
40
|
+
build: process.env.BUILD_SHA,
|
|
41
|
+
buildTimestamp: process.env.BUILD_TIMESTAMP,
|
|
42
|
+
},
|
|
39
43
|
}));
|
|
40
44
|
```
|
|
41
45
|
|
|
46
|
+
Hit `/vitals` without a token to get a shallow response:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{ "status": "ok", "timestamp": "...", "build": "stg-45d76e5", "buildTimestamp": "2025-02-25T19:41:56Z" }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Provide the token (`?token=...` or `Authorization: Bearer ...`) to get the full deep response with check results.
|
|
53
|
+
|
|
42
54
|
## Quick Start (Next.js)
|
|
43
55
|
|
|
44
56
|
```typescript
|
|
@@ -58,6 +70,9 @@ registry.add('api', httpCheck(`${process.env.API_BASE_URL}/health`));
|
|
|
58
70
|
export const GET = createNextHandler({
|
|
59
71
|
registry,
|
|
60
72
|
token: process.env.VITALS_TOKEN,
|
|
73
|
+
metadata: {
|
|
74
|
+
build: process.env.BUILD_SHA,
|
|
75
|
+
},
|
|
61
76
|
});
|
|
62
77
|
```
|
|
63
78
|
|
|
@@ -194,6 +209,9 @@ app.get('/vitals', createHealthcheckMiddleware({
|
|
|
194
209
|
registry,
|
|
195
210
|
token: 'my-secret-token', // optional — omit to disable auth
|
|
196
211
|
queryParamName: 'token', // default: 'token'
|
|
212
|
+
metadata: { // optional — included in shallow & deep responses
|
|
213
|
+
build: 'stg-45d76e5',
|
|
214
|
+
},
|
|
197
215
|
}));
|
|
198
216
|
```
|
|
199
217
|
|
|
@@ -205,6 +223,7 @@ import { createNextHandler } from '@firebreak/vitals/next';
|
|
|
205
223
|
export const GET = createNextHandler({
|
|
206
224
|
registry,
|
|
207
225
|
token: process.env.VITALS_TOKEN,
|
|
226
|
+
metadata: { build: process.env.BUILD_SHA },
|
|
208
227
|
});
|
|
209
228
|
```
|
|
210
229
|
|
|
@@ -215,19 +234,55 @@ For other frameworks, use the generic handler directly:
|
|
|
215
234
|
```typescript
|
|
216
235
|
import { createHealthcheckHandler } from '@firebreak/vitals';
|
|
217
236
|
|
|
218
|
-
const handle = createHealthcheckHandler({
|
|
237
|
+
const handle = createHealthcheckHandler({
|
|
238
|
+
registry,
|
|
239
|
+
token: process.env.VITALS_TOKEN,
|
|
240
|
+
metadata: { build: 'stg-45d76e5' },
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// No token → shallow response
|
|
244
|
+
const shallow = await handle({});
|
|
245
|
+
// { status: 200, body: { status: 'ok', timestamp: '...', build: 'stg-45d76e5' } }
|
|
219
246
|
|
|
220
|
-
//
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
247
|
+
// Valid token → deep response
|
|
248
|
+
const deep = await handle({ queryParams: { token: '...' } });
|
|
249
|
+
// { status: 200, body: { status: 'healthy', timestamp: '...', build: 'stg-45d76e5', checks: { ... } } }
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Shallow / Deep Responses
|
|
253
|
+
|
|
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 | Deep response always (backwards-compatible) |
|
|
262
|
+
|
|
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.
|
|
264
|
+
|
|
265
|
+
### Metadata
|
|
266
|
+
|
|
267
|
+
Attach static key-value pairs that appear in both shallow and deep responses:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
createHealthcheckHandler({
|
|
271
|
+
registry,
|
|
272
|
+
token: process.env.VITALS_TOKEN,
|
|
273
|
+
metadata: {
|
|
274
|
+
build: 'stg-45d76e5',
|
|
275
|
+
buildTimestamp: '2025-02-25T19:41:56Z',
|
|
276
|
+
region: 'us-east-1',
|
|
277
|
+
},
|
|
224
278
|
});
|
|
225
|
-
// result = { status: 200, body: { status: 'healthy', ... } }
|
|
226
279
|
```
|
|
227
280
|
|
|
281
|
+
Metadata values can be `string`, `number`, or `boolean`. Keys `status`, `timestamp`, and `checks` are reserved — passing them throws at handler creation time.
|
|
282
|
+
|
|
228
283
|
### Authentication
|
|
229
284
|
|
|
230
|
-
|
|
285
|
+
Tokens can be provided via:
|
|
231
286
|
- Query parameter: `?token=my-secret-token`
|
|
232
287
|
- Bearer header: `Authorization: Bearer my-secret-token`
|
|
233
288
|
|
|
@@ -247,10 +302,25 @@ const token = extractToken({
|
|
|
247
302
|
|
|
248
303
|
## Response Format
|
|
249
304
|
|
|
305
|
+
**Shallow response** (no token provided):
|
|
306
|
+
|
|
307
|
+
```json
|
|
308
|
+
{
|
|
309
|
+
"status": "ok",
|
|
310
|
+
"timestamp": "2025-02-26T12:00:00.000Z",
|
|
311
|
+
"build": "stg-45d76e5",
|
|
312
|
+
"buildTimestamp": "2025-02-25T19:41:56Z"
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Deep response** (valid token provided):
|
|
317
|
+
|
|
250
318
|
```json
|
|
251
319
|
{
|
|
252
320
|
"status": "healthy",
|
|
253
321
|
"timestamp": "2025-02-26T12:00:00.000Z",
|
|
322
|
+
"build": "stg-45d76e5",
|
|
323
|
+
"buildTimestamp": "2025-02-25T19:41:56Z",
|
|
254
324
|
"checks": {
|
|
255
325
|
"postgres": {
|
|
256
326
|
"status": "healthy",
|
|
@@ -266,12 +336,13 @@ const token = extractToken({
|
|
|
266
336
|
}
|
|
267
337
|
```
|
|
268
338
|
|
|
269
|
-
|
|
|
270
|
-
|
|
271
|
-
| `
|
|
272
|
-
| `
|
|
273
|
-
| `
|
|
274
|
-
|
|
|
339
|
+
| Condition | HTTP Code | Status |
|
|
340
|
+
|-----------|-----------|--------|
|
|
341
|
+
| Shallow (no token) | `200` | `"ok"` |
|
|
342
|
+
| Deep — healthy | `200` | `"healthy"` |
|
|
343
|
+
| Deep — degraded | `503` | `"degraded"` |
|
|
344
|
+
| Deep — outage | `503` | `"outage"` |
|
|
345
|
+
| Invalid token | `403` | — |
|
|
275
346
|
|
|
276
347
|
## Requirements
|
|
277
348
|
|
|
@@ -4,22 +4,23 @@ interface HealthcheckHandlerOptions {
|
|
|
4
4
|
registry: HealthcheckRegistry;
|
|
5
5
|
token?: string | null;
|
|
6
6
|
queryParamName?: string;
|
|
7
|
+
metadata?: Record<string, string | number | boolean>;
|
|
7
8
|
}
|
|
8
9
|
interface HealthcheckRequest {
|
|
9
10
|
queryParams?: Record<string, string | string[] | undefined>;
|
|
10
11
|
authorizationHeader?: string | null;
|
|
11
12
|
}
|
|
13
|
+
interface ShallowResponseJson {
|
|
14
|
+
status: 'ok';
|
|
15
|
+
timestamp: string;
|
|
16
|
+
[key: string]: string | number | boolean;
|
|
17
|
+
}
|
|
12
18
|
interface HealthcheckHandlerResult {
|
|
13
19
|
status: number;
|
|
14
|
-
body: HealthcheckResponseJson | {
|
|
20
|
+
body: HealthcheckResponseJson | ShallowResponseJson | {
|
|
15
21
|
error: string;
|
|
16
22
|
};
|
|
17
23
|
}
|
|
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
24
|
declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: HealthcheckRequest) => Promise<HealthcheckHandlerResult>;
|
|
24
25
|
|
|
25
|
-
export { type HealthcheckHandlerOptions as H, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
|
|
26
|
+
export { type HealthcheckHandlerOptions as H, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
|
|
@@ -4,22 +4,23 @@ interface HealthcheckHandlerOptions {
|
|
|
4
4
|
registry: HealthcheckRegistry;
|
|
5
5
|
token?: string | null;
|
|
6
6
|
queryParamName?: string;
|
|
7
|
+
metadata?: Record<string, string | number | boolean>;
|
|
7
8
|
}
|
|
8
9
|
interface HealthcheckRequest {
|
|
9
10
|
queryParams?: Record<string, string | string[] | undefined>;
|
|
10
11
|
authorizationHeader?: string | null;
|
|
11
12
|
}
|
|
13
|
+
interface ShallowResponseJson {
|
|
14
|
+
status: 'ok';
|
|
15
|
+
timestamp: string;
|
|
16
|
+
[key: string]: string | number | boolean;
|
|
17
|
+
}
|
|
12
18
|
interface HealthcheckHandlerResult {
|
|
13
19
|
status: number;
|
|
14
|
-
body: HealthcheckResponseJson | {
|
|
20
|
+
body: HealthcheckResponseJson | ShallowResponseJson | {
|
|
15
21
|
error: string;
|
|
16
22
|
};
|
|
17
23
|
}
|
|
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
24
|
declare function createHealthcheckHandler(options: HealthcheckHandlerOptions): (req: HealthcheckRequest) => Promise<HealthcheckHandlerResult>;
|
|
24
25
|
|
|
25
|
-
export { type HealthcheckHandlerOptions as H, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
|
|
26
|
+
export { type HealthcheckHandlerOptions as H, type ShallowResponseJson as S, type HealthcheckHandlerResult as a, type HealthcheckRequest as b, createHealthcheckHandler as c };
|
package/dist/index.cjs
CHANGED
|
@@ -189,8 +189,14 @@ function extractToken(options) {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
// src/handler.ts
|
|
192
|
+
var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks"];
|
|
192
193
|
function createHealthcheckHandler(options) {
|
|
193
|
-
const { registry, token = null, queryParamName = "token" } = options;
|
|
194
|
+
const { registry, token = null, queryParamName = "token", metadata = {} } = options;
|
|
195
|
+
for (const key of Object.keys(metadata)) {
|
|
196
|
+
if (RESERVED_METADATA_KEYS.includes(key)) {
|
|
197
|
+
throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
194
200
|
return async (req) => {
|
|
195
201
|
if (token !== null) {
|
|
196
202
|
const provided = extractToken({
|
|
@@ -198,14 +204,22 @@ function createHealthcheckHandler(options) {
|
|
|
198
204
|
authorizationHeader: req.authorizationHeader,
|
|
199
205
|
queryParamName
|
|
200
206
|
});
|
|
201
|
-
if (provided === null
|
|
207
|
+
if (provided === null) {
|
|
208
|
+
const body = {
|
|
209
|
+
status: "ok",
|
|
210
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
211
|
+
...metadata
|
|
212
|
+
};
|
|
213
|
+
return { status: 200, body };
|
|
214
|
+
}
|
|
215
|
+
if (!verifyToken(provided, token)) {
|
|
202
216
|
return { status: 403, body: { error: "Forbidden" } };
|
|
203
217
|
}
|
|
204
218
|
}
|
|
205
219
|
const response = await registry.run();
|
|
206
220
|
return {
|
|
207
221
|
status: httpStatusCode(response.status),
|
|
208
|
-
body: toJson(response)
|
|
222
|
+
body: { ...metadata, ...toJson(response) }
|
|
209
223
|
};
|
|
210
224
|
};
|
|
211
225
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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-
|
|
2
|
+
export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, b as HealthcheckRequest, S as ShallowResponseJson, c as createHealthcheckHandler } from './handler-Bvf66wzh.cjs';
|
|
3
3
|
|
|
4
4
|
declare function verifyToken(provided: string, expected: string): boolean;
|
|
5
5
|
declare function extractToken(options: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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-
|
|
2
|
+
export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult, b as HealthcheckRequest, S as ShallowResponseJson, c as createHealthcheckHandler } from './handler-R2U3ygLo.js';
|
|
3
3
|
|
|
4
4
|
declare function verifyToken(provided: string, expected: string): boolean;
|
|
5
5
|
declare function extractToken(options: {
|
package/dist/index.mjs
CHANGED
|
@@ -154,8 +154,14 @@ function extractToken(options) {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
// src/handler.ts
|
|
157
|
+
var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks"];
|
|
157
158
|
function createHealthcheckHandler(options) {
|
|
158
|
-
const { registry, token = null, queryParamName = "token" } = options;
|
|
159
|
+
const { registry, token = null, queryParamName = "token", metadata = {} } = options;
|
|
160
|
+
for (const key of Object.keys(metadata)) {
|
|
161
|
+
if (RESERVED_METADATA_KEYS.includes(key)) {
|
|
162
|
+
throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
159
165
|
return async (req) => {
|
|
160
166
|
if (token !== null) {
|
|
161
167
|
const provided = extractToken({
|
|
@@ -163,14 +169,22 @@ function createHealthcheckHandler(options) {
|
|
|
163
169
|
authorizationHeader: req.authorizationHeader,
|
|
164
170
|
queryParamName
|
|
165
171
|
});
|
|
166
|
-
if (provided === null
|
|
172
|
+
if (provided === null) {
|
|
173
|
+
const body = {
|
|
174
|
+
status: "ok",
|
|
175
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
176
|
+
...metadata
|
|
177
|
+
};
|
|
178
|
+
return { status: 200, body };
|
|
179
|
+
}
|
|
180
|
+
if (!verifyToken(provided, token)) {
|
|
167
181
|
return { status: 403, body: { error: "Forbidden" } };
|
|
168
182
|
}
|
|
169
183
|
}
|
|
170
184
|
const response = await registry.run();
|
|
171
185
|
return {
|
|
172
186
|
status: httpStatusCode(response.status),
|
|
173
|
-
body: toJson(response)
|
|
187
|
+
body: { ...metadata, ...toJson(response) }
|
|
174
188
|
};
|
|
175
189
|
};
|
|
176
190
|
}
|
|
@@ -77,8 +77,14 @@ function httpStatusCode(status) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// src/handler.ts
|
|
80
|
+
var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks"];
|
|
80
81
|
function createHealthcheckHandler(options) {
|
|
81
|
-
const { registry, token = null, queryParamName = "token" } = options;
|
|
82
|
+
const { registry, token = null, queryParamName = "token", metadata = {} } = options;
|
|
83
|
+
for (const key of Object.keys(metadata)) {
|
|
84
|
+
if (RESERVED_METADATA_KEYS.includes(key)) {
|
|
85
|
+
throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
82
88
|
return async (req) => {
|
|
83
89
|
if (token !== null) {
|
|
84
90
|
const provided = extractToken({
|
|
@@ -86,14 +92,22 @@ function createHealthcheckHandler(options) {
|
|
|
86
92
|
authorizationHeader: req.authorizationHeader,
|
|
87
93
|
queryParamName
|
|
88
94
|
});
|
|
89
|
-
if (provided === null
|
|
95
|
+
if (provided === null) {
|
|
96
|
+
const body = {
|
|
97
|
+
status: "ok",
|
|
98
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
99
|
+
...metadata
|
|
100
|
+
};
|
|
101
|
+
return { status: 200, body };
|
|
102
|
+
}
|
|
103
|
+
if (!verifyToken(provided, token)) {
|
|
90
104
|
return { status: 403, body: { error: "Forbidden" } };
|
|
91
105
|
}
|
|
92
106
|
}
|
|
93
107
|
const response = await registry.run();
|
|
94
108
|
return {
|
|
95
109
|
status: httpStatusCode(response.status),
|
|
96
|
-
body: toJson(response)
|
|
110
|
+
body: { ...metadata, ...toJson(response) }
|
|
97
111
|
};
|
|
98
112
|
};
|
|
99
113
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestHandler } from 'express';
|
|
2
|
-
import { H as HealthcheckHandlerOptions } from '../handler-
|
|
2
|
+
import { H as HealthcheckHandlerOptions } from '../handler-Bvf66wzh.cjs';
|
|
3
3
|
import '../core-BJ2Z0rRi.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-
|
|
2
|
+
import { H as HealthcheckHandlerOptions } from '../handler-R2U3ygLo.js';
|
|
3
3
|
import '../core-BJ2Z0rRi.js';
|
|
4
4
|
|
|
5
5
|
type HealthcheckMiddlewareOptions = HealthcheckHandlerOptions;
|
|
@@ -51,8 +51,14 @@ function httpStatusCode(status) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// src/handler.ts
|
|
54
|
+
var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks"];
|
|
54
55
|
function createHealthcheckHandler(options) {
|
|
55
|
-
const { registry, token = null, queryParamName = "token" } = options;
|
|
56
|
+
const { registry, token = null, queryParamName = "token", metadata = {} } = options;
|
|
57
|
+
for (const key of Object.keys(metadata)) {
|
|
58
|
+
if (RESERVED_METADATA_KEYS.includes(key)) {
|
|
59
|
+
throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
56
62
|
return async (req) => {
|
|
57
63
|
if (token !== null) {
|
|
58
64
|
const provided = extractToken({
|
|
@@ -60,14 +66,22 @@ function createHealthcheckHandler(options) {
|
|
|
60
66
|
authorizationHeader: req.authorizationHeader,
|
|
61
67
|
queryParamName
|
|
62
68
|
});
|
|
63
|
-
if (provided === null
|
|
69
|
+
if (provided === null) {
|
|
70
|
+
const body = {
|
|
71
|
+
status: "ok",
|
|
72
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
73
|
+
...metadata
|
|
74
|
+
};
|
|
75
|
+
return { status: 200, body };
|
|
76
|
+
}
|
|
77
|
+
if (!verifyToken(provided, token)) {
|
|
64
78
|
return { status: 403, body: { error: "Forbidden" } };
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
81
|
const response = await registry.run();
|
|
68
82
|
return {
|
|
69
83
|
status: httpStatusCode(response.status),
|
|
70
|
-
body: toJson(response)
|
|
84
|
+
body: { ...metadata, ...toJson(response) }
|
|
71
85
|
};
|
|
72
86
|
};
|
|
73
87
|
}
|
|
@@ -77,8 +77,14 @@ function httpStatusCode(status) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// src/handler.ts
|
|
80
|
+
var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks"];
|
|
80
81
|
function createHealthcheckHandler(options) {
|
|
81
|
-
const { registry, token = null, queryParamName = "token" } = options;
|
|
82
|
+
const { registry, token = null, queryParamName = "token", metadata = {} } = options;
|
|
83
|
+
for (const key of Object.keys(metadata)) {
|
|
84
|
+
if (RESERVED_METADATA_KEYS.includes(key)) {
|
|
85
|
+
throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
82
88
|
return async (req) => {
|
|
83
89
|
if (token !== null) {
|
|
84
90
|
const provided = extractToken({
|
|
@@ -86,14 +92,22 @@ function createHealthcheckHandler(options) {
|
|
|
86
92
|
authorizationHeader: req.authorizationHeader,
|
|
87
93
|
queryParamName
|
|
88
94
|
});
|
|
89
|
-
if (provided === null
|
|
95
|
+
if (provided === null) {
|
|
96
|
+
const body = {
|
|
97
|
+
status: "ok",
|
|
98
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
99
|
+
...metadata
|
|
100
|
+
};
|
|
101
|
+
return { status: 200, body };
|
|
102
|
+
}
|
|
103
|
+
if (!verifyToken(provided, token)) {
|
|
90
104
|
return { status: 403, body: { error: "Forbidden" } };
|
|
91
105
|
}
|
|
92
106
|
}
|
|
93
107
|
const response = await registry.run();
|
|
94
108
|
return {
|
|
95
109
|
status: httpStatusCode(response.status),
|
|
96
|
-
body: toJson(response)
|
|
110
|
+
body: { ...metadata, ...toJson(response) }
|
|
97
111
|
};
|
|
98
112
|
};
|
|
99
113
|
}
|
|
@@ -51,8 +51,14 @@ function httpStatusCode(status) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// src/handler.ts
|
|
54
|
+
var RESERVED_METADATA_KEYS = ["status", "timestamp", "checks"];
|
|
54
55
|
function createHealthcheckHandler(options) {
|
|
55
|
-
const { registry, token = null, queryParamName = "token" } = options;
|
|
56
|
+
const { registry, token = null, queryParamName = "token", metadata = {} } = options;
|
|
57
|
+
for (const key of Object.keys(metadata)) {
|
|
58
|
+
if (RESERVED_METADATA_KEYS.includes(key)) {
|
|
59
|
+
throw new Error(`Metadata key '${key}' is reserved. Use a different key name.`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
56
62
|
return async (req) => {
|
|
57
63
|
if (token !== null) {
|
|
58
64
|
const provided = extractToken({
|
|
@@ -60,14 +66,22 @@ function createHealthcheckHandler(options) {
|
|
|
60
66
|
authorizationHeader: req.authorizationHeader,
|
|
61
67
|
queryParamName
|
|
62
68
|
});
|
|
63
|
-
if (provided === null
|
|
69
|
+
if (provided === null) {
|
|
70
|
+
const body = {
|
|
71
|
+
status: "ok",
|
|
72
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
73
|
+
...metadata
|
|
74
|
+
};
|
|
75
|
+
return { status: 200, body };
|
|
76
|
+
}
|
|
77
|
+
if (!verifyToken(provided, token)) {
|
|
64
78
|
return { status: 403, body: { error: "Forbidden" } };
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
81
|
const response = await registry.run();
|
|
68
82
|
return {
|
|
69
83
|
status: httpStatusCode(response.status),
|
|
70
|
-
body: toJson(response)
|
|
84
|
+
body: { ...metadata, ...toJson(response) }
|
|
71
85
|
};
|
|
72
86
|
};
|
|
73
87
|
}
|