diff --git a/examples/demo/package.json b/examples/demo/package.json index 4aa2256f406..edeecb0e7c7 100644 --- a/examples/demo/package.json +++ b/examples/demo/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "dependencies": { - "@apollo/client": "^3.12.4", + "@apollo/client": "^4.1.6", "@mui/icons-material": "^7.0.0", "@mui/material": "^7.0.0", "@types/recharts": "^1.8.10", @@ -14,7 +14,7 @@ "date-fns": "^3.6.0", "echarts": "^5.6.0", "fakerest": "^4.2.0", - "graphql": "^15.6.0", + "graphql": "^16.13.2", "graphql-tag": "^2.12.6", "inflection": "^3.0.0", "json-graphql-server": "^3.0.1", @@ -30,7 +30,8 @@ "react-admin": "^5.0.0", "react-dom": "^19.0.0", "react-router": "^7.1.1", - "react-router-dom": "^7.1.1" + "react-router-dom": "^7.1.1", + "rxjs": "^7.8.2" }, "scripts": { "dev": "vite", diff --git a/examples/demo/src/dataProvider/graphql.ts b/examples/demo/src/dataProvider/graphql.ts index 13738b59f98..be8ce2ee0fd 100644 --- a/examples/demo/src/dataProvider/graphql.ts +++ b/examples/demo/src/dataProvider/graphql.ts @@ -1,4 +1,3 @@ -import { ApolloQueryResult } from '@apollo/client'; import buildApolloClient, { buildQuery as buildQueryFactory, } from 'ra-data-graphql-simple'; @@ -44,7 +43,7 @@ const customBuildQuery: BuildQueryFactory = introspectionResults => { } }`, variables: { id: params.id }, - parseResponse: ({ data }: ApolloQueryResult) => { + parseResponse: ({ data }) => { if (data[`remove${resource}`]) { return { data: { id: params.id } }; } @@ -98,7 +97,7 @@ const customBuildQuery: BuildQueryFactory = introspectionResults => { } `, variables: params.data, - parseResponse: ({ data }: ApolloQueryResult) => { + parseResponse: ({ data }) => { if (data.createCustomer) { return { data: { id: data.createCustomer.id } }; } diff --git a/packages/ra-data-graphql-simple/README.md b/packages/ra-data-graphql-simple/README.md index be7507e5ad9..8020ddb4c77 100644 --- a/packages/ra-data-graphql-simple/README.md +++ b/packages/ra-data-graphql-simple/README.md @@ -14,15 +14,18 @@ built with [Apollo](https://www.apollodata.com/) and tailored to target a simple Install with: ```sh -npm install --save graphql ra-data-graphql-simple +npm install --save graphql rxjs ra-data-graphql-simple ``` or ```sh -yarn add graphql ra-data-graphql-simple +yarn add graphql rxjs ra-data-graphql-simple ``` +This package is built on Apollo Client 4, which requires `graphql` 16 or later and +`rxjs` 7.3 or later. Both are peer dependencies, so your application provides them. + ## Usage The `ra-data-graphql-simple` package exposes a single function, which is a constructor for a `dataProvider` based on a GraphQL endpoint. When executed, this function calls the GraphQL endpoint, running an [introspection](https://graphql.org/learn/introspection/) query. It uses the result of this query (the GraphQL schema) to automatically configure the `dataProvider` accordingly. diff --git a/packages/ra-data-graphql-simple/package.json b/packages/ra-data-graphql-simple/package.json index 4f0752bd1f0..018d91233cd 100644 --- a/packages/ra-data-graphql-simple/package.json +++ b/packages/ra-data-graphql-simple/package.json @@ -32,18 +32,20 @@ "build": "zshy --silent" }, "dependencies": { - "@apollo/client": "^3.3.19", + "@apollo/client": "^4.1.6", "graphql-ast-types-browser": "~1.0.2", "lodash": "~4.18.1", "pluralize": "~7.0.0", "ra-data-graphql": "^5.14.7" }, "peerDependencies": { - "graphql": "^15.6.0", - "ra-core": "^5.0.0" + "graphql": "^16.0.0 || ^17.0.0", + "ra-core": "^5.0.0", + "rxjs": "^7.3.0" }, "devDependencies": { - "graphql": "^15.6.0", + "graphql": "^16.13.2", + "rxjs": "^7.8.2", "typescript": "^5.1.3", "zshy": "^0.5.0" }, diff --git a/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts b/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts index 5e502ffc4a0..6e1f65402e7 100644 --- a/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts +++ b/packages/ra-data-graphql-simple/src/buildGqlQuery.test.ts @@ -995,8 +995,7 @@ describe('buildGqlQuery', () => { data: deleteCommands(ids: $ids) { ids } -} -` +}` ); }); @@ -1018,8 +1017,7 @@ describe('buildGqlQuery', () => { data: updateCommands(ids: $ids, data: $data) { ids } -} -` +}` ); }); }); diff --git a/packages/ra-data-graphql-simple/src/getGqlType.test.ts b/packages/ra-data-graphql-simple/src/getGqlType.test.ts index a65847104ae..9cc7a1d16aa 100644 --- a/packages/ra-data-graphql-simple/src/getGqlType.test.ts +++ b/packages/ra-data-graphql-simple/src/getGqlType.test.ts @@ -1,4 +1,10 @@ -import { TypeKind, print } from 'graphql'; +import { + buildSchema, + getIntrospectionQuery, + graphqlSync, + print, + TypeKind, +} from 'graphql'; import { getGqlType } from './getGqlType'; describe('getGqlType', () => { @@ -106,4 +112,76 @@ describe('getGqlType', () => { ) ).toEqual('[[ID!]]!'); }); + + it('returns the arg type for a named type carrying a null ofType', () => { + expect( + print( + getGqlType({ + kind: TypeKind.SCALAR, + name: 'foo', + ofType: null, + }) + ) + ).toEqual('foo'); + }); + + it('returns the arg type for wrapped types carrying a null ofType', () => { + expect( + print( + getGqlType({ + kind: TypeKind.NON_NULL, + name: null, + ofType: { + kind: TypeKind.LIST, + name: null, + ofType: { + kind: TypeKind.NON_NULL, + name: null, + ofType: { + kind: TypeKind.SCALAR, + name: 'ID', + ofType: null, + }, + }, + }, + }) + ) + ).toEqual('[ID!]!'); + }); + + it('prints every argument type of a real introspection result', () => { + const schema = buildSchema(` + input CommandInput { id: ID } + type Command { id: ID! } + type Query { + command( + id: ID! + tags: [String] + requiredTags: [String!]! + nested: [[Int!]]! + input: CommandInput + ): Command + } + `); + const introspection = graphqlSync({ + schema, + source: getIntrospectionQuery(), + }); + const types = (introspection.data as any).__schema.types; + const args = types + .find(type => type.name === 'Query') + .fields.find(field => field.name === 'command').args; + + expect( + Object.fromEntries( + args.map(arg => [arg.name, print(getGqlType(arg.type))]) + ) + ).toEqual({ + id: 'ID!', + tags: '[String]', + requiredTags: '[String!]!', + nested: '[[Int!]]!', + input: 'CommandInput', + }); + }); }); diff --git a/packages/ra-data-graphql-simple/src/getGqlType.ts b/packages/ra-data-graphql-simple/src/getGqlType.ts index b827c7189a9..c5e7b8f2fd7 100644 --- a/packages/ra-data-graphql-simple/src/getGqlType.ts +++ b/packages/ra-data-graphql-simple/src/getGqlType.ts @@ -1,5 +1,4 @@ import { - IntrospectionListTypeRef, IntrospectionType, IntrospectionTypeRef, TypeKind, @@ -7,17 +6,19 @@ import { } from 'graphql'; import * as gqlTypes from 'graphql-ast-types-browser'; +const isWrappingTypeRef = ( + type: IntrospectionType | IntrospectionTypeRef +): type is Extract => + type.kind === TypeKind.LIST || type.kind === TypeKind.NON_NULL; + export const getGqlType = ( - type: IntrospectionType | IntrospectionListTypeRef | IntrospectionTypeRef + type: IntrospectionType | IntrospectionTypeRef ): TypeNode => { - switch (type.kind) { - case TypeKind.LIST: - return gqlTypes.listType(getGqlType(type.ofType)); - - case TypeKind.NON_NULL: - return gqlTypes.nonNullType(getGqlType(type.ofType)); - - default: - return gqlTypes.namedType(gqlTypes.name(type.name)); + if (isWrappingTypeRef(type)) { + return type.kind === TypeKind.LIST + ? gqlTypes.listType(getGqlType(type.ofType)) + : gqlTypes.nonNullType(getGqlType(type.ofType)); } + + return gqlTypes.namedType(gqlTypes.name(type.name)); }; diff --git a/packages/ra-data-graphql-simple/src/getResponseParser.ts b/packages/ra-data-graphql-simple/src/getResponseParser.ts index cbe3135efdb..a69ce5ccd3b 100644 --- a/packages/ra-data-graphql-simple/src/getResponseParser.ts +++ b/packages/ra-data-graphql-simple/src/getResponseParser.ts @@ -7,7 +7,7 @@ import { } from 'ra-core'; import { IntrospectionResult, IntrospectedResource } from 'ra-data-graphql'; import { IntrospectionField } from 'graphql'; -import { ApolloQueryResult } from '@apollo/client'; +import { ApolloClient } from '@apollo/client'; export default (_introspectionResults: IntrospectionResult) => ( @@ -15,7 +15,7 @@ export default (_introspectionResults: IntrospectionResult) => _resource: IntrospectedResource, _queryType: IntrospectionField ) => - (response: ApolloQueryResult) => { + (response: ApolloClient.QueryResult) => { const data = response.data; if ( diff --git a/packages/ra-data-graphql/README.md b/packages/ra-data-graphql/README.md index 145a12a5a62..9fff2899e6a 100644 --- a/packages/ra-data-graphql/README.md +++ b/packages/ra-data-graphql/README.md @@ -28,15 +28,18 @@ Below is a rough graph summarizing how the data flows: Install with: ```sh -npm install --save graphql ra-data-graphql +npm install --save graphql rxjs ra-data-graphql ``` or ```sh -yarn add graphql ra-data-graphql +yarn add graphql rxjs ra-data-graphql ``` +This package is built on Apollo Client 4, which requires `graphql` 16 or later and +`rxjs` 7.3 or later. Both are peer dependencies, so your application provides them. + ## Usage Build the data provider on mount, and pass it to the `` component when ready: diff --git a/packages/ra-data-graphql/package.json b/packages/ra-data-graphql/package.json index 37a4519a5e6..9ffdbdb2c95 100644 --- a/packages/ra-data-graphql/package.json +++ b/packages/ra-data-graphql/package.json @@ -32,17 +32,19 @@ "build": "zshy --silent" }, "dependencies": { - "@apollo/client": "^3.3.19", + "@apollo/client": "^4.1.6", "graphql-tag": "^2.12.6", "lodash": "~4.18.1", "pluralize": "~7.0.0" }, "peerDependencies": { - "graphql": "^15.6.0 || ^16", - "ra-core": "^5.0.0" + "graphql": "^16.0.0 || ^17.0.0", + "ra-core": "^5.0.0", + "rxjs": "^7.3.0" }, "devDependencies": { - "graphql": "^15.6.0", + "graphql": "^16.13.2", + "rxjs": "^7.8.2", "typescript": "^5.1.3", "zshy": "^0.5.0" }, diff --git a/packages/ra-data-graphql/src/buildApolloClient.test.ts b/packages/ra-data-graphql/src/buildApolloClient.test.ts new file mode 100644 index 00000000000..5157cc689f2 --- /dev/null +++ b/packages/ra-data-graphql/src/buildApolloClient.test.ts @@ -0,0 +1,76 @@ +import { HttpLink } from '@apollo/client'; +import gql from 'graphql-tag'; + +import buildApolloClient from './buildApolloClient'; + +const okResponse = () => + Promise.resolve( + new Response(JSON.stringify({ data: { foo: 'bar' } }), { + status: 200, + headers: { 'content-type': 'application/json' }, + }) + ); + +describe('buildApolloClient', () => { + let fetchSpy; + + beforeEach(() => { + fetchSpy = jest + .spyOn(globalThis, 'fetch') + .mockImplementation(okResponse as any); + }); + + afterEach(() => { + fetchSpy.mockRestore(); + }); + + const runQuery = async client => { + await client.query({ + query: gql` + query { + foo + } + `, + fetchPolicy: 'no-cache', + }); + return fetchSpy.mock.calls[0]; + }; + + it('sends the query to the uri passed in options', async () => { + const client = buildApolloClient({ + uri: 'http://example.com/graphql', + }); + + const [url] = await runQuery(client); + + expect(String(url)).toBe('http://example.com/graphql'); + }); + + it('forwards credentials and headers to the HttpLink', async () => { + const client = buildApolloClient({ + uri: 'http://example.com/graphql', + credentials: 'include', + headers: { 'X-Custom': 'yes' }, + }); + + const [, init] = await runQuery(client); + + expect(init.credentials).toBe('include'); + expect(new Headers(init.headers).get('X-Custom')).toBe('yes'); + }); + + it('lets an explicit link take precedence over uri', async () => { + const client = buildApolloClient({ + uri: 'http://ignored.example.com/graphql', + link: new HttpLink({ uri: 'http://explicit.example.com/graphql' }), + }); + + const [url] = await runQuery(client); + + expect(String(url)).toBe('http://explicit.example.com/graphql'); + }); + + it('builds a client without any options', () => { + expect(buildApolloClient().link).toBeDefined(); + }); +}); diff --git a/packages/ra-data-graphql/src/buildApolloClient.ts b/packages/ra-data-graphql/src/buildApolloClient.ts index f6e488df3e7..29ccc6ef78b 100644 --- a/packages/ra-data-graphql/src/buildApolloClient.ts +++ b/packages/ra-data-graphql/src/buildApolloClient.ts @@ -1,14 +1,24 @@ import { ApolloClient, - ApolloClientOptions, - HttpLink, InMemoryCache, + HttpLink, + type ApolloClientOptions, } from '@apollo/client'; -export default (options?: Partial>) => { +/** + * Apollo Client 4 moved `uri`, `credentials` and `headers` out of the client + * options: they are HttpLink options now. We keep accepting them here and + * forward them to the HttpLink we build, so that + * `buildGraphQLProvider({ clientOptions: { uri } })` keeps working. + */ +export type BuildApolloClientOptions = Partial & + Pick; + +export default (options?: BuildApolloClientOptions) => { if (!options) { return new ApolloClient({ cache: new InMemoryCache().restore({}), + link: new HttpLink({}), }); } @@ -17,7 +27,7 @@ export default (options?: Partial>) => { uri, credentials, headers, - link = uri ? new HttpLink({ uri, credentials, headers }) : undefined, + link = new HttpLink({ uri, credentials, headers }), ...otherOptions } = options; diff --git a/packages/ra-data-graphql/src/index.test.ts b/packages/ra-data-graphql/src/index.test.ts index 51bd7f1fb1e..df6e5e562df 100644 --- a/packages/ra-data-graphql/src/index.test.ts +++ b/packages/ra-data-graphql/src/index.test.ts @@ -1,4 +1,8 @@ -import { ApolloClient, ApolloError } from '@apollo/client'; +import { + ApolloClient, + CombinedGraphQLErrors, + ServerError, +} from '@apollo/client'; import { GraphQLError } from 'graphql'; import gql from 'graphql-tag'; @@ -7,12 +11,10 @@ import buildDataProvider, { BuildQueryFactory } from './index'; describe('GraphQL data provider', () => { describe('mutate', () => { describe('with error', () => { - it('sets ApolloError in body', async () => { + const buildDataProviderThrowing = (error: unknown) => { const mockClient = { mutate: async () => { - throw new ApolloError({ - graphQLErrors: [new GraphQLError('some error')], - }); + throw error; }, }; const mockBuildQueryFactory = () => { @@ -27,22 +29,52 @@ describe('GraphQL data provider', () => { parseResponse: () => ({}), }); }; - const dataProvider = await buildDataProvider({ - client: mockClient as unknown as ApolloClient, + return buildDataProvider({ + client: mockClient as unknown as ApolloClient, introspection: false, buildQuery: mockBuildQueryFactory as unknown as BuildQueryFactory, }); + }; + + const update = dataProvider => + dataProvider.update('myResource', { + id: 1, + previousData: { id: 1 }, + data: {}, + }); + + it('sets the GraphQL errors in body', async () => { + const dataProvider = buildDataProviderThrowing( + new CombinedGraphQLErrors({ + errors: [new GraphQLError('some error')], + }) + ); try { - await dataProvider.update('myResource', { - id: 1, - previousData: { id: 1 }, - data: {}, - }); + await update(dataProvider); } catch (error) { - expect(error.body).not.toBeNull(); - expect(error.body.graphQLErrors).toBeDefined(); + expect(error.status).toBe(200); expect(error.body.graphQLErrors).toHaveLength(1); + expect(error.body.graphQLErrors[0].message).toBe( + 'some error' + ); + return; + } + fail('expected data provider to throw an error'); + }); + + it('sets the status code of a server error', async () => { + const dataProvider = buildDataProviderThrowing( + new ServerError('Service Unavailable', { + response: new Response('', { status: 503 }), + bodyText: '', + }) + ); + try { + await update(dataProvider); + } catch (error) { + expect(error.status).toBe(503); + expect(error.message).toBe('Service Unavailable'); return; } fail('expected data provider to throw an error'); @@ -81,7 +113,7 @@ describe('GraphQL data provider', () => { }; const dataProvider = buildDataProvider({ - client: client as unknown as ApolloClient, + client: client as unknown as ApolloClient, buildQuery: () => () => undefined, }); diff --git a/packages/ra-data-graphql/src/index.ts b/packages/ra-data-graphql/src/index.ts index 0aefac5aad7..fb8101a16f0 100644 --- a/packages/ra-data-graphql/src/index.ts +++ b/packages/ra-data-graphql/src/index.ts @@ -16,17 +16,19 @@ import { } from 'ra-core'; import { ApolloClient, - ApolloClientOptions, - ApolloError, - ApolloQueryResult, + CombinedGraphQLErrors, + CombinedProtocolErrors, MutationOptions, WatchQueryOptions, QueryOptions, OperationVariables, ServerError, + ServerParseError, } from '@apollo/client'; -import buildApolloClient from './buildApolloClient'; +import buildApolloClient, { + BuildApolloClientOptions, +} from './buildApolloClient'; import { QUERY_TYPES as INNER_QUERY_TYPES, MUTATION_TYPES as INNER_MUTATION_TYPES, @@ -39,6 +41,7 @@ import { } from './introspection'; export * from './introspection'; +export type { BuildApolloClientOptions } from './buildApolloClient'; export const QUERY_TYPES = INNER_QUERY_TYPES; export const MUTATION_TYPES = INNER_MUTATION_TYPES; export const ALL_TYPES = INNER_ALL_TYPES; @@ -90,7 +93,7 @@ const getOptions = ( }; export type BuildQueryResult = QueryOptions & { - parseResponse: (response: ApolloQueryResult) => any; + parseResponse: (response: ApolloClient.QueryResult) => any; }; export type BuildQuery = ( @@ -119,8 +122,8 @@ export type GetWatchQueryOptions = ( ) => Partial>; export type Options = { - client?: ApolloClient; - clientOptions?: Partial>; + client?: ApolloClient; + clientOptions?: BuildApolloClientOptions; introspection?: false | Partial; override?: { [key: string]: (params: any) => BuildQueryResult; @@ -254,15 +257,26 @@ const buildGraphQLProvider = (options: Options): GraphqlDataProvider => { return raDataProvider; }; -const handleError = (error: ApolloError) => { - if (error?.networkError as ServerError) { - throw new HttpError( - (error?.networkError as ServerError)?.message, - (error?.networkError as ServerError)?.statusCode - ); +const handleError = (error: unknown) => { + // Apollo Client 4 replaced the single ApolloError, which carried a + // `networkError` and a `graphQLErrors` field, with one class per error kind. + if (ServerError.is(error) || ServerParseError.is(error)) { + throw new HttpError(error.message, error.statusCode); + } + + // `body.graphQLErrors` is kept for backwards compatibility: that is where + // the ApolloError of Apollo Client 3 used to expose them. + if (CombinedGraphQLErrors.is(error) || CombinedProtocolErrors.is(error)) { + throw new HttpError(error.message, 200, { + graphQLErrors: error.errors, + }); } - throw new HttpError(error.message, 200, error); + throw new HttpError( + error instanceof Error ? error.message : String(error), + 200, + error + ); }; const getQueryOperation = query => { @@ -276,7 +290,7 @@ const getQueryOperation = query => { export type GetIntrospection = () => Promise; export type GraphqlDataProvider = DataProvider & { getIntrospection: GetIntrospection; - client: ApolloClient; + client: ApolloClient; }; export default buildGraphQLProvider; diff --git a/packages/ra-data-graphql/src/introspection.ts b/packages/ra-data-graphql/src/introspection.ts index 9d389923207..76a035677a0 100644 --- a/packages/ra-data-graphql/src/introspection.ts +++ b/packages/ra-data-graphql/src/introspection.ts @@ -15,7 +15,7 @@ import { ALL_TYPES } from './constants'; * @param {Object} options The introspection options */ export const introspectSchema = async ( - client: ApolloClient, + client: ApolloClient, options: IntrospectionOptions ) => { const schema = options.schema ? options.schema : await fetchSchema(client); @@ -50,9 +50,7 @@ export type IntrospectionResult = { schema: IntrospectionSchema; }; -const fetchSchema = ( - client: ApolloClient -): Promise => +const fetchSchema = (client: ApolloClient): Promise => client .query({ fetchPolicy: 'network-only', @@ -60,7 +58,14 @@ const fetchSchema = ( ${getIntrospectionQuery()} `, }) - .then(({ data: { __schema } }) => __schema); + .then(({ data }) => { + if (!data) { + throw new Error( + 'The GraphQL schema introspection returned no data' + ); + } + return data.__schema; + }); const getQueriesFromSchema = ( schema: IntrospectionSchema diff --git a/yarn.lock b/yarn.lock index ee7293671ba..7eb4ea0ab0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35,7 +35,7 @@ __metadata: languageName: node linkType: hard -"@apollo/client@npm:^3.12.4, @apollo/client@npm:^3.3.19, @apollo/client@npm:^3.9.11": +"@apollo/client@npm:^3.9.11": version: 3.12.4 resolution: "@apollo/client@npm:3.12.4" dependencies: @@ -72,6 +72,37 @@ __metadata: languageName: node linkType: hard +"@apollo/client@npm:^4.1.6": + version: 4.2.9 + resolution: "@apollo/client@npm:4.2.9" + dependencies: + "@graphql-typed-document-node/core": "npm:^3.1.1" + "@wry/caches": "npm:^1.0.0" + "@wry/equality": "npm:^0.5.6" + "@wry/trie": "npm:^0.5.0" + graphql-tag: "npm:^2.12.6" + optimism: "npm:^0.18.0" + tslib: "npm:^2.3.0" + peerDependencies: + graphql: ^16.0.0 || ^17.0.0 + graphql-ws: ^5.5.5 || ^6.0.3 + react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^17.0.0 || ^18.0.0 || >=19.0.0-rc + rxjs: ^7.3.0 + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + checksum: 89d22061b58556da51c593fb2be0d8b930805f1c0ffb4720e79d723549777387b388831c3ca5dcc711961bc3ab9dbf0abf5885c5901fef29e7789aef9cead61c + languageName: node + linkType: hard + "@astrojs/compiler@npm:^2.9.1": version: 2.13.0 resolution: "@astrojs/compiler@npm:2.13.0" @@ -10725,7 +10756,7 @@ __metadata: version: 0.0.0-use.local resolution: "demo@workspace:examples/demo" dependencies: - "@apollo/client": "npm:^3.12.4" + "@apollo/client": "npm:^4.1.6" "@mui/icons-material": "npm:^7.0.0" "@mui/material": "npm:^7.0.0" "@types/jest": "npm:^29.5.2" @@ -10739,7 +10770,7 @@ __metadata: date-fns: "npm:^3.6.0" echarts: "npm:^5.6.0" fakerest: "npm:^4.2.0" - graphql: "npm:^15.6.0" + graphql: "npm:^16.13.2" graphql-tag: "npm:^2.12.6" inflection: "npm:^3.0.0" json-graphql-server: "npm:^3.0.1" @@ -10759,6 +10790,7 @@ __metadata: react-router-dom: "npm:^7.1.1" rollup-plugin-visualizer: "npm:^5.14.0" rollup-preserve-directives: "npm:^1.1.3" + rxjs: "npm:^7.8.2" typescript: "npm:^5.1.3" vite: "npm:^7.0.0" languageName: unknown @@ -13534,13 +13566,6 @@ __metadata: languageName: node linkType: hard -"graphql@npm:^15.6.0": - version: 15.8.0 - resolution: "graphql@npm:15.8.0" - checksum: 30cc09b77170a9d1ed68e4c017ec8c5265f69501c96e4f34f8f6613f39a886c96dd9853eac925f212566ed651736334c8fe24ceae6c44e8d7625c95c3009a801 - languageName: node - linkType: hard - "graphql@npm:^16.13.2, graphql@npm:^16.8.1": version: 16.14.2 resolution: "graphql@npm:16.14.2" @@ -20428,17 +20453,19 @@ __metadata: version: 0.0.0-use.local resolution: "ra-data-graphql-simple@workspace:packages/ra-data-graphql-simple" dependencies: - "@apollo/client": "npm:^3.3.19" - graphql: "npm:^15.6.0" + "@apollo/client": "npm:^4.1.6" + graphql: "npm:^16.13.2" graphql-ast-types-browser: "npm:~1.0.2" lodash: "npm:~4.18.1" pluralize: "npm:~7.0.0" ra-data-graphql: "npm:^5.14.7" + rxjs: "npm:^7.8.2" typescript: "npm:^5.1.3" zshy: "npm:^0.5.0" peerDependencies: - graphql: ^15.6.0 + graphql: ^16.0.0 || ^17.0.0 ra-core: ^5.0.0 + rxjs: ^7.3.0 languageName: unknown linkType: soft @@ -20446,16 +20473,18 @@ __metadata: version: 0.0.0-use.local resolution: "ra-data-graphql@workspace:packages/ra-data-graphql" dependencies: - "@apollo/client": "npm:^3.3.19" - graphql: "npm:^15.6.0" + "@apollo/client": "npm:^4.1.6" + graphql: "npm:^16.13.2" graphql-tag: "npm:^2.12.6" lodash: "npm:~4.18.1" pluralize: "npm:~7.0.0" + rxjs: "npm:^7.8.2" typescript: "npm:^5.1.3" zshy: "npm:^0.5.0" peerDependencies: - graphql: ^15.6.0 || ^16 + graphql: ^16.0.0 || ^17.0.0 ra-core: ^5.0.0 + rxjs: ^7.3.0 languageName: unknown linkType: soft