@platformatic/kafka 0.2.0 → 0.4.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.
@@ -16,7 +16,7 @@ import { defaultBaseOptions } from "../base/options.js";
16
16
  import { createPromisifiedCallback, kCallbackPromise, runConcurrentCallbacks } from "../callbacks.js";
17
17
  import { ensureMetric } from "../metrics.js";
18
18
  import { MessagesStream } from "./messages-stream.js";
19
- import { commitOptionsValidator, consumeOptionsValidator, consumerOptionsValidator, defaultConsumerOptions, fetchOptionsValidator, groupOptionsValidator, listCommitsOptionsValidator, listOffsetsOptionsValidator } from "./options.js";
19
+ import { commitOptionsValidator, consumeOptionsValidator, consumerOptionsValidator, defaultConsumerOptions, fetchOptionsValidator, groupIdAndOptionsValidator, groupOptionsValidator, listCommitsOptionsValidator, listOffsetsOptionsValidator } from "./options.js";
20
20
  import { TopicsMap } from "./topics-map.js";
21
21
  export class Consumer extends Base {
22
22
  groupId;
@@ -64,7 +64,7 @@ export class Consumer extends Base {
64
64
  this.#coordinatorId = null;
65
65
  this.#heartbeatInterval = null;
66
66
  this.#streams = new Set();
67
- this.#validateGroupOptions(this[kOptions]);
67
+ this.#validateGroupOptions(this[kOptions], groupIdAndOptionsValidator);
68
68
  // Initialize connection pool
69
69
  this[kFetchConnections] = this[kCreateConnectionPool]();
70
70
  if (this[kPrometheus]) {
@@ -688,10 +688,11 @@ export class Consumer extends Base {
688
688
  });
689
689
  });
690
690
  }
691
- #validateGroupOptions(options) {
692
- const valid = groupOptionsValidator(options);
691
+ #validateGroupOptions(options, validator) {
692
+ validator ??= groupOptionsValidator;
693
+ const valid = validator(options);
693
694
  if (!valid) {
694
- throw new UserError(this[kFormatValidationErrors](groupOptionsValidator, '/options'));
695
+ throw new UserError(this[kFormatValidationErrors](validator, '/options'));
695
696
  }
696
697
  }
697
698
  /*
@@ -269,12 +269,12 @@ export class MessagesStream extends Readable {
269
269
  const firstTimestamp = records.firstTimestamp;
270
270
  const leaderEpoch = metadata.topics.get(topic).partitions[partition].leaderEpoch;
271
271
  for (const record of records.records) {
272
- const key = keyDeserializer(record.key);
273
- const value = valueDeserializer(record.value);
274
272
  const headers = new Map();
275
273
  for (const [headerKey, headerValue] of record.headers) {
276
274
  headers.set(headerKeyDeserializer(headerKey), headerValueDeserializer(headerValue));
277
275
  }
276
+ const key = keyDeserializer(record.key, headers);
277
+ const value = valueDeserializer(record.value, headers);
278
278
  this.#metricsConsumedMessages?.inc();
279
279
  canPush = this.push({
280
280
  key,
@@ -1,4 +1,120 @@
1
1
  import { type ConsumerOptions } from './types.ts';
2
+ export declare const groupOptionsProperties: {
3
+ sessionTimeout: {
4
+ type: string;
5
+ minimum: number;
6
+ };
7
+ rebalanceTimeout: {
8
+ type: string;
9
+ minimum: number;
10
+ };
11
+ heartbeatInterval: {
12
+ type: string;
13
+ minimum: number;
14
+ };
15
+ protocols: {
16
+ type: string;
17
+ items: {
18
+ type: string;
19
+ properties: {
20
+ name: {
21
+ type: string;
22
+ pattern: string;
23
+ };
24
+ version: {
25
+ type: string;
26
+ minimum: number;
27
+ };
28
+ topics: {
29
+ type: string;
30
+ items: {
31
+ type: string;
32
+ };
33
+ };
34
+ metadata: {
35
+ oneOf: ({
36
+ type: string;
37
+ buffer?: undefined;
38
+ } | {
39
+ buffer: boolean;
40
+ type?: undefined;
41
+ })[];
42
+ };
43
+ };
44
+ };
45
+ };
46
+ };
47
+ export declare const groupOptionsAdditionalValidations: {
48
+ rebalanceTimeout: {
49
+ properties: {
50
+ rebalanceTimeout: {
51
+ type: string;
52
+ minimum: number;
53
+ gteProperty: string;
54
+ };
55
+ };
56
+ };
57
+ heartbeatInterval: {
58
+ properties: {
59
+ heartbeatInterval: {
60
+ type: string;
61
+ minimum: number;
62
+ allOf: {
63
+ lteProperty: string;
64
+ }[];
65
+ };
66
+ };
67
+ };
68
+ };
69
+ export declare const consumeOptionsProperties: {
70
+ autocommit: {
71
+ oneOf: ({
72
+ type: string;
73
+ minimum?: undefined;
74
+ } | {
75
+ type: string;
76
+ minimum: number;
77
+ })[];
78
+ };
79
+ minBytes: {
80
+ type: string;
81
+ minimum: number;
82
+ };
83
+ maxBytes: {
84
+ type: string;
85
+ minimum: number;
86
+ };
87
+ maxWaitTime: {
88
+ type: string;
89
+ minimum: number;
90
+ };
91
+ isolationLevel: {
92
+ type: string;
93
+ enum: string[];
94
+ };
95
+ deserializers: {
96
+ type: string;
97
+ properties: {
98
+ key: {
99
+ function: boolean;
100
+ };
101
+ value: {
102
+ function: boolean;
103
+ };
104
+ headerKey: {
105
+ function: boolean;
106
+ };
107
+ headerValue: {
108
+ function: boolean;
109
+ };
110
+ };
111
+ additionalProperties: boolean;
112
+ };
113
+ highWaterMark: {
114
+ type: string;
115
+ minimum: number;
116
+ };
117
+ };
2
118
  export declare const groupOptionsSchema: {
3
119
  type: string;
4
120
  properties: {
@@ -500,6 +616,9 @@ export declare const listOffsetsOptionsSchema: {
500
616
  additionalProperties: boolean;
501
617
  };
502
618
  export declare const groupOptionsValidator: import("ajv").ValidateFunction<unknown>;
619
+ export declare const groupIdAndOptionsValidator: import("ajv").ValidateFunction<{
620
+ groupId: any;
621
+ }>;
503
622
  export declare const consumeOptionsValidator: import("ajv").ValidateFunction<{
504
623
  [x: string]: {};
505
624
  }>;
@@ -3,7 +3,7 @@ import { ajv } from "../../utils.js";
3
3
  import { idProperty, topicWithPartitionAndOffsetProperties } from "../base/options.js";
4
4
  import { serdeProperties } from "../serde.js";
5
5
  import { MessagesStreamFallbackModes, MessagesStreamModes } from "./types.js";
6
- const groupOptionsProperties = {
6
+ export const groupOptionsProperties = {
7
7
  sessionTimeout: { type: 'number', minimum: 0 },
8
8
  rebalanceTimeout: { type: 'number', minimum: 0 },
9
9
  heartbeatInterval: { type: 'number', minimum: 0 },
@@ -23,7 +23,7 @@ const groupOptionsProperties = {
23
23
  }
24
24
  }
25
25
  };
26
- const groupOptionsAdditionalValidations = {
26
+ export const groupOptionsAdditionalValidations = {
27
27
  rebalanceTimeout: {
28
28
  properties: {
29
29
  rebalanceTimeout: {
@@ -50,7 +50,7 @@ const groupOptionsAdditionalValidations = {
50
50
  }
51
51
  }
52
52
  };
53
- const consumeOptionsProperties = {
53
+ export const consumeOptionsProperties = {
54
54
  autocommit: { oneOf: [{ type: 'boolean' }, { type: 'number', minimum: 100 }] },
55
55
  minBytes: { type: 'number', minimum: 0 },
56
56
  maxBytes: { type: 'number', minimum: 0 },
@@ -187,6 +187,16 @@ export const groupOptionsValidator = ajv.compile({
187
187
  ...groupOptionsSchema,
188
188
  dependentSchemas: groupOptionsAdditionalValidations
189
189
  });
190
+ export const groupIdAndOptionsValidator = ajv.compile({
191
+ type: 'object',
192
+ properties: {
193
+ groupId: idProperty,
194
+ ...groupOptionsProperties
195
+ },
196
+ required: ['groupId'],
197
+ additionalProperties: true,
198
+ dependentSchemas: groupOptionsAdditionalValidations
199
+ });
190
200
  export const consumeOptionsValidator = ajv.compile(consumeOptionsSchema);
191
201
  export const consumerOptionsValidator = ajv.compile(consumerOptionsSchema);
192
202
  export const fetchOptionsValidator = ajv.compile(fetchOptionsSchema);
@@ -1,3 +1,33 @@
1
+ export declare const produceOptionsProperties: {
2
+ producerId: {
3
+ bigint: boolean;
4
+ };
5
+ producerEpoch: {
6
+ type: string;
7
+ };
8
+ idempotent: {
9
+ type: string;
10
+ };
11
+ acks: {
12
+ type: string;
13
+ enum: (0 | 1 | -1)[];
14
+ errorMessage: string;
15
+ };
16
+ compression: {
17
+ type: string;
18
+ enum: string[];
19
+ errorMessage: string;
20
+ };
21
+ partitioner: {
22
+ function: boolean;
23
+ };
24
+ autocreateTopics: {
25
+ type: string;
26
+ };
27
+ repeatOnStaleMetadata: {
28
+ type: string;
29
+ };
30
+ };
1
31
  export declare const produceOptionsSchema: {
2
32
  type: string;
3
33
  properties: {
@@ -3,7 +3,7 @@ import { compressionsAlgorithms } from "../../protocol/compression.js";
3
3
  import { messageSchema } from "../../protocol/records.js";
4
4
  import { ajv, enumErrorMessage } from "../../utils.js";
5
5
  import { serdeProperties } from "../serde.js";
6
- const produceOptionsProperties = {
6
+ export const produceOptionsProperties = {
7
7
  producerId: { bigint: true },
8
8
  producerEpoch: { type: 'number' },
9
9
  idempotent: { type: 'boolean' },
@@ -159,8 +159,19 @@ export class Producer extends Base {
159
159
  const messages = [];
160
160
  for (const message of options.messages) {
161
161
  const topic = message.topic;
162
- const key = this.#keySerializer(message.key);
163
- const headers = new Map();
162
+ let headers = new Map();
163
+ const serializedHeaders = new Map();
164
+ if (message.headers) {
165
+ headers =
166
+ message.headers instanceof Map
167
+ ? message.headers
168
+ : new Map(Object.entries(message.headers));
169
+ for (const [key, value] of headers) {
170
+ serializedHeaders.set(this.#headerKeySerializer(key), this.#headerValueSerializer(value));
171
+ }
172
+ }
173
+ const key = this.#keySerializer(message.key, headers);
174
+ const value = this.#valueSerializer(message.value, headers);
164
175
  let partition = 0;
165
176
  if (typeof message.partition !== 'number') {
166
177
  if (partitioner) {
@@ -177,17 +188,11 @@ export class Producer extends Base {
177
188
  else {
178
189
  partition = message.partition;
179
190
  }
180
- if (message.headers) {
181
- const entries = message.headers instanceof Map ? message.headers : Object.entries(message.headers);
182
- for (const [key, value] of entries) {
183
- headers.set(this.#headerKeySerializer(key), this.#headerValueSerializer(value));
184
- }
185
- }
186
191
  topics.add(topic);
187
192
  messages.push({
188
193
  key,
189
- value: this.#valueSerializer(message.value),
190
- headers,
194
+ value,
195
+ headers: serializedHeaders,
191
196
  topic,
192
197
  partition,
193
198
  timestamp: message.timestamp
@@ -1,14 +1,16 @@
1
1
  export type Serializer<InputType = unknown> = (data?: InputType) => Buffer | undefined;
2
2
  export type Deserializer<OutputType = unknown> = (data?: Buffer) => OutputType | undefined;
3
+ export type SerializerWithHeaders<InputType = unknown, HeaderKey = unknown, HeaderValue = unknown> = (data?: InputType, headers?: Map<HeaderKey, HeaderValue>) => Buffer | undefined;
4
+ export type DeserializerWithHeaders<OutputType = unknown, HeaderKey = unknown, HeaderValue = unknown> = (data?: Buffer, headers?: Map<HeaderKey, HeaderValue>) => OutputType | undefined;
3
5
  export interface Serializers<Key, Value, HeaderKey, HeaderValue> {
4
- key: Serializer<Key>;
5
- value: Serializer<Value>;
6
+ key: SerializerWithHeaders<Key, HeaderKey, HeaderValue>;
7
+ value: SerializerWithHeaders<Value, HeaderKey, HeaderValue>;
6
8
  headerKey: Serializer<HeaderKey>;
7
9
  headerValue: Serializer<HeaderValue>;
8
10
  }
9
11
  export interface Deserializers<Key, Value, HeaderKey, HeaderValue> {
10
- key: Deserializer<Key>;
11
- value: Deserializer<Value>;
12
+ key: DeserializerWithHeaders<Key>;
13
+ value: DeserializerWithHeaders<Value>;
12
14
  headerKey: Deserializer<HeaderKey>;
13
15
  headerValue: Deserializer<HeaderValue>;
14
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/kafka",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Modern and performant client for Apache Kafka",
5
5
  "homepage": "https://github.com/platformatic/kafka",
6
6
  "author": "Platformatic Inc. <oss@platformatic.dev> (https://platformatic.dev)",