@healthzkit/kafka 0.0.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,138 @@
1
+ # @healthzkit/kafka
2
+
3
+ Kafka **healthzkit** `HealthAdapter` helpers for **[`kafkajs`](https://kafka.js.org/)** and **[`node-rdkafka`](https://github.com/Blizzard/node-rdkafka)**. Successful checks return `ok` with `metadata.latencyMs` plus any fields from an optional `metadata` hook; failures return `fail` with the caught error.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @healthzkit/kafka healthzkit
9
+ # plus one of:
10
+ npm install kafkajs
11
+ npm install node-rdkafka
12
+ ```
13
+
14
+ Both clients are optional peers—install the library you use.
15
+
16
+ `node-rdkafka` is a native addon (requires `librdkafka` at build/runtime). Prefer **`kafkajs`** when you want a pure JavaScript client.
17
+
18
+ ## Shared options
19
+
20
+ Both factories accept `BaseKafkaOptions`:
21
+
22
+ | Option | Description |
23
+ | ---------- | ----------------------------------------------------------------------------------------------------- |
24
+ | `metadata` | Optional `(client) => Record<string, unknown>` (sync or async) merged into metadata with `latencyMs`. |
25
+
26
+ Pass either client configuration or an existing client/producer/consumer (not both). The shape depends on the adapter (see below).
27
+
28
+ ## `kafkajsAdapter` (`kafkajs`)
29
+
30
+ **Peer:** `kafkajs` ≥ 2.
31
+
32
+ Each check creates an admin client, connects, calls `describeCluster()`, and disconnects the admin handle. The underlying `Kafka` instance is reused when you pass `config`.
33
+
34
+ ### Config
35
+
36
+ The adapter lazily imports `kafkajs`, constructs `new Kafka(config)` once, and reuses it across checks.
37
+
38
+ ```ts
39
+ import { createHealthKit } from "healthzkit";
40
+ import { kafkajsAdapter } from "@healthzkit/kafka";
41
+
42
+ const kit = createHealthKit({
43
+ checks: [
44
+ {
45
+ name: "kafka",
46
+ type: ["readiness"],
47
+ adapter: kafkajsAdapter({
48
+ config: { brokers: [process.env.KAFKA_BROKERS!] },
49
+ }),
50
+ },
51
+ ],
52
+ });
53
+ ```
54
+
55
+ `config` is the first argument to the `Kafka` constructor (for example `brokers`, `clientId`, `ssl`, `sasl`).
56
+
57
+ ### Existing client
58
+
59
+ Pass **`client`** as an existing `Kafka` instance from your app. The adapter reuses that client across checks.
60
+
61
+ ```ts
62
+ import { Kafka } from "kafkajs";
63
+ import { kafkajsAdapter } from "@healthzkit/kafka";
64
+
65
+ const kafka = new Kafka({ brokers: [process.env.KAFKA_BROKERS!] });
66
+
67
+ const adapter = kafkajsAdapter({
68
+ client: kafka,
69
+ metadata: () => ({ driver: "kafkajs" }),
70
+ });
71
+ ```
72
+
73
+ ## `nodeRdKafkaAdapter` (`node-rdkafka`)
74
+
75
+ **Peer:** `node-rdkafka` ≥ 3.
76
+
77
+ Each check fetches broker metadata via `getMetadata()` when the client is already connected, or `connect({}, cb)` otherwise. That exercises the broker path without producing or consuming messages.
78
+
79
+ ### Config
80
+
81
+ The adapter lazily imports `node-rdkafka`, constructs `new Producer(config)` once, and reuses it across checks.
82
+
83
+ ```ts
84
+ import { nodeRdKafkaAdapter } from "@healthzkit/kafka";
85
+
86
+ const adapter = nodeRdKafkaAdapter({
87
+ config: { "bootstrap.servers": process.env.KAFKA_BROKERS! },
88
+ });
89
+ ```
90
+
91
+ `config` is a `ProducerGlobalConfig` object (for example `bootstrap.servers`, `security.protocol`, `sasl.username`).
92
+
93
+ ### Existing client
94
+
95
+ Pass **`client`** as an existing `Producer` or `KafkaConsumer` from your app. The adapter reuses that instance across checks.
96
+
97
+ ```ts
98
+ import { Producer } from "node-rdkafka";
99
+ import { nodeRdKafkaAdapter } from "@healthzkit/kafka";
100
+
101
+ const producer = new Producer({
102
+ "bootstrap.servers": process.env.KAFKA_BROKERS!,
103
+ });
104
+
105
+ const adapter = nodeRdKafkaAdapter({
106
+ client: producer,
107
+ metadata: () => ({ driver: "node-rdkafka" }),
108
+ });
109
+ ```
110
+
111
+ ## Check result
112
+
113
+ On success:
114
+
115
+ ```json
116
+ {
117
+ "status": "ok",
118
+ "metadata": { "latencyMs": 12 }
119
+ }
120
+ ```
121
+
122
+ On failure, `status` is `"fail"` and `error` is set (see [healthzkit](https://github.com/alasti-company/healthzkit) for how that rolls up into probe responses).
123
+
124
+ ## Scheduling
125
+
126
+ For brokers that should not be probed on every request, pair these adapters with a **`schedule`** on the check so readiness reads cached results instead of hitting Kafka on every probe. See the **Scheduling** section in the `healthzkit` README.
127
+
128
+ ## Development
129
+
130
+ From the monorepo root:
131
+
132
+ ```bash
133
+ vp install
134
+ vp test --filter @healthzkit/kafka
135
+ vp pack --filter @healthzkit/kafka
136
+ ```
137
+
138
+ See the repo root `AGENTS.md` for Vite+ / `vp` conventions.
@@ -0,0 +1,3 @@
1
+ import { KafkaJsAdapterOptions, kafkajsAdapter } from "./kafkajs.mjs";
2
+ import { NodeRdKafkaAdapterOptions, nodeRdKafkaAdapter } from "./node-rdkafka.mjs";
3
+ export { type KafkaJsAdapterOptions, type NodeRdKafkaAdapterOptions, kafkajsAdapter, nodeRdKafkaAdapter };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ import{kafkajsAdapter as e}from"./kafkajs.mjs";import{nodeRdKafkaAdapter as t}from"./node-rdkafka.mjs";export{e as kafkajsAdapter,t as nodeRdKafkaAdapter};
@@ -0,0 +1,16 @@
1
+ import { n as HealthAdapter, t as BaseKafkaOptions } from "./shared-BQHQT909.mjs";
2
+ import { Kafka } from "kafkajs";
3
+
4
+ //#region src/kafkajs.d.ts
5
+ interface KafkaJsAdapterOptionsWithClient extends BaseKafkaOptions<Kafka> {
6
+ client: Kafka;
7
+ config?: never;
8
+ }
9
+ interface KafkaJsAdapterOptionsWithConfig extends BaseKafkaOptions<Kafka> {
10
+ config: ConstructorParameters<typeof Kafka>[0];
11
+ client?: never;
12
+ }
13
+ type KafkaJsAdapterOptions = KafkaJsAdapterOptionsWithClient | KafkaJsAdapterOptionsWithConfig;
14
+ declare function kafkajsAdapter(options: KafkaJsAdapterOptions): HealthAdapter;
15
+ //#endregion
16
+ export { KafkaJsAdapterOptions, KafkaJsAdapterOptionsWithClient, KafkaJsAdapterOptionsWithConfig, kafkajsAdapter };
@@ -0,0 +1 @@
1
+ import{n as e,t}from"./shared-BiUsKU63.mjs";function n(n){let r=null;async function i(){if(`client`in n&&n.client)return n.client;if(!r){let{Kafka:e}=await import(`kafkajs`);r=new e(n.config)}return r}return{async check(){let r=null;try{let t=await i(),a=Date.now();r=t.admin(),await r.connect(),await r.describeCluster();let o=Date.now()-a,s=n.metadata?n.metadata(t):void 0;return e(o,s instanceof Promise?await s:s)}catch(e){return t(e)}finally{r&&await r.disconnect().catch(()=>{})}}}}export{n as kafkajsAdapter};
@@ -0,0 +1,17 @@
1
+ import { n as HealthAdapter, t as BaseKafkaOptions } from "./shared-BQHQT909.mjs";
2
+ import { KafkaConsumer, Producer, ProducerGlobalConfig } from "node-rdkafka";
3
+
4
+ //#region src/node-rdkafka.d.ts
5
+ type RdKafkaClient = Producer | KafkaConsumer;
6
+ interface NodeRdKafkaOptionsWithClient extends BaseKafkaOptions<RdKafkaClient> {
7
+ client: RdKafkaClient;
8
+ config?: never;
9
+ }
10
+ interface NodeRdKafkaOptionsWithConfig extends BaseKafkaOptions<RdKafkaClient> {
11
+ config: ProducerGlobalConfig;
12
+ client?: never;
13
+ }
14
+ type NodeRdKafkaAdapterOptions = NodeRdKafkaOptionsWithClient | NodeRdKafkaOptionsWithConfig;
15
+ declare function nodeRdKafkaAdapter(options: NodeRdKafkaAdapterOptions): HealthAdapter;
16
+ //#endregion
17
+ export { NodeRdKafkaAdapterOptions, NodeRdKafkaOptionsWithClient, NodeRdKafkaOptionsWithConfig, nodeRdKafkaAdapter };
@@ -0,0 +1 @@
1
+ import{n as e,t}from"./shared-BiUsKU63.mjs";function n(e){return new Promise((t,n)=>{let r=e=>{e?n(e):t()};if(e.isConnected()){e.getMetadata({},r);return}e.connect({},t=>{if(t){n(t);return}e.getMetadata({},r)})})}function r(r){let i=null,a=null;async function o(){return`client`in r&&r.client?r.client:i||(a||=(async()=>{try{let{Producer:e}=await import(`node-rdkafka`);return i=new e(r.config),i}finally{a=null}})(),a)}return{async check(){try{let t=await o(),i=Date.now();await n(t);let a=Date.now()-i,s=r.metadata?r.metadata(t):void 0;return e(a,s instanceof Promise?await s:s)}catch(e){return t(e)}}}}export{r as nodeRdKafkaAdapter};
@@ -0,0 +1,12 @@
1
+ import { HealthAdapter, MetadataFn } from "@healthzkit/shared";
2
+
3
+ //#region src/shared.d.ts
4
+ interface BaseKafkaOptions<TClient> {
5
+ /**
6
+ * Optional function to populate metadata in the check result.
7
+ * Receives the resolved client so you can additional operations.
8
+ */
9
+ metadata?: MetadataFn<TClient>;
10
+ }
11
+ //#endregion
12
+ export { HealthAdapter as n, BaseKafkaOptions as t };
@@ -0,0 +1 @@
1
+ import{buildErrorResult as e,buildResult as t}from"@healthzkit/shared";export{t as n,e as t};
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@healthzkit/kafka",
3
+ "version": "0.0.0",
4
+ "license": "AGPL-3.0-only",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/alasti-company/healthzkit.dev",
8
+ "directory": "packages/kafka"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "type": "module",
14
+ "exports": {
15
+ ".": "./dist/index.mjs",
16
+ "./kafkajs": "./dist/kafkajs.mjs",
17
+ "./node-rdkafka": "./dist/node-rdkafka.mjs",
18
+ "./package.json": "./package.json"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "vp pack",
25
+ "dev": "vp pack --watch",
26
+ "test": "vp test",
27
+ "check": "vp check",
28
+ "prepublishOnly": "vp run build"
29
+ },
30
+ "dependencies": {
31
+ "@healthzkit/shared": "workspace:*"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "catalog:",
35
+ "@typescript/native-preview": "7.0.0-dev.20260509.2",
36
+ "bumpp": "^11.1.0",
37
+ "healthzkit": "workspace:*",
38
+ "kafkajs": "^2.2.4",
39
+ "node-rdkafka": "^3.6.1",
40
+ "typescript": "catalog:",
41
+ "vite-plus": "catalog:"
42
+ },
43
+ "peerDependencies": {
44
+ "kafkajs": ">=2.0.0",
45
+ "node-rdkafka": ">=3.0.0"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "kafkajs": {
49
+ "optional": true
50
+ },
51
+ "node-rdkafka": {
52
+ "optional": true
53
+ }
54
+ }
55
+ }