graphql-http 1.17.0 → 1.17.1

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.
@@ -1,3 +1,3 @@
1
- export * from './common';
2
- export * from './server';
3
- export * from './render';
1
+ export * from './common.mjs';
2
+ export * from './server.mjs';
3
+ export * from './render.mjs';
@@ -1,4 +1,4 @@
1
- import { AuditResult } from './common';
1
+ import { AuditResult } from './common.mjs';
2
2
  /**
3
3
  * Renders the provided audit results to well-formatted and valid HTML.
4
4
  *
@@ -3,7 +3,7 @@
3
3
  * audit/server
4
4
  *
5
5
  */
6
- import { Audit, AuditResult } from './common';
6
+ import { Audit, AuditResult } from './common.mjs';
7
7
  /**
8
8
  * Options for server audits required to check GraphQL over HTTP spec conformance.
9
9
  *
@@ -86,7 +86,9 @@ function serverAudits(opts) {
86
86
  headers: {
87
87
  'content-type': 'application/json; charset=utf-8',
88
88
  },
89
- body: JSON.stringify({ query: '{ __typename }' }),
89
+ body: JSON.stringify({
90
+ query: '{ __type(name: "Run🏃Swim🏊") { name } }',
91
+ }),
90
92
  });
91
93
  (0, utils_1.ressert)(res).status.toBe(200);
92
94
  }),
@@ -534,6 +536,20 @@ function serverAudits(opts) {
534
536
  });
535
537
  (0, utils_1.ressert)(res).status.toBe(200);
536
538
  }),
539
+ (0, utils_1.audit)('7B9B', 'SHOULD use a status code of 200 on variable coercion failure when accepting application/json', async () => {
540
+ const res = await fetchFn(await getUrl(opts.url), {
541
+ method: 'POST',
542
+ headers: {
543
+ 'content-type': 'application/json',
544
+ accept: 'application/json',
545
+ },
546
+ body: JSON.stringify({
547
+ query: 'query CoerceFailure($id: ID!){ __typename }',
548
+ variables: { id: null },
549
+ }),
550
+ });
551
+ (0, utils_1.ressert)(res).status.toBe(200);
552
+ }),
537
553
  // Response application/graphql-response+json
538
554
  (0, utils_1.audit)(
539
555
  // TODO: convert to MUST after watershed
@@ -682,6 +698,20 @@ function serverAudits(opts) {
682
698
  });
683
699
  await (0, utils_1.ressert)(res).bodyAsExecutionResult.data.toBe(undefined);
684
700
  }),
701
+ (0, utils_1.audit)('86EE', 'SHOULD use a status code of 400 on variable coercion failure when accepting application/graphql-response+json', async () => {
702
+ const res = await fetchFn(await getUrl(opts.url), {
703
+ method: 'POST',
704
+ headers: {
705
+ 'content-type': 'application/json',
706
+ accept: 'application/graphql-response+json',
707
+ },
708
+ body: JSON.stringify({
709
+ query: 'query CoerceFailure($id: ID!){ __typename }',
710
+ variables: { id: null },
711
+ }),
712
+ });
713
+ (0, utils_1.ressert)(res).status.toBe(400);
714
+ }),
685
715
  // TODO: how to fail and have the data entry?
686
716
  // audit('EE52', 'MUST use 2xx status code if response contains the data entry and it is not null when accepting application/graphql-response+json'),
687
717
  // TODO: how to make an unauthorized request?
@@ -83,7 +83,9 @@ export function serverAudits(opts) {
83
83
  headers: {
84
84
  'content-type': 'application/json; charset=utf-8',
85
85
  },
86
- body: JSON.stringify({ query: '{ __typename }' }),
86
+ body: JSON.stringify({
87
+ query: '{ __type(name: "Run🏃Swim🏊") { name } }',
88
+ }),
87
89
  });
88
90
  ressert(res).status.toBe(200);
89
91
  }),
@@ -531,6 +533,20 @@ export function serverAudits(opts) {
531
533
  });
532
534
  ressert(res).status.toBe(200);
533
535
  }),
536
+ audit('7B9B', 'SHOULD use a status code of 200 on variable coercion failure when accepting application/json', async () => {
537
+ const res = await fetchFn(await getUrl(opts.url), {
538
+ method: 'POST',
539
+ headers: {
540
+ 'content-type': 'application/json',
541
+ accept: 'application/json',
542
+ },
543
+ body: JSON.stringify({
544
+ query: 'query CoerceFailure($id: ID!){ __typename }',
545
+ variables: { id: null },
546
+ }),
547
+ });
548
+ ressert(res).status.toBe(200);
549
+ }),
534
550
  // Response application/graphql-response+json
535
551
  audit(
536
552
  // TODO: convert to MUST after watershed
@@ -679,6 +695,20 @@ export function serverAudits(opts) {
679
695
  });
680
696
  await ressert(res).bodyAsExecutionResult.data.toBe(undefined);
681
697
  }),
698
+ audit('86EE', 'SHOULD use a status code of 400 on variable coercion failure when accepting application/graphql-response+json', async () => {
699
+ const res = await fetchFn(await getUrl(opts.url), {
700
+ method: 'POST',
701
+ headers: {
702
+ 'content-type': 'application/json',
703
+ accept: 'application/graphql-response+json',
704
+ },
705
+ body: JSON.stringify({
706
+ query: 'query CoerceFailure($id: ID!){ __typename }',
707
+ variables: { id: null },
708
+ }),
709
+ });
710
+ ressert(res).status.toBe(400);
711
+ }),
682
712
  // TODO: how to fail and have the data entry?
683
713
  // audit('EE52', 'MUST use 2xx status code if response contains the data entry and it is not null when accepting application/graphql-response+json'),
684
714
  // TODO: how to make an unauthorized request?
@@ -4,8 +4,8 @@
4
4
  *
5
5
  */
6
6
  import type { ExecutionResult } from 'graphql';
7
- import { Audit, AuditName } from './common';
8
- export * from '../utils';
7
+ import { Audit, AuditName } from './common.mjs';
8
+ export * from '../utils.mjs';
9
9
  /**
10
10
  * Wrap and prepare an audit for testing.
11
11
  *
package/lib/client.d.mts CHANGED
@@ -4,9 +4,9 @@
4
4
  *
5
5
  */
6
6
  import type { ExecutionResult } from 'graphql';
7
- import { RequestParams, Sink } from './common';
7
+ import { RequestParams, Sink } from './common.mjs';
8
8
  /** This file is the entry point for browsers, re-export common elements. */
9
- export * from './common';
9
+ export * from './common.mjs';
10
10
  /** @category Client */
11
11
  export interface ClientOptions {
12
12
  /**
package/lib/handler.d.mts CHANGED
@@ -4,7 +4,7 @@
4
4
  *
5
5
  */
6
6
  import { ExecutionArgs, ExecutionResult, GraphQLSchema, validate as graphqlValidate, ValidationRule, execute as graphqlExecute, parse as graphqlParse, getOperationAST as graphqlGetOperationAST, GraphQLError } from 'graphql';
7
- import { RequestParams } from './common';
7
+ import { RequestParams } from './common.mjs';
8
8
  /**
9
9
  * The incoming request headers the implementing server should provide.
10
10
  *
@@ -246,7 +246,7 @@ export type Handler<RequestRaw = unknown, RequestContext = unknown> = (req: Requ
246
246
  * ```js
247
247
  * import http from 'http';
248
248
  * import { createHandler } from 'graphql-http';
249
- * import { schema } from './my-graphql-schema';
249
+ * import { schema } from './my-graphql-schema/index.mjs';
250
250
  *
251
251
  * // Create the GraphQL over HTTP handler
252
252
  * const handler = createHandler({ schema });
package/lib/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export * from './common';
2
- export * from './handler';
3
- export * from './client';
4
- export * from './audits';
1
+ export * from './common.mjs';
2
+ export * from './handler.mjs';
3
+ export * from './client.mjs';
4
+ export * from './audits/index.mjs';
@@ -1,5 +1,5 @@
1
1
  import type { Request, Response, Handler } from 'express';
2
- import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler';
2
+ import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler.mjs';
3
3
  /**
4
4
  * The context in the request for the handler.
5
5
  *
@@ -21,7 +21,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = RawHa
21
21
  * ```js
22
22
  * import express from 'express'; // yarn add express
23
23
  * import { createHandler } from 'graphql-http/lib/use/express';
24
- * import { schema } from './my-graphql-schema';
24
+ * import { schema } from './my-graphql-schema/index.mjs';
25
25
  *
26
26
  * const app = express();
27
27
  * app.all('/graphql', createHandler({ schema }));
@@ -1,5 +1,5 @@
1
1
  import type { FastifyRequest, FastifyReply, RouteHandler } from 'fastify';
2
- import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler';
2
+ import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler.mjs';
3
3
  /**
4
4
  * The context in the request for the handler.
5
5
  *
@@ -21,7 +21,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = RawHa
21
21
  * ```js
22
22
  * import Fastify from 'fastify'; // yarn add fastify
23
23
  * import { createHandler } from 'graphql-http/lib/use/express';
24
- * import { schema } from './my-graphql-schema';
24
+ * import { schema } from './my-graphql-schema/index.mjs';
25
25
  *
26
26
  * const fastify = Fastify();
27
27
  * fastify.all('/graphql', createHandler({ schema }));
@@ -1,4 +1,4 @@
1
- import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler';
1
+ import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler.mjs';
2
2
  /**
3
3
  * The necessary API from the fetch environment for the handler.
4
4
  *
@@ -26,7 +26,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = RawHa
26
26
  * import http from 'http';
27
27
  * import { createServerAdapter } from '@whatwg-node/server'; // yarn add @whatwg-node/server
28
28
  * import { createHandler } from 'graphql-http/lib/use/fetch';
29
- * import { schema } from './my-graphql-step';
29
+ * import { schema } from './my-graphql-step/index.mjs';
30
30
  *
31
31
  * // Use this adapter in _any_ environment.
32
32
  * const adapter = createServerAdapter({
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import type { IncomingMessage, ServerResponse } from 'http';
3
- import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler';
3
+ import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler.mjs';
4
4
  /**
5
5
  * The context in the request for the handler.
6
6
  *
@@ -22,7 +22,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = RawHa
22
22
  * ```js
23
23
  * import http from 'http';
24
24
  * import { createHandler } from 'graphql-http/lib/use/http';
25
- * import { schema } from './my-graphql-step';
25
+ * import { schema } from './my-graphql-step/index.mjs';
26
26
  *
27
27
  * const server = http.createServer(createHandler({ schema }));
28
28
  *
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import type { Http2ServerRequest, Http2ServerResponse } from 'http2';
3
- import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler';
3
+ import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler.mjs';
4
4
  /**
5
5
  * The context in the request for the handler.
6
6
  *
@@ -28,7 +28,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = RawHa
28
28
  * import fs from 'fs';
29
29
  * import http2 from 'http2';
30
30
  * import { createHandler } from 'graphql-http/lib/use/http2';
31
- * import { schema } from './my-graphql-step';
31
+ * import { schema } from './my-graphql-step/index.mjs';
32
32
  *
33
33
  * const server = http2.createSecureServer(
34
34
  * {
package/lib/use/koa.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import type { Middleware, Response } from 'koa';
3
3
  import type { IncomingMessage } from 'http';
4
- import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler';
4
+ import { HandlerOptions as RawHandlerOptions, OperationContext } from '../handler.mjs';
5
5
  /**
6
6
  * The context in the request for the handler.
7
7
  *
@@ -24,7 +24,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = RawHa
24
24
  * import Koa from 'koa'; // yarn add koa
25
25
  * import mount from 'koa-mount'; // yarn add koa-mount
26
26
  * import { createHandler } from 'graphql-http/lib/use/koa';
27
- * import { schema } from './my-graphql-schema';
27
+ * import { schema } from './my-graphql-schema/index.mjs';
28
28
  *
29
29
  * const app = new Koa();
30
30
  * app.use(mount('/', createHandler({ schema })));
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import { HandlerOptions as HttpHandlerOptions } from './http';
3
- import { OperationContext } from '../handler';
2
+ import { HandlerOptions as HttpHandlerOptions } from './http.mjs';
3
+ import { OperationContext } from '../handler.mjs';
4
4
  /**
5
5
  * Handler options when using the node adapter.
6
6
  *
@@ -16,7 +16,7 @@ export type HandlerOptions<Context extends OperationContext = undefined> = HttpH
16
16
  * ```js
17
17
  * import http from 'http';
18
18
  * import { createHandler } from 'graphql-http/lib/use/node';
19
- * import { schema } from './my-graphql-step';
19
+ * import { schema } from './my-graphql-step/index.mjs';
20
20
  *
21
21
  * const server = http.createServer(createHandler({ schema }));
22
22
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphql-http",
3
- "version": "1.17.0",
3
+ "version": "1.17.1",
4
4
  "description": "Simple, pluggable, zero-dependency, GraphQL over HTTP spec compliant server, client and audit suite.",
5
5
  "keywords": [
6
6
  "graphql",
@@ -106,18 +106,18 @@
106
106
  "graphql": ">=0.11 <=16"
107
107
  },
108
108
  "devDependencies": {
109
- "@babel/core": "^7.21.3",
109
+ "@babel/core": "^7.21.4",
110
110
  "@babel/plugin-proposal-class-properties": "^7.18.6",
111
111
  "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
112
112
  "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
113
113
  "@babel/plugin-proposal-optional-chaining": "^7.21.0",
114
- "@babel/preset-env": "^7.20.2",
115
- "@babel/preset-typescript": "^7.21.0",
114
+ "@babel/preset-env": "^7.21.4",
115
+ "@babel/preset-typescript": "^7.21.4",
116
116
  "@rollup/plugin-terser": "^0.4.0",
117
117
  "@rollup/plugin-typescript": "^11.0.0",
118
118
  "@semantic-release/changelog": "^6.0.3",
119
119
  "@semantic-release/git": "^10.0.1",
120
- "@types/eslint": "^8.21.3",
120
+ "@types/eslint": "^8.37.0",
121
121
  "@types/express": "^4.17.17",
122
122
  "@types/glob": "^8.1.0",
123
123
  "@types/html-validator": "^5.0.3",
@@ -128,7 +128,7 @@
128
128
  "@typescript-eslint/parser": "^5.57.0",
129
129
  "@whatwg-node/fetch": "^0.8.4",
130
130
  "babel-jest": "^29.5.0",
131
- "eslint": "^8.36.0",
131
+ "eslint": "^8.37.0",
132
132
  "eslint-config-prettier": "^8.8.0",
133
133
  "express": "^4.18.2",
134
134
  "fastify": "^4.15.0",
@@ -146,7 +146,7 @@
146
146
  "tslib": "^2.5.0",
147
147
  "typedoc": "^0.23.28",
148
148
  "typedoc-plugin-markdown": "^3.14.0",
149
- "typescript": "^5.0.2"
149
+ "typescript": "^5.0.3"
150
150
  },
151
151
  "resolutions": {
152
152
  "npm/libnpmversion": "^3.0.6"
@@ -245,7 +245,9 @@
245
245
  headers: {
246
246
  'content-type': 'application/json; charset=utf-8',
247
247
  },
248
- body: JSON.stringify({ query: '{ __typename }' }),
248
+ body: JSON.stringify({
249
+ query: '{ __type(name: "Run🏃Swim🏊") { name } }',
250
+ }),
249
251
  });
250
252
  ressert(res).status.toBe(200);
251
253
  }),
@@ -693,6 +695,20 @@
693
695
  });
694
696
  ressert(res).status.toBe(200);
695
697
  }),
698
+ audit('7B9B', 'SHOULD use a status code of 200 on variable coercion failure when accepting application/json', async () => {
699
+ const res = await fetchFn(await getUrl(opts.url), {
700
+ method: 'POST',
701
+ headers: {
702
+ 'content-type': 'application/json',
703
+ accept: 'application/json',
704
+ },
705
+ body: JSON.stringify({
706
+ query: 'query CoerceFailure($id: ID!){ __typename }',
707
+ variables: { id: null },
708
+ }),
709
+ });
710
+ ressert(res).status.toBe(200);
711
+ }),
696
712
  // Response application/graphql-response+json
697
713
  audit(
698
714
  // TODO: convert to MUST after watershed
@@ -841,6 +857,20 @@
841
857
  });
842
858
  await ressert(res).bodyAsExecutionResult.data.toBe(undefined);
843
859
  }),
860
+ audit('86EE', 'SHOULD use a status code of 400 on variable coercion failure when accepting application/graphql-response+json', async () => {
861
+ const res = await fetchFn(await getUrl(opts.url), {
862
+ method: 'POST',
863
+ headers: {
864
+ 'content-type': 'application/json',
865
+ accept: 'application/graphql-response+json',
866
+ },
867
+ body: JSON.stringify({
868
+ query: 'query CoerceFailure($id: ID!){ __typename }',
869
+ variables: { id: null },
870
+ }),
871
+ });
872
+ ressert(res).status.toBe(400);
873
+ }),
844
874
  // TODO: how to fail and have the data entry?
845
875
  // audit('EE52', 'MUST use 2xx status code if response contains the data entry and it is not null when accepting application/graphql-response+json'),
846
876
  // TODO: how to make an unauthorized request?
@@ -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){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}));
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("graphql")):"function"==typeof define&&define.amd?define(["exports","graphql"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlHttpAudits={})}(this,(function(e){"use strict";function t(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function a(e,t,a){return{id:e,name:t,fn:async()=>{try{return await a(),{id:e,name:t,status:"ok"}}catch(a){if(!(a instanceof n))throw a;return{id:e,name:t,status:t.startsWith("MUST")?"error":"warn",reason:a.reason,response:a.response}}}}}class n{constructor(e,t){this.response=e,this.reason=t}}function o(e){return{status:{toBe(t){if(e.status!==t)throw new n(e,`Response status code is not ${t}`)},toBeBetween:(t,a)=>{if(!(t<=e.status&&e.status<=a))throw new n(e,`Response status is not between ${t} and ${a}`)}},header:t=>({toContain(a){var o;if(!(null===(o=e.headers.get(t))||void 0===o?void 0:o.includes(a)))throw new n(e,`Response header ${t} does not contain ${a}`)},notToContain(a){var o;if(null===(o=e.headers.get(t))||void 0===o?void 0:o.includes(a))throw new n(e,`Response header ${t} contains ${a}`)}}),bodyAsExecutionResult:{data:{async toBe(t){const a=e.clone();if((await s(e)).data!==t)throw new n(a,`Response body execution result data is not "${t}"`)}},async toHaveProperty(t){const a=e.clone();if(!(t in await s(e)))throw new n(a,`Response body execution result does not have a property "${t}"`)},async notToHaveProperty(t){const a=e.clone();if(t in await s(e))throw new n(a,`Response body execution result has a property "${t}"`)}}}}async function s(e){let t,a;try{const a=new TextDecoder("utf-8"),n=await e.arrayBuffer();t=a.decode(n)}catch(t){throw new n(e,"Response body is not UTF-8 encoded")}try{a=JSON.parse(t)}catch(t){throw new n(e,"Response body is not valid JSON")}return a}function i(e){const s=e.fetchFn||fetch;return[a("22EB","SHOULD accept application/graphql-response+json and match the content-type",(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }"})});o(t).status.toBe(200),o(t).header("content-type").toContain("application/graphql-response+json")})),a("4655","MUST accept application/json and match the content-type",(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(t).status.toBe(200),o(t).header("content-type").toContain("application/json")})),a("47DE","SHOULD accept */* and use application/json for the content-type",(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"*/*"},body:JSON.stringify({query:"{ __typename }"})});o(t).status.toBe(200),o(t).header("content-type").toContain("application/json")})),a("80D8","SHOULD assume application/json content-type when accept is missing",(async()=>{const t=new URL(await r(e.url));t.searchParams.set("query","{ __typename }");const a=await s(t.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(t).status.toBe(200);try{new TextDecoder("utf-8").decode(await t.arrayBuffer())}catch(e){throw new n(t,"Response body is not UTF-8 encoded")}})),a("BF61","MUST accept utf-8 encoded request",(async()=>{o(await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json; charset=utf-8"},body:JSON.stringify({query:'{ __type(name: "Run🏃Swim🏊") { name } }'})})).status.toBe(200)})),a("78D5","MUST assume utf-8 in request if encoding is unspecified",(async()=>{o(await s(await r(e.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(e.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 t=new URL(await r(e.url));t.searchParams.set("query","{ __typename }");o(await s(t.toString())).status.toBe(200)})),a("9C48","MAY NOT allow executing mutations on GET requests",(async()=>{const t=new URL(await r(e.url));t.searchParams.set("query","mutation { __typename }");o(await s(t.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(e.url),{method:"POST"})).status.toBeBetween(400,499)})),a("03D4","MUST accept application/json POST requests",(async()=>{o(await s(await r(e.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 t;const a=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json"}});(null===(t=a.headers.get("content-type"))||void 0===t?void 0:t.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(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({notquery:"{ __typename }"})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.toHaveProperty("errors")})),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`4F5${i}`,`SHOULD use 400 status code on ${t(n)} {query} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(e.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 ${t(n)} {query} parameter when accepting application/json`,(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:n})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.toHaveProperty("errors")})))),a("34A2","SHOULD allow string {query} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }"})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.notToHaveProperty("errors")})),...[{obj:"ect"},0,!1,["array"]].map(((n,i)=>a(`E3E${i}`,`SHOULD use 400 status code on ${t(n)} {operationName} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(e.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 ${t(n)} {operationName} parameter when accepting application/json`,(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({operationName:n,query:"{ __typename }"})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.toHaveProperty("errors")})))),a("8161","SHOULD allow string {operationName} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({operationName:"Query",query:"query Query { __typename }"})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.notToHaveProperty("errors")})),...["variables","operationName","extensions"].flatMap(((t,n)=>[a(`94B${n}`,`SHOULD allow null {${t}} parameter when accepting application/graphql-response+json`,(async()=>{const a=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ __typename }",[t]:null})});o(a).status.toBe(200),await o(a).bodyAsExecutionResult.notToHaveProperty("errors")})),a(`022${n}`,`MUST allow null {${t}} parameter when accepting application/json`,(async()=>{const a=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",[t]: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 ${t(n)} {variables} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(e.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 ${t(n)} {variables} parameter when accepting application/json`,(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",variables:n})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.toHaveProperty("errors")})))),a("2EA1","SHOULD allow map {variables} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(e.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 t=await s(await r(e.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(t).status.toBe(200),await o(t).bodyAsExecutionResult.notToHaveProperty("errors")})),a("D6D5","MAY allow URL-encoded JSON string {variables} parameter in GETs when accepting application/graphql-response+json",(async()=>{const t=new URL(await r(e.url));t.searchParams.set("query","query Type($name: String!) { __type(name: $name) { name } }"),t.searchParams.set("variables",JSON.stringify({name:"sometype"}));o(await s(t.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 t=new URL(await r(e.url));t.searchParams.set("query","query Type($name: String!) { __type(name: $name) { name } }"),t.searchParams.set("variables",JSON.stringify({name:"sometype"}));const a=await s(t.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 ${t(n)} {extensions} parameter when accepting application/graphql-response+json`,(async()=>{o(await s(await r(e.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 ${t(n)} {extensions} parameter when accepting application/json`,(async()=>{const t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",extensions:n})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.toHaveProperty("errors")})))),a("428F","SHOULD allow map {extensions} parameter when accepting application/graphql-response+json",(async()=>{o(await s(await r(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ __typename }",extensions:{some:"value"}})});o(t).status.toBe(200),await o(t).bodyAsExecutionResult.notToHaveProperty("errors")})),a("D477","SHOULD use 200 status code on JSON parsing failure when accepting application/json",(async()=>{o(await s(await r(e.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(e.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(e.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(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})})).status.toBe(200)})),a("7B9B","SHOULD use a status code of 200 on variable coercion failure when accepting application/json",(async()=>{o(await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:"query CoerceFailure($id: ID!){ __typename }",variables:{id:null}})})).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(e.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(e.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(e.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(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({qeury:"{ __typename }"})});await o(t).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(e.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(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{"})});await o(t).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(e.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(e.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 t=await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"{ 8f31403dfe404bccbb0e835f2629c6a7 }"})});await o(t).bodyAsExecutionResult.data.toBe(void 0)})),a("86EE","SHOULD use a status code of 400 on variable coercion failure when accepting application/graphql-response+json",(async()=>{o(await s(await r(e.url),{method:"POST",headers:{"content-type":"application/json",accept:"application/graphql-response+json"},body:JSON.stringify({query:"query CoerceFailure($id: ID!){ __typename }",variables:{id:null}})})).status.toBe(400)}))]}async function r(e){return"function"==typeof e?await e():e}async function p(e){let t="";t+=`<li><code>${e.id}</code> ${e.name}\n`,t+="<details>\n",t+=`<summary>${function(e,t=1024){if(e.length>t)return e.substring(0,t)+"...";return e}(e.reason)}</summary>\n`,t+='<pre><code class="lang-json">';const a=e.response,n={};for(const[e,t]of a.headers.entries())"date"===e?n[e]="<timestamp>":["cf-ray","server-timing"].includes(e)?n[e]="<omitted>":n[e]=t;let o,s="";try{s=await a.text(),o=JSON.parse(s)}catch(e){}return t+=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},((e,t)=>{if(null!=t&&"object"==typeof t&&!Array.isArray(t)){const e={};return Object.keys(t).sort().reverse().reduce(((e,a)=>(e[a]=t[a],e)),e)}return t}),2)+"\n",t+="</code></pre>\n",t+="</details>\n",t+="</li>\n",t}e.auditServer=async function(e){const t=i(e);return await Promise.all(t.map((({fn:e})=>e())))},e.renderAuditResultsToHTML=async function(e){const t={total:0,ok:[],warn:[],error:[]};for(const a of e)t.total++,a.status,t[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>${t.total}</b> audits in total</li>\n`,t.ok.length&&(a+=`<li><span style="font-family: monospace">✅</span> <b>${t.ok.length}</b> pass</li>\n`),t.warn.length&&(a+=`<li><span style="font-family: monospace">⚠️</span> <b>${t.warn.length}</b> warnings (optional)</li>\n`),t.error.length&&(a+=`<li><span style="font-family: monospace">❌</span> <b>${t.error.length}</b> errors (required)</li>\n`),a+="</ul>\n",a+="\n",t.ok.length){a+="<h2>Passing</h2>\n",a+="<ol>\n";for(const[,e]of t.ok.entries())a+=`<li><code>${e.id}</code> ${e.name}</li>\n`;a+="</ol>\n",a+="\n"}if(t.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[,e]of t.warn.entries())a+=await p(e);a+="</ol>\n",a+="\n"}if(t.error.length){a+="<h2>Errors</h2>\n",a+="The server <b>MUST</b> support these.\n",a+="<ol>\n";for(const[,e]of t.error.entries())a+=await p(e);a+="</ol>\n"}return a},e.serverAudits=i}));
Binary file