@avantstay/graphql-ts-client 10.7.0 → 10.9.0

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.
package/package.json CHANGED
@@ -1,57 +1,44 @@
1
1
  {
2
2
  "name": "@avantstay/graphql-ts-client",
3
- "version": "10.7.0",
3
+ "version": "10.9.0",
4
4
  "description": "GraphQL Typescript Client Generator",
5
- "author": "Wellington Guimaraes",
6
- "license": "MIT",
7
- "main": "dist/index.js",
8
- "typings": "dist/index.d.ts",
9
- "scripts": {
10
- "build": "tsup src/index.ts src/endpoint.ts --dts",
11
- "test": "cross-env GQL_CLIENT_DIST_PATH='.' jest --watch",
12
- "prepublishOnly": "yarn build"
13
- },
14
- "files": [
15
- "dist",
16
- "src"
17
- ],
18
- "engines": {
19
- "node": ">=12"
20
- },
5
+ "homepage": "https://github.com/avantstay/graphql-ts-client",
21
6
  "bugs": {
22
7
  "url": "https://github.com/avantstay/graphql-ts-client/issues"
23
8
  },
24
- "homepage": "https://github.com/avantstay/graphql-ts-client#readme",
25
9
  "repository": {
26
10
  "type": "git",
27
11
  "url": "git+https://github.com/avantstay/graphql-ts-client.git"
28
12
  },
29
- "peerDependencies": {},
30
- "prettier": {
31
- "trailingComma": "es5",
32
- "tabWidth": 2,
33
- "proseWrap": "always",
34
- "bracketSpacing": true,
35
- "jsxBracketSameLine": false,
36
- "semi": false,
37
- "singleQuote": true,
38
- "arrowParens": "avoid",
39
- "endOfLine": "lf",
40
- "printWidth": 130,
41
- "htmlWhitespaceSensitivity": "ignore",
42
- "jsxSingleQuote": false
43
- },
44
- "module": "dist/graphql-ts-client.esm.js",
45
- "size-limit": [
46
- {
47
- "path": "dist/graphql-ts-client.cjs.production.min.js",
48
- "limit": "10 KB"
13
+ "license": "MIT",
14
+ "author": "Wellington Guimaraes",
15
+ "contributors": [
16
+ "Felipe Pinheiro <felipe.pinheiro.90@hotmail.com>"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "import": "./dist/index.mjs",
21
+ "require": "./dist/index.js",
22
+ "types": "./dist/index.d.ts"
49
23
  },
50
- {
51
- "path": "dist/graphql-ts-client.esm.js",
52
- "limit": "10 KB"
24
+ "./dist/endpoint": {
25
+ "import": "./dist/endpoint.mjs",
26
+ "require": "./dist/endpoint.js",
27
+ "types": "./dist/endpoint.d.ts"
53
28
  }
29
+ },
30
+ "main": "dist/index.js",
31
+ "module": "dist/index.mjs",
32
+ "typings": "dist/index.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "src"
54
36
  ],
37
+ "scripts": {
38
+ "build": "tsup src/index.ts src/endpoint.ts --dts --format cjs,esm",
39
+ "prepublishOnly": "yarn build",
40
+ "test": "cross-env GQL_CLIENT_DIST_PATH='.' jest --watch"
41
+ },
55
42
  "dependencies": {
56
43
  "@types/md5": "^2.3.2",
57
44
  "axios": "^0.24.0",
@@ -87,7 +74,21 @@
87
74
  "tsup": "^6.5.0",
88
75
  "typescript": "^4.9.4"
89
76
  },
77
+ "peerDependencies": {},
78
+ "engines": {
79
+ "node": ">=12"
80
+ },
90
81
  "publishConfig": {
91
82
  "@avantstay:registry": "https://registry.npmjs.org/"
92
- }
83
+ },
84
+ "size-limit": [
85
+ {
86
+ "path": "dist/graphql-ts-client.cjs.production.min.js",
87
+ "limit": "10 KB"
88
+ },
89
+ {
90
+ "path": "dist/graphql-ts-client.esm.js",
91
+ "limit": "10 KB"
92
+ }
93
+ ]
93
94
  }
@@ -29,7 +29,7 @@ __export(exports, {
29
29
  client: () => client,
30
30
  default: () => stdin_default
31
31
  });
32
- var import_endpoint = __toModule(require("../dist/endpoint"));
32
+ var import_endpoint = __toModule(require("./endpoint"));
33
33
  const formatGraphQL = (query) => query;
34
34
  const typesTree = {};
35
35
  let verbose = false;
@@ -79,7 +79,7 @@ var stdin_default = client;
79
79
  ",
80
80
  "typings": "// noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
81
81
  import { DeepRequired } from "ts-essentials"
82
- import { Maybe, IResponseListener, Endpoint } from "../dist"
82
+ import { Maybe, IResponseListener, Endpoint } from "."
83
83
 
84
84
  // Scalars
85
85
  export type IDate = string | Date
@@ -119,6 +119,7 @@ export declare const client: {
119
119
  __headers?: { [key: string]: string }
120
120
  __retry?: boolean
121
121
  __alias?: string
122
+ __url?: string
122
123
  },
123
124
  string,
124
125
  AllEnums
@@ -0,0 +1,164 @@
1
+ // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
2
+ import { DeepRequired } from "ts-essentials"
3
+ import { Maybe, IResponseListener, Endpoint } from "."
4
+
5
+ // Scalars
6
+ export type IDate = string | Date
7
+ export declare type ISODate = IDate
8
+
9
+ // Enums
10
+
11
+ export declare enum BookType {
12
+ dolor = "DOLOR",
13
+ ipsum = "IPSUM",
14
+ sit = "SIT",
15
+ }
16
+
17
+ type AllEnums = BookType
18
+
19
+ // Args
20
+ export interface BooksWithoutParamsArgs {}
21
+ export interface BooksWithOptionalParamsArgs {
22
+ params?: BookSearchParamsAllOptional
23
+ }
24
+ export interface BooksWithRequiredParamsArgs {
25
+ params: BookSearchParamsSomeRequired
26
+ }
27
+ export interface FailingQueryArgs {
28
+ id: string
29
+ }
30
+
31
+ // Input/Output Types
32
+
33
+ /**
34
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
35
+ */
36
+
37
+ export interface Book {
38
+ title?: string
39
+ author?: string
40
+ type?: BookType
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
+ }
53
+
54
+ /**
55
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
56
+ */
57
+
58
+ export interface BookSearchParamsAllOptional {
59
+ title?: string
60
+ author?: string
61
+ createdAfter?: ISODate
62
+ }
63
+
64
+ /**
65
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
66
+ */
67
+
68
+ export interface BookSearchParamsSomeRequired {
69
+ title: string
70
+ author?: string
71
+ }
72
+
73
+ /**
74
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
75
+ */
76
+
77
+ export interface Query {
78
+ booksWithoutParams?: Book[]
79
+ booksWithOptionalParams?: Book[]
80
+ booksWithRequiredParams?: Book[]
81
+ failingQuery?: string
82
+ }
83
+
84
+ // Selection Types
85
+
86
+ export interface BookSelection {
87
+ title?: boolean
88
+ author?: boolean
89
+ type?: boolean
90
+ dateCreated?: boolean
91
+ sequence?: BookSequenceSelection
92
+ }
93
+
94
+ export interface BookSequenceSelection {
95
+ previousBook?: BookSelection
96
+ nextBook?: BookSelection
97
+ }
98
+
99
+ export interface BookSearchParamsAllOptionalSelection {
100
+ title?: boolean
101
+ author?: boolean
102
+ createdAfter?: boolean
103
+ }
104
+
105
+ export interface BookSearchParamsSomeRequiredSelection {
106
+ title?: boolean
107
+ author?: boolean
108
+ }
109
+
110
+ export declare const myApiClient: {
111
+ addResponseListener: (listener: IResponseListener) => void
112
+ setHeader: (key: string, value: string) => void
113
+ setHeaders: (newHeaders: { [k: string]: string }) => void
114
+ setUrl: (url: string) => void
115
+ setRetryConfig: (options: {
116
+ max: number
117
+ waitBeforeRetry?: number
118
+ before?: IResponseListener
119
+ }) => void
120
+ queries: {
121
+ booksWithoutParams: Endpoint<
122
+ {
123
+ __headers?: { [key: string]: string }
124
+ __retry?: boolean
125
+ __alias?: string
126
+ } & BookSelection,
127
+ DeepRequired<Book[]>,
128
+ AllEnums
129
+ >
130
+ booksWithOptionalParams: Endpoint<
131
+ {
132
+ __headers?: { [key: string]: string }
133
+ __retry?: boolean
134
+ __alias?: string
135
+ __args?: BooksWithOptionalParamsArgs
136
+ } & BookSelection,
137
+ DeepRequired<Book[]>,
138
+ AllEnums
139
+ >
140
+ booksWithRequiredParams: Endpoint<
141
+ {
142
+ __headers?: { [key: string]: string }
143
+ __retry?: boolean
144
+ __alias?: string
145
+ __args: BooksWithRequiredParamsArgs
146
+ } & BookSelection,
147
+ DeepRequired<Book[]>,
148
+ AllEnums
149
+ >
150
+ failingQuery: Endpoint<
151
+ {
152
+ __headers?: { [key: string]: string }
153
+ __retry?: boolean
154
+ __alias?: string
155
+ __args: FailingQueryArgs
156
+ },
157
+ string,
158
+ AllEnums
159
+ >
160
+ }
161
+ mutations: {}
162
+ }
163
+
164
+ export default myApiClient
@@ -0,0 +1,135 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
8
+ var __export = (target, all) => {
9
+ __markAsModule(target);
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __reExport = (target, module2, desc) => {
14
+ if (module2 && typeof module2 === "object" || typeof module2 === "function") {
15
+ for (let key of __getOwnPropNames(module2))
16
+ if (!__hasOwnProp.call(target, key) && key !== "default")
17
+ __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
18
+ }
19
+ return target;
20
+ };
21
+ var __toModule = (module2) => {
22
+ return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
23
+ };
24
+ __export(exports, {
25
+ BookType: () => BookType,
26
+ default: () => stdin_default,
27
+ myApiClient: () => myApiClient
28
+ });
29
+ var import_endpoint = __toModule(require("./endpoint"));
30
+ var import_standalone = __toModule(require("prettier/standalone"));
31
+ var import_parser_graphql = __toModule(require("prettier/parser-graphql"));
32
+ const formatGraphQL = (query) => (0, import_standalone.format)(query, { parser: "graphql", plugins: [import_parser_graphql.default] });
33
+ const BookType = {
34
+ dolor: "DOLOR",
35
+ ipsum: "IPSUM",
36
+ sit: "SIT"
37
+ };
38
+ const typesTree = {
39
+ Query: {
40
+ get booksWithOptionalParams() {
41
+ return {
42
+ __fields: typesTree.Book,
43
+ __args: {
44
+ params: "BookSearchParamsAllOptional!"
45
+ }
46
+ };
47
+ },
48
+ get booksWithRequiredParams() {
49
+ return {
50
+ __fields: typesTree.Book,
51
+ __args: {
52
+ params: "BookSearchParamsSomeRequired!"
53
+ }
54
+ };
55
+ },
56
+ get failingQuery() {
57
+ return {
58
+ __args: {
59
+ id: "String!"
60
+ }
61
+ };
62
+ },
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
+ }
87
+ }
88
+ };
89
+ let verbose = false;
90
+ let headers = {};
91
+ let url = "http://localhost:4123/graphql";
92
+ let retryConfig = {
93
+ max: 0,
94
+ before: void 0,
95
+ waitBeforeRetry: 0
96
+ };
97
+ let responseListeners = [];
98
+ let errorsParser = void 0;
99
+ let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
100
+ getClient: () => ({ url, headers, retryConfig }),
101
+ responseListeners,
102
+ maxAge: 3e4,
103
+ verbose,
104
+ typesTree,
105
+ formatGraphQL,
106
+ errorsParser
107
+ });
108
+ const myApiClient = {
109
+ addResponseListener: (listener) => responseListeners.push(listener),
110
+ setHeader: (key, value) => {
111
+ headers[key] = value;
112
+ },
113
+ setHeaders: (newHeaders) => {
114
+ headers = newHeaders;
115
+ },
116
+ setRetryConfig: (options) => {
117
+ if (!Number.isInteger(options.max) || options.max < 0) {
118
+ throw new Error("retryOptions.max should be a non-negative integer");
119
+ }
120
+ retryConfig = {
121
+ max: options.max,
122
+ waitBeforeRetry: options.waitBeforeRetry,
123
+ before: options.before
124
+ };
125
+ },
126
+ setUrl: (_url) => url = _url,
127
+ queries: {
128
+ booksWithoutParams: apiEndpoint("query", "booksWithoutParams"),
129
+ booksWithOptionalParams: apiEndpoint("query", "booksWithOptionalParams"),
130
+ booksWithRequiredParams: apiEndpoint("query", "booksWithRequiredParams"),
131
+ failingQuery: apiEndpoint("query", "failingQuery")
132
+ },
133
+ mutations: {}
134
+ };
135
+ var stdin_default = myApiClient;
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: {
@@ -32,7 +28,10 @@ export const getApiEndpointCreator =
32
28
  headers: any
33
29
  status: any
34
30
  }> => {
31
+ const clientConfig = apiConfig.getClient()
32
+
35
33
  const alias = (jsonQuery as any)?.__alias ?? queryName
34
+ const url = (jsonQuery as any)?.__url ?? clientConfig.url
36
35
  const shouldRetry = (jsonQuery as any)?.__retry ?? true
37
36
  const requestHeaders = (jsonQuery as any)?.__headers ?? {}
38
37
  const { query, variables } = jsonToGraphQLQuery({ kind, queryName, jsonQuery, typesTree: apiConfig.typesTree })
@@ -58,11 +57,11 @@ export const getApiEndpointCreator =
58
57
  shouldRetry,
59
58
  failureMode,
60
59
  queryName: alias,
61
- client: apiConfig.getClient(),
60
+ client: { ...clientConfig, url },
62
61
  requestHeaders,
63
62
  query,
64
63
  variables,
65
- errorsParser: apiConfig.errorsParser
64
+ errorsParser: apiConfig.errorsParser,
66
65
  })
67
66
 
68
67
  const response = { data, warnings, headers, status, errors }
@@ -75,7 +74,7 @@ export const getApiEndpointCreator =
75
74
  })
76
75
  }
77
76
 
78
- executeListeners(apiConfig.responseListeners,{
77
+ executeListeners(apiConfig.responseListeners, {
79
78
  ...responseListenerData,
80
79
  response,
81
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,
@@ -17,7 +17,7 @@ import {
17
17
  IntrospectionType,
18
18
  Source,
19
19
  } from 'graphql'
20
- import { kebabCase } from 'lodash'
20
+ import kebabCase from 'lodash/kebabCase'
21
21
  import orderBy from 'lodash/orderBy'
22
22
  import set from 'lodash/set'
23
23
  import md5 from 'md5'
@@ -25,6 +25,7 @@ import os from 'os'
25
25
  import path from 'path'
26
26
  import * as prettier from 'prettier'
27
27
  import pkg from '../package.json'
28
+ import { TypescriptClientOutput } from './types'
28
29
 
29
30
  const tempDir = fs.realpathSync(os.tmpdir())
30
31
 
@@ -108,7 +109,7 @@ function gqlFieldToTypescript(
108
109
  })
109
110
  )
110
111
 
111
- fieldTypeDefinition = `{ __headers?: {[key: string]: string}; __retry?: boolean; __alias?: string; __args${
112
+ fieldTypeDefinition = `{ __headers?: {[key: string]: string}; __retry?: boolean; __alias?: string; __url?: string; __args${
112
113
  fieldsOnArgs.every(arg => arg.isOptional) ? '?' : ''
113
114
  }: { ${fieldsOnArgs.map(arg => arg.code).join(', ')} }}${fieldTypeDefinition ? ` & ${fieldTypeDefinition}` : ''}`
114
115
  }
@@ -148,14 +149,14 @@ function gqlEndpointToCode(kind: 'mutation' | 'query', endpoint: IntrospectionFi
148
149
  __headers?: {[key: string]: string};
149
150
  __retry?: boolean;
150
151
  __alias?: string;
152
+ __url?: string;
151
153
  ${argsType ? `__args${argsType.optional ? '?' : ''}: ${argsType.alias}` : ''}
152
154
  }${selectionType ? ` & ${selectionType}` : ''}`
153
155
 
154
156
  const outputType = gqlTypeToTypescript(endpoint.type, { required: true })
155
- const wrappedOutputType = /^(string|number|boolean)$/.test(outputType) ? outputType : `DeepRequired<${outputType}>`
156
157
 
157
158
  return codeOutputType === 'ts'
158
- ? `${endpoint.name}: Endpoint<${inputType}, ${wrappedOutputType}, AllEnums>`
159
+ ? `${endpoint.name}: Endpoint<${inputType}, ${outputType}, AllEnums>`
159
160
  : `${endpoint.name}: apiEndpoint('${kind}', '${endpoint.name}')`
160
161
  }
161
162
 
@@ -314,7 +315,7 @@ type IClientOptions = {
314
315
  errorsParser?: (errors: any[]) => any
315
316
  }
316
317
 
317
- type FetchIntrospectionOptions = Omit< IClientOptions, 'output' | 'introspectionEndpoint'>
318
+ type FetchIntrospectionOptions = Omit<IClientOptions, 'output' | 'introspectionEndpoint'>
318
319
 
319
320
  function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Omit<IClientOptions, 'output'>) {
320
321
  const typesHash = md5(`${JSON.stringify(options)}__${JSON.stringify(types)}`)
@@ -322,7 +323,11 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
322
323
  const clientCacheFilePath = path.resolve(tempDir, clientCacheFileName)
323
324
 
324
325
  if (!options.skipCache && fs.existsSync(clientCacheFilePath)) {
325
- return JSON.parse(fs.readFileSync(clientCacheFilePath, { encoding: 'utf8' }))
326
+ const output: Partial<TypescriptClientOutput> = JSON.parse(fs.readFileSync(clientCacheFilePath, { encoding: 'utf8' }))
327
+
328
+ if (output.js && output.mjs && output.typings) {
329
+ return output as TypescriptClientOutput
330
+ }
326
331
  }
327
332
 
328
333
  const queries = (<IntrospectionObjectType>types.find(it => it.name === 'Query'))?.fields || []
@@ -472,8 +477,9 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
472
477
 
473
478
  export default ${clientName}`
474
479
 
475
- const output = {
480
+ const output: TypescriptClientOutput = {
476
481
  js: esbuild.transformSync(jsCode, { format: 'cjs', loader: 'js' }).code,
482
+ mjs: esbuild.transformSync(jsCode, { format: 'esm', loader: 'js' }).code,
477
483
  typings: prettier.format(typingsCode, { semi: false, parser: 'typescript' }),
478
484
  }
479
485
 
@@ -500,7 +506,7 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
500
506
  },
501
507
  }
502
508
  )
503
- .catch(() => {
509
+ .catch(e => {
504
510
  const errorMessage = `The GraphQL introspection request failed (${endpoint})`
505
511
  if (fs.existsSync(introspectionCacheFilePath)) {
506
512
  const cachedSchema = JSON.parse(fs.readFileSync(introspectionCacheFilePath, { encoding: 'utf8' }))
@@ -508,6 +514,7 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
508
514
  console.warn(`Successfully restored from local cache.`)
509
515
  return { data: cachedSchema }
510
516
  } else {
517
+ console.error(e)
511
518
  return Promise.reject(errorMessage)
512
519
  }
513
520
  })
@@ -525,10 +532,11 @@ async function fetchIntrospection({ endpoint, headers }: FetchIntrospectionOptio
525
532
  return types
526
533
  }
527
534
 
528
- type Client = { typings: string; js: string }
529
-
530
- function generateClient(introspectionTypes: ReadonlyArray<IntrospectionType>, {output,...restOptions}: IClientOptions): Client {
531
- const { js, typings } = generateClientCode(introspectionTypes, restOptions)
535
+ function generateClient(
536
+ introspectionTypes: ReadonlyArray<IntrospectionType>,
537
+ { output, ...restOptions }: IClientOptions
538
+ ): TypescriptClientOutput {
539
+ const { js, mjs, typings } = generateClientCode(introspectionTypes, restOptions)
532
540
 
533
541
  if (output && typeof output === 'string') {
534
542
  const outputDir = path.dirname(output)
@@ -539,12 +547,16 @@ function generateClient(introspectionTypes: ReadonlyArray<IntrospectionType>, {o
539
547
 
540
548
  fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.d.ts'), typings, { encoding: 'utf8' })
541
549
  fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.js'), js, { encoding: 'utf8' })
550
+ fs.writeFileSync(output.replace(/(\.(ts|js))?$/, '.mjs'), mjs, { encoding: 'utf8' })
542
551
  }
543
552
 
544
- return { js, typings }
553
+ return { js, mjs, typings }
545
554
  }
546
555
 
547
- export async function generateTypescriptClient({ introspectionEndpoint, ...options }: IClientOptions): Promise<Client> {
556
+ export async function generateTypescriptClient({
557
+ introspectionEndpoint,
558
+ ...options
559
+ }: IClientOptions): Promise<TypescriptClientOutput> {
548
560
  console.log(`Generating TypeScript client (name: ${options.clientName ?? 'n/a'})`)
549
561
 
550
562
  axiosRetry(axios, { retries: 5, retryDelay: retryCount => 1000 * 2 ** retryCount })
@@ -555,14 +567,14 @@ export async function generateTypescriptClient({ introspectionEndpoint, ...optio
555
567
  })
556
568
 
557
569
  return generateClient(introspectionTypes, options)
558
-
559
570
  }
560
571
 
561
- export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions): Client {
562
- console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? 'n/a'})`);
572
+ export function generateTypescriptClientFromSDL(SDL: string, options: IClientOptions): TypescriptClientOutput {
573
+ console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? 'n/a'})`)
563
574
 
564
- const graphqlSchemaObj = buildSchema(SDL);
565
- const introspectionTypes = graphqlSync(graphqlSchemaObj, new Source(getIntrospectionQuery())).data?.__schema.types as IntrospectionType[]
575
+ const graphqlSchemaObj = buildSchema(SDL)
576
+ const introspectionTypes = graphqlSync(graphqlSchemaObj, new Source(getIntrospectionQuery())).data?.__schema
577
+ .types as IntrospectionType[]
566
578
 
567
579
  return generateClient(introspectionTypes, options)
568
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',