graphql-http 1.17.1 → 1.18.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 +1 -0
- package/lib/audits/common.d.mts +1 -1
- package/lib/audits/common.d.ts +1 -1
- package/lib/audits/render.js +15 -0
- package/lib/audits/render.mjs +15 -0
- package/lib/audits/server.js +42 -172
- package/lib/audits/server.mjs +42 -172
- package/lib/audits/utils.js +6 -3
- package/lib/audits/utils.mjs +6 -3
- package/lib/handler.d.mts +20 -3
- package/lib/handler.d.ts +20 -3
- package/lib/handler.js +36 -14
- package/lib/handler.mjs +37 -15
- package/lib/utils.d.mts +2 -0
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +15 -1
- package/lib/utils.mjs +13 -0
- package/package.json +12 -11
- package/umd/graphql-http-audits.js +63 -175
- package/umd/graphql-http-audits.min.js +1 -1
- package/umd/graphql-http-audits.min.js.gz +0 -0
package/lib/handler.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
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 { areGraphQLErrors, isAsyncIterable, isExecutionResult, isGraphQLError, isObject, } from './utils.mjs';
|
|
7
|
+
import { areGraphQLErrors, isAsyncIterable, isExecutionResult, isGraphQLError, isObject, jsonErrorReplacer, } from './utils.mjs';
|
|
8
8
|
/**
|
|
9
9
|
* Checks whether the passed value is the `graphql-http` server agnostic response.
|
|
10
10
|
*
|
|
@@ -72,7 +72,7 @@ export function isResponse(val) {
|
|
|
72
72
|
* @category Server
|
|
73
73
|
*/
|
|
74
74
|
export function createHandler(options) {
|
|
75
|
-
const { schema, context, validate = graphqlValidate, validationRules = [], execute = graphqlExecute, parse = graphqlParse, getOperationAST = graphqlGetOperationAST, rootValue, onSubscribe, onOperation, } = options;
|
|
75
|
+
const { schema, context, validate = graphqlValidate, validationRules = [], execute = graphqlExecute, parse = graphqlParse, getOperationAST = graphqlGetOperationAST, rootValue, onSubscribe, onOperation, formatError = (err) => err, } = options;
|
|
76
76
|
return async function handler(req) {
|
|
77
77
|
var _a, _b;
|
|
78
78
|
const method = req.method;
|
|
@@ -173,6 +173,10 @@ export function createHandler(options) {
|
|
|
173
173
|
Array.isArray(partParams.variables))) {
|
|
174
174
|
throw new Error('Invalid variables');
|
|
175
175
|
}
|
|
176
|
+
if (partParams.operationName != null &&
|
|
177
|
+
typeof partParams.operationName !== 'string') {
|
|
178
|
+
throw new Error('Invalid operationName');
|
|
179
|
+
}
|
|
176
180
|
if (partParams.extensions != null &&
|
|
177
181
|
(typeof partParams.extensions !== 'object' ||
|
|
178
182
|
Array.isArray(partParams.extensions))) {
|
|
@@ -182,7 +186,7 @@ export function createHandler(options) {
|
|
|
182
186
|
params = partParams;
|
|
183
187
|
}
|
|
184
188
|
catch (err) {
|
|
185
|
-
return makeResponse(
|
|
189
|
+
return makeResponse(err, acceptedMediaType, formatError);
|
|
186
190
|
}
|
|
187
191
|
let args;
|
|
188
192
|
const maybeResErrsOrArgs = await (onSubscribe === null || onSubscribe === void 0 ? void 0 : onSubscribe(req, params));
|
|
@@ -190,7 +194,7 @@ export function createHandler(options) {
|
|
|
190
194
|
return maybeResErrsOrArgs;
|
|
191
195
|
else if (isExecutionResult(maybeResErrsOrArgs) ||
|
|
192
196
|
areGraphQLErrors(maybeResErrsOrArgs))
|
|
193
|
-
return makeResponse(maybeResErrsOrArgs, acceptedMediaType);
|
|
197
|
+
return makeResponse(maybeResErrsOrArgs, acceptedMediaType, formatError);
|
|
194
198
|
else if (maybeResErrsOrArgs)
|
|
195
199
|
args = maybeResErrsOrArgs;
|
|
196
200
|
else {
|
|
@@ -202,7 +206,7 @@ export function createHandler(options) {
|
|
|
202
206
|
document = parse(query);
|
|
203
207
|
}
|
|
204
208
|
catch (err) {
|
|
205
|
-
return makeResponse(err, acceptedMediaType);
|
|
209
|
+
return makeResponse(err, acceptedMediaType, formatError);
|
|
206
210
|
}
|
|
207
211
|
const resOrContext = typeof context === 'function' ? await context(req, params) : context;
|
|
208
212
|
if (isResponse(resOrContext))
|
|
@@ -231,7 +235,7 @@ export function createHandler(options) {
|
|
|
231
235
|
}
|
|
232
236
|
const validationErrs = validate(args.schema, args.document, rules);
|
|
233
237
|
if (validationErrs.length) {
|
|
234
|
-
return makeResponse(validationErrs, acceptedMediaType);
|
|
238
|
+
return makeResponse(validationErrs, acceptedMediaType, formatError);
|
|
235
239
|
}
|
|
236
240
|
}
|
|
237
241
|
let operation;
|
|
@@ -242,10 +246,10 @@ export function createHandler(options) {
|
|
|
242
246
|
operation = ast.operation;
|
|
243
247
|
}
|
|
244
248
|
catch (_d) {
|
|
245
|
-
return makeResponse(new GraphQLError('Unable to detect operation AST'), acceptedMediaType);
|
|
249
|
+
return makeResponse(new GraphQLError('Unable to detect operation AST'), acceptedMediaType, formatError);
|
|
246
250
|
}
|
|
247
251
|
if (operation === 'subscription') {
|
|
248
|
-
return makeResponse(new GraphQLError('Subscriptions are not supported'), acceptedMediaType);
|
|
252
|
+
return makeResponse(new GraphQLError('Subscriptions are not supported'), acceptedMediaType, formatError);
|
|
249
253
|
}
|
|
250
254
|
// mutations cannot happen over GETs
|
|
251
255
|
// https://graphql.github.io/graphql-over-http/draft/#sel-CALFJRPAAELBAAxwP
|
|
@@ -279,9 +283,9 @@ export function createHandler(options) {
|
|
|
279
283
|
else if (maybeResponseOrResult)
|
|
280
284
|
result = maybeResponseOrResult;
|
|
281
285
|
if (isAsyncIterable(result)) {
|
|
282
|
-
return makeResponse(new GraphQLError('Subscriptions are not supported'), acceptedMediaType);
|
|
286
|
+
return makeResponse(new GraphQLError('Subscriptions are not supported'), acceptedMediaType, formatError);
|
|
283
287
|
}
|
|
284
|
-
return makeResponse(result, acceptedMediaType);
|
|
288
|
+
return makeResponse(result, acceptedMediaType, formatError);
|
|
285
289
|
};
|
|
286
290
|
}
|
|
287
291
|
/**
|
|
@@ -321,12 +325,29 @@ export function getAcceptableMediaType(acceptHeader) {
|
|
|
321
325
|
*
|
|
322
326
|
* If the first argument is an `ExecutionResult`, the operation will be treated as "successful".
|
|
323
327
|
*
|
|
324
|
-
* If the first argument is
|
|
325
|
-
*
|
|
328
|
+
* If the first argument is (an array of) `GraphQLError`, or an `ExecutionResult` without the `data` field, it will be treated
|
|
329
|
+
* the response will be constructed with the help of `acceptedMediaType` complying with the GraphQL over HTTP spec.
|
|
330
|
+
*
|
|
331
|
+
* If the first argument is an `Error`, the operation will be treated as a bad request responding with `400: Bad Request` and the
|
|
332
|
+
* error will be present in the `ExecutionResult` style.
|
|
326
333
|
*
|
|
327
334
|
* @category Server
|
|
328
335
|
*/
|
|
329
|
-
export function makeResponse(resultOrErrors, acceptedMediaType) {
|
|
336
|
+
export function makeResponse(resultOrErrors, acceptedMediaType, formatError) {
|
|
337
|
+
if (resultOrErrors instanceof Error &&
|
|
338
|
+
// because GraphQLError extends the Error class
|
|
339
|
+
!isGraphQLError(resultOrErrors)) {
|
|
340
|
+
return [
|
|
341
|
+
JSON.stringify({ errors: [formatError(resultOrErrors)] }, jsonErrorReplacer),
|
|
342
|
+
{
|
|
343
|
+
status: 400,
|
|
344
|
+
statusText: 'Bad Request',
|
|
345
|
+
headers: {
|
|
346
|
+
'content-type': 'application/json; charset=utf-8',
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
];
|
|
350
|
+
}
|
|
330
351
|
const errors = isGraphQLError(resultOrErrors)
|
|
331
352
|
? [resultOrErrors]
|
|
332
353
|
: areGraphQLErrors(resultOrErrors)
|
|
@@ -334,7 +355,7 @@ export function makeResponse(resultOrErrors, acceptedMediaType) {
|
|
|
334
355
|
: null;
|
|
335
356
|
if (errors) {
|
|
336
357
|
return [
|
|
337
|
-
JSON.stringify({ errors }),
|
|
358
|
+
JSON.stringify({ errors: errors.map(formatError) }, jsonErrorReplacer),
|
|
338
359
|
Object.assign(Object.assign({}, (acceptedMediaType === 'application/json'
|
|
339
360
|
? {
|
|
340
361
|
status: 200,
|
|
@@ -351,7 +372,8 @@ export function makeResponse(resultOrErrors, acceptedMediaType) {
|
|
|
351
372
|
];
|
|
352
373
|
}
|
|
353
374
|
return [
|
|
354
|
-
JSON.stringify(resultOrErrors
|
|
375
|
+
JSON.stringify('errors' in resultOrErrors && resultOrErrors.errors
|
|
376
|
+
? Object.assign(Object.assign({}, resultOrErrors), { errors: resultOrErrors.errors.map(formatError) }) : resultOrErrors, jsonErrorReplacer),
|
|
355
377
|
{
|
|
356
378
|
status: 200,
|
|
357
379
|
statusText: 'OK',
|
package/lib/utils.d.mts
CHANGED
|
@@ -17,3 +17,5 @@ export declare function isGraphQLError(obj: unknown): obj is GraphQLError;
|
|
|
17
17
|
export declare function isExecutionResult(val: unknown): val is ExecutionResult;
|
|
18
18
|
/** @private */
|
|
19
19
|
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
|
@@ -17,3 +17,5 @@ export declare function isGraphQLError(obj: unknown): obj is GraphQLError;
|
|
|
17
17
|
export declare function isExecutionResult(val: unknown): val is ExecutionResult;
|
|
18
18
|
/** @private */
|
|
19
19
|
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,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.isAsyncIterable = exports.isExecutionResult = exports.isGraphQLError = exports.areGraphQLErrors = exports.isObject = exports.extendedTypeof = void 0;
|
|
8
|
+
exports.jsonErrorReplacer = exports.isAsyncIterable = exports.isExecutionResult = exports.isGraphQLError = exports.areGraphQLErrors = exports.isObject = exports.extendedTypeof = void 0;
|
|
9
9
|
const graphql_1 = require("graphql");
|
|
10
10
|
/** @private */
|
|
11
11
|
function extendedTypeof(val) {
|
|
@@ -47,3 +47,17 @@ function isAsyncIterable(val) {
|
|
|
47
47
|
return typeof Object(val)[Symbol.asyncIterator] === 'function';
|
|
48
48
|
}
|
|
49
49
|
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
|
@@ -38,3 +38,16 @@ export function isExecutionResult(val) {
|
|
|
38
38
|
export function isAsyncIterable(val) {
|
|
39
39
|
return typeof Object(val)[Symbol.asyncIterator] === 'function';
|
|
40
40
|
}
|
|
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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphql-http",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Simple, pluggable, zero-dependency, GraphQL over HTTP spec compliant server, client and audit suite.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphql",
|
|
@@ -113,8 +113,8 @@
|
|
|
113
113
|
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
|
|
114
114
|
"@babel/preset-env": "^7.21.4",
|
|
115
115
|
"@babel/preset-typescript": "^7.21.4",
|
|
116
|
-
"@rollup/plugin-terser": "^0.4.
|
|
117
|
-
"@rollup/plugin-typescript": "^11.
|
|
116
|
+
"@rollup/plugin-terser": "^0.4.1",
|
|
117
|
+
"@rollup/plugin-typescript": "^11.1.0",
|
|
118
118
|
"@semantic-release/changelog": "^6.0.3",
|
|
119
119
|
"@semantic-release/git": "^10.0.1",
|
|
120
120
|
"@types/eslint": "^8.37.0",
|
|
@@ -124,29 +124,30 @@
|
|
|
124
124
|
"@types/jest": "^29.5.0",
|
|
125
125
|
"@types/koa": "^2.13.6",
|
|
126
126
|
"@types/koa-mount": "^4.0.2",
|
|
127
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
128
|
-
"@typescript-eslint/parser": "^5.
|
|
127
|
+
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
|
128
|
+
"@typescript-eslint/parser": "^5.58.0",
|
|
129
129
|
"@whatwg-node/fetch": "^0.8.4",
|
|
130
130
|
"babel-jest": "^29.5.0",
|
|
131
|
-
"eslint": "^8.
|
|
131
|
+
"eslint": "^8.38.0",
|
|
132
132
|
"eslint-config-prettier": "^8.8.0",
|
|
133
133
|
"express": "^4.18.2",
|
|
134
134
|
"fastify": "^4.15.0",
|
|
135
|
+
"glob": "^10.0.0",
|
|
135
136
|
"graphql": "^16.6.0",
|
|
136
137
|
"html-validator": "^6.0.1",
|
|
137
138
|
"jest": "^29.5.0",
|
|
138
139
|
"jest-jasmine2": "^29.5.0",
|
|
139
|
-
"koa": "^2.14.
|
|
140
|
+
"koa": "^2.14.2",
|
|
140
141
|
"koa-mount": "^4.0.0",
|
|
141
142
|
"node-fetch": "^3.3.1",
|
|
142
143
|
"prettier": "^2.8.7",
|
|
143
144
|
"rollup": "^3.20.2",
|
|
144
145
|
"rollup-plugin-gzip": "^3.1.0",
|
|
145
|
-
"semantic-release": "^21.0.
|
|
146
|
+
"semantic-release": "^21.0.1",
|
|
146
147
|
"tslib": "^2.5.0",
|
|
147
|
-
"typedoc": "^0.
|
|
148
|
-
"typedoc-plugin-markdown": "^3.
|
|
149
|
-
"typescript": "^5.0.
|
|
148
|
+
"typedoc": "^0.24.1",
|
|
149
|
+
"typedoc-plugin-markdown": "^3.15.1",
|
|
150
|
+
"typescript": "^5.0.4"
|
|
150
151
|
},
|
|
151
152
|
"resolutions": {
|
|
152
153
|
"npm/libnpmversion": "^3.0.6"
|