Skip to content

Commit 1d6dbe6

Browse files
authored
fix(client): respect user-provided mapSubresponse in BatchLinkPlugin (#1848)
A custom `mapSubresponse` passed to `BatchLinkPlugin` was silently ignored: the constructor assigned the built-in implementation unconditionally instead of using the `options.mapSubresponse ?? ...` fallback that every other option uses. Users who supplied the hook to rewrite sub-responses got the default header merge instead, with no error or warning. ## Fixes A user-provided `mapSubresponse` now runs for every sub-request, and the response it returns (headers and body alike) is what reaches the caller. Behavior is unchanged when the option is omitted. ## Testing New test in `packages/client/src/plugins/batch.test.ts` supplies a custom `mapSubresponse` that tags headers and rewrites the body, then asserts it is called once per sub-request, that its headers reach the codec, and that its body is what `link.call` resolves to. The batch response carries its own header so the test also confirms the default merge is replaced rather than layered on. The test fails on the unpatched plugin and passes with the fix.
1 parent bc0f743 commit 1d6dbe6

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

packages/client/src/plugins/batch.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,49 @@ describe('batchLinkPlugin', () => {
408408
expect(subResponse2.headers['x-index']).toEqual('1')
409409
})
410410

411+
it('uses custom mapSubresponse and forwards its response to the caller', async () => {
412+
const codec = makeCodec()
413+
const transport = makeTransport()
414+
415+
vi.mocked(transport.send).mockImplementation(async (request) => {
416+
const response = makeBufferedBatchResponseFromRequest(request)
417+
return {
418+
...response,
419+
headers: { ...response.headers, 'x-from-batch-response': 'true' },
420+
}
421+
})
422+
423+
const mapSubresponse = vi.fn((subResponse: StandardLazyResponse, batchResponse: StandardLazyResponse): StandardLazyResponse => ({
424+
...subResponse,
425+
headers: {
426+
...subResponse.headers,
427+
'x-mapped': 'true',
428+
'x-batch-status': `${batchResponse.status}`,
429+
},
430+
resolveBody: async () => `mapped-${await subResponse.resolveBody()}`,
431+
}))
432+
433+
const link = new StandardLink(codec, transport, {
434+
plugins: [new BatchLinkPlugin({
435+
groups: [defaultGroup],
436+
mapSubresponse,
437+
})],
438+
})
439+
440+
await Promise.all([
441+
expect(link.call(['a'], {}, { context: {} })).resolves.toBe('mapped-result-0'),
442+
expect(link.call(['b'], {}, { context: {} })).resolves.toBe('mapped-result-1'),
443+
])
444+
445+
expect(mapSubresponse).toHaveBeenCalledTimes(2)
446+
447+
const subResponse1 = vi.mocked(codec.decodeResponse).mock.calls[0]![0]
448+
expect(subResponse1.headers['x-mapped']).toEqual('true')
449+
expect(subResponse1.headers['x-batch-status']).toEqual('207')
450+
// the default merge of batch response headers is not applied anymore
451+
expect(subResponse1.headers['x-from-batch-response']).toBeUndefined()
452+
})
453+
411454
it('separates GET and POST requests into distinct batches', async () => {
412455
const codec = makeCodec()
413456
const transport = makeTransport()

packages/client/src/plugins/batch.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,15 @@ export class BatchLinkPlugin<T extends ClientContext> implements StandardLinkPlu
161161
headers: subHeaders,
162162
}
163163
})
164-
this.mapSubresponse = (subResponse, batchResponse) => {
164+
this.mapSubresponse = options.mapSubresponse ?? ((subResponse, batchResponse) => {
165165
return {
166166
...subResponse,
167167
headers: {
168168
...batchResponse.headers, // low-priority
169169
...subResponse.headers,
170170
},
171171
}
172-
}
172+
})
173173
}
174174

175175
init(options: StandardLinkOptions<T>): StandardLinkOptions<T> {

0 commit comments

Comments
 (0)