Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions packages/better-call/src/to-response.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,53 @@ describe("toResponse", () => {
});
});

describe("Set-Cookie header preservation", () => {
it("should preserve multiple Set-Cookie when merging onto existing Response", () => {
const res = new Response("ok");
const initHeaders = new Headers();
initHeaders.append("set-cookie", "session=abc123; Path=/");
initHeaders.append("set-cookie", "session_data=xyz; Path=/");
const response = toResponse(res, { headers: initHeaders });
const setCookies = response.headers.getSetCookie?.() ?? [];
expect(setCookies).toHaveLength(2);
expect(setCookies[0]).toContain("session=abc123");
expect(setCookies[1]).toContain("session_data=xyz");
});

it("should preserve multiple Set-Cookie in _flag=json with init.headers", () => {
const flaggedData = {
_flag: "json",
body: { ok: true },
status: 200,
};
const initHeaders = new Headers();
initHeaders.append("set-cookie", "session_token=token1; Path=/; HttpOnly");
initHeaders.append("set-cookie", "session_data=cache; Path=/");
const response = toResponse(flaggedData, { headers: initHeaders });
const setCookies = response.headers.getSetCookie?.() ?? [];
expect(setCookies).toHaveLength(2);
expect(setCookies[0]).toContain("session_token=token1");
expect(setCookies[1]).toContain("session_data=cache");
});

it("should preserve multiple Set-Cookie from routerResponse.headers in _flag=json", () => {
const routerHeaders = new Headers();
routerHeaders.append("set-cookie", "a=1; Path=/");
routerHeaders.append("set-cookie", "b=2; Path=/");
const flaggedData = {
_flag: "json",
body: { ok: true },
routerResponse: { headers: routerHeaders },
status: 200,
};
const response = toResponse(flaggedData);
const setCookies = response.headers.getSetCookie?.() ?? [];
expect(setCookies).toHaveLength(2);
expect(setCookies[0]).toContain("a=1");
expect(setCookies[1]).toContain("b=2");
});
});

describe("BigInt handling", () => {
it("should handle simple bigint values", async () => {
const data = { id: BigInt(9007199254740991) };
Expand Down
27 changes: 21 additions & 6 deletions packages/better-call/src/to-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ export function toResponse(data?: any, init?: ResponseInit): Response {
if (data instanceof Response) {
if (init?.headers instanceof Headers) {
init.headers.forEach((value, key) => {
data.headers.set(key, value);
if (key.toLowerCase() === "set-cookie") {
data.headers.append(key, value);
} else {
data.headers.set(key, value);
}
});
}
return data;
Expand All @@ -90,19 +94,30 @@ export function toResponse(data?: any, init?: ResponseInit): Response {
}
const headers = new Headers();
if (routerResponse?.headers) {
const headers = new Headers(routerResponse.headers);
for (const [key, value] of headers.entries()) {
headers.set(key, value);
for (const [key, value] of new Headers(routerResponse.headers).entries()) {
if (key.toLowerCase() === "set-cookie") {
headers.append(key, value);
} else {
headers.set(key, value);
}
}
}
if (data.headers) {
for (const [key, value] of new Headers(data.headers).entries()) {
headers.set(key, value);
if (key.toLowerCase() === "set-cookie") {
headers.append(key, value);
} else {
headers.set(key, value);
}
}
}
if (init?.headers) {
for (const [key, value] of new Headers(init.headers).entries()) {
headers.set(key, value);
if (key.toLowerCase() === "set-cookie") {
headers.append(key, value);
} else {
headers.set(key, value);
}
}
}

Expand Down