@@ -15,6 +15,7 @@ import {
1515import type { Dispatch } from 'react' ;
1616import type { StateCreator } from 'zustand' ;
1717import type { SlicesWithActions , SchemaReference } from '../types' ;
18+ import { tryParseJSONC } from '../utility' ;
1819
1920type MaybeGraphQLSchema = GraphQLSchema | null | undefined ;
2021
@@ -59,7 +60,9 @@ export const createSchemaSlice: CreateSchemaSlice = initial => (set, get) => ({
5960 onSchemaChange,
6061 headerEditor,
6162 fetcher,
62- ...rest
63+ inputValueDeprecation,
64+ introspectionQueryName,
65+ schemaDescription,
6366 } = get ( ) ;
6467
6568 /**
@@ -71,67 +74,57 @@ export const createSchemaSlice: CreateSchemaSlice = initial => (set, get) => ({
7174 return ;
7275 }
7376 const counter = requestCounter + 1 ;
74- set ( { requestCounter : counter } ) ;
75-
77+ set ( { requestCounter : counter , isIntrospecting : true , fetchError : null } ) ;
7678 try {
77- const currentHeaders = headerEditor ?. getValue ( ) ;
78- const parsedHeaders = parseHeaderString ( currentHeaders ) ;
79- if ( ! parsedHeaders . isValidJSON ) {
80- set ( { fetchError : 'Introspection failed as headers are invalid.' } ) ;
81- return ;
79+ let headers : Record < string , unknown > | undefined ;
80+ try {
81+ headers = tryParseJSONC ( headerEditor ?. getValue ( ) ) ;
82+ } catch ( error ) {
83+ throw new Error (
84+ `Introspection failed. Request headers ${ error instanceof Error ? error . message : error } ` ,
85+ ) ;
8286 }
8387
84- const fetcherOpts : FetcherOpts = parsedHeaders . headers
85- ? { headers : parsedHeaders . headers }
86- : { } ;
87-
88+ const fetcherOpts : FetcherOpts = headers ? { headers } : { } ;
8889 /**
8990 * Get an introspection query for settings given via props
9091 */
91- const {
92- introspectionQuery,
93- introspectionQueryName,
94- introspectionQuerySansSubscriptions,
95- } = generateIntrospectionQuery ( rest ) ;
96- const fetch = fetcherReturnToPromise (
97- fetcher (
98- {
99- query : introspectionQuery ,
100- operationName : introspectionQueryName ,
101- } ,
102- fetcherOpts ,
103- ) ,
104- ) ;
105-
106- if ( ! isPromise ( fetch ) ) {
107- set ( {
108- fetchError : 'Fetcher did not return a Promise for introspection.' ,
109- } ) ;
110- return ;
111- }
112- set ( { isIntrospecting : true , fetchError : null } ) ;
113- let result = await fetch ;
92+ const introspectionQuery = getIntrospectionQuery ( {
93+ inputValueDeprecation,
94+ schemaDescription,
95+ } ) ;
11496
115- if ( typeof result !== 'object' || ! ( 'data' in result ) ) {
116- // Try the stock introspection query first, falling back on the
117- // sans-subscriptions query for services which do not yet support it.
118- const fetch2 = fetcherReturnToPromise (
97+ function doIntrospection ( query : string ) {
98+ const fetch = fetcherReturnToPromise (
11999 fetcher (
120- {
121- query : introspectionQuerySansSubscriptions ,
122- operationName : introspectionQueryName ,
123- } ,
100+ { query, operationName : introspectionQueryName } ,
124101 fetcherOpts ,
125102 ) ,
126103 ) ;
127- if ( ! isPromise ( fetch2 ) ) {
128- throw new Error (
104+ if ( ! isPromise ( fetch ) ) {
105+ throw new TypeError (
129106 'Fetcher did not return a Promise for introspection.' ,
130107 ) ;
131108 }
132- result = await fetch2 ;
109+ return fetch ;
133110 }
134111
112+ const normalizedQuery =
113+ introspectionQueryName === 'IntrospectionQuery'
114+ ? introspectionQuery
115+ : introspectionQuery . replace (
116+ 'query IntrospectionQuery' ,
117+ `query ${ introspectionQueryName } ` ,
118+ ) ;
119+ let result = await doIntrospection ( normalizedQuery ) ;
120+
121+ if ( typeof result !== 'object' || ! ( 'data' in result ) ) {
122+ // Try the stock introspection query first, falling back on the
123+ // sans-subscriptions query for services which do not yet support it.
124+ result = await doIntrospection (
125+ introspectionQuery . replace ( 'subscriptionType { name }' , '' ) ,
126+ ) ;
127+ }
135128 set ( { isIntrospecting : false } ) ;
136129 let introspectionData : IntrospectionQuery | undefined ;
137130 if ( result . data && '__schema' in result . data ) {
@@ -160,9 +153,12 @@ export const createSchemaSlice: CreateSchemaSlice = initial => (set, get) => ({
160153 if ( counter !== get ( ) . requestCounter ) {
161154 return ;
162155 }
156+ if ( error instanceof Error ) {
157+ delete error . stack ;
158+ }
163159 set ( {
164- fetchError : formatError ( error ) ,
165160 isIntrospecting : false ,
161+ fetchError : formatError ( error ) ,
166162 } ) ;
167163 }
168164 } ,
@@ -233,7 +229,7 @@ export interface SchemaActions {
233229 setSchemaReference : Dispatch < SchemaReference > ;
234230}
235231
236- export interface SchemaProps extends IntrospectionArgs {
232+ export interface SchemaProps {
237233 /**
238234 * This prop can be used to skip validating the GraphQL schema. This applies
239235 * to both schemas fetched via introspection and schemas explicitly passed
@@ -272,9 +268,7 @@ export interface SchemaProps extends IntrospectionArgs {
272268 * run without a schema.
273269 */
274270 schema ?: GraphQLSchema | IntrospectionQuery | null ;
275- }
276271
277- interface IntrospectionArgs {
278272 /**
279273 * Can be used to set the equally named option for introspecting a GraphQL
280274 * server.
@@ -297,45 +291,3 @@ interface IntrospectionArgs {
297291 */
298292 schemaDescription ?: boolean ;
299293}
300-
301- function generateIntrospectionQuery ( {
302- inputValueDeprecation,
303- introspectionQueryName,
304- schemaDescription,
305- } : IntrospectionArgs ) {
306- const query = getIntrospectionQuery ( {
307- inputValueDeprecation,
308- schemaDescription,
309- } ) ;
310- const introspectionQuery =
311- introspectionQueryName === 'IntrospectionQuery'
312- ? query
313- : query . replace (
314- 'query IntrospectionQuery' ,
315- `query ${ introspectionQueryName } ` ,
316- ) ;
317- const introspectionQuerySansSubscriptions = query . replace (
318- 'subscriptionType { name }' ,
319- '' ,
320- ) ;
321-
322- return {
323- introspectionQueryName,
324- introspectionQuery,
325- introspectionQuerySansSubscriptions,
326- } ;
327- }
328-
329- function parseHeaderString ( headersString ?: string ) {
330- let headers : Record < string , unknown > | null = null ;
331- let isValidJSON = true ;
332-
333- try {
334- if ( headersString ) {
335- headers = JSON . parse ( headersString ) ;
336- }
337- } catch {
338- isValidJSON = false ;
339- }
340- return { headers, isValidJSON } ;
341- }
0 commit comments