@platformatic/kafka 1.12.0 → 1.13.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.
@@ -117,6 +117,9 @@ export declare const baseOptionsSchema: {
117
117
  type?: undefined;
118
118
  })[];
119
119
  };
120
+ authBytesValidator: {
121
+ function: boolean;
122
+ };
120
123
  };
121
124
  required: string[];
122
125
  additionalProperties: boolean;
@@ -39,7 +39,8 @@ export const baseOptionsSchema = {
39
39
  mechanism: { type: 'string', enum: SASLMechanisms },
40
40
  username: { oneOf: [{ type: 'string' }, { function: true }] },
41
41
  password: { oneOf: [{ type: 'string' }, { function: true }] },
42
- token: { oneOf: [{ type: 'string' }, { function: true }] }
42
+ token: { oneOf: [{ type: 'string' }, { function: true }] },
43
+ authBytesValidator: { function: true }
43
44
  },
44
45
  required: ['mechanism'],
45
46
  additionalProperties: false
@@ -1,4 +1,4 @@
1
- import { type CompressionAlgorithms } from '../../protocol/compression.ts';
1
+ import { type CompressionAlgorithmValue } from '../../protocol/compression.ts';
2
2
  import { type MessageToProduce } from '../../protocol/records.ts';
3
3
  import { type BaseOptions, type TopicWithPartitionAndOffset } from '../base/types.ts';
4
4
  import { type Serializers } from '../serde.ts';
@@ -16,7 +16,7 @@ export interface ProduceOptions<Key, Value, HeaderKey, HeaderValue> {
16
16
  producerEpoch?: number;
17
17
  idempotent?: boolean;
18
18
  acks?: number;
19
- compression?: CompressionAlgorithms;
19
+ compression?: CompressionAlgorithmValue;
20
20
  partitioner?: Partitioner<Key, Value, HeaderKey, HeaderValue>;
21
21
  autocreateTopics?: boolean;
22
22
  repeatOnStaleMetadata?: boolean;
@@ -15,6 +15,7 @@ export interface SASLOptions {
15
15
  username?: string | SASLCredentialProvider;
16
16
  password?: string | SASLCredentialProvider;
17
17
  token?: string | SASLCredentialProvider;
18
+ authBytesValidator?: (authBytes: Buffer, callback: CallbackWithPromise<Buffer>) => void;
18
19
  }
19
20
  export interface ConnectionOptions {
20
21
  connectTimeout?: number;
@@ -336,7 +336,19 @@ export class Connection extends EventEmitter {
336
336
  this.#onConnectionError(host, port, diagnosticContext, error);
337
337
  return;
338
338
  }
339
- if (response.sessionLifetimeMs > 0) {
339
+ if (this.#options.sasl.authBytesValidator) {
340
+ this.#options.sasl.authBytesValidator(response.authBytes, this.#onSaslAuthenticationValidation.bind(this, host, port, diagnosticContext, response.sessionLifetimeMs));
341
+ }
342
+ else {
343
+ this.#onSaslAuthenticationValidation(host, port, diagnosticContext, response.sessionLifetimeMs, null, response.authBytes);
344
+ }
345
+ }
346
+ #onSaslAuthenticationValidation(host, port, diagnosticContext, sessionLifetimeMs, error, authBytes) {
347
+ if (error) {
348
+ this.#onConnectionError(host, port, diagnosticContext, error);
349
+ return;
350
+ }
351
+ if (sessionLifetimeMs > 0) {
340
352
  this.#reauthenticationTimeout = setTimeout(() => {
341
353
  const diagnosticContext = createDiagnosticContext({
342
354
  connection: this,
@@ -345,13 +357,13 @@ export class Connection extends EventEmitter {
345
357
  port
346
358
  });
347
359
  this.#authenticate(host, port, diagnosticContext);
348
- }, Number(response.sessionLifetimeMs) * 0.8);
360
+ }, Number(sessionLifetimeMs) * 0.8);
349
361
  }
350
362
  if (this.#status === ConnectionStatuses.CONNECTED) {
351
- this.emit('sasl:authentication:extended', response.authBytes);
363
+ this.emit('sasl:authentication:extended', authBytes);
352
364
  }
353
365
  else {
354
- this.emit('sasl:authentication', response.authBytes);
366
+ this.emit('sasl:authentication', authBytes);
355
367
  this.#onConnectionSucceed(diagnosticContext);
356
368
  }
357
369
  }
@@ -1,12 +1,21 @@
1
1
  import { DynamicBuffer } from './dynamic-buffer.ts';
2
2
  export type SyncCompressionPhase = (data: Buffer | DynamicBuffer) => Buffer;
3
3
  export type CompressionOperation = (data: Buffer) => Buffer;
4
- export interface CompressionAlgorithm {
4
+ export interface CompressionAlgorithmSpecification {
5
5
  compressSync: SyncCompressionPhase;
6
6
  decompressSync: SyncCompressionPhase;
7
7
  bitmask: number;
8
8
  available?: boolean;
9
9
  }
10
+ export declare const CompressionAlgorithms: {
11
+ readonly NONE: "none";
12
+ readonly GZIP: "gzip";
13
+ readonly SNAPPY: "snappy";
14
+ readonly LZ4: "lz4";
15
+ readonly ZSTD: "zstd";
16
+ };
17
+ export type CompressionAlgorithm = keyof typeof CompressionAlgorithms;
18
+ export type CompressionAlgorithmValue = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms];
10
19
  export declare const compressionsAlgorithms: {
11
20
  readonly none: {
12
21
  readonly compressSync: (data: Buffer | DynamicBuffer) => Buffer;
@@ -67,4 +76,3 @@ export declare const compressionsAlgorithmsByBitmask: {
67
76
  readonly available: boolean;
68
77
  };
69
78
  };
70
- export type CompressionAlgorithms = keyof typeof compressionsAlgorithms;
@@ -4,6 +4,13 @@ import { UnsupportedCompressionError } from "../errors.js";
4
4
  import { DynamicBuffer } from "./dynamic-buffer.js";
5
5
  const require = createRequire(import.meta.url);
6
6
  const { zstdCompressSync, zstdDecompressSync, gzipSync, gunzipSync } = zlib;
7
+ export const CompressionAlgorithms = {
8
+ NONE: 'none',
9
+ GZIP: 'gzip',
10
+ SNAPPY: 'snappy',
11
+ LZ4: 'lz4',
12
+ ZSTD: 'zstd'
13
+ };
7
14
  function ensureBuffer(data) {
8
15
  return DynamicBuffer.isDynamicBuffer(data) ? data.slice() : data;
9
16
  }
@@ -1,5 +1,5 @@
1
1
  import { type NumericMap } from '../utils.ts';
2
- import { type CompressionAlgorithms } from './compression.ts';
2
+ import { type CompressionAlgorithmValue } from './compression.ts';
3
3
  import { type NullableString } from './definitions.ts';
4
4
  import { Reader } from './reader.ts';
5
5
  import { Writer } from './writer.ts';
@@ -28,7 +28,7 @@ export interface MessageRecord {
28
28
  }
29
29
  export interface CreateRecordsBatchOptions {
30
30
  transactionalId?: NullableString;
31
- compression: CompressionAlgorithms;
31
+ compression: CompressionAlgorithmValue;
32
32
  firstSequence?: number;
33
33
  producerId: bigint;
34
34
  producerEpoch: number;
@@ -140,6 +140,9 @@ export function readRecordsBatch(reader) {
140
140
  throw new UnsupportedCompressionError(`Unsupported compression algorithm with bitmask ${compression}`);
141
141
  }
142
142
  const buffer = algorithm.decompressSync(reader.buffer.slice(reader.position, reader.buffer.length));
143
+ // Move the original reader to the end
144
+ reader.skip(reader.buffer.length - reader.position);
145
+ // Replace the reader with the decompressed buffer
143
146
  reader = Reader.from(buffer);
144
147
  }
145
148
  for (let i = 0; i < recordsLength; i++) {
@@ -1,5 +1,6 @@
1
1
  import { type CallbackWithPromise } from '../../apis/callbacks.ts';
2
2
  import { type SASLAuthenticationAPI, type SaslAuthenticateResponse } from '../../apis/security/sasl-authenticate-v2.ts';
3
3
  import { type Connection, type SASLCredentialProvider } from '../../network/connection.ts';
4
+ export declare function jwtValidateAuthenticationBytes(authBytes: Buffer, callback: CallbackWithPromise<Buffer>): void;
4
5
  export declare function authenticate(authenticateAPI: SASLAuthenticationAPI, connection: Connection, tokenOrProvider: string | SASLCredentialProvider, callback: CallbackWithPromise<SaslAuthenticateResponse>): void;
5
6
  export declare function authenticate(authenticateAPI: SASLAuthenticationAPI, connection: Connection, tokenOrProvider: string | SASLCredentialProvider): Promise<SaslAuthenticateResponse>;
@@ -1,5 +1,20 @@
1
1
  import { createPromisifiedCallback, kCallbackPromise } from "../../apis/callbacks.js";
2
+ import { AuthenticationError } from "../../errors.js";
2
3
  import { getCredential } from "./credential-provider.js";
4
+ export function jwtValidateAuthenticationBytes(authBytes, callback) {
5
+ let authData;
6
+ try {
7
+ authData = authBytes.length > 0 ? JSON.parse(authBytes.toString('utf-8')) : {};
8
+ }
9
+ catch (e) {
10
+ callback(new AuthenticationError('Invalid authBytes in SASL/OAUTHBEARER response', { authBytes }), undefined);
11
+ return;
12
+ }
13
+ if (authData.status === 'invalid_token') {
14
+ callback(new AuthenticationError('Invalid SASL/OAUTHBEARER token.', { authData }), undefined);
15
+ }
16
+ callback(null, authBytes);
17
+ }
3
18
  export function authenticate(authenticateAPI, connection, tokenOrProvider, callback) {
4
19
  if (!callback) {
5
20
  callback = createPromisifiedCallback();
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export const name = "@platformatic/kafka";
2
- export const version = "1.12.0";
2
+ export const version = "1.13.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformatic/kafka",
3
- "version": "1.12.0",
3
+ "version": "1.13.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)",