@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/dist/index.mjs ADDED
@@ -0,0 +1,527 @@
1
+ import {
2
+ GraphQLClientError
3
+ } from "./chunk-I4QOADOI.mjs";
4
+
5
+ // src/generateTypescriptClient.ts
6
+ import axios from "axios";
7
+ import axiosRetry from "axios-retry";
8
+ import Case from "case";
9
+ import * as esbuild from "esbuild";
10
+ import * as fs from "fs";
11
+ import {
12
+ buildSchema,
13
+ getIntrospectionQuery,
14
+ graphqlSync,
15
+ Source
16
+ } from "graphql";
17
+ import kebabCase from "lodash/kebabCase";
18
+ import orderBy from "lodash/orderBy";
19
+ import set from "lodash/set";
20
+ import md5 from "md5";
21
+ import os from "os";
22
+ import path from "path";
23
+ import * as prettier from "prettier";
24
+
25
+ // package.json
26
+ var package_default = {
27
+ name: "@avantstay/graphql-ts-client",
28
+ version: "10.9.0",
29
+ description: "GraphQL Typescript Client Generator",
30
+ homepage: "https://github.com/avantstay/graphql-ts-client",
31
+ bugs: {
32
+ url: "https://github.com/avantstay/graphql-ts-client/issues"
33
+ },
34
+ repository: {
35
+ type: "git",
36
+ url: "git+https://github.com/avantstay/graphql-ts-client.git"
37
+ },
38
+ license: "MIT",
39
+ author: "Wellington Guimaraes",
40
+ contributors: [
41
+ "Felipe Pinheiro <felipe.pinheiro.90@hotmail.com>"
42
+ ],
43
+ exports: {
44
+ ".": {
45
+ import: "./dist/index.mjs",
46
+ require: "./dist/index.js",
47
+ types: "./dist/index.d.ts"
48
+ },
49
+ "./dist/endpoint": {
50
+ import: "./dist/endpoint.mjs",
51
+ require: "./dist/endpoint.js",
52
+ types: "./dist/endpoint.d.ts"
53
+ }
54
+ },
55
+ main: "dist/index.js",
56
+ module: "dist/index.mjs",
57
+ typings: "dist/index.d.ts",
58
+ files: [
59
+ "dist",
60
+ "src"
61
+ ],
62
+ scripts: {
63
+ build: "tsup src/index.ts src/endpoint.ts --dts --format cjs,esm",
64
+ prepublishOnly: "yarn build",
65
+ test: "cross-env GQL_CLIENT_DIST_PATH='.' jest --watch"
66
+ },
67
+ dependencies: {
68
+ "@types/md5": "^2.3.2",
69
+ axios: "^0.24.0",
70
+ "axios-retry": "^3.2.4",
71
+ case: "^1.6.3",
72
+ esbuild: "^0.13.14",
73
+ graphql: "^15.6.0",
74
+ lodash: "^4.17.21",
75
+ md5: "^2.3.0",
76
+ moize: "^6.1.0",
77
+ prettier: "^2.5.1",
78
+ "temp-dir": "^3.0.0",
79
+ "ts-essentials": "^8.1.0"
80
+ },
81
+ devDependencies: {
82
+ "@babel/preset-env": "^7.20.2",
83
+ "@babel/preset-typescript": "^7.18.6",
84
+ "@jest/globals": "^29.3.1",
85
+ "@size-limit/preset-small-lib": "^5.0.4",
86
+ "@swc/core": "^1.3.22",
87
+ "@types/graphql": "^14.5.0",
88
+ "@types/jest": "^29.2.4",
89
+ "@types/lodash": "^4.14.177",
90
+ "@types/node": "^16.11.12",
91
+ "@types/prettier": "^2.4.2",
92
+ "apollo-server": "^3.11.1",
93
+ concurrently: "^7.6.0",
94
+ "cross-env": "^7.0.3",
95
+ jest: "^29.3.1",
96
+ "ts-jest": "^29.0.3",
97
+ "ts-node": "^10.9.1",
98
+ tslib: "^2.3.1",
99
+ tsup: "^6.5.0",
100
+ typescript: "^4.9.4"
101
+ },
102
+ peerDependencies: {},
103
+ engines: {
104
+ node: ">=12"
105
+ },
106
+ publishConfig: {
107
+ "@avantstay:registry": "https://registry.npmjs.org/"
108
+ },
109
+ "size-limit": [
110
+ {
111
+ path: "dist/graphql-ts-client.cjs.production.min.js",
112
+ limit: "10 KB"
113
+ },
114
+ {
115
+ path: "dist/graphql-ts-client.esm.js",
116
+ limit: "10 KB"
117
+ }
118
+ ]
119
+ };
120
+
121
+ // src/generateTypescriptClient.ts
122
+ var tempDir = fs.realpathSync(os.tmpdir());
123
+ var graphqlTsClientPath = process.env.GQL_CLIENT_DIST_PATH || "@avantstay/graphql-ts-client/dist";
124
+ function gqlScalarToTypescript(gqlType) {
125
+ if (/(int|long|double|decimal|float)/i.test(gqlType))
126
+ return "number";
127
+ if (/boolean/i.test(gqlType))
128
+ return "boolean";
129
+ if (/String/i.test(gqlType))
130
+ return "string";
131
+ return gqlType;
132
+ }
133
+ function gqlTypeToTypescript(gqlType, { required = false, isInput = false, selection = false } = {}) {
134
+ if (!gqlType)
135
+ return "";
136
+ const maybeWrapped = (it) => required || selection ? it : `Maybe<${it}>`;
137
+ if (typeof gqlType === "string") {
138
+ return maybeWrapped(gqlType);
139
+ }
140
+ if (gqlType.kind.endsWith("OBJECT")) {
141
+ return maybeWrapped(gqlType.name + (selection ? "Selection" : ""));
142
+ }
143
+ if (gqlType.kind === "NON_NULL") {
144
+ return `${gqlTypeToTypescript(gqlType.ofType, {
145
+ isInput,
146
+ required: true,
147
+ selection
148
+ })}`;
149
+ }
150
+ if (gqlType.kind === "LIST") {
151
+ return maybeWrapped(
152
+ `${gqlTypeToTypescript(gqlType.ofType, {
153
+ isInput,
154
+ required: true,
155
+ selection
156
+ })}${selection ? "" : "[]"}`
157
+ );
158
+ }
159
+ if (selection) {
160
+ return "";
161
+ }
162
+ if (gqlType.kind === "ENUM" && gqlType.name) {
163
+ return maybeWrapped(gqlType.name);
164
+ }
165
+ if (gqlType.kind === "SCALAR") {
166
+ return maybeWrapped(gqlScalarToTypescript(gqlType.name));
167
+ }
168
+ return "";
169
+ }
170
+ function gqlFieldToTypescript(field, { isInput, selection, defaultValue }) {
171
+ let fieldTypeDefinition = gqlTypeToTypescript(field.type, {
172
+ isInput,
173
+ selection
174
+ });
175
+ fieldTypeDefinition = `${fieldTypeDefinition}`;
176
+ if (selection && field.args && field.args.length) {
177
+ let fieldsOnArgs = field.args.map(
178
+ (arg) => gqlFieldToTypescript(arg, {
179
+ defaultValue: arg.defaultValue,
180
+ isInput: true,
181
+ selection: false
182
+ })
183
+ );
184
+ fieldTypeDefinition = `{ __headers?: {[key: string]: string}; __retry?: boolean; __alias?: string; __url?: string; __args${fieldsOnArgs.every((arg) => arg.isOptional) ? "?" : ""}: { ${fieldsOnArgs.map((arg) => arg.code).join(", ")} }}${fieldTypeDefinition ? ` & ${fieldTypeDefinition}` : ""}`;
185
+ }
186
+ const isOptional = defaultValue || selection || fieldTypeDefinition.startsWith("Maybe");
187
+ const rawType = fieldTypeDefinition || selection && "boolean";
188
+ const wrappedType = isOptional ? rawType.replace(/Maybe<(.+?)>/, "$1") : rawType;
189
+ return {
190
+ isOptional,
191
+ code: `${field.name}${isOptional ? "?:" : ":"} ${wrappedType}`
192
+ };
193
+ }
194
+ function getArgsType(endpoint) {
195
+ const fieldsOnArgs = endpoint.args.map(
196
+ (arg) => gqlFieldToTypescript(arg, {
197
+ defaultValue: arg.defaultValue,
198
+ isInput: true,
199
+ selection: false
200
+ })
201
+ );
202
+ const argsType = `{ ${fieldsOnArgs.map((arg) => arg.code).join(", ")} }`;
203
+ const argsFullyOptional = fieldsOnArgs.every((arg) => arg.isOptional);
204
+ return { alias: Case.pascal(`${endpoint.name}Args`), type: argsType, optional: argsFullyOptional };
205
+ }
206
+ function gqlEndpointToCode(kind, endpoint, codeOutputType) {
207
+ const selectionType = gqlTypeToTypescript(endpoint.type, {
208
+ isInput: false,
209
+ selection: true
210
+ });
211
+ const argsType = endpoint.args && endpoint.args.length ? getArgsType(endpoint) : null;
212
+ const inputType = `{
213
+ __headers?: {[key: string]: string};
214
+ __retry?: boolean;
215
+ __alias?: string;
216
+ __url?: string;
217
+ ${argsType ? `__args${argsType.optional ? "?" : ""}: ${argsType.alias}` : ""}
218
+ }${selectionType ? ` & ${selectionType}` : ""}`;
219
+ const outputType = gqlTypeToTypescript(endpoint.type, { required: true });
220
+ return codeOutputType === "ts" ? `${endpoint.name}: Endpoint<${inputType}, ${outputType}, AllEnums>` : `${endpoint.name}: apiEndpoint('${kind}', '${endpoint.name}')`;
221
+ }
222
+ function gqlSchemaToCode(gqlType, { selection = false, outputType }) {
223
+ const rawKind = gqlType.kind || gqlType.type;
224
+ if (rawKind === "SCALAR") {
225
+ return outputType === "ts" ? `export declare type ${gqlType.name} = ${/date/i.test(gqlType.name) ? "IDate" : "string"}` : "";
226
+ }
227
+ if (rawKind === "ENUM")
228
+ return outputType === "ts" ? `
229
+ export declare enum ${gqlType.name} {
230
+ ${orderBy(gqlType.enumValues, "name").map((_) => `${Case.camel(_.name)} = '${_.name}'`).join(",\n ")}
231
+ }` : `export const ${gqlType.name} = {${orderBy(gqlType.enumValues, "name").map((_) => `${Case.camel(_.name)}: '${_.name}'`).join(",\n ")}}`;
232
+ const fields = gqlType.fields && gqlType.fields || gqlType.inputFields && gqlType.inputFields || [];
233
+ return outputType === "ts" ? `
234
+ export interface ${gqlType.name}${selection ? "Selection" : ""} {
235
+ ${fields.map(
236
+ (_) => gqlFieldToTypescript(_, {
237
+ isInput: gqlType.kind === "INPUT_OBJECT",
238
+ selection
239
+ }).code
240
+ ).join(",\n ")}
241
+ }` : "";
242
+ }
243
+ function getGraphQLInputType(type) {
244
+ switch (type.kind) {
245
+ case "NON_NULL":
246
+ return `${getGraphQLInputType(type.ofType)}!`;
247
+ case "SCALAR":
248
+ case "INPUT_OBJECT":
249
+ case "ENUM":
250
+ return type.name;
251
+ case "LIST":
252
+ return `[${getGraphQLInputType(type.ofType)}]`;
253
+ default:
254
+ return "";
255
+ }
256
+ }
257
+ function getGraphQLOutputType(type) {
258
+ switch (type.kind) {
259
+ case "LIST":
260
+ return `${getGraphQLOutputType(type.ofType)}[]`;
261
+ case "NON_NULL":
262
+ return getGraphQLOutputType(type.ofType);
263
+ case "OBJECT":
264
+ return type.name;
265
+ default:
266
+ return "";
267
+ }
268
+ }
269
+ function getTypesTreeCode(types) {
270
+ const typesTree = {};
271
+ types.forEach(
272
+ (type) => type.fields.filter((_) => _.args && _.args.length).forEach(
273
+ (_) => _.args.forEach((a) => {
274
+ let inputType = getGraphQLInputType(a.type);
275
+ if (inputType) {
276
+ set(typesTree, `${type.name}.${_.name}.__args.${a.name}`, inputType);
277
+ }
278
+ })
279
+ )
280
+ );
281
+ types.forEach(
282
+ (t) => t.fields.forEach((f) => {
283
+ let outputType = getGraphQLOutputType(f.type);
284
+ if (outputType) {
285
+ set(typesTree, `${t.name}.${f.name}.__shape`, outputType);
286
+ }
287
+ })
288
+ );
289
+ return `
290
+ const typesTree = {
291
+ ${Object.entries(typesTree).map(([key, value]) => {
292
+ let entryCode = Object.entries(value).map(([k, v]) => {
293
+ const cleanShapeType = v.__shape && v.__shape.replace(/[\[\]!?]/g, "");
294
+ const fieldsCode = v.__shape && typesTree.hasOwnProperty(cleanShapeType) ? `__fields: typesTree.${cleanShapeType},` : "";
295
+ const argsCode = v.__args ? `__args: {
296
+ ${Object.entries(v.__args).map(([k2, v2]) => `${k2}: '${v2}'`).join(",\n")}
297
+ }` : "";
298
+ return fieldsCode || argsCode ? `get ${k}() {
299
+ return {
300
+ ${fieldsCode}
301
+ ${argsCode}
302
+ }
303
+ }` : `${k}: {}`;
304
+ }).filter(Boolean).join(",\n").trim();
305
+ return entryCode && `
306
+ ${key}: {
307
+ ${entryCode}
308
+ }`;
309
+ }).filter(Boolean).join(",\n")}
310
+ }
311
+ `;
312
+ }
313
+ function generateClientCode(types, options) {
314
+ const typesHash = md5(`${JSON.stringify(options)}__${JSON.stringify(types)}`);
315
+ const clientCacheFileName = `gql-ts-client__client__${typesHash}__${package_default.version}.json`;
316
+ const clientCacheFilePath = path.resolve(tempDir, clientCacheFileName);
317
+ if (!options.skipCache && fs.existsSync(clientCacheFilePath)) {
318
+ const output2 = JSON.parse(fs.readFileSync(clientCacheFilePath, { encoding: "utf8" }));
319
+ if (output2.js && output2.mjs && output2.typings) {
320
+ return output2;
321
+ }
322
+ }
323
+ const queries = types.find((it) => it.name === "Query")?.fields || [];
324
+ const mutations = types.find((it) => it.name === "Mutation")?.fields || [];
325
+ const enums = types.filter((it) => it.kind === "ENUM" && !it.name.startsWith("__"));
326
+ const scalars = types.filter(
327
+ (it) => it.kind === "SCALAR" && !/decimal|int|float|string|long|boolean/i.test(it.name)
328
+ );
329
+ const objectTypes = types.filter((it) => ["OBJECT", "INPUT_OBJECT"].includes(it.kind) && !it.name.startsWith("__"));
330
+ const forInputExtraction = types.filter(
331
+ (it) => !it.name.startsWith("__") && ["OBJECT"].includes(it.kind)
332
+ );
333
+ const clientName = options.clientName || "client";
334
+ const jsCode = `
335
+ // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols
336
+ import { getApiEndpointCreator } from '${graphqlTsClientPath}/endpoint'
337
+
338
+ ${options.formatGraphQL || options.verbose ? `
339
+ import { format as formatCode } from "prettier/standalone"
340
+ import parserGraphql from "prettier/parser-graphql"
341
+
342
+ const formatGraphQL = (query) => formatCode(query, {parser: 'graphql', plugins: [parserGraphql]})` : `
343
+ const formatGraphQL = (query) => query`}
344
+
345
+ // Enums
346
+ ${enums.map((it) => gqlSchemaToCode(it, { selection: false, outputType: "js" })).join("\n")}
347
+
348
+ // Schema Resolution Tree
349
+ ${getTypesTreeCode(forInputExtraction)}
350
+
351
+ let verbose = ${Boolean(options.verbose)}
352
+ let headers = {}
353
+ let url = '${options.endpoint}'
354
+ let retryConfig = {
355
+ max: 0,
356
+ before: undefined,
357
+ waitBeforeRetry: 0
358
+ }
359
+ let responseListeners = []
360
+ let errorsParser = ${options.errorsParser}
361
+ // noinspection JSUnusedLocalSymbols
362
+ let apiEndpoint = getApiEndpointCreator({
363
+ getClient: () => ({ url, headers, retryConfig }),
364
+ responseListeners,
365
+ maxAge: 30000,
366
+ verbose,
367
+ typesTree,
368
+ formatGraphQL,
369
+ errorsParser
370
+ })
371
+
372
+ export const ${clientName} = {
373
+ addResponseListener: (listener) => responseListeners.push(
374
+ listener),
375
+ setHeader: (key, value) => {
376
+ headers[key] = value
377
+ },
378
+ setHeaders: (newHeaders) => {
379
+ headers = newHeaders
380
+ },
381
+ setRetryConfig: (options) => {
382
+ if (!Number.isInteger(options.max) || options.max < 0) {
383
+ throw new Error('retryOptions.max should be a non-negative integer')
384
+ }
385
+
386
+ retryConfig = {
387
+ max: options.max,
388
+ waitBeforeRetry: options.waitBeforeRetry,
389
+ before: options.before
390
+ }
391
+ },
392
+ setUrl: (_url) => url = _url,
393
+ queries: {
394
+ ${queries.map((query) => gqlEndpointToCode("query", query, "js")).join(",\n")}
395
+ },
396
+ mutations: {
397
+ ${mutations.map((mutation) => gqlEndpointToCode("mutation", mutation, "js")).join(",\n")}
398
+ }
399
+ }
400
+
401
+ export default ${clientName}`;
402
+ const typingsCode = `
403
+ // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
404
+ import { DeepRequired } from 'ts-essentials'
405
+ import { Maybe, IResponseListener, Endpoint } from '${graphqlTsClientPath}'
406
+
407
+ // Scalars
408
+ export type IDate = string | Date
409
+ ${scalars.map((it) => gqlSchemaToCode(it, { selection: false, outputType: "ts" })).join("\n")}
410
+
411
+ // Enums
412
+ ${enums.map((it) => gqlSchemaToCode(it, { selection: false, outputType: "ts" })).join("\n")}
413
+
414
+ type AllEnums = ${enums.length ? enums.map((it) => it.name).join(" | ") : "never"}
415
+
416
+ // Args
417
+ ${[...queries, ...mutations].map((query) => {
418
+ const argsType = getArgsType(query);
419
+ return `export interface ${argsType.alias} ${argsType.type}`;
420
+ }).join("\n")}
421
+
422
+ // Input/Output Types
423
+ ${objectTypes.map(
424
+ (it) => `
425
+ /**
426
+ * @deprecated Avoid directly using this interface. Instead, create a type alias based on the query/mutation return type.
427
+ */
428
+ ${gqlSchemaToCode(it, { selection: false, outputType: "ts" })}`
429
+ ).join("\n")}
430
+
431
+ // Selection Types
432
+ ${objectTypes.filter((it) => it.name !== "Query").map((it) => gqlSchemaToCode(it, { selection: true, outputType: "ts" })).join("\n")}
433
+
434
+ export declare const ${clientName}: {
435
+ addResponseListener: (listener: IResponseListener) => void
436
+ setHeader: (key: string, value: string) => void
437
+ setHeaders: (newHeaders: { [k: string]: string }) => void,
438
+ setUrl: (url: string) => void,
439
+ setRetryConfig: (options: { max: number, waitBeforeRetry?: number, before?: IResponseListener }) => void
440
+ queries: {
441
+ ${queries.map((q) => gqlEndpointToCode("query", q, "ts")).join(",\n")}
442
+ },
443
+ mutations: {
444
+ ${mutations.map((q) => gqlEndpointToCode("mutation", q, "ts")).join(",\n")}
445
+ }
446
+ }
447
+
448
+ export default ${clientName}`;
449
+ const output = {
450
+ js: esbuild.transformSync(jsCode, { format: "cjs", loader: "js" }).code,
451
+ mjs: esbuild.transformSync(jsCode, { format: "esm", loader: "js" }).code,
452
+ typings: prettier.format(typingsCode, { semi: false, parser: "typescript" })
453
+ };
454
+ fs.writeFileSync(clientCacheFilePath, JSON.stringify(output));
455
+ return output;
456
+ }
457
+ async function fetchIntrospection({ endpoint, headers }) {
458
+ const introspectionCacheFileName = `gql-ts-client__introspection__${kebabCase(endpoint)}.json`;
459
+ const introspectionCacheFilePath = path.resolve(tempDir, introspectionCacheFileName);
460
+ let loadedFromCache = false;
461
+ let types;
462
+ const { data } = await axios.post(
463
+ endpoint,
464
+ { query: getIntrospectionQuery() },
465
+ {
466
+ headers: {
467
+ "Content-Type": "application/json",
468
+ ...headers
469
+ }
470
+ }
471
+ ).catch((e) => {
472
+ const errorMessage = `The GraphQL introspection request failed (${endpoint})`;
473
+ if (fs.existsSync(introspectionCacheFilePath)) {
474
+ const cachedSchema = JSON.parse(fs.readFileSync(introspectionCacheFilePath, { encoding: "utf8" }));
475
+ loadedFromCache = true;
476
+ console.warn(`Successfully restored from local cache.`);
477
+ return { data: cachedSchema };
478
+ } else {
479
+ console.error(e);
480
+ return Promise.reject(errorMessage);
481
+ }
482
+ });
483
+ types = data.data.__schema.types;
484
+ if (!loadedFromCache) {
485
+ console.log(`Successfully loaded GraphQL introspection from ${endpoint}`);
486
+ fs.writeFileSync(introspectionCacheFilePath, JSON.stringify(data), {
487
+ encoding: "utf8"
488
+ });
489
+ }
490
+ return types;
491
+ }
492
+ function generateClient(introspectionTypes, { output, ...restOptions }) {
493
+ const { js, mjs, typings } = generateClientCode(introspectionTypes, restOptions);
494
+ if (output && typeof output === "string") {
495
+ const outputDir = path.dirname(output);
496
+ if (!fs.existsSync(outputDir)) {
497
+ fs.mkdirSync(outputDir, { recursive: true });
498
+ }
499
+ fs.writeFileSync(output.replace(/(\.(ts|js))?$/, ".d.ts"), typings, { encoding: "utf8" });
500
+ fs.writeFileSync(output.replace(/(\.(ts|js))?$/, ".js"), js, { encoding: "utf8" });
501
+ fs.writeFileSync(output.replace(/(\.(ts|js))?$/, ".mjs"), mjs, { encoding: "utf8" });
502
+ }
503
+ return { js, mjs, typings };
504
+ }
505
+ async function generateTypescriptClient({
506
+ introspectionEndpoint,
507
+ ...options
508
+ }) {
509
+ console.log(`Generating TypeScript client (name: ${options.clientName ?? "n/a"})`);
510
+ axiosRetry(axios, { retries: 5, retryDelay: (retryCount) => 1e3 * 2 ** retryCount });
511
+ const introspectionTypes = await fetchIntrospection({
512
+ ...options,
513
+ endpoint: introspectionEndpoint || options.endpoint
514
+ });
515
+ return generateClient(introspectionTypes, options);
516
+ }
517
+ function generateTypescriptClientFromSDL(SDL, options) {
518
+ console.log(`Generating TypeScript client from SDL (name: ${options.clientName ?? "n/a"})`);
519
+ const graphqlSchemaObj = buildSchema(SDL);
520
+ const introspectionTypes = graphqlSync(graphqlSchemaObj, new Source(getIntrospectionQuery())).data?.__schema.types;
521
+ return generateClient(introspectionTypes, options);
522
+ }
523
+ export {
524
+ GraphQLClientError,
525
+ generateTypescriptClient,
526
+ generateTypescriptClientFromSDL
527
+ };
@@ -0,0 +1,75 @@
1
+ type Maybe<T> = null | undefined | T;
2
+ type Defined<T> = Exclude<T, undefined>;
3
+ type ResponseData = {
4
+ data: any;
5
+ warnings: any;
6
+ headers: any;
7
+ status?: number;
8
+ errors: {
9
+ message: string;
10
+ }[];
11
+ };
12
+ type ResponseListenerInfo = {
13
+ queryName: string;
14
+ query: string;
15
+ variables: any;
16
+ response: ResponseData;
17
+ };
18
+ type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
19
+ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
20
+ type Primitive = Date | string | number | boolean | null | undefined;
21
+ type Projection<Selection, Base, E = never> = Base extends Array<any> ? ArrayElement<Base> extends Primitive | E ? ArrayElement<Base>[] : Projection<Defined<Selection>, ArrayElement<Base>, E>[] : Base extends Primitive | E ? Selection extends undefined ? Base | undefined : Base : {
22
+ [k in keyof Selection & keyof Base]: Selection[k] extends boolean ? Base[k] : Base[k] extends Array<infer A> ? Projection<Defined<Selection[k]>, A, E>[] : Projection<Defined<Selection[k]>, Base[k], E>;
23
+ };
24
+ type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
25
+ type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
26
+ type DeepReplace<T, Ignore, M extends [any, any]> = {
27
+ [P in keyof T]: T[P] extends M[0] ? T[P] extends Ignore ? T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P] : Replacement<M, T[P]> : T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P];
28
+ };
29
+ type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
30
+ data: Projection<S, O, E>;
31
+ errors: any[];
32
+ warnings: any[];
33
+ headers: any;
34
+ status: any;
35
+ }>;
36
+ type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
37
+ type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
38
+ memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
39
+ memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
40
+ raw: RawEndpoint<I, JsonOutput<O, E>, E>;
41
+ };
42
+ type ClientConfig = {
43
+ url: string;
44
+ headers: {
45
+ [key: string]: string;
46
+ };
47
+ retryConfig: {
48
+ max: number;
49
+ waitBeforeRetry?: number;
50
+ before: IResponseListener;
51
+ };
52
+ };
53
+ type LogInfo = {
54
+ query: string;
55
+ variables: any;
56
+ formatGraphQL: any;
57
+ kind: string;
58
+ queryName: string;
59
+ response?: any;
60
+ error?: Error;
61
+ duration: number;
62
+ };
63
+ type TypescriptClientOutput = {
64
+ js: string;
65
+ mjs: string;
66
+ typings: string;
67
+ };
68
+ declare class GraphQLClientError extends Error {
69
+ responseData: ResponseData;
70
+ constructor(responseData: ResponseData);
71
+ get message(): string;
72
+ get response(): ResponseData;
73
+ }
74
+
75
+ export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IResponseListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, TypescriptClientOutput as T, Unpacked as U, ResponseListenerInfo as a, Replacement as b, DeepReplace as c, RawEndpoint as d };
@@ -0,0 +1,70 @@
1
+ type Maybe<T> = null | undefined | T;
2
+ type Defined<T> = Exclude<T, undefined>;
3
+ type ResponseData = {
4
+ data: any;
5
+ warnings: any;
6
+ headers: any;
7
+ status?: number;
8
+ errors: {
9
+ message: string;
10
+ }[];
11
+ };
12
+ type ResponseListenerInfo = {
13
+ queryName: string;
14
+ query: string;
15
+ variables: any;
16
+ response: ResponseData;
17
+ };
18
+ type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
19
+ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
20
+ type Primitive = Date | string | number | boolean | null | undefined;
21
+ type Projection<Selection, Base, E = never> = Base extends Array<any> ? ArrayElement<Base> extends Primitive | E ? ArrayElement<Base>[] : Projection<Defined<Selection>, ArrayElement<Base>, E>[] : Base extends Primitive | E ? Selection extends undefined ? Base | undefined : Base : {
22
+ [k in keyof Selection & keyof Base]: Selection[k] extends boolean ? Base[k] : Base[k] extends Array<infer A> ? Projection<Defined<Selection[k]>, A, E>[] : Projection<Defined<Selection[k]>, Base[k], E>;
23
+ };
24
+ type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
25
+ type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
26
+ type DeepReplace<T, Ignore, M extends [any, any]> = {
27
+ [P in keyof T]: T[P] extends M[0] ? T[P] extends Ignore ? T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P] : Replacement<M, T[P]> : T[P] extends object ? DeepReplace<T[P], Ignore, M> : T[P];
28
+ };
29
+ type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
30
+ data: Projection<S, O, E>;
31
+ errors: any[];
32
+ warnings: any[];
33
+ headers: any;
34
+ status: any;
35
+ }>;
36
+ type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
37
+ type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
38
+ memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
39
+ memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
40
+ raw: RawEndpoint<I, JsonOutput<O, E>, E>;
41
+ };
42
+ type ClientConfig = {
43
+ url: string;
44
+ headers: {
45
+ [key: string]: string;
46
+ };
47
+ retryConfig: {
48
+ max: number;
49
+ waitBeforeRetry?: number;
50
+ before: IResponseListener;
51
+ };
52
+ };
53
+ type LogInfo = {
54
+ query: string;
55
+ variables: any;
56
+ formatGraphQL: any;
57
+ kind: string;
58
+ queryName: string;
59
+ response?: any;
60
+ error?: Error;
61
+ duration: number;
62
+ };
63
+ declare class GraphQLClientError extends Error {
64
+ responseData: ResponseData;
65
+ constructor(responseData: ResponseData);
66
+ get message(): string;
67
+ get response(): ResponseData;
68
+ }
69
+
70
+ export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IResponseListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, Unpacked as U, ResponseListenerInfo as a, Replacement as b, DeepReplace as c, RawEndpoint as d };