From 455c40f1c3f07e93db00a311aaaf5b093bb8901c Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Thu, 8 Dec 2022 16:32:00 -0700 Subject: [PATCH 01/12] Add test to ensure client directive is stripped from the query --- src/core/__tests__/QueryManager/links.ts | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/core/__tests__/QueryManager/links.ts b/src/core/__tests__/QueryManager/links.ts index 140af995013..b23fef69db5 100644 --- a/src/core/__tests__/QueryManager/links.ts +++ b/src/core/__tests__/QueryManager/links.ts @@ -1,5 +1,6 @@ // externals import gql from 'graphql-tag'; +import { print } from 'graphql' import { Observable, ObservableSubscription } from '../../../utilities/observables/Observable'; import { ApolloLink } from '../../../link/core'; @@ -360,4 +361,47 @@ describe('Link interactions', () => { }); }); }); + + it('strips client directives from the query before it reaches the link', async () => { + const query = gql` + query { + books { + id + title + isRead @client + } + } + `; + + const expectedQuery = gql` + query { + books { + id + title + } + } + `; + + const bookData = { + books: [ + { id: 1, title: 'Woo', __typename: 'Book' }, + { id: 2, title: 'Foo', __typename: 'Book' }, + ], + }; + + const link = new ApolloLink((operation) => { + expect(print(operation.query)).toEqual(print(expectedQuery)) + + return Observable.of({ data: bookData }); + }); + + const queryManager = new QueryManager({ + link, + cache: new InMemoryCache({ addTypename: false }), + }); + + const { data } = await queryManager.query({ query }); + + expect(data).toEqual(bookData); + }); }); From 34daf8143c5dd4a98b2957c1912783cbf8081180 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 12:45:58 -0700 Subject: [PATCH 02/12] Add option to toggle whether @client directives are removed --- src/core/ApolloClient.ts | 2 + src/core/LocalState.ts | 13 +++-- src/core/QueryManager.ts | 8 ++- src/core/__tests__/QueryManager/links.ts | 63 ++++++++++++++++++++++++ src/core/types.ts | 10 +++- 5 files changed, 91 insertions(+), 5 deletions(-) diff --git a/src/core/ApolloClient.ts b/src/core/ApolloClient.ts index b26da37e579..96d11c56baf 100644 --- a/src/core/ApolloClient.ts +++ b/src/core/ApolloClient.ts @@ -20,6 +20,7 @@ import { RefetchQueriesResult, InternalRefetchQueriesResult, RefetchQueriesInclude, + TransformQueryOptions, } from './types'; import { @@ -39,6 +40,7 @@ export interface DefaultOptions { watchQuery?: Partial>; query?: Partial>; mutate?: Partial>; + transformQuery?: Partial; } let hasSuggestedDevtools = false; diff --git a/src/core/LocalState.ts b/src/core/LocalState.ts index e6e9518016b..d4c8fe4ee74 100644 --- a/src/core/LocalState.ts +++ b/src/core/LocalState.ts @@ -171,9 +171,16 @@ export class LocalState { return null; } - // Server queries are stripped of all @client based selection sets. - public serverQuery(document: DocumentNode) { - return removeClientSetsFromDocument(document); + // Server queries by default are stripped of all @client based selection sets. + public serverQuery( + document: DocumentNode, + options: { removeClientFields?: boolean } = Object.create(null) + ) { + const { removeClientFields = true } = options; + + return removeClientFields + ? removeClientSetsFromDocument(document) + : document; } public prepareContext(context?: Record) { diff --git a/src/core/QueryManager.ts b/src/core/QueryManager.ts index ecebf55c554..e568b7c31e7 100644 --- a/src/core/QueryManager.ts +++ b/src/core/QueryManager.ts @@ -52,6 +52,7 @@ import { InternalRefetchQueriesOptions, InternalRefetchQueriesResult, InternalRefetchQueriesMap, + TransformQueryOptions, } from './types'; import { LocalState } from './LocalState'; @@ -607,12 +608,17 @@ export class QueryManager { public transform(document: DocumentNode) { const { transformCache } = this; + const { + removeClientFields = true + } = this.defaultOptions.transformQuery || Object.create(null); if (!transformCache.has(document)) { const transformed = this.cache.transformDocument(document); const noConnection = removeConnectionDirectiveFromDocument(transformed); const clientQuery = this.localState.clientQuery(transformed); - const serverQuery = noConnection && this.localState.serverQuery(noConnection); + const serverQuery = + noConnection && + this.localState.serverQuery(noConnection, { removeClientFields }); const cacheEntry: TransformCacheEntry = { document: transformed, diff --git a/src/core/__tests__/QueryManager/links.ts b/src/core/__tests__/QueryManager/links.ts index b23fef69db5..3e5d511c6c4 100644 --- a/src/core/__tests__/QueryManager/links.ts +++ b/src/core/__tests__/QueryManager/links.ts @@ -404,4 +404,67 @@ describe('Link interactions', () => { expect(data).toEqual(bookData); }); + + it('sends client directives to the link when defaultOptions.transformQuery.removeClientFields is false', async () => { + const query = gql` + query { + books { + id + title + isRead @client + } + } + `; + + const expectedQuery = gql` + query { + books { + id + title + isRead @client + __typename + } + } + `; + + const bookData = { + books: [ + { id: 1, title: 'Woo', __typename: 'Book' }, + { id: 2, title: 'Foo', __typename: 'Book' }, + ], + }; + + const link = new ApolloLink((operation) => { + expect(print(operation.query)).toEqual(print(expectedQuery)) + + return Observable.of({ data: bookData }); + }); + + const queryManager = new QueryManager({ + link, + cache: new InMemoryCache({ + typePolicies: { + Book: { + fields: { + isRead: () => true + } + } + } + }), + defaultOptions: { + transformQuery: { + removeClientFields: false + } + } + }); + + const { data } = await queryManager.query({ query }); + + expect(data).toEqual({ + books: [ + { id: 1, title: 'Woo', isRead: true, __typename: 'Book' }, + { id: 2, title: 'Foo', isRead: true, __typename: 'Book' }, + ], + }) + }); }); diff --git a/src/core/types.ts b/src/core/types.ts index 9d34bd4050b..aa9fb2d9fbb 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -140,7 +140,7 @@ export type ApolloQueryResult = { */ errors?: ReadonlyArray; /** - * The single Error object that is passed to onError and useQuery hooks, and is often thrown during manual `client.query` calls. + * The single Error object that is passed to onError and useQuery hooks, and is often thrown during manual `client.query` calls. * This will contain both a NetworkError field and any GraphQLErrors. * See https://www.apollographql.com/docs/react/data/error-handling/ for more information. */ @@ -194,3 +194,11 @@ export interface Resolvers { [ field: string ]: Resolver; }; } + +export interface TransformQueryOptions { + /** + * Determines whether fields using the `@client` directive should be removed + * from the query before it is sent through the link chain. Defaults to `true`. + */ + removeClientFields?: boolean +} From b531a499327a484719a4efc0229de7482a8a32a4 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 13:25:44 -0700 Subject: [PATCH 03/12] Add tests for the client to prove client fields can be removed via options --- src/__tests__/client.ts | 91 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/src/__tests__/client.ts b/src/__tests__/client.ts index 322c14070ec..89cd387c747 100644 --- a/src/__tests__/client.ts +++ b/src/__tests__/client.ts @@ -1,5 +1,5 @@ import { cloneDeep, assign } from 'lodash'; -import { GraphQLError, ExecutionResult, DocumentNode } from 'graphql'; +import { GraphQLError, ExecutionResult, DocumentNode, print } from 'graphql'; import gql from 'graphql-tag'; import { @@ -8,6 +8,7 @@ import { WatchQueryFetchPolicy, QueryOptions, ObservableQuery, + Operation, TypedDocumentNode, } from '../core'; @@ -940,6 +941,94 @@ describe('client', () => { .then(resolve, reject); }); + it('removes client fields from the query before it reaches the link', async () => { + let operation: Operation; + + const query = gql` + query { + author { + firstName + lastName + isInCollection @client + } + } + `; + + const transformedQuery = gql` + query { + author { + firstName + lastName + } + } + `; + + const link = new ApolloLink((_operation) => { + operation = _operation + + return Observable.of({ + data: { + author: { + firstName: 'John', + lastName: 'Smith', + __typename: 'Author', + } + } + }); + }); + + const client = new ApolloClient({ + link, + cache: new InMemoryCache({ addTypename: false }), + }); + + await client.query({ query }); + + expect(print(operation!.query)).toEqual(print(transformedQuery)); + }) + + it('sends client fields to the link when defaultOptions.transformQuery.removeClientFields is `false`', async () => { + let operation: Operation; + + const query = gql` + query { + author { + firstName + lastName + isInCollection @client + } + } + `; + + const link = new ApolloLink((_operation) => { + operation = _operation + + return Observable.of({ + data: { + author: { + firstName: 'John', + lastName: 'Smith', + __typename: 'Author', + } + } + }); + }); + + const client = new ApolloClient({ + link, + cache: new InMemoryCache({ addTypename: false }), + defaultOptions: { + transformQuery: { + removeClientFields: false, + } + } + }); + + await client.query({ query }); + + expect(print(operation!.query)).toEqual(print(query)); + }) + itAsync('should handle named fragments on mutations', (resolve, reject) => { const mutation = gql` mutation { From 89e74d03ffac03e139298569223c6f6014956962 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 17:00:10 -0700 Subject: [PATCH 04/12] Remove unused import --- src/core/QueryManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/QueryManager.ts b/src/core/QueryManager.ts index e568b7c31e7..36b905ec43d 100644 --- a/src/core/QueryManager.ts +++ b/src/core/QueryManager.ts @@ -52,7 +52,6 @@ import { InternalRefetchQueriesOptions, InternalRefetchQueriesResult, InternalRefetchQueriesMap, - TransformQueryOptions, } from './types'; import { LocalState } from './LocalState'; From 1f4d871015f695177fc5495e178ef8dd94175420 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 17:29:36 -0700 Subject: [PATCH 05/12] Remove client-only fields in HttpLink --- src/link/http/__tests__/HttpLink.ts | 70 +++++++++++++++++++++++++++++ src/link/http/createHttpLink.ts | 16 ++++++- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/link/http/__tests__/HttpLink.ts b/src/link/http/__tests__/HttpLink.ts index 07f8e7d404e..3384ad49223 100644 --- a/src/link/http/__tests__/HttpLink.ts +++ b/src/link/http/__tests__/HttpLink.ts @@ -1014,6 +1014,76 @@ describe('HttpLink', () => { () => {}, ); }); + + it('removes client fields from the query before sending it to the server', async () => { + fetchMock.mock('https://example.com/graphql', { + status: 200, + body: JSON.stringify({ + data: { + author: { __typename: 'Author', name: 'Test User' } + } + }), + headers: { 'content-type': 'application/json' } + }); + + const query = gql` + query { + author { + name + isInCollection @client + } + } + `; + + const serverQuery = gql` + query { + author { + name + } + } + `; + + const link = createHttpLink({ uri: 'https://example.com/graphql' }); + + await new Promise((resolve, reject) => { + execute(link, { query }).subscribe({ + next: resolve, + error: reject + }); + }); + + const [, options] = fetchMock.lastCall()!; + const { body } = options! + + expect(JSON.parse(body!.toString())).toEqual({ + query: print(serverQuery), + variables: {} + }); + }); + + it('responds with error when trying to send a client-only query', async () => { + const errorHandler = jest.fn() + const query = gql` + query { + author @client { + name + } + } + `; + + const link = createHttpLink({ uri: 'https://example.com/graphql' }); + + await new Promise((resolve, reject) => { + execute(link, { query }).subscribe({ + next: reject, + error: errorHandler.mockImplementation(resolve) + }); + }); + + expect(errorHandler).toHaveBeenCalledWith( + new Error('HttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.') + ); + }) }); describe('Dev warnings', () => { diff --git a/src/link/http/createHttpLink.ts b/src/link/http/createHttpLink.ts index b97d9faf6f8..9b3542a517c 100644 --- a/src/link/http/createHttpLink.ts +++ b/src/link/http/createHttpLink.ts @@ -21,7 +21,7 @@ import { import { createSignalIfSupported } from './createSignalIfSupported'; import { rewriteURIForGET } from './rewriteURIForGET'; import { fromError } from '../utils'; -import { maybe } from '../../utilities'; +import { maybe, removeClientSetsFromDocument } from '../../utilities'; const backupFetch = maybe(() => fetch); @@ -86,6 +86,20 @@ export const createHttpLink = (linkOptions: HttpOptions = {}) => { headers: contextHeaders, }; + if (hasDirectives(['client'], operation.query)) { + const transformedQuery = removeClientSetsFromDocument(operation.query); + + if (!transformedQuery) { + return fromError( + new Error( + 'HttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.' + ) + ); + } + + operation.query = transformedQuery; + } + //uses fallback, link, and then context to build options const { options, body } = selectHttpOptionsAndBodyInternal( operation, From 990ff8aa4f0d2ed10c453f972f947c73013d8e47 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 18:05:38 -0700 Subject: [PATCH 06/12] Remove client-only fields in BatchHttpLink --- .../batch-http/__tests__/batchHttpLink.ts | 74 ++++++++++++++++++- src/link/batch-http/batchHttpLink.ts | 34 +++++++-- 2 files changed, 101 insertions(+), 7 deletions(-) diff --git a/src/link/batch-http/__tests__/batchHttpLink.ts b/src/link/batch-http/__tests__/batchHttpLink.ts index e9b22ef431c..8bcd776fbb5 100644 --- a/src/link/batch-http/__tests__/batchHttpLink.ts +++ b/src/link/batch-http/__tests__/batchHttpLink.ts @@ -582,7 +582,7 @@ describe('SharedHttpTest', () => { const variables = { params: 'stub' }; const link = createHttpLink({ uri: '/data', - headers: { + headers: { authorization: '1234', AUTHORIZATION: '1234', 'CONTENT-TYPE': 'application/json', @@ -898,4 +898,76 @@ describe('SharedHttpTest', () => { () => {}, ); }); + + it('removes client fields from the query before sending it to the server', async () => { + fetchMock.mock('https://example.com/graphql', { + status: 200, + body: JSON.stringify({ + data: { + author: { __typename: 'Author', name: 'Test User' } + } + }), + headers: { 'content-type': 'application/json' } + }); + + const query = gql` + query { + author { + name + isInCollection @client + } + } + `; + + const serverQuery = gql` + query { + author { + name + } + } + `; + + const link = createHttpLink({ uri: 'https://example.com/graphql' }); + + await new Promise((resolve, reject) => { + execute(link, { query }).subscribe({ + next: resolve, + error: reject + }); + }); + + const [, options] = fetchMock.lastCall()!; + const { body } = options! + + expect(JSON.parse(body!.toString())).toEqual([ + { + query: print(serverQuery), + variables: {} + } + ]); + }); + + it('responds with error when trying to send a client-only query', async () => { + const errorHandler = jest.fn() + const query = gql` + query { + author @client { + name + } + } + `; + + const link = createHttpLink({ uri: 'https://example.com/graphql' }); + + await new Promise((resolve, reject) => { + execute(link, { query }).subscribe({ + next: reject, + error: errorHandler.mockImplementation(resolve) + }); + }); + + expect(errorHandler).toHaveBeenCalledWith( + new Error('BatchHttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.') + ); + }); }); diff --git a/src/link/batch-http/batchHttpLink.ts b/src/link/batch-http/batchHttpLink.ts index 73c065f33a9..5f0ec3e5933 100644 --- a/src/link/batch-http/batchHttpLink.ts +++ b/src/link/batch-http/batchHttpLink.ts @@ -1,5 +1,9 @@ import { ApolloLink, Operation, FetchResult } from '../core'; -import { Observable } from '../../utilities'; +import { + Observable, + hasDirectives, + removeClientSetsFromDocument +} from '../../utilities'; import { fromError } from '../utils'; import { serializeFetchParameter, @@ -95,16 +99,34 @@ export class BatchHttpLink extends ApolloLink { headers: { ...clientAwarenessHeaders, ...context.headers }, }; + const queries = operations.map(({ query }) => { + if (hasDirectives(['client'], query)) { + return removeClientSetsFromDocument(query); + } + + return query + }); + + // If we have a query that returned `null` after removing client-only + // fields, it indicates a query that is using all client-only fields. + if (queries.some(query => !query)) { + return fromError( + new Error( + 'BatchHttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.' + ) + ); + } + //uses fallback, link, and then context to build options - const optsAndBody = operations.map(operation => - selectHttpOptionsAndBodyInternal( - operation, + const optsAndBody = operations.map((operation, index) => { + return selectHttpOptionsAndBodyInternal( + { ...operation, query: queries[index]! }, print, fallbackHttpConfig, linkConfig, contextConfig, - ), - ); + ) + }); const loadedBody = optsAndBody.map(({ body }) => body); const options = optsAndBody[0].options; From ee1ba02d97eded91c4ca35fe4296ad3ad620f6de Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 21:25:14 -0700 Subject: [PATCH 07/12] Minor changes to how test is setup for better readability --- src/__tests__/client.ts | 24 ++++---- src/core/__tests__/QueryManager/links.ts | 74 +++++++++++------------- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/__tests__/client.ts b/src/__tests__/client.ts index 89cd387c747..5193575d9d1 100644 --- a/src/__tests__/client.ts +++ b/src/__tests__/client.ts @@ -942,7 +942,9 @@ describe('client', () => { }); it('removes client fields from the query before it reaches the link', async () => { - let operation: Operation; + const result: { current: Operation | undefined } = { + current: undefined + } const query = gql` query { @@ -963,8 +965,8 @@ describe('client', () => { } `; - const link = new ApolloLink((_operation) => { - operation = _operation + const link = new ApolloLink((operation) => { + result.current = operation; return Observable.of({ data: { @@ -984,11 +986,13 @@ describe('client', () => { await client.query({ query }); - expect(print(operation!.query)).toEqual(print(transformedQuery)); - }) + expect(print(result.current!.query)).toEqual(print(transformedQuery)); + }); it('sends client fields to the link when defaultOptions.transformQuery.removeClientFields is `false`', async () => { - let operation: Operation; + const result: { current: Operation | undefined } = { + current: undefined + }; const query = gql` query { @@ -1000,8 +1004,8 @@ describe('client', () => { } `; - const link = new ApolloLink((_operation) => { - operation = _operation + const link = new ApolloLink((operation) => { + result.current = operation return Observable.of({ data: { @@ -1026,8 +1030,8 @@ describe('client', () => { await client.query({ query }); - expect(print(operation!.query)).toEqual(print(query)); - }) + expect(print(result.current!.query)).toEqual(print(query)); + }); itAsync('should handle named fragments on mutations', (resolve, reject) => { const mutation = gql` diff --git a/src/core/__tests__/QueryManager/links.ts b/src/core/__tests__/QueryManager/links.ts index 3e5d511c6c4..4172b346719 100644 --- a/src/core/__tests__/QueryManager/links.ts +++ b/src/core/__tests__/QueryManager/links.ts @@ -362,7 +362,11 @@ describe('Link interactions', () => { }); }); - it('strips client directives from the query before it reaches the link', async () => { + it('removes client fields from the query before it reaches the link', async () => { + const result: { current: Operation | undefined } = { + current: undefined + }; + const query = gql` query { books { @@ -382,17 +386,17 @@ describe('Link interactions', () => { } `; - const bookData = { - books: [ - { id: 1, title: 'Woo', __typename: 'Book' }, - { id: 2, title: 'Foo', __typename: 'Book' }, - ], - }; - const link = new ApolloLink((operation) => { - expect(print(operation.query)).toEqual(print(expectedQuery)) - - return Observable.of({ data: bookData }); + result.current = operation; + + return Observable.of({ + data: { + books: [ + { id: 1, title: 'Woo', __typename: 'Book' }, + { id: 2, title: 'Foo', __typename: 'Book' }, + ], + } + }); }); const queryManager = new QueryManager({ @@ -400,12 +404,16 @@ describe('Link interactions', () => { cache: new InMemoryCache({ addTypename: false }), }); - const { data } = await queryManager.query({ query }); + await queryManager.query({ query }); - expect(data).toEqual(bookData); + expect(print(result.current!.query)).toEqual(print(expectedQuery)) }); it('sends client directives to the link when defaultOptions.transformQuery.removeClientFields is false', async () => { + const result: { current: Operation | undefined } = { + current: undefined + }; + const query = gql` query { books { @@ -422,35 +430,26 @@ describe('Link interactions', () => { id title isRead @client - __typename } } `; - const bookData = { - books: [ - { id: 1, title: 'Woo', __typename: 'Book' }, - { id: 2, title: 'Foo', __typename: 'Book' }, - ], - }; - const link = new ApolloLink((operation) => { - expect(print(operation.query)).toEqual(print(expectedQuery)) - - return Observable.of({ data: bookData }); + result.current = operation; + + return Observable.of({ + data: { + books: [ + { id: 1, title: 'Woo', __typename: 'Book' }, + { id: 2, title: 'Foo', __typename: 'Book' }, + ], + } + }); }); const queryManager = new QueryManager({ link, - cache: new InMemoryCache({ - typePolicies: { - Book: { - fields: { - isRead: () => true - } - } - } - }), + cache: new InMemoryCache({ addTypename: false }), defaultOptions: { transformQuery: { removeClientFields: false @@ -458,13 +457,8 @@ describe('Link interactions', () => { } }); - const { data } = await queryManager.query({ query }); + await queryManager.query({ query }); - expect(data).toEqual({ - books: [ - { id: 1, title: 'Woo', isRead: true, __typename: 'Book' }, - { id: 2, title: 'Foo', isRead: true, __typename: 'Book' }, - ], - }) + expect(print(result.current!.query)).toEqual(print(expectedQuery)) }); }); From be3e98eea269af5fbf9f400ab142c55cb4d617d3 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 21:32:38 -0700 Subject: [PATCH 08/12] Add changeset --- .changeset/rude-mayflies-scream.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/rude-mayflies-scream.md diff --git a/.changeset/rude-mayflies-scream.md b/.changeset/rude-mayflies-scream.md new file mode 100644 index 00000000000..d3896e963a9 --- /dev/null +++ b/.changeset/rude-mayflies-scream.md @@ -0,0 +1,5 @@ +--- +'@apollo/client': minor +--- + +Add the ability to allow `@client` fields to be sent to the link chain. From 7dd28bc6c2b9fec482a1132e0666492c1e75addf Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 22:17:36 -0700 Subject: [PATCH 09/12] Fix some code formatting --- src/link/batch-http/batchHttpLink.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/link/batch-http/batchHttpLink.ts b/src/link/batch-http/batchHttpLink.ts index 5f0ec3e5933..75dec9d3586 100644 --- a/src/link/batch-http/batchHttpLink.ts +++ b/src/link/batch-http/batchHttpLink.ts @@ -104,7 +104,7 @@ export class BatchHttpLink extends ApolloLink { return removeClientSetsFromDocument(query); } - return query + return query; }); // If we have a query that returned `null` after removing client-only @@ -118,15 +118,15 @@ export class BatchHttpLink extends ApolloLink { } //uses fallback, link, and then context to build options - const optsAndBody = operations.map((operation, index) => { - return selectHttpOptionsAndBodyInternal( + const optsAndBody = operations.map((operation, index) => + selectHttpOptionsAndBodyInternal( { ...operation, query: queries[index]! }, print, fallbackHttpConfig, linkConfig, contextConfig, - ) - }); + ), + ); const loadedBody = optsAndBody.map(({ body }) => body); const options = optsAndBody[0].options; From 43b532b7922b69958ff0cca86e1e28cbfa61e716 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Fri, 9 Dec 2022 22:19:14 -0700 Subject: [PATCH 10/12] Minor change to name of some tests --- src/__tests__/client.ts | 4 ++-- src/core/__tests__/QueryManager/links.ts | 4 ++-- src/link/batch-http/__tests__/batchHttpLink.ts | 2 +- src/link/http/__tests__/HttpLink.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/__tests__/client.ts b/src/__tests__/client.ts index 5193575d9d1..1abff321499 100644 --- a/src/__tests__/client.ts +++ b/src/__tests__/client.ts @@ -941,7 +941,7 @@ describe('client', () => { .then(resolve, reject); }); - it('removes client fields from the query before it reaches the link', async () => { + it('removes @client fields from the query before it reaches the link', async () => { const result: { current: Operation | undefined } = { current: undefined } @@ -989,7 +989,7 @@ describe('client', () => { expect(print(result.current!.query)).toEqual(print(transformedQuery)); }); - it('sends client fields to the link when defaultOptions.transformQuery.removeClientFields is `false`', async () => { + it('sends @client fields to the link when defaultOptions.transformQuery.removeClientFields is `false`', async () => { const result: { current: Operation | undefined } = { current: undefined }; diff --git a/src/core/__tests__/QueryManager/links.ts b/src/core/__tests__/QueryManager/links.ts index 4172b346719..ccee150703b 100644 --- a/src/core/__tests__/QueryManager/links.ts +++ b/src/core/__tests__/QueryManager/links.ts @@ -362,7 +362,7 @@ describe('Link interactions', () => { }); }); - it('removes client fields from the query before it reaches the link', async () => { + it('removes @client fields from the query before it reaches the link', async () => { const result: { current: Operation | undefined } = { current: undefined }; @@ -409,7 +409,7 @@ describe('Link interactions', () => { expect(print(result.current!.query)).toEqual(print(expectedQuery)) }); - it('sends client directives to the link when defaultOptions.transformQuery.removeClientFields is false', async () => { + it('sends @client fields to the link when defaultOptions.transformQuery.removeClientFields is false', async () => { const result: { current: Operation | undefined } = { current: undefined }; diff --git a/src/link/batch-http/__tests__/batchHttpLink.ts b/src/link/batch-http/__tests__/batchHttpLink.ts index 8bcd776fbb5..bbaf12bedd5 100644 --- a/src/link/batch-http/__tests__/batchHttpLink.ts +++ b/src/link/batch-http/__tests__/batchHttpLink.ts @@ -899,7 +899,7 @@ describe('SharedHttpTest', () => { ); }); - it('removes client fields from the query before sending it to the server', async () => { + it('removes @client fields from the query before sending it to the server', async () => { fetchMock.mock('https://example.com/graphql', { status: 200, body: JSON.stringify({ diff --git a/src/link/http/__tests__/HttpLink.ts b/src/link/http/__tests__/HttpLink.ts index 3384ad49223..58f814377a6 100644 --- a/src/link/http/__tests__/HttpLink.ts +++ b/src/link/http/__tests__/HttpLink.ts @@ -1015,7 +1015,7 @@ describe('HttpLink', () => { ); }); - it('removes client fields from the query before sending it to the server', async () => { + it('removes @client fields from the query before sending it to the server', async () => { fetchMock.mock('https://example.com/graphql', { status: 200, body: JSON.stringify({ From 466b930a41e3d3975b43758469f19958c0549c51 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 21 Dec 2022 11:19:06 -0700 Subject: [PATCH 11/12] Update bundlesize --- config/bundlesize.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bundlesize.ts b/config/bundlesize.ts index 7c005a5ead0..33b1cd94112 100644 --- a/config/bundlesize.ts +++ b/config/bundlesize.ts @@ -3,7 +3,7 @@ import { join } from "path"; import { gzipSync } from "zlib"; import bytes from "bytes"; -const gzipBundleByteLengthLimit = bytes("33.01KB"); +const gzipBundleByteLengthLimit = bytes("33.17KB"); const minFile = join("dist", "apollo-client.min.cjs"); const minPath = join(__dirname, "..", minFile); const gzipByteLen = gzipSync(readFileSync(minPath)).byteLength; From 48f629445a424834ed106e30ca348a2892f5cd11 Mon Sep 17 00:00:00 2001 From: Jerel Miller Date: Wed, 21 Dec 2022 13:20:32 -0700 Subject: [PATCH 12/12] Update error message to be less ambiguous --- src/link/http/__tests__/HttpLink.ts | 2 +- src/link/http/createHttpLink.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/link/http/__tests__/HttpLink.ts b/src/link/http/__tests__/HttpLink.ts index 58f814377a6..8b24a8f54bd 100644 --- a/src/link/http/__tests__/HttpLink.ts +++ b/src/link/http/__tests__/HttpLink.ts @@ -1081,7 +1081,7 @@ describe('HttpLink', () => { }); expect(errorHandler).toHaveBeenCalledWith( - new Error('HttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.') + new Error('HttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or set the `transformOptions.removeClientFields` option to `true`.') ); }) }); diff --git a/src/link/http/createHttpLink.ts b/src/link/http/createHttpLink.ts index 9b3542a517c..8bf2b41e107 100644 --- a/src/link/http/createHttpLink.ts +++ b/src/link/http/createHttpLink.ts @@ -92,7 +92,7 @@ export const createHttpLink = (linkOptions: HttpOptions = {}) => { if (!transformedQuery) { return fromError( new Error( - 'HttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or enable the `transformOptions.removeClientFields` option.' + 'HttpLink: Trying to send a client-only query to the server. To send to the server, ensure a non-client field is added to the query or set the `transformOptions.removeClientFields` option to `true`.' ) ); }