graphql-http 1.19.0 → 1.20.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
@@ -61,7 +61,7 @@ import { schema } from './previous-step';
61
61
  // Create the GraphQL over HTTP Node request handler
62
62
  const handler = createHandler({ schema });
63
63
 
64
- // Create a HTTP server using the listner on `/graphql`
64
+ // Create a HTTP server using the listener on `/graphql`
65
65
  const server = http.createServer((req, res) => {
66
66
  if (req.url.startsWith('/graphql')) {
67
67
  handler(req, res);
@@ -560,8 +560,8 @@ const client = createClient({
560
560
 
561
561
  </details>
562
562
 
563
- <details id="migrating-express-grpahql">
564
- <summary><a href="#migrating-express-grpahql">🔗</a> Server handler migration from <a href="https://github.com/graphql/express-graphql">express-graphql</a></summary>
563
+ <details id="migrating-express-graphql">
564
+ <summary><a href="#migrating-express-graphql">🔗</a> Server handler migration from <a href="https://github.com/graphql/express-graphql">express-graphql</a></summary>
565
565
 
566
566
  ```diff
567
567
  import express from 'express';
@@ -630,7 +630,7 @@ const handler = createHandler({
630
630
  context: async (req, args) => {
631
631
  return getDynamicContext(req, args);
632
632
  },
633
- // or static context by supplying the value direcly
633
+ // or static context by supplying the value directly
634
634
  });
635
635
  ```
636
636
 
@@ -725,6 +725,78 @@ console.log('Listening to port 4000');
725
725
 
726
726
  </details>
727
727
 
728
+ <details id="graphql-upload-http">
729
+ <summary><a href="#graphql-upload-http">🔗</a> Server handler usage with <a href="https://github.com/jaydenseric/graphql-upload">graphql-upload</a> and <a href="https://nodejs.org/api/http.html">http</a></summary>
730
+
731
+ ```js
732
+ import http from 'http';
733
+ import { createHandler } from 'graphql-http/lib/use/http';
734
+ import processRequest from 'graphql-upload/processRequest.mjs'; // yarn add graphql-upload
735
+ import { schema } from './my-graphql';
736
+
737
+ const handler = createHandler({
738
+ schema,
739
+ async parseRequestParams(req) {
740
+ const params = await processRequest(req.raw, req.context.res);
741
+ if (Array.isArray(params)) {
742
+ throw new Error('Batching is not supported');
743
+ }
744
+ return {
745
+ ...params,
746
+ // variables must be an object as per the GraphQL over HTTP spec
747
+ variables: Object(params.variables),
748
+ };
749
+ },
750
+ });
751
+
752
+ const server = http.createServer((req, res) => {
753
+ if (req.url.startsWith('/graphql')) {
754
+ handler(req, res);
755
+ } else {
756
+ res.writeHead(404).end();
757
+ }
758
+ });
759
+
760
+ server.listen(4000);
761
+ console.log('Listening to port 4000');
762
+ ```
763
+
764
+ </details>
765
+
766
+ <details id="graphql-upload-express">
767
+ <summary><a href="#graphql-upload-express">🔗</a> Server handler usage with <a href="https://github.com/jaydenseric/graphql-upload">graphql-upload</a> and <a href="https://expressjs.com/">express</a></summary>
768
+
769
+ ```js
770
+ import express from 'express'; // yarn add express
771
+ import { createHandler } from 'graphql-http/lib/use/express';
772
+ import processRequest from 'graphql-upload/processRequest.mjs'; // yarn add graphql-upload
773
+ import { schema } from './my-graphql';
774
+
775
+ const app = express();
776
+ app.all(
777
+ '/graphql',
778
+ createHandler({
779
+ schema,
780
+ async parseRequestParams(req) {
781
+ const params = await processRequest(req.raw, req.context.res);
782
+ if (Array.isArray(params)) {
783
+ throw new Error('Batching is not supported');
784
+ }
785
+ return {
786
+ ...params,
787
+ // variables must be an object as per the GraphQL over HTTP spec
788
+ variables: Object(params.variables),
789
+ };
790
+ },
791
+ }),
792
+ );
793
+
794
+ app.listen({ port: 4000 });
795
+ console.log('Listening to port 4000');
796
+ ```
797
+
798
+ </details>
799
+
728
800
  <details id="audit-jest">
729
801
  <summary><a href="#audit-jest">🔗</a> Audit for servers usage in <a href="https://jestjs.io">Jest</a> environment</summary>
730
802
 
package/lib/client.d.mts CHANGED
@@ -76,7 +76,7 @@ export interface ClientOptions {
76
76
  *
77
77
  * You may implement your own waiting strategy by timing the resolution of the returned promise.
78
78
  *
79
- * Useful for retrying requests that failed because the service is temporarely unavailable.
79
+ * Useful for retrying requests that failed because the service is temporarily unavailable.
80
80
  *
81
81
  * `retries` argument counts actual retries, so it will begin with
82
82
  * 0 after the first failed request.
@@ -135,7 +135,7 @@ export declare function createClient(options: ClientOptions): Client;
135
135
  */
136
136
  export declare class NetworkError<Response extends ResponseLike = ResponseLike> extends Error {
137
137
  /**
138
- * The underlyig response thats considered an error.
138
+ * The underlying response thats considered an error.
139
139
  *
140
140
  * Will be undefined when no response is received,
141
141
  * instead an unexpected network error.
package/lib/client.d.ts CHANGED
@@ -76,7 +76,7 @@ export interface ClientOptions {
76
76
  *
77
77
  * You may implement your own waiting strategy by timing the resolution of the returned promise.
78
78
  *
79
- * Useful for retrying requests that failed because the service is temporarely unavailable.
79
+ * Useful for retrying requests that failed because the service is temporarily unavailable.
80
80
  *
81
81
  * `retries` argument counts actual retries, so it will begin with
82
82
  * 0 after the first failed request.
@@ -135,7 +135,7 @@ export declare function createClient(options: ClientOptions): Client;
135
135
  */
136
136
  export declare class NetworkError<Response extends ResponseLike = ResponseLike> extends Error {
137
137
  /**
138
- * The underlyig response thats considered an error.
138
+ * The underlying response thats considered an error.
139
139
  *
140
140
  * Will be undefined when no response is received,
141
141
  * instead an unexpected network error.
package/lib/common.d.mts CHANGED
@@ -11,10 +11,10 @@
11
11
  * @category Common
12
12
  */
13
13
  export interface RequestParams {
14
- operationName?: string | undefined;
14
+ operationName?: string | null | undefined;
15
15
  query: string;
16
- variables?: Record<string, unknown> | undefined;
17
- extensions?: Record<string, unknown> | undefined;
16
+ variables?: Record<string, unknown> | null | undefined;
17
+ extensions?: Record<string, unknown> | null | undefined;
18
18
  }
19
19
  /**
20
20
  * A representation of any set of values over any amount of time.
@@ -24,7 +24,7 @@ export interface RequestParams {
24
24
  export interface Sink<T = unknown> {
25
25
  /** Next value arriving. */
26
26
  next(value: T): void;
27
- /** An error that has occured. This function "closes" the sink. */
27
+ /** An error that has occurred. This function "closes" the sink. */
28
28
  error(error: unknown): void;
29
29
  /** The sink has completed. This function "closes" the sink. */
30
30
  complete(): void;
package/lib/common.d.ts CHANGED
@@ -11,10 +11,10 @@
11
11
  * @category Common
12
12
  */
13
13
  export interface RequestParams {
14
- operationName?: string | undefined;
14
+ operationName?: string | null | undefined;
15
15
  query: string;
16
- variables?: Record<string, unknown> | undefined;
17
- extensions?: Record<string, unknown> | undefined;
16
+ variables?: Record<string, unknown> | null | undefined;
17
+ extensions?: Record<string, unknown> | null | undefined;
18
18
  }
19
19
  /**
20
20
  * A representation of any set of values over any amount of time.
@@ -24,7 +24,7 @@ export interface RequestParams {
24
24
  export interface Sink<T = unknown> {
25
25
  /** Next value arriving. */
26
26
  next(value: T): void;
27
- /** An error that has occured. This function "closes" the sink. */
27
+ /** An error that has occurred. This function "closes" the sink. */
28
28
  error(error: unknown): void;
29
29
  /** The sink has completed. This function "closes" the sink. */
30
30
  complete(): void;
package/lib/handler.d.mts CHANGED
@@ -84,16 +84,10 @@ export interface ResponseInit {
84
84
  * @category Server
85
85
  */
86
86
  export type Response = readonly [body: ResponseBody | null, init: ResponseInit];
87
- /**
88
- * Checks whether the passed value is the `graphql-http` server agnostic response.
89
- *
90
- * @category Server
91
- */
92
- export declare function isResponse(val: unknown): val is Response;
93
87
  /**
94
88
  * A concrete GraphQL execution context value type.
95
89
  *
96
- * Mainly used because TypeScript collapes unions
90
+ * Mainly used because TypeScript collapses unions
97
91
  * with `any` or `unknown` to `any` or `unknown`. So,
98
92
  * we use a custom type to allow definitions such as
99
93
  * the `context` server option.
@@ -107,6 +101,25 @@ export type OperationContext = Record<PropertyKey, unknown> | symbol | number |
107
101
  * @category Server
108
102
  */
109
103
  export type FormatError = (err: Readonly<GraphQLError | Error>) => GraphQLError | Error;
104
+ /**
105
+ * The request parser for an incoming GraphQL request. It parses and validates the
106
+ * request itself, including the request method and the content-type of the body.
107
+ *
108
+ * In case you are extending the server to handle more request types, this is the
109
+ * perfect place to do so.
110
+ *
111
+ * If an error is thrown, it will be formatted using the provided {@link FormatError}
112
+ * and handled following the spec to be gracefully reported to the client.
113
+ *
114
+ * Throwing an instance of `Error` will _always_ have the client respond with a `400: Bad Request`
115
+ * and the error's message in the response body; however, if an instance of `GraphQLError` is thrown,
116
+ * it will be reported depending on the accepted content-type.
117
+ *
118
+ * If you return nothing, the default parser will be used instead.
119
+ *
120
+ * @category Server
121
+ */
122
+ export type ParseRequestParams<RequestRaw = unknown, RequestContext = unknown> = (req: Request<RequestRaw, RequestContext>) => Promise<RequestParams | Response | void> | RequestParams | Response | void;
110
123
  /** @category Server */
111
124
  export type OperationArgs<Context extends OperationContext = undefined> = ExecutionArgs & {
112
125
  contextValue?: Context;
@@ -223,15 +236,21 @@ export interface HandlerOptions<RequestRaw = unknown, RequestContext = unknown,
223
236
  onOperation?: (req: Request<RequestRaw, RequestContext>, args: OperationArgs<Context>, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void;
224
237
  /**
225
238
  * Format handled errors to your satisfaction. Either GraphQL errors
226
- * or safe request processing errors are meant by "handleded errors".
239
+ * or safe request processing errors are meant by "handled errors".
227
240
  *
228
- * If multiple errors have occured, all of them will be mapped using
241
+ * If multiple errors have occurred, all of them will be mapped using
229
242
  * this formatter.
230
243
  */
231
244
  formatError?: FormatError;
245
+ /**
246
+ * The request parser for an incoming GraphQL request.
247
+ *
248
+ * Read more about it in {@link ParseRequestParams}.
249
+ */
250
+ parseRequestParams?: ParseRequestParams<RequestRaw, RequestContext>;
232
251
  }
233
252
  /**
234
- * The ready-to-use handler. Simply plug it in your favourite HTTP framework
253
+ * The ready-to-use handler. Simply plug it in your favorite HTTP framework
235
254
  * and enjoy.
236
255
  *
237
256
  * Errors thrown from **any** of the provided options or callbacks (or even due to
@@ -243,7 +262,7 @@ export interface HandlerOptions<RequestRaw = unknown, RequestContext = unknown,
243
262
  export type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Request<RequestRaw, RequestContext>) => Promise<Response>;
244
263
  /**
245
264
  * Makes a GraphQL over HTTP spec compliant server handler. The handler can
246
- * be used with your favourite server library.
265
+ * be used with your favorite server library.
247
266
  *
248
267
  * Beware that the handler resolves only after the whole operation completes.
249
268
  *
@@ -297,30 +316,3 @@ export type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Requ
297
316
  * @category Server
298
317
  */
299
318
  export declare function createHandler<RequestRaw = unknown, RequestContext = unknown, Context extends OperationContext = undefined>(options: HandlerOptions<RequestRaw, RequestContext, Context>): Handler<RequestRaw, RequestContext>;
300
- /**
301
- * Request's Media-Type that the server accepts.
302
- *
303
- * @category Server
304
- */
305
- export type AcceptableMediaType = 'application/graphql-response+json' | 'application/json';
306
- /**
307
- * Inspects the request and detects the appropriate/acceptable Media-Type
308
- * looking at the `Accept` header while complying with the GraphQL over HTTP spec.
309
- *
310
- * @category Server
311
- */
312
- export declare function getAcceptableMediaType(acceptHeader: string | null | undefined): AcceptableMediaType | null;
313
- /**
314
- * Creates an appropriate GraphQL over HTTP response following the provided arguments.
315
- *
316
- * If the first argument is an `ExecutionResult`, the operation will be treated as "successful".
317
- *
318
- * If the first argument is (an array of) `GraphQLError`, or an `ExecutionResult` without the `data` field, it will be treated
319
- * the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP spec.
320
- *
321
- * If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the
322
- * error will be present in the `ExecutionResult` style.
323
- *
324
- * @category Server
325
- */
326
- export declare function makeResponse(resultOrErrors: Readonly<ExecutionResult> | Readonly<GraphQLError[]> | Readonly<GraphQLError> | Readonly<Error>, acceptedMediaType: AcceptableMediaType, formatError: FormatError): Response;
package/lib/handler.d.ts CHANGED
@@ -84,16 +84,10 @@ export interface ResponseInit {
84
84
  * @category Server
85
85
  */
86
86
  export type Response = readonly [body: ResponseBody | null, init: ResponseInit];
87
- /**
88
- * Checks whether the passed value is the `graphql-http` server agnostic response.
89
- *
90
- * @category Server
91
- */
92
- export declare function isResponse(val: unknown): val is Response;
93
87
  /**
94
88
  * A concrete GraphQL execution context value type.
95
89
  *
96
- * Mainly used because TypeScript collapes unions
90
+ * Mainly used because TypeScript collapses unions
97
91
  * with `any` or `unknown` to `any` or `unknown`. So,
98
92
  * we use a custom type to allow definitions such as
99
93
  * the `context` server option.
@@ -107,6 +101,25 @@ export type OperationContext = Record<PropertyKey, unknown> | symbol | number |
107
101
  * @category Server
108
102
  */
109
103
  export type FormatError = (err: Readonly<GraphQLError | Error>) => GraphQLError | Error;
104
+ /**
105
+ * The request parser for an incoming GraphQL request. It parses and validates the
106
+ * request itself, including the request method and the content-type of the body.
107
+ *
108
+ * In case you are extending the server to handle more request types, this is the
109
+ * perfect place to do so.
110
+ *
111
+ * If an error is thrown, it will be formatted using the provided {@link FormatError}
112
+ * and handled following the spec to be gracefully reported to the client.
113
+ *
114
+ * Throwing an instance of `Error` will _always_ have the client respond with a `400: Bad Request`
115
+ * and the error's message in the response body; however, if an instance of `GraphQLError` is thrown,
116
+ * it will be reported depending on the accepted content-type.
117
+ *
118
+ * If you return nothing, the default parser will be used instead.
119
+ *
120
+ * @category Server
121
+ */
122
+ export type ParseRequestParams<RequestRaw = unknown, RequestContext = unknown> = (req: Request<RequestRaw, RequestContext>) => Promise<RequestParams | Response | void> | RequestParams | Response | void;
110
123
  /** @category Server */
111
124
  export type OperationArgs<Context extends OperationContext = undefined> = ExecutionArgs & {
112
125
  contextValue?: Context;
@@ -223,15 +236,21 @@ export interface HandlerOptions<RequestRaw = unknown, RequestContext = unknown,
223
236
  onOperation?: (req: Request<RequestRaw, RequestContext>, args: OperationArgs<Context>, result: ExecutionResult) => Promise<ExecutionResult | Response | void> | ExecutionResult | Response | void;
224
237
  /**
225
238
  * Format handled errors to your satisfaction. Either GraphQL errors
226
- * or safe request processing errors are meant by "handleded errors".
239
+ * or safe request processing errors are meant by "handled errors".
227
240
  *
228
- * If multiple errors have occured, all of them will be mapped using
241
+ * If multiple errors have occurred, all of them will be mapped using
229
242
  * this formatter.
230
243
  */
231
244
  formatError?: FormatError;
245
+ /**
246
+ * The request parser for an incoming GraphQL request.
247
+ *
248
+ * Read more about it in {@link ParseRequestParams}.
249
+ */
250
+ parseRequestParams?: ParseRequestParams<RequestRaw, RequestContext>;
232
251
  }
233
252
  /**
234
- * The ready-to-use handler. Simply plug it in your favourite HTTP framework
253
+ * The ready-to-use handler. Simply plug it in your favorite HTTP framework
235
254
  * and enjoy.
236
255
  *
237
256
  * Errors thrown from **any** of the provided options or callbacks (or even due to
@@ -243,7 +262,7 @@ export interface HandlerOptions<RequestRaw = unknown, RequestContext = unknown,
243
262
  export type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Request<RequestRaw, RequestContext>) => Promise<Response>;
244
263
  /**
245
264
  * Makes a GraphQL over HTTP spec compliant server handler. The handler can
246
- * be used with your favourite server library.
265
+ * be used with your favorite server library.
247
266
  *
248
267
  * Beware that the handler resolves only after the whole operation completes.
249
268
  *
@@ -297,30 +316,3 @@ export type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Requ
297
316
  * @category Server
298
317
  */
299
318
  export declare function createHandler<RequestRaw = unknown, RequestContext = unknown, Context extends OperationContext = undefined>(options: HandlerOptions<RequestRaw, RequestContext, Context>): Handler<RequestRaw, RequestContext>;
300
- /**
301
- * Request's Media-Type that the server accepts.
302
- *
303
- * @category Server
304
- */
305
- export type AcceptableMediaType = 'application/graphql-response+json' | 'application/json';
306
- /**
307
- * Inspects the request and detects the appropriate/acceptable Media-Type
308
- * looking at the `Accept` header while complying with the GraphQL over HTTP spec.
309
- *
310
- * @category Server
311
- */
312
- export declare function getAcceptableMediaType(acceptHeader: string | null | undefined): AcceptableMediaType | null;
313
- /**
314
- * Creates an appropriate GraphQL over HTTP response following the provided arguments.
315
- *
316
- * If the first argument is an `ExecutionResult`, the operation will be treated as "successful".
317
- *
318
- * If the first argument is (an array of) `GraphQLError`, or an `ExecutionResult` without the `data` field, it will be treated
319
- * the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP spec.
320
- *
321
- * If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the
322
- * error will be present in the `ExecutionResult` style.
323
- *
324
- * @category Server
325
- */
326
- export declare function makeResponse(resultOrErrors: Readonly<ExecutionResult> | Readonly<GraphQLError[]> | Readonly<GraphQLError> | Readonly<Error>, acceptedMediaType: AcceptableMediaType, formatError: FormatError): Response;
package/lib/handler.js CHANGED
@@ -5,24 +5,19 @@
5
5
  *
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.makeResponse = exports.getAcceptableMediaType = exports.createHandler = exports.isResponse = void 0;
8
+ exports.createHandler = void 0;
9
9
  const graphql_1 = require("graphql");
10
10
  const utils_1 = require("./utils");
11
- /**
12
- * Checks whether the passed value is the `graphql-http` server agnostic response.
13
- *
14
- * @category Server
15
- */
11
+ /** Checks whether the passed value is the `graphql-http` server agnostic response. */
16
12
  function isResponse(val) {
17
13
  // TODO: make sure the contents of init match ResponseInit
18
14
  return (Array.isArray(val) &&
19
15
  (typeof val[0] === 'string' || val[0] === null) &&
20
16
  (0, utils_1.isObject)(val[1]));
21
17
  }
22
- exports.isResponse = isResponse;
23
18
  /**
24
19
  * Makes a GraphQL over HTTP spec compliant server handler. The handler can
25
- * be used with your favourite server library.
20
+ * be used with your favorite server library.
26
21
  *
27
22
  * Beware that the handler resolves only after the whole operation completes.
28
23
  *
@@ -76,23 +71,32 @@ exports.isResponse = isResponse;
76
71
  * @category Server
77
72
  */
78
73
  function createHandler(options) {
79
- const { schema, context, validate = graphql_1.validate, validationRules = [], execute = graphql_1.execute, parse = graphql_1.parse, getOperationAST = graphql_1.getOperationAST, rootValue, onSubscribe, onOperation, formatError = (err) => err, } = options;
74
+ const { schema, context, validate = graphql_1.validate, validationRules = [], execute = graphql_1.execute, parse = graphql_1.parse, getOperationAST = graphql_1.getOperationAST, rootValue, onSubscribe, onOperation, formatError = (err) => err, parseRequestParams = defaultParseRequestParams, } = options;
80
75
  return async function handler(req) {
81
- var _a, _b;
82
- const method = req.method;
83
- if (method !== 'GET' && method !== 'POST') {
84
- return [
85
- null,
86
- {
87
- status: 405,
88
- statusText: 'Method Not Allowed',
89
- headers: {
90
- allow: 'GET, POST',
91
- },
92
- },
93
- ];
76
+ let acceptedMediaType = null;
77
+ const accepts = (getHeader(req, 'accept') || '*/*')
78
+ .replace(/\s/g, '')
79
+ .toLowerCase()
80
+ .split(',');
81
+ for (const accept of accepts) {
82
+ // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
83
+ // TODO: handle the weight parameter "q"
84
+ const [mediaType, ...params] = accept.split(';');
85
+ const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
86
+ if (mediaType === 'application/graphql-response+json' &&
87
+ charset === 'charset=utf8') {
88
+ acceptedMediaType = 'application/graphql-response+json';
89
+ break;
90
+ }
91
+ // application/json should be the default until watershed
92
+ if ((mediaType === 'application/json' ||
93
+ mediaType === 'application/*' ||
94
+ mediaType === '*/*') &&
95
+ charset === 'charset=utf8') {
96
+ acceptedMediaType = 'application/json';
97
+ break;
98
+ }
94
99
  }
95
- const acceptedMediaType = getAcceptableMediaType(getHeader(req, 'accept'));
96
100
  if (!acceptedMediaType) {
97
101
  return [
98
102
  null,
@@ -105,89 +109,14 @@ function createHandler(options) {
105
109
  },
106
110
  ];
107
111
  }
108
- // TODO: should graphql-http care about content-encoding? I'd say unzipping should happen before handler is reached
109
- const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
110
- ] = (getHeader(req, 'content-type') || '')
111
- .replace(/\s/g, '')
112
- .toLowerCase()
113
- .split(';');
114
112
  let params;
115
113
  try {
116
- const partParams = {};
117
- switch (true) {
118
- case method === 'GET': {
119
- // TODO: what if content-type is specified and is not application/x-www-form-urlencoded?
120
- try {
121
- const [, search] = req.url.split('?');
122
- const searchParams = new URLSearchParams(search);
123
- partParams.operationName =
124
- (_a = searchParams.get('operationName')) !== null && _a !== void 0 ? _a : undefined;
125
- partParams.query = (_b = searchParams.get('query')) !== null && _b !== void 0 ? _b : undefined;
126
- const variables = searchParams.get('variables');
127
- if (variables)
128
- partParams.variables = JSON.parse(variables);
129
- const extensions = searchParams.get('extensions');
130
- if (extensions)
131
- partParams.extensions = JSON.parse(extensions);
132
- }
133
- catch (_c) {
134
- throw new Error('Unparsable URL');
135
- }
136
- break;
137
- }
138
- case method === 'POST' &&
139
- mediaType === 'application/json' &&
140
- charset === 'charset=utf-8':
141
- {
142
- if (!req.body) {
143
- throw new Error('Missing body');
144
- }
145
- let data;
146
- try {
147
- const body = typeof req.body === 'function' ? await req.body() : req.body;
148
- data = typeof body === 'string' ? JSON.parse(body) : body;
149
- }
150
- catch (err) {
151
- throw new Error('Unparsable JSON body');
152
- }
153
- if (!(0, utils_1.isObject)(data)) {
154
- throw new Error('JSON body must be an object');
155
- }
156
- partParams.operationName = data.operationName;
157
- partParams.query = data.query;
158
- partParams.variables = data.variables;
159
- partParams.extensions = data.extensions;
160
- break;
161
- }
162
- default: // graphql-http doesnt support any other content type
163
- return [
164
- null,
165
- {
166
- status: 415,
167
- statusText: 'Unsupported Media Type',
168
- },
169
- ];
170
- }
171
- if (partParams.query == null)
172
- throw new Error('Missing query');
173
- if (typeof partParams.query !== 'string')
174
- throw new Error('Invalid query');
175
- if (partParams.variables != null &&
176
- (typeof partParams.variables !== 'object' ||
177
- Array.isArray(partParams.variables))) {
178
- throw new Error('Invalid variables');
179
- }
180
- if (partParams.operationName != null &&
181
- typeof partParams.operationName !== 'string') {
182
- throw new Error('Invalid operationName');
183
- }
184
- if (partParams.extensions != null &&
185
- (typeof partParams.extensions !== 'object' ||
186
- Array.isArray(partParams.extensions))) {
187
- throw new Error('Invalid extensions');
188
- }
189
- // request parameters are checked and now complete
190
- params = partParams;
114
+ let paramsOrRes = await parseRequestParams(req);
115
+ if (!paramsOrRes)
116
+ paramsOrRes = await defaultParseRequestParams(req);
117
+ if (isResponse(paramsOrRes))
118
+ return paramsOrRes;
119
+ params = paramsOrRes;
191
120
  }
192
121
  catch (err) {
193
122
  return makeResponse(err, acceptedMediaType, formatError);
@@ -249,7 +178,7 @@ function createHandler(options) {
249
178
  throw null;
250
179
  operation = ast.operation;
251
180
  }
252
- catch (_d) {
181
+ catch (_a) {
253
182
  return makeResponse(new graphql_1.GraphQLError('Unable to detect operation AST'), acceptedMediaType, formatError);
254
183
  }
255
184
  if (operation === 'subscription') {
@@ -257,7 +186,7 @@ function createHandler(options) {
257
186
  }
258
187
  // mutations cannot happen over GETs
259
188
  // https://graphql.github.io/graphql-over-http/draft/#sel-CALFJRPAAELBAAxwP
260
- if (operation === 'mutation' && method === 'GET') {
189
+ if (operation === 'mutation' && req.method === 'GET') {
261
190
  return [
262
191
  JSON.stringify({
263
192
  errors: [new graphql_1.GraphQLError('Cannot perform mutations over GET')],
@@ -294,38 +223,109 @@ function createHandler(options) {
294
223
  }
295
224
  exports.createHandler = createHandler;
296
225
  /**
297
- * Inspects the request and detects the appropriate/acceptable Media-Type
298
- * looking at the `Accept` header while complying with the GraphQL over HTTP spec.
226
+ * The default request params parser. Used when no custom one is provided or if it
227
+ * returns nothing.
299
228
  *
300
- * @category Server
229
+ * Read more about it in {@link ParseRequestParams}.
230
+ *
231
+ * TODO: should graphql-http itself care about content-encoding? I'd say unzipping should happen before handler is reached
301
232
  */
302
- function getAcceptableMediaType(acceptHeader) {
303
- let acceptedMediaType = null;
304
- const accepts = (acceptHeader || '*/*')
233
+ async function defaultParseRequestParams(req) {
234
+ var _a, _b;
235
+ const method = req.method;
236
+ if (method !== 'GET' && method !== 'POST') {
237
+ return [
238
+ null,
239
+ {
240
+ status: 405,
241
+ statusText: 'Method Not Allowed',
242
+ headers: {
243
+ allow: 'GET, POST',
244
+ },
245
+ },
246
+ ];
247
+ }
248
+ const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
249
+ ] = (getHeader(req, 'content-type') || '')
305
250
  .replace(/\s/g, '')
306
251
  .toLowerCase()
307
- .split(',');
308
- for (const accept of accepts) {
309
- // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
310
- // TODO: handle the weight parameter "q"
311
- const [mediaType, ...params] = accept.split(';');
312
- const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
313
- if (mediaType === 'application/graphql-response+json' &&
314
- charset === 'charset=utf8') {
315
- acceptedMediaType = 'application/graphql-response+json';
316
- break;
317
- }
318
- if ((mediaType === 'application/json' ||
319
- mediaType === 'application/*' ||
320
- mediaType === '*/*') &&
321
- charset === 'charset=utf8') {
322
- acceptedMediaType = 'application/json';
252
+ .split(';');
253
+ const partParams = {};
254
+ switch (true) {
255
+ case method === 'GET': {
256
+ // TODO: what if content-type is specified and is not application/x-www-form-urlencoded?
257
+ try {
258
+ const [, search] = req.url.split('?');
259
+ const searchParams = new URLSearchParams(search);
260
+ partParams.operationName =
261
+ (_a = searchParams.get('operationName')) !== null && _a !== void 0 ? _a : undefined;
262
+ partParams.query = (_b = searchParams.get('query')) !== null && _b !== void 0 ? _b : undefined;
263
+ const variables = searchParams.get('variables');
264
+ if (variables)
265
+ partParams.variables = JSON.parse(variables);
266
+ const extensions = searchParams.get('extensions');
267
+ if (extensions)
268
+ partParams.extensions = JSON.parse(extensions);
269
+ }
270
+ catch (_c) {
271
+ throw new Error('Unparsable URL');
272
+ }
323
273
  break;
324
274
  }
275
+ case method === 'POST' &&
276
+ mediaType === 'application/json' &&
277
+ charset === 'charset=utf-8':
278
+ {
279
+ if (!req.body) {
280
+ throw new Error('Missing body');
281
+ }
282
+ let data;
283
+ try {
284
+ const body = typeof req.body === 'function' ? await req.body() : req.body;
285
+ data = typeof body === 'string' ? JSON.parse(body) : body;
286
+ }
287
+ catch (err) {
288
+ throw new Error('Unparsable JSON body');
289
+ }
290
+ if (!(0, utils_1.isObject)(data)) {
291
+ throw new Error('JSON body must be an object');
292
+ }
293
+ partParams.operationName = data.operationName;
294
+ partParams.query = data.query;
295
+ partParams.variables = data.variables;
296
+ partParams.extensions = data.extensions;
297
+ break;
298
+ }
299
+ default: // graphql-http doesnt support any other content type
300
+ return [
301
+ null,
302
+ {
303
+ status: 415,
304
+ statusText: 'Unsupported Media Type',
305
+ },
306
+ ];
307
+ }
308
+ if (partParams.query == null)
309
+ throw new Error('Missing query');
310
+ if (typeof partParams.query !== 'string')
311
+ throw new Error('Invalid query');
312
+ if (partParams.variables != null &&
313
+ (typeof partParams.variables !== 'object' ||
314
+ Array.isArray(partParams.variables))) {
315
+ throw new Error('Invalid variables');
316
+ }
317
+ if (partParams.operationName != null &&
318
+ typeof partParams.operationName !== 'string') {
319
+ throw new Error('Invalid operationName');
325
320
  }
326
- return acceptedMediaType;
321
+ if (partParams.extensions != null &&
322
+ (typeof partParams.extensions !== 'object' ||
323
+ Array.isArray(partParams.extensions))) {
324
+ throw new Error('Invalid extensions');
325
+ }
326
+ // request parameters are checked and now complete
327
+ return partParams;
327
328
  }
328
- exports.getAcceptableMediaType = getAcceptableMediaType;
329
329
  /**
330
330
  * Creates an appropriate GraphQL over HTTP response following the provided arguments.
331
331
  *
@@ -336,8 +336,6 @@ exports.getAcceptableMediaType = getAcceptableMediaType;
336
336
  *
337
337
  * If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the
338
338
  * error will be present in the `ExecutionResult` style.
339
- *
340
- * @category Server
341
339
  */
342
340
  function makeResponse(resultOrErrors, acceptedMediaType, formatError) {
343
341
  if (resultOrErrors instanceof Error &&
@@ -391,7 +389,6 @@ function makeResponse(resultOrErrors, acceptedMediaType, formatError) {
391
389
  },
392
390
  ];
393
391
  }
394
- exports.makeResponse = makeResponse;
395
392
  function getHeader(req, key) {
396
393
  if (typeof req.headers.get === 'function') {
397
394
  return req.headers.get(key);
package/lib/handler.mjs CHANGED
@@ -5,12 +5,8 @@
5
5
  */
6
6
  import { validate as graphqlValidate, specifiedRules, execute as graphqlExecute, parse as graphqlParse, getOperationAST as graphqlGetOperationAST, GraphQLError, } from 'graphql';
7
7
  import { areGraphQLErrors, isAsyncIterable, isExecutionResult, isGraphQLError, isObject, jsonErrorReplacer, } from './utils.mjs';
8
- /**
9
- * Checks whether the passed value is the `graphql-http` server agnostic response.
10
- *
11
- * @category Server
12
- */
13
- export function isResponse(val) {
8
+ /** Checks whether the passed value is the `graphql-http` server agnostic response. */
9
+ function isResponse(val) {
14
10
  // TODO: make sure the contents of init match ResponseInit
15
11
  return (Array.isArray(val) &&
16
12
  (typeof val[0] === 'string' || val[0] === null) &&
@@ -18,7 +14,7 @@ export function isResponse(val) {
18
14
  }
19
15
  /**
20
16
  * Makes a GraphQL over HTTP spec compliant server handler. The handler can
21
- * be used with your favourite server library.
17
+ * be used with your favorite server library.
22
18
  *
23
19
  * Beware that the handler resolves only after the whole operation completes.
24
20
  *
@@ -72,23 +68,32 @@ export function isResponse(val) {
72
68
  * @category Server
73
69
  */
74
70
  export function createHandler(options) {
75
- const { schema, context, validate = graphqlValidate, validationRules = [], execute = graphqlExecute, parse = graphqlParse, getOperationAST = graphqlGetOperationAST, rootValue, onSubscribe, onOperation, formatError = (err) => err, } = options;
71
+ const { schema, context, validate = graphqlValidate, validationRules = [], execute = graphqlExecute, parse = graphqlParse, getOperationAST = graphqlGetOperationAST, rootValue, onSubscribe, onOperation, formatError = (err) => err, parseRequestParams = defaultParseRequestParams, } = options;
76
72
  return async function handler(req) {
77
- var _a, _b;
78
- const method = req.method;
79
- if (method !== 'GET' && method !== 'POST') {
80
- return [
81
- null,
82
- {
83
- status: 405,
84
- statusText: 'Method Not Allowed',
85
- headers: {
86
- allow: 'GET, POST',
87
- },
88
- },
89
- ];
73
+ let acceptedMediaType = null;
74
+ const accepts = (getHeader(req, 'accept') || '*/*')
75
+ .replace(/\s/g, '')
76
+ .toLowerCase()
77
+ .split(',');
78
+ for (const accept of accepts) {
79
+ // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
80
+ // TODO: handle the weight parameter "q"
81
+ const [mediaType, ...params] = accept.split(';');
82
+ const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
83
+ if (mediaType === 'application/graphql-response+json' &&
84
+ charset === 'charset=utf8') {
85
+ acceptedMediaType = 'application/graphql-response+json';
86
+ break;
87
+ }
88
+ // application/json should be the default until watershed
89
+ if ((mediaType === 'application/json' ||
90
+ mediaType === 'application/*' ||
91
+ mediaType === '*/*') &&
92
+ charset === 'charset=utf8') {
93
+ acceptedMediaType = 'application/json';
94
+ break;
95
+ }
90
96
  }
91
- const acceptedMediaType = getAcceptableMediaType(getHeader(req, 'accept'));
92
97
  if (!acceptedMediaType) {
93
98
  return [
94
99
  null,
@@ -101,89 +106,14 @@ export function createHandler(options) {
101
106
  },
102
107
  ];
103
108
  }
104
- // TODO: should graphql-http care about content-encoding? I'd say unzipping should happen before handler is reached
105
- const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
106
- ] = (getHeader(req, 'content-type') || '')
107
- .replace(/\s/g, '')
108
- .toLowerCase()
109
- .split(';');
110
109
  let params;
111
110
  try {
112
- const partParams = {};
113
- switch (true) {
114
- case method === 'GET': {
115
- // TODO: what if content-type is specified and is not application/x-www-form-urlencoded?
116
- try {
117
- const [, search] = req.url.split('?');
118
- const searchParams = new URLSearchParams(search);
119
- partParams.operationName =
120
- (_a = searchParams.get('operationName')) !== null && _a !== void 0 ? _a : undefined;
121
- partParams.query = (_b = searchParams.get('query')) !== null && _b !== void 0 ? _b : undefined;
122
- const variables = searchParams.get('variables');
123
- if (variables)
124
- partParams.variables = JSON.parse(variables);
125
- const extensions = searchParams.get('extensions');
126
- if (extensions)
127
- partParams.extensions = JSON.parse(extensions);
128
- }
129
- catch (_c) {
130
- throw new Error('Unparsable URL');
131
- }
132
- break;
133
- }
134
- case method === 'POST' &&
135
- mediaType === 'application/json' &&
136
- charset === 'charset=utf-8':
137
- {
138
- if (!req.body) {
139
- throw new Error('Missing body');
140
- }
141
- let data;
142
- try {
143
- const body = typeof req.body === 'function' ? await req.body() : req.body;
144
- data = typeof body === 'string' ? JSON.parse(body) : body;
145
- }
146
- catch (err) {
147
- throw new Error('Unparsable JSON body');
148
- }
149
- if (!isObject(data)) {
150
- throw new Error('JSON body must be an object');
151
- }
152
- partParams.operationName = data.operationName;
153
- partParams.query = data.query;
154
- partParams.variables = data.variables;
155
- partParams.extensions = data.extensions;
156
- break;
157
- }
158
- default: // graphql-http doesnt support any other content type
159
- return [
160
- null,
161
- {
162
- status: 415,
163
- statusText: 'Unsupported Media Type',
164
- },
165
- ];
166
- }
167
- if (partParams.query == null)
168
- throw new Error('Missing query');
169
- if (typeof partParams.query !== 'string')
170
- throw new Error('Invalid query');
171
- if (partParams.variables != null &&
172
- (typeof partParams.variables !== 'object' ||
173
- Array.isArray(partParams.variables))) {
174
- throw new Error('Invalid variables');
175
- }
176
- if (partParams.operationName != null &&
177
- typeof partParams.operationName !== 'string') {
178
- throw new Error('Invalid operationName');
179
- }
180
- if (partParams.extensions != null &&
181
- (typeof partParams.extensions !== 'object' ||
182
- Array.isArray(partParams.extensions))) {
183
- throw new Error('Invalid extensions');
184
- }
185
- // request parameters are checked and now complete
186
- params = partParams;
111
+ let paramsOrRes = await parseRequestParams(req);
112
+ if (!paramsOrRes)
113
+ paramsOrRes = await defaultParseRequestParams(req);
114
+ if (isResponse(paramsOrRes))
115
+ return paramsOrRes;
116
+ params = paramsOrRes;
187
117
  }
188
118
  catch (err) {
189
119
  return makeResponse(err, acceptedMediaType, formatError);
@@ -245,7 +175,7 @@ export function createHandler(options) {
245
175
  throw null;
246
176
  operation = ast.operation;
247
177
  }
248
- catch (_d) {
178
+ catch (_a) {
249
179
  return makeResponse(new GraphQLError('Unable to detect operation AST'), acceptedMediaType, formatError);
250
180
  }
251
181
  if (operation === 'subscription') {
@@ -253,7 +183,7 @@ export function createHandler(options) {
253
183
  }
254
184
  // mutations cannot happen over GETs
255
185
  // https://graphql.github.io/graphql-over-http/draft/#sel-CALFJRPAAELBAAxwP
256
- if (operation === 'mutation' && method === 'GET') {
186
+ if (operation === 'mutation' && req.method === 'GET') {
257
187
  return [
258
188
  JSON.stringify({
259
189
  errors: [new GraphQLError('Cannot perform mutations over GET')],
@@ -289,36 +219,108 @@ export function createHandler(options) {
289
219
  };
290
220
  }
291
221
  /**
292
- * Inspects the request and detects the appropriate/acceptable Media-Type
293
- * looking at the `Accept` header while complying with the GraphQL over HTTP spec.
222
+ * The default request params parser. Used when no custom one is provided or if it
223
+ * returns nothing.
294
224
  *
295
- * @category Server
225
+ * Read more about it in {@link ParseRequestParams}.
226
+ *
227
+ * TODO: should graphql-http itself care about content-encoding? I'd say unzipping should happen before handler is reached
296
228
  */
297
- export function getAcceptableMediaType(acceptHeader) {
298
- let acceptedMediaType = null;
299
- const accepts = (acceptHeader || '*/*')
229
+ async function defaultParseRequestParams(req) {
230
+ var _a, _b;
231
+ const method = req.method;
232
+ if (method !== 'GET' && method !== 'POST') {
233
+ return [
234
+ null,
235
+ {
236
+ status: 405,
237
+ statusText: 'Method Not Allowed',
238
+ headers: {
239
+ allow: 'GET, POST',
240
+ },
241
+ },
242
+ ];
243
+ }
244
+ const [mediaType, charset = 'charset=utf-8', // utf-8 is assumed when not specified. this parameter is either "charset" or "boundary" (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length)
245
+ ] = (getHeader(req, 'content-type') || '')
300
246
  .replace(/\s/g, '')
301
247
  .toLowerCase()
302
- .split(',');
303
- for (const accept of accepts) {
304
- // accept-charset became obsolete, shouldnt be used (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset)
305
- // TODO: handle the weight parameter "q"
306
- const [mediaType, ...params] = accept.split(';');
307
- const charset = (params === null || params === void 0 ? void 0 : params.find((param) => param.includes('charset='))) || 'charset=utf8'; // utf-8 is assumed when not specified;
308
- if (mediaType === 'application/graphql-response+json' &&
309
- charset === 'charset=utf8') {
310
- acceptedMediaType = 'application/graphql-response+json';
311
- break;
312
- }
313
- if ((mediaType === 'application/json' ||
314
- mediaType === 'application/*' ||
315
- mediaType === '*/*') &&
316
- charset === 'charset=utf8') {
317
- acceptedMediaType = 'application/json';
248
+ .split(';');
249
+ const partParams = {};
250
+ switch (true) {
251
+ case method === 'GET': {
252
+ // TODO: what if content-type is specified and is not application/x-www-form-urlencoded?
253
+ try {
254
+ const [, search] = req.url.split('?');
255
+ const searchParams = new URLSearchParams(search);
256
+ partParams.operationName =
257
+ (_a = searchParams.get('operationName')) !== null && _a !== void 0 ? _a : undefined;
258
+ partParams.query = (_b = searchParams.get('query')) !== null && _b !== void 0 ? _b : undefined;
259
+ const variables = searchParams.get('variables');
260
+ if (variables)
261
+ partParams.variables = JSON.parse(variables);
262
+ const extensions = searchParams.get('extensions');
263
+ if (extensions)
264
+ partParams.extensions = JSON.parse(extensions);
265
+ }
266
+ catch (_c) {
267
+ throw new Error('Unparsable URL');
268
+ }
318
269
  break;
319
270
  }
271
+ case method === 'POST' &&
272
+ mediaType === 'application/json' &&
273
+ charset === 'charset=utf-8':
274
+ {
275
+ if (!req.body) {
276
+ throw new Error('Missing body');
277
+ }
278
+ let data;
279
+ try {
280
+ const body = typeof req.body === 'function' ? await req.body() : req.body;
281
+ data = typeof body === 'string' ? JSON.parse(body) : body;
282
+ }
283
+ catch (err) {
284
+ throw new Error('Unparsable JSON body');
285
+ }
286
+ if (!isObject(data)) {
287
+ throw new Error('JSON body must be an object');
288
+ }
289
+ partParams.operationName = data.operationName;
290
+ partParams.query = data.query;
291
+ partParams.variables = data.variables;
292
+ partParams.extensions = data.extensions;
293
+ break;
294
+ }
295
+ default: // graphql-http doesnt support any other content type
296
+ return [
297
+ null,
298
+ {
299
+ status: 415,
300
+ statusText: 'Unsupported Media Type',
301
+ },
302
+ ];
303
+ }
304
+ if (partParams.query == null)
305
+ throw new Error('Missing query');
306
+ if (typeof partParams.query !== 'string')
307
+ throw new Error('Invalid query');
308
+ if (partParams.variables != null &&
309
+ (typeof partParams.variables !== 'object' ||
310
+ Array.isArray(partParams.variables))) {
311
+ throw new Error('Invalid variables');
312
+ }
313
+ if (partParams.operationName != null &&
314
+ typeof partParams.operationName !== 'string') {
315
+ throw new Error('Invalid operationName');
320
316
  }
321
- return acceptedMediaType;
317
+ if (partParams.extensions != null &&
318
+ (typeof partParams.extensions !== 'object' ||
319
+ Array.isArray(partParams.extensions))) {
320
+ throw new Error('Invalid extensions');
321
+ }
322
+ // request parameters are checked and now complete
323
+ return partParams;
322
324
  }
323
325
  /**
324
326
  * Creates an appropriate GraphQL over HTTP response following the provided arguments.
@@ -330,10 +332,8 @@ export function getAcceptableMediaType(acceptHeader) {
330
332
  *
331
333
  * If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the
332
334
  * error will be present in the `ExecutionResult` style.
333
- *
334
- * @category Server
335
335
  */
336
- export function makeResponse(resultOrErrors, acceptedMediaType, formatError) {
336
+ function makeResponse(resultOrErrors, acceptedMediaType, formatError) {
337
337
  if (resultOrErrors instanceof Error &&
338
338
  // because GraphQLError extends the Error class
339
339
  !isGraphQLError(resultOrErrors)) {
package/lib/utils.js CHANGED
@@ -48,7 +48,9 @@ function isAsyncIterable(val) {
48
48
  }
49
49
  exports.isAsyncIterable = isAsyncIterable;
50
50
  /** @private */
51
- function jsonErrorReplacer(_key, val) {
51
+ function jsonErrorReplacer(_key,
52
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
+ val) {
52
54
  if (val instanceof Error &&
53
55
  // GraphQL errors implement their own stringer
54
56
  !isGraphQLError(val)) {
package/lib/utils.mjs CHANGED
@@ -39,7 +39,9 @@ export function isAsyncIterable(val) {
39
39
  return typeof Object(val)[Symbol.asyncIterator] === 'function';
40
40
  }
41
41
  /** @private */
42
- export function jsonErrorReplacer(_key, val) {
42
+ export function jsonErrorReplacer(_key,
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ val) {
43
45
  if (val instanceof Error &&
44
46
  // GraphQL errors implement their own stringer
45
47
  !isGraphQLError(val)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-http",
3
- "version": "1.19.0",
3
+ "version": "1.20.0",
4
4
  "description": "Simple, pluggable, zero-dependency, GraphQL over HTTP spec compliant server, client and audit suite.",
5
5
  "keywords": [
6
6
  "graphql",
@@ -24,7 +24,7 @@
24
24
  "engines": {
25
25
  "node": ">=12"
26
26
  },
27
- "packageManager": "yarn@3.6.0",
27
+ "packageManager": "yarn@3.6.1",
28
28
  "main": "lib/index.js",
29
29
  "module": "lib/index.mjs",
30
30
  "browser": "umd/graphql-http.js",
@@ -91,18 +91,18 @@
91
91
  "access": "public"
92
92
  },
93
93
  "scripts": {
94
- "gendocs": "typedoc --options typedoc.js src/",
95
- "lint:eslint": "eslint 'src'",
96
- "lint:prettier": "prettier --check .",
97
- "lint:fix": "yarn lint:eslint --fix && yarn lint:prettier --write",
98
- "lint": "yarn lint:eslint && yarn lint:prettier",
99
- "type-check": "tsc --noEmit",
94
+ "check:format": "prettier --check .",
95
+ "format": "yarn check:format --write",
96
+ "check:lint": "eslint 'src'",
97
+ "check:spell": "cspell --gitignore **/*.md",
98
+ "check:type": "tsc --noEmit",
100
99
  "test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest",
101
- "build:esm": "tsc -b tsconfig.esm.json && node scripts/esm-post-process.mjs",
100
+ "build:esm": "tsc -b tsconfig.esm.json && tsx scripts/esm-post-process.ts",
102
101
  "build:cjs": "tsc -b tsconfig.cjs.json",
103
102
  "build:umd": "rollup --configPlugin typescript --config rollup.config.ts",
104
103
  "build": "yarn build:esm && yarn build:cjs && yarn build:umd",
105
- "release": "semantic-release"
104
+ "release": "semantic-release",
105
+ "gendocs": "typedoc --options typedoc.js src/"
106
106
  },
107
107
  "workspaces": [
108
108
  "implementations/**/*"
@@ -111,49 +111,52 @@
111
111
  "graphql": ">=0.11 <=16"
112
112
  },
113
113
  "devDependencies": {
114
- "@babel/core": "^7.22.1",
114
+ "@babel/core": "^7.22.8",
115
115
  "@babel/plugin-proposal-class-properties": "^7.18.6",
116
116
  "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
117
117
  "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
118
118
  "@babel/plugin-proposal-optional-chaining": "^7.21.0",
119
- "@babel/preset-env": "^7.22.4",
120
- "@babel/preset-typescript": "^7.21.5",
119
+ "@babel/preset-env": "^7.22.7",
120
+ "@babel/preset-typescript": "^7.22.5",
121
+ "@cspell/cspell-types": "^6.31.1",
121
122
  "@rollup/plugin-terser": "^0.4.3",
122
- "@rollup/plugin-typescript": "^11.1.1",
123
+ "@rollup/plugin-typescript": "^11.1.2",
123
124
  "@semantic-release/changelog": "^6.0.3",
124
125
  "@semantic-release/git": "^10.0.1",
125
- "@types/eslint": "^8.40.0",
126
+ "@types/eslint": "^8.44.0",
126
127
  "@types/express": "^4.17.17",
127
128
  "@types/glob": "^8.1.0",
128
129
  "@types/html-validator": "^5.0.3",
129
130
  "@types/jest": "^29.5.2",
130
- "@types/k6": "^0.44.2",
131
+ "@types/k6": "^0.45.0",
131
132
  "@types/koa": "^2.13.6",
132
133
  "@types/koa-mount": "^4.0.2",
133
- "@typescript-eslint/eslint-plugin": "^5.59.8",
134
- "@typescript-eslint/parser": "^5.59.8",
135
- "@whatwg-node/fetch": "^0.9.2",
136
- "babel-jest": "^29.5.0",
137
- "eslint": "^8.42.0",
134
+ "@typescript-eslint/eslint-plugin": "^5.61.0",
135
+ "@typescript-eslint/parser": "^5.61.0",
136
+ "@whatwg-node/fetch": "^0.9.7",
137
+ "babel-jest": "^29.6.1",
138
+ "cspell": "^6.31.1",
139
+ "eslint": "^8.44.0",
138
140
  "eslint-config-prettier": "^8.8.0",
139
141
  "express": "^4.18.2",
140
- "fastify": "^4.17.0",
141
- "glob": "^10.2.6",
142
- "graphql": "^16.6.0",
142
+ "fastify": "^4.19.2",
143
+ "glob": "^10.3.2",
144
+ "graphql": "^16.7.1",
143
145
  "html-validator": "^6.0.1",
144
- "jest": "^29.5.0",
145
- "jest-jasmine2": "^29.5.0",
146
+ "jest": "^29.6.1",
147
+ "jest-jasmine2": "^29.6.1",
146
148
  "koa": "^2.14.2",
147
149
  "koa-mount": "^4.0.0",
148
150
  "node-fetch": "^3.3.1",
149
151
  "prettier": "^2.8.8",
150
- "rollup": "^3.23.1",
152
+ "rollup": "^3.26.2",
151
153
  "rollup-plugin-gzip": "^3.1.0",
152
- "semantic-release": "^21.0.3",
153
- "tslib": "^2.5.3",
154
+ "semantic-release": "^21.0.7",
155
+ "tslib": "^2.6.0",
156
+ "tsx": "^3.12.7",
154
157
  "typedoc": "^0.24.8",
155
158
  "typedoc-plugin-markdown": "^3.15.3",
156
- "typescript": "^5.1.3",
159
+ "typescript": "^5.1.6",
157
160
  "uWebSockets.js": "uNetworking/uWebSockets.js#v20.30.0"
158
161
  }
159
162
  }