@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 +74 -0
- package/dist/_virtual/rolldown_runtime.cjs +30 -0
- package/dist/mod.cjs +30 -0
- package/dist/mod.d.cts +26 -0
- package/dist/mod.d.cts.map +1 -0
- package/dist/mod.d.ts +26 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +29 -0
- package/dist/mod.js.map +1 -0
- package/package.json +62 -0
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
|
package/dist/mod.js.map
ADDED
|
@@ -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
|
+
}
|