@platformatic/kafka 0.1.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.
Files changed (223) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +270 -0
  3. package/dist/apis/admin/alter-client-quotas.d.ts +33 -0
  4. package/dist/apis/admin/alter-client-quotas.js +64 -0
  5. package/dist/apis/admin/alter-configs.d.ts +26 -0
  6. package/dist/apis/admin/alter-configs.js +57 -0
  7. package/dist/apis/admin/alter-partition-reassignments.d.ts +30 -0
  8. package/dist/apis/admin/alter-partition-reassignments.js +68 -0
  9. package/dist/apis/admin/alter-partition.d.ts +39 -0
  10. package/dist/apis/admin/alter-partition.js +87 -0
  11. package/dist/apis/admin/alter-replica-log-dirs.d.ts +26 -0
  12. package/dist/apis/admin/alter-replica-log-dirs.js +55 -0
  13. package/dist/apis/admin/alter-user-scram-credentials.d.ts +27 -0
  14. package/dist/apis/admin/alter-user-scram-credentials.js +60 -0
  15. package/dist/apis/admin/consumer-group-describe.d.ts +41 -0
  16. package/dist/apis/admin/consumer-group-describe.js +103 -0
  17. package/dist/apis/admin/create-acls.d.ts +24 -0
  18. package/dist/apis/admin/create-acls.js +55 -0
  19. package/dist/apis/admin/create-delegation-token.d.ts +24 -0
  20. package/dist/apis/admin/create-delegation-token.js +54 -0
  21. package/dist/apis/admin/create-partitions.d.ts +24 -0
  22. package/dist/apis/admin/create-partitions.js +54 -0
  23. package/dist/apis/admin/create-topics.d.ts +42 -0
  24. package/dist/apis/admin/create-topics.js +86 -0
  25. package/dist/apis/admin/delete-acls.d.ts +36 -0
  26. package/dist/apis/admin/delete-acls.js +82 -0
  27. package/dist/apis/admin/delete-groups.d.ts +14 -0
  28. package/dist/apis/admin/delete-groups.js +40 -0
  29. package/dist/apis/admin/delete-records.d.ts +27 -0
  30. package/dist/apis/admin/delete-records.js +59 -0
  31. package/dist/apis/admin/delete-topics.d.ts +21 -0
  32. package/dist/apis/admin/delete-topics.js +50 -0
  33. package/dist/apis/admin/describe-acls.d.ts +25 -0
  34. package/dist/apis/admin/describe-acls.js +66 -0
  35. package/dist/apis/admin/describe-client-quotas.d.ts +30 -0
  36. package/dist/apis/admin/describe-client-quotas.js +57 -0
  37. package/dist/apis/admin/describe-cluster.d.ts +23 -0
  38. package/dist/apis/admin/describe-cluster.js +50 -0
  39. package/dist/apis/admin/describe-configs.d.ts +38 -0
  40. package/dist/apis/admin/describe-configs.js +85 -0
  41. package/dist/apis/admin/describe-delegation-token.d.ts +31 -0
  42. package/dist/apis/admin/describe-delegation-token.js +62 -0
  43. package/dist/apis/admin/describe-groups.d.ts +28 -0
  44. package/dist/apis/admin/describe-groups.js +67 -0
  45. package/dist/apis/admin/describe-log-dirs.d.ts +32 -0
  46. package/dist/apis/admin/describe-log-dirs.js +75 -0
  47. package/dist/apis/admin/describe-producers.d.ts +33 -0
  48. package/dist/apis/admin/describe-producers.js +70 -0
  49. package/dist/apis/admin/describe-quorum.d.ts +50 -0
  50. package/dist/apis/admin/describe-quorum.js +116 -0
  51. package/dist/apis/admin/describe-topic-partitions.d.ts +42 -0
  52. package/dist/apis/admin/describe-topic-partitions.js +94 -0
  53. package/dist/apis/admin/describe-transactions.d.ts +24 -0
  54. package/dist/apis/admin/describe-transactions.js +59 -0
  55. package/dist/apis/admin/describe-user-scram-credentials.d.ts +26 -0
  56. package/dist/apis/admin/describe-user-scram-credentials.js +62 -0
  57. package/dist/apis/admin/envelope.d.ts +10 -0
  58. package/dist/apis/admin/envelope.js +32 -0
  59. package/dist/apis/admin/expire-delegation-token.d.ts +11 -0
  60. package/dist/apis/admin/expire-delegation-token.js +29 -0
  61. package/dist/apis/admin/incremental-alter-configs.d.ts +27 -0
  62. package/dist/apis/admin/incremental-alter-configs.js +58 -0
  63. package/dist/apis/admin/index.d.ts +37 -0
  64. package/dist/apis/admin/index.js +37 -0
  65. package/dist/apis/admin/list-groups.d.ts +18 -0
  66. package/dist/apis/admin/list-groups.js +43 -0
  67. package/dist/apis/admin/list-partition-reassignments.d.ts +27 -0
  68. package/dist/apis/admin/list-partition-reassignments.js +56 -0
  69. package/dist/apis/admin/list-transactions.d.ts +18 -0
  70. package/dist/apis/admin/list-transactions.js +45 -0
  71. package/dist/apis/admin/offset-delete.d.ts +26 -0
  72. package/dist/apis/admin/offset-delete.js +59 -0
  73. package/dist/apis/admin/renew-delegation-token.d.ts +11 -0
  74. package/dist/apis/admin/renew-delegation-token.js +29 -0
  75. package/dist/apis/admin/unregister-broker.d.ts +12 -0
  76. package/dist/apis/admin/unregister-broker.js +28 -0
  77. package/dist/apis/admin/update-features.d.ts +23 -0
  78. package/dist/apis/admin/update-features.js +60 -0
  79. package/dist/apis/consumer/consumer-group-heartbeat.d.ts +27 -0
  80. package/dist/apis/consumer/consumer-group-heartbeat.js +70 -0
  81. package/dist/apis/consumer/fetch.d.ts +46 -0
  82. package/dist/apis/consumer/fetch.js +121 -0
  83. package/dist/apis/consumer/heartbeat.d.ts +11 -0
  84. package/dist/apis/consumer/heartbeat.js +34 -0
  85. package/dist/apis/consumer/index.d.ts +9 -0
  86. package/dist/apis/consumer/index.js +9 -0
  87. package/dist/apis/consumer/join-group.d.ts +27 -0
  88. package/dist/apis/consumer/join-group.js +71 -0
  89. package/dist/apis/consumer/leave-group.d.ts +22 -0
  90. package/dist/apis/consumer/leave-group.js +57 -0
  91. package/dist/apis/consumer/list-offsets.d.ts +30 -0
  92. package/dist/apis/consumer/list-offsets.js +68 -0
  93. package/dist/apis/consumer/offset-commit.d.ts +29 -0
  94. package/dist/apis/consumer/offset-commit.js +68 -0
  95. package/dist/apis/consumer/offset-fetch.d.ts +37 -0
  96. package/dist/apis/consumer/offset-fetch.js +81 -0
  97. package/dist/apis/consumer/sync-group.d.ts +18 -0
  98. package/dist/apis/consumer/sync-group.js +49 -0
  99. package/dist/apis/definitions.d.ts +16 -0
  100. package/dist/apis/definitions.js +12 -0
  101. package/dist/apis/enumerations.d.ts +114 -0
  102. package/dist/apis/enumerations.js +78 -0
  103. package/dist/apis/index.d.ts +8 -0
  104. package/dist/apis/index.js +10 -0
  105. package/dist/apis/metadata/api-versions.d.ts +17 -0
  106. package/dist/apis/metadata/api-versions.js +41 -0
  107. package/dist/apis/metadata/find-coordinator.d.ts +19 -0
  108. package/dist/apis/metadata/find-coordinator.js +50 -0
  109. package/dist/apis/metadata/index.d.ts +3 -0
  110. package/dist/apis/metadata/index.js +3 -0
  111. package/dist/apis/metadata/metadata.d.ts +37 -0
  112. package/dist/apis/metadata/metadata.js +92 -0
  113. package/dist/apis/producer/add-offsets-to-txn.d.ts +10 -0
  114. package/dist/apis/producer/add-offsets-to-txn.js +34 -0
  115. package/dist/apis/producer/add-partitions-to-txn.d.ts +34 -0
  116. package/dist/apis/producer/add-partitions-to-txn.js +79 -0
  117. package/dist/apis/producer/end-txn.d.ts +10 -0
  118. package/dist/apis/producer/end-txn.js +34 -0
  119. package/dist/apis/producer/index.d.ts +6 -0
  120. package/dist/apis/producer/index.js +6 -0
  121. package/dist/apis/producer/init-producer-id.d.ts +21 -0
  122. package/dist/apis/producer/init-producer-id.js +38 -0
  123. package/dist/apis/producer/produce.d.ts +29 -0
  124. package/dist/apis/producer/produce.js +104 -0
  125. package/dist/apis/producer/txn-offset-commit.d.ts +29 -0
  126. package/dist/apis/producer/txn-offset-commit.js +77 -0
  127. package/dist/apis/security/index.d.ts +2 -0
  128. package/dist/apis/security/index.js +2 -0
  129. package/dist/apis/security/sasl-authenticate.d.ts +15 -0
  130. package/dist/apis/security/sasl-authenticate.js +30 -0
  131. package/dist/apis/security/sasl-handshake.d.ts +10 -0
  132. package/dist/apis/security/sasl-handshake.js +28 -0
  133. package/dist/apis/telemetry/get-telemetry-subscriptions.d.ts +18 -0
  134. package/dist/apis/telemetry/get-telemetry-subscriptions.js +46 -0
  135. package/dist/apis/telemetry/index.d.ts +3 -0
  136. package/dist/apis/telemetry/index.js +3 -0
  137. package/dist/apis/telemetry/list-client-metrics-resources.d.ts +14 -0
  138. package/dist/apis/telemetry/list-client-metrics-resources.js +32 -0
  139. package/dist/apis/telemetry/push-telemetry.d.ts +10 -0
  140. package/dist/apis/telemetry/push-telemetry.js +36 -0
  141. package/dist/clients/admin/admin.d.ts +18 -0
  142. package/dist/clients/admin/admin.js +322 -0
  143. package/dist/clients/admin/index.d.ts +3 -0
  144. package/dist/clients/admin/index.js +3 -0
  145. package/dist/clients/admin/options.d.ts +135 -0
  146. package/dist/clients/admin/options.js +81 -0
  147. package/dist/clients/admin/types.d.ts +56 -0
  148. package/dist/clients/admin/types.js +1 -0
  149. package/dist/clients/base/base.d.ts +48 -0
  150. package/dist/clients/base/base.js +242 -0
  151. package/dist/clients/base/index.d.ts +3 -0
  152. package/dist/clients/base/index.js +3 -0
  153. package/dist/clients/base/options.d.ts +115 -0
  154. package/dist/clients/base/options.js +59 -0
  155. package/dist/clients/base/types.d.ts +38 -0
  156. package/dist/clients/base/types.js +1 -0
  157. package/dist/clients/callbacks.d.ts +8 -0
  158. package/dist/clients/callbacks.js +42 -0
  159. package/dist/clients/consumer/consumer.d.ts +33 -0
  160. package/dist/clients/consumer/consumer.js +767 -0
  161. package/dist/clients/consumer/index.d.ts +5 -0
  162. package/dist/clients/consumer/index.js +5 -0
  163. package/dist/clients/consumer/messages-stream.d.ts +56 -0
  164. package/dist/clients/consumer/messages-stream.js +404 -0
  165. package/dist/clients/consumer/options.d.ts +521 -0
  166. package/dist/clients/consumer/options.js +177 -0
  167. package/dist/clients/consumer/topics-map.d.ts +8 -0
  168. package/dist/clients/consumer/topics-map.js +48 -0
  169. package/dist/clients/consumer/types.d.ts +74 -0
  170. package/dist/clients/consumer/types.js +11 -0
  171. package/dist/clients/index.d.ts +6 -0
  172. package/dist/clients/index.js +6 -0
  173. package/dist/clients/producer/index.d.ts +3 -0
  174. package/dist/clients/producer/index.js +3 -0
  175. package/dist/clients/producer/options.d.ts +122 -0
  176. package/dist/clients/producer/options.js +47 -0
  177. package/dist/clients/producer/producer.d.ts +13 -0
  178. package/dist/clients/producer/producer.js +272 -0
  179. package/dist/clients/producer/types.d.ts +29 -0
  180. package/dist/clients/producer/types.js +1 -0
  181. package/dist/clients/serde.d.ts +40 -0
  182. package/dist/clients/serde.js +49 -0
  183. package/dist/errors.d.ts +67 -0
  184. package/dist/errors.js +160 -0
  185. package/dist/index.d.ts +6 -0
  186. package/dist/index.js +10 -0
  187. package/dist/network/connection-pool.d.ts +11 -0
  188. package/dist/network/connection-pool.js +101 -0
  189. package/dist/network/connection.d.ts +49 -0
  190. package/dist/network/connection.js +319 -0
  191. package/dist/network/index.d.ts +2 -0
  192. package/dist/network/index.js +2 -0
  193. package/dist/protocol/apis.d.ts +2 -0
  194. package/dist/protocol/apis.js +191 -0
  195. package/dist/protocol/compression.d.ts +70 -0
  196. package/dist/protocol/compression.js +114 -0
  197. package/dist/protocol/crc32c.d.ts +2 -0
  198. package/dist/protocol/crc32c.js +83 -0
  199. package/dist/protocol/definitions.d.ts +12 -0
  200. package/dist/protocol/definitions.js +11 -0
  201. package/dist/protocol/dynamic-buffer.d.ts +65 -0
  202. package/dist/protocol/dynamic-buffer.js +557 -0
  203. package/dist/protocol/errors.d.ts +8 -0
  204. package/dist/protocol/errors.js +908 -0
  205. package/dist/protocol/index.d.ts +14 -0
  206. package/dist/protocol/index.js +14 -0
  207. package/dist/protocol/murmur2.d.ts +1 -0
  208. package/dist/protocol/murmur2.js +55 -0
  209. package/dist/protocol/reader.d.ts +58 -0
  210. package/dist/protocol/reader.js +296 -0
  211. package/dist/protocol/records.d.ts +110 -0
  212. package/dist/protocol/records.js +149 -0
  213. package/dist/protocol/sasl/plain.d.ts +3 -0
  214. package/dist/protocol/sasl/plain.js +3 -0
  215. package/dist/protocol/sasl/scram-sha.d.ts +28 -0
  216. package/dist/protocol/sasl/scram-sha.js +104 -0
  217. package/dist/protocol/varint.d.ts +12 -0
  218. package/dist/protocol/varint.js +36 -0
  219. package/dist/protocol/writer.d.ts +48 -0
  220. package/dist/protocol/writer.js +223 -0
  221. package/dist/utils.d.ts +20 -0
  222. package/dist/utils.js +127 -0
  223. package/package.json +75 -0
@@ -0,0 +1,48 @@
1
+ export class TopicsMap extends Map {
2
+ #current = [];
3
+ get current() {
4
+ return this.#current;
5
+ }
6
+ track(topic) {
7
+ let updated = false;
8
+ let existing = this.get(topic);
9
+ if (typeof existing === 'undefined') {
10
+ existing = 0;
11
+ updated = true;
12
+ }
13
+ this.set(topic, existing + 1);
14
+ if (updated) {
15
+ this.#updateCurrentList();
16
+ }
17
+ return updated;
18
+ }
19
+ trackAll(...topics) {
20
+ const updated = [];
21
+ for (const topic of topics.flat()) {
22
+ updated.push(this.track(topic));
23
+ }
24
+ return updated;
25
+ }
26
+ untrack(topic) {
27
+ const existing = this.get(topic);
28
+ if (existing === 1) {
29
+ this.delete(topic);
30
+ this.#updateCurrentList();
31
+ return true;
32
+ }
33
+ else if (typeof existing === 'number') {
34
+ this.set(topic, existing - 1);
35
+ }
36
+ return false;
37
+ }
38
+ untrackAll(...topics) {
39
+ const updated = [];
40
+ for (const topic of topics.flat()) {
41
+ updated.push(this.untrack(topic));
42
+ }
43
+ return updated;
44
+ }
45
+ #updateCurrentList() {
46
+ this.#current = Array.from(this.keys());
47
+ }
48
+ }
@@ -0,0 +1,74 @@
1
+ import { type FetchRequestTopic } from '../../apis/consumer/fetch.ts';
2
+ import { type FetchIsolationLevel } from '../../apis/enumerations.ts';
3
+ import { type BaseOptions, type TopicWithPartitionAndOffset } from '../base/types.ts';
4
+ import { type Deserializers } from '../serde.ts';
5
+ export interface GroupProtocolSubscription {
6
+ name: string;
7
+ version: number;
8
+ metadata?: Buffer | string;
9
+ }
10
+ export interface GroupAssignment {
11
+ topic: string;
12
+ partitions: number[];
13
+ }
14
+ export interface ExtendedGroupProtocolSubscription extends Omit<GroupProtocolSubscription, 'name'> {
15
+ topics?: string[];
16
+ memberId: string;
17
+ }
18
+ export type Offsets = Map<string, bigint[]>;
19
+ export declare const MessagesStreamModes: {
20
+ readonly LATEST: "latest";
21
+ readonly EARLIEST: "earliest";
22
+ readonly COMMITTED: "committed";
23
+ readonly MANUAL: "manual";
24
+ };
25
+ export type MessagesStreamMode = keyof typeof MessagesStreamModes;
26
+ export declare const MessagesStreamFallbackModes: {
27
+ readonly LATEST: "latest";
28
+ readonly EARLIEST: "earliest";
29
+ readonly FAIL: "fail";
30
+ };
31
+ export type MessagesStreamFallbackMode = keyof typeof MessagesStreamFallbackModes;
32
+ export interface GroupOptions {
33
+ sessionTimeout?: number;
34
+ rebalanceTimeout?: number;
35
+ heartbeatInterval?: number;
36
+ protocols?: GroupProtocolSubscription[];
37
+ }
38
+ export interface ConsumeBaseOptions<Key, Value, HeaderKey, HeaderValue> {
39
+ autocommit?: boolean | number;
40
+ minBytes?: number;
41
+ maxBytes?: number;
42
+ maxWaitTime?: number;
43
+ isolationLevel?: FetchIsolationLevel;
44
+ deserializers?: Partial<Deserializers<Key, Value, HeaderKey, HeaderValue>>;
45
+ highWaterMark?: number;
46
+ }
47
+ export interface StreamOptions {
48
+ topics: string[];
49
+ mode?: string;
50
+ fallbackMode?: string;
51
+ offsets?: TopicWithPartitionAndOffset[];
52
+ }
53
+ export type ConsumeOptions<Key, Value, HeaderKey, HeaderValue> = StreamOptions & ConsumeBaseOptions<Key, Value, HeaderKey, HeaderValue> & GroupOptions;
54
+ export type ConsumerOptions<Key, Value, HeaderKey, HeaderValue> = BaseOptions & {
55
+ groupId: string;
56
+ } & GroupOptions & ConsumeBaseOptions<Key, Value, HeaderKey, HeaderValue>;
57
+ export type FetchOptions<Key, Value, HeaderKey, HeaderValue> = Omit<ConsumeBaseOptions<Key, Value, HeaderKey, HeaderValue>, 'deserializers'> & GroupOptions & {
58
+ node: number;
59
+ topics: FetchRequestTopic[];
60
+ };
61
+ export interface CommitOptionsPartition extends TopicWithPartitionAndOffset {
62
+ leaderEpoch: number;
63
+ }
64
+ export interface CommitOptions {
65
+ offsets: CommitOptionsPartition[];
66
+ }
67
+ export interface ListCommitsOptions {
68
+ topics: GroupAssignment[];
69
+ }
70
+ export interface ListOffsetsOptions {
71
+ topics: string[];
72
+ timestamp?: bigint;
73
+ isolationLevel?: FetchIsolationLevel;
74
+ }
@@ -0,0 +1,11 @@
1
+ export const MessagesStreamModes = {
2
+ LATEST: 'latest',
3
+ EARLIEST: 'earliest',
4
+ COMMITTED: 'committed',
5
+ MANUAL: 'manual'
6
+ };
7
+ export const MessagesStreamFallbackModes = {
8
+ LATEST: 'latest',
9
+ EARLIEST: 'earliest',
10
+ FAIL: 'fail'
11
+ };
@@ -0,0 +1,6 @@
1
+ export * from './callbacks.ts';
2
+ export * from './serde.ts';
3
+ export * from './admin/index.ts';
4
+ export * from './base/index.ts';
5
+ export * from './consumer/index.ts';
6
+ export * from './producer/index.ts';
@@ -0,0 +1,6 @@
1
+ export * from "./callbacks.js";
2
+ export * from "./serde.js";
3
+ export * from "./admin/index.js";
4
+ export * from "./base/index.js";
5
+ export * from "./consumer/index.js";
6
+ export * from "./producer/index.js";
@@ -0,0 +1,3 @@
1
+ export * from './options.ts';
2
+ export * from './producer.ts';
3
+ export * from './types.ts';
@@ -0,0 +1,3 @@
1
+ export * from "./options.js";
2
+ export * from "./producer.js";
3
+ export * from "./types.js";
@@ -0,0 +1,122 @@
1
+ export declare const produceOptionsSchema: {
2
+ type: string;
3
+ properties: {
4
+ producerId: {
5
+ bigint: boolean;
6
+ };
7
+ producerEpoch: {
8
+ type: string;
9
+ };
10
+ idempotent: {
11
+ type: string;
12
+ };
13
+ acks: {
14
+ type: string;
15
+ enum: (0 | 1 | -1)[];
16
+ errorMessage: string;
17
+ };
18
+ compression: {
19
+ type: string;
20
+ enum: string[];
21
+ errorMessage: string;
22
+ };
23
+ partitioner: {
24
+ function: boolean;
25
+ };
26
+ autocreateTopics: {
27
+ type: string;
28
+ };
29
+ repeatOnStaleMetadata: {
30
+ type: string;
31
+ };
32
+ };
33
+ additionalProperties: boolean;
34
+ };
35
+ export declare const produceOptionsValidator: import("ajv").ValidateFunction<unknown>;
36
+ export declare const producerOptionsValidator: import("ajv").ValidateFunction<unknown>;
37
+ export declare const sendOptionsSchema: {
38
+ type: string;
39
+ properties: {
40
+ producerId: {
41
+ bigint: boolean;
42
+ };
43
+ producerEpoch: {
44
+ type: string;
45
+ };
46
+ idempotent: {
47
+ type: string;
48
+ };
49
+ acks: {
50
+ type: string;
51
+ enum: (0 | 1 | -1)[];
52
+ errorMessage: string;
53
+ };
54
+ compression: {
55
+ type: string;
56
+ enum: string[];
57
+ errorMessage: string;
58
+ };
59
+ partitioner: {
60
+ function: boolean;
61
+ };
62
+ autocreateTopics: {
63
+ type: string;
64
+ };
65
+ repeatOnStaleMetadata: {
66
+ type: string;
67
+ };
68
+ messages: {
69
+ type: string;
70
+ items: {
71
+ type: string;
72
+ properties: {
73
+ key: {
74
+ oneOf: ({
75
+ type: string;
76
+ buffer?: undefined;
77
+ } | {
78
+ buffer: boolean;
79
+ type?: undefined;
80
+ })[];
81
+ };
82
+ value: {
83
+ oneOf: ({
84
+ type: string;
85
+ buffer?: undefined;
86
+ } | {
87
+ buffer: boolean;
88
+ type?: undefined;
89
+ })[];
90
+ };
91
+ headers: {
92
+ anyOf: ({
93
+ map: boolean;
94
+ type?: undefined;
95
+ additionalProperties?: undefined;
96
+ } | {
97
+ type: string;
98
+ additionalProperties: boolean;
99
+ map?: undefined;
100
+ })[];
101
+ };
102
+ topic: {
103
+ type: string;
104
+ };
105
+ partition: {
106
+ type: string;
107
+ };
108
+ timestamp: {
109
+ bigint: boolean;
110
+ };
111
+ };
112
+ required: string[];
113
+ additionalProperties: boolean;
114
+ };
115
+ };
116
+ };
117
+ required: string[];
118
+ additionalProperties: boolean;
119
+ };
120
+ export declare const sendOptionsValidator: import("ajv").ValidateFunction<{
121
+ [x: string]: {};
122
+ }>;
@@ -0,0 +1,47 @@
1
+ import { ProduceAcks } from "../../apis/enumerations.js";
2
+ import { compressionsAlgorithms } from "../../protocol/compression.js";
3
+ import { messageSchema } from "../../protocol/records.js";
4
+ import { ajv, enumErrorMessage } from "../../utils.js";
5
+ import { serdeProperties } from "../serde.js";
6
+ const produceOptionsProperties = {
7
+ producerId: { bigint: true },
8
+ producerEpoch: { type: 'number' },
9
+ idempotent: { type: 'boolean' },
10
+ acks: {
11
+ type: 'number',
12
+ enum: Object.values(ProduceAcks),
13
+ errorMessage: enumErrorMessage(ProduceAcks)
14
+ },
15
+ compression: {
16
+ type: 'string',
17
+ enum: Object.keys(compressionsAlgorithms),
18
+ errorMessage: enumErrorMessage(compressionsAlgorithms, true)
19
+ },
20
+ partitioner: { function: true },
21
+ autocreateTopics: { type: 'boolean' },
22
+ repeatOnStaleMetadata: { type: 'boolean' }
23
+ };
24
+ export const produceOptionsSchema = {
25
+ type: 'object',
26
+ properties: produceOptionsProperties,
27
+ additionalProperties: false
28
+ };
29
+ export const produceOptionsValidator = ajv.compile(produceOptionsSchema);
30
+ export const producerOptionsValidator = ajv.compile({
31
+ type: 'object',
32
+ properties: {
33
+ ...produceOptionsProperties,
34
+ serializers: serdeProperties
35
+ },
36
+ additionalProperties: true
37
+ });
38
+ export const sendOptionsSchema = {
39
+ type: 'object',
40
+ properties: {
41
+ messages: { type: 'array', items: messageSchema },
42
+ ...produceOptionsProperties
43
+ },
44
+ required: ['messages'],
45
+ additionalProperties: false
46
+ };
47
+ export const sendOptionsValidator = ajv.compile(sendOptionsSchema);
@@ -0,0 +1,13 @@
1
+ import { Base } from '../base/base.ts';
2
+ import { type CallbackWithPromise } from '../callbacks.ts';
3
+ import { type ProduceOptions, type ProduceResult, type ProducerInfo, type ProducerOptions, type SendOptions } from './types.ts';
4
+ export declare class Producer<Key = Buffer, Value = Buffer, HeaderKey = Buffer, HeaderValue = Buffer> extends Base<ProducerOptions<Key, Value, HeaderKey, HeaderValue>> {
5
+ #private;
6
+ constructor(options: ProducerOptions<Key, Value, HeaderKey, HeaderValue>);
7
+ get producerId(): bigint | undefined;
8
+ get producerEpoch(): number | undefined;
9
+ initIdempotentProducer(options: ProduceOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<ProducerInfo>): void;
10
+ initIdempotentProducer(options: ProduceOptions<Key, Value, HeaderKey, HeaderValue>): Promise<ProducerInfo>;
11
+ send(options: SendOptions<Key, Value, HeaderKey, HeaderValue>, callback: CallbackWithPromise<ProduceResult>): void;
12
+ send(options: SendOptions<Key, Value, HeaderKey, HeaderValue>): Promise<ProduceResult>;
13
+ }
@@ -0,0 +1,272 @@
1
+ import { ProduceAcks } from "../../apis/enumerations.js";
2
+ import { api as initProducerIdV5 } from "../../apis/producer/init-producer-id.js";
3
+ import { api as produceV11 } from "../../apis/producer/produce.js";
4
+ import { UserError } from "../../errors.js";
5
+ import { murmur2 } from "../../protocol/murmur2.js";
6
+ import { NumericMap } from "../../utils.js";
7
+ import { Base, kBootstrapBrokers, kCheckNotClosed, kClearMetadata, kConnections, kMetadata, kOptions, kPerformDeduplicated, kPerformWithRetry, kValidateOptions } from "../base/base.js";
8
+ import { createPromisifiedCallback, kCallbackPromise, runConcurrentCallbacks } from "../callbacks.js";
9
+ import { produceOptionsValidator, producerOptionsValidator, sendOptionsValidator } from "./options.js";
10
+ // Don't move this function as being in the same file will enable V8 to remove.
11
+ // For futher info, ask Matteo.
12
+ function noopSerializer(data) {
13
+ return data;
14
+ }
15
+ export class Producer extends Base {
16
+ #partitionsRoundRobin;
17
+ // These two values should be serializable and loadable in the constructor in order to restore
18
+ // the idempotent producer status.
19
+ #producerInfo;
20
+ #sequences;
21
+ #keySerializer;
22
+ #valueSerializer;
23
+ #headerKeySerializer;
24
+ #headerValueSerializer;
25
+ constructor(options) {
26
+ if (options.idempotent) {
27
+ options.maxInflights = 1;
28
+ options.acks = ProduceAcks.ALL;
29
+ options.retries = Number.MAX_SAFE_INTEGER;
30
+ }
31
+ options.repeatOnStaleMetadata ??= true;
32
+ super(options);
33
+ this.#partitionsRoundRobin = new NumericMap();
34
+ this.#sequences = new NumericMap();
35
+ this.#keySerializer = options.serializers?.key ?? noopSerializer;
36
+ this.#valueSerializer = options.serializers?.value ?? noopSerializer;
37
+ this.#headerKeySerializer = options.serializers?.headerKey ?? noopSerializer;
38
+ this.#headerValueSerializer = options.serializers?.headerValue ?? noopSerializer;
39
+ this[kValidateOptions](options, producerOptionsValidator, '/options');
40
+ }
41
+ get producerId() {
42
+ return this.#producerInfo?.producerId;
43
+ }
44
+ get producerEpoch() {
45
+ return this.#producerInfo?.producerEpoch;
46
+ }
47
+ initIdempotentProducer(options, callback) {
48
+ if (!callback) {
49
+ callback = createPromisifiedCallback();
50
+ }
51
+ if (this[kCheckNotClosed](callback)) {
52
+ return callback[kCallbackPromise];
53
+ }
54
+ const validationError = this[kValidateOptions](options, produceOptionsValidator, '/options', false);
55
+ if (validationError) {
56
+ callback(validationError, undefined);
57
+ return callback[kCallbackPromise];
58
+ }
59
+ return this[kPerformDeduplicated]('initProducerId', deduplicateCallback => {
60
+ this[kPerformWithRetry]('initProducerId', retryCallback => {
61
+ this[kConnections].getFirstAvailable(this[kBootstrapBrokers], (error, connection) => {
62
+ if (error) {
63
+ callback(error, undefined);
64
+ return;
65
+ }
66
+ initProducerIdV5(connection, null, this[kOptions].timeout, options.producerId ?? this[kOptions].producerId ?? 0n, options.producerEpoch ?? this[kOptions].producerEpoch ?? 0, retryCallback);
67
+ });
68
+ }, (error, response) => {
69
+ if (error) {
70
+ callback(error, undefined);
71
+ return;
72
+ }
73
+ this.#producerInfo = { producerId: response.producerId, producerEpoch: response.producerEpoch };
74
+ deduplicateCallback(null, this.#producerInfo);
75
+ }, 0);
76
+ }, callback);
77
+ }
78
+ send(options, callback) {
79
+ if (!callback) {
80
+ callback = createPromisifiedCallback();
81
+ }
82
+ if (this[kCheckNotClosed](callback)) {
83
+ return callback[kCallbackPromise];
84
+ }
85
+ const validationError = this[kValidateOptions](options, sendOptionsValidator, '/options', false);
86
+ if (validationError) {
87
+ callback(validationError, undefined);
88
+ return callback[kCallbackPromise];
89
+ }
90
+ options.idempotent ??= this[kOptions].idempotent ?? false;
91
+ /* c8 ignore next */
92
+ options.repeatOnStaleMetadata ??= this[kOptions].repeatOnStaleMetadata ?? true;
93
+ options.partitioner ??= this[kOptions].partitioner;
94
+ const { idempotent, partitioner } = options;
95
+ if (idempotent) {
96
+ options.acks ??= ProduceAcks.ALL;
97
+ }
98
+ else {
99
+ options.acks ??= ProduceAcks.LEADER;
100
+ }
101
+ // We still need to initialize the producerId
102
+ if (idempotent) {
103
+ if (!this.#producerInfo) {
104
+ const { messages, ...initOptions } = options;
105
+ this.initIdempotentProducer(initOptions, error => {
106
+ if (error) {
107
+ callback(error, undefined);
108
+ return;
109
+ }
110
+ this.send(options, callback);
111
+ });
112
+ return callback[kCallbackPromise];
113
+ }
114
+ if (typeof options.producerId !== 'undefined' || typeof options.producerEpoch !== 'undefined') {
115
+ callback(new UserError('Cannot specify producerId or producerEpoch when using idempotent producer.'), undefined);
116
+ return callback[kCallbackPromise];
117
+ }
118
+ if (options.acks !== ProduceAcks.ALL) {
119
+ callback(new UserError('Idempotent producer requires acks to be ALL (-1).'), undefined);
120
+ return callback[kCallbackPromise];
121
+ }
122
+ }
123
+ const produceOptions = {
124
+ compression: options.compression ?? this[kOptions].compression,
125
+ producerId: idempotent ? this.#producerInfo.producerId : options.producerId,
126
+ producerEpoch: idempotent ? this.#producerInfo.producerEpoch : options.producerEpoch,
127
+ sequences: idempotent ? this.#sequences : undefined
128
+ };
129
+ // Build messages records out of messages
130
+ const topics = new Set();
131
+ const messages = [];
132
+ for (const message of options.messages) {
133
+ const topic = message.topic;
134
+ const key = this.#keySerializer(message.key);
135
+ const headers = new Map();
136
+ let partition = 0;
137
+ if (typeof message.partition !== 'number') {
138
+ if (partitioner) {
139
+ partition = partitioner(message);
140
+ }
141
+ else if (key) {
142
+ partition = murmur2(key) >>> 0;
143
+ }
144
+ else {
145
+ // Use the roundrobin
146
+ partition = this.#partitionsRoundRobin.postIncrement(topic, 1, -1);
147
+ }
148
+ }
149
+ else {
150
+ partition = message.partition;
151
+ }
152
+ if (message.headers) {
153
+ const entries = message.headers instanceof Map ? message.headers : Object.entries(message.headers);
154
+ for (const [key, value] of entries) {
155
+ headers.set(this.#headerKeySerializer(key), this.#headerValueSerializer(value));
156
+ }
157
+ }
158
+ topics.add(topic);
159
+ messages.push({
160
+ key,
161
+ value: this.#valueSerializer(message.value),
162
+ headers,
163
+ topic,
164
+ partition,
165
+ timestamp: message.timestamp
166
+ });
167
+ }
168
+ this.#performSend(Array.from(topics), messages, options, produceOptions, callback);
169
+ return callback[kCallbackPromise];
170
+ }
171
+ #performSend(topics, messages, sendOptions, produceOptions, callback) {
172
+ // Get the metadata with the topic/partitions informations
173
+ this[kMetadata]({ topics, autocreateTopics: sendOptions.autocreateTopics }, (error, metadata) => {
174
+ if (error) {
175
+ callback(error, undefined);
176
+ return;
177
+ }
178
+ const messagesByDestination = new Map();
179
+ // Track the number of messages per partition so we can update the sequence number
180
+ const messagesPerPartition = new NumericMap();
181
+ // Normalize the partition of all messages, then enqueue them to their destination
182
+ for (const message of messages) {
183
+ message.partition %= metadata.topics.get(message.topic).partitionsCount;
184
+ const { topic, partition } = message;
185
+ const leader = metadata.topics.get(topic).partitions[partition].leader;
186
+ let destination = messagesByDestination.get(leader);
187
+ if (!destination) {
188
+ destination = [];
189
+ messagesByDestination.set(leader, destination);
190
+ }
191
+ const messagePartitionKey = `${message.topic}:${partition}`;
192
+ messagesPerPartition.postIncrement(messagePartitionKey, 1, 0);
193
+ destination.push(message);
194
+ }
195
+ // Track nodes so that we can get their ID for delayed write reporting
196
+ const nodes = [];
197
+ runConcurrentCallbacks('Producing messages failed.', messagesByDestination, ([destination, messages], concurrentCallback) => {
198
+ nodes.push(destination);
199
+ this.#performSingleDestinationSend(topics, messages, this[kOptions].timeout, sendOptions.acks, sendOptions.autocreateTopics, sendOptions.repeatOnStaleMetadata, produceOptions, concurrentCallback);
200
+ }, (error, apiResults) => {
201
+ if (error) {
202
+ callback(error, undefined);
203
+ return;
204
+ }
205
+ const results = {};
206
+ if (sendOptions.acks === ProduceAcks.NO_RESPONSE) {
207
+ const unwritableNodes = [];
208
+ for (let i = 0; i < apiResults.length; i++) {
209
+ if (apiResults[i] === false) {
210
+ unwritableNodes.push(nodes[i]);
211
+ }
212
+ }
213
+ results.unwritableNodes = unwritableNodes;
214
+ }
215
+ else {
216
+ const topics = [];
217
+ for (const result of apiResults) {
218
+ for (const { name, partitionResponses } of result.responses) {
219
+ for (const partitionResponse of partitionResponses) {
220
+ topics.push({
221
+ topic: name,
222
+ partition: partitionResponse.index,
223
+ offset: partitionResponse.baseOffset
224
+ });
225
+ const partitionKey = `${name}:${partitionResponse.index}`;
226
+ this.#sequences.postIncrement(partitionKey, messagesPerPartition.get(partitionKey), 0);
227
+ }
228
+ }
229
+ results.offsets = topics;
230
+ }
231
+ }
232
+ callback(null, results);
233
+ });
234
+ });
235
+ }
236
+ #performSingleDestinationSend(topics, messages, timeout, acks, autocreateTopics, repeatOnStaleMetadata, produceOptions, callback) {
237
+ // Get the metadata with the topic/partitions informations
238
+ this[kMetadata]({ topics, autocreateTopics }, (error, metadata) => {
239
+ if (error) {
240
+ callback(error, undefined);
241
+ return;
242
+ }
243
+ const { topic, partition } = messages[0];
244
+ const leader = metadata.topics.get(topic).partitions[partition].leader;
245
+ this[kPerformWithRetry]('produce', retryCallback => {
246
+ this[kConnections].get(metadata.brokers.get(leader), (error, connection) => {
247
+ if (error) {
248
+ retryCallback(error, undefined);
249
+ return;
250
+ }
251
+ produceV11(connection, acks, timeout, messages, produceOptions, retryCallback);
252
+ });
253
+ }, (error, results) => {
254
+ if (error) {
255
+ // If the last error was due to stale metadata, we retry the operation with this set of messages
256
+ // since the partition is already set, it should attempt on the new destination
257
+ const hasStaleMetadata = error.findBy('hasStaleMetadata', true);
258
+ if (hasStaleMetadata && repeatOnStaleMetadata) {
259
+ this[kClearMetadata]();
260
+ this.#performSingleDestinationSend(topics, messages, timeout, acks, autocreateTopics, false, produceOptions, callback);
261
+ return;
262
+ }
263
+ callback(error, undefined);
264
+ return;
265
+ }
266
+ callback(error, results);
267
+ }, 0, [], (error) => {
268
+ return repeatOnStaleMetadata && !!error.findBy('hasStaleMetadata', true);
269
+ });
270
+ });
271
+ }
272
+ }
@@ -0,0 +1,29 @@
1
+ import { type CompressionAlgorithms } from '../../protocol/compression.ts';
2
+ import { type MessageToProduce } from '../../protocol/records.ts';
3
+ import { type BaseOptions, type TopicWithPartitionAndOffset } from '../base/types.ts';
4
+ import { type Serializers } from '../serde.ts';
5
+ export interface ProducerInfo {
6
+ producerId: bigint;
7
+ producerEpoch: number;
8
+ }
9
+ export interface ProduceResult {
10
+ offsets?: TopicWithPartitionAndOffset[];
11
+ unwritableNodes?: number[];
12
+ }
13
+ export type Partitioner<Key, Value, HeaderKey, HeaderValue> = (message: MessageToProduce<Key, Value, HeaderKey, HeaderValue>) => number;
14
+ export interface ProduceOptions<Key, Value, HeaderKey, HeaderValue> {
15
+ producerId?: bigint;
16
+ producerEpoch?: number;
17
+ idempotent?: boolean;
18
+ acks?: number;
19
+ compression?: CompressionAlgorithms;
20
+ partitioner?: Partitioner<Key, Value, HeaderKey, HeaderValue>;
21
+ autocreateTopics?: boolean;
22
+ repeatOnStaleMetadata?: boolean;
23
+ }
24
+ export type ProducerOptions<Key, Value, HeaderKey, HeaderValue> = BaseOptions & ProduceOptions<Key, Value, HeaderKey, HeaderValue> & {
25
+ serializers?: Partial<Serializers<Key, Value, HeaderKey, HeaderValue>>;
26
+ };
27
+ export type SendOptions<Key, Value, HeaderKey, HeaderValue> = {
28
+ messages: MessageToProduce<Key, Value, HeaderKey, HeaderValue>[];
29
+ } & ProduceOptions<Key, Value, HeaderKey, HeaderValue>;
@@ -0,0 +1 @@
1
+ export {};