From dc3dca74be3415f4694ab1a79e0a3f8dd36f3c42 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 17 Jan 2025 15:48:43 -0500 Subject: [PATCH 01/11] feat(graphiql-toolkit): accept HeadersInit --- .../src/create-fetcher/lib.ts | 63 ++++++++++++++----- .../src/create-fetcher/types.ts | 4 +- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index fc8e8e1fc8e..665edd2e9df 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -24,6 +24,23 @@ const errorHasCode = (err: unknown): err is { code: string } => { return typeof err === 'object' && err !== null && 'code' in err; }; +/** + * Merge two Headers instances into one. + * + * Returns a new Headers instance (does not mutate). + * + * Headers are merged by having a copy of the first headers argument apply its `set` + * method to assign each header from the second headers argument. This means that headers + * from the second Headers instance overwrite same-named headers in the first. + */ +const mergeHeadersWithSetStrategy = (headersA: Headers, headersB: Headers) => { + const newHeaders = new Headers(headersA); + for (const [key, value] of headersB.entries()) { + newHeaders.set(key, value); + } + return newHeaders; +}; + /** * Returns true if the name matches a subscription in the AST * @@ -57,14 +74,18 @@ export const isSubscriptionWithName = ( export const createSimpleFetcher = (options: CreateFetcherOptions, httpFetch: typeof fetch): Fetcher => async (graphQLParams: FetcherParams, fetcherOpts?: FetcherOpts) => { + const headers = [ + new Headers({ + 'content-type': 'application/json', + }), + new Headers(options.headers ?? {}), + new Headers(fetcherOpts?.headers ?? {}), + ].reduce(mergeHeadersWithSetStrategy, new Headers()); + const data = await httpFetch(options.url, { method: 'POST', body: JSON.stringify(graphQLParams), - headers: { - 'content-type': 'application/json', - ...options.headers, - ...fetcherOpts?.headers, - }, + headers, }); return data.json(); }; @@ -141,17 +162,19 @@ export const createMultipartFetcher = ( httpFetch: typeof fetch, ): Fetcher => async function* (graphQLParams: FetcherParams, fetcherOpts?: FetcherOpts) { + const headers = [ + new Headers({ + 'content-type': 'application/json', + accept: 'application/json, multipart/mixed', + }), + new Headers(options.headers ?? {}), + new Headers(fetcherOpts?.headers ?? {}), + ].reduce(mergeHeadersWithSetStrategy, new Headers()); + const response = await httpFetch(options.url, { method: 'POST', body: JSON.stringify(graphQLParams), - headers: { - 'content-type': 'application/json', - accept: 'application/json, multipart/mixed', - ...options.headers, - // allow user-defined headers to override - // the static provided headers - ...fetcherOpts?.headers, - }, + headers, }).then(r => meros>(r, { multiple: true, @@ -187,9 +210,21 @@ export async function getWsFetcher( return createWebsocketsFetcherFromClient(options.wsClient); } if (options.subscriptionUrl) { + const fetcherOptsHeaders = new Headers(fetcherOpts?.headers ?? {}); + // @ts-expect-error: Current TS Config target does not support `Headers.entries()` method. + // However it is reported as "widely available" and so should be fine to use. This could + // would be more complicated without it. + // @see https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries + const fetcherOptsHeadersEntries: [string, string][] = [ + ...fetcherOptsHeaders.entries(), + ]; + // todo: If there are headers with multiple values, they will be lost. Is this a problem? + const fetcherOptsHeadersRecord = Object.fromEntries( + fetcherOptsHeadersEntries, + ); return createWebsocketsFetcherFromUrl(options.subscriptionUrl, { ...options.wsConnectionParams, - ...fetcherOpts?.headers, + ...fetcherOptsHeadersRecord, }); } const legacyWebsocketsClient = options.legacyClient || options.legacyWsClient; diff --git a/packages/graphiql-toolkit/src/create-fetcher/types.ts b/packages/graphiql-toolkit/src/create-fetcher/types.ts index 9ae06a67beb..fa30ce8739e 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/types.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/types.ts @@ -31,7 +31,7 @@ export type FetcherParams = { }; export type FetcherOpts = { - headers?: { [key: string]: any }; + headers?: HeadersInit; documentAST?: DocumentNode; }; @@ -104,7 +104,7 @@ export interface CreateFetcherOptions { * If you enable the headers editor and the user provides * A header you set statically here, it will be overridden by their value. */ - headers?: Record; + headers?: HeadersInit; /** * Websockets connection params used when you provide subscriptionUrl. graphql-ws `ClientOptions.connectionParams` */ From 863ae8c035c2c6c31adc7e2b286ba66505ba163a Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 09:27:07 -0500 Subject: [PATCH 02/11] refactor --- .../src/create-fetcher/lib.ts | 65 +++++++------------ 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index 665edd2e9df..a475145e725 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -1,3 +1,9 @@ +// todo +// Current TS Config target does not support `Headers.entries()` method. +// However it is reported as "widely available" and so should be fine to use. +// @see https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries +// Several places we currently use ts-expect-error to allow this. + import { DocumentNode, visit } from 'graphql'; import { meros } from 'meros'; import type { @@ -24,23 +30,6 @@ const errorHasCode = (err: unknown): err is { code: string } => { return typeof err === 'object' && err !== null && 'code' in err; }; -/** - * Merge two Headers instances into one. - * - * Returns a new Headers instance (does not mutate). - * - * Headers are merged by having a copy of the first headers argument apply its `set` - * method to assign each header from the second headers argument. This means that headers - * from the second Headers instance overwrite same-named headers in the first. - */ -const mergeHeadersWithSetStrategy = (headersA: Headers, headersB: Headers) => { - const newHeaders = new Headers(headersA); - for (const [key, value] of headersB.entries()) { - newHeaders.set(key, value); - } - return newHeaders; -}; - /** * Returns true if the name matches a subscription in the AST * @@ -74,14 +63,13 @@ export const isSubscriptionWithName = ( export const createSimpleFetcher = (options: CreateFetcherOptions, httpFetch: typeof fetch): Fetcher => async (graphQLParams: FetcherParams, fetcherOpts?: FetcherOpts) => { - const headers = [ - new Headers({ - 'content-type': 'application/json', - }), - new Headers(options.headers ?? {}), - new Headers(fetcherOpts?.headers ?? {}), - ].reduce(mergeHeadersWithSetStrategy, new Headers()); - + const headers = new Headers([ + ['content-type', 'application/json'], + // @ts-expect-error: todo enable ES target that has entries on headers + ...new Headers(options.headers ?? {}).entries(), + // @ts-expect-error: todo enable ES target that has entries on headers + ...new Headers(fetcherOpts?.headers ?? {}).entries(), + ]); const data = await httpFetch(options.url, { method: 'POST', body: JSON.stringify(graphQLParams), @@ -162,14 +150,14 @@ export const createMultipartFetcher = ( httpFetch: typeof fetch, ): Fetcher => async function* (graphQLParams: FetcherParams, fetcherOpts?: FetcherOpts) { - const headers = [ - new Headers({ - 'content-type': 'application/json', - accept: 'application/json, multipart/mixed', - }), - new Headers(options.headers ?? {}), - new Headers(fetcherOpts?.headers ?? {}), - ].reduce(mergeHeadersWithSetStrategy, new Headers()); + const headers = new Headers([ + ['content-type', 'application/json'], + ['accept', 'application/json, multipart/mixed'], + // @ts-expect-error: todo enable ES target that has entries on headers + ...new Headers(options.headers ?? {}).entries(), + // @ts-expect-error: todo enable ES target that has entries on headers + ...new Headers(fetcherOpts?.headers ?? {}).entries(), + ]); const response = await httpFetch(options.url, { method: 'POST', @@ -210,17 +198,10 @@ export async function getWsFetcher( return createWebsocketsFetcherFromClient(options.wsClient); } if (options.subscriptionUrl) { - const fetcherOptsHeaders = new Headers(fetcherOpts?.headers ?? {}); - // @ts-expect-error: Current TS Config target does not support `Headers.entries()` method. - // However it is reported as "widely available" and so should be fine to use. This could - // would be more complicated without it. - // @see https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries - const fetcherOptsHeadersEntries: [string, string][] = [ - ...fetcherOptsHeaders.entries(), - ]; // todo: If there are headers with multiple values, they will be lost. Is this a problem? const fetcherOptsHeadersRecord = Object.fromEntries( - fetcherOptsHeadersEntries, + // @ts-expect-error: todo enable ES target that has entries on headers + new Headers(fetcherOpts?.headers ?? {}).entries(), ); return createWebsocketsFetcherFromUrl(options.subscriptionUrl, { ...options.wsConnectionParams, From edb63e834d5c5ab01034b1eeee832b940ad8e077 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 09:32:29 -0500 Subject: [PATCH 03/11] refactor --- packages/graphiql-toolkit/src/create-fetcher/lib.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index a475145e725..1caa63c271c 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -198,14 +198,14 @@ export async function getWsFetcher( return createWebsocketsFetcherFromClient(options.wsClient); } if (options.subscriptionUrl) { - // todo: If there are headers with multiple values, they will be lost. Is this a problem? - const fetcherOptsHeadersRecord = Object.fromEntries( - // @ts-expect-error: todo enable ES target that has entries on headers - new Headers(fetcherOpts?.headers ?? {}).entries(), - ); + // @ts-expect-error: todo enable ES target that has entries on headers + const fetcherOptsHeaders = new Headers( + fetcherOpts?.headers ?? {}, + ).entries(); + return createWebsocketsFetcherFromUrl(options.subscriptionUrl, { ...options.wsConnectionParams, - ...fetcherOptsHeadersRecord, + ...Object.fromEntries(fetcherOptsHeaders), }); } const legacyWebsocketsClient = options.legacyClient || options.legacyWsClient; From 56219f030e3f31727c29928b1346bc73eb2428ea Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 09:33:23 -0500 Subject: [PATCH 04/11] refactor --- packages/graphiql-toolkit/src/create-fetcher/lib.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index 1caa63c271c..3178bb5bf2a 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -198,11 +198,10 @@ export async function getWsFetcher( return createWebsocketsFetcherFromClient(options.wsClient); } if (options.subscriptionUrl) { - // @ts-expect-error: todo enable ES target that has entries on headers const fetcherOptsHeaders = new Headers( fetcherOpts?.headers ?? {}, + // @ts-expect-error: todo enable ES target that has entries on headers ).entries(); - return createWebsocketsFetcherFromUrl(options.subscriptionUrl, { ...options.wsConnectionParams, ...Object.fromEntries(fetcherOptsHeaders), From ba808458609535171a67b1894aaefaebf65a1be2 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 11:46:18 -0500 Subject: [PATCH 05/11] add tests --- packages/graphiql-toolkit/package.json | 2 +- .../src/create-fetcher/__tests__/_helpers.ts | 36 +++++++++ .../__tests__/createFetcher.spec.ts | 77 +++++++++++++++++++ .../src/create-fetcher/createFetcher.ts | 5 +- .../src/create-fetcher/lib.ts | 33 ++++---- 5 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 packages/graphiql-toolkit/src/create-fetcher/__tests__/_helpers.ts create mode 100644 packages/graphiql-toolkit/src/create-fetcher/__tests__/createFetcher.spec.ts diff --git a/packages/graphiql-toolkit/package.json b/packages/graphiql-toolkit/package.json index 1602a314e59..78f8dc9bc85 100644 --- a/packages/graphiql-toolkit/package.json +++ b/packages/graphiql-toolkit/package.json @@ -23,7 +23,7 @@ "dev": "tsup --watch", "prebuild": "yarn types:check", "types:check": "tsc --noEmit", - "test": "vitest run" + "test": "vitest" }, "dependencies": { "@n1ru4l/push-pull-async-iterable-iterator": "^3.1.0", diff --git a/packages/graphiql-toolkit/src/create-fetcher/__tests__/_helpers.ts b/packages/graphiql-toolkit/src/create-fetcher/__tests__/_helpers.ts new file mode 100644 index 00000000000..b0a87bc36dc --- /dev/null +++ b/packages/graphiql-toolkit/src/create-fetcher/__tests__/_helpers.ts @@ -0,0 +1,36 @@ +/* eslint-disable */ + +import { Mock, it as itBase } from 'vitest'; + +export const test = itBase.extend<{ + fetch: Mock; + graphqlWs: { + createClient: Mock< + (parameters: { connectionParams: Record }) => any + >; + }; +}>({ + // @ts-expect-error fixme + fetch: async ({}, use) => { + const originalFetch = globalThis.fetch; + const mock = vi + .fn() + .mockResolvedValueOnce(new Response(JSON.stringify({ data: {} }))); + globalThis.fetch = mock; + await use(fetch); + globalThis.fetch = originalFetch; + }, + graphqlWs: async ({}, use) => { + const graphqlWsExports = { + createClient: vi.fn(() => { + return { + subscribe: vi.fn(), + }; + }), + }; + vi.doMock('graphql-ws', () => { + return graphqlWsExports; + }); + await use(graphqlWsExports); + }, +}); diff --git a/packages/graphiql-toolkit/src/create-fetcher/__tests__/createFetcher.spec.ts b/packages/graphiql-toolkit/src/create-fetcher/__tests__/createFetcher.spec.ts new file mode 100644 index 00000000000..71a99083a1f --- /dev/null +++ b/packages/graphiql-toolkit/src/create-fetcher/__tests__/createFetcher.spec.ts @@ -0,0 +1,77 @@ +/* eslint-disable */ + +import { parse } from 'graphql'; +import { createGraphiQLFetcher } from '../createFetcher'; +import { test } from './_helpers'; + +interface TestCase { + constructor: HeadersInit; + send: HeadersInit; + expected: Record; +} + +const H = Headers; +const cases: TestCase[] = [ + // --- levels merge + { constructor: { a:'1' } , send: { b:'2' } , expected: { a:'1', b:'2' } }, + { constructor: [['a','1']] , send: [['b','2']] , expected: { a:'1', b:'2' } }, + { constructor: new H({a:'1'}) , send: new H({b:'2'}) , expected: { a:'1', b:'2' } }, + // --- send level takes precedence + { constructor: { a:'1' } , send: { a:'2' } , expected: { a:'2' } }, + { constructor: [['a','1']] , send: [['a','2']] , expected: { a:'2' } }, + { constructor: new H({a:'1'}) , send: new H({a:'2'}) , expected: { a:'2' } }, +]; // prettier-ignore + +describe('accepts HeadersInit on constructor and send levels, send taking precedence', () => { + test.for(cases)('%j', async (_case, { fetch }) => { + const fetcher = createGraphiQLFetcher({ + url: 'https://foobar', + enableIncrementalDelivery: false, + headers: _case.constructor, + }); + await fetcher({ query: '' }, { headers: _case.send }); + // @ts-expect-error + const requestHeaders = Object.fromEntries(new Headers(fetch.mock.calls[0]?.[1]?.headers ?? {}).entries()); // prettier-ignore + expect(fetch).toBeCalledTimes(1); + expect(requestHeaders).toMatchObject(_case.expected); + }); + + test.for(cases)('incremental delivery: %j', async (_case, { fetch }) => { + const fetcher = createGraphiQLFetcher({ + url: 'https://foobar', + enableIncrementalDelivery: true, + headers: _case.constructor, + }); + const result = await fetcher({ query: '' }, { headers: _case.send }); + // TODO: Improve types to indicate that result is AsyncIterable when enableIncrementalDelivery is true + await drainAsyncIterable(result as AsyncIterable); + // @ts-expect-error + const requestHeaders = Object.fromEntries(new Headers(fetch.mock.calls[0]?.[1]?.headers ?? {}).entries()); // prettier-ignore + expect(fetch).toBeCalledTimes(1); + expect(requestHeaders).toMatchObject(_case.expected); + }); + + test.for(cases)('subscription: %j', async (_case, { graphqlWs }) => { + const fetcher = createGraphiQLFetcher({ + url: 'https://foobar', + headers: _case.constructor, + subscriptionUrl: 'wss://foobar', + }); + await fetcher({ query: '', operationName:'foo' }, { headers: _case.send, documentAST: parse('subscription foo { bar }') }); // prettier-ignore + const connectionParams = graphqlWs.createClient.mock.calls[0]?.[0]?.connectionParams ?? {}; // prettier-ignore + expect(graphqlWs.createClient).toBeCalledTimes(1); + expect(connectionParams).toMatchObject(_case.expected); + }); +}); + +// ------------------------------------------------------------------------------------------------- +// Helpers +// ------------------------------------------------------------------------------------------------- + +const drainAsyncIterable = async (iterable: AsyncIterable) => { + const result: any[] = []; + for await (const item of iterable) { + result.push(item); + } + return result; +}; diff --git a/packages/graphiql-toolkit/src/create-fetcher/createFetcher.ts b/packages/graphiql-toolkit/src/create-fetcher/createFetcher.ts index b90c65ee83e..3635c339028 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/createFetcher.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/createFetcher.ts @@ -13,11 +13,11 @@ import { * - optionally supports graphql-ws or ` */ export function createGraphiQLFetcher(options: CreateFetcherOptions): Fetcher { - const httpFetch = - options.fetch || (typeof window !== 'undefined' && window.fetch); + const httpFetch = options.fetch ?? globalThis.fetch; if (!httpFetch) { throw new Error('No valid fetcher implementation available'); } + options.enableIncrementalDelivery = options.enableIncrementalDelivery !== false; // simpler fetcher for schema requests @@ -29,6 +29,7 @@ export function createGraphiQLFetcher(options: CreateFetcherOptions): Fetcher { return async (graphQLParams, fetcherOpts) => { if (graphQLParams.operationName === 'IntrospectionQuery') { + // todo test this return (options.schemaFetcher || simpleFetcher)( graphQLParams, fetcherOpts, diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index 3178bb5bf2a..babc6349044 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -63,13 +63,13 @@ export const isSubscriptionWithName = ( export const createSimpleFetcher = (options: CreateFetcherOptions, httpFetch: typeof fetch): Fetcher => async (graphQLParams: FetcherParams, fetcherOpts?: FetcherOpts) => { - const headers = new Headers([ - ['content-type', 'application/json'], + const headers = new Headers({ + 'content-type': 'application/json', // @ts-expect-error: todo enable ES target that has entries on headers - ...new Headers(options.headers ?? {}).entries(), + ...Object.fromEntries(new Headers(options.headers ?? {}).entries()), // @ts-expect-error: todo enable ES target that has entries on headers - ...new Headers(fetcherOpts?.headers ?? {}).entries(), - ]); + ...Object.fromEntries(new Headers(fetcherOpts?.headers ?? {}).entries()), + }); const data = await httpFetch(options.url, { method: 'POST', body: JSON.stringify(graphQLParams), @@ -150,15 +150,14 @@ export const createMultipartFetcher = ( httpFetch: typeof fetch, ): Fetcher => async function* (graphQLParams: FetcherParams, fetcherOpts?: FetcherOpts) { - const headers = new Headers([ - ['content-type', 'application/json'], - ['accept', 'application/json, multipart/mixed'], + const headers = new Headers({ + 'content-type': 'application/json', + accept: 'application/json, multipart/mixed', // @ts-expect-error: todo enable ES target that has entries on headers - ...new Headers(options.headers ?? {}).entries(), + ...Object.fromEntries(new Headers(options.headers ?? {}).entries()), // @ts-expect-error: todo enable ES target that has entries on headers - ...new Headers(fetcherOpts?.headers ?? {}).entries(), - ]); - + ...Object.fromEntries(new Headers(fetcherOpts?.headers ?? {}).entries()), + }); const response = await httpFetch(options.url, { method: 'POST', body: JSON.stringify(graphQLParams), @@ -198,13 +197,15 @@ export async function getWsFetcher( return createWebsocketsFetcherFromClient(options.wsClient); } if (options.subscriptionUrl) { - const fetcherOptsHeaders = new Headers( - fetcherOpts?.headers ?? {}, + const headers = { + // @ts-expect-error: todo enable ES target that has entries on headers + ...Object.fromEntries(new Headers(options?.headers ?? {}).entries()), // @ts-expect-error: todo enable ES target that has entries on headers - ).entries(); + ...Object.fromEntries(new Headers(fetcherOpts?.headers ?? {}).entries()), + }; return createWebsocketsFetcherFromUrl(options.subscriptionUrl, { ...options.wsConnectionParams, - ...Object.fromEntries(fetcherOptsHeaders), + ...headers, }); } const legacyWebsocketsClient = options.legacyClient || options.legacyWsClient; From 82626ba3e7692ce10dfbf074666bbe0bdc86b361 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 11:50:54 -0500 Subject: [PATCH 06/11] fix types in graphiql-react --- packages/graphiql-react/src/execution.tsx | 2 +- packages/graphiql-react/src/schema.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/graphiql-react/src/execution.tsx b/packages/graphiql-react/src/execution.tsx index 3c13d335fa3..2db8f8f73cc 100644 --- a/packages/graphiql-react/src/execution.tsx +++ b/packages/graphiql-react/src/execution.tsx @@ -147,7 +147,7 @@ export function ExecutionContextProvider({ } const headersString = headerEditor?.getValue(); - let headers: Record | undefined; + let headers: Record | undefined; try { headers = tryParseJsonObject({ json: headersString, diff --git a/packages/graphiql-react/src/schema.tsx b/packages/graphiql-react/src/schema.tsx index 20346f3e903..3a7d8791e94 100644 --- a/packages/graphiql-react/src/schema.tsx +++ b/packages/graphiql-react/src/schema.tsx @@ -391,7 +391,7 @@ function useIntrospectionQuery({ } function parseHeaderString(headersString?: string) { - let headers: Record | null = null; + let headers: Record | null = null; let isValidJSON = true; try { From 1e5415ea1cfb8c8cc1dd72515f47da97cb96d6df Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 12:01:18 -0500 Subject: [PATCH 07/11] changelog --- .changeset/early-pears-remember.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/early-pears-remember.md diff --git a/.changeset/early-pears-remember.md b/.changeset/early-pears-remember.md new file mode 100644 index 00000000000..6845daf2c06 --- /dev/null +++ b/.changeset/early-pears-remember.md @@ -0,0 +1,12 @@ +--- +'@graphiql/toolkit': minor +'@graphiql/react': patch +--- + +`graphiql-toolkit` now accepts `HeadersInit` input. + +`graphiql-react` has internal type changes to support this. + +BREAKING CHANGE: + +Because `graphiql-toolkit` functions now accept HeadersInit where previously a partially wider type of `Record` was accepted, there is a technical backwards incompatibility. This new stricter type could for example cause your project to fail type checking after this upgrade. At runtime, nothing should change since if you weren't already using `string` typed value headers already then they were being coerced implicitly. In practice, this should only serve to marginally improve your code with trivial effort. From f309b5b0f66e3619560761e3b3ae292458a1d96c Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 16:51:30 -0500 Subject: [PATCH 08/11] Update .changeset/early-pears-remember.md Co-authored-by: Ted Thibodeau Jr --- .changeset/early-pears-remember.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/early-pears-remember.md b/.changeset/early-pears-remember.md index 6845daf2c06..7c7a865cfc0 100644 --- a/.changeset/early-pears-remember.md +++ b/.changeset/early-pears-remember.md @@ -9,4 +9,4 @@ BREAKING CHANGE: -Because `graphiql-toolkit` functions now accept HeadersInit where previously a partially wider type of `Record` was accepted, there is a technical backwards incompatibility. This new stricter type could for example cause your project to fail type checking after this upgrade. At runtime, nothing should change since if you weren't already using `string` typed value headers already then they were being coerced implicitly. In practice, this should only serve to marginally improve your code with trivial effort. +Because `graphiql-toolkit` functions now accept HeadersInit where previously a partially-wider type of `Record` was accepted, there is a technical backwards incompatibility. This new stricter type could, for example, cause your project to fail type-checking after this upgrade. At runtime, nothing should change, since if you weren't already using `string` typed value headers, then they were being coerced implicitly. In practice, this should only serve to marginally improve your code, with trivial effort. From 6d6af802d046f85ae0c669735549a4f5d4eabb1f Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 16:51:50 -0500 Subject: [PATCH 09/11] Update packages/graphiql-toolkit/src/create-fetcher/lib.ts Co-authored-by: Ted Thibodeau Jr --- packages/graphiql-toolkit/src/create-fetcher/lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index babc6349044..55c83748d16 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -1,6 +1,6 @@ // todo // Current TS Config target does not support `Headers.entries()` method. -// However it is reported as "widely available" and so should be fine to use. +// However, it is reported as "widely available", and so should be fine to use. // @see https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries // Several places we currently use ts-expect-error to allow this. From b1ce926c340fa83fb74bdf35807a1f76d47862b3 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Thu, 23 Jan 2025 16:52:02 -0500 Subject: [PATCH 10/11] Update packages/graphiql-toolkit/src/create-fetcher/lib.ts Co-authored-by: Ted Thibodeau Jr --- packages/graphiql-toolkit/src/create-fetcher/lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/graphiql-toolkit/src/create-fetcher/lib.ts b/packages/graphiql-toolkit/src/create-fetcher/lib.ts index 55c83748d16..829bdf48f3b 100644 --- a/packages/graphiql-toolkit/src/create-fetcher/lib.ts +++ b/packages/graphiql-toolkit/src/create-fetcher/lib.ts @@ -2,7 +2,7 @@ // Current TS Config target does not support `Headers.entries()` method. // However, it is reported as "widely available", and so should be fine to use. // @see https://developer.mozilla.org/en-US/docs/Web/API/Headers/entries -// Several places we currently use ts-expect-error to allow this. +// We currently use ts-expect-error at several places to allow this. import { DocumentNode, visit } from 'graphql'; import { meros } from 'meros'; From 26db8791a151ab8909c4f8bab3613cbf1db85dac Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Tue, 4 Feb 2025 22:26:53 +0700 Subject: [PATCH 11/11] Update .changeset/early-pears-remember.md Co-authored-by: Saihajpreet Singh --- .changeset/early-pears-remember.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/early-pears-remember.md b/.changeset/early-pears-remember.md index 7c7a865cfc0..fe453e01cb3 100644 --- a/.changeset/early-pears-remember.md +++ b/.changeset/early-pears-remember.md @@ -1,5 +1,5 @@ --- -'@graphiql/toolkit': minor +'@graphiql/toolkit': major '@graphiql/react': patch ---