graphql-http 1.15.0 → 1.17.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 +38 -11
- package/lib/audits/utils.js +6 -3
- package/lib/audits/utils.mjs +6 -3
- package/lib/handler.d.mts +3 -3
- package/lib/handler.d.ts +3 -3
- package/lib/handler.js +3 -3
- package/lib/handler.mjs +3 -3
- package/lib/use/express.d.mts +18 -4
- package/lib/use/express.d.ts +18 -4
- package/lib/use/express.js +2 -2
- package/lib/use/express.mjs +2 -2
- package/lib/use/fastify.d.mts +18 -4
- package/lib/use/fastify.d.ts +18 -4
- package/lib/use/fastify.js +2 -2
- package/lib/use/fastify.mjs +2 -2
- package/lib/use/fetch.d.mts +10 -4
- package/lib/use/fetch.d.ts +10 -4
- package/lib/use/fetch.js +6 -6
- package/lib/use/fetch.mjs +6 -6
- package/lib/use/http.d.mts +35 -0
- package/lib/use/http.d.ts +35 -0
- package/lib/use/http.js +72 -0
- package/lib/use/http.mjs +68 -0
- package/lib/use/http2.d.mts +47 -0
- package/lib/use/http2.d.ts +47 -0
- package/lib/use/http2.js +90 -0
- package/lib/use/http2.mjs +86 -0
- package/lib/use/koa.d.mts +18 -4
- package/lib/use/koa.d.ts +18 -4
- package/lib/use/koa.js +2 -2
- package/lib/use/koa.mjs +2 -2
- package/lib/use/node.d.mts +14 -4
- package/lib/use/node.d.ts +14 -4
- package/lib/use/node.js +5 -50
- package/lib/use/node.mjs +5 -50
- package/package.json +38 -27
- package/umd/graphql-http-audits.js +6 -3
- package/umd/graphql-http-audits.min.js +1 -1
- package/umd/graphql-http-audits.min.js.gz +0 -0
package/lib/use/node.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createHandler as
|
|
1
|
+
import { createHandler as httpCreateHandler, } from './http.mjs';
|
|
2
2
|
/**
|
|
3
|
-
* Create a GraphQL over HTTP
|
|
3
|
+
* Create a GraphQL over HTTP spec compliant request handler for
|
|
4
4
|
* the Node environment.
|
|
5
5
|
*
|
|
6
6
|
* ```js
|
|
@@ -15,54 +15,9 @@ import { createHandler as createRawHandler, } from '../handler.mjs';
|
|
|
15
15
|
* ```
|
|
16
16
|
*
|
|
17
17
|
* @category Server/node
|
|
18
|
+
*
|
|
19
|
+
* @deprecated Please use {@link use/http.createHandler | http} or {@link use/http2.createHandler | http2} adapters instead.
|
|
18
20
|
*/
|
|
19
21
|
export function createHandler(options) {
|
|
20
|
-
|
|
21
|
-
const handle = createRawHandler(options);
|
|
22
|
-
return async function requestListener(req, res) {
|
|
23
|
-
try {
|
|
24
|
-
if (!req.url) {
|
|
25
|
-
throw new Error('Missing request URL');
|
|
26
|
-
}
|
|
27
|
-
if (!req.method) {
|
|
28
|
-
throw new Error('Missing request method');
|
|
29
|
-
}
|
|
30
|
-
const [body, init] = await handle({
|
|
31
|
-
url: req.url,
|
|
32
|
-
method: req.method,
|
|
33
|
-
headers: req.headers,
|
|
34
|
-
body: () => new Promise((resolve) => {
|
|
35
|
-
let body = '';
|
|
36
|
-
req.on('data', (chunk) => (body += chunk));
|
|
37
|
-
req.on('end', () => resolve(body));
|
|
38
|
-
}),
|
|
39
|
-
raw: req,
|
|
40
|
-
context: undefined,
|
|
41
|
-
});
|
|
42
|
-
res.writeHead(init.status, init.statusText, init.headers).end(body);
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
// The handler shouldnt throw errors.
|
|
46
|
-
// If you wish to handle them differently, consider implementing your own request handler.
|
|
47
|
-
console.error('Internal error occurred during request handling. ' +
|
|
48
|
-
'Please check your implementation.', err);
|
|
49
|
-
if (isProd) {
|
|
50
|
-
res.writeHead(500).end();
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
res
|
|
54
|
-
.writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
|
|
55
|
-
.end(JSON.stringify({
|
|
56
|
-
errors: [
|
|
57
|
-
err instanceof Error
|
|
58
|
-
? {
|
|
59
|
-
message: err.message,
|
|
60
|
-
stack: err.stack,
|
|
61
|
-
}
|
|
62
|
-
: err,
|
|
63
|
-
],
|
|
64
|
-
}));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
};
|
|
22
|
+
return httpCreateHandler(options);
|
|
68
23
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphql-http",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.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.
|
|
27
|
+
"packageManager": "yarn@3.5.0",
|
|
28
28
|
"main": "lib/index.js",
|
|
29
29
|
"module": "lib/index.mjs",
|
|
30
30
|
"browser": "umd/graphql-http.js",
|
|
@@ -45,6 +45,16 @@
|
|
|
45
45
|
"require": "./lib/use/node.js",
|
|
46
46
|
"import": "./lib/use/node.mjs"
|
|
47
47
|
},
|
|
48
|
+
"./lib/use/http": {
|
|
49
|
+
"types": "./lib/use/http.d.ts",
|
|
50
|
+
"require": "./lib/use/http.js",
|
|
51
|
+
"import": "./lib/use/http.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./lib/use/http2": {
|
|
54
|
+
"types": "./lib/use/http2.d.ts",
|
|
55
|
+
"require": "./lib/use/http2.js",
|
|
56
|
+
"import": "./lib/use/http2.mjs"
|
|
57
|
+
},
|
|
48
58
|
"./lib/use/express": {
|
|
49
59
|
"types": "./lib/use/express.d.ts",
|
|
50
60
|
"require": "./lib/use/express.js",
|
|
@@ -78,10 +88,11 @@
|
|
|
78
88
|
"scripts": {
|
|
79
89
|
"gendocs": "typedoc --options typedoc.js src/",
|
|
80
90
|
"lint:eslint": "eslint 'src'",
|
|
81
|
-
"lint:prettier": "prettier
|
|
91
|
+
"lint:prettier": "prettier --check .",
|
|
92
|
+
"lint:fix": "yarn lint:eslint --fix && yarn lint:prettier --write",
|
|
82
93
|
"lint": "yarn lint:eslint && yarn lint:prettier",
|
|
83
94
|
"type-check": "tsc --noEmit",
|
|
84
|
-
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
95
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest",
|
|
85
96
|
"build:esm": "tsc -b tsconfig.esm.json && node scripts/esm-post-process.mjs",
|
|
86
97
|
"build:cjs": "tsc -b tsconfig.cjs.json",
|
|
87
98
|
"build:umd": "rollup --configPlugin typescript --config rollup.config.ts",
|
|
@@ -95,47 +106,47 @@
|
|
|
95
106
|
"graphql": ">=0.11 <=16"
|
|
96
107
|
},
|
|
97
108
|
"devDependencies": {
|
|
98
|
-
"@babel/core": "^7.
|
|
109
|
+
"@babel/core": "^7.21.3",
|
|
99
110
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
100
111
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
|
101
112
|
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
|
|
102
|
-
"@babel/plugin-proposal-optional-chaining": "^7.
|
|
113
|
+
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
|
|
103
114
|
"@babel/preset-env": "^7.20.2",
|
|
104
|
-
"@babel/preset-typescript": "^7.
|
|
115
|
+
"@babel/preset-typescript": "^7.21.0",
|
|
105
116
|
"@rollup/plugin-terser": "^0.4.0",
|
|
106
117
|
"@rollup/plugin-typescript": "^11.0.0",
|
|
107
|
-
"@semantic-release/changelog": "^6.0.
|
|
118
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
108
119
|
"@semantic-release/git": "^10.0.1",
|
|
109
|
-
"@types/eslint": "^8.21.
|
|
120
|
+
"@types/eslint": "^8.21.3",
|
|
110
121
|
"@types/express": "^4.17.17",
|
|
111
|
-
"@types/glob": "^8.0
|
|
122
|
+
"@types/glob": "^8.1.0",
|
|
112
123
|
"@types/html-validator": "^5.0.3",
|
|
113
|
-
"@types/jest": "^29.
|
|
114
|
-
"@types/koa": "^2.13.
|
|
124
|
+
"@types/jest": "^29.5.0",
|
|
125
|
+
"@types/koa": "^2.13.6",
|
|
115
126
|
"@types/koa-mount": "^4.0.2",
|
|
116
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
117
|
-
"@typescript-eslint/parser": "^5.
|
|
118
|
-
"@whatwg-node/fetch": "^0.8.
|
|
119
|
-
"babel-jest": "^29.
|
|
120
|
-
"eslint": "^8.
|
|
121
|
-
"eslint-config-prettier": "^8.
|
|
127
|
+
"@typescript-eslint/eslint-plugin": "^5.57.0",
|
|
128
|
+
"@typescript-eslint/parser": "^5.57.0",
|
|
129
|
+
"@whatwg-node/fetch": "^0.8.4",
|
|
130
|
+
"babel-jest": "^29.5.0",
|
|
131
|
+
"eslint": "^8.36.0",
|
|
132
|
+
"eslint-config-prettier": "^8.8.0",
|
|
122
133
|
"express": "^4.18.2",
|
|
123
|
-
"fastify": "^4.
|
|
134
|
+
"fastify": "^4.15.0",
|
|
124
135
|
"graphql": "^16.6.0",
|
|
125
136
|
"html-validator": "^6.0.1",
|
|
126
|
-
"jest": "^29.
|
|
127
|
-
"jest-jasmine2": "^29.
|
|
137
|
+
"jest": "^29.5.0",
|
|
138
|
+
"jest-jasmine2": "^29.5.0",
|
|
128
139
|
"koa": "^2.14.1",
|
|
129
140
|
"koa-mount": "^4.0.0",
|
|
130
|
-
"node-fetch": "^3.3.
|
|
131
|
-
"prettier": "^2.8.
|
|
132
|
-
"rollup": "^3.
|
|
141
|
+
"node-fetch": "^3.3.1",
|
|
142
|
+
"prettier": "^2.8.7",
|
|
143
|
+
"rollup": "^3.20.2",
|
|
133
144
|
"rollup-plugin-gzip": "^3.1.0",
|
|
134
|
-
"semantic-release": "^
|
|
145
|
+
"semantic-release": "^21.0.0",
|
|
135
146
|
"tslib": "^2.5.0",
|
|
136
|
-
"typedoc": "^0.23.
|
|
147
|
+
"typedoc": "^0.23.28",
|
|
137
148
|
"typedoc-plugin-markdown": "^3.14.0",
|
|
138
|
-
"typescript": "^
|
|
149
|
+
"typescript": "^5.0.2"
|
|
139
150
|
},
|
|
140
151
|
"resolutions": {
|
|
141
152
|
"npm/libnpmversion": "^3.0.6"
|
|
@@ -116,22 +116,25 @@
|
|
|
116
116
|
bodyAsExecutionResult: {
|
|
117
117
|
data: {
|
|
118
118
|
async toBe(val) {
|
|
119
|
+
const clonedRes = res.clone(); // allow the body to be re-read
|
|
119
120
|
const body = await assertBodyAsExecutionResult(res);
|
|
120
121
|
if (body.data !== val) {
|
|
121
|
-
throw new AuditError(
|
|
122
|
+
throw new AuditError(clonedRes, `Response body execution result data is not "${val}"`);
|
|
122
123
|
}
|
|
123
124
|
},
|
|
124
125
|
},
|
|
125
126
|
async toHaveProperty(key) {
|
|
127
|
+
const clonedRes = res.clone(); // allow the body to be re-read
|
|
126
128
|
const body = await assertBodyAsExecutionResult(res);
|
|
127
129
|
if (!(key in body)) {
|
|
128
|
-
throw new AuditError(
|
|
130
|
+
throw new AuditError(clonedRes, `Response body execution result does not have a property "${key}"`);
|
|
129
131
|
}
|
|
130
132
|
},
|
|
131
133
|
async notToHaveProperty(key) {
|
|
134
|
+
const clonedRes = res.clone(); // allow the body to be re-read
|
|
132
135
|
const body = await assertBodyAsExecutionResult(res);
|
|
133
136
|
if (key in body) {
|
|
134
|
-
throw new AuditError(
|
|
137
|
+
throw new AuditError(clonedRes, `Response body execution result has a property "${key}"`);
|
|
135
138
|
}
|
|
136
139
|
},
|
|
137
140
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("graphql")):"function"==typeof define&&define.amd?define(["exports","graphql"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).graphqlHttpAudits={})}(this,(function(t){"use strict";function e(t){return null===t?"null":Array.isArray(t)?"array":typeof t}function a(t,e,a){return{id:t,name:e,fn:async()=>{try{return await a(),{id:t,name:e,status:"ok"}}catch(a){if(!(a instanceof n))throw a;return{id:t,name:e,status:e.startsWith("MUST")?"error":"warn",reason:a.reason,response:a.response}}}}}class n{constructor(t,e){this.response=t,this.reason=e}}function o(t){return{status:{toBe(e){if(t.status!==e)throw new n(t,`Response status code is not ${e}`)},toBeBetween:(e,a)=>{if(!(e<=t.status&&t.status<=a))throw new n(t,`Response status is not between ${e} and ${a}`)}},header:e=>({toContain(a){var o;if(!(null===(o=t.headers.get(e))||void 0===o?void 0:o.includes(a)))throw new n(t,`Response header ${e} does not contain ${a}`)},notToContain(a){var o;if(null===(o=t.headers.get(e))||void 0===o?void 0:o.includes(a))throw new n(t,`Response header ${e} contains ${a}`)}}),bodyAsExecutionResult:{data:{async toBe(e){if((await s(t)).data!==e)throw new n(t,`Response body execution result data is not "${e}"`)}},async toHaveProperty(e){if(!(e in await s(t)))throw new n(t,`Response body execution result does not have a property "${e}"`)},async notToHaveProperty(e){if(e in await s(t))throw new n(t,`Response body execution result has a property "${e}"`)}}}}async function s(t){let e,a;try{const a=new TextDecoder("utf-8"),n=await t.arrayBuffer();e=a.decode(n)}catch(e){throw new n(t,"Response body is not UTF-8 encoded")}try{a=JSON.parse(e)}catch(e){throw new n(t,"Response body is not valid JSON")}return a}function i(t){const s=t.fetchFn||fetch;return[a("22EB","SHOULD accept application/graphql-response+json and match the content-type",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),o(e).header("content-type").toContain("application/graphql-response+json")})),a("4655","MUST accept application/json and match the content-type",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),o(e).header("content-type").toContain("application/json")})),a("47DE","SHOULD accept */* and use application/json for the content-type",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"*/*"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),o(e).header("content-type").toContain("application/json")})),a("80D8","SHOULD assume application/json content-type when accept is missing",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","{ __typename }");const a=await s(e.toString());o(a).status.toBe(200),o(a).header("content-type").toContain("application/json")})),a("82A3","MUST use utf-8 encoding when responding",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200);try{new TextDecoder("utf-8").decode(await e.arrayBuffer())}catch(t){throw new n(e,"Response body is not UTF-8 encoded")}})),a("BF61","MUST accept utf-8 encoded request",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("78D5","MUST assume utf-8 in request if encoding is unspecified",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("2C94","MUST accept POST requests",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("5A70","MAY accept application/x-www-form-urlencoded formatted GET requests",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","{ __typename }");o(await s(e.toString())).status.toBe(200)})),a("9C48","MAY NOT allow executing mutations on GET requests",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","mutation { __typename }");o(await s(e.toString(),{headers:{accept:"application/graphql-response+json"}})).status.toBeBetween(400,499)})),a("9ABE","SHOULD respond with 4xx status code if content-type is not supplied on POST requests",(async()=>{o(await s(await r(t.url),{method:"POST"})).status.toBeBetween(400,499)})),a("03D4","MUST accept application/json POST requests",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("7267","MUST require a request body on POST",(async()=>{var e;const a=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"}});(null===(e=a.headers.get("content-type"))||void 0===e?void 0:e.includes("application/json"))?await o(a).bodyAsExecutionResult.toHaveProperty("errors"):o(a).status.toBe(400)})),a("6610","SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({notquery:"{ __typename }"})})).status.toBe(400)})),a("3715","SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({notquery:"{ __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`4F5${i}`,`SHOULD use 400 status code on ${e(n)} {query} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:n})})).status.toBe(400)})))),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`9FE${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {query} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:n})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("34A2","SHOULD allow string {query} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("13EE","MUST allow string {query} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`E3E${i}`,`SHOULD use 400 status code on ${e(n)} {operationName} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({operationName:n,query:"{ __typename }"})})).status.toBe(400)})))),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`FB9${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {operationName} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({operationName:n,query:"{ __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("8161","SHOULD allow string {operationName} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({operationName:"Query",query:"query Query { __typename }"})})).status.toBe(200)})),a("B8B3","MUST allow string {operationName} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({operationName:"Query",query:"query Query { __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),...["variables","operationName","extensions"].flatMap(((e,n)=>[a(`94B${n}`,`SHOULD allow null {${e}} parameter when accepting application/graphql-response+json`,(async()=>{const a=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",[e]:null})});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")})),a(`022${n}`,`MUST allow null {${e}} parameter when accepting application/json`,(async()=>{const a=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",[e]:null})});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")}))])),...["string",0,!1,["array"]].map(((n,i)=>a(`69B${i}`,`SHOULD use 400 status code on ${e(n)} {variables} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",variables:n})})).status.toBe(400)})))),...["string",0,!1,["array"]].map(((n,i)=>a(`F05${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {variables} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",variables:n})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("2EA1","SHOULD allow map {variables} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"query Type($name: String!) { __type(name: $name) { name } }",variables:{name:"sometype"}})})).status.toBe(200)})),a("28B9","MUST allow map {variables} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"query Type($name: String!) { __type(name: $name) { name } }",variables:{name:"sometype"}})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),a("D6D5","MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","query Type($name: String!) { __type(name: $name) { name } }"),e.searchParams.set("variables",JSON.stringify({name:"sometype"}));o(await s(e.toString(),{method:"GET",headers:{accept:"application/graphql-response+json"}})).status.toBe(200)})),a("6A70","MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","query Type($name: String!) { __type(name: $name) { name } }"),e.searchParams.set("variables",JSON.stringify({name:"sometype"}));const a=await s(e.toString(),{method:"GET",headers:{accept:"application/json"}});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")})),...["string",0,!1,["array"]].map(((n,i)=>a(`904${i}`,`SHOULD use 400 status code on ${e(n)} {extensions} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",extensions:n})})).status.toBe(400)})))),...["string",0,!1,["array"]].map(((n,i)=>a(`368${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {extensions} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",extensions:n})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("428F","SHOULD allow map {extensions} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",extensions:{some:"value"}})})).status.toBe(200)})),a("1B7A","MUST allow map {extensions} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",extensions:{some:"value"}})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),a("D477","SHOULD use 200 status code on JSON parsing failure when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:'{ "not a JSON'})).status.toBe(200)})),a("F5AF","SHOULD use 200 status code if parameters are invalid when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({qeury:"{ __typename }"})})).status.toBe(200)})),a("572B","SHOULD use 200 status code on document parsing failure when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{"})})).status.toBe(200)})),a("FDE2","SHOULD use 200 status code on document validation failure when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBe(200)})),a("60AA","SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:'{ "not a JSON'})).status.toBeBetween(400,499)})),a("2163","SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:'{ "not a JSON'})).status.toBe(400)})),a("3E36","SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})})).status.toBeBetween(400,599)})),a("17C5","SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})})).status.toBe(400)})),a("34D6","SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})});await o(e).bodyAsExecutionResult.data.toBe(void 0)})),a("865D","SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})})).status.toBeBetween(400,599)})),a("556A","SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})})).status.toBe(400)})),a("D586","SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})});await o(e).bodyAsExecutionResult.data.toBe(void 0)})),a("51FE","SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBeBetween(400,599)})),a("74FF","SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBe(400)})),a("5E5B","SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})});await o(e).bodyAsExecutionResult.data.toBe(void 0)}))]}async function r(t){return"function"==typeof t?await t():t}async function p(t){let e="";e+=`<li><code>${t.id}</code> ${t.name}\n`,e+="<details>\n",e+=`<summary>${function(t,e=1024){if(t.length>e)return t.substring(0,e)+"...";return t}(t.reason)}</summary>\n`,e+='<pre><code class="lang-json">';const a=t.response,n={};for(const[t,e]of a.headers.entries())"date"===t?n[t]="<timestamp>":["cf-ray","server-timing"].includes(t)?n[t]="<omitted>":n[t]=e;let o,s="";try{s=await a.text(),o=JSON.parse(s)}catch(t){}return e+=JSON.stringify({status:a.status,statusText:a.statusText,headers:n,body:o||((null==s?void 0:s.length)>5120?"<body is too long>":s)||null},((t,e)=>{if(null!=e&&"object"==typeof e&&!Array.isArray(e)){const t={};return Object.keys(e).sort().reverse().reduce(((t,a)=>(t[a]=e[a],t)),t)}return e}),2)+"\n",e+="</code></pre>\n",e+="</details>\n",e+="</li>\n",e}t.auditServer=async function(t){const e=i(t);return await Promise.all(e.map((({fn:t})=>t())))},t.renderAuditResultsToHTML=async function(t){const e={total:0,ok:[],warn:[],error:[]};for(const a of t)e.total++,a.status,e[a.status].push(a);let a="<i>* This report was auto-generated by graphql-http</i>\n";if(a+="\n",a+="<h1>GraphQL over HTTP audit report</h1>\n",a+="\n",a+="<ul>\n",a+=`<li><b>${e.total}</b> audits in total</li>\n`,e.ok.length&&(a+=`<li><span style="font-family: monospace">✅</span> <b>${e.ok.length}</b> pass</li>\n`),e.warn.length&&(a+=`<li><span style="font-family: monospace">⚠️</span> <b>${e.warn.length}</b> warnings (optional)</li>\n`),e.error.length&&(a+=`<li><span style="font-family: monospace">❌</span> <b>${e.error.length}</b> errors (required)</li>\n`),a+="</ul>\n",a+="\n",e.ok.length){a+="<h2>Passing</h2>\n",a+="<ol>\n";for(const[,t]of e.ok.entries())a+=`<li><code>${t.id}</code> ${t.name}</li>\n`;a+="</ol>\n",a+="\n"}if(e.warn.length){a+="<h2>Warnings</h2>\n",a+="The server <i>SHOULD</i> support these, but is not required.\n",a+="<ol>\n";for(const[,t]of e.warn.entries())a+=await p(t);a+="</ol>\n",a+="\n"}if(e.error.length){a+="<h2>Errors</h2>\n",a+="The server <b>MUST</b> support these.\n",a+="<ol>\n";for(const[,t]of e.error.entries())a+=await p(t);a+="</ol>\n"}return a},t.serverAudits=i}));
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("graphql")):"function"==typeof define&&define.amd?define(["exports","graphql"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).graphqlHttpAudits={})}(this,(function(t){"use strict";function e(t){return null===t?"null":Array.isArray(t)?"array":typeof t}function a(t,e,a){return{id:t,name:e,fn:async()=>{try{return await a(),{id:t,name:e,status:"ok"}}catch(a){if(!(a instanceof n))throw a;return{id:t,name:e,status:e.startsWith("MUST")?"error":"warn",reason:a.reason,response:a.response}}}}}class n{constructor(t,e){this.response=t,this.reason=e}}function o(t){return{status:{toBe(e){if(t.status!==e)throw new n(t,`Response status code is not ${e}`)},toBeBetween:(e,a)=>{if(!(e<=t.status&&t.status<=a))throw new n(t,`Response status is not between ${e} and ${a}`)}},header:e=>({toContain(a){var o;if(!(null===(o=t.headers.get(e))||void 0===o?void 0:o.includes(a)))throw new n(t,`Response header ${e} does not contain ${a}`)},notToContain(a){var o;if(null===(o=t.headers.get(e))||void 0===o?void 0:o.includes(a))throw new n(t,`Response header ${e} contains ${a}`)}}),bodyAsExecutionResult:{data:{async toBe(e){const a=t.clone();if((await s(t)).data!==e)throw new n(a,`Response body execution result data is not "${e}"`)}},async toHaveProperty(e){const a=t.clone();if(!(e in await s(t)))throw new n(a,`Response body execution result does not have a property "${e}"`)},async notToHaveProperty(e){const a=t.clone();if(e in await s(t))throw new n(a,`Response body execution result has a property "${e}"`)}}}}async function s(t){let e,a;try{const a=new TextDecoder("utf-8"),n=await t.arrayBuffer();e=a.decode(n)}catch(e){throw new n(t,"Response body is not UTF-8 encoded")}try{a=JSON.parse(e)}catch(e){throw new n(t,"Response body is not valid JSON")}return a}function i(t){const s=t.fetchFn||fetch;return[a("22EB","SHOULD accept application/graphql-response+json and match the content-type",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),o(e).header("content-type").toContain("application/graphql-response+json")})),a("4655","MUST accept application/json and match the content-type",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),o(e).header("content-type").toContain("application/json")})),a("47DE","SHOULD accept */* and use application/json for the content-type",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"*/*"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),o(e).header("content-type").toContain("application/json")})),a("80D8","SHOULD assume application/json content-type when accept is missing",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","{ __typename }");const a=await s(e.toString());o(a).status.toBe(200),o(a).header("content-type").toContain("application/json")})),a("82A3","MUST use utf-8 encoding when responding",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200);try{new TextDecoder("utf-8").decode(await e.arrayBuffer())}catch(t){throw new n(e,"Response body is not UTF-8 encoded")}})),a("BF61","MUST accept utf-8 encoded request",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("78D5","MUST assume utf-8 in request if encoding is unspecified",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("2C94","MUST accept POST requests",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("5A70","MAY accept application/x-www-form-urlencoded formatted GET requests",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","{ __typename }");o(await s(e.toString())).status.toBe(200)})),a("9C48","MAY NOT allow executing mutations on GET requests",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","mutation { __typename }");o(await s(e.toString(),{headers:{accept:"application/graphql-response+json"}})).status.toBeBetween(400,499)})),a("9ABE","SHOULD respond with 4xx status code if content-type is not supplied on POST requests",(async()=>{o(await s(await r(t.url),{method:"POST"})).status.toBeBetween(400,499)})),a("03D4","MUST accept application/json POST requests",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("7267","MUST require a request body on POST",(async()=>{var e;const a=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json"}});(null===(e=a.headers.get("content-type"))||void 0===e?void 0:e.includes("application/json"))?await o(a).bodyAsExecutionResult.toHaveProperty("errors"):o(a).status.toBe(400)})),a("6610","SHOULD use 400 status code on missing {query} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({notquery:"{ __typename }"})})).status.toBe(400)})),a("3715","SHOULD use 200 status code with errors field on missing {query} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({notquery:"{ __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`4F5${i}`,`SHOULD use 400 status code on ${e(n)} {query} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:n})})).status.toBe(400)})))),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`9FE${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {query} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:n})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("34A2","SHOULD allow string {query} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }"})})).status.toBe(200)})),a("13EE","MUST allow string {query} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`E3E${i}`,`SHOULD use 400 status code on ${e(n)} {operationName} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({operationName:n,query:"{ __typename }"})})).status.toBe(400)})))),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`FB9${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {operationName} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({operationName:n,query:"{ __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("8161","SHOULD allow string {operationName} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({operationName:"Query",query:"query Query { __typename }"})})).status.toBe(200)})),a("B8B3","MUST allow string {operationName} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({operationName:"Query",query:"query Query { __typename }"})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),...["variables","operationName","extensions"].flatMap(((e,n)=>[a(`94B${n}`,`SHOULD allow null {${e}} parameter when accepting application/graphql-response+json`,(async()=>{const a=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",[e]:null})});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")})),a(`022${n}`,`MUST allow null {${e}} parameter when accepting application/json`,(async()=>{const a=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",[e]:null})});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")}))])),...["string",0,!1,["array"]].map(((n,i)=>a(`69B${i}`,`SHOULD use 400 status code on ${e(n)} {variables} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",variables:n})})).status.toBe(400)})))),...["string",0,!1,["array"]].map(((n,i)=>a(`F05${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {variables} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",variables:n})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("2EA1","SHOULD allow map {variables} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"query Type($name: String!) { __type(name: $name) { name } }",variables:{name:"sometype"}})})).status.toBe(200)})),a("28B9","MUST allow map {variables} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"query Type($name: String!) { __type(name: $name) { name } }",variables:{name:"sometype"}})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),a("D6D5","MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","query Type($name: String!) { __type(name: $name) { name } }"),e.searchParams.set("variables",JSON.stringify({name:"sometype"}));o(await s(e.toString(),{method:"GET",headers:{accept:"application/graphql-response+json"}})).status.toBe(200)})),a("6A70","MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/json",(async()=>{const e=new URL(await r(t.url));e.searchParams.set("query","query Type($name: String!) { __type(name: $name) { name } }"),e.searchParams.set("variables",JSON.stringify({name:"sometype"}));const a=await s(e.toString(),{method:"GET",headers:{accept:"application/json"}});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")})),...["string",0,!1,["array"]].map(((n,i)=>a(`904${i}`,`SHOULD use 400 status code on ${e(n)} {extensions} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",extensions:n})})).status.toBe(400)})))),...["string",0,!1,["array"]].map(((n,i)=>a(`368${i}`,`SHOULD use 200 status code with errors field on ${e(n)} {extensions} parameter when accepting application/json`,(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",extensions:n})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.toHaveProperty("errors")})))),a("428F","SHOULD allow map {extensions} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",extensions:{some:"value"}})})).status.toBe(200)})),a("1B7A","MUST allow map {extensions} parameter when accepting application/json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",extensions:{some:"value"}})});o(e).status.toBe(200),await o(e).bodyAsExecutionResult.notToHaveProperty("errors")})),a("D477","SHOULD use 200 status code on JSON parsing failure when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:'{ "not a JSON'})).status.toBe(200)})),a("F5AF","SHOULD use 200 status code if parameters are invalid when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({qeury:"{ __typename }"})})).status.toBe(200)})),a("572B","SHOULD use 200 status code on document parsing failure when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{"})})).status.toBe(200)})),a("FDE2","SHOULD use 200 status code on document validation failure when accepting application/json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBe(200)})),a("60AA","SHOULD use 4xx or 5xx status codes on JSON parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:'{ "not a JSON'})).status.toBeBetween(400,499)})),a("2163","SHOULD use 400 status code on JSON parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:'{ "not a JSON'})).status.toBe(400)})),a("3E36","SHOULD use 4xx or 5xx status codes if parameters are invalid when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})})).status.toBeBetween(400,599)})),a("17C5","SHOULD use 400 status code if parameters are invalid when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})})).status.toBe(400)})),a("34D6","SHOULD not contain the data entry if parameters are invalid when accepting application/graphql-response+json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})});await o(e).bodyAsExecutionResult.data.toBe(void 0)})),a("865D","SHOULD use 4xx or 5xx status codes on document parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})})).status.toBeBetween(400,599)})),a("556A","SHOULD use 400 status code on document parsing failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})})).status.toBe(400)})),a("D586","SHOULD not contain the data entry on document parsing failure when accepting application/graphql-response+json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})});await o(e).bodyAsExecutionResult.data.toBe(void 0)})),a("51FE","SHOULD use 4xx or 5xx status codes on document validation failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBeBetween(400,599)})),a("74FF","SHOULD use 400 status code on document validation failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBe(400)})),a("5E5B","SHOULD not contain the data entry on document validation failure when accepting application/graphql-response+json",(async()=>{const e=await s(await r(t.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})});await o(e).bodyAsExecutionResult.data.toBe(void 0)}))]}async function r(t){return"function"==typeof t?await t():t}async function p(t){let e="";e+=`<li><code>${t.id}</code> ${t.name}\n`,e+="<details>\n",e+=`<summary>${function(t,e=1024){if(t.length>e)return t.substring(0,e)+"...";return t}(t.reason)}</summary>\n`,e+='<pre><code class="lang-json">';const a=t.response,n={};for(const[t,e]of a.headers.entries())"date"===t?n[t]="<timestamp>":["cf-ray","server-timing"].includes(t)?n[t]="<omitted>":n[t]=e;let o,s="";try{s=await a.text(),o=JSON.parse(s)}catch(t){}return e+=JSON.stringify({status:a.status,statusText:a.statusText,headers:n,body:o||((null==s?void 0:s.length)>5120?"<body is too long>":s)||null},((t,e)=>{if(null!=e&&"object"==typeof e&&!Array.isArray(e)){const t={};return Object.keys(e).sort().reverse().reduce(((t,a)=>(t[a]=e[a],t)),t)}return e}),2)+"\n",e+="</code></pre>\n",e+="</details>\n",e+="</li>\n",e}t.auditServer=async function(t){const e=i(t);return await Promise.all(e.map((({fn:t})=>t())))},t.renderAuditResultsToHTML=async function(t){const e={total:0,ok:[],warn:[],error:[]};for(const a of t)e.total++,a.status,e[a.status].push(a);let a="<i>* This report was auto-generated by graphql-http</i>\n";if(a+="\n",a+="<h1>GraphQL over HTTP audit report</h1>\n",a+="\n",a+="<ul>\n",a+=`<li><b>${e.total}</b> audits in total</li>\n`,e.ok.length&&(a+=`<li><span style="font-family: monospace">✅</span> <b>${e.ok.length}</b> pass</li>\n`),e.warn.length&&(a+=`<li><span style="font-family: monospace">⚠️</span> <b>${e.warn.length}</b> warnings (optional)</li>\n`),e.error.length&&(a+=`<li><span style="font-family: monospace">❌</span> <b>${e.error.length}</b> errors (required)</li>\n`),a+="</ul>\n",a+="\n",e.ok.length){a+="<h2>Passing</h2>\n",a+="<ol>\n";for(const[,t]of e.ok.entries())a+=`<li><code>${t.id}</code> ${t.name}</li>\n`;a+="</ol>\n",a+="\n"}if(e.warn.length){a+="<h2>Warnings</h2>\n",a+="The server <i>SHOULD</i> support these, but is not required.\n",a+="<ol>\n";for(const[,t]of e.warn.entries())a+=await p(t);a+="</ol>\n",a+="\n"}if(e.error.length){a+="<h2>Errors</h2>\n",a+="The server <b>MUST</b> support these.\n",a+="<ol>\n";for(const[,t]of e.error.entries())a+=await p(t);a+="</ol>\n"}return a},t.serverAudits=i}));
|
|
Binary file
|