graphql-http 1.19.0 → 1.21.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 +86 -4
- package/lib/client.d.mts +2 -2
- package/lib/client.d.ts +2 -2
- package/lib/common.d.mts +4 -4
- package/lib/common.d.ts +4 -4
- package/lib/handler.d.mts +30 -38
- package/lib/handler.d.ts +30 -38
- package/lib/handler.js +160 -140
- package/lib/handler.mjs +155 -132
- package/lib/use/@netlify/functions.d.mts +14 -0
- package/lib/use/@netlify/functions.d.ts +14 -0
- package/lib/use/@netlify/functions.js +37 -0
- package/lib/use/@netlify/functions.mjs +33 -0
- package/lib/utils.d.mts +0 -7
- package/lib/utils.d.ts +0 -7
- package/lib/utils.js +1 -29
- package/lib/utils.mjs +0 -25
- package/package.json +36 -37
- package/umd/graphql-http-audits.js +2 -2
- package/umd/graphql-http-audits.min.js +1 -1
- package/umd/graphql-http-audits.min.js.gz +0 -0
- package/umd/graphql-http.js +3 -2
- package/umd/graphql-http.min.js +1 -1
- package/umd/graphql-http.min.js.gz +0 -0
package/lib/handler.mjs
CHANGED
|
@@ -4,13 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
import { validate as graphqlValidate, specifiedRules, execute as graphqlExecute, parse as graphqlParse, getOperationAST as graphqlGetOperationAST, GraphQLError, } from 'graphql';
|
|
7
|
-
import {
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
* @category Server
|
|
12
|
-
*/
|
|
13
|
-
export function isResponse(val) {
|
|
7
|
+
import { isAsyncIterable, isExecutionResult, isObject } from './utils.mjs';
|
|
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
|
|
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
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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 (
|
|
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
|
-
*
|
|
293
|
-
*
|
|
222
|
+
* The default request params parser. Used when no custom one is provided or if it
|
|
223
|
+
* returns nothing.
|
|
294
224
|
*
|
|
295
|
-
* @
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
const
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
336
|
+
function makeResponse(resultOrErrors, acceptedMediaType, formatError) {
|
|
337
337
|
if (resultOrErrors instanceof Error &&
|
|
338
338
|
// because GraphQLError extends the Error class
|
|
339
339
|
!isGraphQLError(resultOrErrors)) {
|
|
@@ -391,3 +391,26 @@ function getHeader(req, key) {
|
|
|
391
391
|
}
|
|
392
392
|
return Object(req.headers)[key];
|
|
393
393
|
}
|
|
394
|
+
function areGraphQLErrors(obj) {
|
|
395
|
+
return (Array.isArray(obj) &&
|
|
396
|
+
obj.length > 0 &&
|
|
397
|
+
// if one item in the array is a GraphQLError, we're good
|
|
398
|
+
obj.some(isGraphQLError));
|
|
399
|
+
}
|
|
400
|
+
function isGraphQLError(obj) {
|
|
401
|
+
return obj instanceof GraphQLError;
|
|
402
|
+
}
|
|
403
|
+
function jsonErrorReplacer(_key,
|
|
404
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
405
|
+
val) {
|
|
406
|
+
if (val instanceof Error &&
|
|
407
|
+
// GraphQL errors implement their own stringer
|
|
408
|
+
!isGraphQLError(val)) {
|
|
409
|
+
return {
|
|
410
|
+
// name: val.name, name is included in message
|
|
411
|
+
message: val.message,
|
|
412
|
+
// stack: val.stack, can leak sensitive details
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
return val;
|
|
416
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HandlerOptions as RawHandlerOptions, OperationContext } from '../../handler.mjs';
|
|
2
|
+
import type { Handler as NetlifyHandler, HandlerEvent as NetlifyHandlerEvent, HandlerContext as NetlifyHandlerContext } from '@netlify/functions';
|
|
3
|
+
/**
|
|
4
|
+
* Handler options when using the netlify adapter
|
|
5
|
+
*
|
|
6
|
+
* @category Server/@netlify/functions
|
|
7
|
+
*/
|
|
8
|
+
export type HandlerOptions<Context extends OperationContext = undefined> = RawHandlerOptions<NetlifyHandlerEvent, NetlifyHandlerContext, Context>;
|
|
9
|
+
/**
|
|
10
|
+
* Create a GraphQL over HTTP spec compliant request handler for netlify functions
|
|
11
|
+
*
|
|
12
|
+
* @category Server/@netlify/functions
|
|
13
|
+
*/
|
|
14
|
+
export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<Context>): NetlifyHandler;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { HandlerOptions as RawHandlerOptions, OperationContext } from '../../handler';
|
|
2
|
+
import type { Handler as NetlifyHandler, HandlerEvent as NetlifyHandlerEvent, HandlerContext as NetlifyHandlerContext } from '@netlify/functions';
|
|
3
|
+
/**
|
|
4
|
+
* Handler options when using the netlify adapter
|
|
5
|
+
*
|
|
6
|
+
* @category Server/@netlify/functions
|
|
7
|
+
*/
|
|
8
|
+
export type HandlerOptions<Context extends OperationContext = undefined> = RawHandlerOptions<NetlifyHandlerEvent, NetlifyHandlerContext, Context>;
|
|
9
|
+
/**
|
|
10
|
+
* Create a GraphQL over HTTP spec compliant request handler for netlify functions
|
|
11
|
+
*
|
|
12
|
+
* @category Server/@netlify/functions
|
|
13
|
+
*/
|
|
14
|
+
export declare function createHandler<Context extends OperationContext = undefined>(options: HandlerOptions<Context>): NetlifyHandler;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createHandler = void 0;
|
|
4
|
+
const handler_1 = require("../../handler");
|
|
5
|
+
/**
|
|
6
|
+
* Create a GraphQL over HTTP spec compliant request handler for netlify functions
|
|
7
|
+
*
|
|
8
|
+
* @category Server/@netlify/functions
|
|
9
|
+
*/
|
|
10
|
+
function createHandler(options) {
|
|
11
|
+
const handler = (0, handler_1.createHandler)(options);
|
|
12
|
+
return async function handleRequest(req, ctx) {
|
|
13
|
+
try {
|
|
14
|
+
const [body, init] = await handler({
|
|
15
|
+
method: req.httpMethod,
|
|
16
|
+
url: req.rawUrl,
|
|
17
|
+
headers: req.headers,
|
|
18
|
+
body: req.body,
|
|
19
|
+
raw: req,
|
|
20
|
+
context: ctx,
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
// if body is null, return undefined
|
|
24
|
+
body: body !== null && body !== void 0 ? body : undefined,
|
|
25
|
+
statusCode: init.status,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
// The handler shouldnt throw errors.
|
|
30
|
+
// If you wish to handle them differently, consider implementing your own request handler.
|
|
31
|
+
console.error('Internal error occurred during request handling. ' +
|
|
32
|
+
'Please check your implementation.', err);
|
|
33
|
+
return { statusCode: 500 };
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
exports.createHandler = createHandler;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHandler as createRawHandler, } from '../../handler.mjs';
|
|
2
|
+
/**
|
|
3
|
+
* Create a GraphQL over HTTP spec compliant request handler for netlify functions
|
|
4
|
+
*
|
|
5
|
+
* @category Server/@netlify/functions
|
|
6
|
+
*/
|
|
7
|
+
export function createHandler(options) {
|
|
8
|
+
const handler = createRawHandler(options);
|
|
9
|
+
return async function handleRequest(req, ctx) {
|
|
10
|
+
try {
|
|
11
|
+
const [body, init] = await handler({
|
|
12
|
+
method: req.httpMethod,
|
|
13
|
+
url: req.rawUrl,
|
|
14
|
+
headers: req.headers,
|
|
15
|
+
body: req.body,
|
|
16
|
+
raw: req,
|
|
17
|
+
context: ctx,
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
// if body is null, return undefined
|
|
21
|
+
body: body !== null && body !== void 0 ? body : undefined,
|
|
22
|
+
statusCode: init.status,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
// The handler shouldnt throw errors.
|
|
27
|
+
// If you wish to handle them differently, consider implementing your own request handler.
|
|
28
|
+
console.error('Internal error occurred during request handling. ' +
|
|
29
|
+
'Please check your implementation.', err);
|
|
30
|
+
return { statusCode: 500 };
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
package/lib/utils.d.mts
CHANGED
|
@@ -4,18 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
import type { ExecutionResult } from 'graphql';
|
|
7
|
-
import { GraphQLError } from 'graphql';
|
|
8
7
|
/** @private */
|
|
9
8
|
export declare function extendedTypeof(val: unknown): 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'array' | 'null';
|
|
10
9
|
/** @private */
|
|
11
10
|
export declare function isObject(val: unknown): val is Record<PropertyKey, any>;
|
|
12
11
|
/** @private */
|
|
13
|
-
export declare function areGraphQLErrors(obj: unknown): obj is readonly GraphQLError[];
|
|
14
|
-
/** @private */
|
|
15
|
-
export declare function isGraphQLError(obj: unknown): obj is GraphQLError;
|
|
16
|
-
/** @private */
|
|
17
12
|
export declare function isExecutionResult(val: unknown): val is ExecutionResult;
|
|
18
13
|
/** @private */
|
|
19
14
|
export declare function isAsyncIterable<T = unknown>(val: unknown): val is AsyncIterable<T>;
|
|
20
|
-
/** @private */
|
|
21
|
-
export declare function jsonErrorReplacer(_key: string, val: any): any;
|
package/lib/utils.d.ts
CHANGED
|
@@ -4,18 +4,11 @@
|
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
import type { ExecutionResult } from 'graphql';
|
|
7
|
-
import { GraphQLError } from 'graphql';
|
|
8
7
|
/** @private */
|
|
9
8
|
export declare function extendedTypeof(val: unknown): 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | 'array' | 'null';
|
|
10
9
|
/** @private */
|
|
11
10
|
export declare function isObject(val: unknown): val is Record<PropertyKey, any>;
|
|
12
11
|
/** @private */
|
|
13
|
-
export declare function areGraphQLErrors(obj: unknown): obj is readonly GraphQLError[];
|
|
14
|
-
/** @private */
|
|
15
|
-
export declare function isGraphQLError(obj: unknown): obj is GraphQLError;
|
|
16
|
-
/** @private */
|
|
17
12
|
export declare function isExecutionResult(val: unknown): val is ExecutionResult;
|
|
18
13
|
/** @private */
|
|
19
14
|
export declare function isAsyncIterable<T = unknown>(val: unknown): val is AsyncIterable<T>;
|
|
20
|
-
/** @private */
|
|
21
|
-
export declare function jsonErrorReplacer(_key: string, val: any): any;
|
package/lib/utils.js
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.
|
|
9
|
-
const graphql_1 = require("graphql");
|
|
8
|
+
exports.isAsyncIterable = exports.isExecutionResult = exports.isObject = exports.extendedTypeof = void 0;
|
|
10
9
|
/** @private */
|
|
11
10
|
function extendedTypeof(val) {
|
|
12
11
|
if (val === null) {
|
|
@@ -24,19 +23,6 @@ function isObject(val) {
|
|
|
24
23
|
}
|
|
25
24
|
exports.isObject = isObject;
|
|
26
25
|
/** @private */
|
|
27
|
-
function areGraphQLErrors(obj) {
|
|
28
|
-
return (Array.isArray(obj) &&
|
|
29
|
-
obj.length > 0 &&
|
|
30
|
-
// if one item in the array is a GraphQLError, we're good
|
|
31
|
-
obj.some(isGraphQLError));
|
|
32
|
-
}
|
|
33
|
-
exports.areGraphQLErrors = areGraphQLErrors;
|
|
34
|
-
/** @private */
|
|
35
|
-
function isGraphQLError(obj) {
|
|
36
|
-
return obj instanceof graphql_1.GraphQLError;
|
|
37
|
-
}
|
|
38
|
-
exports.isGraphQLError = isGraphQLError;
|
|
39
|
-
/** @private */
|
|
40
26
|
function isExecutionResult(val) {
|
|
41
27
|
return (isObject(val) &&
|
|
42
28
|
('data' in val || ('data' in val && val.data == null && 'errors' in val)));
|
|
@@ -47,17 +33,3 @@ function isAsyncIterable(val) {
|
|
|
47
33
|
return typeof Object(val)[Symbol.asyncIterator] === 'function';
|
|
48
34
|
}
|
|
49
35
|
exports.isAsyncIterable = isAsyncIterable;
|
|
50
|
-
/** @private */
|
|
51
|
-
function jsonErrorReplacer(_key, val) {
|
|
52
|
-
if (val instanceof Error &&
|
|
53
|
-
// GraphQL errors implement their own stringer
|
|
54
|
-
!isGraphQLError(val)) {
|
|
55
|
-
return {
|
|
56
|
-
// name: val.name, name is included in message
|
|
57
|
-
message: val.message,
|
|
58
|
-
// stack: val.stack, can leak sensitive details
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
return val;
|
|
62
|
-
}
|
|
63
|
-
exports.jsonErrorReplacer = jsonErrorReplacer;
|
package/lib/utils.mjs
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* utils
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
|
-
import { GraphQLError } from 'graphql';
|
|
7
6
|
/** @private */
|
|
8
7
|
export function extendedTypeof(val) {
|
|
9
8
|
if (val === null) {
|
|
@@ -19,17 +18,6 @@ export function isObject(val) {
|
|
|
19
18
|
return typeof val === 'object' && val !== null;
|
|
20
19
|
}
|
|
21
20
|
/** @private */
|
|
22
|
-
export function areGraphQLErrors(obj) {
|
|
23
|
-
return (Array.isArray(obj) &&
|
|
24
|
-
obj.length > 0 &&
|
|
25
|
-
// if one item in the array is a GraphQLError, we're good
|
|
26
|
-
obj.some(isGraphQLError));
|
|
27
|
-
}
|
|
28
|
-
/** @private */
|
|
29
|
-
export function isGraphQLError(obj) {
|
|
30
|
-
return obj instanceof GraphQLError;
|
|
31
|
-
}
|
|
32
|
-
/** @private */
|
|
33
21
|
export function isExecutionResult(val) {
|
|
34
22
|
return (isObject(val) &&
|
|
35
23
|
('data' in val || ('data' in val && val.data == null && 'errors' in val)));
|
|
@@ -38,16 +26,3 @@ export function isExecutionResult(val) {
|
|
|
38
26
|
export function isAsyncIterable(val) {
|
|
39
27
|
return typeof Object(val)[Symbol.asyncIterator] === 'function';
|
|
40
28
|
}
|
|
41
|
-
/** @private */
|
|
42
|
-
export function jsonErrorReplacer(_key, val) {
|
|
43
|
-
if (val instanceof Error &&
|
|
44
|
-
// GraphQL errors implement their own stringer
|
|
45
|
-
!isGraphQLError(val)) {
|
|
46
|
-
return {
|
|
47
|
-
// name: val.name, name is included in message
|
|
48
|
-
message: val.message,
|
|
49
|
-
// stack: val.stack, can leak sensitive details
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
return val;
|
|
53
|
-
}
|