@avantstay/graphql-ts-client 11.0.0 → 12.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -76,6 +76,58 @@ const client = {
76
76
  mutations: {}
77
77
  };
78
78
  var stdin_default = client;
79
+ ",
80
+ "mjs": "import { getApiEndpointCreator } from "./endpoint";
81
+ const formatGraphQL = (query) => query;
82
+ const typesTree = {};
83
+ let verbose = false;
84
+ let headers = {};
85
+ let url = "https://sample.endpoint.com/graphl";
86
+ let retryConfig = {
87
+ max: 0,
88
+ before: void 0,
89
+ waitBeforeRetry: 0
90
+ };
91
+ let responseListeners = [];
92
+ let errorsParser = void 0;
93
+ let apiEndpoint = getApiEndpointCreator({
94
+ getClient: () => ({ url, headers, retryConfig }),
95
+ responseListeners,
96
+ maxAge: 3e4,
97
+ verbose,
98
+ typesTree,
99
+ formatGraphQL,
100
+ errorsParser
101
+ });
102
+ const client = {
103
+ addResponseListener: (listener) => responseListeners.push(listener),
104
+ setHeader: (key, value) => {
105
+ headers[key] = value;
106
+ },
107
+ setHeaders: (newHeaders) => {
108
+ headers = newHeaders;
109
+ },
110
+ setRetryConfig: (options) => {
111
+ if (!Number.isInteger(options.max) || options.max < 0) {
112
+ throw new Error("retryOptions.max should be a non-negative integer");
113
+ }
114
+ retryConfig = {
115
+ max: options.max,
116
+ waitBeforeRetry: options.waitBeforeRetry,
117
+ before: options.before
118
+ };
119
+ },
120
+ setUrl: (_url) => url = _url,
121
+ queries: {
122
+ hello: apiEndpoint("query", "hello")
123
+ },
124
+ mutations: {}
125
+ };
126
+ var stdin_default = client;
127
+ export {
128
+ client,
129
+ stdin_default as default
130
+ };
79
131
  ",
80
132
  "typings": "// noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
81
133
  import { DeepRequired } from "ts-essentials"
@@ -39,16 +39,6 @@ export interface Book {
39
39
  author?: string
40
40
  type?: BookType
41
41
  dateCreated?: ISODate
42
- sequence?: BookSequence
43
- }
44
-
45
- /**
46
- * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
47
- */
48
-
49
- export interface BookSequence {
50
- previousBook?: Book
51
- nextBook?: Book
52
42
  }
53
43
 
54
44
  /**
@@ -88,12 +78,6 @@ export interface BookSelection {
88
78
  author?: boolean
89
79
  type?: boolean
90
80
  dateCreated?: boolean
91
- sequence?: BookSequenceSelection
92
- }
93
-
94
- export interface BookSequenceSelection {
95
- previousBook?: BookSelection
96
- nextBook?: BookSelection
97
81
  }
98
82
 
99
83
  export interface BookSearchParamsAllOptionalSelection {
@@ -123,8 +107,9 @@ export declare const myApiClient: {
123
107
  __headers?: { [key: string]: string }
124
108
  __retry?: boolean
125
109
  __alias?: string
110
+ __url?: string
126
111
  } & BookSelection,
127
- DeepRequired<Book[]>,
112
+ Book[],
128
113
  AllEnums
129
114
  >
130
115
  booksWithOptionalParams: Endpoint<
@@ -132,9 +117,10 @@ export declare const myApiClient: {
132
117
  __headers?: { [key: string]: string }
133
118
  __retry?: boolean
134
119
  __alias?: string
120
+ __url?: string
135
121
  __args?: BooksWithOptionalParamsArgs
136
122
  } & BookSelection,
137
- DeepRequired<Book[]>,
123
+ Book[],
138
124
  AllEnums
139
125
  >
140
126
  booksWithRequiredParams: Endpoint<
@@ -142,9 +128,10 @@ export declare const myApiClient: {
142
128
  __headers?: { [key: string]: string }
143
129
  __retry?: boolean
144
130
  __alias?: string
131
+ __url?: string
145
132
  __args: BooksWithRequiredParamsArgs
146
133
  } & BookSelection,
147
- DeepRequired<Book[]>,
134
+ Book[],
148
135
  AllEnums
149
136
  >
150
137
  failingQuery: Endpoint<
@@ -152,6 +139,7 @@ export declare const myApiClient: {
152
139
  __headers?: { [key: string]: string }
153
140
  __retry?: boolean
154
141
  __alias?: string
142
+ __url?: string
155
143
  __args: FailingQueryArgs
156
144
  },
157
145
  string,
@@ -39,7 +39,6 @@ const typesTree = {
39
39
  Query: {
40
40
  get booksWithOptionalParams() {
41
41
  return {
42
- __fields: typesTree.Book,
43
42
  __args: {
44
43
  params: "BookSearchParamsAllOptional!"
45
44
  }
@@ -47,7 +46,6 @@ const typesTree = {
47
46
  },
48
47
  get booksWithRequiredParams() {
49
48
  return {
50
- __fields: typesTree.Book,
51
49
  __args: {
52
50
  params: "BookSearchParamsSomeRequired!"
53
51
  }
@@ -60,30 +58,7 @@ const typesTree = {
60
58
  }
61
59
  };
62
60
  },
63
- get booksWithoutParams() {
64
- return {
65
- __fields: typesTree.Book
66
- };
67
- }
68
- },
69
- Book: {
70
- get sequence() {
71
- return {
72
- __fields: typesTree.BookSequence
73
- };
74
- }
75
- },
76
- BookSequence: {
77
- get previousBook() {
78
- return {
79
- __fields: typesTree.Book
80
- };
81
- },
82
- get nextBook() {
83
- return {
84
- __fields: typesTree.Book
85
- };
86
- }
61
+ booksWithoutParams: {}
87
62
  }
88
63
  };
89
64
  let verbose = false;
@@ -0,0 +1,87 @@
1
+ import { getApiEndpointCreator } from "./endpoint";
2
+ import { format as formatCode } from "prettier/standalone";
3
+ import parserGraphql from "prettier/parser-graphql";
4
+ const formatGraphQL = (query) => formatCode(query, { parser: "graphql", plugins: [parserGraphql] });
5
+ const BookType = {
6
+ dolor: "DOLOR",
7
+ ipsum: "IPSUM",
8
+ sit: "SIT"
9
+ };
10
+ const typesTree = {
11
+ Query: {
12
+ get booksWithOptionalParams() {
13
+ return {
14
+ __args: {
15
+ params: "BookSearchParamsAllOptional!"
16
+ }
17
+ };
18
+ },
19
+ get booksWithRequiredParams() {
20
+ return {
21
+ __args: {
22
+ params: "BookSearchParamsSomeRequired!"
23
+ }
24
+ };
25
+ },
26
+ get failingQuery() {
27
+ return {
28
+ __args: {
29
+ id: "String!"
30
+ }
31
+ };
32
+ },
33
+ booksWithoutParams: {}
34
+ }
35
+ };
36
+ let verbose = false;
37
+ let headers = {};
38
+ let url = "http://localhost:4123/graphql";
39
+ let retryConfig = {
40
+ max: 0,
41
+ before: void 0,
42
+ waitBeforeRetry: 0
43
+ };
44
+ let responseListeners = [];
45
+ let errorsParser = void 0;
46
+ let apiEndpoint = getApiEndpointCreator({
47
+ getClient: () => ({ url, headers, retryConfig }),
48
+ responseListeners,
49
+ maxAge: 3e4,
50
+ verbose,
51
+ typesTree,
52
+ formatGraphQL,
53
+ errorsParser
54
+ });
55
+ const myApiClient = {
56
+ addResponseListener: (listener) => responseListeners.push(listener),
57
+ setHeader: (key, value) => {
58
+ headers[key] = value;
59
+ },
60
+ setHeaders: (newHeaders) => {
61
+ headers = newHeaders;
62
+ },
63
+ setRetryConfig: (options) => {
64
+ if (!Number.isInteger(options.max) || options.max < 0) {
65
+ throw new Error("retryOptions.max should be a non-negative integer");
66
+ }
67
+ retryConfig = {
68
+ max: options.max,
69
+ waitBeforeRetry: options.waitBeforeRetry,
70
+ before: options.before
71
+ };
72
+ },
73
+ setUrl: (_url) => url = _url,
74
+ queries: {
75
+ booksWithoutParams: apiEndpoint("query", "booksWithoutParams"),
76
+ booksWithOptionalParams: apiEndpoint("query", "booksWithOptionalParams"),
77
+ booksWithRequiredParams: apiEndpoint("query", "booksWithRequiredParams"),
78
+ failingQuery: apiEndpoint("query", "failingQuery")
79
+ },
80
+ mutations: {}
81
+ };
82
+ var stdin_default = myApiClient;
83
+ export {
84
+ BookType,
85
+ stdin_default as default,
86
+ myApiClient
87
+ };
package/src/endpoint.ts CHANGED
@@ -2,14 +2,10 @@ import memoize from 'moize'
2
2
  import { graphqlRequest } from './graphqlRequest'
3
3
  import { jsonToGraphQLQuery } from './jsonToGraphQLQuery'
4
4
  import { logRequest } from './logging'
5
- import {ClientConfig, Endpoint, GraphQLClientError, IResponseListener, Projection, ResponseListenerInfo} from './types'
5
+ import { ClientConfig, Endpoint, GraphQLClientError, IResponseListener, Projection, ResponseListenerInfo } from './types'
6
6
 
7
7
  const executeListeners = (listeners: IResponseListener[], data: ResponseListenerInfo) =>
8
- setTimeout(() =>
9
- listeners.forEach(runResponseListener =>
10
- runResponseListener(data)
11
- )
12
- )
8
+ setTimeout(() => listeners.forEach(runResponseListener => runResponseListener(data)))
13
9
 
14
10
  export const getApiEndpointCreator =
15
11
  (apiConfig: {
@@ -61,11 +57,11 @@ export const getApiEndpointCreator =
61
57
  shouldRetry,
62
58
  failureMode,
63
59
  queryName: alias,
64
- client: {...clientConfig, url },
60
+ client: { ...clientConfig, url },
65
61
  requestHeaders,
66
62
  query,
67
63
  variables,
68
- errorsParser: apiConfig.errorsParser
64
+ errorsParser: apiConfig.errorsParser,
69
65
  })
70
66
 
71
67
  const response = { data, warnings, headers, status, errors }
@@ -78,7 +74,7 @@ export const getApiEndpointCreator =
78
74
  })
79
75
  }
80
76
 
81
- executeListeners(apiConfig.responseListeners,{
77
+ executeListeners(apiConfig.responseListeners, {
82
78
  ...responseListenerData,
83
79
  response,
84
80
  })
@@ -125,12 +125,12 @@ describe('Generated Client', () => {
125
125
  expect(responseData?.response.errors.length).toBeGreaterThan(0)
126
126
  })
127
127
 
128
- it('should generate proper code from SDL', ()=>{
128
+ it('should generate proper code from SDL', () => {
129
129
  const sdlString = `
130
130
  type Query {
131
131
  hello: String
132
132
  }
133
- `;
134
- expect(generateTypescriptClientFromSDL(sdlString, {endpoint: 'https://sample.endpoint.com/graphl'})).toMatchSnapshot()
133
+ `
134
+ expect(generateTypescriptClientFromSDL(sdlString, { endpoint: 'https://sample.endpoint.com/graphl' })).toMatchSnapshot()
135
135
  })
136
136
  })
@@ -6,8 +6,8 @@ import * as fs from 'fs'
6
6
  import { PathLike } from 'fs'
7
7
  import {
8
8
  buildSchema,
9
- graphqlSync,
10
9
  getIntrospectionQuery,
10
+ graphqlSync,
11
11
  IntrospectionEnumType,
12
12
  IntrospectionField,
13
13
  IntrospectionInputObjectType,
@@ -15,16 +15,14 @@ import {
15
15
  IntrospectionObjectType,
16
16
  IntrospectionOutputTypeRef,
17
17
  IntrospectionType,
18
- Source,
19
18
  } from 'graphql'
20
- import kebabCase from 'lodash/kebabCase'
21
- import orderBy from 'lodash/orderBy'
22
- import set from 'lodash/set'
19
+ import { kebabCase, orderBy, set } from 'lodash'
23
20
  import md5 from 'md5'
24
21
  import os from 'os'
25
22
  import path from 'path'
26
23
  import * as prettier from 'prettier'
27
24
  import pkg from '../package.json'
25
+ import { TypescriptClientOutput } from './types'
28
26
 
29
27
  const tempDir = fs.realpathSync(os.tmpdir())
30
28
 
@@ -314,7 +312,7 @@ type IClientOptions = {
314
312
  errorsParser?: (errors: any[]) => any
315
313
  }
316
314
 
317
- type FetchIntrospectionOptions = Omit< IClientOptions, 'output' | 'introspectionEndpoint'>
315
+ type FetchIntrospectionOptions = Omit<IClientOptions, 'output' | 'introspectionEndpoint'>
318
316
 
319
317
  function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Omit<IClientOptions, 'output'>) {
320
318
  const typesHash = md5(`${JSON.stringify(options)}__${JSON.stringify(types)}`)
@@ -322,7 +320,11 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
322
320
  const clientCacheFilePath = path.resolve(tempDir, clientCacheFileName)
323
321
 
324
322
  if (!options.skipCache && fs.existsSync(clientCacheFilePath)) {
325
- return JSON.parse(fs.readFileSync(clientCacheFilePath, { encoding: 'utf8' }))
323
+ const output: Partial<TypescriptClientOutput> = JSON.parse(fs.readFileSync(clientCacheFilePath, { encoding: 'utf8' }))
324
+
325
+ if (output.js && output.mjs && output.typings) {
326
+ return output as TypescriptClientOutput
327
+ }
326
328
  }
327
329
 
328
330
  const queries = (<IntrospectionObjectType>types.find(it => it.name === 'Query'))?.fields || []
@@ -472,8 +474,9 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
472
474
 
473
475
  export default ${clientName}`
474
476
 
475
- const output = {
477
+ const output: TypescriptClientOutput = {
476
478
  js: esbuild.transformSync(jsCode, { format: 'cjs', loader: 'js' }).code,
479
+ mjs: esbuild.transformSync(jsCode, { format: 'esm', loader: 'js' }).code,
477
480
  typings: prettier.format(typingsCode, { semi: false, parser: 'typescript' }),
478
481
  }
479
482
 
@@ -498,18 +501,18 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
498
501
  'Content-Type': 'application/json',
499
502
  ...headers,
500
503
  },
504
+ timeout: 5000,
501
505
  }
502
506
  )
503
- .catch((e) => {
504
- const errorMessage = `The GraphQL introspection request failed (${endpoint})`
507
+ .catch(e => {
505
508
  if (fs.existsSync(introspectionCacheFilePath)) {
506
509
  const cachedSchema = JSON.parse(fs.readFileSync(introspectionCacheFilePath, { encoding: 'utf8' }))
507
510
  loadedFromCache = true
508
- console.warn(`Successfully restored from local cache.`)
511
+ console.warn(`Successfully restored (${endpoint}) from local cache.`)
509
512
  return { data: cachedSchema }
510
513
  } else {
511
514
  console.error(e)
512
- return Promise.reject(errorMessage)
515
+ return Promise.reject(`The GraphQL introspection request failed (${endpoint})`)
513
516
  }
514
517
  })
515
518
 
@@ -526,10 +529,11 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
526
529
  return types
527
530
  }
528
531
 
529
- type Client = { typings: string; js: string }
530
-
531
- function generateClient(introspectionTypes: ReadonlyArray<IntrospectionType>, {output,...restOptions}: IClientOptions): Client {
532
- const { js, typings } = generateClientCode(introspectionTypes, restOptions)
532
+ function generateClient(
533
+ introspectionTypes: ReadonlyArray<IntrospectionType>,
534
+ { output, ...restOptions }: IClientOptions
535
+ ): TypescriptClientOutput {
536
+ const { js, mjs, typings } = generateClientCode(introspectionTypes, restOptions)
533
537
 
534
538
  if (output && typeof output === 'string') {
535
539
  const outputDir = path.dirname(output)
@@ -540,12 +544,16 @@ function generateClient(introspectionTypes: ReadonlyArray<IntrospectionType>, {o
540
544
 
541
545
  fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.d.ts'), typings, { encoding: 'utf8' })
542
546
  fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.js'), js, { encoding: 'utf8' })
547
+ fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.mjs'), mjs, { encoding: 'utf8' })
543
548
  }
544
549
 
545
- return { js, typings }
550
+ return { js, mjs, typings }
546
551
  }
547
552
 
548
- export async function generateTypescriptClient({ introspectionEndpoint, ...options }: IClientOptions): Promise<Client> {
553
+ export async function generateTypescriptClient({
554
+ introspectionEndpoint,
555
+ ...options
556
+ }: IClientOptions): Promise<TypescriptClientOutput> {
549
557
  console.log(`Generating TypeScript client (name: ${options.clientName ?? 'n/a'})`)
550
558
 
551
559
  axiosRetry(axios, { retries: 5, retryDelay: retryCount => 1000 * 2 ** retryCount })
@@ -556,14 +564,17 @@ export async function generateTypescriptClient({ introspectionEndpoint, ...optio
556
564
  })
557
565
 
558
566
  return generateClient(introspectionTypes, options)
559
-
560
567
  }
561
568
 
562
- export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions): Client {
563
- console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? 'n/a'})`);
569
+ export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions): TypescriptClientOutput {
570
+ console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? 'n/a'})`)
564
571
 
565
- const graphqlSchemaObj = buildSchema(SDL);
566
- const introspectionTypes = graphqlSync(graphqlSchemaObj, new Source(getIntrospectionQuery())).data?.__schema.types as IntrospectionType[]
572
+ const graphqlSchemaObj = buildSchema(SDL)
573
+ const introspectionResult = graphqlSync({
574
+ schema: graphqlSchemaObj,
575
+ source: getIntrospectionQuery(),
576
+ })
577
+ const introspectionTypes = (introspectionResult.data as any)?.__schema.types as IntrospectionType[]
567
578
 
568
579
  return generateClient(introspectionTypes, options)
569
580
  }
@@ -2,10 +2,10 @@ import { graphqlRequest } from './graphqlRequest'
2
2
 
3
3
  describe('GraphQLRequest', () => {
4
4
  it('Should request have proper structure', async () => {
5
- let request: any;
5
+ let request: any
6
6
 
7
7
  const mockedAxios = {
8
- post: function() {
8
+ post: function () {
9
9
  request = arguments
10
10
  return {
11
11
  status: 200,
@@ -19,7 +19,7 @@ describe('GraphQLRequest', () => {
19
19
  axios: mockedAxios,
20
20
  queryName: 'sampleQueryName',
21
21
  query: 'sampleQuery',
22
- variables: {foo:'bar',bar:'foo'},
22
+ variables: { foo: 'bar', bar: 'foo' },
23
23
  client: {
24
24
  url: 'https://whatever.com',
25
25
  headers: {},
@@ -51,7 +51,6 @@ describe('GraphQLRequest', () => {
51
51
  } as any
52
52
 
53
53
  const result = await graphqlRequest({
54
-
55
54
  failureMode: 'loud',
56
55
  axios: mockedAxios,
57
56
  queryName: 'whatever',
@@ -1,12 +1,8 @@
1
- import omit from 'lodash/omit'
1
+ import { cloneDeep, fromPairs as fromEntries, omit, toPairs as entries } from 'lodash'
2
2
 
3
3
  const VAR_PREFIX = '@@VAR@@'
4
4
  const VAR_PREFIX_LENGTH = VAR_PREFIX.length
5
5
 
6
- const fromEntries: (arr: [string, any][]) => { [key: string]: any } = require('lodash/fromPairs')
7
- const entries: (obj: { [key: string]: any }) => [string, any][] = require('lodash/toPairs')
8
- const cloneDeep = require('lodash/cloneDeep')
9
-
10
6
  type ExtractedVariables = Record<string, (Variable & { name: string; update: (index?: number) => string })[]>
11
7
  type Variable = { type: any; value: any }
12
8
 
@@ -31,14 +27,17 @@ export function jsonToGraphQLQuery({
31
27
  parentType: kind === 'query' ? typesTree.Query : typesTree.Mutation,
32
28
  })
33
29
 
34
- const variableItems = Object.values(variablesData).reduce((variablesObj, variables) => {
35
- variables.forEach((variable, index) => {
36
- const name = variable.update(variables.length > 1 ? index : undefined)
37
- variablesObj[name] = { type: variable.type, value: variable.value }
38
- })
30
+ const variableItems = Object.values(variablesData).reduce(
31
+ (variablesObj, variables) => {
32
+ variables.forEach((variable, index) => {
33
+ const name = variable.update(variables.length > 1 ? index : undefined)
34
+ variablesObj[name] = { type: variable.type, value: variable.value }
35
+ })
39
36
 
40
- return variablesObj
41
- }, {} as Record<string, Variable>)
37
+ return variablesObj
38
+ },
39
+ {} as Record<string, Variable>
40
+ )
42
41
 
43
42
  const variablesQuery = Object.keys(variableItems).length
44
43
  ? `(${entries(variableItems)
package/src/types.ts CHANGED
@@ -24,30 +24,31 @@ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends read
24
24
  type Primitive = Date | string | number | boolean | null | undefined
25
25
 
26
26
  // Projection is the resulting type of Selection (type generated out of a query) applied to Base (generated graphql type)
27
- export type Projection<Selection, Base, E = never> = Base extends Array<any>
28
- ? ArrayElement<Base> extends Primitive | E
29
- ? ArrayElement<Base>[]
30
- : Projection<Defined<Selection>, ArrayElement<Base>, E>[]
31
- : Base extends Primitive | E
32
- ? // Is primitive and extends undefined
33
- Selection extends undefined
34
- ? Base | undefined
35
- : Base
36
- : {
37
- [k in keyof Selection & keyof Base]: Selection[k] extends boolean
38
- ? Base[k]
39
- : Base[k] extends Array<infer A>
40
- ? Projection<Defined<Selection[k]>, A, E>[]
41
- : Projection<Defined<Selection[k]>, Base[k], E>
42
- }
27
+ export type Projection<Selection, Base, E = never> =
28
+ Base extends Array<any>
29
+ ? ArrayElement<Base> extends Primitive | E
30
+ ? ArrayElement<Base>[]
31
+ : Projection<Defined<Selection>, ArrayElement<Base>, E>[]
32
+ : Base extends Primitive | E
33
+ ? // Is primitive and extends undefined
34
+ Selection extends undefined
35
+ ? Base | undefined
36
+ : Base
37
+ : {
38
+ [k in keyof Selection & keyof Base]: Selection[k] extends boolean
39
+ ? Base[k]
40
+ : Base[k] extends Array<infer A>
41
+ ? Projection<Defined<Selection[k]>, A, E>[]
42
+ : Projection<Defined<Selection[k]>, Base[k], E>
43
+ }
43
44
 
44
45
  export type Unpacked<T> = T extends (infer U)[]
45
46
  ? U
46
47
  : T extends (...args: any[]) => infer U
47
- ? U
48
- : T extends Promise<infer U>
49
- ? U
50
- : T
48
+ ? U
49
+ : T extends Promise<infer U>
50
+ ? U
51
+ : T
51
52
 
52
53
  export type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never
53
54
 
@@ -59,8 +60,8 @@ export type DeepReplace<T, Ignore, M extends [any, any]> = {
59
60
  : T[P]
60
61
  : Replacement<M, T[P]>
61
62
  : T[P] extends object
62
- ? DeepReplace<T[P], Ignore, M>
63
- : T[P]
63
+ ? DeepReplace<T[P], Ignore, M>
64
+ : T[P]
64
65
  }
65
66
 
66
67
  export type RawEndpoint<I, O, E> = <S extends I>(
@@ -98,6 +99,12 @@ export type LogInfo = {
98
99
  duration: number
99
100
  }
100
101
 
102
+ export type TypescriptClientOutput = {
103
+ js: string
104
+ mjs: string
105
+ typings: string
106
+ }
107
+
101
108
  export class GraphQLClientError extends Error {
102
109
  responseData: ResponseData
103
110