kafka-crab-js 1.0.2 → 1.0.5

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # 🦀 Kafka Crab JS 🦀
4
4
 
5
- A lightweight and flexible Kafka client for JavaScript/TypeScript, built with Rust-inspired reliability.
5
+ A lightweight, flexible, and reliable Kafka client for JavaScript/TypeScript. It is built using Rust and librdkafka, providing a high-performance and feature-rich Kafka client.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/kafka-crab-js.svg)](https://www.npmjs.com/package/kafka-crab-js)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -38,6 +38,8 @@ A lightweight and flexible Kafka client for JavaScript/TypeScript, built with Ru
38
38
  npm install kafka-crab-js
39
39
  # or
40
40
  yarn add kafka-crab-js
41
+ # or
42
+ pnpm add kafka-crab-js
41
43
  ```
42
44
 
43
45
  ## Quick Start
@@ -205,11 +207,123 @@ async function produceWithMetadata() {
205
207
  }
206
208
  ```
207
209
 
210
+ ### Reconnecting Kafka Consumer
211
+
212
+ ```javascript
213
+ import { KafkaClient } from 'kafka-crab-js'
214
+
215
+ const kafkaClient = new KafkaClient({
216
+ brokers: 'localhost:29092',
217
+ clientId: 'reconnect-test',
218
+ logLevel: 'debug',
219
+ brokerAddressFamily: 'v4',
220
+ configuration: {
221
+ 'auto.offset.reset': 'earliest',
222
+ },
223
+ })
224
+
225
+ /**
226
+ * Creates and configures a new Kafka stream consumer
227
+ */
228
+ async function createConsumer() {
229
+ const kafkaStream = kafkaClient.createStreamConsumer({
230
+ groupId: 'reconnect-test',
231
+ enableAutoCommit: true,
232
+ })
233
+ await kafkaStream.subscribe([
234
+ { topic: 'foo' },
235
+ { topic: 'bar' },
236
+ ])
237
+ return kafkaStream
238
+ }
239
+
240
+ /**
241
+ * Starts a Kafka consumer with auto-restart capability
242
+ */
243
+ async function startConsumer() {
244
+ let counter = 0
245
+ let retryCount = 0
246
+ const MAX_RETRIES = 5
247
+ const RETRY_DELAY = 5000 // 5 seconds
248
+
249
+ async function handleRetry() {
250
+ if (retryCount < MAX_RETRIES) {
251
+ retryCount++
252
+ console.log(
253
+ `Attempting to restart consumer (attempt ${retryCount}/${MAX_RETRIES}) in ${RETRY_DELAY / 1000} seconds...`,
254
+ )
255
+ setTimeout(setupConsumerWithRetry, RETRY_DELAY)
256
+ } else {
257
+ console.error(`Maximum retry attempts (${MAX_RETRIES}) reached. Stopping consumer.`)
258
+ process.exit(1)
259
+ }
260
+ }
261
+
262
+ async function setupConsumerWithRetry() {
263
+ try {
264
+ const kafkaStream = await createConsumer()
265
+ retryCount = 0 // Reset retry count on successful connection
266
+
267
+ console.log('Starting consumer')
268
+
269
+ kafkaStream.on('data', (message) => {
270
+ counter++
271
+ console.log('>>> Message received:', {
272
+ counter,
273
+ payload: message.payload.toString(),
274
+ offset: message.offset,
275
+ partition: message.partition,
276
+ topic: message.topic,
277
+ })
278
+ })
279
+
280
+ kafkaStream.on('error', async (error) => {
281
+ console.error('Stream error:', error)
282
+ handleRetry()
283
+ })
284
+
285
+ kafkaStream.on('close', () => {
286
+ console.log('Stream ended')
287
+ try {
288
+ kafkaStream.unsubscribe()
289
+ } catch (unsubError) {
290
+ console.error('Error unsubscribing:', unsubError)
291
+ }
292
+ })
293
+ } catch (error) {
294
+ console.error('Error setting up consumer:', error)
295
+ handleRetry()
296
+ }
297
+ }
298
+
299
+ await setupConsumerWithRetry()
300
+ }
301
+
302
+ await startConsumer()
303
+ ```
304
+
305
+ ### Examples
306
+
307
+ You can find some examples on the [example](https://github.com/mthssdrbrg/kafka-crab-js/tree/main/example) folder of this project.
308
+
208
309
  ## Configuration
209
310
 
210
311
  ### Configuration properties
211
312
 
212
- You can see the available options here: [librdkafka](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md).
313
+ ### KafkaConfiguration
314
+
315
+ | Property | Type | Default | Description |
316
+ | --- | --- | --- | --- |
317
+ | `brokers` | `string` || List of brokers to connect to |
318
+ | `clientId` | `string` || Client id to use for the connection |
319
+ | `securityProtocol` | `SecurityProtocol` || Security protocol to use (PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL) |
320
+ | `logLevel` | `string` | `info` | Client id to use for the connection |
321
+ | `brokerAddressFamily` | `string` | `"v4"` | Address family to use for the connection (v4, v6) |
322
+ | `configuration` | `Map<string, string>` | `{}` | Additional configuration options for the client. See [librdkafka](https://docs.confluent.io/platform/current/clients/librdkafka/html/md_CONFIGURATION.html) |
323
+
324
+ You can see the available options here: [librdkafka](https://docs.confluent.io/platform/current/clients/librdkafka/html/md_CONFIGURATION.html).
325
+
326
+
213
327
 
214
328
  ## Best Practices
215
329
 
@@ -223,11 +337,6 @@ You can see the available options here: [librdkafka](https://github.com/edenhill
223
337
  - Configure appropriate batch sizes and compression
224
338
  - Monitor and tune consumer group performance
225
339
 
226
- ### Resource Management
227
- - Implement proper shutdown procedures
228
- - Clean up resources (disconnect producers/consumers)
229
- - Handle process signals (SIGTERM, SIGINT)
230
-
231
340
  ### Message Processing
232
341
  - Validate message formats before processing
233
342
  - Implement proper serialization/deserialization
package/js-binding.d.ts CHANGED
@@ -13,7 +13,7 @@ export interface RetryStrategy {
13
13
  }
14
14
  export enum CommitMode {
15
15
  Sync = 0,
16
- Async = 1,
16
+ Async = 1
17
17
  }
18
18
  export interface ConsumerConfiguration {
19
19
  groupId: string
@@ -25,7 +25,7 @@ export interface ConsumerConfiguration {
25
25
  export enum PartitionPosition {
26
26
  Beginning = 'Beginning',
27
27
  End = 'End',
28
- Stored = 'Stored',
28
+ Stored = 'Stored'
29
29
  }
30
30
  export interface OffsetModel {
31
31
  offset?: number
@@ -44,7 +44,7 @@ export enum SecurityProtocol {
44
44
  Plaintext = 'Plaintext',
45
45
  Ssl = 'Ssl',
46
46
  SaslPlaintext = 'SaslPlaintext',
47
- SaslSsl = 'SaslSsl',
47
+ SaslSsl = 'SaslSsl'
48
48
  }
49
49
  export interface KafkaConfiguration {
50
50
  brokers: string
@@ -92,8 +92,9 @@ export declare class KafkaConsumer {
92
92
  pause(): void
93
93
  resume(): void
94
94
  unsubscribe(): void
95
+ shutdownConsumer(): Promise<void>
95
96
  seek(topic: string, partition: number, offsetModel: OffsetModel, timeout?: number | undefined | null): void
96
- recv(): Promise<Message>
97
+ recv(): Promise<Message | null>
97
98
  commit(topic: string, partition: number, offset: number, commit: CommitMode): void
98
99
  }
99
100
  export declare class KafkaClientConfig {
package/js-binding.js CHANGED
@@ -63,7 +63,7 @@ switch (platform) {
63
63
  switch (arch) {
64
64
  case 'x64':
65
65
  localFileExisted = existsSync(
66
- join(__dirname, 'kafka-crab-js.win32-x64-msvc.node'),
66
+ join(__dirname, 'kafka-crab-js.win32-x64-msvc.node')
67
67
  )
68
68
  try {
69
69
  if (localFileExisted) {
@@ -77,7 +77,7 @@ switch (platform) {
77
77
  break
78
78
  case 'ia32':
79
79
  localFileExisted = existsSync(
80
- join(__dirname, 'kafka-crab-js.win32-ia32-msvc.node'),
80
+ join(__dirname, 'kafka-crab-js.win32-ia32-msvc.node')
81
81
  )
82
82
  try {
83
83
  if (localFileExisted) {
@@ -91,7 +91,7 @@ switch (platform) {
91
91
  break
92
92
  case 'arm64':
93
93
  localFileExisted = existsSync(
94
- join(__dirname, 'kafka-crab-js.win32-arm64-msvc.node'),
94
+ join(__dirname, 'kafka-crab-js.win32-arm64-msvc.node')
95
95
  )
96
96
  try {
97
97
  if (localFileExisted) {
@@ -132,7 +132,7 @@ switch (platform) {
132
132
  break
133
133
  case 'arm64':
134
134
  localFileExisted = existsSync(
135
- join(__dirname, 'kafka-crab-js.darwin-arm64.node'),
135
+ join(__dirname, 'kafka-crab-js.darwin-arm64.node')
136
136
  )
137
137
  try {
138
138
  if (localFileExisted) {
@@ -168,7 +168,7 @@ switch (platform) {
168
168
  case 'x64':
169
169
  if (isMusl()) {
170
170
  localFileExisted = existsSync(
171
- join(__dirname, 'kafka-crab-js.linux-x64-musl.node'),
171
+ join(__dirname, 'kafka-crab-js.linux-x64-musl.node')
172
172
  )
173
173
  try {
174
174
  if (localFileExisted) {
@@ -181,7 +181,7 @@ switch (platform) {
181
181
  }
182
182
  } else {
183
183
  localFileExisted = existsSync(
184
- join(__dirname, 'kafka-crab-js.linux-x64-gnu.node'),
184
+ join(__dirname, 'kafka-crab-js.linux-x64-gnu.node')
185
185
  )
186
186
  try {
187
187
  if (localFileExisted) {
@@ -197,7 +197,7 @@ switch (platform) {
197
197
  case 'arm64':
198
198
  if (isMusl()) {
199
199
  localFileExisted = existsSync(
200
- join(__dirname, 'kafka-crab-js.linux-arm64-musl.node'),
200
+ join(__dirname, 'kafka-crab-js.linux-arm64-musl.node')
201
201
  )
202
202
  try {
203
203
  if (localFileExisted) {
@@ -210,7 +210,7 @@ switch (platform) {
210
210
  }
211
211
  } else {
212
212
  localFileExisted = existsSync(
213
- join(__dirname, 'kafka-crab-js.linux-arm64-gnu.node'),
213
+ join(__dirname, 'kafka-crab-js.linux-arm64-gnu.node')
214
214
  )
215
215
  try {
216
216
  if (localFileExisted) {
@@ -226,7 +226,7 @@ switch (platform) {
226
226
  case 'arm':
227
227
  if (isMusl()) {
228
228
  localFileExisted = existsSync(
229
- join(__dirname, 'kafka-crab-js.linux-arm-musleabihf.node'),
229
+ join(__dirname, 'kafka-crab-js.linux-arm-musleabihf.node')
230
230
  )
231
231
  try {
232
232
  if (localFileExisted) {
@@ -239,7 +239,7 @@ switch (platform) {
239
239
  }
240
240
  } else {
241
241
  localFileExisted = existsSync(
242
- join(__dirname, 'kafka-crab-js.linux-arm-gnueabihf.node'),
242
+ join(__dirname, 'kafka-crab-js.linux-arm-gnueabihf.node')
243
243
  )
244
244
  try {
245
245
  if (localFileExisted) {
@@ -255,7 +255,7 @@ switch (platform) {
255
255
  case 'riscv64':
256
256
  if (isMusl()) {
257
257
  localFileExisted = existsSync(
258
- join(__dirname, 'kafka-crab-js.linux-riscv64-musl.node'),
258
+ join(__dirname, 'kafka-crab-js.linux-riscv64-musl.node')
259
259
  )
260
260
  try {
261
261
  if (localFileExisted) {
@@ -268,7 +268,7 @@ switch (platform) {
268
268
  }
269
269
  } else {
270
270
  localFileExisted = existsSync(
271
- join(__dirname, 'kafka-crab-js.linux-riscv64-gnu.node'),
271
+ join(__dirname, 'kafka-crab-js.linux-riscv64-gnu.node')
272
272
  )
273
273
  try {
274
274
  if (localFileExisted) {
@@ -283,7 +283,7 @@ switch (platform) {
283
283
  break
284
284
  case 's390x':
285
285
  localFileExisted = existsSync(
286
- join(__dirname, 'kafka-crab-js.linux-s390x-gnu.node'),
286
+ join(__dirname, 'kafka-crab-js.linux-s390x-gnu.node')
287
287
  )
288
288
  try {
289
289
  if (localFileExisted) {
@@ -310,8 +310,7 @@ if (!nativeBinding) {
310
310
  throw new Error(`Failed to load native binding`)
311
311
  }
312
312
 
313
- const { KafkaConsumer, CommitMode, PartitionPosition, SecurityProtocol, KafkaClientConfig, KafkaProducer } =
314
- nativeBinding
313
+ const { KafkaConsumer, CommitMode, PartitionPosition, SecurityProtocol, KafkaClientConfig, KafkaProducer } = nativeBinding
315
314
 
316
315
  module.exports.KafkaConsumer = KafkaConsumer
317
316
  module.exports.CommitMode = CommitMode
package/kafka-client.js CHANGED
@@ -13,7 +13,7 @@ class KafkaClient {
13
13
  */
14
14
  constructor(kafkaConfiguration) {
15
15
  this.kafkaConfiguration = kafkaConfiguration;
16
- this.kafkaClientConfig = new js_binding_js_1.KafkaClientConfig(kafkaConfiguration);
16
+ this.kafkaClientConfig = new js_binding_js_1.KafkaClientConfig(this.kafkaConfiguration);
17
17
  }
18
18
  /**
19
19
  * Creates a KafkaProducer instance
@@ -1,5 +1,6 @@
1
1
  import { Readable } from 'stream';
2
- import { KafkaConsumer, TopicPartitionConfig } from './js-binding';
2
+ import { CommitMode } from './js-binding';
3
+ import { KafkaConsumer, OffsetModel, TopicPartitionConfig } from './js-binding';
3
4
  /**
4
5
  * KafkaStreamReadable class
5
6
  * @extends Readable
@@ -14,6 +15,8 @@ export declare class KafkaStreamReadable extends Readable {
14
15
  * Subscribes to topics
15
16
  */
16
17
  subscribe(topics: string | Array<TopicPartitionConfig>): Promise<void>;
18
+ seek(topic: string, partition: number, offsetModel: OffsetModel, timeout?: number | undefined): void;
19
+ commit(topic: string, partition: number, offset: number, commit: CommitMode): void;
17
20
  /**
18
21
  * Unsubscribe from topics
19
22
  */
@@ -27,6 +27,12 @@ class KafkaStreamReadable extends stream_1.Readable {
27
27
  }
28
28
  await this.kafkaConsumer.subscribe(topics);
29
29
  }
30
+ seek(topic, partition, offsetModel, timeout) {
31
+ this.kafkaConsumer.seek(topic, partition, offsetModel, timeout);
32
+ }
33
+ commit(topic, partition, offset, commit) {
34
+ this.kafkaConsumer.commit(topic, partition, offset, commit);
35
+ }
30
36
  /**
31
37
  * Unsubscribe from topics
32
38
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kafka-crab-js",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "module": "commonjs",
@@ -40,13 +40,13 @@
40
40
  "url": "https://github.com/inaiat/kafka-crab-js.git"
41
41
  },
42
42
  "devDependencies": {
43
- "@faker-js/faker": "9.2.0",
43
+ "@faker-js/faker": "9.3.0",
44
44
  "@napi-rs/cli": "^2.18.4",
45
- "@types/node": "22.9.0",
45
+ "@types/node": "22.10.1",
46
46
  "ava": "6.2.0",
47
- "dprint": "^0.47.5",
48
- "nanoid": "5.0.8",
49
- "typescript": "5.6.3",
47
+ "dprint": "^0.48.0",
48
+ "nanoid": "5.0.9",
49
+ "typescript": "5.7.2",
50
50
  "copyfiles": "^2.4.1",
51
51
  "@types/copyfiles": "^2.4.4",
52
52
  "rimraf": "^6.0.1"
@@ -65,10 +65,10 @@
65
65
  "version": "napi version",
66
66
  "fmt": "dprint fmt"
67
67
  },
68
- "packageManager": "pnpm@9.14.2",
68
+ "packageManager": "pnpm@9.15.2",
69
69
  "optionalDependencies": {
70
- "kafka-crab-js-darwin-arm64": "1.0.2",
71
- "kafka-crab-js-darwin-x64": "1.0.2",
72
- "kafka-crab-js-linux-x64-gnu": "1.0.2"
70
+ "kafka-crab-js-darwin-arm64": "1.0.5",
71
+ "kafka-crab-js-darwin-x64": "1.0.5",
72
+ "kafka-crab-js-linux-x64-gnu": "1.0.5"
73
73
  }
74
74
  }