@avantstay/graphql-ts-client 12.0.2 → 12.1.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.
@@ -1,7 +1,8 @@
1
- import { C as ClientConfig, I as IResponseListener, E as Endpoint } from './types-23d2d6aa.js';
1
+ import { C as ClientConfig, I as IRequestListener, c as IResponseListener, E as Endpoint } from './types-c6f94d0b.js';
2
2
 
3
3
  declare const getApiEndpointCreator: (apiConfig: {
4
4
  getClient: () => ClientConfig;
5
+ requestListeners: IRequestListener[];
5
6
  responseListeners: IResponseListener[];
6
7
  typesTree: any;
7
8
  maxAge: number;
package/dist/endpoint.js CHANGED
@@ -724,13 +724,11 @@ var getApiEndpointCreator = function(apiConfig) {
724
724
  return function(kind, queryName) {
725
725
  var rawEndpoint = function() {
726
726
  var _ref = _asyncToGenerator(function(failureMode, jsonQuery) {
727
- var clientConfig, _jsonQuery___alias, alias, _jsonQuery___url, url, _jsonQuery___retry, shouldRetry, _jsonQuery___headers, requestHeaders, _jsonToGraphQLQuery, query, variables, start, logOptions, responseListenerData, _ref, data, errors, warnings, headers, status, response, error;
727
+ var _jsonQuery___alias, alias, _jsonQuery___retry, shouldRetry, _jsonQuery___headers, requestHeaders, _jsonToGraphQLQuery, query, variables, start, logOptions, listenerData, clientConfig, _jsonQuery___url, url, _ref, data, errors, warnings, headers, status, response, error;
728
728
  return __generator(this, function(_state) {
729
729
  switch(_state.label){
730
730
  case 0:
731
- clientConfig = apiConfig.getClient();
732
731
  alias = (_jsonQuery___alias = jsonQuery === null || jsonQuery === void 0 ? void 0 : jsonQuery.__alias) !== null && _jsonQuery___alias !== void 0 ? _jsonQuery___alias : queryName;
733
- url = (_jsonQuery___url = jsonQuery === null || jsonQuery === void 0 ? void 0 : jsonQuery.__url) !== null && _jsonQuery___url !== void 0 ? _jsonQuery___url : clientConfig.url;
734
732
  shouldRetry = (_jsonQuery___retry = jsonQuery === null || jsonQuery === void 0 ? void 0 : jsonQuery.__retry) !== null && _jsonQuery___retry !== void 0 ? _jsonQuery___retry : true;
735
733
  requestHeaders = (_jsonQuery___headers = jsonQuery === null || jsonQuery === void 0 ? void 0 : jsonQuery.__headers) !== null && _jsonQuery___headers !== void 0 ? _jsonQuery___headers : {};
736
734
  _jsonToGraphQLQuery = jsonToGraphQLQuery({
@@ -748,18 +746,29 @@ var getApiEndpointCreator = function(apiConfig) {
748
746
  query: query,
749
747
  variables: variables
750
748
  };
751
- responseListenerData = {
749
+ listenerData = {
752
750
  queryName: alias,
753
751
  query: apiConfig.formatGraphQL(query),
754
- variables: variables
752
+ variables: variables,
753
+ headers: _objectSpread({}, requestHeaders)
755
754
  };
756
- _state.label = 1;
755
+ return [
756
+ 4,
757
+ Promise.all(apiConfig.requestListeners.map(function(listener) {
758
+ return listener(listenerData);
759
+ }))
760
+ ];
757
761
  case 1:
762
+ _state.sent();
763
+ clientConfig = apiConfig.getClient();
764
+ url = (_jsonQuery___url = jsonQuery === null || jsonQuery === void 0 ? void 0 : jsonQuery.__url) !== null && _jsonQuery___url !== void 0 ? _jsonQuery___url : clientConfig.url;
765
+ _state.label = 2;
766
+ case 2:
758
767
  _state.trys.push([
759
- 1,
760
- 3,
768
+ 2,
769
+ 4,
761
770
  ,
762
- 4
771
+ 5
763
772
  ]);
764
773
  return [
765
774
  4,
@@ -770,13 +779,13 @@ var getApiEndpointCreator = function(apiConfig) {
770
779
  client: _objectSpreadProps(_objectSpread({}, clientConfig), {
771
780
  url: url
772
781
  }),
773
- requestHeaders: requestHeaders,
782
+ requestHeaders: listenerData.headers,
774
783
  query: query,
775
784
  variables: variables,
776
785
  errorsParser: apiConfig.errorsParser
777
786
  })
778
787
  ];
779
- case 2:
788
+ case 3:
780
789
  _ref = _state.sent(), data = _ref.data, errors = _ref.errors, warnings = _ref.warnings, headers = _ref.headers, status = _ref.status;
781
790
  response = {
782
791
  data: data,
@@ -791,7 +800,7 @@ var getApiEndpointCreator = function(apiConfig) {
791
800
  duration: +new Date() - start
792
801
  }));
793
802
  }
794
- executeListeners(apiConfig.responseListeners, _objectSpreadProps(_objectSpread({}, responseListenerData), {
803
+ executeListeners(apiConfig.responseListeners, _objectSpreadProps(_objectSpread({}, listenerData), {
795
804
  response: response
796
805
  }));
797
806
  return [
@@ -804,7 +813,7 @@ var getApiEndpointCreator = function(apiConfig) {
804
813
  status: status
805
814
  }
806
815
  ];
807
- case 3:
816
+ case 4:
808
817
  error = _state.sent();
809
818
  if (apiConfig.verbose && globalThis.document) {
810
819
  logRequest(_objectSpreadProps(_objectSpread({}, logOptions), {
@@ -812,11 +821,11 @@ var getApiEndpointCreator = function(apiConfig) {
812
821
  duration: +new Date() - start
813
822
  }));
814
823
  }
815
- executeListeners(apiConfig.responseListeners, _objectSpreadProps(_objectSpread({}, responseListenerData), {
824
+ executeListeners(apiConfig.responseListeners, _objectSpreadProps(_objectSpread({}, listenerData), {
816
825
  response: error.response
817
826
  }));
818
827
  throw error;
819
- case 4:
828
+ case 5:
820
829
  return [
821
830
  2
822
831
  ];
package/dist/endpoint.mjs CHANGED
@@ -197,9 +197,7 @@ function logRequest(logInfo) {
197
197
  var executeListeners = (listeners, data) => setTimeout(() => listeners.forEach((runResponseListener) => runResponseListener(data)));
198
198
  var getApiEndpointCreator = (apiConfig) => (kind, queryName) => {
199
199
  const rawEndpoint = async (failureMode, jsonQuery) => {
200
- const clientConfig = apiConfig.getClient();
201
200
  const alias = jsonQuery?.__alias ?? queryName;
202
- const url = jsonQuery?.__url ?? clientConfig.url;
203
201
  const shouldRetry = jsonQuery?.__retry ?? true;
204
202
  const requestHeaders = jsonQuery?.__headers ?? {};
205
203
  const { query, variables } = jsonToGraphQLQuery({ kind, queryName, jsonQuery, typesTree: apiConfig.typesTree });
@@ -212,18 +210,22 @@ var getApiEndpointCreator = (apiConfig) => (kind, queryName) => {
212
210
  query,
213
211
  variables
214
212
  };
215
- const responseListenerData = {
213
+ const listenerData = {
216
214
  queryName: alias,
217
215
  query: apiConfig.formatGraphQL(query),
218
- variables
216
+ variables,
217
+ headers: { ...requestHeaders }
219
218
  };
219
+ await Promise.all(apiConfig.requestListeners.map((listener) => listener(listenerData)));
220
+ const clientConfig = apiConfig.getClient();
221
+ const url = jsonQuery?.__url ?? clientConfig.url;
220
222
  try {
221
223
  const { data, errors, warnings, headers, status } = await graphqlRequest({
222
224
  shouldRetry,
223
225
  failureMode,
224
226
  queryName: alias,
225
227
  client: { ...clientConfig, url },
226
- requestHeaders,
228
+ requestHeaders: listenerData.headers,
227
229
  query,
228
230
  variables,
229
231
  errorsParser: apiConfig.errorsParser
@@ -237,7 +239,7 @@ var getApiEndpointCreator = (apiConfig) => (kind, queryName) => {
237
239
  });
238
240
  }
239
241
  executeListeners(apiConfig.responseListeners, {
240
- ...responseListenerData,
242
+ ...listenerData,
241
243
  response
242
244
  });
243
245
  return { data: data?.[alias], errors, warnings, headers, status };
@@ -250,7 +252,7 @@ var getApiEndpointCreator = (apiConfig) => (kind, queryName) => {
250
252
  });
251
253
  }
252
254
  executeListeners(apiConfig.responseListeners, {
253
- ...responseListenerData,
255
+ ...listenerData,
254
256
  response: error.response
255
257
  });
256
258
  throw error;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { PathLike } from 'fs';
2
- import { T as TypescriptClientOutput } from './types-23d2d6aa.js';
3
- export { C as ClientConfig, c as DeepReplace, D as Defined, E as Endpoint, G as GraphQLClientError, I as IResponseListener, J as JsonOutput, L as LogInfo, M as Maybe, P as Projection, d as RawEndpoint, b as Replacement, R as ResponseData, a as ResponseListenerInfo, T as TypescriptClientOutput, U as Unpacked } from './types-23d2d6aa.js';
2
+ import { T as TypescriptClientOutput } from './types-c6f94d0b.js';
3
+ export { C as ClientConfig, e as DeepReplace, D as Defined, E as Endpoint, G as GraphQLClientError, I as IRequestListener, c as IResponseListener, J as JsonOutput, L as LogInfo, M as Maybe, P as Projection, f as RawEndpoint, d as Replacement, a as RequestListenerInfo, R as ResponseData, b as ResponseListenerInfo, T as TypescriptClientOutput, U as Unpacked } from './types-c6f94d0b.js';
4
4
 
5
5
  type IClientOptions = {
6
6
  output?: PathLike;
package/dist/index.js CHANGED
@@ -487,7 +487,7 @@ var prettier = __toESM(require("prettier"));
487
487
  // package.json
488
488
  var package_default = {
489
489
  name: "@avantstay/graphql-ts-client",
490
- version: "12.0.2",
490
+ version: "12.1.0",
491
491
  description: "GraphQL Typescript Client Generator",
492
492
  homepage: "https://github.com/avantstay/graphql-ts-client",
493
493
  bugs: {
@@ -810,12 +810,12 @@ function generateClientCode(types, options) {
810
810
  selection: false,
811
811
  outputType: "js"
812
812
  });
813
- }).join("\n"), "\n\n // Schema Resolution Tree\n ").concat(getTypesTreeCode(forInputExtraction), "\n\n let verbose = ").concat(Boolean(options.verbose), "\n let headers = {}\n let url = '").concat(options.endpoint, "'\n let retryConfig = {\n max: 0,\n before: undefined,\n waitBeforeRetry: 0\n }\n let responseListeners = []\n let errorsParser = ").concat(options.errorsParser, "\n // noinspection JSUnusedLocalSymbols\n let apiEndpoint = getApiEndpointCreator({\n getClient: () => ({ url, headers, retryConfig }),\n responseListeners,\n maxAge: 30000,\n verbose,\n typesTree,\n formatGraphQL,\n errorsParser\n })\n\n export const ").concat(clientName, " = {\n addResponseListener: (listener) => responseListeners.push(\n listener),\n setHeader: (key, value) => {\n headers[key] = value\n },\n setHeaders: (newHeaders) => {\n headers = newHeaders\n },\n setRetryConfig: (options) => {\n if (!Number.isInteger(options.max) || options.max < 0) {\n throw new Error('retryOptions.max should be a non-negative integer')\n }\n \n retryConfig = { \n max: options.max,\n waitBeforeRetry: options.waitBeforeRetry,\n before: options.before \n }\n },\n setUrl: (_url) => url = _url,\n queries: {\n ").concat(queries.map(function(query) {
813
+ }).join("\n"), "\n\n // Schema Resolution Tree\n ").concat(getTypesTreeCode(forInputExtraction), "\n\n let verbose = ").concat(Boolean(options.verbose), "\n let headers = {}\n let url = '").concat(options.endpoint, "'\n let retryConfig = {\n max: 0,\n before: undefined,\n waitBeforeRetry: 0\n }\n let requestListeners = []\n let responseListeners = []\n let errorsParser = ").concat(options.errorsParser, "\n // noinspection JSUnusedLocalSymbols\n let apiEndpoint = getApiEndpointCreator({\n getClient: () => ({ url, headers, retryConfig }),\n requestListeners,\n responseListeners,\n maxAge: 30000,\n verbose,\n typesTree,\n formatGraphQL,\n errorsParser\n })\n\n export const ").concat(clientName, " = {\n addRequestListener: (listener) => requestListeners.push(listener),\n addResponseListener: (listener) => responseListeners.push(\n listener),\n setHeader: (key, value) => {\n headers[key] = value\n },\n setHeaders: (newHeaders) => {\n headers = newHeaders\n },\n setRetryConfig: (options) => {\n if (!Number.isInteger(options.max) || options.max < 0) {\n throw new Error('retryOptions.max should be a non-negative integer')\n }\n \n retryConfig = { \n max: options.max,\n waitBeforeRetry: options.waitBeforeRetry,\n before: options.before \n }\n },\n setUrl: (_url) => url = _url,\n queries: {\n ").concat(queries.map(function(query) {
814
814
  return gqlEndpointToCode("query", query, "js");
815
815
  }).join(",\n"), "\n },\n mutations: {\n ").concat(mutations.map(function(mutation) {
816
816
  return gqlEndpointToCode("mutation", mutation, "js");
817
817
  }).join(",\n"), "\n }\n }\n\n export default ").concat(clientName);
818
- var typingsCode = "\n // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport\n import { DeepRequired } from 'ts-essentials'\n import { Maybe, IResponseListener, Endpoint } from '".concat(graphqlTsClientPath, "'\n\n // Scalars\n export type IDate = string | Date\n ").concat(scalars.map(function(it) {
818
+ var typingsCode = "\n // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport\n import { DeepRequired } from 'ts-essentials'\n import { Maybe, IRequestListener, IResponseListener, Endpoint } from '".concat(graphqlTsClientPath, "'\n\n // Scalars\n export type IDate = string | Date\n ").concat(scalars.map(function(it) {
819
819
  return gqlSchemaToCode(it, {
820
820
  selection: false,
821
821
  outputType: "ts"
@@ -842,7 +842,7 @@ function generateClientCode(types, options) {
842
842
  selection: true,
843
843
  outputType: "ts"
844
844
  });
845
- }).join("\n"), "\n \n export declare const ").concat(clientName, ": {\n addResponseListener: (listener: IResponseListener) => void\n setHeader: (key: string, value: string) => void\n setHeaders: (newHeaders: { [k: string]: string }) => void,\n setUrl: (url: string) => void,\n setRetryConfig: (options: { max: number, waitBeforeRetry?: number, before?: IResponseListener }) => void\n queries: {\n ").concat(queries.map(function(q) {
845
+ }).join("\n"), "\n \n export declare const ").concat(clientName, ": {\n addRequestListener: (listener: IRequestListener) => void\n addResponseListener: (listener: IResponseListener) => void\n setHeader: (key: string, value: string) => void\n setHeaders: (newHeaders: { [k: string]: string }) => void,\n setUrl: (url: string) => void,\n setRetryConfig: (options: { max: number, waitBeforeRetry?: number, before?: IResponseListener }) => void\n queries: {\n ").concat(queries.map(function(q) {
846
846
  return gqlEndpointToCode("query", q, "ts");
847
847
  }).join(",\n"), "\n },\n mutations: {\n ").concat(mutations.map(function(q) {
848
848
  return gqlEndpointToCode("mutation", q, "ts");
package/dist/index.mjs CHANGED
@@ -24,7 +24,7 @@ import * as prettier from "prettier";
24
24
  // package.json
25
25
  var package_default = {
26
26
  name: "@avantstay/graphql-ts-client",
27
- version: "12.0.2",
27
+ version: "12.1.0",
28
28
  description: "GraphQL Typescript Client Generator",
29
29
  homepage: "https://github.com/avantstay/graphql-ts-client",
30
30
  bugs: {
@@ -355,11 +355,13 @@ function generateClientCode(types, options) {
355
355
  before: undefined,
356
356
  waitBeforeRetry: 0
357
357
  }
358
+ let requestListeners = []
358
359
  let responseListeners = []
359
360
  let errorsParser = ${options.errorsParser}
360
361
  // noinspection JSUnusedLocalSymbols
361
362
  let apiEndpoint = getApiEndpointCreator({
362
363
  getClient: () => ({ url, headers, retryConfig }),
364
+ requestListeners,
363
365
  responseListeners,
364
366
  maxAge: 30000,
365
367
  verbose,
@@ -369,6 +371,7 @@ function generateClientCode(types, options) {
369
371
  })
370
372
 
371
373
  export const ${clientName} = {
374
+ addRequestListener: (listener) => requestListeners.push(listener),
372
375
  addResponseListener: (listener) => responseListeners.push(
373
376
  listener),
374
377
  setHeader: (key, value) => {
@@ -401,7 +404,7 @@ function generateClientCode(types, options) {
401
404
  const typingsCode = `
402
405
  // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
403
406
  import { DeepRequired } from 'ts-essentials'
404
- import { Maybe, IResponseListener, Endpoint } from '${graphqlTsClientPath}'
407
+ import { Maybe, IRequestListener, IResponseListener, Endpoint } from '${graphqlTsClientPath}'
405
408
 
406
409
  // Scalars
407
410
  export type IDate = string | Date
@@ -431,6 +434,7 @@ function generateClientCode(types, options) {
431
434
  ${objectTypes.filter((it) => it.name !== "Query").map((it) => gqlSchemaToCode(it, { selection: true, outputType: "ts" })).join("\n")}
432
435
 
433
436
  export declare const ${clientName}: {
437
+ addRequestListener: (listener: IRequestListener) => void
434
438
  addResponseListener: (listener: IResponseListener) => void
435
439
  setHeader: (key: string, value: string) => void
436
440
  setHeaders: (newHeaders: { [k: string]: string }) => void,
@@ -9,6 +9,12 @@ type ResponseData = {
9
9
  message: string;
10
10
  }[];
11
11
  };
12
+ type RequestListenerInfo = {
13
+ queryName: string;
14
+ query: string;
15
+ variables: any;
16
+ };
17
+ type IRequestListener = (info: RequestListenerInfo) => void | Promise<void>;
12
18
  type ResponseListenerInfo = {
13
19
  queryName: string;
14
20
  query: string;
@@ -17,7 +23,8 @@ type ResponseListenerInfo = {
17
23
  };
18
24
  type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
19
25
  type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
20
- type Projection<Selection, Base, E = never> = Base extends Array<any> ? ArrayElement<Base> extends Date | string | number | boolean | null | undefined | E ? ArrayElement<Base>[] : Projection<Defined<Selection>, ArrayElement<Base>, E>[] : Base extends Date | string | number | boolean | null | E ? Selection extends undefined ? Base | undefined : Base : {
26
+ type Primitive = Date | string | number | boolean | null | undefined;
27
+ 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 : {
21
28
  [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>;
22
29
  };
23
30
  type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
@@ -59,6 +66,11 @@ type LogInfo = {
59
66
  error?: Error;
60
67
  duration: number;
61
68
  };
69
+ type TypescriptClientOutput = {
70
+ js: string;
71
+ mjs: string;
72
+ typings: string;
73
+ };
62
74
  declare class GraphQLClientError extends Error {
63
75
  responseData: ResponseData;
64
76
  constructor(responseData: ResponseData);
@@ -66,4 +78,4 @@ declare class GraphQLClientError extends Error {
66
78
  get response(): ResponseData;
67
79
  }
68
80
 
69
- 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 };
81
+ export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IRequestListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, TypescriptClientOutput as T, Unpacked as U, RequestListenerInfo as a, ResponseListenerInfo as b, IResponseListener as c, Replacement as d, DeepReplace as e, RawEndpoint as f };
@@ -0,0 +1,85 @@
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 RequestListenerInfo = {
13
+ url: string;
14
+ queryName: string;
15
+ query: string;
16
+ variables: any;
17
+ headers: {
18
+ [key: string]: string;
19
+ };
20
+ };
21
+ type IRequestListener = (info: RequestListenerInfo) => void | Promise<void>;
22
+ type ResponseListenerInfo = {
23
+ queryName: string;
24
+ query: string;
25
+ variables: any;
26
+ response: ResponseData;
27
+ };
28
+ type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
29
+ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
30
+ type Primitive = Date | string | number | boolean | null | undefined;
31
+ 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 : {
32
+ [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>;
33
+ };
34
+ type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
35
+ type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
36
+ type DeepReplace<T, Ignore, M extends [any, any]> = {
37
+ [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];
38
+ };
39
+ type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
40
+ data: Projection<S, O, E>;
41
+ errors: any[];
42
+ warnings: any[];
43
+ headers: any;
44
+ status: any;
45
+ }>;
46
+ type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
47
+ type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
48
+ memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
49
+ memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
50
+ raw: RawEndpoint<I, JsonOutput<O, E>, E>;
51
+ };
52
+ type ClientConfig = {
53
+ url: string;
54
+ headers: {
55
+ [key: string]: string;
56
+ };
57
+ retryConfig: {
58
+ max: number;
59
+ waitBeforeRetry?: number;
60
+ before: IResponseListener;
61
+ };
62
+ };
63
+ type LogInfo = {
64
+ query: string;
65
+ variables: any;
66
+ formatGraphQL: any;
67
+ kind: string;
68
+ queryName: string;
69
+ response?: any;
70
+ error?: Error;
71
+ duration: number;
72
+ };
73
+ type TypescriptClientOutput = {
74
+ js: string;
75
+ mjs: string;
76
+ typings: string;
77
+ };
78
+ declare class GraphQLClientError extends Error {
79
+ responseData: ResponseData;
80
+ constructor(responseData: ResponseData);
81
+ get message(): string;
82
+ get response(): ResponseData;
83
+ }
84
+
85
+ export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IRequestListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, TypescriptClientOutput as T, Unpacked as U, RequestListenerInfo as a, ResponseListenerInfo as b, IResponseListener as c, Replacement as d, DeepReplace as e, RawEndpoint as f };
@@ -0,0 +1,84 @@
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 RequestListenerInfo = {
13
+ queryName: string;
14
+ query: string;
15
+ variables: any;
16
+ headers: {
17
+ [key: string]: string;
18
+ };
19
+ };
20
+ type IRequestListener = (info: RequestListenerInfo) => void | Promise<void>;
21
+ type ResponseListenerInfo = {
22
+ queryName: string;
23
+ query: string;
24
+ variables: any;
25
+ response: ResponseData;
26
+ };
27
+ type IResponseListener = (info: ResponseListenerInfo) => void | Promise<void>;
28
+ type ArrayElement<ArrayType extends readonly unknown[]> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never;
29
+ type Primitive = Date | string | number | boolean | null | undefined;
30
+ 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 : {
31
+ [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>;
32
+ };
33
+ type Unpacked<T> = T extends (infer U)[] ? U : T extends (...args: any[]) => infer U ? U : T extends Promise<infer U> ? U : T;
34
+ type Replacement<M extends [any, any], T> = M extends any ? ([T] extends [M[0]] ? M[1] : never) : never;
35
+ type DeepReplace<T, Ignore, M extends [any, any]> = {
36
+ [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];
37
+ };
38
+ type RawEndpoint<I, O, E> = <S extends I>(jsonQuery?: S) => Promise<{
39
+ data: Projection<S, O, E>;
40
+ errors: any[];
41
+ warnings: any[];
42
+ headers: any;
43
+ status: any;
44
+ }>;
45
+ type JsonOutput<O, ToBeIgnored> = DeepReplace<O, ToBeIgnored, [string | Date, string]>;
46
+ type Endpoint<I, O, E> = (<S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>) & {
47
+ memo: <S extends I>(jsonQuery?: S) => Promise<Projection<S, JsonOutput<O, E>, E>>;
48
+ memoRaw: RawEndpoint<I, JsonOutput<O, E>, E>;
49
+ raw: RawEndpoint<I, JsonOutput<O, E>, E>;
50
+ };
51
+ type ClientConfig = {
52
+ url: string;
53
+ headers: {
54
+ [key: string]: string;
55
+ };
56
+ retryConfig: {
57
+ max: number;
58
+ waitBeforeRetry?: number;
59
+ before: IResponseListener;
60
+ };
61
+ };
62
+ type LogInfo = {
63
+ query: string;
64
+ variables: any;
65
+ formatGraphQL: any;
66
+ kind: string;
67
+ queryName: string;
68
+ response?: any;
69
+ error?: Error;
70
+ duration: number;
71
+ };
72
+ type TypescriptClientOutput = {
73
+ js: string;
74
+ mjs: string;
75
+ typings: string;
76
+ };
77
+ declare class GraphQLClientError extends Error {
78
+ responseData: ResponseData;
79
+ constructor(responseData: ResponseData);
80
+ get message(): string;
81
+ get response(): ResponseData;
82
+ }
83
+
84
+ export { ClientConfig as C, Defined as D, Endpoint as E, GraphQLClientError as G, IRequestListener as I, JsonOutput as J, LogInfo as L, Maybe as M, Projection as P, ResponseData as R, TypescriptClientOutput as T, Unpacked as U, RequestListenerInfo as a, ResponseListenerInfo as b, IResponseListener as c, Replacement as d, DeepReplace as e, RawEndpoint as f };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avantstay/graphql-ts-client",
3
- "version": "12.0.2",
3
+ "version": "12.1.0",
4
4
  "description": "GraphQL Typescript Client Generator",
5
5
  "homepage": "https://github.com/avantstay/graphql-ts-client",
6
6
  "bugs": {
@@ -91,4 +91,4 @@
91
91
  "limit": "10 KB"
92
92
  }
93
93
  ]
94
- }
94
+ }
@@ -29,7 +29,7 @@ __export(exports, {
29
29
  client: () => client,
30
30
  default: () => stdin_default
31
31
  });
32
- var import_endpoint = __toModule(require("./endpoint"));
32
+ var import_endpoint = __toModule(require("@avantstay/graphql-ts-client/dist/endpoint"));
33
33
  const formatGraphQL = (query) => query;
34
34
  const typesTree = {};
35
35
  let verbose = false;
@@ -40,10 +40,12 @@ let retryConfig = {
40
40
  before: void 0,
41
41
  waitBeforeRetry: 0
42
42
  };
43
+ let requestListeners = [];
43
44
  let responseListeners = [];
44
45
  let errorsParser = void 0;
45
46
  let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
46
47
  getClient: () => ({ url, headers, retryConfig }),
48
+ requestListeners,
47
49
  responseListeners,
48
50
  maxAge: 3e4,
49
51
  verbose,
@@ -52,6 +54,7 @@ let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
52
54
  errorsParser
53
55
  });
54
56
  const client = {
57
+ addRequestListener: (listener) => requestListeners.push(listener),
55
58
  addResponseListener: (listener) => responseListeners.push(listener),
56
59
  setHeader: (key, value) => {
57
60
  headers[key] = value;
@@ -77,7 +80,7 @@ const client = {
77
80
  };
78
81
  var stdin_default = client;
79
82
  ",
80
- "mjs": "import { getApiEndpointCreator } from "./endpoint";
83
+ "mjs": "import { getApiEndpointCreator } from "@avantstay/graphql-ts-client/dist/endpoint";
81
84
  const formatGraphQL = (query) => query;
82
85
  const typesTree = {};
83
86
  let verbose = false;
@@ -88,10 +91,12 @@ let retryConfig = {
88
91
  before: void 0,
89
92
  waitBeforeRetry: 0
90
93
  };
94
+ let requestListeners = [];
91
95
  let responseListeners = [];
92
96
  let errorsParser = void 0;
93
97
  let apiEndpoint = getApiEndpointCreator({
94
98
  getClient: () => ({ url, headers, retryConfig }),
99
+ requestListeners,
95
100
  responseListeners,
96
101
  maxAge: 3e4,
97
102
  verbose,
@@ -100,6 +105,7 @@ let apiEndpoint = getApiEndpointCreator({
100
105
  errorsParser
101
106
  });
102
107
  const client = {
108
+ addRequestListener: (listener) => requestListeners.push(listener),
103
109
  addResponseListener: (listener) => responseListeners.push(listener),
104
110
  setHeader: (key, value) => {
105
111
  headers[key] = value;
@@ -131,7 +137,12 @@ export {
131
137
  ",
132
138
  "typings": "// noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
133
139
  import { DeepRequired } from "ts-essentials"
134
- import { Maybe, IResponseListener, Endpoint } from "."
140
+ import {
141
+ Maybe,
142
+ IRequestListener,
143
+ IResponseListener,
144
+ Endpoint,
145
+ } from "@avantstay/graphql-ts-client/dist"
135
146
 
136
147
  // Scalars
137
148
  export type IDate = string | Date
@@ -156,6 +167,7 @@ export interface Query {
156
167
  // Selection Types
157
168
 
158
169
  export declare const client: {
170
+ addRequestListener: (listener: IRequestListener) => void
159
171
  addResponseListener: (listener: IResponseListener) => void
160
172
  setHeader: (key: string, value: string) => void
161
173
  setHeaders: (newHeaders: { [k: string]: string }) => void
@@ -1,6 +1,11 @@
1
1
  // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
2
2
  import { DeepRequired } from "ts-essentials"
3
- import { Maybe, IResponseListener, Endpoint } from "."
3
+ import {
4
+ Maybe,
5
+ IRequestListener,
6
+ IResponseListener,
7
+ Endpoint,
8
+ } from "@avantstay/graphql-ts-client/dist"
4
9
 
5
10
  // Scalars
6
11
  export type IDate = string | Date
@@ -92,6 +97,7 @@ export interface BookSearchParamsSomeRequiredSelection {
92
97
  }
93
98
 
94
99
  export declare const myApiClient: {
100
+ addRequestListener: (listener: IRequestListener) => void
95
101
  addResponseListener: (listener: IResponseListener) => void
96
102
  setHeader: (key: string, value: string) => void
97
103
  setHeaders: (newHeaders: { [k: string]: string }) => void
@@ -26,7 +26,7 @@ __export(exports, {
26
26
  default: () => stdin_default,
27
27
  myApiClient: () => myApiClient
28
28
  });
29
- var import_endpoint = __toModule(require("./endpoint"));
29
+ var import_endpoint = __toModule(require("@avantstay/graphql-ts-client/dist/endpoint"));
30
30
  var import_standalone = __toModule(require("prettier/standalone"));
31
31
  var import_parser_graphql = __toModule(require("prettier/parser-graphql"));
32
32
  const formatGraphQL = (query) => (0, import_standalone.format)(query, { parser: "graphql", plugins: [import_parser_graphql.default] });
@@ -69,10 +69,12 @@ let retryConfig = {
69
69
  before: void 0,
70
70
  waitBeforeRetry: 0
71
71
  };
72
+ let requestListeners = [];
72
73
  let responseListeners = [];
73
74
  let errorsParser = void 0;
74
75
  let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
75
76
  getClient: () => ({ url, headers, retryConfig }),
77
+ requestListeners,
76
78
  responseListeners,
77
79
  maxAge: 3e4,
78
80
  verbose,
@@ -81,6 +83,7 @@ let apiEndpoint = (0, import_endpoint.getApiEndpointCreator)({
81
83
  errorsParser
82
84
  });
83
85
  const myApiClient = {
86
+ addRequestListener: (listener) => requestListeners.push(listener),
84
87
  addResponseListener: (listener) => responseListeners.push(listener),
85
88
  setHeader: (key, value) => {
86
89
  headers[key] = value;
@@ -1,4 +1,4 @@
1
- import { getApiEndpointCreator } from "./endpoint";
1
+ import { getApiEndpointCreator } from "@avantstay/graphql-ts-client/dist/endpoint";
2
2
  import { format as formatCode } from "prettier/standalone";
3
3
  import parserGraphql from "prettier/parser-graphql";
4
4
  const formatGraphQL = (query) => formatCode(query, { parser: "graphql", plugins: [parserGraphql] });
@@ -41,10 +41,12 @@ let retryConfig = {
41
41
  before: void 0,
42
42
  waitBeforeRetry: 0
43
43
  };
44
+ let requestListeners = [];
44
45
  let responseListeners = [];
45
46
  let errorsParser = void 0;
46
47
  let apiEndpoint = getApiEndpointCreator({
47
48
  getClient: () => ({ url, headers, retryConfig }),
49
+ requestListeners,
48
50
  responseListeners,
49
51
  maxAge: 3e4,
50
52
  verbose,
@@ -53,6 +55,7 @@ let apiEndpoint = getApiEndpointCreator({
53
55
  errorsParser
54
56
  });
55
57
  const myApiClient = {
58
+ addRequestListener: (listener) => requestListeners.push(listener),
56
59
  addResponseListener: (listener) => responseListeners.push(listener),
57
60
  setHeader: (key, value) => {
58
61
  headers[key] = value;
package/src/endpoint.ts CHANGED
@@ -2,7 +2,15 @@ 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 {
6
+ ClientConfig,
7
+ Endpoint,
8
+ GraphQLClientError,
9
+ IRequestListener,
10
+ IResponseListener,
11
+ Projection,
12
+ ResponseListenerInfo,
13
+ } from './types'
6
14
 
7
15
  const executeListeners = (listeners: IResponseListener[], data: ResponseListenerInfo) =>
8
16
  setTimeout(() => listeners.forEach(runResponseListener => runResponseListener(data)))
@@ -10,6 +18,7 @@ const executeListeners = (listeners: IResponseListener[], data: ResponseListener
10
18
  export const getApiEndpointCreator =
11
19
  (apiConfig: {
12
20
  getClient: () => ClientConfig
21
+ requestListeners: IRequestListener[]
13
22
  responseListeners: IResponseListener[]
14
23
  typesTree: any
15
24
  maxAge: number
@@ -28,10 +37,7 @@ export const getApiEndpointCreator =
28
37
  headers: any
29
38
  status: any
30
39
  }> => {
31
- const clientConfig = apiConfig.getClient()
32
-
33
40
  const alias = (jsonQuery as any)?.__alias ?? queryName
34
- const url = (jsonQuery as any)?.__url ?? clientConfig.url
35
41
  const shouldRetry = (jsonQuery as any)?.__retry ?? true
36
42
  const requestHeaders = (jsonQuery as any)?.__headers ?? {}
37
43
  const { query, variables } = jsonToGraphQLQuery({ kind, queryName, jsonQuery, typesTree: apiConfig.typesTree })
@@ -46,19 +52,25 @@ export const getApiEndpointCreator =
46
52
  variables,
47
53
  }
48
54
 
49
- const responseListenerData = {
55
+ const listenerData = {
50
56
  queryName: alias,
51
57
  query: apiConfig.formatGraphQL(query),
52
58
  variables,
59
+ headers: { ...requestHeaders },
53
60
  }
54
61
 
62
+ await Promise.all(apiConfig.requestListeners.map(listener => listener(listenerData)))
63
+
64
+ const clientConfig = apiConfig.getClient()
65
+ const url = (jsonQuery as any)?.__url ?? clientConfig.url
66
+
55
67
  try {
56
68
  const { data, errors, warnings, headers, status } = await graphqlRequest({
57
69
  shouldRetry,
58
70
  failureMode,
59
71
  queryName: alias,
60
72
  client: { ...clientConfig, url },
61
- requestHeaders,
73
+ requestHeaders: listenerData.headers,
62
74
  query,
63
75
  variables,
64
76
  errorsParser: apiConfig.errorsParser,
@@ -75,7 +87,7 @@ export const getApiEndpointCreator =
75
87
  }
76
88
 
77
89
  executeListeners(apiConfig.responseListeners, {
78
- ...responseListenerData,
90
+ ...listenerData,
79
91
  response,
80
92
  })
81
93
 
@@ -90,7 +102,7 @@ export const getApiEndpointCreator =
90
102
  }
91
103
 
92
104
  executeListeners(apiConfig.responseListeners, {
93
- ...responseListenerData,
105
+ ...listenerData,
94
106
  response: (error as GraphQLClientError).response,
95
107
  })
96
108
 
@@ -2,7 +2,7 @@ import { ApolloServer } from 'apollo-server'
2
2
  import * as path from 'path'
3
3
  import { generateTypescriptClient, generateTypescriptClientFromSDL } from './generateTypescriptClient'
4
4
  import { startServer } from './testServer'
5
- import { GraphQLClientError, ResponseListenerInfo } from './types'
5
+ import { RequestListenerInfo, ResponseListenerInfo } from './types'
6
6
 
7
7
  let testServer: { server: ApolloServer; url: string }
8
8
  let client: any
@@ -77,7 +77,7 @@ describe('Generated Client', () => {
77
77
  (err: any) => err
78
78
  )
79
79
 
80
- expect(result).toBeInstanceOf(GraphQLClientError)
80
+ expect(result.constructor.name).toContain('GraphQLClientError')
81
81
  expect(result.message).toBe('Failed lorem ipsum dolor')
82
82
  })
83
83
 
@@ -109,6 +109,53 @@ describe('Generated Client', () => {
109
109
  expect(failed).toBe(true)
110
110
  })
111
111
 
112
+ it('request listener is called before the request', async () => {
113
+ let requestData: RequestListenerInfo | undefined
114
+ client.addRequestListener((data: any) => (requestData = data))
115
+
116
+ await client.queries.booksWithoutParams({ title: true })
117
+
118
+ expect(requestData?.queryName).toBe('booksWithoutParams')
119
+ expect(requestData?.query).toBeDefined()
120
+ expect(requestData?.variables).toBeDefined()
121
+ })
122
+
123
+ it('header set in request listener is sent with the request', async () => {
124
+ const axios = require('axios')
125
+ const axiosSpy = jest.spyOn(axios, 'post')
126
+
127
+ client.addRequestListener(async () => {
128
+ const token = await Promise.resolve('my-fresh-token')
129
+ client.setHeader('Authorization', `Bearer ${token}`)
130
+ })
131
+
132
+ await client.queries.booksWithoutParams({ title: true })
133
+
134
+ expect(axiosSpy).toHaveBeenCalledWith(
135
+ expect.any(String),
136
+ expect.any(Object),
137
+ expect.objectContaining({
138
+ headers: expect.objectContaining({
139
+ Authorization: 'Bearer my-fresh-token',
140
+ }),
141
+ })
142
+ )
143
+
144
+ axiosSpy.mockRestore()
145
+ client.setHeader('Authorization', undefined)
146
+ })
147
+
148
+ it('request listener is called even for failing operations', async () => {
149
+ let requestData: RequestListenerInfo | undefined
150
+ client.addRequestListener((data: any) => (requestData = data))
151
+
152
+ try {
153
+ await client.queries.failingQuery({ __args: { id: 'hello' } })
154
+ } catch {}
155
+
156
+ expect(requestData?.queryName).toBe('failingQuery')
157
+ })
158
+
112
159
  it('failing operations throw errors', async () => {
113
160
  let responseData: ResponseListenerInfo | undefined
114
161
  client.addResponseListener((data: any) => (responseData = data))
@@ -376,11 +376,13 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
376
376
  before: undefined,
377
377
  waitBeforeRetry: 0
378
378
  }
379
+ let requestListeners = []
379
380
  let responseListeners = []
380
381
  let errorsParser = ${options.errorsParser}
381
382
  // noinspection JSUnusedLocalSymbols
382
383
  let apiEndpoint = getApiEndpointCreator({
383
384
  getClient: () => ({ url, headers, retryConfig }),
385
+ requestListeners,
384
386
  responseListeners,
385
387
  maxAge: 30000,
386
388
  verbose,
@@ -390,6 +392,7 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
390
392
  })
391
393
 
392
394
  export const ${clientName} = {
395
+ addRequestListener: (listener) => requestListeners.push(listener),
393
396
  addResponseListener: (listener) => responseListeners.push(
394
397
  listener),
395
398
  setHeader: (key, value) => {
@@ -424,7 +427,7 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
424
427
  const typingsCode = `
425
428
  // noinspection TypeScriptUnresolvedVariable, ES6UnusedImports, JSUnusedLocalSymbols, TypeScriptCheckImport
426
429
  import { DeepRequired } from 'ts-essentials'
427
- import { Maybe, IResponseListener, Endpoint } from '${graphqlTsClientPath}'
430
+ import { Maybe, IRequestListener, IResponseListener, Endpoint } from '${graphqlTsClientPath}'
428
431
 
429
432
  // Scalars
430
433
  export type IDate = string | Date
@@ -461,6 +464,7 @@ function generateClientCode(types: ReadonlyArray<IntrospectionType>, options: Om
461
464
  .join('\n')}
462
465
 
463
466
  export declare const ${clientName}: {
467
+ addRequestListener: (listener: IRequestListener) => void
464
468
  addResponseListener: (listener: IResponseListener) => void
465
469
  setHeader: (key: string, value: string) => void
466
470
  setHeaders: (newHeaders: { [k: string]: string }) => void,
package/src/types.ts CHANGED
@@ -11,6 +11,14 @@ export type ResponseData = {
11
11
  }[]
12
12
  }
13
13
 
14
+ export type RequestListenerInfo = {
15
+ queryName: string
16
+ query: string
17
+ variables: any
18
+ headers: { [key: string]: string }
19
+ }
20
+ export type IRequestListener = (info: RequestListenerInfo) => void | Promise<void>
21
+
14
22
  export type ResponseListenerInfo = {
15
23
  queryName: string
16
24
  query: string
@@ -1,27 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined")
5
- return require.apply(this, arguments);
6
- throw new Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
-
9
- // src/types.ts
10
- var GraphQLClientError = class extends Error {
11
- constructor(responseData) {
12
- super();
13
- this.responseData = responseData;
14
- Object.setPrototypeOf(this, GraphQLClientError.prototype);
15
- }
16
- get message() {
17
- return this.response.errors.map((it) => it.message).join(";\n");
18
- }
19
- get response() {
20
- return this.responseData;
21
- }
22
- };
23
-
24
- export {
25
- __require,
26
- GraphQLClientError
27
- };