graphql-http 1.1.0 → 1.2.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/README.md CHANGED
@@ -214,8 +214,10 @@ import { serve } from 'https://deno.land/std@0.151.0/http/server.ts';
214
214
  import { createHandler } from 'https://esm.sh/graphql-http';
215
215
  import { schema } from './previous-step';
216
216
 
217
+ // Create the GraphQL over HTTP handler
217
218
  const handler = createHandler<Request>({ schema });
218
219
 
220
+ // Start serving on `/graphql` using the handler
219
221
  await serve(
220
222
  async (req: Request) => {
221
223
  const [path, _search] = req.url.split('?');
package/lib/common.d.ts CHANGED
@@ -3,42 +3,6 @@
3
3
  * common
4
4
  *
5
5
  */
6
- /**
7
- * The incoming request headers the implementing server should provide.
8
- *
9
- * @category Common
10
- */
11
- export interface RequestHeaders {
12
- accept?: string | undefined;
13
- allow?: string | undefined;
14
- 'content-type'?: string | undefined;
15
- /**
16
- * Always an array in Node. Duplicates are added to it.
17
- * Not necessarily true for other environments, make sure
18
- * to check the type during runtime.
19
- */
20
- 'set-cookie'?: string | string[] | undefined;
21
- [key: string]: string | string[] | undefined;
22
- }
23
- /**
24
- * Server agnostic request interface containing the raw request
25
- * which is server dependant.
26
- *
27
- * @category Common
28
- */
29
- export interface Request<RawRequest> {
30
- readonly method: string;
31
- readonly url: string;
32
- readonly headers: RequestHeaders;
33
- readonly body: string | Record<string, unknown> | null;
34
- /**
35
- * The raw request itself from the implementing server.
36
- *
37
- * For example: `express.Request` when using Express, or maybe
38
- * `http.IncomingMessage` when just using Node with `http.createServer`.
39
- */
40
- readonly raw: RawRequest;
41
- }
42
6
  /**
43
7
  * Parameters for GraphQL's request for execution.
44
8
  *
@@ -52,47 +16,6 @@ export interface RequestParams {
52
16
  variables?: Record<string, unknown> | undefined;
53
17
  extensions?: Record<string, unknown> | undefined;
54
18
  }
55
- /**
56
- * The response headers that get returned from graphql-http.
57
- *
58
- * @category Common
59
- */
60
- export declare type ResponseHeaders = {
61
- accept?: string;
62
- allow?: string;
63
- 'content-type'?: string;
64
- } & Record<string, string>;
65
- /**
66
- * Server agnostic response body returned from `graphql-http` needing
67
- * to be coerced to the server implementation in use.
68
- *
69
- * @category Common
70
- */
71
- export declare type ResponseBody = string;
72
- /**
73
- * Server agnostic response options (ex. status and headers) returned from
74
- * `graphql-http` needing to be coerced to the server implementation in use.
75
- *
76
- * @category Common
77
- */
78
- export interface ResponseInit {
79
- readonly status: number;
80
- readonly statusText: string;
81
- readonly headers?: ResponseHeaders;
82
- }
83
- /**
84
- * Server agnostic response returned from `graphql-http` containing the
85
- * body and init options needing to be coerced to the server implementation in use.
86
- *
87
- * @category Common
88
- */
89
- export declare type Response = readonly [body: ResponseBody | null, init: ResponseInit];
90
- /**
91
- * Checks whether the passed value is the `graphql-http` server agnostic response.
92
- *
93
- * @category Common
94
- */
95
- export declare function isResponse(val: unknown): val is Response;
96
19
  /**
97
20
  * A representation of any set of values over any amount of time.
98
21
  *
package/lib/common.js CHANGED
@@ -5,17 +5,3 @@
5
5
  *
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.isResponse = void 0;
9
- const utils_1 = require("./utils");
10
- /**
11
- * Checks whether the passed value is the `graphql-http` server agnostic response.
12
- *
13
- * @category Common
14
- */
15
- function isResponse(val) {
16
- // TODO: make sure the contents of init match ResponseInit
17
- return (Array.isArray(val) &&
18
- (typeof val[0] === 'string' || val[0] === null) &&
19
- (0, utils_1.isObject)(val[1]));
20
- }
21
- exports.isResponse = isResponse;
package/lib/common.mjs CHANGED
@@ -3,15 +3,4 @@
3
3
  * common
4
4
  *
5
5
  */
6
- import { isObject } from './utils.mjs';
7
- /**
8
- * Checks whether the passed value is the `graphql-http` server agnostic response.
9
- *
10
- * @category Common
11
- */
12
- export function isResponse(val) {
13
- // TODO: make sure the contents of init match ResponseInit
14
- return (Array.isArray(val) &&
15
- (typeof val[0] === 'string' || val[0] === null) &&
16
- isObject(val[1]));
17
- }
6
+ export {};
package/lib/handler.d.ts CHANGED
@@ -4,7 +4,88 @@
4
4
  *
5
5
  */
6
6
  import { ExecutionArgs, ExecutionResult, GraphQLSchema, validate as graphqlValidate, execute as graphqlExecute, parse as graphqlParse, getOperationAST as graphqlGetOperationAST, GraphQLError } from 'graphql';
7
- import { Request, RequestParams, Response } from './common';
7
+ import { RequestParams } from './common';
8
+ /**
9
+ * The incoming request headers the implementing server should provide.
10
+ *
11
+ * @category Common
12
+ */
13
+ export interface RequestHeaders {
14
+ accept?: string | undefined;
15
+ allow?: string | undefined;
16
+ 'content-type'?: string | undefined;
17
+ /**
18
+ * Always an array in Node. Duplicates are added to it.
19
+ * Not necessarily true for other environments, make sure
20
+ * to check the type during runtime.
21
+ */
22
+ 'set-cookie'?: string | string[] | undefined;
23
+ [key: string]: string | string[] | undefined;
24
+ }
25
+ /**
26
+ * Server agnostic request interface containing the raw request
27
+ * which is server dependant.
28
+ *
29
+ * @category Common
30
+ */
31
+ export interface Request<RawRequest, Context> {
32
+ readonly method: string;
33
+ readonly url: string;
34
+ readonly headers: RequestHeaders;
35
+ readonly body: string | Record<string, unknown> | null;
36
+ /**
37
+ * The raw request itself from the implementing server.
38
+ *
39
+ * For example: `express.Request` when using Express, or maybe
40
+ * `http.IncomingMessage` when just using Node with `http.createServer`.
41
+ */
42
+ readonly raw: RawRequest;
43
+ /**
44
+ * Context value about the incoming request, you're free to pass any information here.
45
+ */
46
+ readonly context: Context;
47
+ }
48
+ /**
49
+ * The response headers that get returned from graphql-http.
50
+ *
51
+ * @category Common
52
+ */
53
+ export declare type ResponseHeaders = {
54
+ accept?: string;
55
+ allow?: string;
56
+ 'content-type'?: string;
57
+ } & Record<string, string>;
58
+ /**
59
+ * Server agnostic response body returned from `graphql-http` needing
60
+ * to be coerced to the server implementation in use.
61
+ *
62
+ * @category Common
63
+ */
64
+ export declare type ResponseBody = string;
65
+ /**
66
+ * Server agnostic response options (ex. status and headers) returned from
67
+ * `graphql-http` needing to be coerced to the server implementation in use.
68
+ *
69
+ * @category Common
70
+ */
71
+ export interface ResponseInit {
72
+ readonly status: number;
73
+ readonly statusText: string;
74
+ readonly headers?: ResponseHeaders;
75
+ }
76
+ /**
77
+ * Server agnostic response returned from `graphql-http` containing the
78
+ * body and init options needing to be coerced to the server implementation in use.
79
+ *
80
+ * @category Common
81
+ */
82
+ export declare type Response = readonly [body: ResponseBody | null, init: ResponseInit];
83
+ /**
84
+ * Checks whether the passed value is the `graphql-http` server agnostic response.
85
+ *
86
+ * @category Common
87
+ */
88
+ export declare function isResponse(val: unknown): val is Response;
8
89
  /**
9
90
  * A concrete GraphQL execution context value type.
10
91
  *
@@ -17,7 +98,7 @@ import { Request, RequestParams, Response } from './common';
17
98
  */
18
99
  export declare type ExecutionContext = object | symbol | number | string | boolean | undefined | null;
19
100
  /** @category Server */
20
- export interface HandlerOptions<RawRequest = unknown> {
101
+ export interface HandlerOptions<RawRequest = unknown, Context = unknown> {
21
102
  /**
22
103
  * The GraphQL schema on which the operations will
23
104
  * be executed and validated against.
@@ -34,16 +115,18 @@ export interface HandlerOptions<RawRequest = unknown> {
34
115
  * you should do by returning a `Request` argument which will stop
35
116
  * further execution.
36
117
  */
37
- schema?: GraphQLSchema | ((req: Request<RawRequest>, args: Omit<ExecutionArgs, 'schema'>) => Promise<GraphQLSchema | Response> | GraphQLSchema | Response);
118
+ schema?: GraphQLSchema | ((req: Request<RawRequest, Context>, args: Omit<ExecutionArgs, 'schema'>) => Promise<GraphQLSchema | Response> | GraphQLSchema | Response);
38
119
  /**
39
120
  * A value which is provided to every resolver and holds
40
121
  * important contextual information like the currently
41
122
  * logged in user, or access to a database.
42
123
  */
43
- context?: ExecutionContext | ((req: Request<RawRequest>, args: ExecutionArgs) => Promise<ExecutionContext | Response> | ExecutionContext | Response);
124
+ context?: ExecutionContext | ((req: Request<RawRequest, Context>, args: ExecutionArgs) => Promise<ExecutionContext | Response> | ExecutionContext | Response);
44
125
  /**
45
126
  * A custom GraphQL validate function allowing you to apply your
46
127
  * own validation rules.
128
+ *
129
+ * Will not be used when implementing a custom `onSubscribe`.
47
130
  */
48
131
  validate?: typeof graphqlValidate;
49
132
  /**
@@ -63,10 +146,16 @@ export interface HandlerOptions<RawRequest = unknown> {
63
146
  * The subscribe callback executed right after processing the request
64
147
  * before proceeding with the GraphQL operation execution.
65
148
  *
149
+ * If you return `ExecutionResult` from the callback, it will be used
150
+ * directly for responding to the request. Useful for implementing a response
151
+ * cache.
152
+ *
66
153
  * If you return `ExecutionArgs` from the callback, it will be used instead of
67
154
  * trying to build one internally. In this case, you are responsible for providing
68
155
  * a ready set of arguments which will be directly plugged in the operation execution.
69
156
  *
157
+ * You *must* validate the `ExecutionArgs` yourself if returning them.
158
+ *
70
159
  * If you return an array of `GraphQLError` from the callback, they will be reported
71
160
  * to the client while complying with the spec.
72
161
  *
@@ -81,7 +170,7 @@ export interface HandlerOptions<RawRequest = unknown> {
81
170
  * you should do by returning a `Request` argument which will stop
82
171
  * further execution.
83
172
  */
84
- onSubscribe?: (req: Request<RawRequest>, params: RequestParams) => Promise<ExecutionArgs | GraphQLError[] | Response | void> | ExecutionArgs | GraphQLError[] | Response | void;
173
+ onSubscribe?: (req: Request<RawRequest, Context>, params: RequestParams) => Promise<ExecutionResult | ExecutionArgs | readonly GraphQLError[] | Response | void> | ExecutionResult | ExecutionArgs | readonly GraphQLError[] | Response | void;
85
174
  /**
86
175
  * Executed after the operation call resolves.
87
176
  *
@@ -95,7 +184,7 @@ export interface HandlerOptions<RawRequest = unknown> {
95
184
  * you should do by returning a `Request` argument which will stop
96
185
  * further execution.
97
186
  */
98
- onOperation?: (req: Request<RawRequest>, args: ExecutionArgs, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void;
187
+ onOperation?: (req: Request<RawRequest, Context>, args: ExecutionArgs, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void;
99
188
  }
100
189
  /**
101
190
  * The ready-to-use handler. Simply plug it in your favourite HTTP framework
@@ -107,7 +196,7 @@ export interface HandlerOptions<RawRequest = unknown> {
107
196
  *
108
197
  * @category Server
109
198
  */
110
- export declare type Handler<RawRequest = unknown> = (req: Request<RawRequest>) => Promise<Response>;
199
+ export declare type Handler<RawRequest = unknown, Context = unknown> = (req: Request<RawRequest, Context>) => Promise<Response>;
111
200
  /**
112
201
  * Makes a GraphQL over HTTP Protocol compliant server handler. The handler can
113
202
  * be used with your favourite server library.
@@ -163,4 +252,28 @@ export declare type Handler<RawRequest = unknown> = (req: Request<RawRequest>) =
163
252
  *
164
253
  * @category Server
165
254
  */
166
- export declare function createHandler<RawRequest = unknown>(options: HandlerOptions<RawRequest>): Handler<RawRequest>;
255
+ export declare function createHandler<RawRequest = unknown, Context = unknown>(options: HandlerOptions<RawRequest, Context>): Handler<RawRequest, Context>;
256
+ /**
257
+ * Request's Media-Type that the server accepts.
258
+ *
259
+ * @category Server
260
+ */
261
+ export declare type AcceptableMediaType = 'application/graphql+json' | 'application/json';
262
+ /**
263
+ * Inspects the request and detects the appropriate/acceptable Media-Type
264
+ * looking at the `Accept` header while complying with the GraphQL over HTTP Protocol.
265
+ *
266
+ * @category Server
267
+ */
268
+ export declare function getAcceptableMediaType(acceptHeader: string | null | undefined): AcceptableMediaType | null;
269
+ /**
270
+ * Creates an appropriate GraphQL over HTTP response following the provided arguments.
271
+ *
272
+ * If the first argument is an `ExecutionResult`, the operation will be treated as "successful".
273
+ *
274
+ * If the first argument is _any_ object without the `data` field, it will be treated as an error (as per the spec)
275
+ * and the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP Protocol.
276
+ *
277
+ * @category Server
278
+ */
279
+ export declare function makeResponse(resultOrErrors: Readonly<ExecutionResult> | Readonly<GraphQLError[]> | Readonly<GraphQLError>, acceptedMediaType: AcceptableMediaType): Response;
package/lib/handler.js CHANGED
@@ -5,10 +5,21 @@
5
5
  *
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.createHandler = void 0;
8
+ exports.makeResponse = exports.getAcceptableMediaType = exports.createHandler = exports.isResponse = void 0;
9
9
  const graphql_1 = require("graphql");
10
- const common_1 = require("./common");
11
10
  const utils_1 = require("./utils");
11
+ /**
12
+ * Checks whether the passed value is the `graphql-http` server agnostic response.
13
+ *
14
+ * @category Common
15
+ */
16
+ function isResponse(val) {
17
+ // TODO: make sure the contents of init match ResponseInit
18
+ return (Array.isArray(val) &&
19
+ (typeof val[0] === 'string' || val[0] === null) &&
20
+ (0, utils_1.isObject)(val[1]));
21
+ }
22
+ exports.isResponse = isResponse;
12
23
  /**
13
24
  * Makes a GraphQL over HTTP Protocol compliant server handler. The handler can
14
25
  * be used with your favourite server library.
@@ -81,28 +92,7 @@ function createHandler(options) {
81
92
  },
82
93
  ];
83
94
  }
84
- let acceptedMediaType;
85
- const accepts = (req.headers.accept || '*/*')
86
- .replace(/\s/g, '')
87
- .toLowerCase()
88
- .split(',');
89
- for (const accept of accepts) {
90
- // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
91
- // TODO: handle the weight parameter "q"
92
- const [mediaType, ...params] = accept.split(';');
93
- const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
94
- if (mediaType === 'application/json' && charset === 'charset=utf8') {
95
- acceptedMediaType = 'application/json';
96
- break;
97
- }
98
- if ((mediaType === 'application/graphql+json' ||
99
- mediaType === 'application/*' ||
100
- mediaType === '*/*') &&
101
- charset === 'charset=utf8') {
102
- acceptedMediaType = 'application/graphql+json';
103
- break;
104
- }
105
- }
95
+ const acceptedMediaType = getAcceptableMediaType(req.headers.accept);
106
96
  if (!acceptedMediaType) {
107
97
  return [
108
98
  null,
@@ -173,8 +163,10 @@ function createHandler(options) {
173
163
  },
174
164
  ];
175
165
  }
176
- if (!partParams.query)
166
+ if (partParams.query == null)
177
167
  throw new Error('Missing query');
168
+ if (typeof partParams.query !== 'string')
169
+ throw new Error('Invalid query');
178
170
  if (partParams.variables != null &&
179
171
  (typeof partParams.variables !== 'object' ||
180
172
  Array.isArray(partParams.variables))) {
@@ -189,40 +181,15 @@ function createHandler(options) {
189
181
  params = partParams;
190
182
  }
191
183
  catch (err) {
192
- return [
193
- err.message,
194
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
195
- ? {
196
- status: 200,
197
- statusText: 'OK',
198
- }
199
- : {
200
- status: 400,
201
- statusText: 'Bad Request',
202
- })), { statusText: 'Bad Request' }),
203
- ];
184
+ return makeResponse(new graphql_1.GraphQLError(err.message), acceptedMediaType);
204
185
  }
205
186
  let args;
206
187
  const maybeResErrsOrArgs = await (onSubscribe === null || onSubscribe === void 0 ? void 0 : onSubscribe(req, params));
207
- if ((0, common_1.isResponse)(maybeResErrsOrArgs))
188
+ if (isResponse(maybeResErrsOrArgs))
208
189
  return maybeResErrsOrArgs;
209
- else if ((0, utils_1.areGraphQLErrors)(maybeResErrsOrArgs))
210
- return [
211
- JSON.stringify({ errors: maybeResErrsOrArgs }),
212
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
213
- ? {
214
- status: 200,
215
- statusText: 'OK',
216
- }
217
- : {
218
- status: 400,
219
- statusText: 'Bad Request',
220
- })), { headers: {
221
- 'content-type': acceptedMediaType === 'application/json'
222
- ? 'application/json; charset=utf-8'
223
- : 'application/graphql+json; charset=utf-8',
224
- } }),
225
- ];
190
+ else if ((0, utils_1.isExecutionResult)(maybeResErrsOrArgs) ||
191
+ (0, utils_1.areGraphQLErrors)(maybeResErrsOrArgs))
192
+ return makeResponse(maybeResErrsOrArgs, acceptedMediaType);
226
193
  else if (maybeResErrsOrArgs)
227
194
  args = maybeResErrsOrArgs;
228
195
  else {
@@ -234,22 +201,7 @@ function createHandler(options) {
234
201
  document = parse(query);
235
202
  }
236
203
  catch (err) {
237
- return [
238
- JSON.stringify({ errors: [err] }),
239
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
240
- ? {
241
- status: 200,
242
- statusText: 'OK',
243
- }
244
- : {
245
- status: 400,
246
- statusText: 'Bad Request',
247
- })), { statusText: 'Bad Request', headers: {
248
- 'content-type': acceptedMediaType === 'application/json'
249
- ? 'application/json; charset=utf-8'
250
- : 'application/graphql+json; charset=utf-8',
251
- } }),
252
- ];
204
+ return makeResponse(err, acceptedMediaType);
253
205
  }
254
206
  const argsWithoutSchema = {
255
207
  operationName,
@@ -258,13 +210,17 @@ function createHandler(options) {
258
210
  };
259
211
  if (typeof schema === 'function') {
260
212
  const resOrSchema = await schema(req, argsWithoutSchema);
261
- if ((0, common_1.isResponse)(resOrSchema))
213
+ if (isResponse(resOrSchema))
262
214
  return resOrSchema;
263
215
  args = Object.assign(Object.assign({}, argsWithoutSchema), { schema: resOrSchema });
264
216
  }
265
217
  else {
266
218
  args = Object.assign(Object.assign({}, argsWithoutSchema), { schema });
267
219
  }
220
+ const validationErrs = validate(args.schema, args.document);
221
+ if (validationErrs.length) {
222
+ return makeResponse(validationErrs, acceptedMediaType);
223
+ }
268
224
  }
269
225
  let operation;
270
226
  try {
@@ -274,33 +230,18 @@ function createHandler(options) {
274
230
  operation = ast.operation;
275
231
  }
276
232
  catch (_e) {
277
- return [
278
- 'Unable to detect operation AST',
279
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
280
- ? {
281
- status: 200,
282
- statusText: 'OK',
283
- }
284
- : {
285
- status: 400,
286
- statusText: 'Bad Request',
287
- })), { statusText: 'Bad Request' }),
288
- ];
233
+ return makeResponse(new graphql_1.GraphQLError('Unable to detect operation AST'), acceptedMediaType);
289
234
  }
290
235
  if (operation === 'subscription') {
291
- return [
292
- 'Subscriptions are not supported',
293
- {
294
- status: 400,
295
- statusText: 'Bad Request',
296
- },
297
- ];
236
+ return makeResponse(new graphql_1.GraphQLError('Subscriptions are not supported'), acceptedMediaType);
298
237
  }
299
238
  // mutations cannot happen over GETs
300
239
  // https://graphql.github.io/graphql-over-http/draft/#sel-CALFJRPAAELBAAxwP
301
240
  if (operation === 'mutation' && method === 'GET') {
302
241
  return [
303
- 'Cannot perform mutations over GET',
242
+ JSON.stringify({
243
+ errors: [new graphql_1.GraphQLError('Cannot perform mutations over GET')],
244
+ }),
304
245
  {
305
246
  status: 405,
306
247
  statusText: 'Method Not Allowed',
@@ -312,37 +253,69 @@ function createHandler(options) {
312
253
  }
313
254
  if (!('contextValue' in args)) {
314
255
  const maybeResOrContext = typeof context === 'function' ? await context(req, args) : context;
315
- if ((0, common_1.isResponse)(maybeResOrContext))
256
+ if (isResponse(maybeResOrContext))
316
257
  return maybeResOrContext;
317
258
  args.contextValue = maybeResOrContext;
318
259
  }
319
- const validationErrs = validate(args.schema, args.document);
320
- if (validationErrs.length) {
321
- return [
322
- JSON.stringify({ errors: validationErrs }),
323
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
324
- ? {
325
- status: 200,
326
- statusText: 'OK',
327
- }
328
- : {
329
- status: 400,
330
- statusText: 'Bad Request',
331
- })), { headers: {
332
- 'content-type': acceptedMediaType === 'application/json'
333
- ? 'application/json; charset=utf-8'
334
- : 'application/graphql+json; charset=utf-8',
335
- } }),
336
- ];
337
- }
338
260
  let result = await execute(args);
339
- const maybeResOrResult = await (onOperation === null || onOperation === void 0 ? void 0 : onOperation(req, args, result));
340
- if ((0, common_1.isResponse)(maybeResOrResult))
341
- return maybeResOrResult;
342
- else if (maybeResOrResult)
343
- result = maybeResOrResult;
261
+ const maybeResponseOrResult = await (onOperation === null || onOperation === void 0 ? void 0 : onOperation(req, args, result));
262
+ if (isResponse(maybeResponseOrResult))
263
+ return maybeResponseOrResult;
264
+ else if (maybeResponseOrResult)
265
+ result = maybeResponseOrResult;
266
+ if ((0, utils_1.isAsyncIterable)(result)) {
267
+ return makeResponse(new graphql_1.GraphQLError('Subscriptions are not supported'), acceptedMediaType);
268
+ }
269
+ return makeResponse(result, acceptedMediaType);
270
+ };
271
+ }
272
+ exports.createHandler = createHandler;
273
+ /**
274
+ * Inspects the request and detects the appropriate/acceptable Media-Type
275
+ * looking at the `Accept` header while complying with the GraphQL over HTTP Protocol.
276
+ *
277
+ * @category Server
278
+ */
279
+ function getAcceptableMediaType(acceptHeader) {
280
+ let acceptedMediaType = null;
281
+ const accepts = (acceptHeader || '*/*')
282
+ .replace(/\s/g, '')
283
+ .toLowerCase()
284
+ .split(',');
285
+ for (const accept of accepts) {
286
+ // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
287
+ // TODO: handle the weight parameter "q"
288
+ const [mediaType, ...params] = accept.split(';');
289
+ const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
290
+ if (mediaType === 'application/json' && charset === 'charset=utf8') {
291
+ acceptedMediaType = 'application/json';
292
+ break;
293
+ }
294
+ if ((mediaType === 'application/graphql+json' ||
295
+ mediaType === 'application/*' ||
296
+ mediaType === '*/*') &&
297
+ charset === 'charset=utf8') {
298
+ acceptedMediaType = 'application/graphql+json';
299
+ break;
300
+ }
301
+ }
302
+ return acceptedMediaType;
303
+ }
304
+ exports.getAcceptableMediaType = getAcceptableMediaType;
305
+ /**
306
+ * Creates an appropriate GraphQL over HTTP response following the provided arguments.
307
+ *
308
+ * If the first argument is an `ExecutionResult`, the operation will be treated as "successful".
309
+ *
310
+ * If the first argument is _any_ object without the `data` field, it will be treated as an error (as per the spec)
311
+ * and the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP Protocol.
312
+ *
313
+ * @category Server
314
+ */
315
+ function makeResponse(resultOrErrors, acceptedMediaType) {
316
+ if ((0, utils_1.isExecutionResult)(resultOrErrors)) {
344
317
  return [
345
- JSON.stringify(result),
318
+ JSON.stringify(resultOrErrors),
346
319
  {
347
320
  status: 200,
348
321
  statusText: 'OK',
@@ -353,6 +326,28 @@ function createHandler(options) {
353
326
  },
354
327
  },
355
328
  ];
356
- };
329
+ }
330
+ return [
331
+ JSON.stringify({
332
+ errors: Array.isArray(resultOrErrors)
333
+ ? (0, utils_1.isObject)(resultOrErrors)
334
+ ? resultOrErrors
335
+ : new graphql_1.GraphQLError(String(resultOrErrors))
336
+ : [resultOrErrors],
337
+ }),
338
+ Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
339
+ ? {
340
+ status: 200,
341
+ statusText: 'OK',
342
+ }
343
+ : {
344
+ status: 400,
345
+ statusText: 'Bad Request',
346
+ })), { headers: {
347
+ 'content-type': acceptedMediaType === 'application/json'
348
+ ? 'application/json; charset=utf-8'
349
+ : 'application/graphql+json; charset=utf-8',
350
+ } }),
351
+ ];
357
352
  }
358
- exports.createHandler = createHandler;
353
+ exports.makeResponse = makeResponse;
package/lib/handler.mjs CHANGED
@@ -3,9 +3,19 @@
3
3
  * handler
4
4
  *
5
5
  */
6
- import { validate as graphqlValidate, execute as graphqlExecute, parse as graphqlParse, getOperationAST as graphqlGetOperationAST, } from 'graphql';
7
- import { isResponse } from './common.mjs';
8
- import { areGraphQLErrors } from './utils.mjs';
6
+ import { validate as graphqlValidate, execute as graphqlExecute, parse as graphqlParse, getOperationAST as graphqlGetOperationAST, GraphQLError, } from 'graphql';
7
+ import { areGraphQLErrors, isAsyncIterable, isExecutionResult, isObject, } from './utils.mjs';
8
+ /**
9
+ * Checks whether the passed value is the `graphql-http` server agnostic response.
10
+ *
11
+ * @category Common
12
+ */
13
+ export function isResponse(val) {
14
+ // TODO: make sure the contents of init match ResponseInit
15
+ return (Array.isArray(val) &&
16
+ (typeof val[0] === 'string' || val[0] === null) &&
17
+ isObject(val[1]));
18
+ }
9
19
  /**
10
20
  * Makes a GraphQL over HTTP Protocol compliant server handler. The handler can
11
21
  * be used with your favourite server library.
@@ -78,28 +88,7 @@ export function createHandler(options) {
78
88
  },
79
89
  ];
80
90
  }
81
- let acceptedMediaType;
82
- const accepts = (req.headers.accept || '*/*')
83
- .replace(/\s/g, '')
84
- .toLowerCase()
85
- .split(',');
86
- for (const accept of accepts) {
87
- // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
88
- // TODO: handle the weight parameter "q"
89
- const [mediaType, ...params] = accept.split(';');
90
- const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
91
- if (mediaType === 'application/json' && charset === 'charset=utf8') {
92
- acceptedMediaType = 'application/json';
93
- break;
94
- }
95
- if ((mediaType === 'application/graphql+json' ||
96
- mediaType === 'application/*' ||
97
- mediaType === '*/*') &&
98
- charset === 'charset=utf8') {
99
- acceptedMediaType = 'application/graphql+json';
100
- break;
101
- }
102
- }
91
+ const acceptedMediaType = getAcceptableMediaType(req.headers.accept);
103
92
  if (!acceptedMediaType) {
104
93
  return [
105
94
  null,
@@ -170,8 +159,10 @@ export function createHandler(options) {
170
159
  },
171
160
  ];
172
161
  }
173
- if (!partParams.query)
162
+ if (partParams.query == null)
174
163
  throw new Error('Missing query');
164
+ if (typeof partParams.query !== 'string')
165
+ throw new Error('Invalid query');
175
166
  if (partParams.variables != null &&
176
167
  (typeof partParams.variables !== 'object' ||
177
168
  Array.isArray(partParams.variables))) {
@@ -186,40 +177,15 @@ export function createHandler(options) {
186
177
  params = partParams;
187
178
  }
188
179
  catch (err) {
189
- return [
190
- err.message,
191
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
192
- ? {
193
- status: 200,
194
- statusText: 'OK',
195
- }
196
- : {
197
- status: 400,
198
- statusText: 'Bad Request',
199
- })), { statusText: 'Bad Request' }),
200
- ];
180
+ return makeResponse(new GraphQLError(err.message), acceptedMediaType);
201
181
  }
202
182
  let args;
203
183
  const maybeResErrsOrArgs = await (onSubscribe === null || onSubscribe === void 0 ? void 0 : onSubscribe(req, params));
204
184
  if (isResponse(maybeResErrsOrArgs))
205
185
  return maybeResErrsOrArgs;
206
- else if (areGraphQLErrors(maybeResErrsOrArgs))
207
- return [
208
- JSON.stringify({ errors: maybeResErrsOrArgs }),
209
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
210
- ? {
211
- status: 200,
212
- statusText: 'OK',
213
- }
214
- : {
215
- status: 400,
216
- statusText: 'Bad Request',
217
- })), { headers: {
218
- 'content-type': acceptedMediaType === 'application/json'
219
- ? 'application/json; charset=utf-8'
220
- : 'application/graphql+json; charset=utf-8',
221
- } }),
222
- ];
186
+ else if (isExecutionResult(maybeResErrsOrArgs) ||
187
+ areGraphQLErrors(maybeResErrsOrArgs))
188
+ return makeResponse(maybeResErrsOrArgs, acceptedMediaType);
223
189
  else if (maybeResErrsOrArgs)
224
190
  args = maybeResErrsOrArgs;
225
191
  else {
@@ -231,22 +197,7 @@ export function createHandler(options) {
231
197
  document = parse(query);
232
198
  }
233
199
  catch (err) {
234
- return [
235
- JSON.stringify({ errors: [err] }),
236
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
237
- ? {
238
- status: 200,
239
- statusText: 'OK',
240
- }
241
- : {
242
- status: 400,
243
- statusText: 'Bad Request',
244
- })), { statusText: 'Bad Request', headers: {
245
- 'content-type': acceptedMediaType === 'application/json'
246
- ? 'application/json; charset=utf-8'
247
- : 'application/graphql+json; charset=utf-8',
248
- } }),
249
- ];
200
+ return makeResponse(err, acceptedMediaType);
250
201
  }
251
202
  const argsWithoutSchema = {
252
203
  operationName,
@@ -262,6 +213,10 @@ export function createHandler(options) {
262
213
  else {
263
214
  args = Object.assign(Object.assign({}, argsWithoutSchema), { schema });
264
215
  }
216
+ const validationErrs = validate(args.schema, args.document);
217
+ if (validationErrs.length) {
218
+ return makeResponse(validationErrs, acceptedMediaType);
219
+ }
265
220
  }
266
221
  let operation;
267
222
  try {
@@ -271,33 +226,18 @@ export function createHandler(options) {
271
226
  operation = ast.operation;
272
227
  }
273
228
  catch (_e) {
274
- return [
275
- 'Unable to detect operation AST',
276
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
277
- ? {
278
- status: 200,
279
- statusText: 'OK',
280
- }
281
- : {
282
- status: 400,
283
- statusText: 'Bad Request',
284
- })), { statusText: 'Bad Request' }),
285
- ];
229
+ return makeResponse(new GraphQLError('Unable to detect operation AST'), acceptedMediaType);
286
230
  }
287
231
  if (operation === 'subscription') {
288
- return [
289
- 'Subscriptions are not supported',
290
- {
291
- status: 400,
292
- statusText: 'Bad Request',
293
- },
294
- ];
232
+ return makeResponse(new GraphQLError('Subscriptions are not supported'), acceptedMediaType);
295
233
  }
296
234
  // mutations cannot happen over GETs
297
235
  // https://graphql.github.io/graphql-over-http/draft/#sel-CALFJRPAAELBAAxwP
298
236
  if (operation === 'mutation' && method === 'GET') {
299
237
  return [
300
- 'Cannot perform mutations over GET',
238
+ JSON.stringify({
239
+ errors: [new GraphQLError('Cannot perform mutations over GET')],
240
+ }),
301
241
  {
302
242
  status: 405,
303
243
  statusText: 'Method Not Allowed',
@@ -313,33 +253,63 @@ export function createHandler(options) {
313
253
  return maybeResOrContext;
314
254
  args.contextValue = maybeResOrContext;
315
255
  }
316
- const validationErrs = validate(args.schema, args.document);
317
- if (validationErrs.length) {
318
- return [
319
- JSON.stringify({ errors: validationErrs }),
320
- Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
321
- ? {
322
- status: 200,
323
- statusText: 'OK',
324
- }
325
- : {
326
- status: 400,
327
- statusText: 'Bad Request',
328
- })), { headers: {
329
- 'content-type': acceptedMediaType === 'application/json'
330
- ? 'application/json; charset=utf-8'
331
- : 'application/graphql+json; charset=utf-8',
332
- } }),
333
- ];
334
- }
335
256
  let result = await execute(args);
336
- const maybeResOrResult = await (onOperation === null || onOperation === void 0 ? void 0 : onOperation(req, args, result));
337
- if (isResponse(maybeResOrResult))
338
- return maybeResOrResult;
339
- else if (maybeResOrResult)
340
- result = maybeResOrResult;
257
+ const maybeResponseOrResult = await (onOperation === null || onOperation === void 0 ? void 0 : onOperation(req, args, result));
258
+ if (isResponse(maybeResponseOrResult))
259
+ return maybeResponseOrResult;
260
+ else if (maybeResponseOrResult)
261
+ result = maybeResponseOrResult;
262
+ if (isAsyncIterable(result)) {
263
+ return makeResponse(new GraphQLError('Subscriptions are not supported'), acceptedMediaType);
264
+ }
265
+ return makeResponse(result, acceptedMediaType);
266
+ };
267
+ }
268
+ /**
269
+ * Inspects the request and detects the appropriate/acceptable Media-Type
270
+ * looking at the `Accept` header while complying with the GraphQL over HTTP Protocol.
271
+ *
272
+ * @category Server
273
+ */
274
+ export function getAcceptableMediaType(acceptHeader) {
275
+ let acceptedMediaType = null;
276
+ const accepts = (acceptHeader || '*/*')
277
+ .replace(/\s/g, '')
278
+ .toLowerCase()
279
+ .split(',');
280
+ for (const accept of accepts) {
281
+ // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
282
+ // TODO: handle the weight parameter "q"
283
+ const [mediaType, ...params] = accept.split(';');
284
+ const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
285
+ if (mediaType === 'application/json' && charset === 'charset=utf8') {
286
+ acceptedMediaType = 'application/json';
287
+ break;
288
+ }
289
+ if ((mediaType === 'application/graphql+json' ||
290
+ mediaType === 'application/*' ||
291
+ mediaType === '*/*') &&
292
+ charset === 'charset=utf8') {
293
+ acceptedMediaType = 'application/graphql+json';
294
+ break;
295
+ }
296
+ }
297
+ return acceptedMediaType;
298
+ }
299
+ /**
300
+ * Creates an appropriate GraphQL over HTTP response following the provided arguments.
301
+ *
302
+ * If the first argument is an `ExecutionResult`, the operation will be treated as "successful".
303
+ *
304
+ * If the first argument is _any_ object without the `data` field, it will be treated as an error (as per the spec)
305
+ * and the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP Protocol.
306
+ *
307
+ * @category Server
308
+ */
309
+ export function makeResponse(resultOrErrors, acceptedMediaType) {
310
+ if (isExecutionResult(resultOrErrors)) {
341
311
  return [
342
- JSON.stringify(result),
312
+ JSON.stringify(resultOrErrors),
343
313
  {
344
314
  status: 200,
345
315
  statusText: 'OK',
@@ -350,5 +320,27 @@ export function createHandler(options) {
350
320
  },
351
321
  },
352
322
  ];
353
- };
323
+ }
324
+ return [
325
+ JSON.stringify({
326
+ errors: Array.isArray(resultOrErrors)
327
+ ? isObject(resultOrErrors)
328
+ ? resultOrErrors
329
+ : new GraphQLError(String(resultOrErrors))
330
+ : [resultOrErrors],
331
+ }),
332
+ Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
333
+ ? {
334
+ status: 200,
335
+ statusText: 'OK',
336
+ }
337
+ : {
338
+ status: 400,
339
+ statusText: 'Bad Request',
340
+ })), { headers: {
341
+ 'content-type': acceptedMediaType === 'application/json'
342
+ ? 'application/json; charset=utf-8'
343
+ : 'application/graphql+json; charset=utf-8',
344
+ } }),
345
+ ];
354
346
  }
package/lib/utils.d.ts CHANGED
@@ -3,8 +3,12 @@
3
3
  * utils
4
4
  *
5
5
  */
6
- import type { GraphQLError } from 'graphql';
6
+ import type { ExecutionResult, GraphQLError } from 'graphql';
7
7
  /** @private */
8
8
  export declare function isObject(val: unknown): val is Record<PropertyKey, unknown>;
9
9
  /** @private */
10
- export declare function areGraphQLErrors(obj: unknown): obj is GraphQLError[];
10
+ export declare function areGraphQLErrors(obj: unknown): obj is readonly GraphQLError[];
11
+ /** @private */
12
+ export declare function isExecutionResult(val: unknown): val is ExecutionResult;
13
+ /** @private */
14
+ export declare function isAsyncIterable<T = unknown>(val: unknown): val is AsyncIterable<T>;
package/lib/utils.js CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.areGraphQLErrors = exports.isObject = void 0;
8
+ exports.isAsyncIterable = exports.isExecutionResult = exports.areGraphQLErrors = exports.isObject = void 0;
9
9
  /** @private */
10
10
  function isObject(val) {
11
11
  return typeof val === 'object' && val !== null;
@@ -20,3 +20,14 @@ function areGraphQLErrors(obj) {
20
20
  obj.every((ob) => 'message' in ob));
21
21
  }
22
22
  exports.areGraphQLErrors = areGraphQLErrors;
23
+ /** @private */
24
+ function isExecutionResult(val) {
25
+ return (isObject(val) &&
26
+ ('data' in val || ('data' in val && val.data == null && 'errors' in val)));
27
+ }
28
+ exports.isExecutionResult = isExecutionResult;
29
+ /** @private */
30
+ function isAsyncIterable(val) {
31
+ return typeof Object(val)[Symbol.asyncIterator] === 'function';
32
+ }
33
+ exports.isAsyncIterable = isAsyncIterable;
package/lib/utils.mjs CHANGED
@@ -15,3 +15,12 @@ export function areGraphQLErrors(obj) {
15
15
  // error has at least a message
16
16
  obj.every((ob) => 'message' in ob));
17
17
  }
18
+ /** @private */
19
+ export function isExecutionResult(val) {
20
+ return (isObject(val) &&
21
+ ('data' in val || ('data' in val && val.data == null && 'errors' in val)));
22
+ }
23
+ /** @private */
24
+ export function isAsyncIterable(val) {
25
+ return typeof Object(val)[Symbol.asyncIterator] === 'function';
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-http",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Simple, pluggable, zero-dependency, GraphQL over HTTP Protocol compliant server and client",
5
5
  "keywords": [
6
6
  "graphql",
@@ -76,8 +76,8 @@
76
76
  "@semantic-release/changelog": "^6.0.1",
77
77
  "@semantic-release/git": "^10.0.1",
78
78
  "@types/jest": "^28.1.6",
79
- "@typescript-eslint/eslint-plugin": "^5.32.0",
80
- "@typescript-eslint/parser": "^5.32.0",
79
+ "@typescript-eslint/eslint-plugin": "^5.33.0",
80
+ "@typescript-eslint/parser": "^5.33.0",
81
81
  "babel-jest": "^28.1.3",
82
82
  "eslint": "^8.21.0",
83
83
  "eslint-config-prettier": "^8.5.0",
@@ -88,7 +88,7 @@
88
88
  "node-fetch": "^3.2.10",
89
89
  "prettier": "^2.7.1",
90
90
  "replacestream": "^4.0.3",
91
- "rollup": "^2.77.2",
91
+ "rollup": "^2.77.3",
92
92
  "rollup-plugin-terser": "^7.0.2",
93
93
  "semantic-release": "^19.0.3",
94
94
  "tslib": "^2.4.0",
@@ -14,23 +14,6 @@
14
14
  return typeof val === 'object' && val !== null;
15
15
  }
16
16
 
17
- /**
18
- *
19
- * common
20
- *
21
- */
22
- /**
23
- * Checks whether the passed value is the `graphql-http` server agnostic response.
24
- *
25
- * @category Common
26
- */
27
- function isResponse(val) {
28
- // TODO: make sure the contents of init match ResponseInit
29
- return (Array.isArray(val) &&
30
- (typeof val[0] === 'string' || val[0] === null) &&
31
- isObject(val[1]));
32
- }
33
-
34
17
  /**
35
18
  *
36
19
  * client
@@ -201,7 +184,6 @@
201
184
 
202
185
  exports.NetworkError = NetworkError;
203
186
  exports.createClient = createClient;
204
- exports.isResponse = isResponse;
205
187
 
206
188
  Object.defineProperty(exports, '__esModule', { value: true });
207
189
 
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlHttp={})}(this,(function(e){"use strict";function t(e){return"object"==typeof e&&null!==e}class r extends Error{constructor(e){let r,o;var n;t(n=e)&&"boolean"==typeof n.ok&&"number"==typeof n.status&&"string"==typeof n.statusText?(o=e,r="Server responded with "+e.status+": "+e.statusText):r=e instanceof Error?e.message:String(e),super(r),this.name=this.constructor.name,this.response=o}}e.NetworkError=r,e.createClient=function(e){const{credentials:t="same-origin",referrer:o,referrerPolicy:n,shouldRetry:s=(()=>!1)}=e,i=e.fetchFn||fetch,a=e.abortControllerImpl||AbortController,c=(()=>{let e=!1;const t=[];return{get disposed(){return e},onDispose:r=>e?(setTimeout((()=>r()),0),()=>{}):(t.push(r),()=>{t.splice(t.indexOf(r),1)}),dispose(){if(!e){e=!0;for(const e of[...t])e()}}}})();return{subscribe(l,p){if(c.disposed)throw new Error("Client has been disposed");const f=new a,u=c.onDispose((()=>{u(),f.abort()}));return(async()=>{var a;let c=null,u=0;for(;;){if(c){const e=await s(c,u);if(f.signal.aborted)return;if(!e)throw c;u++}try{const s="function"==typeof e.url?await e.url(l):e.url;if(f.signal.aborted)return;const c="function"==typeof e.headers?await e.headers():null!==(a=e.headers)&&void 0!==a?a:{};if(f.signal.aborted)return;let u;try{u=await i(s,{signal:f.signal,method:"POST",headers:Object.assign(Object.assign({},c),{"content-type":"application/json; charset=utf-8",accept:"application/graphql+json, application/json"}),credentials:t,referrer:o,referrerPolicy:n,body:JSON.stringify(l)})}catch(e){throw new r(e)}if(!u.ok)throw new r(u);if(!u.body)throw new Error("Missing response body");const d=u.headers.get("content-type");if(!d)throw new Error("Missing response content-type");if(!d.includes("application/graphql+json")&&!d.includes("application/json"))throw new Error(`Unsupported response content-type ${d}`);const h=await u.json();return p.next(h),f.abort()}catch(e){if(f.signal.aborted)return;if(!(e instanceof r))throw e;c=e}}})().then((()=>p.complete())).catch((e=>p.error(e))),()=>f.abort()},dispose(){c.dispose()}}},e.isResponse=function(e){return Array.isArray(e)&&("string"==typeof e[0]||null===e[0])&&t(e[1])},Object.defineProperty(e,"__esModule",{value:!0})}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlHttp={})}(this,(function(e){"use strict";class t extends Error{constructor(e){let t,r;var o;(function(e){return"object"==typeof e&&null!==e})(o=e)&&"boolean"==typeof o.ok&&"number"==typeof o.status&&"string"==typeof o.statusText?(r=e,t="Server responded with "+e.status+": "+e.statusText):t=e instanceof Error?e.message:String(e),super(t),this.name=this.constructor.name,this.response=r}}e.NetworkError=t,e.createClient=function(e){const{credentials:r="same-origin",referrer:o,referrerPolicy:n,shouldRetry:s=(()=>!1)}=e,i=e.fetchFn||fetch,a=e.abortControllerImpl||AbortController,c=(()=>{let e=!1;const t=[];return{get disposed(){return e},onDispose:r=>e?(setTimeout((()=>r()),0),()=>{}):(t.push(r),()=>{t.splice(t.indexOf(r),1)}),dispose(){if(!e){e=!0;for(const e of[...t])e()}}}})();return{subscribe(l,p){if(c.disposed)throw new Error("Client has been disposed");const f=new a,u=c.onDispose((()=>{u(),f.abort()}));return(async()=>{var a;let c=null,u=0;for(;;){if(c){const e=await s(c,u);if(f.signal.aborted)return;if(!e)throw c;u++}try{const s="function"==typeof e.url?await e.url(l):e.url;if(f.signal.aborted)return;const c="function"==typeof e.headers?await e.headers():null!==(a=e.headers)&&void 0!==a?a:{};if(f.signal.aborted)return;let u;try{u=await i(s,{signal:f.signal,method:"POST",headers:Object.assign(Object.assign({},c),{"content-type":"application/json; charset=utf-8",accept:"application/graphql+json, application/json"}),credentials:r,referrer:o,referrerPolicy:n,body:JSON.stringify(l)})}catch(e){throw new t(e)}if(!u.ok)throw new t(u);if(!u.body)throw new Error("Missing response body");const d=u.headers.get("content-type");if(!d)throw new Error("Missing response content-type");if(!d.includes("application/graphql+json")&&!d.includes("application/json"))throw new Error(`Unsupported response content-type ${d}`);const h=await u.json();return p.next(h),f.abort()}catch(e){if(f.signal.aborted)return;if(!(e instanceof t))throw e;c=e}}})().then((()=>p.complete())).catch((e=>p.error(e))),()=>f.abort()},dispose(){c.dispose()}}},Object.defineProperty(e,"__esModule",{value:!0})}));
Binary file