From 7ebf560c704b4cc4ebb22cb05d62a7b5626a6c07 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:28:19 +0000 Subject: [PATCH 1/4] Initial plan From cd194e8d2f1bf58723dd83ddde326d9ad20a6337 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:35:59 +0000 Subject: [PATCH 2/4] Initial plan for fixing baseURL double-prefix bug Agent-Logs-Url: https://github.com/dev-dami/kiattp/sessions/5761a7d0-5bf0-440b-9347-d3a3f6abbc83 Co-authored-by: dev-dami <141376183+dev-dami@users.noreply.github.com> --- package-lock.json | 4 ++-- test/unit/diag-baseurl.test.ts | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/unit/diag-baseurl.test.ts diff --git a/package-lock.json b/package-lock.json index 24d1240..beb33b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "kiattp", - "version": "0.1.0", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kiattp", - "version": "0.1.0", + "version": "0.3.0", "license": "MIT", "devDependencies": { "@types/node": "^25.5.2", diff --git a/test/unit/diag-baseurl.test.ts b/test/unit/diag-baseurl.test.ts new file mode 100644 index 0000000..ee750e7 --- /dev/null +++ b/test/unit/diag-baseurl.test.ts @@ -0,0 +1,32 @@ +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { setupServer } from 'msw/node'; +import { http, HttpResponse } from 'msw'; +import { axios } from '../../src/axios'; + +let capturedUrl = ''; + +const server = setupServer( + http.all('*', ({ request: req }) => { + capturedUrl = req.url; + return HttpResponse.json({ token: 'abc' }); + }), +); + +beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })); +afterAll(() => server.close()); + +describe('baseURL diagnostic', () => { + it('axios.create({ baseURL: /api }) - request URL with leading slash', async () => { + capturedUrl = ''; + const client = axios.create({ baseURL: '/api' }); + try { + await client.post('/auth/login', { email: 'test@test.com', password: 'test' }); + console.log('Request succeeded, URL:', capturedUrl); + } catch (e: any) { + console.log('Request error:', e.message, e.name); + console.log('Captured URL:', capturedUrl); + } + // This test is for diagnostics only + expect(true).toBe(true); + }); +}); From 1a40f1c557e79ac5ea53fa2fb9c6275df4c4e9f2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:41:58 +0000 Subject: [PATCH 3/4] Fix baseURL double-prefix bug when request path starts with / Agent-Logs-Url: https://github.com/dev-dami/kiattp/sessions/5761a7d0-5bf0-440b-9347-d3a3f6abbc83 Co-authored-by: dev-dami <141376183+dev-dami@users.noreply.github.com> --- src/instance.ts | 6 +++- test/axios/compatibility.test.ts | 10 +++++++ test/unit/diag-baseurl.test.ts | 32 --------------------- test/unit/instance-baseurl.test.ts | 46 ++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 33 deletions(-) delete mode 100644 test/unit/diag-baseurl.test.ts create mode 100644 test/unit/instance-baseurl.test.ts diff --git a/src/instance.ts b/src/instance.ts index 97e2c87..211f4c3 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -23,7 +23,11 @@ export function createInstance(defaults?: Partial): Instance { ...merged, url: fullUrl, }); - return request(instanceConfig.url!, instanceConfig, instanceChain); + // Strip baseURL and url from instanceConfig before passing to request(), + // since the URL is already fully resolved by buildUrl() above. + // This prevents baseURL from being applied twice in core/request.ts. + const { baseURL: _baseURL, url: _url, ...resolvedInstanceConfig } = instanceConfig; + return request(instanceConfig.url!, resolvedInstanceConfig, instanceChain); }; const methodFn = (method: HttpMethod): RequestFn => { diff --git a/test/axios/compatibility.test.ts b/test/axios/compatibility.test.ts index de08e35..36d7e49 100644 --- a/test/axios/compatibility.test.ts +++ b/test/axios/compatibility.test.ts @@ -15,6 +15,10 @@ const server = setupServer( await new Promise((resolve) => setTimeout(resolve, 1000)); return HttpResponse.json([{ id: 1 }]); }), + http.post('https://api.example.com/api/auth/login', async ({ request: req }) => { + const body = await req.json(); + return HttpResponse.json({ token: 'abc', ...body }); + }), ); beforeAll(() => server.listen()); @@ -74,4 +78,10 @@ describe('axios compatibility', () => { ]); expect(results).toHaveLength(2); }); + + it('axios.create() with baseURL containing a path prepends full baseURL when path starts with /', async () => { + const api = axios.create({ baseURL: 'https://api.example.com/api' }); + const res = await api.post('/auth/login', { email: 'test@test.com', password: 'test' }); + expect(res.data).toMatchObject({ token: 'abc', email: 'test@test.com' }); + }); }); diff --git a/test/unit/diag-baseurl.test.ts b/test/unit/diag-baseurl.test.ts deleted file mode 100644 index ee750e7..0000000 --- a/test/unit/diag-baseurl.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { describe, it, expect, beforeAll, afterAll } from 'vitest'; -import { setupServer } from 'msw/node'; -import { http, HttpResponse } from 'msw'; -import { axios } from '../../src/axios'; - -let capturedUrl = ''; - -const server = setupServer( - http.all('*', ({ request: req }) => { - capturedUrl = req.url; - return HttpResponse.json({ token: 'abc' }); - }), -); - -beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })); -afterAll(() => server.close()); - -describe('baseURL diagnostic', () => { - it('axios.create({ baseURL: /api }) - request URL with leading slash', async () => { - capturedUrl = ''; - const client = axios.create({ baseURL: '/api' }); - try { - await client.post('/auth/login', { email: 'test@test.com', password: 'test' }); - console.log('Request succeeded, URL:', capturedUrl); - } catch (e: any) { - console.log('Request error:', e.message, e.name); - console.log('Captured URL:', capturedUrl); - } - // This test is for diagnostics only - expect(true).toBe(true); - }); -}); diff --git a/test/unit/instance-baseurl.test.ts b/test/unit/instance-baseurl.test.ts new file mode 100644 index 0000000..5331f28 --- /dev/null +++ b/test/unit/instance-baseurl.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { createInstance } from '../../src/instance'; + +describe('baseURL + leading slash path (relative baseURL)', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('does not double-prefix baseURL when path starts with /', async () => { + const capturedUrls: string[] = []; + + // Spy on global fetch to capture the URL actually used + vi.stubGlobal('fetch', vi.fn(async (url: string) => { + capturedUrls.push(url); + return new Response(JSON.stringify({ ok: true }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + })); + + const instance = createInstance({ baseURL: '/api' }); + await instance.post('/auth/login', { body: { email: 'test@test.com' } }); + + expect(capturedUrls).toHaveLength(1); + // Should be /api/auth/login, NOT /api/api/auth/login + expect(capturedUrls[0]).toBe('/api/auth/login'); + }); + + it('does not double-prefix baseURL when path does not start with /', async () => { + const capturedUrls: string[] = []; + + vi.stubGlobal('fetch', vi.fn(async (url: string) => { + capturedUrls.push(url); + return new Response(JSON.stringify({ ok: true }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + })); + + const instance = createInstance({ baseURL: '/api' }); + await instance.get('users'); + + expect(capturedUrls).toHaveLength(1); + expect(capturedUrls[0]).toBe('/api/users'); + }); +}); From 2026796bb44123cd3f1168cbe5f7a329ce92c7b6 Mon Sep 17 00:00:00 2001 From: Dev <141376183+dev-dami@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:43:46 +0100 Subject: [PATCH 4/4] Remove comments about instanceConfig processing Removed comments explaining the stripping of baseURL and url from instanceConfig. --- src/instance.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/instance.ts b/src/instance.ts index 211f4c3..24cbd95 100644 --- a/src/instance.ts +++ b/src/instance.ts @@ -23,9 +23,6 @@ export function createInstance(defaults?: Partial): Instance { ...merged, url: fullUrl, }); - // Strip baseURL and url from instanceConfig before passing to request(), - // since the URL is already fully resolved by buildUrl() above. - // This prevents baseURL from being applied twice in core/request.ts. const { baseURL: _baseURL, url: _url, ...resolvedInstanceConfig } = instanceConfig; return request(instanceConfig.url!, resolvedInstanceConfig, instanceChain); };