Skip to content
Merged
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
6 changes: 4 additions & 2 deletions packages/better-fetch/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ export const betterFetch = async <
const headers = await getHeaders(opts);
const body = getBody(opts, headers);
const method = getMethod(__url, opts);
let context = {
// one stable object for the whole request so per-request state keyed on
// its identity survives hooks that return a replacement context
const context = {
...opts,
url: _url,
headers,
Expand All @@ -59,7 +61,7 @@ export const betterFetch = async <
if (onRequest) {
const res = await onRequest(context);
if (typeof res === "object" && res !== null) {
context = res;
Object.assign(context, res);
}
}
}
Expand Down
37 changes: 33 additions & 4 deletions packages/better-fetch/src/test/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,37 @@ describe("create-fetch-runtime-test", () => {
method: "PUT",
});
});

it("keeps the request-context identity stable across replacing hooks", async () => {
const seen: object[] = [];
const capture = (id: string): BetterFetchPlugin => ({
id,
name: id,
hooks: {
// returning a replacement must not break per-request identity
onRequest(context) {
seen.push(context);
return { ...context };
},
},
});
const $fetch = createFetch({
baseURL: "http://localhost:4001",
customFetchImpl: async () => new Response(null, { status: 200 }),
plugins: [capture("a"), capture("b")],
});

let successRequest: object | undefined;
await $fetch("/", {
onSuccess(context) {
successRequest = context.request;
},
});

expect(seen).toHaveLength(2);
expect(seen[1]).toBe(seen[0]);
expect(successRequest).toBe(seen[0]);
});
});

describe("create-fetch-type-test", () => {
Expand All @@ -270,10 +301,8 @@ describe("create-fetch-type-test", () => {
const res = await $fetch("/", {
throw: true,
});
expectTypeOf(res).toMatchTypeOf<
{ message: string }
>();
})
expectTypeOf(res).toMatchTypeOf<{ message: string }>();
});

it("should return unknown if no output is defined", () => {
const res = $fetch("/");
Expand Down