Skip to content

Commit afde929

Browse files
committed
Fix #118
toResponse overwrites multiple Set-Cookie headers
1 parent c661748 commit afde929

2 files changed

Lines changed: 68 additions & 6 deletions

File tree

packages/better-call/src/to-response.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,53 @@ describe("toResponse", () => {
162162
});
163163
});
164164

165+
describe("Set-Cookie header preservation", () => {
166+
it("should preserve multiple Set-Cookie when merging onto existing Response", () => {
167+
const res = new Response("ok");
168+
const initHeaders = new Headers();
169+
initHeaders.append("set-cookie", "session=abc123; Path=/");
170+
initHeaders.append("set-cookie", "session_data=xyz; Path=/");
171+
const response = toResponse(res, { headers: initHeaders });
172+
const setCookies = response.headers.getSetCookie?.() ?? [];
173+
expect(setCookies).toHaveLength(2);
174+
expect(setCookies[0]).toContain("session=abc123");
175+
expect(setCookies[1]).toContain("session_data=xyz");
176+
});
177+
178+
it("should preserve multiple Set-Cookie in _flag=json with init.headers", () => {
179+
const flaggedData = {
180+
_flag: "json",
181+
body: { ok: true },
182+
status: 200,
183+
};
184+
const initHeaders = new Headers();
185+
initHeaders.append("set-cookie", "session_token=token1; Path=/; HttpOnly");
186+
initHeaders.append("set-cookie", "session_data=cache; Path=/");
187+
const response = toResponse(flaggedData, { headers: initHeaders });
188+
const setCookies = response.headers.getSetCookie?.() ?? [];
189+
expect(setCookies).toHaveLength(2);
190+
expect(setCookies[0]).toContain("session_token=token1");
191+
expect(setCookies[1]).toContain("session_data=cache");
192+
});
193+
194+
it("should preserve multiple Set-Cookie from routerResponse.headers in _flag=json", () => {
195+
const routerHeaders = new Headers();
196+
routerHeaders.append("set-cookie", "a=1; Path=/");
197+
routerHeaders.append("set-cookie", "b=2; Path=/");
198+
const flaggedData = {
199+
_flag: "json",
200+
body: { ok: true },
201+
routerResponse: { headers: routerHeaders },
202+
status: 200,
203+
};
204+
const response = toResponse(flaggedData);
205+
const setCookies = response.headers.getSetCookie?.() ?? [];
206+
expect(setCookies).toHaveLength(2);
207+
expect(setCookies[0]).toContain("a=1");
208+
expect(setCookies[1]).toContain("b=2");
209+
});
210+
});
211+
165212
describe("BigInt handling", () => {
166213
it("should handle simple bigint values", async () => {
167214
const data = { id: BigInt(9007199254740991) };

packages/better-call/src/to-response.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,11 @@ export function toResponse(data?: any, init?: ResponseInit): Response {
7676
if (data instanceof Response) {
7777
if (init?.headers instanceof Headers) {
7878
init.headers.forEach((value, key) => {
79-
data.headers.set(key, value);
79+
if (key.toLowerCase() === "set-cookie") {
80+
data.headers.append(key, value);
81+
} else {
82+
data.headers.set(key, value);
83+
}
8084
});
8185
}
8286
return data;
@@ -90,19 +94,30 @@ export function toResponse(data?: any, init?: ResponseInit): Response {
9094
}
9195
const headers = new Headers();
9296
if (routerResponse?.headers) {
93-
const headers = new Headers(routerResponse.headers);
94-
for (const [key, value] of headers.entries()) {
95-
headers.set(key, value);
97+
for (const [key, value] of new Headers(routerResponse.headers).entries()) {
98+
if (key.toLowerCase() === "set-cookie") {
99+
headers.append(key, value);
100+
} else {
101+
headers.set(key, value);
102+
}
96103
}
97104
}
98105
if (data.headers) {
99106
for (const [key, value] of new Headers(data.headers).entries()) {
100-
headers.set(key, value);
107+
if (key.toLowerCase() === "set-cookie") {
108+
headers.append(key, value);
109+
} else {
110+
headers.set(key, value);
111+
}
101112
}
102113
}
103114
if (init?.headers) {
104115
for (const [key, value] of new Headers(init.headers).entries()) {
105-
headers.set(key, value);
116+
if (key.toLowerCase() === "set-cookie") {
117+
headers.append(key, value);
118+
} else {
119+
headers.set(key, value);
120+
}
106121
}
107122
}
108123

0 commit comments

Comments
 (0)