@visulima/health-check 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## @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
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* fixed wrong image and url for the npm version ([297c187](https://github.com/visulima/visulima/commit/297c187d07ca7fb82d25fd46defe4f320c514de9))
|
|
7
|
+
|
|
1
8
|
## @visulima/health-check 1.0.0 (2022-11-16)
|
|
2
9
|
|
|
3
10
|
|
package/README.md
CHANGED
|
@@ -200,5 +200,5 @@ The visulima health-check is open-sourced software licensed under the [MIT][lice
|
|
|
200
200
|
[typescript-url]: "typescript"
|
|
201
201
|
[license-image]: https://img.shields.io/npm/l/@visulima/health-check?color=blueviolet&style=for-the-badge
|
|
202
202
|
[license-url]: LICENSE.md "license"
|
|
203
|
-
[npm-image]: https://img.shields.io/npm/v/@visulima/health-check/
|
|
204
|
-
[npm-url]: https://www.npmjs.com/package/@visulima/health-check/v/
|
|
203
|
+
[npm-image]: https://img.shields.io/npm/v/@visulima/health-check/latest.svg?style=for-the-badge&logo=npm
|
|
204
|
+
[npm-url]: https://www.npmjs.com/package/@visulima/health-check/v/latest "npm"
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var healthcheck_default = (healthCheck, sendHeader = true) => async (_, response
|
|
|
14
14
|
if (sendHeader) {
|
|
15
15
|
response.setHeader("Content-Type", "application/json");
|
|
16
16
|
}
|
|
17
|
-
response.end(JSON.stringify(payload));
|
|
17
|
+
response.end(JSON.stringify(payload, null, 2));
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
// src/handler/readyhandler.ts
|
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));\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","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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ var healthcheck_default = (healthCheck, sendHeader = true) => async (_, response
|
|
|
14
14
|
if (sendHeader) {
|
|
15
15
|
response.setHeader("Content-Type", "application/json");
|
|
16
16
|
}
|
|
17
|
-
response.end(JSON.stringify(payload));
|
|
17
|
+
response.end(JSON.stringify(payload, null, 2));
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
// src/handler/readyhandler.ts
|
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));\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"],"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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visulima/health-check",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
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",
|