@visulima/health-check 1.0.1 → 1.0.3
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/CHANGELOG.md +15 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +17 -248
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -246
- package/dist/index.mjs.map +1 -1
- package/package.json +31 -30
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## @visulima/health-check [1.0.3](https://github.com/visulima/visulima/compare/@visulima/health-check@1.0.2...@visulima/health-check@1.0.3) (2023-01-25)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* updated tsconfig to use module esnext and target es2021 ([#107](https://github.com/visulima/visulima/issues/107)) ([e888fe8](https://github.com/visulima/visulima/commit/e888fe8d15c99453a3c04f2cf9d2f6c69c158648))
|
|
7
|
+
|
|
8
|
+
## @visulima/health-check [1.0.2](https://github.com/visulima/visulima/compare/@visulima/health-check@1.0.1...@visulima/health-check@1.0.2) (2023-01-08)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* allow higher node versions ([c93d55b](https://github.com/visulima/visulima/commit/c93d55b80135282235e933da52d9c88ade3073a8))
|
|
14
|
+
* allow higher node versions ([faf4780](https://github.com/visulima/visulima/commit/faf478069f3508249db22ed2171ddee4fa380122))
|
|
15
|
+
|
|
1
16
|
## @visulima/health-check [1.0.1](https://github.com/visulima/visulima/compare/@visulima/health-check@1.0.0...@visulima/health-check@1.0.1) (2022-11-16)
|
|
2
17
|
|
|
3
18
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import {
|
|
2
|
+
import { Options, IPFamily } from 'cacheable-lookup';
|
|
3
3
|
import { extendedPingOptions } from 'pingman';
|
|
4
4
|
|
|
5
5
|
type Checker = () => Promise<HealthReportEntry>;
|
|
@@ -30,9 +30,9 @@ type HealthReport = {
|
|
|
30
30
|
*/
|
|
31
31
|
interface HealthCheck {
|
|
32
32
|
servicesList: string[];
|
|
33
|
-
addChecker(service: string, checker: Checker)
|
|
34
|
-
isLive()
|
|
35
|
-
getReport()
|
|
33
|
+
addChecker: (service: string, checker: Checker) => void;
|
|
34
|
+
isLive: () => Promise<boolean>;
|
|
35
|
+
getReport: () => Promise<{ healthy: boolean; report: HealthReport }>;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
declare const _default$1: (healthCheck: HealthCheck, sendHeader?: boolean | undefined) => <Request_1 extends IncomingMessage, Response_1 extends ServerResponse<IncomingMessage>>(_: Request_1, response: Response_1) => Promise<void>;
|
|
@@ -51,10 +51,10 @@ declare class Healthcheck implements HealthCheck {
|
|
|
51
51
|
isLive(): Promise<boolean>;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
declare const dnsCheck: (host: string, expectedAddresses?: string[], options?: {
|
|
54
|
+
declare const dnsCheck: (host: string, expectedAddresses?: string[], options?: Options & {
|
|
55
55
|
family?: IPFamily | "all";
|
|
56
56
|
hints?: number;
|
|
57
|
-
}
|
|
57
|
+
}) => Checker;
|
|
58
58
|
|
|
59
59
|
declare const httpCheck: (host: RequestInfo | URL, options?: {
|
|
60
60
|
fetchOptions?: RequestInit;
|
|
@@ -64,7 +64,7 @@ declare const httpCheck: (host: RequestInfo | URL, options?: {
|
|
|
64
64
|
};
|
|
65
65
|
}) => Checker;
|
|
66
66
|
|
|
67
|
-
declare const nodeEnvironmentCheck: (
|
|
67
|
+
declare const nodeEnvironmentCheck: (expectedEnvironment?: string) => Checker;
|
|
68
68
|
|
|
69
69
|
declare const pingCheck: (host: string, options?: extendedPingOptions) => Checker;
|
|
70
70
|
|
package/dist/index.js
CHANGED
|
@@ -1,249 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
// src/handler/readyhandler.ts
|
|
21
|
-
|
|
22
|
-
var readyhandler_default = (healthCheck) => async (_request, response) => {
|
|
23
|
-
const { healthy } = await healthCheck.getReport();
|
|
24
|
-
response.statusCode = healthy ? _httpstatuscodes.StatusCodes.NO_CONTENT : _httpstatuscodes.StatusCodes.SERVICE_UNAVAILABLE;
|
|
25
|
-
response.end();
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// src/healthcheck.ts
|
|
29
|
-
var Healthcheck = class {
|
|
30
|
-
constructor() {
|
|
31
|
-
this.healthCheckers = {};
|
|
32
|
-
}
|
|
33
|
-
get servicesList() {
|
|
34
|
-
return Object.keys(this.healthCheckers);
|
|
35
|
-
}
|
|
36
|
-
async invokeChecker(service, reportSheet) {
|
|
37
|
-
const checker = this.healthCheckers[service];
|
|
38
|
-
let report;
|
|
39
|
-
try {
|
|
40
|
-
report = await checker();
|
|
41
|
-
report.displayName = report.displayName || service;
|
|
42
|
-
} catch (error) {
|
|
43
|
-
report = {
|
|
44
|
-
displayName: service,
|
|
45
|
-
health: { healthy: false, message: error.message, timestamp: new Date().toISOString() },
|
|
46
|
-
meta: { fatal: true }
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
reportSheet[service] = report;
|
|
50
|
-
return report.health.healthy;
|
|
51
|
-
}
|
|
52
|
-
addChecker(service, checker) {
|
|
53
|
-
this.healthCheckers[service] = checker;
|
|
54
|
-
}
|
|
55
|
-
async getReport() {
|
|
56
|
-
const report = {};
|
|
57
|
-
await Promise.all(Object.keys(this.healthCheckers).map((service) => this.invokeChecker(service, report)));
|
|
58
|
-
const unhealthyService = Object.keys(report).find((service) => !report[service].health.healthy);
|
|
59
|
-
return { healthy: !unhealthyService, report };
|
|
60
|
-
}
|
|
61
|
-
async isLive() {
|
|
62
|
-
const { healthy } = await this.getReport();
|
|
63
|
-
return healthy;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
var healthcheck_default2 = Healthcheck;
|
|
67
|
-
|
|
68
|
-
// src/checks/dns-check.ts
|
|
69
|
-
var _cacheablelookup = require('cacheable-lookup'); var _cacheablelookup2 = _interopRequireDefault(_cacheablelookup);
|
|
70
|
-
var DISPLAY_NAME = "DNS check for";
|
|
71
|
-
var dnsCheck = (host, expectedAddresses, options) => async () => {
|
|
72
|
-
const { hints, family = "all", ...config } = options || {};
|
|
73
|
-
const cacheable = new (0, _cacheablelookup2.default)(config);
|
|
74
|
-
try {
|
|
75
|
-
const meta = await cacheable.lookupAsync(host.replace(/^https?:\/\//, ""), {
|
|
76
|
-
hints,
|
|
77
|
-
...family === "all" ? { all: true } : { family }
|
|
78
|
-
});
|
|
79
|
-
if (Array.isArray(expectedAddresses) && !(expectedAddresses == null ? void 0 : expectedAddresses.includes(meta.address))) {
|
|
80
|
-
return {
|
|
81
|
-
displayName: `${DISPLAY_NAME} ${host}`,
|
|
82
|
-
health: {
|
|
83
|
-
healthy: false,
|
|
84
|
-
message: `${DISPLAY_NAME} ${host} returned address ${meta.address} instead of ${expectedAddresses.join(", ")}.`,
|
|
85
|
-
timestamp: new Date().toISOString()
|
|
86
|
-
},
|
|
87
|
-
meta: {
|
|
88
|
-
host,
|
|
89
|
-
addresses: meta
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
displayName: `${DISPLAY_NAME} ${host}`,
|
|
95
|
-
health: {
|
|
96
|
-
healthy: true,
|
|
97
|
-
message: `${DISPLAY_NAME} ${host} were resolved.`,
|
|
98
|
-
timestamp: new Date().toISOString()
|
|
99
|
-
},
|
|
100
|
-
meta: {
|
|
101
|
-
host,
|
|
102
|
-
addresses: meta
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return {
|
|
107
|
-
displayName: `${DISPLAY_NAME} ${host}`,
|
|
108
|
-
health: {
|
|
109
|
-
healthy: false,
|
|
110
|
-
message: error.message,
|
|
111
|
-
timestamp: new Date().toISOString()
|
|
112
|
-
},
|
|
113
|
-
meta: {
|
|
114
|
-
host
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
var dns_check_default = dnsCheck;
|
|
120
|
-
|
|
121
|
-
// src/checks/http-check.ts
|
|
122
|
-
var _assert = require('assert');
|
|
123
|
-
var DISPLAY_NAME2 = "HTTP check for";
|
|
124
|
-
var httpCheck = (host, options) => async () => {
|
|
125
|
-
var _a, _b, _c, _d, _e;
|
|
126
|
-
try {
|
|
127
|
-
const response = await fetch(host, (options == null ? void 0 : options.fetchOptions) || {});
|
|
128
|
-
if (typeof ((_a = options == null ? void 0 : options.expected) == null ? void 0 : _a.status) !== "undefined" && ((_b = options == null ? void 0 : options.expected) == null ? void 0 : _b.status) !== response.status) {
|
|
129
|
-
throw new Error(`${DISPLAY_NAME2} ${host} returned status ${response.status} instead of ${options == null ? void 0 : options.expected.status}`);
|
|
130
|
-
}
|
|
131
|
-
if (typeof ((_c = options == null ? void 0 : options.expected) == null ? void 0 : _c.body) !== "undefined") {
|
|
132
|
-
const textBody = await response.text();
|
|
133
|
-
try {
|
|
134
|
-
_assert.deepStrictEqual.call(void 0, textBody, options == null ? void 0 : options.expected.body);
|
|
135
|
-
} catch (e) {
|
|
136
|
-
throw new Error(`${DISPLAY_NAME2} ${host} returned body ${JSON.stringify(textBody)} instead of ${JSON.stringify(options == null ? void 0 : options.expected.body)}`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
displayName: `${DISPLAY_NAME2} ${host}`,
|
|
141
|
-
health: {
|
|
142
|
-
healthy: true,
|
|
143
|
-
message: `${DISPLAY_NAME2} ${host} was successful.`,
|
|
144
|
-
timestamp: new Date().toISOString()
|
|
145
|
-
},
|
|
146
|
-
meta: {
|
|
147
|
-
host,
|
|
148
|
-
method: ((_d = options == null ? void 0 : options.fetchOptions) == null ? void 0 : _d.method) || "GET",
|
|
149
|
-
status: response.status
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
} catch (error) {
|
|
153
|
-
return {
|
|
154
|
-
displayName: `${DISPLAY_NAME2} ${host}`,
|
|
155
|
-
health: {
|
|
156
|
-
healthy: false,
|
|
157
|
-
message: error.message,
|
|
158
|
-
timestamp: new Date().toISOString()
|
|
159
|
-
},
|
|
160
|
-
meta: {
|
|
161
|
-
host,
|
|
162
|
-
method: ((_e = options == null ? void 0 : options.fetchOptions) == null ? void 0 : _e.method) || "GET"
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
var http_check_default = httpCheck;
|
|
168
|
-
|
|
169
|
-
// src/checks/node-environment-check.ts
|
|
170
|
-
var DISPLAY_NAME3 = "Node Environment Check";
|
|
171
|
-
var nodeEnvironmentCheck = (expectedEnv) => async () => {
|
|
172
|
-
const environment = "development";
|
|
173
|
-
let errorMessage;
|
|
174
|
-
if (typeof environment !== "undefined" && typeof expectedEnv !== "undefined" && environment !== expectedEnv) {
|
|
175
|
-
errorMessage = `NODE_ENV environment variable is set to "${environment}" instead of "${expectedEnv}".`;
|
|
176
|
-
} else if (typeof environment === "undefined") {
|
|
177
|
-
errorMessage = ["Missing NODE_ENV environment variable.", "It can make some parts of the application misbehave"].join(" ");
|
|
178
|
-
}
|
|
179
|
-
if (typeof errorMessage !== "undefined") {
|
|
180
|
-
return {
|
|
181
|
-
displayName: DISPLAY_NAME3,
|
|
182
|
-
health: {
|
|
183
|
-
healthy: false,
|
|
184
|
-
message: errorMessage,
|
|
185
|
-
timestamp: new Date().toISOString()
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
displayName: DISPLAY_NAME3,
|
|
191
|
-
health: {
|
|
192
|
-
healthy: true,
|
|
193
|
-
timestamp: new Date().toISOString()
|
|
194
|
-
},
|
|
195
|
-
meta: {
|
|
196
|
-
env: environment
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
};
|
|
200
|
-
var node_environment_check_default = nodeEnvironmentCheck;
|
|
201
|
-
|
|
202
|
-
// src/checks/ping-check.ts
|
|
203
|
-
var _pingman = require('pingman'); var _pingman2 = _interopRequireDefault(_pingman);
|
|
204
|
-
var DISPLAY_NAME4 = "Ping check for";
|
|
205
|
-
var pingCheck = (host, options) => async () => {
|
|
206
|
-
try {
|
|
207
|
-
const response = await _pingman2.default.call(void 0, host.replace(/^https?:\/\//, ""), options);
|
|
208
|
-
if (!response.alive) {
|
|
209
|
-
return {
|
|
210
|
-
displayName: `${DISPLAY_NAME4} ${host}`,
|
|
211
|
-
health: {
|
|
212
|
-
healthy: false,
|
|
213
|
-
message: `Ping failed for ${host}.`,
|
|
214
|
-
timestamp: new Date().toISOString()
|
|
215
|
-
},
|
|
216
|
-
meta: response
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
displayName: `${DISPLAY_NAME4} ${host}`,
|
|
221
|
-
health: {
|
|
222
|
-
healthy: true,
|
|
223
|
-
message: `${DISPLAY_NAME4} ${host} was successful.`,
|
|
224
|
-
timestamp: new Date().toISOString()
|
|
225
|
-
},
|
|
226
|
-
meta: response
|
|
227
|
-
};
|
|
228
|
-
} catch (error) {
|
|
229
|
-
return {
|
|
230
|
-
displayName: `${DISPLAY_NAME4} ${host}`,
|
|
231
|
-
health: {
|
|
232
|
-
healthy: false,
|
|
233
|
-
message: error.message,
|
|
234
|
-
timestamp: new Date().toISOString()
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
var ping_check_default = pingCheck;
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
exports.HealthCheck = healthcheck_default2; exports.dnsCheck = dns_check_default; exports.healthCheckHandler = healthcheck_default; exports.healthReadyHandler = readyhandler_default; exports.httpCheck = http_check_default; exports.nodeEnvCheck = node_environment_check_default; exports.pingCheck = ping_check_default;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var httpStatusCodes = require('http-status-codes');
|
|
4
|
+
var k = require('cacheable-lookup');
|
|
5
|
+
var assert = require('assert');
|
|
6
|
+
var R = require('pingman');
|
|
7
|
+
|
|
8
|
+
var f=(t,e=!0)=>async(a,r)=>{let{healthy:s,report:o}=await t.getReport(),l={status:s?"ok":"error",message:s?"Health check successful":"Health check failed",appName:process.env.APP_NAME??"unknown",appVersion:process.env.APP_VERSION??"unknown",timestamp:new Date().toISOString(),reports:o};r.statusCode=s?httpStatusCodes.StatusCodes.OK:httpStatusCodes.StatusCodes.SERVICE_UNAVAILABLE,e&&r.setHeader("Content-Type","application/json"),r.end(JSON.stringify(l,null,2));};var u=t=>async(e,a)=>{let{healthy:r}=await t.getReport();a.statusCode=r?httpStatusCodes.StatusCodes.NO_CONTENT:httpStatusCodes.StatusCodes.SERVICE_UNAVAILABLE,a.end();};var c=class{constructor(){this.healthCheckers={};}get servicesList(){return Object.keys(this.healthCheckers)}async invokeChecker(e,a){let r=this.healthCheckers[e],s;try{s=await r(),s.displayName=s.displayName||e;}catch(o){s={displayName:e,health:{healthy:!1,message:o.message,timestamp:new Date().toISOString()},meta:{fatal:!0}};}return a[e]=s,s.health.healthy}addChecker(e,a){this.healthCheckers[e]=a;}async getReport(){let e={};return await Promise.all(Object.keys(this.healthCheckers).map(r=>this.invokeChecker(r,e))),{healthy:!Object.keys(e).find(r=>!e[r].health.healthy),report:e}}async isLive(){let{healthy:e}=await this.getReport();return e}},g=c;var i="DNS check for",C=(t,e,a)=>async()=>{let{hints:r,family:s="all",...o}=a??{},l=new k(o);try{let n=await l.lookupAsync(t.replace(/^https?:\/\//,""),{hints:r,...s==="all"?{all:!0}:{family:s}});return Array.isArray(e)&&!e.includes(n.address)?{displayName:`${i} ${t}`,health:{healthy:!1,message:`${i} ${t} returned address ${n.address} instead of ${e.join(", ")}.`,timestamp:new Date().toISOString()},meta:{host:t,addresses:n}}:{displayName:`${i} ${t}`,health:{healthy:!0,message:`${i} ${t} were resolved.`,timestamp:new Date().toISOString()},meta:{host:t,addresses:n}}}catch(n){return {displayName:`${i} ${t}`,health:{healthy:!1,message:n.message,timestamp:new Date().toISOString()},meta:{host:t}}}},S=C;var h="HTTP check for",$=(t,e)=>async()=>{try{let a=await fetch(t,e?.fetchOptions??{});if(e?.expected?.status!==void 0&&e.expected.status!==a.status)throw new Error(`${h} ${t} returned status ${a.status} instead of ${e.expected.status}`);if(e?.expected?.body!==void 0){let r=await a.text();try{assert.deepStrictEqual(r,e.expected.body);}catch{throw new Error(`${h} ${t} returned body ${JSON.stringify(r)} instead of ${JSON.stringify(e.expected.body)}`)}}return {displayName:`${h} ${t}`,health:{healthy:!0,message:`${h} ${t} was successful.`,timestamp:new Date().toISOString()},meta:{host:t,method:e?.fetchOptions?.method??"GET",status:a.status}}}catch(a){return {displayName:`${h} ${t}`,health:{healthy:!1,message:a.message,timestamp:new Date().toISOString()},meta:{host:t,method:e?.fetchOptions?.method??"GET"}}}},O=$;var y="Node Environment Check",E=t=>async()=>{let e="production",a;return t!==void 0&&e!==t?a=`NODE_ENV environment variable is set to "${e}" instead of "${t}".`:e,a!==void 0?{displayName:y,health:{healthy:!1,message:a,timestamp:new Date().toISOString()}}:{displayName:y,health:{healthy:!0,timestamp:new Date().toISOString()},meta:{env:e}}},I=E;var p="Ping check for",w=(t,e)=>async()=>{try{let a=await R(t.replace(/^https?:\/\//,""),e);return a.alive?{displayName:`${p} ${t}`,health:{healthy:!0,message:`${p} ${t} was successful.`,timestamp:new Date().toISOString()},meta:a}:{displayName:`${p} ${t}`,health:{healthy:!1,message:`Ping failed for ${t}.`,timestamp:new Date().toISOString()},meta:a}}catch(a){return {displayName:`${p} ${t}`,health:{healthy:!1,message:a.message,timestamp:new Date().toISOString()}}}},x=w;
|
|
9
|
+
|
|
10
|
+
exports.HealthCheck = g;
|
|
11
|
+
exports.dnsCheck = S;
|
|
12
|
+
exports.healthCheckHandler = f;
|
|
13
|
+
exports.healthReadyHandler = u;
|
|
14
|
+
exports.httpCheck = O;
|
|
15
|
+
exports.nodeEnvCheck = I;
|
|
16
|
+
exports.pingCheck = x;
|
|
17
|
+
//# sourceMappingURL=out.js.map
|
|
249
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handler/healthcheck.ts","../src/handler/readyhandler.ts","../src/healthcheck.ts","../src/checks/dns-check.ts","../src/checks/http-check.ts","../src/checks/node-environment-check.ts","../src/checks/ping-check.ts"],"names":["StatusCodes","healthcheck_default","DISPLAY_NAME"],"mappings":"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","sourcesContent":["import { StatusCodes } from \"http-status-codes\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { HealthCheck, HealthReport } from \"../types\";\n\nexport default (healthCheck: HealthCheck, sendHeader: boolean | undefined = true) =>\n async <Request extends IncomingMessage, Response extends ServerResponse>(_: Request, response: Response) => {\n const { healthy, report } = await healthCheck.getReport();\n\n const payload: HealthCheckApiPayload = {\n status: healthy ? \"ok\" : \"error\",\n message: healthy ? \"Health check successful\" : \"Health check failed\",\n appName: process.env.APP_NAME ?? \"unknown\",\n appVersion: process.env.APP_VERSION ?? \"unknown\",\n timestamp: new Date().toISOString(),\n reports: report,\n };\n\n response.statusCode = healthy ? StatusCodes.OK : StatusCodes.SERVICE_UNAVAILABLE;\n\n if (sendHeader) {\n response.setHeader(\"Content-Type\", \"application/json\");\n }\n\n response.end(JSON.stringify(payload, null, 2));\n };\n\nexport type HealthCheckApiPayload = {\n status: \"ok\" | \"error\";\n message: string;\n appName: string;\n appVersion: string;\n timestamp: string;\n reports: HealthReport;\n};\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { StatusCodes } from \"http-status-codes\";\n\nimport type { HealthCheck } from \"../types\";\n\nexport default <Request extends IncomingMessage, Response extends ServerResponse>(healthCheck: HealthCheck) => async (_request: Request, response: Response) => {\n const { healthy } = await healthCheck.getReport();\n\n response.statusCode = healthy ? StatusCodes.NO_CONTENT : StatusCodes.SERVICE_UNAVAILABLE;\n response.end()\n};\n","import {\n Checker, HealthCheck as HealthcheckInterface, HealthReport, HealthReportEntry,\n} from \"./types\";\n\nclass Healthcheck implements HealthcheckInterface {\n /**\n * A copy of registered checkers\n */\n private healthCheckers: { [service: string]: Checker } = {};\n\n /**\n * Returns an array of registered services names\n */\n public get servicesList(): string[] {\n return Object.keys(this.healthCheckers);\n }\n\n /**\n * Invokes a given checker to collect the report metrics.\n */\n private async invokeChecker(service: string, reportSheet: HealthReport): Promise<boolean> {\n const checker = this.healthCheckers[service] as Checker;\n\n let report: HealthReportEntry;\n\n try {\n report = await checker();\n\n report.displayName = report.displayName || service;\n } catch (error: any) {\n report = {\n displayName: service,\n health: { healthy: false, message: error.message, timestamp: new Date().toISOString() },\n meta: { fatal: true },\n };\n }\n\n // eslint-disable-next-line no-param-reassign\n reportSheet[service] = report;\n\n return report.health.healthy;\n }\n\n public addChecker(service: string, checker: Checker): void {\n this.healthCheckers[service] = checker;\n }\n\n /**\n * Returns the health check reports. The health checks are performed when\n * this method is invoked.\n */\n public async getReport(): Promise<{ healthy: boolean; report: HealthReport }> {\n const report: HealthReport = {};\n\n // eslint-disable-next-line compat/compat\n await Promise.all(Object.keys(this.healthCheckers).map((service) => this.invokeChecker(service, report)));\n\n /**\n * Finding unhealthy service to know if system is healthy or not\n */\n const unhealthyService = Object.keys(report).find((service) => !(report[service] as HealthReportEntry).health.healthy);\n\n return { healthy: !unhealthyService, report };\n }\n\n public async isLive(): Promise<boolean> {\n const { healthy } = await this.getReport();\n\n return healthy;\n }\n}\n\nexport default Healthcheck;\n","import type { IPFamily, Options } from \"cacheable-lookup\";\nimport CacheableLookup from \"cacheable-lookup\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"DNS check for\";\n\n/**\n * Register the `dns` checker to ensure that a domain is reachable.\n */\nconst dnsCheck = (\n host: string,\n expectedAddresses?: string[],\n options?: {\n family?: IPFamily | \"all\";\n hints?: number;\n } & Options,\n): Checker => async () => {\n const { hints, family = \"all\", ...config } = options || {};\n\n const cacheable = new CacheableLookup(config);\n\n try {\n const meta = await cacheable.lookupAsync(host.replace(/^https?:\\/\\//, \"\"), {\n hints,\n ...(family === \"all\" ? { all: true } : { family: family as IPFamily }),\n });\n\n if (Array.isArray(expectedAddresses) && !expectedAddresses?.includes(meta.address)) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `${DISPLAY_NAME} ${host} returned address ${meta.address} instead of ${expectedAddresses.join(\", \")}.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} were resolved.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: error.message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n },\n };\n }\n};\n\nexport default dnsCheck;\n","import { deepStrictEqual } from \"node:assert\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"HTTP check for\";\n\n/**\n * Register the `http` checker to ensure http body and status is correct.\n */\nconst httpCheck =\n (host: RequestInfo | URL, options?: {\n fetchOptions?: RequestInit,\n expected?: { status?: number; body?: string }\n }): Checker =>\n async () => {\n try {\n // eslint-disable-next-line compat/compat\n const response = await fetch(host, options?.fetchOptions || {});\n\n if (typeof options?.expected?.status !== \"undefined\" && options?.expected?.status !== response.status) {\n throw new Error(`${DISPLAY_NAME} ${host} returned status ${response.status} instead of ${options?.expected.status}`);\n }\n\n if (typeof options?.expected?.body !== \"undefined\") {\n const textBody = await response.text();\n\n try {\n deepStrictEqual(textBody, options?.expected.body);\n } catch {\n throw new Error(`${DISPLAY_NAME} ${host} returned body ${JSON.stringify(textBody)} instead of ${JSON.stringify(options?.expected.body)}`);\n }\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method || \"GET\",\n status: response.status,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: error.message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method || \"GET\",\n },\n };\n }\n };\n\nexport default httpCheck;\n","import type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Node Environment Check\";\n\n/**\n * Register the `env` checker to ensure that `NODE_ENV` environment\n * variable is defined.\n */\nconst nodeEnvironmentCheck = (expectedEnv?: string): Checker => async () => {\n const environment = process.env.NODE_ENV;\n\n let errorMessage: string | undefined;\n\n if (typeof environment !== \"undefined\" && typeof expectedEnv !== \"undefined\" && environment !== expectedEnv) {\n errorMessage = `NODE_ENV environment variable is set to \"${environment}\" instead of \"${expectedEnv}\".`;\n } else if (typeof environment === \"undefined\") {\n errorMessage = [\"Missing NODE_ENV environment variable.\", \"It can make some parts of the application misbehave\"].join(\" \");\n }\n\n if (typeof errorMessage !== \"undefined\") {\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: false,\n message: errorMessage,\n timestamp: new Date().toISOString(),\n },\n };\n }\n\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: true,\n timestamp: new Date().toISOString(),\n },\n meta: {\n env: environment,\n },\n };\n};\n\nexport default nodeEnvironmentCheck;\n","import type { extendedPingOptions } from \"pingman\";\nimport ping from \"pingman\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Ping check for\";\n\n/**\n * Register the `ping` checker to ensure that a domain is reachable.\n */\nconst pingCheck = (host: string, options?: extendedPingOptions): Checker => async () => {\n try {\n const response = await ping(host.replace(/^https?:\\/\\//, \"\"), options);\n\n if (!response.alive) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `Ping failed for ${host}.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: error.message,\n timestamp: new Date().toISOString(),\n },\n };\n }\n};\n\nexport default pingCheck;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/handler/healthcheck.ts","../src/handler/readyhandler.ts","../src/healthcheck.ts","../src/checks/dns-check.ts","../src/checks/http-check.ts","../src/checks/node-environment-check.ts","../src/checks/ping-check.ts"],"names":["StatusCodes","healthcheck_default","healthCheck","sendHeader","_","response","healthy","report","payload","readyhandler_default","_request","Healthcheck","service","reportSheet","checker","error","CacheableLookup","DISPLAY_NAME","dnsCheck","host","expectedAddresses","options","hints","family","config","cacheable","meta","dns_check_default","deepStrictEqual","httpCheck","textBody","http_check_default","nodeEnvironmentCheck","expectedEnvironment","environment","errorMessage","node_environment_check_default","ping","pingCheck","ping_check_default"],"mappings":"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","sourcesContent":["import { StatusCodes } from \"http-status-codes\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { HealthCheck, HealthReport } from \"../types\";\n\n// eslint-disable-next-line max-len\nexport default (healthCheck: HealthCheck, sendHeader: boolean | undefined = true) => async <Request extends IncomingMessage, Response extends ServerResponse>(_: Request, response: Response): Promise<void> => {\n const { healthy, report } = await healthCheck.getReport();\n\n const payload: HealthCheckApiPayload = {\n status: healthy ? \"ok\" : \"error\",\n message: healthy ? \"Health check successful\" : \"Health check failed\",\n appName: process.env[\"APP_NAME\"] ?? \"unknown\",\n appVersion: process.env[\"APP_VERSION\"] ?? \"unknown\",\n timestamp: new Date().toISOString(),\n reports: report,\n };\n\n response.statusCode = healthy ? StatusCodes.OK : StatusCodes.SERVICE_UNAVAILABLE;\n\n if (sendHeader) {\n response.setHeader(\"Content-Type\", \"application/json\");\n }\n\n response.end(JSON.stringify(payload, null, 2));\n};\n\nexport type HealthCheckApiPayload = {\n status: \"error\" | \"ok\";\n message: string;\n appName: string;\n appVersion: string;\n timestamp: string;\n reports: HealthReport;\n};\n","import { StatusCodes } from \"http-status-codes\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { HealthCheck } from \"../types\";\n\n// eslint-disable-next-line max-len\nexport default <Request extends IncomingMessage, Response extends ServerResponse>(healthCheck: HealthCheck) => async (_request: Request, response: Response): Promise<void> => {\n const { healthy } = await healthCheck.getReport();\n\n response.statusCode = healthy ? StatusCodes.NO_CONTENT : StatusCodes.SERVICE_UNAVAILABLE;\n response.end();\n};\n","import type {\n Checker, HealthCheck as HealthcheckInterface, HealthReport, HealthReportEntry,\n} from \"./types.d\";\n\nclass Healthcheck implements HealthcheckInterface {\n /**\n * A copy of registered checkers\n */\n private healthCheckers: { [service: string]: Checker } = {};\n\n /**\n * Returns an array of registered services names\n */\n public get servicesList(): string[] {\n return Object.keys(this.healthCheckers);\n }\n\n /**\n * Invokes a given checker to collect the report metrics.\n */\n private async invokeChecker(service: string, reportSheet: HealthReport): Promise<boolean> {\n const checker = this.healthCheckers[service] as Checker;\n\n let report: HealthReportEntry;\n\n try {\n report = await checker();\n\n report.displayName = report.displayName || service;\n } catch (error: any) {\n report = {\n displayName: service,\n health: { healthy: false, message: (error as Error).message, timestamp: new Date().toISOString() },\n meta: { fatal: true },\n };\n }\n\n // eslint-disable-next-line no-param-reassign\n reportSheet[service] = report;\n\n return report.health.healthy;\n }\n\n public addChecker(service: string, checker: Checker): void {\n this.healthCheckers[service] = checker;\n }\n\n /**\n * Returns the health check reports. The health checks are performed when\n * this method is invoked.\n */\n public async getReport(): Promise<{ healthy: boolean; report: HealthReport }> {\n const report: HealthReport = {};\n\n // eslint-disable-next-line compat/compat\n await Promise.all(Object.keys(this.healthCheckers).map((service) => this.invokeChecker(service, report)));\n\n /**\n * Finding unhealthy service to know if system is healthy or not\n */\n const unhealthyService = Object.keys(report).find((service) => !(report[service] as HealthReportEntry).health.healthy);\n\n return { healthy: !unhealthyService, report };\n }\n\n public async isLive(): Promise<boolean> {\n const { healthy } = await this.getReport();\n\n return healthy;\n }\n}\n\nexport default Healthcheck;\n","import type { IPFamily, Options } from \"cacheable-lookup\";\nimport CacheableLookup from \"cacheable-lookup\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"DNS check for\";\n\n/**\n * Register the `dns` checker to ensure that a domain is reachable.\n */\nconst dnsCheck = (\n host: string,\n expectedAddresses?: string[],\n options?: Options & {\n family?: IPFamily | \"all\";\n hints?: number;\n },\n): Checker => async () => {\n const { hints, family = \"all\", ...config } = options ?? {};\n\n const cacheable = new CacheableLookup(config);\n\n try {\n const meta = await cacheable.lookupAsync(host.replace(/^https?:\\/\\//, \"\"), {\n hints,\n ...(family === \"all\" ? { all: true } : { family }),\n });\n\n if (Array.isArray(expectedAddresses) && !expectedAddresses.includes(meta.address)) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `${DISPLAY_NAME} ${host} returned address ${meta.address} instead of ${expectedAddresses.join(\", \")}.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} were resolved.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: (error as Error).message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n },\n };\n }\n};\n\nexport default dnsCheck;\n","import { deepStrictEqual } from \"node:assert\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"HTTP check for\";\n\n/**\n * Register the `http` checker to ensure http body and status is correct.\n */\nconst httpCheck = (host: RequestInfo | URL, options?: {\n fetchOptions?: RequestInit,\n expected?: { status?: number; body?: string }\n}): Checker => async () => {\n try {\n // eslint-disable-next-line compat/compat\n const response = await fetch(host, options?.fetchOptions ?? {});\n\n if (options?.expected?.status !== undefined && options.expected.status !== response.status) {\n throw new Error(`${DISPLAY_NAME} ${host} returned status ${response.status} instead of ${options.expected.status}`);\n }\n\n if (options?.expected?.body !== undefined) {\n const textBody = await response.text();\n\n try {\n deepStrictEqual(textBody, options.expected.body);\n } catch {\n throw new Error(`${DISPLAY_NAME} ${host} returned body ${JSON.stringify(textBody)} instead of ${JSON.stringify(options.expected.body)}`);\n }\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method ?? \"GET\",\n status: response.status,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: (error as Error).message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method ?? \"GET\",\n },\n };\n }\n};\n\nexport default httpCheck;\n","import type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Node Environment Check\";\n\n/**\n * Register the `env` checker to ensure that `NODE_ENV` environment\n * variable is defined.\n */\nconst nodeEnvironmentCheck = (expectedEnvironment?: string): Checker => async () => {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n const environment: string | undefined = process.env[\"NODE_ENV\"];\n\n let errorMessage: string | undefined;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (environment !== undefined && expectedEnvironment !== undefined && environment !== expectedEnvironment) {\n errorMessage = `NODE_ENV environment variable is set to \"${environment}\" instead of \"${expectedEnvironment}\".`;\n } else if (!environment) {\n errorMessage = [\"Missing NODE_ENV environment variable.\", \"It can make some parts of the application misbehave\"].join(\" \");\n }\n\n if (errorMessage !== undefined) {\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: false,\n message: errorMessage,\n timestamp: new Date().toISOString(),\n },\n };\n }\n\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: true,\n timestamp: new Date().toISOString(),\n },\n meta: {\n env: environment,\n },\n };\n};\n\nexport default nodeEnvironmentCheck;\n","import type { extendedPingOptions } from \"pingman\";\nimport ping from \"pingman\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Ping check for\";\n\n/**\n * Register the `ping` checker to ensure that a domain is reachable.\n */\nconst pingCheck = (host: string, options?: extendedPingOptions): Checker => async () => {\n try {\n const response = await ping(host.replace(/^https?:\\/\\//, \"\"), options);\n\n if (!response.alive) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `Ping failed for ${host}.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: (error as Error).message,\n timestamp: new Date().toISOString(),\n },\n };\n }\n};\n\nexport default pingCheck;\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,249 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const payload = {
|
|
6
|
-
status: healthy ? "ok" : "error",
|
|
7
|
-
message: healthy ? "Health check successful" : "Health check failed",
|
|
8
|
-
appName: process.env.APP_NAME ?? "unknown",
|
|
9
|
-
appVersion: process.env.APP_VERSION ?? "unknown",
|
|
10
|
-
timestamp: new Date().toISOString(),
|
|
11
|
-
reports: report
|
|
12
|
-
};
|
|
13
|
-
response.statusCode = healthy ? StatusCodes.OK : StatusCodes.SERVICE_UNAVAILABLE;
|
|
14
|
-
if (sendHeader) {
|
|
15
|
-
response.setHeader("Content-Type", "application/json");
|
|
16
|
-
}
|
|
17
|
-
response.end(JSON.stringify(payload, null, 2));
|
|
18
|
-
};
|
|
1
|
+
import { StatusCodes } from 'http-status-codes';
|
|
2
|
+
import k from 'cacheable-lookup';
|
|
3
|
+
import { deepStrictEqual } from 'assert';
|
|
4
|
+
import R from 'pingman';
|
|
19
5
|
|
|
20
|
-
|
|
21
|
-
import { StatusCodes as StatusCodes2 } from "http-status-codes";
|
|
22
|
-
var readyhandler_default = (healthCheck) => async (_request, response) => {
|
|
23
|
-
const { healthy } = await healthCheck.getReport();
|
|
24
|
-
response.statusCode = healthy ? StatusCodes2.NO_CONTENT : StatusCodes2.SERVICE_UNAVAILABLE;
|
|
25
|
-
response.end();
|
|
26
|
-
};
|
|
6
|
+
var f=(t,e=!0)=>async(a,r)=>{let{healthy:s,report:o}=await t.getReport(),l={status:s?"ok":"error",message:s?"Health check successful":"Health check failed",appName:process.env.APP_NAME??"unknown",appVersion:process.env.APP_VERSION??"unknown",timestamp:new Date().toISOString(),reports:o};r.statusCode=s?StatusCodes.OK:StatusCodes.SERVICE_UNAVAILABLE,e&&r.setHeader("Content-Type","application/json"),r.end(JSON.stringify(l,null,2));};var u=t=>async(e,a)=>{let{healthy:r}=await t.getReport();a.statusCode=r?StatusCodes.NO_CONTENT:StatusCodes.SERVICE_UNAVAILABLE,a.end();};var c=class{constructor(){this.healthCheckers={};}get servicesList(){return Object.keys(this.healthCheckers)}async invokeChecker(e,a){let r=this.healthCheckers[e],s;try{s=await r(),s.displayName=s.displayName||e;}catch(o){s={displayName:e,health:{healthy:!1,message:o.message,timestamp:new Date().toISOString()},meta:{fatal:!0}};}return a[e]=s,s.health.healthy}addChecker(e,a){this.healthCheckers[e]=a;}async getReport(){let e={};return await Promise.all(Object.keys(this.healthCheckers).map(r=>this.invokeChecker(r,e))),{healthy:!Object.keys(e).find(r=>!e[r].health.healthy),report:e}}async isLive(){let{healthy:e}=await this.getReport();return e}},g=c;var i="DNS check for",C=(t,e,a)=>async()=>{let{hints:r,family:s="all",...o}=a??{},l=new k(o);try{let n=await l.lookupAsync(t.replace(/^https?:\/\//,""),{hints:r,...s==="all"?{all:!0}:{family:s}});return Array.isArray(e)&&!e.includes(n.address)?{displayName:`${i} ${t}`,health:{healthy:!1,message:`${i} ${t} returned address ${n.address} instead of ${e.join(", ")}.`,timestamp:new Date().toISOString()},meta:{host:t,addresses:n}}:{displayName:`${i} ${t}`,health:{healthy:!0,message:`${i} ${t} were resolved.`,timestamp:new Date().toISOString()},meta:{host:t,addresses:n}}}catch(n){return {displayName:`${i} ${t}`,health:{healthy:!1,message:n.message,timestamp:new Date().toISOString()},meta:{host:t}}}},S=C;var h="HTTP check for",$=(t,e)=>async()=>{try{let a=await fetch(t,e?.fetchOptions??{});if(e?.expected?.status!==void 0&&e.expected.status!==a.status)throw new Error(`${h} ${t} returned status ${a.status} instead of ${e.expected.status}`);if(e?.expected?.body!==void 0){let r=await a.text();try{deepStrictEqual(r,e.expected.body);}catch{throw new Error(`${h} ${t} returned body ${JSON.stringify(r)} instead of ${JSON.stringify(e.expected.body)}`)}}return {displayName:`${h} ${t}`,health:{healthy:!0,message:`${h} ${t} was successful.`,timestamp:new Date().toISOString()},meta:{host:t,method:e?.fetchOptions?.method??"GET",status:a.status}}}catch(a){return {displayName:`${h} ${t}`,health:{healthy:!1,message:a.message,timestamp:new Date().toISOString()},meta:{host:t,method:e?.fetchOptions?.method??"GET"}}}},O=$;var y="Node Environment Check",E=t=>async()=>{let e="production",a;return t!==void 0&&e!==t?a=`NODE_ENV environment variable is set to "${e}" instead of "${t}".`:e,a!==void 0?{displayName:y,health:{healthy:!1,message:a,timestamp:new Date().toISOString()}}:{displayName:y,health:{healthy:!0,timestamp:new Date().toISOString()},meta:{env:e}}},I=E;var p="Ping check for",w=(t,e)=>async()=>{try{let a=await R(t.replace(/^https?:\/\//,""),e);return a.alive?{displayName:`${p} ${t}`,health:{healthy:!0,message:`${p} ${t} was successful.`,timestamp:new Date().toISOString()},meta:a}:{displayName:`${p} ${t}`,health:{healthy:!1,message:`Ping failed for ${t}.`,timestamp:new Date().toISOString()},meta:a}}catch(a){return {displayName:`${p} ${t}`,health:{healthy:!1,message:a.message,timestamp:new Date().toISOString()}}}},x=w;
|
|
27
7
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
constructor() {
|
|
31
|
-
this.healthCheckers = {};
|
|
32
|
-
}
|
|
33
|
-
get servicesList() {
|
|
34
|
-
return Object.keys(this.healthCheckers);
|
|
35
|
-
}
|
|
36
|
-
async invokeChecker(service, reportSheet) {
|
|
37
|
-
const checker = this.healthCheckers[service];
|
|
38
|
-
let report;
|
|
39
|
-
try {
|
|
40
|
-
report = await checker();
|
|
41
|
-
report.displayName = report.displayName || service;
|
|
42
|
-
} catch (error) {
|
|
43
|
-
report = {
|
|
44
|
-
displayName: service,
|
|
45
|
-
health: { healthy: false, message: error.message, timestamp: new Date().toISOString() },
|
|
46
|
-
meta: { fatal: true }
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
reportSheet[service] = report;
|
|
50
|
-
return report.health.healthy;
|
|
51
|
-
}
|
|
52
|
-
addChecker(service, checker) {
|
|
53
|
-
this.healthCheckers[service] = checker;
|
|
54
|
-
}
|
|
55
|
-
async getReport() {
|
|
56
|
-
const report = {};
|
|
57
|
-
await Promise.all(Object.keys(this.healthCheckers).map((service) => this.invokeChecker(service, report)));
|
|
58
|
-
const unhealthyService = Object.keys(report).find((service) => !report[service].health.healthy);
|
|
59
|
-
return { healthy: !unhealthyService, report };
|
|
60
|
-
}
|
|
61
|
-
async isLive() {
|
|
62
|
-
const { healthy } = await this.getReport();
|
|
63
|
-
return healthy;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
var healthcheck_default2 = Healthcheck;
|
|
67
|
-
|
|
68
|
-
// src/checks/dns-check.ts
|
|
69
|
-
import CacheableLookup from "cacheable-lookup";
|
|
70
|
-
var DISPLAY_NAME = "DNS check for";
|
|
71
|
-
var dnsCheck = (host, expectedAddresses, options) => async () => {
|
|
72
|
-
const { hints, family = "all", ...config } = options || {};
|
|
73
|
-
const cacheable = new CacheableLookup(config);
|
|
74
|
-
try {
|
|
75
|
-
const meta = await cacheable.lookupAsync(host.replace(/^https?:\/\//, ""), {
|
|
76
|
-
hints,
|
|
77
|
-
...family === "all" ? { all: true } : { family }
|
|
78
|
-
});
|
|
79
|
-
if (Array.isArray(expectedAddresses) && !(expectedAddresses == null ? void 0 : expectedAddresses.includes(meta.address))) {
|
|
80
|
-
return {
|
|
81
|
-
displayName: `${DISPLAY_NAME} ${host}`,
|
|
82
|
-
health: {
|
|
83
|
-
healthy: false,
|
|
84
|
-
message: `${DISPLAY_NAME} ${host} returned address ${meta.address} instead of ${expectedAddresses.join(", ")}.`,
|
|
85
|
-
timestamp: new Date().toISOString()
|
|
86
|
-
},
|
|
87
|
-
meta: {
|
|
88
|
-
host,
|
|
89
|
-
addresses: meta
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
displayName: `${DISPLAY_NAME} ${host}`,
|
|
95
|
-
health: {
|
|
96
|
-
healthy: true,
|
|
97
|
-
message: `${DISPLAY_NAME} ${host} were resolved.`,
|
|
98
|
-
timestamp: new Date().toISOString()
|
|
99
|
-
},
|
|
100
|
-
meta: {
|
|
101
|
-
host,
|
|
102
|
-
addresses: meta
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
} catch (error) {
|
|
106
|
-
return {
|
|
107
|
-
displayName: `${DISPLAY_NAME} ${host}`,
|
|
108
|
-
health: {
|
|
109
|
-
healthy: false,
|
|
110
|
-
message: error.message,
|
|
111
|
-
timestamp: new Date().toISOString()
|
|
112
|
-
},
|
|
113
|
-
meta: {
|
|
114
|
-
host
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
var dns_check_default = dnsCheck;
|
|
120
|
-
|
|
121
|
-
// src/checks/http-check.ts
|
|
122
|
-
import { deepStrictEqual } from "assert";
|
|
123
|
-
var DISPLAY_NAME2 = "HTTP check for";
|
|
124
|
-
var httpCheck = (host, options) => async () => {
|
|
125
|
-
var _a, _b, _c, _d, _e;
|
|
126
|
-
try {
|
|
127
|
-
const response = await fetch(host, (options == null ? void 0 : options.fetchOptions) || {});
|
|
128
|
-
if (typeof ((_a = options == null ? void 0 : options.expected) == null ? void 0 : _a.status) !== "undefined" && ((_b = options == null ? void 0 : options.expected) == null ? void 0 : _b.status) !== response.status) {
|
|
129
|
-
throw new Error(`${DISPLAY_NAME2} ${host} returned status ${response.status} instead of ${options == null ? void 0 : options.expected.status}`);
|
|
130
|
-
}
|
|
131
|
-
if (typeof ((_c = options == null ? void 0 : options.expected) == null ? void 0 : _c.body) !== "undefined") {
|
|
132
|
-
const textBody = await response.text();
|
|
133
|
-
try {
|
|
134
|
-
deepStrictEqual(textBody, options == null ? void 0 : options.expected.body);
|
|
135
|
-
} catch {
|
|
136
|
-
throw new Error(`${DISPLAY_NAME2} ${host} returned body ${JSON.stringify(textBody)} instead of ${JSON.stringify(options == null ? void 0 : options.expected.body)}`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
displayName: `${DISPLAY_NAME2} ${host}`,
|
|
141
|
-
health: {
|
|
142
|
-
healthy: true,
|
|
143
|
-
message: `${DISPLAY_NAME2} ${host} was successful.`,
|
|
144
|
-
timestamp: new Date().toISOString()
|
|
145
|
-
},
|
|
146
|
-
meta: {
|
|
147
|
-
host,
|
|
148
|
-
method: ((_d = options == null ? void 0 : options.fetchOptions) == null ? void 0 : _d.method) || "GET",
|
|
149
|
-
status: response.status
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
} catch (error) {
|
|
153
|
-
return {
|
|
154
|
-
displayName: `${DISPLAY_NAME2} ${host}`,
|
|
155
|
-
health: {
|
|
156
|
-
healthy: false,
|
|
157
|
-
message: error.message,
|
|
158
|
-
timestamp: new Date().toISOString()
|
|
159
|
-
},
|
|
160
|
-
meta: {
|
|
161
|
-
host,
|
|
162
|
-
method: ((_e = options == null ? void 0 : options.fetchOptions) == null ? void 0 : _e.method) || "GET"
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
var http_check_default = httpCheck;
|
|
168
|
-
|
|
169
|
-
// src/checks/node-environment-check.ts
|
|
170
|
-
var DISPLAY_NAME3 = "Node Environment Check";
|
|
171
|
-
var nodeEnvironmentCheck = (expectedEnv) => async () => {
|
|
172
|
-
const environment = "development";
|
|
173
|
-
let errorMessage;
|
|
174
|
-
if (typeof environment !== "undefined" && typeof expectedEnv !== "undefined" && environment !== expectedEnv) {
|
|
175
|
-
errorMessage = `NODE_ENV environment variable is set to "${environment}" instead of "${expectedEnv}".`;
|
|
176
|
-
} else if (typeof environment === "undefined") {
|
|
177
|
-
errorMessage = ["Missing NODE_ENV environment variable.", "It can make some parts of the application misbehave"].join(" ");
|
|
178
|
-
}
|
|
179
|
-
if (typeof errorMessage !== "undefined") {
|
|
180
|
-
return {
|
|
181
|
-
displayName: DISPLAY_NAME3,
|
|
182
|
-
health: {
|
|
183
|
-
healthy: false,
|
|
184
|
-
message: errorMessage,
|
|
185
|
-
timestamp: new Date().toISOString()
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
displayName: DISPLAY_NAME3,
|
|
191
|
-
health: {
|
|
192
|
-
healthy: true,
|
|
193
|
-
timestamp: new Date().toISOString()
|
|
194
|
-
},
|
|
195
|
-
meta: {
|
|
196
|
-
env: environment
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
};
|
|
200
|
-
var node_environment_check_default = nodeEnvironmentCheck;
|
|
201
|
-
|
|
202
|
-
// src/checks/ping-check.ts
|
|
203
|
-
import ping from "pingman";
|
|
204
|
-
var DISPLAY_NAME4 = "Ping check for";
|
|
205
|
-
var pingCheck = (host, options) => async () => {
|
|
206
|
-
try {
|
|
207
|
-
const response = await ping(host.replace(/^https?:\/\//, ""), options);
|
|
208
|
-
if (!response.alive) {
|
|
209
|
-
return {
|
|
210
|
-
displayName: `${DISPLAY_NAME4} ${host}`,
|
|
211
|
-
health: {
|
|
212
|
-
healthy: false,
|
|
213
|
-
message: `Ping failed for ${host}.`,
|
|
214
|
-
timestamp: new Date().toISOString()
|
|
215
|
-
},
|
|
216
|
-
meta: response
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
displayName: `${DISPLAY_NAME4} ${host}`,
|
|
221
|
-
health: {
|
|
222
|
-
healthy: true,
|
|
223
|
-
message: `${DISPLAY_NAME4} ${host} was successful.`,
|
|
224
|
-
timestamp: new Date().toISOString()
|
|
225
|
-
},
|
|
226
|
-
meta: response
|
|
227
|
-
};
|
|
228
|
-
} catch (error) {
|
|
229
|
-
return {
|
|
230
|
-
displayName: `${DISPLAY_NAME4} ${host}`,
|
|
231
|
-
health: {
|
|
232
|
-
healthy: false,
|
|
233
|
-
message: error.message,
|
|
234
|
-
timestamp: new Date().toISOString()
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
var ping_check_default = pingCheck;
|
|
240
|
-
export {
|
|
241
|
-
healthcheck_default2 as HealthCheck,
|
|
242
|
-
dns_check_default as dnsCheck,
|
|
243
|
-
healthcheck_default as healthCheckHandler,
|
|
244
|
-
readyhandler_default as healthReadyHandler,
|
|
245
|
-
http_check_default as httpCheck,
|
|
246
|
-
node_environment_check_default as nodeEnvCheck,
|
|
247
|
-
ping_check_default as pingCheck
|
|
248
|
-
};
|
|
8
|
+
export { g as HealthCheck, S as dnsCheck, f as healthCheckHandler, u as healthReadyHandler, O as httpCheck, I as nodeEnvCheck, x as pingCheck };
|
|
9
|
+
//# sourceMappingURL=out.js.map
|
|
249
10
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handler/healthcheck.ts","../src/handler/readyhandler.ts","../src/healthcheck.ts","../src/checks/dns-check.ts","../src/checks/http-check.ts","../src/checks/node-environment-check.ts","../src/checks/ping-check.ts"],"sourcesContent":["import { StatusCodes } from \"http-status-codes\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { HealthCheck, HealthReport } from \"../types\";\n\nexport default (healthCheck: HealthCheck, sendHeader: boolean | undefined = true) =>\n async <Request extends IncomingMessage, Response extends ServerResponse>(_: Request, response: Response) => {\n const { healthy, report } = await healthCheck.getReport();\n\n const payload: HealthCheckApiPayload = {\n status: healthy ? \"ok\" : \"error\",\n message: healthy ? \"Health check successful\" : \"Health check failed\",\n appName: process.env.APP_NAME ?? \"unknown\",\n appVersion: process.env.APP_VERSION ?? \"unknown\",\n timestamp: new Date().toISOString(),\n reports: report,\n };\n\n response.statusCode = healthy ? StatusCodes.OK : StatusCodes.SERVICE_UNAVAILABLE;\n\n if (sendHeader) {\n response.setHeader(\"Content-Type\", \"application/json\");\n }\n\n response.end(JSON.stringify(payload, null, 2));\n };\n\nexport type HealthCheckApiPayload = {\n status: \"ok\" | \"error\";\n message: string;\n appName: string;\n appVersion: string;\n timestamp: string;\n reports: HealthReport;\n};\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { StatusCodes } from \"http-status-codes\";\n\nimport type { HealthCheck } from \"../types\";\n\nexport default <Request extends IncomingMessage, Response extends ServerResponse>(healthCheck: HealthCheck) => async (_request: Request, response: Response) => {\n const { healthy } = await healthCheck.getReport();\n\n response.statusCode = healthy ? StatusCodes.NO_CONTENT : StatusCodes.SERVICE_UNAVAILABLE;\n response.end()\n};\n","import {\n Checker, HealthCheck as HealthcheckInterface, HealthReport, HealthReportEntry,\n} from \"./types\";\n\nclass Healthcheck implements HealthcheckInterface {\n /**\n * A copy of registered checkers\n */\n private healthCheckers: { [service: string]: Checker } = {};\n\n /**\n * Returns an array of registered services names\n */\n public get servicesList(): string[] {\n return Object.keys(this.healthCheckers);\n }\n\n /**\n * Invokes a given checker to collect the report metrics.\n */\n private async invokeChecker(service: string, reportSheet: HealthReport): Promise<boolean> {\n const checker = this.healthCheckers[service] as Checker;\n\n let report: HealthReportEntry;\n\n try {\n report = await checker();\n\n report.displayName = report.displayName || service;\n } catch (error: any) {\n report = {\n displayName: service,\n health: { healthy: false, message: error.message, timestamp: new Date().toISOString() },\n meta: { fatal: true },\n };\n }\n\n // eslint-disable-next-line no-param-reassign\n reportSheet[service] = report;\n\n return report.health.healthy;\n }\n\n public addChecker(service: string, checker: Checker): void {\n this.healthCheckers[service] = checker;\n }\n\n /**\n * Returns the health check reports. The health checks are performed when\n * this method is invoked.\n */\n public async getReport(): Promise<{ healthy: boolean; report: HealthReport }> {\n const report: HealthReport = {};\n\n // eslint-disable-next-line compat/compat\n await Promise.all(Object.keys(this.healthCheckers).map((service) => this.invokeChecker(service, report)));\n\n /**\n * Finding unhealthy service to know if system is healthy or not\n */\n const unhealthyService = Object.keys(report).find((service) => !(report[service] as HealthReportEntry).health.healthy);\n\n return { healthy: !unhealthyService, report };\n }\n\n public async isLive(): Promise<boolean> {\n const { healthy } = await this.getReport();\n\n return healthy;\n }\n}\n\nexport default Healthcheck;\n","import type { IPFamily, Options } from \"cacheable-lookup\";\nimport CacheableLookup from \"cacheable-lookup\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"DNS check for\";\n\n/**\n * Register the `dns` checker to ensure that a domain is reachable.\n */\nconst dnsCheck = (\n host: string,\n expectedAddresses?: string[],\n options?: {\n family?: IPFamily | \"all\";\n hints?: number;\n } & Options,\n): Checker => async () => {\n const { hints, family = \"all\", ...config } = options || {};\n\n const cacheable = new CacheableLookup(config);\n\n try {\n const meta = await cacheable.lookupAsync(host.replace(/^https?:\\/\\//, \"\"), {\n hints,\n ...(family === \"all\" ? { all: true } : { family: family as IPFamily }),\n });\n\n if (Array.isArray(expectedAddresses) && !expectedAddresses?.includes(meta.address)) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `${DISPLAY_NAME} ${host} returned address ${meta.address} instead of ${expectedAddresses.join(\", \")}.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} were resolved.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: error.message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n },\n };\n }\n};\n\nexport default dnsCheck;\n","import { deepStrictEqual } from \"node:assert\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"HTTP check for\";\n\n/**\n * Register the `http` checker to ensure http body and status is correct.\n */\nconst httpCheck =\n (host: RequestInfo | URL, options?: {\n fetchOptions?: RequestInit,\n expected?: { status?: number; body?: string }\n }): Checker =>\n async () => {\n try {\n // eslint-disable-next-line compat/compat\n const response = await fetch(host, options?.fetchOptions || {});\n\n if (typeof options?.expected?.status !== \"undefined\" && options?.expected?.status !== response.status) {\n throw new Error(`${DISPLAY_NAME} ${host} returned status ${response.status} instead of ${options?.expected.status}`);\n }\n\n if (typeof options?.expected?.body !== \"undefined\") {\n const textBody = await response.text();\n\n try {\n deepStrictEqual(textBody, options?.expected.body);\n } catch {\n throw new Error(`${DISPLAY_NAME} ${host} returned body ${JSON.stringify(textBody)} instead of ${JSON.stringify(options?.expected.body)}`);\n }\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method || \"GET\",\n status: response.status,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: error.message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method || \"GET\",\n },\n };\n }\n };\n\nexport default httpCheck;\n","import type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Node Environment Check\";\n\n/**\n * Register the `env` checker to ensure that `NODE_ENV` environment\n * variable is defined.\n */\nconst nodeEnvironmentCheck = (expectedEnv?: string): Checker => async () => {\n const environment = process.env.NODE_ENV;\n\n let errorMessage: string | undefined;\n\n if (typeof environment !== \"undefined\" && typeof expectedEnv !== \"undefined\" && environment !== expectedEnv) {\n errorMessage = `NODE_ENV environment variable is set to \"${environment}\" instead of \"${expectedEnv}\".`;\n } else if (typeof environment === \"undefined\") {\n errorMessage = [\"Missing NODE_ENV environment variable.\", \"It can make some parts of the application misbehave\"].join(\" \");\n }\n\n if (typeof errorMessage !== \"undefined\") {\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: false,\n message: errorMessage,\n timestamp: new Date().toISOString(),\n },\n };\n }\n\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: true,\n timestamp: new Date().toISOString(),\n },\n meta: {\n env: environment,\n },\n };\n};\n\nexport default nodeEnvironmentCheck;\n","import type { extendedPingOptions } from \"pingman\";\nimport ping from \"pingman\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Ping check for\";\n\n/**\n * Register the `ping` checker to ensure that a domain is reachable.\n */\nconst pingCheck = (host: string, options?: extendedPingOptions): Checker => async () => {\n try {\n const response = await ping(host.replace(/^https?:\\/\\//, \"\"), options);\n\n if (!response.alive) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `Ping failed for ${host}.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: error.message,\n timestamp: new Date().toISOString(),\n },\n };\n }\n};\n\nexport default pingCheck;\n"],"mappings":"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","names":["StatusCodes","healthcheck_default","DISPLAY_NAME","DISPLAY_NAME","DISPLAY_NAME"]}
|
|
1
|
+
{"version":3,"sources":["../src/handler/healthcheck.ts","../src/handler/readyhandler.ts","../src/healthcheck.ts","../src/checks/dns-check.ts","../src/checks/http-check.ts","../src/checks/node-environment-check.ts","../src/checks/ping-check.ts"],"names":["StatusCodes","healthcheck_default","healthCheck","sendHeader","_","response","healthy","report","payload","readyhandler_default","_request","Healthcheck","service","reportSheet","checker","error","CacheableLookup","DISPLAY_NAME","dnsCheck","host","expectedAddresses","options","hints","family","config","cacheable","meta","dns_check_default","deepStrictEqual","httpCheck","textBody","http_check_default","nodeEnvironmentCheck","expectedEnvironment","environment","errorMessage","node_environment_check_default","ping","pingCheck","ping_check_default"],"mappings":"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","sourcesContent":["import { StatusCodes } from \"http-status-codes\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { HealthCheck, HealthReport } from \"../types\";\n\n// eslint-disable-next-line max-len\nexport default (healthCheck: HealthCheck, sendHeader: boolean | undefined = true) => async <Request extends IncomingMessage, Response extends ServerResponse>(_: Request, response: Response): Promise<void> => {\n const { healthy, report } = await healthCheck.getReport();\n\n const payload: HealthCheckApiPayload = {\n status: healthy ? \"ok\" : \"error\",\n message: healthy ? \"Health check successful\" : \"Health check failed\",\n appName: process.env[\"APP_NAME\"] ?? \"unknown\",\n appVersion: process.env[\"APP_VERSION\"] ?? \"unknown\",\n timestamp: new Date().toISOString(),\n reports: report,\n };\n\n response.statusCode = healthy ? StatusCodes.OK : StatusCodes.SERVICE_UNAVAILABLE;\n\n if (sendHeader) {\n response.setHeader(\"Content-Type\", \"application/json\");\n }\n\n response.end(JSON.stringify(payload, null, 2));\n};\n\nexport type HealthCheckApiPayload = {\n status: \"error\" | \"ok\";\n message: string;\n appName: string;\n appVersion: string;\n timestamp: string;\n reports: HealthReport;\n};\n","import { StatusCodes } from \"http-status-codes\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { HealthCheck } from \"../types\";\n\n// eslint-disable-next-line max-len\nexport default <Request extends IncomingMessage, Response extends ServerResponse>(healthCheck: HealthCheck) => async (_request: Request, response: Response): Promise<void> => {\n const { healthy } = await healthCheck.getReport();\n\n response.statusCode = healthy ? StatusCodes.NO_CONTENT : StatusCodes.SERVICE_UNAVAILABLE;\n response.end();\n};\n","import type {\n Checker, HealthCheck as HealthcheckInterface, HealthReport, HealthReportEntry,\n} from \"./types.d\";\n\nclass Healthcheck implements HealthcheckInterface {\n /**\n * A copy of registered checkers\n */\n private healthCheckers: { [service: string]: Checker } = {};\n\n /**\n * Returns an array of registered services names\n */\n public get servicesList(): string[] {\n return Object.keys(this.healthCheckers);\n }\n\n /**\n * Invokes a given checker to collect the report metrics.\n */\n private async invokeChecker(service: string, reportSheet: HealthReport): Promise<boolean> {\n const checker = this.healthCheckers[service] as Checker;\n\n let report: HealthReportEntry;\n\n try {\n report = await checker();\n\n report.displayName = report.displayName || service;\n } catch (error: any) {\n report = {\n displayName: service,\n health: { healthy: false, message: (error as Error).message, timestamp: new Date().toISOString() },\n meta: { fatal: true },\n };\n }\n\n // eslint-disable-next-line no-param-reassign\n reportSheet[service] = report;\n\n return report.health.healthy;\n }\n\n public addChecker(service: string, checker: Checker): void {\n this.healthCheckers[service] = checker;\n }\n\n /**\n * Returns the health check reports. The health checks are performed when\n * this method is invoked.\n */\n public async getReport(): Promise<{ healthy: boolean; report: HealthReport }> {\n const report: HealthReport = {};\n\n // eslint-disable-next-line compat/compat\n await Promise.all(Object.keys(this.healthCheckers).map((service) => this.invokeChecker(service, report)));\n\n /**\n * Finding unhealthy service to know if system is healthy or not\n */\n const unhealthyService = Object.keys(report).find((service) => !(report[service] as HealthReportEntry).health.healthy);\n\n return { healthy: !unhealthyService, report };\n }\n\n public async isLive(): Promise<boolean> {\n const { healthy } = await this.getReport();\n\n return healthy;\n }\n}\n\nexport default Healthcheck;\n","import type { IPFamily, Options } from \"cacheable-lookup\";\nimport CacheableLookup from \"cacheable-lookup\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"DNS check for\";\n\n/**\n * Register the `dns` checker to ensure that a domain is reachable.\n */\nconst dnsCheck = (\n host: string,\n expectedAddresses?: string[],\n options?: Options & {\n family?: IPFamily | \"all\";\n hints?: number;\n },\n): Checker => async () => {\n const { hints, family = \"all\", ...config } = options ?? {};\n\n const cacheable = new CacheableLookup(config);\n\n try {\n const meta = await cacheable.lookupAsync(host.replace(/^https?:\\/\\//, \"\"), {\n hints,\n ...(family === \"all\" ? { all: true } : { family }),\n });\n\n if (Array.isArray(expectedAddresses) && !expectedAddresses.includes(meta.address)) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `${DISPLAY_NAME} ${host} returned address ${meta.address} instead of ${expectedAddresses.join(\", \")}.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} were resolved.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n addresses: meta,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: (error as Error).message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n },\n };\n }\n};\n\nexport default dnsCheck;\n","import { deepStrictEqual } from \"node:assert\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"HTTP check for\";\n\n/**\n * Register the `http` checker to ensure http body and status is correct.\n */\nconst httpCheck = (host: RequestInfo | URL, options?: {\n fetchOptions?: RequestInit,\n expected?: { status?: number; body?: string }\n}): Checker => async () => {\n try {\n // eslint-disable-next-line compat/compat\n const response = await fetch(host, options?.fetchOptions ?? {});\n\n if (options?.expected?.status !== undefined && options.expected.status !== response.status) {\n throw new Error(`${DISPLAY_NAME} ${host} returned status ${response.status} instead of ${options.expected.status}`);\n }\n\n if (options?.expected?.body !== undefined) {\n const textBody = await response.text();\n\n try {\n deepStrictEqual(textBody, options.expected.body);\n } catch {\n throw new Error(`${DISPLAY_NAME} ${host} returned body ${JSON.stringify(textBody)} instead of ${JSON.stringify(options.expected.body)}`);\n }\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method ?? \"GET\",\n status: response.status,\n },\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: (error as Error).message,\n timestamp: new Date().toISOString(),\n },\n meta: {\n host,\n method: options?.fetchOptions?.method ?? \"GET\",\n },\n };\n }\n};\n\nexport default httpCheck;\n","import type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Node Environment Check\";\n\n/**\n * Register the `env` checker to ensure that `NODE_ENV` environment\n * variable is defined.\n */\nconst nodeEnvironmentCheck = (expectedEnvironment?: string): Checker => async () => {\n // eslint-disable-next-line @typescript-eslint/dot-notation\n const environment: string | undefined = process.env[\"NODE_ENV\"];\n\n let errorMessage: string | undefined;\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (environment !== undefined && expectedEnvironment !== undefined && environment !== expectedEnvironment) {\n errorMessage = `NODE_ENV environment variable is set to \"${environment}\" instead of \"${expectedEnvironment}\".`;\n } else if (!environment) {\n errorMessage = [\"Missing NODE_ENV environment variable.\", \"It can make some parts of the application misbehave\"].join(\" \");\n }\n\n if (errorMessage !== undefined) {\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: false,\n message: errorMessage,\n timestamp: new Date().toISOString(),\n },\n };\n }\n\n return {\n displayName: DISPLAY_NAME,\n health: {\n healthy: true,\n timestamp: new Date().toISOString(),\n },\n meta: {\n env: environment,\n },\n };\n};\n\nexport default nodeEnvironmentCheck;\n","import type { extendedPingOptions } from \"pingman\";\nimport ping from \"pingman\";\n\nimport type { Checker } from \"../types\";\n\nconst DISPLAY_NAME = \"Ping check for\";\n\n/**\n * Register the `ping` checker to ensure that a domain is reachable.\n */\nconst pingCheck = (host: string, options?: extendedPingOptions): Checker => async () => {\n try {\n const response = await ping(host.replace(/^https?:\\/\\//, \"\"), options);\n\n if (!response.alive) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: `Ping failed for ${host}.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n }\n\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: true,\n message: `${DISPLAY_NAME} ${host} was successful.`,\n timestamp: new Date().toISOString(),\n },\n meta: response,\n };\n } catch (error: any) {\n return {\n displayName: `${DISPLAY_NAME} ${host}`,\n health: {\n healthy: false,\n message: (error as Error).message,\n timestamp: new Date().toISOString(),\n },\n };\n }\n};\n\nexport default pingCheck;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visulima/health-check",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A library built to provide support for defining service health for node services. It allows you to register async health checks for your dependencies and the service itself, provides a health endpoint that exposes their status, and health metrics.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anolilab",
|
|
@@ -58,68 +58,69 @@
|
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "cross-env NODE_ENV=development tsup",
|
|
60
60
|
"build:prod": "cross-env NODE_ENV=production tsup",
|
|
61
|
-
"clean": "rimraf node_modules dist",
|
|
61
|
+
"clean": "rimraf node_modules dist .eslintcache",
|
|
62
62
|
"coverage": "vitest run --coverage",
|
|
63
63
|
"dev": "pnpm predev && pnpm run build --watch",
|
|
64
|
-
"lint:eslint": "cross-env NO_LOGS=true eslint --ext js,jsx,ts,tsx --max-warnings=0 --config .eslintrc.cjs",
|
|
64
|
+
"lint:eslint": "cross-env NO_LOGS=true eslint . --ext js,jsx,ts,tsx --max-warnings=0 --config .eslintrc.cjs --cache --cache-strategy content .",
|
|
65
65
|
"lint:eslint:fix": "pnpm run lint:eslint --fix",
|
|
66
|
-
"test": "vitest"
|
|
66
|
+
"test": "vitest run",
|
|
67
|
+
"test:watch": "vitest"
|
|
67
68
|
},
|
|
68
69
|
"dependencies": {
|
|
69
70
|
"cacheable-lookup": "^7.0.0",
|
|
70
71
|
"http-status-codes": "^2.2.0",
|
|
71
|
-
"pingman": "^
|
|
72
|
+
"pingman": "^2.0.0"
|
|
72
73
|
},
|
|
73
74
|
"devDependencies": {
|
|
74
|
-
"@anolilab/eslint-config": "^
|
|
75
|
-
"@anolilab/semantic-release-preset": "^2.0
|
|
75
|
+
"@anolilab/eslint-config": "^5.0.2",
|
|
76
|
+
"@anolilab/semantic-release-preset": "^2.2.0",
|
|
76
77
|
"@rushstack/eslint-plugin-security": "^0.5.0",
|
|
77
|
-
"@types/node": "^18.
|
|
78
|
-
"@types/react": "^18.0.
|
|
79
|
-
"@types/react-dom": "^18.0.
|
|
80
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
81
|
-
"@typescript-eslint/parser": "^5.
|
|
78
|
+
"@types/node": "^18.11.18",
|
|
79
|
+
"@types/react": "^18.0.27",
|
|
80
|
+
"@types/react-dom": "^18.0.10",
|
|
81
|
+
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
|
82
|
+
"@typescript-eslint/parser": "^5.49.0",
|
|
82
83
|
"cross-env": "^7.0.3",
|
|
83
84
|
"cross-fetch": "^3.1.5",
|
|
84
|
-
"eslint": "^8.
|
|
85
|
+
"eslint": "^8.32.0",
|
|
85
86
|
"eslint-plugin-compat": "^4.0.2",
|
|
86
87
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
87
|
-
"eslint-plugin-import": "^2.
|
|
88
|
+
"eslint-plugin-import": "^2.27.5",
|
|
88
89
|
"eslint-plugin-json": "^3.1.0",
|
|
89
|
-
"eslint-plugin-jsx-a11y": "^6.
|
|
90
|
+
"eslint-plugin-jsx-a11y": "^6.7.1",
|
|
90
91
|
"eslint-plugin-markdown": "^3.0.0",
|
|
91
92
|
"eslint-plugin-no-loops": "^0.3.0",
|
|
92
93
|
"eslint-plugin-no-secrets": "^0.8.9",
|
|
93
94
|
"eslint-plugin-node": "^11.1.0",
|
|
94
95
|
"eslint-plugin-optimize-regex": "^1.2.1",
|
|
95
|
-
"eslint-plugin-promise": "^6.
|
|
96
|
+
"eslint-plugin-promise": "^6.1.1",
|
|
96
97
|
"eslint-plugin-radar": "^0.2.1",
|
|
97
|
-
"eslint-plugin-react": "7.
|
|
98
|
+
"eslint-plugin-react": "7.32.1",
|
|
98
99
|
"eslint-plugin-react-hooks": "4.6.0",
|
|
99
|
-
"eslint-plugin-simple-import-sort": "^
|
|
100
|
+
"eslint-plugin-simple-import-sort": "^9.0.0",
|
|
100
101
|
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
101
|
-
"eslint-plugin-testing-library": "^5.
|
|
102
|
-
"eslint-plugin-unicorn": "^
|
|
102
|
+
"eslint-plugin-testing-library": "^5.10.0",
|
|
103
|
+
"eslint-plugin-unicorn": "^45.0.2",
|
|
103
104
|
"eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0",
|
|
104
105
|
"eslint-plugin-you-dont-need-momentjs": "^1.6.0",
|
|
105
|
-
"next": "^
|
|
106
|
+
"next": "^13.1.5",
|
|
106
107
|
"next-test-api-route-handler": "^4.0.0-canary.1",
|
|
107
|
-
"node-mocks-http": "^1.
|
|
108
|
-
"prettier": "^2.
|
|
108
|
+
"node-mocks-http": "^1.12.1",
|
|
109
|
+
"prettier": "^2.8.3",
|
|
109
110
|
"react": "^18.2.0",
|
|
110
111
|
"react-dom": "^18.2.0",
|
|
111
112
|
"read-pkg": "^7.1.0",
|
|
112
|
-
"rimraf": "^
|
|
113
|
-
"semantic-release": "^
|
|
114
|
-
"tsup": "^6.
|
|
115
|
-
"typescript": "^4.
|
|
116
|
-
"vitest": "^0.
|
|
113
|
+
"rimraf": "^4.1.2",
|
|
114
|
+
"semantic-release": "^20.1.0",
|
|
115
|
+
"tsup": "^6.5.0",
|
|
116
|
+
"typescript": "^4.9.4",
|
|
117
|
+
"vitest": "^0.28.2"
|
|
117
118
|
},
|
|
118
119
|
"optionalDependencies": {
|
|
119
|
-
"next": "^
|
|
120
|
+
"next": "^13.1.4"
|
|
120
121
|
},
|
|
121
122
|
"engines": {
|
|
122
|
-
"node": ">=16"
|
|
123
|
+
"node": ">=16.18.0 <=19.*"
|
|
123
124
|
},
|
|
124
125
|
"publishConfig": {
|
|
125
126
|
"access": "public"
|