From 08982a782495b9d9d6f4ac5fbedad8845b95e925 Mon Sep 17 00:00:00 2001 From: edenbuilds <279970382+edenbuilds@users.noreply.github.com> Date: Fri, 7 Aug 2026 05:02:39 +0530 Subject: [PATCH 1/2] fix(client): omit Content-Type on DELETE requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit defaultHeaders set Content-Type: application/json for every non-GET/HEAD method, including bodyless DELETE. That makes contexts.delete() (and any other DELETE) fail with 400 "Body cannot be empty when content-type is set to application/json" — the same class of bug as extensions.delete (#169 / #180). Exclude delete alongside get and head when applying the default Content-Type header. --- src/core.ts | 2 +- tests/index.test.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/core.ts b/src/core.ts index 10b9d3f..db0552b 100644 --- a/src/core.ts +++ b/src/core.ts @@ -224,7 +224,7 @@ export abstract class APIClient { protected defaultHeaders(opts: FinalRequestOptions): Headers { return { Accept: 'application/json', - ...(['head', 'get'].includes(opts.method) ? {} : { 'Content-Type': 'application/json' }), + ...(['head', 'get', 'delete'].includes(opts.method) ? {} : { 'Content-Type': 'application/json' }), 'User-Agent': this.getUserAgent(), ...getPlatformHeaders(), ...this.authHeaders(opts), diff --git a/tests/index.test.ts b/tests/index.test.ts index 7639b23..baa3c6f 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -148,6 +148,24 @@ describe('instantiate client', () => { expect(capturedRequest?.method).toEqual('PATCH'); }); + test('does not set Content-Type on DELETE (#180)', async () => { + const client = new Browserbase({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + }); + const { req } = await client.buildRequest({ path: '/v1/contexts/id', method: 'delete' }); + expect(req.headers as Headers).not.toHaveProperty('content-type'); + }); + + test('still sets Content-Type on POST', async () => { + const client = new Browserbase({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + }); + const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: { a: 1 } }); + expect((req.headers as Headers)['content-type']).toEqual('application/json'); + }); + describe('baseUrl', () => { test('trailing slash', () => { const client = new Browserbase({ baseURL: 'http://localhost:5000/custom/path/', apiKey: 'My API Key' }); From 14d7925c572c5b7f6c02f38547a64f1821ba35f6 Mon Sep 17 00:00:00 2001 From: edenbuilds <279970382+edenbuilds@users.noreply.github.com> Date: Fri, 7 Aug 2026 06:04:51 +0530 Subject: [PATCH 2/2] fix(client): keep Content-Type on DELETE when a body is sent Bodyless DELETE still omits Content-Type (#180). DELETE with a JSON body restores application/json so fetch does not treat it as text/plain. --- src/core.ts | 8 +++++++- tests/index.test.ts | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/core.ts b/src/core.ts index db0552b..263883e 100644 --- a/src/core.ts +++ b/src/core.ts @@ -222,9 +222,15 @@ export abstract class APIClient { * } */ protected defaultHeaders(opts: FinalRequestOptions): Headers { + // Omit default JSON Content-Type for bodyless methods. DELETE still needs + // application/json when the caller sends a body (#180 / Codex follow-up). + const omitDefaultContentType = + opts.method === 'head' || + opts.method === 'get' || + (opts.method === 'delete' && (opts.body === undefined || opts.body === null)); return { Accept: 'application/json', - ...(['head', 'get', 'delete'].includes(opts.method) ? {} : { 'Content-Type': 'application/json' }), + ...(omitDefaultContentType ? {} : { 'Content-Type': 'application/json' }), 'User-Agent': this.getUserAgent(), ...getPlatformHeaders(), ...this.authHeaders(opts), diff --git a/tests/index.test.ts b/tests/index.test.ts index baa3c6f..1ca9292 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -157,6 +157,19 @@ describe('instantiate client', () => { expect(req.headers as Headers).not.toHaveProperty('content-type'); }); + test('sets Content-Type on DELETE when a JSON body is present', async () => { + const client = new Browserbase({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + }); + const { req } = await client.buildRequest({ + path: '/v1/contexts/id', + method: 'delete', + body: { force: true }, + }); + expect((req.headers as Headers)['content-type']).toEqual('application/json'); + }); + test('still sets Content-Type on POST', async () => { const client = new Browserbase({ baseURL: 'http://localhost:5000/',