@openstatus/health-kafka 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,75 @@
1
+ # @openstatus/health-kafka
2
+
3
+ [Apache Kafka](https://kafka.apache.org/) probe for
4
+ [`@openstatus/health`](https://jsr.io/@openstatus/health). Describes the
5
+ cluster through a connected [KafkaJS](https://kafka.js.org/)-style `Admin`
6
+ client — one metadata request to the broker — and fails the check when no
7
+ broker answers or the cluster reports none.
8
+
9
+ ```sh
10
+ deno add jsr:@openstatus/health jsr:@openstatus/health-kafka
11
+ npm install @openstatus/health @openstatus/health-kafka
12
+ ```
13
+
14
+ ```ts
15
+ import { Kafka } from "kafkajs";
16
+ import { createHealthHandler } from "@openstatus/health";
17
+ import { kafkaProbe } from "@openstatus/health-kafka";
18
+
19
+ const kafka = new Kafka({ brokers: env.KAFKA_BROKERS.split(",") });
20
+ const admin = kafka.admin();
21
+ await admin.connect();
22
+
23
+ Deno.serve(
24
+ createHealthHandler({ probes: [kafkaProbe({ admin })] }),
25
+ );
26
+ ```
27
+
28
+ Connect the `Admin` client once at start-up and keep it: KafkaJS only
29
+ sends the metadata request over an established connection, and creating
30
+ one per health request would add a broker handshake to every poll.
31
+ `describeCluster()` needs no topic and no ACL beyond `Describe` on the
32
+ cluster, so it works with the most restricted credentials. The
33
+ `@confluentinc/kafka-javascript` KafkaJS-compatible `Admin` does not
34
+ implement `describeCluster()`, so it is not supported.
35
+
36
+ ```ts
37
+ kafkaProbe({
38
+ admin,
39
+ // optional overrides from the Probe contract
40
+ name: "events",
41
+ critical: true,
42
+ timeoutMs: 2000,
43
+ skip: () => env.KAFKA_BROKERS == null,
44
+ });
45
+ ```
46
+
47
+ Non-critical by default: Kafka usually carries events processed out of
48
+ band, so an outage degrades the report instead of taking the service out
49
+ of rotation. Set `critical: true` when requests cannot complete without
50
+ producing.
51
+
52
+ The admin client is typed structurally as
53
+ `{ describeCluster(): PromiseLike<{ brokers: [...] }> }`, so `kafkajs` is an
54
+ optional peer dependency for its types only and the probe adds no runtime
55
+ import of it. The factory throws
56
+ `ProbeConfigError` at construction when the client has no
57
+ `describeCluster()`.
58
+
59
+ ## About openstatus
60
+
61
+ [openstatus](https://www.openstatus.dev/) is the open-source uptime monitoring
62
+ and status page platform. This package is part of
63
+ [`@openstatus/health`](https://github.com/openstatusHQ/health), the `/health`
64
+ endpoints behind openstatus's own services, extracted so any JavaScript server
65
+ can expose one. Point an
66
+ [openstatus monitor](https://www.openstatus.dev/docs/reference/http-monitor)
67
+ at the endpoint and assert on `status` in the body to be alerted on
68
+ `degraded` before it becomes `unhealthy`.
69
+
70
+ Source: [github.com/openstatusHQ/health](https://github.com/openstatusHQ/health).
71
+ Issues and PRs welcome.
72
+
73
+ ## License
74
+
75
+ [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,34 @@
1
+ const require_rolldown_runtime = require('./_virtual/rolldown_runtime.cjs');
2
+ const __openstatus_health = require_rolldown_runtime.__toESM(require("@openstatus/health"));
3
+
4
+ //#region src/mod.ts
5
+ /** Probe name when `name` is unset. */
6
+ const kafkaDefaultName = "kafka";
7
+ /** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
8
+ function kafkaProbe(options) {
9
+ const admin = options.admin;
10
+ if (typeof admin?.describeCluster !== "function") throw new __openstatus_health.ProbeConfigError("kafkaProbe", "admin", `must expose describeCluster(), got ${describe(admin)}`);
11
+ return {
12
+ name: options.name ?? kafkaDefaultName,
13
+ critical: options.critical ?? false,
14
+ timeoutMs: options.timeoutMs,
15
+ skip: options.skip,
16
+ run: async () => {
17
+ const cluster = await admin.describeCluster();
18
+ const brokers = cluster?.brokers;
19
+ if (!Array.isArray(brokers)) throw new Error("unexpected response shape");
20
+ if (brokers.length === 0) throw new Error("no brokers in cluster");
21
+ return { brokers: brokers.length };
22
+ }
23
+ };
24
+ }
25
+ function describe(admin) {
26
+ if (admin == null) return String(admin);
27
+ if (typeof admin !== "object") return typeof admin;
28
+ const keys = Object.keys(admin);
29
+ return keys.length === 0 ? "an object with no keys" : `an object with keys ${keys.slice(0, 8).join(", ")}`;
30
+ }
31
+
32
+ //#endregion
33
+ exports.kafkaDefaultName = kafkaDefaultName;
34
+ exports.kafkaProbe = kafkaProbe;
package/dist/mod.d.cts ADDED
@@ -0,0 +1,29 @@
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 kafkaDefaultName = "kafka";
7
+ /** What `describeCluster()` resolves to. */
8
+ interface KafkaClusterDescription {
9
+ /** The brokers currently in the cluster. */
10
+ readonly brokers: readonly {
11
+ readonly nodeId: number;
12
+ }[];
13
+ }
14
+ /** The subset of a KafkaJS `Admin` client the probe uses. */
15
+ interface KafkaLikeAdmin {
16
+ /** Fetch cluster metadata from the connected broker. */
17
+ describeCluster(): PromiseLike<KafkaClusterDescription>;
18
+ }
19
+ /** Options for `kafkaProbe()`. */
20
+ interface KafkaProbeOptions extends ProbeOverrides {
21
+ /** A connected `kafkajs` `Admin` client. */
22
+ readonly admin: KafkaLikeAdmin;
23
+ }
24
+ /** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
25
+ declare function kafkaProbe(options: KafkaProbeOptions): Probe;
26
+ //# sourceMappingURL=mod.d.ts.map
27
+ //#endregion
28
+ export { KafkaClusterDescription, KafkaLikeAdmin, KafkaProbeOptions, kafkaDefaultName, kafkaProbe };
29
+ //# sourceMappingURL=mod.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.cts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AA4CoC,cArBvB,gBAAA,GAqBuB,OAAA;;AAAyB,UAlB5C,uBAAA,CAkB4C;;;;;;;UAZ5C,cAAA;;qBAEI,YAAY;;;UAIhB,iBAAA,SAA0B;;kBAEzB;;;iBAIF,UAAA,UAAoB,oBAAoB"}
package/dist/mod.d.ts ADDED
@@ -0,0 +1,29 @@
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 kafkaDefaultName = "kafka";
7
+ /** What `describeCluster()` resolves to. */
8
+ interface KafkaClusterDescription {
9
+ /** The brokers currently in the cluster. */
10
+ readonly brokers: readonly {
11
+ readonly nodeId: number;
12
+ }[];
13
+ }
14
+ /** The subset of a KafkaJS `Admin` client the probe uses. */
15
+ interface KafkaLikeAdmin {
16
+ /** Fetch cluster metadata from the connected broker. */
17
+ describeCluster(): PromiseLike<KafkaClusterDescription>;
18
+ }
19
+ /** Options for `kafkaProbe()`. */
20
+ interface KafkaProbeOptions extends ProbeOverrides {
21
+ /** A connected `kafkajs` `Admin` client. */
22
+ readonly admin: KafkaLikeAdmin;
23
+ }
24
+ /** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
25
+ declare function kafkaProbe(options: KafkaProbeOptions): Probe;
26
+ //# sourceMappingURL=mod.d.ts.map
27
+ //#endregion
28
+ export { KafkaClusterDescription, KafkaLikeAdmin, KafkaProbeOptions, kafkaDefaultName, kafkaProbe };
29
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","names":[],"sources":["../src/mod.ts"],"sourcesContent":[],"mappings":";;;;;AA4CoC,cArBvB,gBAAA,GAqBuB,OAAA;;AAAyB,UAlB5C,uBAAA,CAkB4C;;;;;;;UAZ5C,cAAA;;qBAEI,YAAY;;;UAIhB,iBAAA,SAA0B;;kBAEzB;;;iBAIF,UAAA,UAAoB,oBAAoB"}
package/dist/mod.js ADDED
@@ -0,0 +1,33 @@
1
+ import { ProbeConfigError } from "@openstatus/health";
2
+
3
+ //#region src/mod.ts
4
+ /** Probe name when `name` is unset. */
5
+ const kafkaDefaultName = "kafka";
6
+ /** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */
7
+ function kafkaProbe(options) {
8
+ const admin = options.admin;
9
+ if (typeof admin?.describeCluster !== "function") throw new ProbeConfigError("kafkaProbe", "admin", `must expose describeCluster(), got ${describe(admin)}`);
10
+ return {
11
+ name: options.name ?? kafkaDefaultName,
12
+ critical: options.critical ?? false,
13
+ timeoutMs: options.timeoutMs,
14
+ skip: options.skip,
15
+ run: async () => {
16
+ const cluster = await admin.describeCluster();
17
+ const brokers = cluster?.brokers;
18
+ if (!Array.isArray(brokers)) throw new Error("unexpected response shape");
19
+ if (brokers.length === 0) throw new Error("no brokers in cluster");
20
+ return { brokers: brokers.length };
21
+ }
22
+ };
23
+ }
24
+ function describe(admin) {
25
+ if (admin == null) return String(admin);
26
+ if (typeof admin !== "object") return typeof admin;
27
+ const keys = Object.keys(admin);
28
+ return keys.length === 0 ? "an object with no keys" : `an object with keys ${keys.slice(0, 8).join(", ")}`;
29
+ }
30
+
31
+ //#endregion
32
+ export { kafkaDefaultName, kafkaProbe };
33
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","names":["options: KafkaProbeOptions","admin: KafkaLikeAdmin"],"sources":["../src/mod.ts"],"sourcesContent":["/**\n * Kafka probe for `@openstatus/health`: describes the cluster through a\n * connected KafkaJS-style `Admin` client and fails when no broker answers.\n *\n * ```ts\n * import { Kafka } from \"kafkajs\";\n * import { kafkaProbe } from \"@openstatus/health-kafka\";\n *\n * const admin = new Kafka({ brokers }).admin();\n * await admin.connect();\n * const probe = kafkaProbe({ admin });\n * ```\n *\n * @module\n */\n\nimport {\n type Probe,\n ProbeConfigError,\n type ProbeOverrides,\n} from \"@openstatus/health\";\n\n/** Probe name when `name` is unset. */\nexport const kafkaDefaultName = \"kafka\";\n\n/** What `describeCluster()` resolves to. */\nexport interface KafkaClusterDescription {\n /** The brokers currently in the cluster. */\n readonly brokers: readonly { readonly nodeId: number }[];\n}\n\n/** The subset of a KafkaJS `Admin` client the probe uses. */\nexport interface KafkaLikeAdmin {\n /** Fetch cluster metadata from the connected broker. */\n describeCluster(): PromiseLike<KafkaClusterDescription>;\n}\n\n/** Options for `kafkaProbe()`. */\nexport interface KafkaProbeOptions extends ProbeOverrides {\n /** A connected `kafkajs` `Admin` client. */\n readonly admin: KafkaLikeAdmin;\n}\n\n/** A probe that describes the cluster and expects at least one broker; non-critical by default. Throws `ProbeConfigError` without `describeCluster()`. */\nexport function kafkaProbe(options: KafkaProbeOptions): Probe {\n const admin = options.admin;\n if (typeof admin?.describeCluster !== \"function\") {\n throw new ProbeConfigError(\n \"kafkaProbe\",\n \"admin\",\n `must expose describeCluster(), got ${describe(admin)}`,\n );\n }\n return {\n name: options.name ?? kafkaDefaultName,\n critical: options.critical ?? false,\n timeoutMs: options.timeoutMs,\n skip: options.skip,\n run: async () => {\n const cluster = await admin.describeCluster();\n const brokers = cluster?.brokers;\n if (!Array.isArray(brokers)) throw new Error(\"unexpected response shape\");\n if (brokers.length === 0) throw new Error(\"no brokers in cluster\");\n return { brokers: brokers.length };\n },\n };\n}\n\nfunction describe(admin: KafkaLikeAdmin): string {\n if (admin == null) return String(admin);\n if (typeof admin !== \"object\") return typeof admin;\n const keys = Object.keys(admin);\n return keys.length === 0\n ? \"an object with no keys\"\n : `an object with keys ${keys.slice(0, 8).join(\", \")}`;\n}\n"],"mappings":";;;;AAuBA,MAAa,mBAAmB;;AAqBhC,SAAgB,WAAWA,SAAmC;CAC5D,MAAM,QAAQ,QAAQ;AACtB,YAAW,OAAO,oBAAoB,WACpC,OAAM,IAAI,iBACR,cACA,UACC,qCAAqC,SAAS,MAAM,CAAC;AAG1D,QAAO;EACL,MAAM,QAAQ,QAAQ;EACtB,UAAU,QAAQ,YAAY;EAC9B,WAAW,QAAQ;EACnB,MAAM,QAAQ;EACd,KAAK,YAAY;GACf,MAAM,UAAU,MAAM,MAAM,iBAAiB;GAC7C,MAAM,UAAU,SAAS;AACzB,QAAK,MAAM,QAAQ,QAAQ,CAAE,OAAM,IAAI,MAAM;AAC7C,OAAI,QAAQ,WAAW,EAAG,OAAM,IAAI,MAAM;AAC1C,UAAO,EAAE,SAAS,QAAQ,OAAQ;EACnC;CACF;AACF;AAED,SAAS,SAASC,OAA+B;AAC/C,KAAI,SAAS,KAAM,QAAO,OAAO,MAAM;AACvC,YAAW,UAAU,SAAU,eAAc;CAC7C,MAAM,OAAO,OAAO,KAAK,MAAM;AAC/B,QAAO,KAAK,WAAW,IACnB,4BACC,sBAAsB,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC;AACxD"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@openstatus/health-kafka",
3
+ "version": "0.1.4-dev.0",
4
+ "description": "Kafka probe for @openstatus/health",
5
+ "keywords": [
6
+ "openstatus",
7
+ "health",
8
+ "healthcheck",
9
+ "kafka",
10
+ "kafkajs",
11
+ "messaging",
12
+ "streaming"
13
+ ],
14
+ "license": "MIT",
15
+ "author": {
16
+ "name": "openstatus",
17
+ "url": "https://www.openstatus.dev/"
18
+ },
19
+ "homepage": "https://github.com/openstatusHQ/health",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/openstatusHQ/health.git",
23
+ "directory": "packages/kafka/"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/openstatusHQ/health/issues"
27
+ },
28
+ "type": "module",
29
+ "module": "./dist/mod.js",
30
+ "main": "./dist/mod.cjs",
31
+ "types": "./dist/mod.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": {
35
+ "import": "./dist/mod.d.ts",
36
+ "require": "./dist/mod.d.cts"
37
+ },
38
+ "import": "./dist/mod.js",
39
+ "require": "./dist/mod.cjs"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "sideEffects": false,
44
+ "files": [
45
+ "dist/"
46
+ ],
47
+ "engines": {
48
+ "node": ">=22"
49
+ },
50
+ "peerDependencies": {
51
+ "@openstatus/health": "^0.1.4-dev.0",
52
+ "kafkajs": ">=2.0.0"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "kafkajs": {
56
+ "optional": true
57
+ }
58
+ },
59
+ "devDependencies": {
60
+ "tsdown": "^0.12.7",
61
+ "typescript": "^5.8.3"
62
+ },
63
+ "scripts": {
64
+ "build": "tsdown",
65
+ "prepack": "tsdown",
66
+ "test": "node --experimental-transform-types --test"
67
+ }
68
+ }