Skip to content

Commit bd2d55c

Browse files
committed
feat: remove defaultTimeout for server options
The `defaultTimeout` causes a default signal to be set on fetch, this is good in practice, but nextjs unfortunately disables the request deduplication process.
1 parent 4247b56 commit bd2d55c

File tree

3 files changed

+14
-53
lines changed

3 files changed

+14
-53
lines changed

.changeset/tricky-news-jam.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@labdigital/graphql-fetcher": minor
3+
---
4+
5+
Remove the default timeout signal since the presence of the signal disables nextjs request deduplication

src/server.test.ts

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, expect, it, vi } from "vitest";
1+
import { describe, expect, it } from "vitest";
22
import { createSha256, pruneObject } from "./helpers";
33
import { initServerFetcher } from "./server";
44
import { TypedDocumentString } from "./testing";
@@ -52,7 +52,6 @@ describe("gqlServerFetch", () => {
5252
}),
5353
cache: "force-cache",
5454
next: { revalidate: 900 },
55-
signal: expect.any(AbortSignal),
5655
},
5756
);
5857
});
@@ -93,7 +92,6 @@ describe("gqlServerFetch", () => {
9392
"Content-Type": "application/json",
9493
}),
9594
next: { revalidate: 900 },
96-
signal: expect.any(AbortSignal),
9795
},
9896
);
9997
});
@@ -131,7 +129,6 @@ describe("gqlServerFetch", () => {
131129
"Content-Type": "application/json",
132130
}),
133131
next: { revalidate: 900 },
134-
signal: expect.any(AbortSignal),
135132
},
136133
);
137134
});
@@ -164,7 +161,6 @@ describe("gqlServerFetch", () => {
164161
}),
165162
cache: "no-store",
166163
next: { revalidate: undefined },
167-
signal: expect.any(AbortSignal),
168164
},
169165
);
170166
});
@@ -203,7 +199,6 @@ describe("gqlServerFetch", () => {
203199
}),
204200
cache: "force-cache",
205201
next: { revalidate: 900 },
206-
signal: expect.any(AbortSignal),
207202
},
208203
);
209204
});
@@ -234,7 +229,6 @@ describe("gqlServerFetch", () => {
234229
"Content-Type": "application/json",
235230
}),
236231
cache: "no-store",
237-
signal: expect.any(AbortSignal),
238232
},
239233
);
240234
});
@@ -264,41 +258,8 @@ describe("gqlServerFetch", () => {
264258
expect(fetchMock).toHaveBeenCalledTimes(1);
265259
});
266260

267-
it("should use time out after 30 seconds by default", async () => {
268-
const timeoutSpy = vi.spyOn(AbortSignal, "timeout");
269-
const gqlServerFetch = initServerFetcher("https://localhost/graphql");
270-
fetchMock.mockResponse(successResponse);
271-
272-
await gqlServerFetch(query, { myVar: "baz" }, {});
273-
274-
expect(timeoutSpy).toHaveBeenCalledWith(30000);
275-
276-
// It should not try to POST the query if the persisted query cannot be parsed
277-
expect(fetchMock).toHaveBeenCalledTimes(1);
278-
});
279-
280-
it("should use the provided timeout duration", async () => {
281-
vi.useFakeTimers();
282-
const timeoutSpy = vi.spyOn(AbortSignal, "timeout");
283-
const gqlServerFetch = initServerFetcher("https://localhost/graphql", {
284-
defaultTimeout: 1,
285-
});
286-
fetchMock.mockResponse(successResponse);
287-
288-
await gqlServerFetch(query, { myVar: "baz" }, {});
289-
290-
vi.runAllTimers();
291-
292-
expect(timeoutSpy).toHaveBeenCalledWith(1);
293-
294-
// It should not try to POST the query if the persisted query cannot be parsed
295-
expect(fetchMock).toHaveBeenCalledTimes(1);
296-
});
297-
298261
it("should use the provided signal", async () => {
299-
const gqlServerFetch = initServerFetcher("https://localhost/graphql", {
300-
defaultTimeout: 1,
301-
});
262+
const gqlServerFetch = initServerFetcher("https://localhost/graphql");
302263
fetchMock.mockResponse(successResponse);
303264

304265
const controller = new AbortController();

src/server.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ import {
2121
} from "./request";
2222

2323
type RequestOptions = {
24+
/**
25+
* Pass an AbortSignal to the fetch request. Note that when passing a signal
26+
* to the fetcher, NextJS will disable cache deduplication, so be careful when
27+
* using this option.
28+
*/
2429
signal?: AbortSignal;
2530
headers?: Headers | Record<string, string>;
2631
};
@@ -33,13 +38,6 @@ type Options = {
3338
*/
3439
dangerouslyDisableCache?: boolean;
3540

36-
/**
37-
* Sets the default timeout duration in ms after which a request will throw a timeout error
38-
*
39-
* @default 30000
40-
*/
41-
defaultTimeout?: number;
42-
4341
/**
4442
* Default headers to be sent with each request
4543
*/
@@ -75,7 +73,6 @@ export const initServerFetcher =
7573
url: string,
7674
{
7775
dangerouslyDisableCache = false,
78-
defaultTimeout = 30000,
7976
defaultHeaders = {},
8077
includeQuery = false,
8178
createDocumentId = getDocumentId,
@@ -85,9 +82,7 @@ export const initServerFetcher =
8582
astNode: DocumentTypeDecoration<TResponse, TVariables>,
8683
variables: TVariables,
8784
{ cache, next = {} }: CacheOptions,
88-
options: RequestOptions = {
89-
signal: AbortSignal.timeout(defaultTimeout),
90-
} satisfies RequestOptions,
85+
options: RequestOptions = {}
9186
): Promise<GqlResponse<TResponse>> => {
9287
const query = isNode(astNode) ? print(astNode) : astNode.toString();
9388

@@ -99,7 +94,7 @@ export const initServerFetcher =
9994
includeQuery,
10095
);
10196
const requestOptions: RequestOptions = {
102-
signal: options.signal ?? AbortSignal.timeout(defaultTimeout),
97+
...options,
10398
headers: mergeHeaders({ ...defaultHeaders, ...options.headers }),
10499
};
105100

0 commit comments

Comments
 (0)