@platformatic/kafka 2.4.0 → 2.6.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.
|
@@ -50,6 +50,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
50
50
|
#responseReader;
|
|
51
51
|
#socket;
|
|
52
52
|
#socketMustBeDrained;
|
|
53
|
+
#detectMissingTLS;
|
|
53
54
|
#reauthenticationTimeout;
|
|
54
55
|
constructor(clientId, options = {}) {
|
|
55
56
|
super();
|
|
@@ -75,6 +76,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
75
76
|
this.#responseBuffer = new DynamicBuffer();
|
|
76
77
|
this.#responseReader = new Reader(this.#responseBuffer);
|
|
77
78
|
this.#socketMustBeDrained = false;
|
|
79
|
+
this.#detectMissingTLS = !this.#options.tls;
|
|
78
80
|
notifyCreation('connection', this);
|
|
79
81
|
}
|
|
80
82
|
/* c8 ignore next 3 - Simple getter */
|
|
@@ -120,6 +122,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
120
122
|
return callback[kCallbackPromise];
|
|
121
123
|
}
|
|
122
124
|
this.#status = ConnectionStatuses.CONNECTING;
|
|
125
|
+
this.#detectMissingTLS = !this.#options.tls;
|
|
123
126
|
const connectionOptions = {
|
|
124
127
|
timeout: this.#options.connectTimeout
|
|
125
128
|
};
|
|
@@ -259,7 +262,7 @@ export class Connection extends TypedEventEmitter {
|
|
|
259
262
|
}
|
|
260
263
|
send(apiKey, apiVersion, createPayload, responseParser, hasRequestHeaderTaggedFields, hasResponseHeaderTaggedFields, callback) {
|
|
261
264
|
// Correlation ID is a 32-bit integer in the protocol, so we need to wrap around after 2^31 - 1
|
|
262
|
-
const correlationId = (this.#correlationId + 1) &
|
|
265
|
+
const correlationId = (this.#correlationId + 1) & 0x7fffffff;
|
|
263
266
|
this.#correlationId = correlationId;
|
|
264
267
|
const diagnostic = createDiagnosticContext({
|
|
265
268
|
connection: this,
|
|
@@ -467,6 +470,27 @@ export class Connection extends TypedEventEmitter {
|
|
|
467
470
|
correlation_id => INT32
|
|
468
471
|
*/
|
|
469
472
|
#onData(chunk) {
|
|
473
|
+
if (this.#detectMissingTLS) {
|
|
474
|
+
this.#detectMissingTLS = false;
|
|
475
|
+
if (this.#isTLSRecord(chunk)) {
|
|
476
|
+
const error = new UserError('Broker requires TLS.');
|
|
477
|
+
this.#status = ConnectionStatuses.ERROR;
|
|
478
|
+
for (const request of this.#afterDrainRequests) {
|
|
479
|
+
if (!request.noResponse) {
|
|
480
|
+
clearTimeout(request.timeoutHandle);
|
|
481
|
+
request.callback(error, undefined);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
this.#afterDrainRequests = [];
|
|
485
|
+
for (const request of this.#inflightRequests.values()) {
|
|
486
|
+
clearTimeout(request.timeoutHandle);
|
|
487
|
+
request.callback(error, undefined);
|
|
488
|
+
}
|
|
489
|
+
this.#inflightRequests.clear();
|
|
490
|
+
this.#socket.destroy();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
470
494
|
this.#responseBuffer.append(chunk);
|
|
471
495
|
// There is at least one message size to add
|
|
472
496
|
// Note that here the initial position is always 0
|
|
@@ -547,6 +571,12 @@ export class Connection extends TypedEventEmitter {
|
|
|
547
571
|
this.#socketMustBeDrained = false;
|
|
548
572
|
this.emit('drain');
|
|
549
573
|
}
|
|
574
|
+
#isTLSRecord(chunk) {
|
|
575
|
+
return (chunk.length >= 3 &&
|
|
576
|
+
(chunk[0] === 0x14 || chunk[0] === 0x15 || chunk[0] === 0x16 || chunk[0] === 0x17) &&
|
|
577
|
+
chunk[1] === 0x03 &&
|
|
578
|
+
chunk[2] <= 0x04);
|
|
579
|
+
}
|
|
550
580
|
#onClose() {
|
|
551
581
|
this.#status = ConnectionStatuses.CLOSED;
|
|
552
582
|
this.emit('close');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ValidateFunction } from 'ajv';
|
|
1
|
+
import { type Options, type ValidateFunction } from 'ajv';
|
|
2
2
|
import { type Type } from 'avsc';
|
|
3
3
|
import { type Root } from 'protobufjs';
|
|
4
4
|
import { type Callback } from '../apis/definitions.ts';
|
|
@@ -20,6 +20,7 @@ export interface ConfluentSchemaRegistryOptions {
|
|
|
20
20
|
};
|
|
21
21
|
protobufTypeMapper?: ConfluentSchemaRegistryProtobufTypeMapper;
|
|
22
22
|
jsonValidateSend?: boolean;
|
|
23
|
+
jsonAjvOptions?: Options;
|
|
23
24
|
}
|
|
24
25
|
export interface Schema {
|
|
25
26
|
id: number;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
1
2
|
import avro from 'avsc';
|
|
2
3
|
import { createRequire } from 'node:module';
|
|
3
4
|
import { jsonDeserializer, jsonSerializer, stringDeserializer, stringSerializer } from "../clients/serde.js";
|
|
4
|
-
import {
|
|
5
|
+
import { EMPTY_BUFFER, UnsupportedFormatError, UserError } from "../index.js";
|
|
5
6
|
import { getCredential } from "../protocol/sasl/utils.js";
|
|
6
7
|
import { AbstractSchemaRegistry } from "./abstract.js";
|
|
7
8
|
const require = createRequire(import.meta.url);
|
|
@@ -17,6 +18,7 @@ export class ConfluentSchemaRegistry extends AbstractSchemaRegistry {
|
|
|
17
18
|
#protobufParse;
|
|
18
19
|
#protobufTypeMapper;
|
|
19
20
|
#jsonValidateSend;
|
|
21
|
+
#jsonAjv;
|
|
20
22
|
#auth;
|
|
21
23
|
constructor(options) {
|
|
22
24
|
super();
|
|
@@ -24,6 +26,7 @@ export class ConfluentSchemaRegistry extends AbstractSchemaRegistry {
|
|
|
24
26
|
this.#schemas = new Map();
|
|
25
27
|
this.#protobufTypeMapper = options.protobufTypeMapper ?? defaultProtobufTypeMapper;
|
|
26
28
|
this.#jsonValidateSend = options.jsonValidateSend ?? false;
|
|
29
|
+
this.#jsonAjv = new Ajv2020({ allErrors: true, coerceTypes: false, strict: true, ...options.jsonAjvOptions });
|
|
27
30
|
this.#auth = options.auth;
|
|
28
31
|
}
|
|
29
32
|
getSchemaId(message, type) {
|
|
@@ -75,7 +78,7 @@ export class ConfluentSchemaRegistry extends AbstractSchemaRegistry {
|
|
|
75
78
|
this.#schemas.set(id, { id, type: 'protobuf', schema: this.#protobufParse(schema).root });
|
|
76
79
|
break;
|
|
77
80
|
case 'JSON':
|
|
78
|
-
this.#schemas.set(id, { id, type: 'json', schema:
|
|
81
|
+
this.#schemas.set(id, { id, type: 'json', schema: this.#jsonAjv.compile(JSON.parse(schema)) });
|
|
79
82
|
break;
|
|
80
83
|
}
|
|
81
84
|
process.nextTick(callback);
|
|
@@ -169,7 +172,7 @@ export class ConfluentSchemaRegistry extends AbstractSchemaRegistry {
|
|
|
169
172
|
const validate = schema.schema;
|
|
170
173
|
const valid = validate(data);
|
|
171
174
|
if (!valid) {
|
|
172
|
-
throw new UserError(`JSON Schema validation failed before serialization: ${
|
|
175
|
+
throw new UserError(`JSON Schema validation failed before serialization: ${this.#jsonAjv.errorsText(validate.errors)}`, { type, data, headers, validationErrors: validate.errors });
|
|
173
176
|
}
|
|
174
177
|
}
|
|
175
178
|
encodedMessage = Buffer.from(JSON.stringify(data));
|
|
@@ -208,7 +211,7 @@ export class ConfluentSchemaRegistry extends AbstractSchemaRegistry {
|
|
|
208
211
|
const validate = schema.schema;
|
|
209
212
|
const valid = validate(parsed);
|
|
210
213
|
if (!valid) {
|
|
211
|
-
throw new UserError(`JSON Schema validation failed before deserialization: ${
|
|
214
|
+
throw new UserError(`JSON Schema validation failed before deserialization: ${this.#jsonAjv.errorsText(validate.errors)}`, { type, data: parsed, headers, validationErrors: validate.errors });
|
|
212
215
|
}
|
|
213
216
|
return parsed;
|
|
214
217
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ValidateFunction } from 'ajv';
|
|
1
|
+
import { type Options, type ValidateFunction } from 'ajv';
|
|
2
2
|
import { type Type } from 'avsc';
|
|
3
3
|
import { type Root } from 'protobufjs';
|
|
4
4
|
import { type Callback } from "../apis/definitions";
|
|
@@ -20,6 +20,7 @@ export interface ConfluentSchemaRegistryOptions {
|
|
|
20
20
|
};
|
|
21
21
|
protobufTypeMapper?: ConfluentSchemaRegistryProtobufTypeMapper;
|
|
22
22
|
jsonValidateSend?: boolean;
|
|
23
|
+
jsonAjvOptions?: Options;
|
|
23
24
|
}
|
|
24
25
|
export interface Schema {
|
|
25
26
|
id: number;
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = "@platformatic/kafka";
|
|
2
|
-
export const version = "2.
|
|
2
|
+
export const version = "2.6.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/kafka",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.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)",
|