From fb4dbfb69c27996e37fd5f29571380d4fcbe15f9 Mon Sep 17 00:00:00 2001 From: Fadi Romdhan Date: Wed, 30 Sep 2026 11:38:10 +0100 Subject: [PATCH] fix: declare listOffsets isolationLevel as a number in the options schema The listOffsets option schema declared isolationLevel as a string with the FetchIsolationLevels enum, but those values are the numbers 0 and 1. With `strict: true` no value could pass validation: `1` failed the type check and `'1'` failed the enum, so strict consumers could not call listOffsets or listOffsetsWithTimestamps with an isolation level at all. Use the number type, as the consumer's own fetch options and the admin schema already do. Signed-off-by: Fadi Romdhan --- src/clients/consumer/options.ts | 2 +- test/clients/consumer/consumer.test.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/clients/consumer/options.ts b/src/clients/consumer/options.ts index 522c6cee..fd36a4cd 100644 --- a/src/clients/consumer/options.ts +++ b/src/clients/consumer/options.ts @@ -210,7 +210,7 @@ export const listOffsetsOptionsSchema = { items: { type: 'number', minimum: 0 } } }, - isolationLevel: { type: 'string', enum: allowedFetchIsolationLevels }, + isolationLevel: { type: 'number', enum: allowedFetchIsolationLevels }, timestamp: { bigint: true } }, required: ['topics'], diff --git a/test/clients/consumer/consumer.test.ts b/test/clients/consumer/consumer.test.ts index eddb01a6..b8b467e8 100644 --- a/test/clients/consumer/consumer.test.ts +++ b/test/clients/consumer/consumer.test.ts @@ -3661,6 +3661,18 @@ test('listOffsets should use custom isolation level when provided', async t => { strictEqual(offsets.has(topic), true, 'Should contain the requested topic') }) +test('listOffsets should accept a custom isolation level in strict mode', async t => { + // The option schema declared isolationLevel as a string while FetchIsolationLevels are numbers, + // so strict consumers rejected every value: `1` failed the type check, `'1'` the enum. + const consumer = createConsumer(t, { strict: true }) + const topic = await createTopic(t, true) + + const offsets = await consumer.listOffsets({ topics: [topic], isolationLevel: FetchIsolationLevels.READ_COMMITTED }) + + strictEqual(offsets instanceof Map, true, 'Should return a Map of offsets') + strictEqual(offsets.has(topic), true, 'Should contain the requested topic') +}) + test('listOffsets should refresh metadata and retry when leadership moves (NOT_LEADER_OR_FOLLOWER)', async t => { const topic = 'test-topic' // retries: 0 isolates the outer forceUpdateMetadata retry (the fix under test) from