@openstatus/health-dns 0.1.4-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # @openstatus/health-dns
2
+
3
+ DNS probe for [`@openstatus/health`](https://jsr.io/@openstatus/health).
4
+ Resolves a hostname through the runtime's resolver and fails the check
5
+ when the name does not resolve — the early warning for an expired domain,
6
+ a broken record change or a resolver outage on the host, before the first
7
+ request to that dependency fails.
8
+
9
+ ```sh
10
+ deno add jsr:@openstatus/health jsr:@openstatus/health-dns
11
+ npm install @openstatus/health @openstatus/health-dns
12
+ ```
13
+
14
+ ```ts
15
+ import { createHealthHandler } from "@openstatus/health";
16
+ import { dnsProbe } from "@openstatus/health-dns";
17
+
18
+ Deno.serve(
19
+ createHealthHandler({
20
+ probes: [dnsProbe({ hostname: "api.stripe.com" })],
21
+ }),
22
+ );
23
+ ```
24
+
25
+ The probe calls `dns.promises.lookup(hostname)`, which uses the same path
26
+ your `fetch` and sockets use — the OS resolver, `/etc/hosts` and whatever
27
+ cache the OS keeps — so it answers "would a connection to this name find an
28
+ address" rather than "what do the authoritative servers say". Pass
29
+ `lookup` to resolve through something else, such as a `Resolver` pointed at
30
+ specific servers with its `resolve4` result mapped to `{ address }` as
31
+ below, and give each probe a `name` when you mount more than one.
32
+
33
+ ```ts
34
+ import { Resolver } from "node:dns/promises";
35
+
36
+ const resolver = new Resolver();
37
+ resolver.setServers(["1.1.1.1"]);
38
+
39
+ dnsProbe({
40
+ hostname: "api.example.com",
41
+ lookup: async (hostname) =>
42
+ (await resolver.resolve4(hostname)).map((address) => ({ address })),
43
+ // optional overrides from the Probe contract
44
+ name: "upstream-dns",
45
+ critical: true,
46
+ timeoutMs: 1000,
47
+ skip: () => env.UPSTREAM_HOST == null,
48
+ });
49
+ ```
50
+
51
+ Non-critical by default: a name that stops resolving is worth alerting on,
52
+ but the dependency behind it usually has a probe of its own that decides
53
+ whether the service can still serve. Set `critical: true` when it cannot.
54
+
55
+ This probe uses `node:dns`, so it runs on Node.js, Deno and Bun but not on
56
+ edge runtimes without a resolver API.
57
+
58
+ ## About openstatus
59
+
60
+ [openstatus](https://www.openstatus.dev/) is the open-source uptime monitoring
61
+ and status page platform. This package is part of
62
+ [`@openstatus/health`](https://github.com/openstatusHQ/health), the `/health`
63
+ endpoints behind openstatus's own services, extracted so any JavaScript server
64
+ can expose one. Point an
65
+ [openstatus monitor](https://www.openstatus.dev/docs/reference/http-monitor)
66
+ at the endpoint and assert on `status` in the body to be alerted on
67
+ `degraded` before it becomes `unhealthy`.
68
+
69
+ Source: [github.com/openstatusHQ/health](https://github.com/openstatusHQ/health).
70
+ Issues and PRs welcome.
71
+
72
+ ## License
73
+
74
+ [MIT](https://github.com/openstatusHQ/health/blob/main/LICENSE)
@@ -0,0 +1,30 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+
25
+ Object.defineProperty(exports, '__toESM', {
26
+ enumerable: true,
27
+ get: function () {
28
+ return __toESM;
29
+ }
30
+ });
package/dist/mod.cjs ADDED
@@ -0,0 +1,30 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ const node_dns_promises = require_rolldown_runtime.__toESM(require("node:dns/promises"));
3
+ const __openstatus_health = require_rolldown_runtime.__toESM(require("@openstatus/health"));
4
+
5
+ //#region src/mod.ts
6
+ /** Probe name when `name` is unset. */
7
+ const dnsDefaultName = "dns";
8
+ /** A probe that resolves `hostname` to at least one address; non-critical by default. Throws `ProbeConfigError` for an empty `hostname`. */
9
+ function dnsProbe(options) {
10
+ const hostname = options.hostname;
11
+ if (typeof hostname !== "string" || hostname.length === 0) throw new __openstatus_health.ProbeConfigError("dnsProbe", "hostname", typeof hostname !== "string" ? `must be a string, got ${String(hostname)}` : "must not be empty");
12
+ const lookup = options.lookup ?? node_dns_promises.lookup;
13
+ return {
14
+ name: options.name ?? dnsDefaultName,
15
+ critical: options.critical ?? false,
16
+ timeoutMs: options.timeoutMs,
17
+ skip: options.skip,
18
+ run: async () => {
19
+ const result = await lookup(hostname);
20
+ const addresses = Array.isArray(result) ? result : [result];
21
+ const address = addresses.find((entry) => typeof entry?.address === "string" && entry.address.length > 0)?.address;
22
+ if (address == null) throw new Error(`no address for ${hostname}`);
23
+ return { address };
24
+ }
25
+ };
26
+ }
27
+
28
+ //#endregion
29
+ exports.dnsDefaultName = dnsDefaultName;
30
+ exports.dnsProbe = dnsProbe;
package/dist/mod.d.cts ADDED
@@ -0,0 +1,26 @@
1
+ import { Probe, ProbeOverrides } from "@openstatus/health";
2
+
3
+ //#region src/mod.d.ts
4
+
5
+ /** Probe name when `name` is unset. */
6
+ declare const dnsDefaultName = "dns";
7
+ /** One resolved address. */
8
+ interface DnsAddress {
9
+ /** The IPv4 or IPv6 address. */
10
+ readonly address: string;
11
+ }
12
+ /** What the probe resolves with; `dns.promises.lookup` by default. */
13
+ type DnsLookup = (hostname: string) => PromiseLike<DnsAddress | readonly DnsAddress[]>;
14
+ /** Options for `dnsProbe()`. */
15
+ interface DnsProbeOptions extends ProbeOverrides {
16
+ /** The name to resolve. */
17
+ readonly hostname: string;
18
+ /** Replacement `lookup`, for tests or a custom resolver. */
19
+ readonly lookup?: DnsLookup;
20
+ }
21
+ /** A probe that resolves `hostname` to at least one address; non-critical by default. Throws `ProbeConfigError` for an empty `hostname`. */
22
+ declare function dnsProbe(options: DnsProbeOptions): Probe;
23
+ //# sourceMappingURL=mod.d.ts.map
24
+ //#endregion
25
+ export { DnsAddress, DnsLookup, DnsProbeOptions, dnsDefaultName, dnsProbe };
26
+ //# sourceMappingURL=mod.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;AAqCuD;AAQvC,cAtBH,cAAA,GAsBW,KAAA;;AAAU,UAnBjB,UAAA,CAmBiB;EAAe;EAAQ,SAAA,OAAA,EAAA,MAAA;;;KAb7C,SAAA,yBAEP,YAAY,sBAAsB;;UAGtB,eAAA,SAAwB;;;;oBAIrB;;;iBAIJ,QAAA,UAAkB,kBAAkB"}
package/dist/mod.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { Probe, ProbeOverrides } from "@openstatus/health";
2
+
3
+ //#region src/mod.d.ts
4
+
5
+ /** Probe name when `name` is unset. */
6
+ declare const dnsDefaultName = "dns";
7
+ /** One resolved address. */
8
+ interface DnsAddress {
9
+ /** The IPv4 or IPv6 address. */
10
+ readonly address: string;
11
+ }
12
+ /** What the probe resolves with; `dns.promises.lookup` by default. */
13
+ type DnsLookup = (hostname: string) => PromiseLike<DnsAddress | readonly DnsAddress[]>;
14
+ /** Options for `dnsProbe()`. */
15
+ interface DnsProbeOptions extends ProbeOverrides {
16
+ /** The name to resolve. */
17
+ readonly hostname: string;
18
+ /** Replacement `lookup`, for tests or a custom resolver. */
19
+ readonly lookup?: DnsLookup;
20
+ }
21
+ /** A probe that resolves `hostname` to at least one address; non-critical by default. Throws `ProbeConfigError` for an empty `hostname`. */
22
+ declare function dnsProbe(options: DnsProbeOptions): Probe;
23
+ //# sourceMappingURL=mod.d.ts.map
24
+ //#endregion
25
+ export { DnsAddress, DnsLookup, DnsProbeOptions, dnsDefaultName, dnsProbe };
26
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;AAqCuD;AAQvC,cAtBH,cAAA,GAsBW,KAAA;;AAAU,UAnBjB,UAAA,CAmBiB;EAAe;EAAQ,SAAA,OAAA,EAAA,MAAA;;;KAb7C,SAAA,yBAEP,YAAY,sBAAsB;;UAGtB,eAAA,SAAwB;;;;oBAIrB;;;iBAIJ,QAAA,UAAkB,kBAAkB"}
package/dist/mod.js ADDED
@@ -0,0 +1,29 @@
1
+ import { lookup } from "node:dns/promises";
2
+ import { ProbeConfigError } from "@openstatus/health";
3
+
4
+ //#region src/mod.ts
5
+ /** Probe name when `name` is unset. */
6
+ const dnsDefaultName = "dns";
7
+ /** A probe that resolves `hostname` to at least one address; non-critical by default. Throws `ProbeConfigError` for an empty `hostname`. */
8
+ function dnsProbe(options) {
9
+ const hostname = options.hostname;
10
+ if (typeof hostname !== "string" || hostname.length === 0) throw new ProbeConfigError("dnsProbe", "hostname", typeof hostname !== "string" ? `must be a string, got ${String(hostname)}` : "must not be empty");
11
+ const lookup$1 = options.lookup ?? lookup;
12
+ return {
13
+ name: options.name ?? dnsDefaultName,
14
+ critical: options.critical ?? false,
15
+ timeoutMs: options.timeoutMs,
16
+ skip: options.skip,
17
+ run: async () => {
18
+ const result = await lookup$1(hostname);
19
+ const addresses = Array.isArray(result) ? result : [result];
20
+ const address = addresses.find((entry) => typeof entry?.address === "string" && entry.address.length > 0)?.address;
21
+ if (address == null) throw new Error(`no address for ${hostname}`);
22
+ return { address };
23
+ }
24
+ };
25
+ }
26
+
27
+ //#endregion
28
+ export { dnsDefaultName, dnsProbe };
29
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","names":["options: DnsProbeOptions","lookup","dnsLookup"],"sources":["../src/mod.ts"],"sourcesContent":["/**\n * DNS probe for `@openstatus/health`: resolves a hostname through the\n * runtime's resolver and fails when it does not resolve.\n *\n * ```ts\n * import { dnsProbe } from \"@openstatus/health-dns\";\n *\n * const probe = dnsProbe({ hostname: \"api.example.com\" });\n * ```\n *\n * Node.js, Deno and Bun only: it uses `node:dns`.\n *\n * @module\n */\n\nimport { lookup as dnsLookup } from \"node:dns/promises\";\nimport {\n type Probe,\n ProbeConfigError,\n type ProbeOverrides,\n} from \"@openstatus/health\";\n\n/** Probe name when `name` is unset. */\nexport const dnsDefaultName = \"dns\";\n\n/** One resolved address. */\nexport interface DnsAddress {\n /** The IPv4 or IPv6 address. */\n readonly address: string;\n}\n\n/** What the probe resolves with; `dns.promises.lookup` by default. */\nexport type DnsLookup = (\n hostname: string,\n) => PromiseLike<DnsAddress | readonly DnsAddress[]>;\n\n/** Options for `dnsProbe()`. */\nexport interface DnsProbeOptions extends ProbeOverrides {\n /** The name to resolve. */\n readonly hostname: string;\n /** Replacement `lookup`, for tests or a custom resolver. */\n readonly lookup?: DnsLookup;\n}\n\n/** A probe that resolves `hostname` to at least one address; non-critical by default. Throws `ProbeConfigError` for an empty `hostname`. */\nexport function dnsProbe(options: DnsProbeOptions): Probe {\n const hostname = options.hostname;\n if (typeof hostname !== \"string\" || hostname.length === 0) {\n throw new ProbeConfigError(\n \"dnsProbe\",\n \"hostname\",\n typeof hostname !== \"string\"\n ? `must be a string, got ${String(hostname)}`\n : \"must not be empty\",\n );\n }\n const lookup = options.lookup ?? dnsLookup;\n return {\n name: options.name ?? dnsDefaultName,\n critical: options.critical ?? false,\n timeoutMs: options.timeoutMs,\n skip: options.skip,\n run: async () => {\n const result = await lookup(hostname);\n const addresses = Array.isArray(result) ? result : [result];\n const address = addresses.find((entry) =>\n typeof entry?.address === \"string\" && entry.address.length > 0\n )?.address;\n if (address == null) throw new Error(`no address for ${hostname}`);\n return { address };\n },\n };\n}\n"],"mappings":";;;;;AAuBA,MAAa,iBAAiB;;AAsB9B,SAAgB,SAASA,SAAiC;CACxD,MAAM,WAAW,QAAQ;AACzB,YAAW,aAAa,YAAY,SAAS,WAAW,EACtD,OAAM,IAAI,iBACR,YACA,mBACO,aAAa,YACf,wBAAwB,OAAO,SAAS,CAAC,IAC1C;CAGR,MAAMC,WAAS,QAAQ,UAAUC;AACjC,QAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ,YAAY;EAC9B,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd,KAAK,YAAY;GACf,MAAM,SAAS,MAAM,SAAO,SAAS;GACrC,MAAM,YAAY,MAAM,QAAQ,OAAO,GAAG,SAAS,CAAC,MAAO;GAC3D,MAAM,UAAU,UAAU,KAAK,CAAC,iBACvB,OAAO,YAAY,YAAY,MAAM,QAAQ,SAAS,EAC9D,EAAE;AACH,OAAI,WAAW,KAAM,OAAM,IAAI,OAAO,iBAAiB,SAAS;AAChE,UAAO,EAAE,QAAS;EACnB;CACF;AACF"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@openstatus/health-dns",
3
+ "version": "0.1.4-dev.0",
4
+ "description": "DNS lookup probe for @openstatus/health",
5
+ "keywords": [
6
+ "openstatus",
7
+ "health",
8
+ "healthcheck",
9
+ "dns",
10
+ "lookup",
11
+ "network"
12
+ ],
13
+ "license": "MIT",
14
+ "author": {
15
+ "name": "openstatus",
16
+ "url": "https://www.openstatus.dev/"
17
+ },
18
+ "homepage": "https://github.com/openstatusHQ/health",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/openstatusHQ/health.git",
22
+ "directory": "packages/dns/"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/openstatusHQ/health/issues"
26
+ },
27
+ "type": "module",
28
+ "module": "./dist/mod.js",
29
+ "main": "./dist/mod.cjs",
30
+ "types": "./dist/mod.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": {
34
+ "import": "./dist/mod.d.ts",
35
+ "require": "./dist/mod.d.cts"
36
+ },
37
+ "import": "./dist/mod.js",
38
+ "require": "./dist/mod.cjs"
39
+ },
40
+ "./package.json": "./package.json"
41
+ },
42
+ "sideEffects": false,
43
+ "files": [
44
+ "dist/"
45
+ ],
46
+ "engines": {
47
+ "node": ">=22"
48
+ },
49
+ "peerDependencies": {
50
+ "@openstatus/health": "^0.1.4-dev.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": ">=22",
54
+ "tsdown": "^0.12.7",
55
+ "typescript": "^5.8.3"
56
+ },
57
+ "scripts": {
58
+ "build": "tsdown",
59
+ "prepack": "tsdown",
60
+ "test": "node --experimental-transform-types --test"
61
+ }
62
+ }