diff --git a/.mocharc.yml b/.mocharc.yml
index eefc53a3..4ab239f4 100644
--- a/.mocharc.yml
+++ b/.mocharc.yml
@@ -1,4 +1,3 @@
-throw-deprecation: true
check-leaks: true
require:
- './resources/register.js'
diff --git a/README.md b/README.md
index ecb94123..10526c27 100644
--- a/README.md
+++ b/README.md
@@ -138,6 +138,8 @@ The `graphqlHTTP` function accepts the following options:
- **`subscriptionEndpoint`**: An optional GraphQL string contains the WebSocket server url for subscription.
+ - **`websocketClient`**: An optional GraphQL string for websocket client used for subscription, `v0`: subscriptions-transport-ws, `v1`: graphql-ws. Defaults to `v0` if not provided
+
- **`rootValue`**: A value to pass as the `rootValue` to the `execute()`
function from [`GraphQL.js/src/execute.js`](https://github.com/graphql/graphql-js/blob/main/src/execution/execute.js#L129).
diff --git a/examples/index_subscription.ts b/examples/index_subscription.ts
new file mode 100644
index 00000000..553a464e
--- /dev/null
+++ b/examples/index_subscription.ts
@@ -0,0 +1,48 @@
+import { createServer } from 'http';
+
+import express from 'express';
+import { execute, subscribe } from 'graphql';
+import ws from 'ws';
+import { useServer } from 'graphql-ws/lib/use/ws';
+
+import { graphqlHTTP } from '../src';
+
+import { schema, roots, rootValue } from './schema';
+
+const PORT = 4000;
+const subscriptionEndpoint = `ws://localhost:${PORT}/subscriptions`;
+
+const app = express();
+app.use(
+ '/graphql',
+ graphqlHTTP({
+ schema,
+ rootValue,
+ graphiql: {
+ subscriptionEndpoint,
+ websocketClient: 'v1',
+ },
+ }),
+);
+
+const server = createServer(app);
+
+const wsServer = new ws.Server({
+ server,
+ path: '/subscriptions',
+});
+
+server.listen(PORT, () => {
+ useServer(
+ {
+ schema,
+ roots,
+ execute,
+ subscribe,
+ },
+ wsServer,
+ );
+ console.info(
+ `Running a GraphQL API server with subscriptions at http://localhost:${PORT}/graphql`,
+ );
+});
diff --git a/examples/index_subscription_legacy.ts b/examples/index_subscription_legacy.ts
new file mode 100644
index 00000000..2cd6d8ba
--- /dev/null
+++ b/examples/index_subscription_legacy.ts
@@ -0,0 +1,53 @@
+import { createServer } from 'http';
+
+import express from 'express';
+import { execute, subscribe } from 'graphql';
+import { SubscriptionServer } from 'subscriptions-transport-ws';
+
+import { graphqlHTTP } from '../src';
+
+import { schema, rootValue } from './schema';
+
+const PORT = 4000;
+const subscriptionEndpoint = `ws://localhost:${PORT}/subscriptions`;
+
+const app = express();
+app.use(
+ '/graphql',
+ graphqlHTTP({
+ schema,
+ rootValue,
+ graphiql: { subscriptionEndpoint },
+ }),
+);
+
+const ws = createServer(app);
+
+ws.listen(PORT, () => {
+ console.log(
+ `Running a GraphQL API server with subscriptions at http://localhost:${PORT}/graphql`,
+ );
+});
+
+const onConnect = (_: any, __: any) => {
+ console.log('connecting ....');
+};
+
+const onDisconnect = (_: any) => {
+ console.log('disconnecting ...');
+};
+
+SubscriptionServer.create(
+ {
+ schema,
+ rootValue,
+ execute,
+ subscribe,
+ onConnect,
+ onDisconnect,
+ },
+ {
+ server: ws,
+ path: '/subscriptions',
+ },
+);
diff --git a/examples/schema.ts b/examples/schema.ts
new file mode 100644
index 00000000..98e55cad
--- /dev/null
+++ b/examples/schema.ts
@@ -0,0 +1,37 @@
+import { buildSchema } from 'graphql';
+
+function sleep(ms: number) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, ms);
+ });
+}
+
+export const schema = buildSchema(`
+type Query {
+ hello: String
+}
+type Subscription {
+ countDown: Int
+}
+`);
+
+export const roots = {
+ Query: {
+ hello: () => 'Hello World!',
+ },
+ subscription: {
+ /* eslint no-await-in-loop: "off" */
+
+ countDown: async function* fiveToOne() {
+ for (const number of [5, 4, 3, 2, 1]) {
+ await sleep(1000); // slow down a bit so user can see the count down on GraphiQL
+ yield { countDown: number };
+ }
+ },
+ },
+};
+
+export const rootValue = {
+ hello: roots.Query.hello,
+ countDown: roots.subscription.countDown,
+};
diff --git a/package-lock.json b/package-lock.json
index 928abda2..565e242e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -318,6 +318,18 @@
}
}
},
+ "@graphiql/toolkit": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.1.1.tgz",
+ "integrity": "sha512-cvsuaPkOA6/TZOdqEdvzqr7i+or2STTpSsteyDkrUXrwftRnH9ZfiUwnHPyf0AC2cKMwpP/Dny/UTS6CLC8ZNQ==",
+ "dev": true,
+ "requires": {
+ "@n1ru4l/push-pull-async-iterable-iterator": "^2.0.1",
+ "graphql-ws": "^4.1.0",
+ "meros": "^1.1.2",
+ "subscriptions-transport-ws": "^0.9.18"
+ }
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -388,6 +400,12 @@
"integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
"dev": true
},
+ "@n1ru4l/push-pull-async-iterable-iterator": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@n1ru4l/push-pull-async-iterable-iterator/-/push-pull-async-iterable-iterator-2.1.2.tgz",
+ "integrity": "sha512-KwZGeX2XK7Xj9ksWwei5923QnqIGoEuLlh3O46OW9vc8hQxjzmMTKCgJMVZ5ne5xaWFQYDT2dMpbUhq6hEOhxA==",
+ "dev": true
+ },
"@netflix/nerror": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.3.tgz",
@@ -695,11 +713,12 @@
}
},
"@types/ws": {
- "version": "0.0.38",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-0.0.38.tgz",
- "integrity": "sha1-QhBv/0tCLKlWc04p8Nc6bYkxlNM=",
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-5.1.2.tgz",
+ "integrity": "sha512-NkTXUKTYdXdnPE2aUUbGOXE1XfMK527SCvU/9bj86kyFF6kZ9ZnOQ3mK5jADn98Y2vEUD/7wKDgZa7Qst2wYOg==",
"dev": true,
"requires": {
+ "@types/events": "*",
"@types/node": "*"
}
},
@@ -991,6 +1010,12 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
+ "async-limiter": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "dev": true
+ },
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -1275,19 +1300,19 @@
}
},
"codemirror": {
- "version": "5.58.2",
- "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.58.2.tgz",
- "integrity": "sha512-K/hOh24cCwRutd1Mk3uLtjWzNISOkm4fvXiMO7LucCrqbh6aJDdtqUziim3MZUI6wOY0rvY1SlL1Ork01uMy6w==",
+ "version": "5.60.0",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.60.0.tgz",
+ "integrity": "sha512-AEL7LhFOlxPlCL8IdTcJDblJm8yrAGib7I+DErJPdZd4l6imx8IMgKK3RblVgBQqz3TZJR4oknQ03bz+uNjBYA==",
"dev": true
},
"codemirror-graphql": {
- "version": "0.12.3",
- "resolved": "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-0.12.3.tgz",
- "integrity": "sha512-u0TooVA2MWGNV+Bio89RCTRW9P5FqegB1V9rnz9I0QKoGXX/c9z9/Fc+nj18p8jxkWK8ii8d7hkz7vsNsHxdkw==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/codemirror-graphql/-/codemirror-graphql-1.0.1.tgz",
+ "integrity": "sha512-5ttMpv2kMn99Rmf2aZ5P6/hMd3y11cN8LP/x5MUeF0ipcalZA/GE/OxxXkhV0YJE/uW5QIcPyZDkvtSsGZa23A==",
"dev": true,
"requires": {
- "graphql-language-service-interface": "^2.4.2",
- "graphql-language-service-parser": "^1.6.4"
+ "graphql-language-service-interface": "^2.8.2",
+ "graphql-language-service-parser": "^1.9.0"
}
},
"color-convert": {
@@ -2102,6 +2127,12 @@
}
}
},
+ "dset": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.0.tgz",
+ "integrity": "sha512-7xTQ5DzyE59Nn+7ZgXDXjKAGSGmXZHqttMVVz1r4QNfmGpyj+cm2YtI3II0c/+4zS4a9yq2mBhgdeq2QnpcYlw==",
+ "dev": true
+ },
"dtrace-provider": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
@@ -2150,9 +2181,9 @@
}
},
"entities": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
- "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"dev": true
},
"error-ex": {
@@ -2532,9 +2563,9 @@
"dev": true
},
"eventemitter3": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
- "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"dev": true
},
"ewma": {
@@ -3021,16 +3052,39 @@
"dev": true
},
"graphiql": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/graphiql/-/graphiql-1.0.6.tgz",
- "integrity": "sha512-PgKEfWkXxU4Lx92eSEcLF/2en5bjGplxNwwLCKEQ82xU7t8wfj4UL46Zwx40E9LcxJum6KRfGzMjcY+bNwHzpQ==",
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/graphiql/-/graphiql-1.4.1.tgz",
+ "integrity": "sha512-C7S36lTgCw2/C/Dt90eJSI9VdxQfohrUoDV1dt/WecS7dm5HcaQUIYFqvLQMZG1cSRJttRKwNwP1rYfs73v8SQ==",
"dev": true,
"requires": {
+ "@graphiql/toolkit": "^0.2.0",
"codemirror": "^5.54.0",
- "codemirror-graphql": "^0.12.3",
+ "codemirror-graphql": "^1.0.0",
"copy-to-clipboard": "^3.2.0",
+ "dset": "^3.1.0",
"entities": "^2.0.0",
+ "graphql-language-service": "^3.1.2",
"markdown-it": "^10.0.0"
+ },
+ "dependencies": {
+ "@graphiql/toolkit": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@graphiql/toolkit/-/toolkit-0.2.0.tgz",
+ "integrity": "sha512-T8fdGSh1bYqpQUurIBnNbXHMOFqV/btTdlcAw3+snItA619GgZfc471lYIT95/cywxbH2Ync/gqGgeSTeZhlTg==",
+ "dev": true,
+ "requires": {
+ "@n1ru4l/push-pull-async-iterable-iterator": "^2.0.1",
+ "graphql-ws": "^4.3.2",
+ "meros": "^1.1.4",
+ "subscriptions-transport-ws": "^0.9.18"
+ }
+ },
+ "graphql-ws": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-4.4.0.tgz",
+ "integrity": "sha512-ZInnJEvEzgFUPUROhjaKH0wVUkUSz6mZY4ix/8QhTb6B4QlWtGtSMmVGG+uKPRi6YuMyoTwMnTcZTOSlC+gMAA==",
+ "dev": true
+ }
}
},
"graphiql-subscriptions-fetcher": {
@@ -3043,6 +3097,21 @@
"subscriptions-transport-ws": "0.5.4"
},
"dependencies": {
+ "@types/ws": {
+ "version": "0.0.38",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-0.0.38.tgz",
+ "integrity": "sha1-QhBv/0tCLKlWc04p8Nc6bYkxlNM=",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "eventemitter3": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
+ "integrity": "sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=",
+ "dev": true
+ },
"graphql": {
"version": "0.9.6",
"resolved": "https://registry.npmjs.org/graphql/-/graphql-0.9.6.tgz",
@@ -3051,6 +3120,32 @@
"requires": {
"iterall": "^1.0.0"
}
+ },
+ "subscriptions-transport-ws": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.5.4.tgz",
+ "integrity": "sha1-EJHlXnO/8NaRqGVwrCuX/2+zXPw=",
+ "dev": true,
+ "requires": {
+ "@types/ws": "0.0.38",
+ "backo2": "^1.0.2",
+ "eventemitter3": "^2.0.2",
+ "graphql-subscriptions": "^0.3.0",
+ "graphql-tag": "^1.2.4",
+ "lodash.isobject": "^3.0.2",
+ "lodash.isstring": "^4.0.1",
+ "ws": "^1.1.0"
+ }
+ },
+ "ws": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz",
+ "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==",
+ "dev": true,
+ "requires": {
+ "options": ">=0.0.5",
+ "ultron": "1.0.x"
+ }
}
}
},
@@ -3060,49 +3155,51 @@
"integrity": "sha512-EB3zgGchcabbsU9cFe1j+yxdzKQKAbGUWRb13DsrsMN1yyfmmIq+2+L5MqVWcDCE4V89R5AyUOi7sMOGxdsYtA==",
"dev": true
},
+ "graphql-language-service": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/graphql-language-service/-/graphql-language-service-3.1.3.tgz",
+ "integrity": "sha512-MTJT8QOpsJbG68wbkrmitlctvaajrQkJEN24AW+KzNxHWFEHnnqil6fFbVccHkRbG3Bk7D0f57fjtffSh37aEw==",
+ "dev": true,
+ "requires": {
+ "graphql-language-service-interface": "^2.8.2",
+ "graphql-language-service-types": "^1.8.0"
+ }
+ },
"graphql-language-service-interface": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.4.2.tgz",
- "integrity": "sha512-iFLMz51cA2L5Tu7/mP19++bRGUuIe2J9ekQZrcJ6sMYStsF60x5eNu3JqheduYTLhQaSdKN55jX7RlLeIDUhQA==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.8.3.tgz",
+ "integrity": "sha512-Gh4Q3dlCT1MrZGO0eaz7v31gkp8fh+ig94YH/A+1Th2q+k3RsRqfSJm5tKZ8TJ4rSADZ/dj+hzOpWCGzLyCiHQ==",
"dev": true,
"requires": {
- "graphql-language-service-parser": "^1.6.4",
- "graphql-language-service-types": "^1.6.3",
- "graphql-language-service-utils": "^2.4.3",
+ "graphql-language-service-parser": "^1.9.0",
+ "graphql-language-service-types": "^1.8.0",
+ "graphql-language-service-utils": "^2.5.1",
"vscode-languageserver-types": "^3.15.1"
}
},
"graphql-language-service-parser": {
- "version": "1.6.4",
- "resolved": "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.6.4.tgz",
- "integrity": "sha512-Y365zUFfJ1GJ9NeRHb5Z/HBo6EnbuTi187Gkuldwd1YIDc0QcD7kqz6U5g043zd7BI/UZQth13Zd7pElvbb2zw==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.9.1.tgz",
+ "integrity": "sha512-GySsDrYxzxu6r1vF282xXDR2KlfVL5aOW7pgc75fF3UFiuqGm/SeoIljNM0mLpRl5KSxo1HNOxhkWoFBoy/h2w==",
"dev": true,
"requires": {
- "graphql-language-service-types": "^1.6.3",
- "typescript": "^3.9.5"
- },
- "dependencies": {
- "typescript": {
- "version": "3.9.7",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
- "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
- "dev": true
- }
+ "graphql-language-service-types": "^1.8.0"
}
},
"graphql-language-service-types": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.6.3.tgz",
- "integrity": "sha512-VDtBhdan1iSe7ad7+eBbsO5rrzWQpC6aV4SxSHEi8AtEQOFXpnL9Lq5jSaN8O02pGvAUr4wNUPu0oRU5g2XmVA==",
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.8.1.tgz",
+ "integrity": "sha512-IpYS0mEHEmRsFlq+loWCpSYYYizAID7Alri6GoFN1QqUdux+8rp1Tkp2NGsGDpDmm3Dbz5ojmJWzNWQGpuwveA==",
"dev": true
},
"graphql-language-service-utils": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.4.3.tgz",
- "integrity": "sha512-XSCMKsV4GuVSGdW8RJTpO/IJDMXgESDJLu67SAuXFXwfel84j1gWrsmBAUeu6Di6NUEoM9NOCEtJv3LbU+/8qw==",
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.5.2.tgz",
+ "integrity": "sha512-hXGd4ARhyD7WTmTwuYmCYo6BcY8FtTp+1JHLaUG0Q63k0NpZTuFuRZ+N7TSP9mcRb7labeozs3DYgaqStsDe1A==",
"dev": true,
"requires": {
- "graphql-language-service-types": "^1.6.3"
+ "graphql-language-service-types": "^1.8.0",
+ "nullthrows": "^1.0.0"
}
},
"graphql-subscriptions": {
@@ -3120,6 +3217,12 @@
"integrity": "sha1-ers6j9nzQV0HFjMU7SNwYceFt1k=",
"dev": true
},
+ "graphql-ws": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-4.1.2.tgz",
+ "integrity": "sha512-c/iOE4kGW6J5h9hmHWaYvgsjAQacioae3ZXvq3JDuVw8uXo3Tbmky71Fzn0+emSKRaRNL1jQuzYtRqFKge2PIw==",
+ "dev": true
+ },
"growl": {
"version": "1.10.5",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
@@ -3830,6 +3933,12 @@
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true
},
+ "meros": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/meros/-/meros-1.1.4.tgz",
+ "integrity": "sha512-E9ZXfK9iQfG9s73ars9qvvvbSIkJZF5yOo9j4tcwM5tN8mUKfj/EKN5PzOr3ZH0y5wL7dLAHw3RVEfpQV9Q7VQ==",
+ "dev": true
+ },
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@@ -4154,6 +4263,12 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
+ "nullthrows": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
+ "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==",
+ "dev": true
+ },
"nyc": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz",
@@ -5521,19 +5636,16 @@
"dev": true
},
"subscriptions-transport-ws": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.5.4.tgz",
- "integrity": "sha1-EJHlXnO/8NaRqGVwrCuX/2+zXPw=",
+ "version": "0.9.18",
+ "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.18.tgz",
+ "integrity": "sha512-tztzcBTNoEbuErsVQpTN2xUNN/efAZXyCyL5m3x4t6SKrEiTL2N8SaKWBFWM4u56pL79ULif3zjyeq+oV+nOaA==",
"dev": true,
"requires": {
- "@types/ws": "0.0.38",
"backo2": "^1.0.2",
- "eventemitter3": "^2.0.2",
- "graphql-subscriptions": "^0.3.0",
- "graphql-tag": "^1.2.4",
- "lodash.isobject": "^3.0.2",
- "lodash.isstring": "^4.0.1",
- "ws": "^1.1.0"
+ "eventemitter3": "^3.1.0",
+ "iterall": "^1.2.1",
+ "symbol-observable": "^1.0.4",
+ "ws": "^5.2.0"
}
},
"superagent": {
@@ -5614,6 +5726,12 @@
"has-flag": "^4.0.0"
}
},
+ "symbol-observable": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
+ "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
+ "dev": true
+ },
"table": {
"version": "5.4.6",
"resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
@@ -5875,9 +5993,9 @@
}
},
"vscode-languageserver-types": {
- "version": "3.15.1",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz",
- "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==",
+ "version": "3.16.0",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz",
+ "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==",
"dev": true
},
"vscode-uri": {
@@ -6038,13 +6156,12 @@
}
},
"ws": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz",
- "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==",
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
"dev": true,
"requires": {
- "options": ">=0.0.5",
- "ultron": "1.0.x"
+ "async-limiter": "~1.0.0"
}
},
"xdg-basedir": {
diff --git a/package.json b/package.json
index ef48d894..06e9a1f3 100644
--- a/package.json
+++ b/package.json
@@ -48,7 +48,9 @@
"check:spelling": "cspell '**/*'",
"check:integrations": "mocha --full-trace integrationTests/*-test.js",
"build:npm": "node resources/build-npm.js",
- "start": "node -r ./resources/register.js examples/index.ts"
+ "start": "node -r ./resources/register.js examples/index.ts",
+ "start:subscription": "node -r ./resources/register.js examples/index_subscription.ts",
+ "start:subscription_legacy": "node -r ./resources/register.js examples/index_subscription_legacy.ts"
},
"dependencies": {
"accepts": "^1.3.7",
@@ -57,6 +59,7 @@
"raw-body": "^2.4.1"
},
"devDependencies": {
+ "@graphiql/toolkit": "^0.1.0",
"@types/accepts": "1.3.5",
"@types/body-parser": "1.19.0",
"@types/chai": "4.2.14",
@@ -70,6 +73,7 @@
"@types/restify": "8.4.2",
"@types/sinon": "9.0.8",
"@types/supertest": "2.0.10",
+ "@types/ws": "5.1.2",
"@typescript-eslint/eslint-plugin": "4.8.1",
"@typescript-eslint/parser": "4.8.1",
"body-parser": "1.19.0",
@@ -83,9 +87,10 @@
"eslint-plugin-istanbul": "0.1.2",
"eslint-plugin-node": "11.1.0",
"express": "4.17.1",
- "graphiql": "1.0.6",
+ "graphiql": "^1.4.1",
"graphiql-subscriptions-fetcher": "0.0.2",
"graphql": "15.4.0",
+ "graphql-ws": "4.1.2",
"mocha": "8.2.1",
"multer": "1.4.2",
"nyc": "15.1.0",
@@ -95,11 +100,12 @@
"react-dom": "16.14.0",
"restify": "8.5.1",
"sinon": "9.2.1",
- "subscriptions-transport-ws": "0.5.4",
+ "subscriptions-transport-ws": "0.9.18",
"supertest": "6.0.1",
"ts-node": "9.0.0",
"typescript": "4.1.2",
- "unfetch": "4.2.0"
+ "unfetch": "4.2.0",
+ "ws": "5.2.2"
},
"peerDependencies": {
"graphql": "^14.7.0 || ^15.3.0"
diff --git a/src/__tests__/http-test.ts b/src/__tests__/http-test.ts
index 6a2b3218..d449e09b 100644
--- a/src/__tests__/http-test.ts
+++ b/src/__tests__/http-test.ts
@@ -2015,6 +2015,34 @@ function runTests(server: Server) {
// should contain the subscriptionEndpoint url
expect(response.text).to.include('ws:\\/\\/localhost');
});
+
+ it('contains subscriptionEndpoint within GraphiQL with websocketClient option', async () => {
+ const app = server();
+
+ app.get(
+ urlString(),
+ graphqlHTTP({
+ schema: TestSchema,
+ graphiql: {
+ subscriptionEndpoint: 'ws://localhost',
+ websocketClient: 'v1',
+ },
+ }),
+ );
+
+ const response = await app
+ .request()
+ .get(urlString())
+ .set('Accept', 'text/html');
+
+ expect(response.status).to.equal(200);
+ expect(response.type).to.equal('text/html');
+ // should contain graphql-ws browser client
+ expect(response.text).to.include('graphql-transport-ws');
+
+ // should contain the subscriptionEndpoint url
+ expect(response.text).to.include('ws:\\/\\/localhost');
+ });
});
describe('Custom validate function', () => {
diff --git a/src/renderGraphiQL.ts b/src/renderGraphiQL.ts
index df5b0a0c..f700e746 100644
--- a/src/renderGraphiQL.ts
+++ b/src/renderGraphiQL.ts
@@ -25,6 +25,13 @@ export interface GraphiQLOptions {
* A websocket endpoint for subscription
*/
subscriptionEndpoint?: string;
+
+ /**
+ * websocket client option for subscription, defaults to v0
+ * v0: subscriptions-transport-ws
+ * v1: graphql-ws
+ */
+ websocketClient?: string;
}
// Ensures string values are safe to be used within a
+
-
- `;
+
+ `;
+ } else {
+ subscriptionScripts = `
+
+
+
+ `;
+ }
}
return `