@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.
- package/dist/handler-BvjN4Ot9.d.ts +20 -0
- package/dist/handler-TZOgZvY7.d.cts +20 -0
- package/dist/index.cjs +19 -39
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +19 -39
- package/dist/integrations/express.cjs +21 -61
- package/dist/integrations/express.d.cts +1 -1
- package/dist/integrations/express.d.ts +1 -1
- package/dist/integrations/express.mjs +21 -61
- package/dist/integrations/next.cjs +21 -61
- package/dist/integrations/next.d.cts +2 -2
- package/dist/integrations/next.d.ts +2 -2
- package/dist/integrations/next.mjs +21 -61
- package/package.json +1 -1
- package/dist/handler-COH7lot9.d.cts +0 -27
- package/dist/handler-CVYUad84.d.ts +0 -27
|
@@ -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,
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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-
|
|
4
|
-
export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult,
|
|
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-
|
|
4
|
-
export { H as HealthcheckHandlerOptions, a as HealthcheckHandlerResult,
|
|
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,
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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,
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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-
|
|
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-
|
|
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,
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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,
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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-
|
|
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
|
-
*
|
|
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-
|
|
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
|
-
*
|
|
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,
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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,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 };
|