├── .editorconfig
├── .gitignore
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── Demo.ts
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── src
├── FastifyGraphQL.ts
├── GraphQLPlugin.ts
├── GraphiQLPlugin.ts
└── Typings.d.ts
├── test
├── FastifyGraphql.test.ts
└── apollo-server-integration-testsuite.ts
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = false
9 | insert_final_newline = false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | .vscode
61 | jsconfig.json
62 |
63 | out
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | src
3 | test
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | - "6"
5 |
6 | cache:
7 | yarn: true
8 |
9 | deploy:
10 | provider: npm
11 | email: sirsavary@outlook.com
12 | api_key: $NPM_TOKEN
13 | skip_cleanup: true
14 | on:
15 | tags: true
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 |
6 | # [4.0.0](https://github.com/sirsavary/fastify-graphql/compare/v3.1.11...v4.0.0) (2018-03-05)
7 |
8 |
9 | ### Bug Fixes
10 |
11 | * **travis:** don't test releases that are unsupported by fastify ([e1432c2](https://github.com/sirsavary/fastify-graphql/commit/e1432c2))
12 |
13 |
14 | ### BREAKING CHANGES
15 |
16 | * **travis:** users running node v4 or v5 will no longer be able to use this module (or fastify)
17 |
18 |
19 |
20 |
21 | ## [3.1.11](https://github.com/sirsavary/fastify-graphql/compare/v3.1.10...v3.1.11) (2018-03-05)
22 |
23 |
24 | ### Bug Fixes
25 |
26 | * test command not running anything ([e1b680e](https://github.com/sirsavary/fastify-graphql/commit/e1b680e))
27 |
28 |
29 |
30 |
31 | ## [3.1.10](https://github.com/sirsavary/fastify-graphql/compare/v3.1.9...v3.1.10) (2018-03-03)
32 |
33 |
34 | ### Bug Fixes
35 |
36 | * **readme:** Update links to apollo-server documentation ([7061f6d](https://github.com/sirsavary/fastify-graphql/commit/7061f6d))
37 |
38 |
39 |
40 |
41 | ## [3.1.9](https://github.com/sirsavary/fastify-graphql/compare/v3.1.8...v3.1.9) (2018-02-16)
42 |
43 |
44 |
45 |
46 | ## [3.1.8](https://github.com/sirsavary/fastify-graphql/compare/v3.1.7...v3.1.8) (2018-02-16)
47 |
48 |
49 |
50 |
51 | ## [3.1.7](https://github.com/sirsavary/fastify-graphql/compare/v3.1.6...v3.1.7) (2018-01-31)
52 |
53 |
54 | ### Bug Fixes
55 |
56 | * fixed Travis not deploying compiled Typescript files ([3be965e](https://github.com/sirsavary/fastify-graphql/commit/3be965e))
57 |
58 |
59 |
60 |
61 | ## [3.1.6](https://github.com/sirsavary/fastify-graphql/compare/v3.1.5...v3.1.6) (2018-01-31)
62 |
63 |
64 |
65 |
66 | ## [3.1.5](https://github.com/sirsavary/fastify-graphql/compare/v3.1.4...v3.1.5) (2018-01-31)
67 |
68 |
69 | ### Bug Fixes
70 |
71 | * Prepare runs before NPM deploy, no need for Travis to run it ([f20ec9b](https://github.com/sirsavary/fastify-graphql/commit/f20ec9b))
72 |
73 |
74 |
75 |
76 | ## [3.1.4](https://github.com/sirsavary/fastify-graphql/compare/v3.1.3...v3.1.4) (2018-01-31)
77 |
78 |
79 | ### Bug Fixes
80 |
81 | * Travis no longer references the old build script ([1db22ec](https://github.com/sirsavary/fastify-graphql/commit/1db22ec))
82 |
83 |
84 |
85 |
86 | ## [3.1.3](https://github.com/sirsavary/fastify-graphql/compare/v3.1.2...v3.1.3) (2018-01-31)
87 |
88 |
89 | ### Bug Fixes
90 |
91 | * prepare really is the proper name for a build script ([fefc9a9](https://github.com/sirsavary/fastify-graphql/commit/fefc9a9))
92 |
93 |
94 |
95 |
96 | ## [3.1.2](https://github.com/sirsavary/fastify-graphql/compare/v3.1.1...v3.1.2) (2018-01-31)
97 |
98 |
99 | ### Bug Fixes
100 |
101 | * attempt to fix Travis not compiling our Typescript ([6295e68](https://github.com/sirsavary/fastify-graphql/commit/6295e68))
102 |
103 |
104 |
105 |
106 | ## [3.1.1](https://github.com/sirsavary/fastify-graphql/compare/v3.1.0...v3.1.1) (2018-01-31)
107 |
108 |
109 | ### Bug Fixes
110 |
111 | * have Travis cache Yarn downloads ([5f2af8e](https://github.com/sirsavary/fastify-graphql/commit/5f2af8e))
112 |
113 |
114 |
115 |
116 | # [3.1.0](https://github.com/sirsavary/fastify-graphql/compare/v0.1.1...v3.1.0) (2018-01-31)
117 |
118 |
119 | ### Features
120 |
121 | * improve CI, add automated deployments ([e751ca9](https://github.com/sirsavary/fastify-graphql/commit/e751ca9))
122 |
--------------------------------------------------------------------------------
/Demo.ts:
--------------------------------------------------------------------------------
1 | import {createFastifyApp, createGQLSchema} from "./test/TestUtils";
2 |
3 | createFastifyApp(createGQLSchema()).listen(3000, (err) => {
4 | if (err) console.error(err);
5 | });
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Nickolena Coop
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fastify-graphql
2 | [](https://travis-ci.org/sirsavary/fastify-graphql)
3 | [](https://www.npmjs.com/package/fastify-graphql)
4 | [](https://conventionalcommits.org)
5 |
6 | A plugin for [Fastify](https://github.com/fastify/fastify) that adds GraphQL and GraphiQL support.
7 |
8 | This project was forked from [fastify-apollo](https://github.com/coopnd/fastify-apollo) as it is no longer being maintained fast enough to keep pace with the rapid changes happening in the GraphQL ecosystem.
9 |
10 | ## Installation
11 | ```bash
12 | npm install --save fastify-graphql graphql
13 | ```
14 |
15 | or
16 |
17 | ```bash
18 | yarn add fastify-graphql graphql
19 | ```
20 |
21 | ## Usage
22 | ```js
23 | const Fastify = require('fastify');
24 | const app = Fastify();
25 |
26 | const {graphiqlFastify, graphqlFastify} = require('fastify-graphql');
27 | app.register(graphqlFastify, {
28 | prefix: '/graphql',
29 | graphql: {
30 | schema: your_graphql_schema,
31 | },
32 | });
33 | app.register(graphiqlFastify, {
34 | prefix: '/graphiql',
35 | graphiql: {
36 | endpointURL: '/graphql',
37 | }
38 | });
39 | ```
40 |
41 | ## Configuration
42 |
43 | Both plugins need to be given a prefix, under which they will mount.
44 |
45 | GraphQL settings extends [GraphQLServerOptions](https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-core/src/graphqlOptions.ts#L9-L37)
46 |
47 | GraphiQL settings extends [GraphiQLData](https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-module-graphiql/src/renderGraphiQL.ts#L9-L33)
48 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fastify-graphql",
3 | "version": "4.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@types/chai": {
8 | "version": "4.1.2",
9 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.2.tgz",
10 | "integrity": "sha512-D8uQwKYUw2KESkorZ27ykzXgvkDJYXVEihGklgfp5I4HUP8D6IxtcdLTMB1emjQiWzV7WZ5ihm1cxIzVwjoleQ==",
11 | "dev": true
12 | },
13 | "@types/events": {
14 | "version": "1.2.0",
15 | "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
16 | "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
17 | "dev": true
18 | },
19 | "@types/node": {
20 | "version": "10.3.1",
21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.3.1.tgz",
22 | "integrity": "sha512-IsX9aDHDzJohkm3VCDB8tkzl5RQ34E/PFA29TQk6uDGb7Oc869ZBtmdKVDBzY3+h9GnXB8ssrRXEPVZrlIOPOw==",
23 | "dev": true
24 | },
25 | "@types/pino": {
26 | "version": "4.16.0",
27 | "resolved": "https://registry.npmjs.org/@types/pino/-/pino-4.16.0.tgz",
28 | "integrity": "sha512-RP7YA3r9nhrLJHidgygV8IdNmkBIivZmYamKgUKjuUF8qfO+eENo8HImNbs8v/Ns4nqBcu7gGmBoIIn8Hbwilw==",
29 | "dev": true,
30 | "requires": {
31 | "@types/events": "*",
32 | "@types/node": "*"
33 | }
34 | },
35 | "abstract-logging": {
36 | "version": "1.0.0",
37 | "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-1.0.0.tgz",
38 | "integrity": "sha1-i33q/TEFWbwo93ck3RuzAXcnjBs=",
39 | "dev": true
40 | },
41 | "ajv": {
42 | "version": "6.5.0",
43 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.0.tgz",
44 | "integrity": "sha512-VDUX1oSajablmiyFyED9L1DFndg0P9h7p1F+NO8FkIzei6EPrR6Zu1n18rd5P8PqaSRd/FrWv3G1TVBqpM83gA==",
45 | "dev": true,
46 | "requires": {
47 | "fast-deep-equal": "^2.0.1",
48 | "fast-json-stable-stringify": "^2.0.0",
49 | "json-schema-traverse": "^0.3.0",
50 | "uri-js": "^4.2.1"
51 | }
52 | },
53 | "ansi-styles": {
54 | "version": "3.2.1",
55 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
56 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
57 | "dev": true,
58 | "requires": {
59 | "color-convert": "^1.9.0"
60 | }
61 | },
62 | "apollo-cache-control": {
63 | "version": "0.0.9",
64 | "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.0.9.tgz",
65 | "integrity": "sha512-bspKyM9gBDxv2nnKPSErzzZiSOdvRXnHwS/3gwBucZG1Dz5U4H6xyPtCx754/YfRto1yT9bUMc7vW85jJ/acOA==",
66 | "requires": {
67 | "graphql-extensions": "^0.0.x"
68 | }
69 | },
70 | "apollo-server-core": {
71 | "version": "1.3.2",
72 | "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-1.3.2.tgz",
73 | "integrity": "sha1-82hVo+vcLXe4ucRUOAvx1wYQX/w=",
74 | "requires": {
75 | "apollo-cache-control": "^0.0.x",
76 | "apollo-tracing": "^0.1.0",
77 | "graphql-extensions": "^0.0.x"
78 | }
79 | },
80 | "apollo-server-module-graphiql": {
81 | "version": "1.3.2",
82 | "resolved": "https://registry.npmjs.org/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.3.2.tgz",
83 | "integrity": "sha1-Cp5MSN7OOvkE/uMz+V97mBczXKc="
84 | },
85 | "apollo-tracing": {
86 | "version": "0.1.3",
87 | "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.1.3.tgz",
88 | "integrity": "sha512-LZhSDL4oe9iNkedzJk6tQ6zLXmw/lwCvB0HDZyJjdp8rqrW+RN0Fk6MmZtNq9Z0olwOUh8EN3vIpzLwR3CJTrw==",
89 | "requires": {
90 | "graphql-extensions": "^0.0.x"
91 | }
92 | },
93 | "assertion-error": {
94 | "version": "1.1.0",
95 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
96 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
97 | "dev": true
98 | },
99 | "avvio": {
100 | "version": "5.4.3",
101 | "resolved": "https://registry.npmjs.org/avvio/-/avvio-5.4.3.tgz",
102 | "integrity": "sha512-rsBXDzL8WxRysiY+V17TJGOMYuufN/xsVkbCEoITyguA/O4pGJ4t2oW9JJAJcZOir3YodyPdMcwsj36z9RpLgw==",
103 | "dev": true,
104 | "requires": {
105 | "debug": "^3.1.0",
106 | "fastq": "^1.5.0"
107 | }
108 | },
109 | "chai": {
110 | "version": "4.1.2",
111 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
112 | "integrity": "sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw=",
113 | "dev": true,
114 | "requires": {
115 | "assertion-error": "^1.0.1",
116 | "check-error": "^1.0.1",
117 | "deep-eql": "^3.0.0",
118 | "get-func-name": "^2.0.0",
119 | "pathval": "^1.0.0",
120 | "type-detect": "^4.0.0"
121 | }
122 | },
123 | "chai-graphql": {
124 | "version": "4.0.0",
125 | "resolved": "https://registry.npmjs.org/chai-graphql/-/chai-graphql-4.0.0.tgz",
126 | "integrity": "sha512-CvgtShjnUEsW3lVNiCSwjXOycYRurvyBPqfIQL9PRmqJF3KvmCJId13RQb0h0EZKwjGCws+Pgbduqn3lT33vlg==",
127 | "dev": true,
128 | "requires": {
129 | "check-error": "^1.0.2"
130 | }
131 | },
132 | "chalk": {
133 | "version": "2.4.1",
134 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
135 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
136 | "dev": true,
137 | "requires": {
138 | "ansi-styles": "^3.2.1",
139 | "escape-string-regexp": "^1.0.5",
140 | "supports-color": "^5.3.0"
141 | }
142 | },
143 | "check-error": {
144 | "version": "1.0.2",
145 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
146 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
147 | "dev": true
148 | },
149 | "color-convert": {
150 | "version": "1.9.1",
151 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
152 | "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
153 | "dev": true,
154 | "requires": {
155 | "color-name": "^1.1.1"
156 | }
157 | },
158 | "color-name": {
159 | "version": "1.1.3",
160 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
161 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
162 | "dev": true
163 | },
164 | "core-js": {
165 | "version": "2.5.3",
166 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz",
167 | "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4="
168 | },
169 | "core-util-is": {
170 | "version": "1.0.2",
171 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
172 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
173 | "dev": true
174 | },
175 | "debug": {
176 | "version": "3.1.0",
177 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
178 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
179 | "dev": true,
180 | "requires": {
181 | "ms": "2.0.0"
182 | }
183 | },
184 | "deep-eql": {
185 | "version": "3.0.1",
186 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
187 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
188 | "dev": true,
189 | "requires": {
190 | "type-detect": "^4.0.0"
191 | }
192 | },
193 | "deepmerge": {
194 | "version": "2.1.1",
195 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz",
196 | "integrity": "sha512-urQxA1smbLZ2cBbXbaYObM1dJ82aJ2H57A1C/Kklfh/ZN1bgH4G/n5KWhdNfOK11W98gqZfyYj7W4frJJRwA2w==",
197 | "dev": true
198 | },
199 | "end-of-stream": {
200 | "version": "1.4.1",
201 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
202 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
203 | "dev": true,
204 | "requires": {
205 | "once": "^1.4.0"
206 | }
207 | },
208 | "escape-string-regexp": {
209 | "version": "1.0.5",
210 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
211 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
212 | "dev": true
213 | },
214 | "fast-decode-uri-component": {
215 | "version": "1.0.0",
216 | "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.0.tgz",
217 | "integrity": "sha512-WQSYVKn6tDW/3htASeUkrx5LcnuTENQIZQPCVlwdnvIJ7bYtSpoJYq38MgUJnx1CQIR1gjZ8HJxAEcN4gqugBg==",
218 | "dev": true
219 | },
220 | "fast-deep-equal": {
221 | "version": "2.0.1",
222 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
223 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
224 | "dev": true
225 | },
226 | "fast-json-parse": {
227 | "version": "1.0.3",
228 | "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz",
229 | "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==",
230 | "dev": true
231 | },
232 | "fast-json-stable-stringify": {
233 | "version": "2.0.0",
234 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
235 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
236 | "dev": true
237 | },
238 | "fast-json-stringify": {
239 | "version": "1.5.4",
240 | "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-1.5.4.tgz",
241 | "integrity": "sha512-rasizCB0oTM1OORpgt37bEuRHI3i5UYkG9BHhhopPEb9ZJ9UsU5v8uFnA4Dpl6xXfBP+uFFyIwHbJDUfJU5eiw==",
242 | "dev": true,
243 | "requires": {
244 | "ajv": "^6.5.0",
245 | "deepmerge": "^2.1.0"
246 | }
247 | },
248 | "fast-safe-stringify": {
249 | "version": "1.2.3",
250 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-1.2.3.tgz",
251 | "integrity": "sha512-QJYT/i0QYoiZBQ71ivxdyTqkwKkQ0oxACXHYxH2zYHJEgzi2LsbjgvtzTbLi1SZcF190Db2YP7I7eTsU2egOlw==",
252 | "dev": true
253 | },
254 | "fastify": {
255 | "version": "1.5.0",
256 | "resolved": "https://registry.npmjs.org/fastify/-/fastify-1.5.0.tgz",
257 | "integrity": "sha512-X/foUNk5FF1dfnFxwjSzZY/ZDyaWM6QM78T+YFTErkfJ2vZ56DHmHgPiMwa6I8MNvC1/LiOHKzxX8WoIBm+AcQ==",
258 | "dev": true,
259 | "requires": {
260 | "@types/pino": "^4.7.1",
261 | "abstract-logging": "^1.0.0",
262 | "ajv": "^6.4.0",
263 | "avvio": "^5.4.3",
264 | "end-of-stream": "^1.4.1",
265 | "fast-json-stringify": "^1.5.2",
266 | "find-my-way": "^1.12.0",
267 | "flatstr": "^1.0.5",
268 | "light-my-request": "^2.0.2",
269 | "middie": "^3.1.0",
270 | "pino": "^4.16.1",
271 | "tiny-lru": "^1.5.2"
272 | }
273 | },
274 | "fastify-plugin": {
275 | "version": "0.2.2",
276 | "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-0.2.2.tgz",
277 | "integrity": "sha512-oRJdjdudgCkQQUARNeh2rkbxFAmj2OhCJSVBNBLUbhS0orF+IMQ4u/bc661N1jh/wDI2J+YKmXmmHSVFQI4e7A==",
278 | "requires": {
279 | "semver": "^5.4.1"
280 | }
281 | },
282 | "fastq": {
283 | "version": "1.6.0",
284 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
285 | "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==",
286 | "dev": true,
287 | "requires": {
288 | "reusify": "^1.0.0"
289 | }
290 | },
291 | "find-my-way": {
292 | "version": "1.13.0",
293 | "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-1.13.0.tgz",
294 | "integrity": "sha512-aIa4UTxZ3klfApaQEJJ5cQvNeqfrxVngcjMgy+G5ygkrOrDPkORhY/RMH6F8mLwBpPt3Z0F03CtzN7gs2Q5H1w==",
295 | "dev": true,
296 | "requires": {
297 | "fast-decode-uri-component": "^1.0.0",
298 | "safe-regex": "^1.1.0"
299 | }
300 | },
301 | "flatstr": {
302 | "version": "1.0.8",
303 | "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.8.tgz",
304 | "integrity": "sha512-YXblbv/vc1zuVVUtnKl1hPqqk7TalZCppnKE7Pr8FI/Rp48vzckS/4SJ4Y9O9RNiI82Vcw/FydmtqdQOg1Dpqw==",
305 | "dev": true
306 | },
307 | "get-func-name": {
308 | "version": "2.0.0",
309 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
310 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
311 | "dev": true
312 | },
313 | "graphql": {
314 | "version": "0.12.3",
315 | "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.12.3.tgz",
316 | "integrity": "sha512-Hn9rdu4zacplKXNrLCvR8YFiTGnbM4Zw/UH8FDmzBDsH7ou40lSNH4tIlsxcYnz2TGNVJCpu1WxCM23yd6kzhA==",
317 | "dev": true,
318 | "requires": {
319 | "iterall": "1.1.3"
320 | }
321 | },
322 | "graphql-extensions": {
323 | "version": "0.0.7",
324 | "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.0.7.tgz",
325 | "integrity": "sha512-OQQeBySD16f+1JWx6RJ3u7p3zQd0eg/tEvSxwiB7B+nc68SJk77Cd1GtkOusJ52MDtCmD5ybwcoLjU9mNCw6nA==",
326 | "requires": {
327 | "core-js": "^2.5.3",
328 | "source-map-support": "^0.5.1"
329 | }
330 | },
331 | "has-flag": {
332 | "version": "3.0.0",
333 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
334 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
335 | "dev": true
336 | },
337 | "inherits": {
338 | "version": "2.0.3",
339 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
340 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
341 | "dev": true
342 | },
343 | "isarray": {
344 | "version": "1.0.0",
345 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
346 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
347 | "dev": true
348 | },
349 | "iterall": {
350 | "version": "1.1.3",
351 | "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz",
352 | "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==",
353 | "dev": true
354 | },
355 | "json-schema-traverse": {
356 | "version": "0.3.1",
357 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
358 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
359 | "dev": true
360 | },
361 | "light-my-request": {
362 | "version": "2.0.2",
363 | "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-2.0.2.tgz",
364 | "integrity": "sha512-e7863fgFyGZ2dbz0ag9AdkFjrQcnEdDFu4lwMeIbDWAW9PcL+zS75WPCkbWstM2jU6WR7/E8ZMjxUVJtCQtrLw==",
365 | "dev": true,
366 | "requires": {
367 | "ajv": "^6.0.0",
368 | "readable-stream": "^2.3.3",
369 | "safe-buffer": "^5.1.1"
370 | }
371 | },
372 | "middie": {
373 | "version": "3.1.0",
374 | "resolved": "https://registry.npmjs.org/middie/-/middie-3.1.0.tgz",
375 | "integrity": "sha512-673tjCpr9xbI30cVqNbCvBe1hNS4pNs7Fi8Yp9wPiqX3qTpuRm87uD3aRtH9ji7Gt8SavbX7cwYMqY2muIPMJw==",
376 | "dev": true,
377 | "requires": {
378 | "path-to-regexp": "^2.0.0",
379 | "reusify": "^1.0.2"
380 | }
381 | },
382 | "ms": {
383 | "version": "2.0.0",
384 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
385 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
386 | "dev": true
387 | },
388 | "nyc": {
389 | "version": "11.4.1",
390 | "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.4.1.tgz",
391 | "integrity": "sha512-5eCZpvaksFVjP2rt1r60cfXmt3MUtsQDw8bAzNqNEr4WLvUMLgiVENMf/B9bE9YAX0mGVvaGA3v9IS9ekNqB1Q==",
392 | "dev": true,
393 | "requires": {
394 | "archy": "^1.0.0",
395 | "arrify": "^1.0.1",
396 | "caching-transform": "^1.0.0",
397 | "convert-source-map": "^1.3.0",
398 | "debug-log": "^1.0.1",
399 | "default-require-extensions": "^1.0.0",
400 | "find-cache-dir": "^0.1.1",
401 | "find-up": "^2.1.0",
402 | "foreground-child": "^1.5.3",
403 | "glob": "^7.0.6",
404 | "istanbul-lib-coverage": "^1.1.1",
405 | "istanbul-lib-hook": "^1.1.0",
406 | "istanbul-lib-instrument": "^1.9.1",
407 | "istanbul-lib-report": "^1.1.2",
408 | "istanbul-lib-source-maps": "^1.2.2",
409 | "istanbul-reports": "^1.1.3",
410 | "md5-hex": "^1.2.0",
411 | "merge-source-map": "^1.0.2",
412 | "micromatch": "^2.3.11",
413 | "mkdirp": "^0.5.0",
414 | "resolve-from": "^2.0.0",
415 | "rimraf": "^2.5.4",
416 | "signal-exit": "^3.0.1",
417 | "spawn-wrap": "^1.4.2",
418 | "test-exclude": "^4.1.1",
419 | "yargs": "^10.0.3",
420 | "yargs-parser": "^8.0.0"
421 | },
422 | "dependencies": {
423 | "align-text": {
424 | "version": "0.1.4",
425 | "bundled": true,
426 | "dev": true,
427 | "requires": {
428 | "kind-of": "^3.0.2",
429 | "longest": "^1.0.1",
430 | "repeat-string": "^1.5.2"
431 | }
432 | },
433 | "amdefine": {
434 | "version": "1.0.1",
435 | "bundled": true,
436 | "dev": true
437 | },
438 | "ansi-regex": {
439 | "version": "2.1.1",
440 | "bundled": true,
441 | "dev": true
442 | },
443 | "ansi-styles": {
444 | "version": "2.2.1",
445 | "bundled": true,
446 | "dev": true
447 | },
448 | "append-transform": {
449 | "version": "0.4.0",
450 | "bundled": true,
451 | "dev": true,
452 | "requires": {
453 | "default-require-extensions": "^1.0.0"
454 | }
455 | },
456 | "archy": {
457 | "version": "1.0.0",
458 | "bundled": true,
459 | "dev": true
460 | },
461 | "arr-diff": {
462 | "version": "2.0.0",
463 | "bundled": true,
464 | "dev": true,
465 | "requires": {
466 | "arr-flatten": "^1.0.1"
467 | }
468 | },
469 | "arr-flatten": {
470 | "version": "1.1.0",
471 | "bundled": true,
472 | "dev": true
473 | },
474 | "array-unique": {
475 | "version": "0.2.1",
476 | "bundled": true,
477 | "dev": true
478 | },
479 | "arrify": {
480 | "version": "1.0.1",
481 | "bundled": true,
482 | "dev": true
483 | },
484 | "async": {
485 | "version": "1.5.2",
486 | "bundled": true,
487 | "dev": true
488 | },
489 | "babel-code-frame": {
490 | "version": "6.26.0",
491 | "bundled": true,
492 | "dev": true,
493 | "requires": {
494 | "chalk": "^1.1.3",
495 | "esutils": "^2.0.2",
496 | "js-tokens": "^3.0.2"
497 | }
498 | },
499 | "babel-generator": {
500 | "version": "6.26.0",
501 | "bundled": true,
502 | "dev": true,
503 | "requires": {
504 | "babel-messages": "^6.23.0",
505 | "babel-runtime": "^6.26.0",
506 | "babel-types": "^6.26.0",
507 | "detect-indent": "^4.0.0",
508 | "jsesc": "^1.3.0",
509 | "lodash": "^4.17.4",
510 | "source-map": "^0.5.6",
511 | "trim-right": "^1.0.1"
512 | }
513 | },
514 | "babel-messages": {
515 | "version": "6.23.0",
516 | "bundled": true,
517 | "dev": true,
518 | "requires": {
519 | "babel-runtime": "^6.22.0"
520 | }
521 | },
522 | "babel-runtime": {
523 | "version": "6.26.0",
524 | "bundled": true,
525 | "dev": true,
526 | "requires": {
527 | "core-js": "^2.4.0",
528 | "regenerator-runtime": "^0.11.0"
529 | }
530 | },
531 | "babel-template": {
532 | "version": "6.26.0",
533 | "bundled": true,
534 | "dev": true,
535 | "requires": {
536 | "babel-runtime": "^6.26.0",
537 | "babel-traverse": "^6.26.0",
538 | "babel-types": "^6.26.0",
539 | "babylon": "^6.18.0",
540 | "lodash": "^4.17.4"
541 | }
542 | },
543 | "babel-traverse": {
544 | "version": "6.26.0",
545 | "bundled": true,
546 | "dev": true,
547 | "requires": {
548 | "babel-code-frame": "^6.26.0",
549 | "babel-messages": "^6.23.0",
550 | "babel-runtime": "^6.26.0",
551 | "babel-types": "^6.26.0",
552 | "babylon": "^6.18.0",
553 | "debug": "^2.6.8",
554 | "globals": "^9.18.0",
555 | "invariant": "^2.2.2",
556 | "lodash": "^4.17.4"
557 | }
558 | },
559 | "babel-types": {
560 | "version": "6.26.0",
561 | "bundled": true,
562 | "dev": true,
563 | "requires": {
564 | "babel-runtime": "^6.26.0",
565 | "esutils": "^2.0.2",
566 | "lodash": "^4.17.4",
567 | "to-fast-properties": "^1.0.3"
568 | }
569 | },
570 | "babylon": {
571 | "version": "6.18.0",
572 | "bundled": true,
573 | "dev": true
574 | },
575 | "balanced-match": {
576 | "version": "1.0.0",
577 | "bundled": true,
578 | "dev": true
579 | },
580 | "brace-expansion": {
581 | "version": "1.1.8",
582 | "bundled": true,
583 | "dev": true,
584 | "requires": {
585 | "balanced-match": "^1.0.0",
586 | "concat-map": "0.0.1"
587 | }
588 | },
589 | "braces": {
590 | "version": "1.8.5",
591 | "bundled": true,
592 | "dev": true,
593 | "requires": {
594 | "expand-range": "^1.8.1",
595 | "preserve": "^0.2.0",
596 | "repeat-element": "^1.1.2"
597 | }
598 | },
599 | "builtin-modules": {
600 | "version": "1.1.1",
601 | "bundled": true,
602 | "dev": true
603 | },
604 | "caching-transform": {
605 | "version": "1.0.1",
606 | "bundled": true,
607 | "dev": true,
608 | "requires": {
609 | "md5-hex": "^1.2.0",
610 | "mkdirp": "^0.5.1",
611 | "write-file-atomic": "^1.1.4"
612 | }
613 | },
614 | "camelcase": {
615 | "version": "1.2.1",
616 | "bundled": true,
617 | "dev": true,
618 | "optional": true
619 | },
620 | "center-align": {
621 | "version": "0.1.3",
622 | "bundled": true,
623 | "dev": true,
624 | "optional": true,
625 | "requires": {
626 | "align-text": "^0.1.3",
627 | "lazy-cache": "^1.0.3"
628 | }
629 | },
630 | "chalk": {
631 | "version": "1.1.3",
632 | "bundled": true,
633 | "dev": true,
634 | "requires": {
635 | "ansi-styles": "^2.2.1",
636 | "escape-string-regexp": "^1.0.2",
637 | "has-ansi": "^2.0.0",
638 | "strip-ansi": "^3.0.0",
639 | "supports-color": "^2.0.0"
640 | }
641 | },
642 | "cliui": {
643 | "version": "2.1.0",
644 | "bundled": true,
645 | "dev": true,
646 | "optional": true,
647 | "requires": {
648 | "center-align": "^0.1.1",
649 | "right-align": "^0.1.1",
650 | "wordwrap": "0.0.2"
651 | },
652 | "dependencies": {
653 | "wordwrap": {
654 | "version": "0.0.2",
655 | "bundled": true,
656 | "dev": true,
657 | "optional": true
658 | }
659 | }
660 | },
661 | "code-point-at": {
662 | "version": "1.1.0",
663 | "bundled": true,
664 | "dev": true
665 | },
666 | "commondir": {
667 | "version": "1.0.1",
668 | "bundled": true,
669 | "dev": true
670 | },
671 | "concat-map": {
672 | "version": "0.0.1",
673 | "bundled": true,
674 | "dev": true
675 | },
676 | "convert-source-map": {
677 | "version": "1.5.1",
678 | "bundled": true,
679 | "dev": true
680 | },
681 | "core-js": {
682 | "version": "2.5.3",
683 | "bundled": true,
684 | "dev": true
685 | },
686 | "cross-spawn": {
687 | "version": "4.0.2",
688 | "bundled": true,
689 | "dev": true,
690 | "requires": {
691 | "lru-cache": "^4.0.1",
692 | "which": "^1.2.9"
693 | }
694 | },
695 | "debug": {
696 | "version": "2.6.9",
697 | "bundled": true,
698 | "dev": true,
699 | "requires": {
700 | "ms": "2.0.0"
701 | }
702 | },
703 | "debug-log": {
704 | "version": "1.0.1",
705 | "bundled": true,
706 | "dev": true
707 | },
708 | "decamelize": {
709 | "version": "1.2.0",
710 | "bundled": true,
711 | "dev": true
712 | },
713 | "default-require-extensions": {
714 | "version": "1.0.0",
715 | "bundled": true,
716 | "dev": true,
717 | "requires": {
718 | "strip-bom": "^2.0.0"
719 | }
720 | },
721 | "detect-indent": {
722 | "version": "4.0.0",
723 | "bundled": true,
724 | "dev": true,
725 | "requires": {
726 | "repeating": "^2.0.0"
727 | }
728 | },
729 | "error-ex": {
730 | "version": "1.3.1",
731 | "bundled": true,
732 | "dev": true,
733 | "requires": {
734 | "is-arrayish": "^0.2.1"
735 | }
736 | },
737 | "escape-string-regexp": {
738 | "version": "1.0.5",
739 | "bundled": true,
740 | "dev": true
741 | },
742 | "esutils": {
743 | "version": "2.0.2",
744 | "bundled": true,
745 | "dev": true
746 | },
747 | "execa": {
748 | "version": "0.7.0",
749 | "bundled": true,
750 | "dev": true,
751 | "requires": {
752 | "cross-spawn": "^5.0.1",
753 | "get-stream": "^3.0.0",
754 | "is-stream": "^1.1.0",
755 | "npm-run-path": "^2.0.0",
756 | "p-finally": "^1.0.0",
757 | "signal-exit": "^3.0.0",
758 | "strip-eof": "^1.0.0"
759 | },
760 | "dependencies": {
761 | "cross-spawn": {
762 | "version": "5.1.0",
763 | "bundled": true,
764 | "dev": true,
765 | "requires": {
766 | "lru-cache": "^4.0.1",
767 | "shebang-command": "^1.2.0",
768 | "which": "^1.2.9"
769 | }
770 | }
771 | }
772 | },
773 | "expand-brackets": {
774 | "version": "0.1.5",
775 | "bundled": true,
776 | "dev": true,
777 | "requires": {
778 | "is-posix-bracket": "^0.1.0"
779 | }
780 | },
781 | "expand-range": {
782 | "version": "1.8.2",
783 | "bundled": true,
784 | "dev": true,
785 | "requires": {
786 | "fill-range": "^2.1.0"
787 | }
788 | },
789 | "extglob": {
790 | "version": "0.3.2",
791 | "bundled": true,
792 | "dev": true,
793 | "requires": {
794 | "is-extglob": "^1.0.0"
795 | }
796 | },
797 | "filename-regex": {
798 | "version": "2.0.1",
799 | "bundled": true,
800 | "dev": true
801 | },
802 | "fill-range": {
803 | "version": "2.2.3",
804 | "bundled": true,
805 | "dev": true,
806 | "requires": {
807 | "is-number": "^2.1.0",
808 | "isobject": "^2.0.0",
809 | "randomatic": "^1.1.3",
810 | "repeat-element": "^1.1.2",
811 | "repeat-string": "^1.5.2"
812 | }
813 | },
814 | "find-cache-dir": {
815 | "version": "0.1.1",
816 | "bundled": true,
817 | "dev": true,
818 | "requires": {
819 | "commondir": "^1.0.1",
820 | "mkdirp": "^0.5.1",
821 | "pkg-dir": "^1.0.0"
822 | }
823 | },
824 | "find-up": {
825 | "version": "2.1.0",
826 | "bundled": true,
827 | "dev": true,
828 | "requires": {
829 | "locate-path": "^2.0.0"
830 | }
831 | },
832 | "for-in": {
833 | "version": "1.0.2",
834 | "bundled": true,
835 | "dev": true
836 | },
837 | "for-own": {
838 | "version": "0.1.5",
839 | "bundled": true,
840 | "dev": true,
841 | "requires": {
842 | "for-in": "^1.0.1"
843 | }
844 | },
845 | "foreground-child": {
846 | "version": "1.5.6",
847 | "bundled": true,
848 | "dev": true,
849 | "requires": {
850 | "cross-spawn": "^4",
851 | "signal-exit": "^3.0.0"
852 | }
853 | },
854 | "fs.realpath": {
855 | "version": "1.0.0",
856 | "bundled": true,
857 | "dev": true
858 | },
859 | "get-caller-file": {
860 | "version": "1.0.2",
861 | "bundled": true,
862 | "dev": true
863 | },
864 | "get-stream": {
865 | "version": "3.0.0",
866 | "bundled": true,
867 | "dev": true
868 | },
869 | "glob": {
870 | "version": "7.1.2",
871 | "bundled": true,
872 | "dev": true,
873 | "requires": {
874 | "fs.realpath": "^1.0.0",
875 | "inflight": "^1.0.4",
876 | "inherits": "2",
877 | "minimatch": "^3.0.4",
878 | "once": "^1.3.0",
879 | "path-is-absolute": "^1.0.0"
880 | }
881 | },
882 | "glob-base": {
883 | "version": "0.3.0",
884 | "bundled": true,
885 | "dev": true,
886 | "requires": {
887 | "glob-parent": "^2.0.0",
888 | "is-glob": "^2.0.0"
889 | }
890 | },
891 | "glob-parent": {
892 | "version": "2.0.0",
893 | "bundled": true,
894 | "dev": true,
895 | "requires": {
896 | "is-glob": "^2.0.0"
897 | }
898 | },
899 | "globals": {
900 | "version": "9.18.0",
901 | "bundled": true,
902 | "dev": true
903 | },
904 | "graceful-fs": {
905 | "version": "4.1.11",
906 | "bundled": true,
907 | "dev": true
908 | },
909 | "handlebars": {
910 | "version": "4.0.11",
911 | "bundled": true,
912 | "dev": true,
913 | "requires": {
914 | "async": "^1.4.0",
915 | "optimist": "^0.6.1",
916 | "source-map": "^0.4.4",
917 | "uglify-js": "^2.6"
918 | },
919 | "dependencies": {
920 | "source-map": {
921 | "version": "0.4.4",
922 | "bundled": true,
923 | "dev": true,
924 | "requires": {
925 | "amdefine": ">=0.0.4"
926 | }
927 | }
928 | }
929 | },
930 | "has-ansi": {
931 | "version": "2.0.0",
932 | "bundled": true,
933 | "dev": true,
934 | "requires": {
935 | "ansi-regex": "^2.0.0"
936 | }
937 | },
938 | "has-flag": {
939 | "version": "1.0.0",
940 | "bundled": true,
941 | "dev": true
942 | },
943 | "hosted-git-info": {
944 | "version": "2.5.0",
945 | "bundled": true,
946 | "dev": true
947 | },
948 | "imurmurhash": {
949 | "version": "0.1.4",
950 | "bundled": true,
951 | "dev": true
952 | },
953 | "inflight": {
954 | "version": "1.0.6",
955 | "bundled": true,
956 | "dev": true,
957 | "requires": {
958 | "once": "^1.3.0",
959 | "wrappy": "1"
960 | }
961 | },
962 | "inherits": {
963 | "version": "2.0.3",
964 | "bundled": true,
965 | "dev": true
966 | },
967 | "invariant": {
968 | "version": "2.2.2",
969 | "bundled": true,
970 | "dev": true,
971 | "requires": {
972 | "loose-envify": "^1.0.0"
973 | }
974 | },
975 | "invert-kv": {
976 | "version": "1.0.0",
977 | "bundled": true,
978 | "dev": true
979 | },
980 | "is-arrayish": {
981 | "version": "0.2.1",
982 | "bundled": true,
983 | "dev": true
984 | },
985 | "is-buffer": {
986 | "version": "1.1.6",
987 | "bundled": true,
988 | "dev": true
989 | },
990 | "is-builtin-module": {
991 | "version": "1.0.0",
992 | "bundled": true,
993 | "dev": true,
994 | "requires": {
995 | "builtin-modules": "^1.0.0"
996 | }
997 | },
998 | "is-dotfile": {
999 | "version": "1.0.3",
1000 | "bundled": true,
1001 | "dev": true
1002 | },
1003 | "is-equal-shallow": {
1004 | "version": "0.1.3",
1005 | "bundled": true,
1006 | "dev": true,
1007 | "requires": {
1008 | "is-primitive": "^2.0.0"
1009 | }
1010 | },
1011 | "is-extendable": {
1012 | "version": "0.1.1",
1013 | "bundled": true,
1014 | "dev": true
1015 | },
1016 | "is-extglob": {
1017 | "version": "1.0.0",
1018 | "bundled": true,
1019 | "dev": true
1020 | },
1021 | "is-finite": {
1022 | "version": "1.0.2",
1023 | "bundled": true,
1024 | "dev": true,
1025 | "requires": {
1026 | "number-is-nan": "^1.0.0"
1027 | }
1028 | },
1029 | "is-fullwidth-code-point": {
1030 | "version": "1.0.0",
1031 | "bundled": true,
1032 | "dev": true,
1033 | "requires": {
1034 | "number-is-nan": "^1.0.0"
1035 | }
1036 | },
1037 | "is-glob": {
1038 | "version": "2.0.1",
1039 | "bundled": true,
1040 | "dev": true,
1041 | "requires": {
1042 | "is-extglob": "^1.0.0"
1043 | }
1044 | },
1045 | "is-number": {
1046 | "version": "2.1.0",
1047 | "bundled": true,
1048 | "dev": true,
1049 | "requires": {
1050 | "kind-of": "^3.0.2"
1051 | }
1052 | },
1053 | "is-posix-bracket": {
1054 | "version": "0.1.1",
1055 | "bundled": true,
1056 | "dev": true
1057 | },
1058 | "is-primitive": {
1059 | "version": "2.0.0",
1060 | "bundled": true,
1061 | "dev": true
1062 | },
1063 | "is-stream": {
1064 | "version": "1.1.0",
1065 | "bundled": true,
1066 | "dev": true
1067 | },
1068 | "is-utf8": {
1069 | "version": "0.2.1",
1070 | "bundled": true,
1071 | "dev": true
1072 | },
1073 | "isarray": {
1074 | "version": "1.0.0",
1075 | "bundled": true,
1076 | "dev": true
1077 | },
1078 | "isexe": {
1079 | "version": "2.0.0",
1080 | "bundled": true,
1081 | "dev": true
1082 | },
1083 | "isobject": {
1084 | "version": "2.1.0",
1085 | "bundled": true,
1086 | "dev": true,
1087 | "requires": {
1088 | "isarray": "1.0.0"
1089 | }
1090 | },
1091 | "istanbul-lib-coverage": {
1092 | "version": "1.1.1",
1093 | "bundled": true,
1094 | "dev": true
1095 | },
1096 | "istanbul-lib-hook": {
1097 | "version": "1.1.0",
1098 | "bundled": true,
1099 | "dev": true,
1100 | "requires": {
1101 | "append-transform": "^0.4.0"
1102 | }
1103 | },
1104 | "istanbul-lib-instrument": {
1105 | "version": "1.9.1",
1106 | "bundled": true,
1107 | "dev": true,
1108 | "requires": {
1109 | "babel-generator": "^6.18.0",
1110 | "babel-template": "^6.16.0",
1111 | "babel-traverse": "^6.18.0",
1112 | "babel-types": "^6.18.0",
1113 | "babylon": "^6.18.0",
1114 | "istanbul-lib-coverage": "^1.1.1",
1115 | "semver": "^5.3.0"
1116 | }
1117 | },
1118 | "istanbul-lib-report": {
1119 | "version": "1.1.2",
1120 | "bundled": true,
1121 | "dev": true,
1122 | "requires": {
1123 | "istanbul-lib-coverage": "^1.1.1",
1124 | "mkdirp": "^0.5.1",
1125 | "path-parse": "^1.0.5",
1126 | "supports-color": "^3.1.2"
1127 | },
1128 | "dependencies": {
1129 | "supports-color": {
1130 | "version": "3.2.3",
1131 | "bundled": true,
1132 | "dev": true,
1133 | "requires": {
1134 | "has-flag": "^1.0.0"
1135 | }
1136 | }
1137 | }
1138 | },
1139 | "istanbul-lib-source-maps": {
1140 | "version": "1.2.2",
1141 | "bundled": true,
1142 | "dev": true,
1143 | "requires": {
1144 | "debug": "^3.1.0",
1145 | "istanbul-lib-coverage": "^1.1.1",
1146 | "mkdirp": "^0.5.1",
1147 | "rimraf": "^2.6.1",
1148 | "source-map": "^0.5.3"
1149 | },
1150 | "dependencies": {
1151 | "debug": {
1152 | "version": "3.1.0",
1153 | "bundled": true,
1154 | "dev": true,
1155 | "requires": {
1156 | "ms": "2.0.0"
1157 | }
1158 | }
1159 | }
1160 | },
1161 | "istanbul-reports": {
1162 | "version": "1.1.3",
1163 | "bundled": true,
1164 | "dev": true,
1165 | "requires": {
1166 | "handlebars": "^4.0.3"
1167 | }
1168 | },
1169 | "js-tokens": {
1170 | "version": "3.0.2",
1171 | "bundled": true,
1172 | "dev": true
1173 | },
1174 | "jsesc": {
1175 | "version": "1.3.0",
1176 | "bundled": true,
1177 | "dev": true
1178 | },
1179 | "kind-of": {
1180 | "version": "3.2.2",
1181 | "bundled": true,
1182 | "dev": true,
1183 | "requires": {
1184 | "is-buffer": "^1.1.5"
1185 | }
1186 | },
1187 | "lazy-cache": {
1188 | "version": "1.0.4",
1189 | "bundled": true,
1190 | "dev": true,
1191 | "optional": true
1192 | },
1193 | "lcid": {
1194 | "version": "1.0.0",
1195 | "bundled": true,
1196 | "dev": true,
1197 | "requires": {
1198 | "invert-kv": "^1.0.0"
1199 | }
1200 | },
1201 | "load-json-file": {
1202 | "version": "1.1.0",
1203 | "bundled": true,
1204 | "dev": true,
1205 | "requires": {
1206 | "graceful-fs": "^4.1.2",
1207 | "parse-json": "^2.2.0",
1208 | "pify": "^2.0.0",
1209 | "pinkie-promise": "^2.0.0",
1210 | "strip-bom": "^2.0.0"
1211 | }
1212 | },
1213 | "locate-path": {
1214 | "version": "2.0.0",
1215 | "bundled": true,
1216 | "dev": true,
1217 | "requires": {
1218 | "p-locate": "^2.0.0",
1219 | "path-exists": "^3.0.0"
1220 | },
1221 | "dependencies": {
1222 | "path-exists": {
1223 | "version": "3.0.0",
1224 | "bundled": true,
1225 | "dev": true
1226 | }
1227 | }
1228 | },
1229 | "lodash": {
1230 | "version": "4.17.4",
1231 | "bundled": true,
1232 | "dev": true
1233 | },
1234 | "longest": {
1235 | "version": "1.0.1",
1236 | "bundled": true,
1237 | "dev": true
1238 | },
1239 | "loose-envify": {
1240 | "version": "1.3.1",
1241 | "bundled": true,
1242 | "dev": true,
1243 | "requires": {
1244 | "js-tokens": "^3.0.0"
1245 | }
1246 | },
1247 | "lru-cache": {
1248 | "version": "4.1.1",
1249 | "bundled": true,
1250 | "dev": true,
1251 | "requires": {
1252 | "pseudomap": "^1.0.2",
1253 | "yallist": "^2.1.2"
1254 | }
1255 | },
1256 | "md5-hex": {
1257 | "version": "1.3.0",
1258 | "bundled": true,
1259 | "dev": true,
1260 | "requires": {
1261 | "md5-o-matic": "^0.1.1"
1262 | }
1263 | },
1264 | "md5-o-matic": {
1265 | "version": "0.1.1",
1266 | "bundled": true,
1267 | "dev": true
1268 | },
1269 | "mem": {
1270 | "version": "1.1.0",
1271 | "bundled": true,
1272 | "dev": true,
1273 | "requires": {
1274 | "mimic-fn": "^1.0.0"
1275 | }
1276 | },
1277 | "merge-source-map": {
1278 | "version": "1.0.4",
1279 | "bundled": true,
1280 | "dev": true,
1281 | "requires": {
1282 | "source-map": "^0.5.6"
1283 | }
1284 | },
1285 | "micromatch": {
1286 | "version": "2.3.11",
1287 | "bundled": true,
1288 | "dev": true,
1289 | "requires": {
1290 | "arr-diff": "^2.0.0",
1291 | "array-unique": "^0.2.1",
1292 | "braces": "^1.8.2",
1293 | "expand-brackets": "^0.1.4",
1294 | "extglob": "^0.3.1",
1295 | "filename-regex": "^2.0.0",
1296 | "is-extglob": "^1.0.0",
1297 | "is-glob": "^2.0.1",
1298 | "kind-of": "^3.0.2",
1299 | "normalize-path": "^2.0.1",
1300 | "object.omit": "^2.0.0",
1301 | "parse-glob": "^3.0.4",
1302 | "regex-cache": "^0.4.2"
1303 | }
1304 | },
1305 | "mimic-fn": {
1306 | "version": "1.1.0",
1307 | "bundled": true,
1308 | "dev": true
1309 | },
1310 | "minimatch": {
1311 | "version": "3.0.4",
1312 | "bundled": true,
1313 | "dev": true,
1314 | "requires": {
1315 | "brace-expansion": "^1.1.7"
1316 | }
1317 | },
1318 | "minimist": {
1319 | "version": "0.0.8",
1320 | "bundled": true,
1321 | "dev": true
1322 | },
1323 | "mkdirp": {
1324 | "version": "0.5.1",
1325 | "bundled": true,
1326 | "dev": true,
1327 | "requires": {
1328 | "minimist": "0.0.8"
1329 | }
1330 | },
1331 | "ms": {
1332 | "version": "2.0.0",
1333 | "bundled": true,
1334 | "dev": true
1335 | },
1336 | "normalize-package-data": {
1337 | "version": "2.4.0",
1338 | "bundled": true,
1339 | "dev": true,
1340 | "requires": {
1341 | "hosted-git-info": "^2.1.4",
1342 | "is-builtin-module": "^1.0.0",
1343 | "semver": "2 || 3 || 4 || 5",
1344 | "validate-npm-package-license": "^3.0.1"
1345 | }
1346 | },
1347 | "normalize-path": {
1348 | "version": "2.1.1",
1349 | "bundled": true,
1350 | "dev": true,
1351 | "requires": {
1352 | "remove-trailing-separator": "^1.0.1"
1353 | }
1354 | },
1355 | "npm-run-path": {
1356 | "version": "2.0.2",
1357 | "bundled": true,
1358 | "dev": true,
1359 | "requires": {
1360 | "path-key": "^2.0.0"
1361 | }
1362 | },
1363 | "number-is-nan": {
1364 | "version": "1.0.1",
1365 | "bundled": true,
1366 | "dev": true
1367 | },
1368 | "object-assign": {
1369 | "version": "4.1.1",
1370 | "bundled": true,
1371 | "dev": true
1372 | },
1373 | "object.omit": {
1374 | "version": "2.0.1",
1375 | "bundled": true,
1376 | "dev": true,
1377 | "requires": {
1378 | "for-own": "^0.1.4",
1379 | "is-extendable": "^0.1.1"
1380 | }
1381 | },
1382 | "once": {
1383 | "version": "1.4.0",
1384 | "bundled": true,
1385 | "dev": true,
1386 | "requires": {
1387 | "wrappy": "1"
1388 | }
1389 | },
1390 | "optimist": {
1391 | "version": "0.6.1",
1392 | "bundled": true,
1393 | "dev": true,
1394 | "requires": {
1395 | "minimist": "~0.0.1",
1396 | "wordwrap": "~0.0.2"
1397 | }
1398 | },
1399 | "os-homedir": {
1400 | "version": "1.0.2",
1401 | "bundled": true,
1402 | "dev": true
1403 | },
1404 | "os-locale": {
1405 | "version": "2.1.0",
1406 | "bundled": true,
1407 | "dev": true,
1408 | "requires": {
1409 | "execa": "^0.7.0",
1410 | "lcid": "^1.0.0",
1411 | "mem": "^1.1.0"
1412 | }
1413 | },
1414 | "p-finally": {
1415 | "version": "1.0.0",
1416 | "bundled": true,
1417 | "dev": true
1418 | },
1419 | "p-limit": {
1420 | "version": "1.1.0",
1421 | "bundled": true,
1422 | "dev": true
1423 | },
1424 | "p-locate": {
1425 | "version": "2.0.0",
1426 | "bundled": true,
1427 | "dev": true,
1428 | "requires": {
1429 | "p-limit": "^1.1.0"
1430 | }
1431 | },
1432 | "parse-glob": {
1433 | "version": "3.0.4",
1434 | "bundled": true,
1435 | "dev": true,
1436 | "requires": {
1437 | "glob-base": "^0.3.0",
1438 | "is-dotfile": "^1.0.0",
1439 | "is-extglob": "^1.0.0",
1440 | "is-glob": "^2.0.0"
1441 | }
1442 | },
1443 | "parse-json": {
1444 | "version": "2.2.0",
1445 | "bundled": true,
1446 | "dev": true,
1447 | "requires": {
1448 | "error-ex": "^1.2.0"
1449 | }
1450 | },
1451 | "path-exists": {
1452 | "version": "2.1.0",
1453 | "bundled": true,
1454 | "dev": true,
1455 | "requires": {
1456 | "pinkie-promise": "^2.0.0"
1457 | }
1458 | },
1459 | "path-is-absolute": {
1460 | "version": "1.0.1",
1461 | "bundled": true,
1462 | "dev": true
1463 | },
1464 | "path-key": {
1465 | "version": "2.0.1",
1466 | "bundled": true,
1467 | "dev": true
1468 | },
1469 | "path-parse": {
1470 | "version": "1.0.5",
1471 | "bundled": true,
1472 | "dev": true
1473 | },
1474 | "path-type": {
1475 | "version": "1.1.0",
1476 | "bundled": true,
1477 | "dev": true,
1478 | "requires": {
1479 | "graceful-fs": "^4.1.2",
1480 | "pify": "^2.0.0",
1481 | "pinkie-promise": "^2.0.0"
1482 | }
1483 | },
1484 | "pify": {
1485 | "version": "2.3.0",
1486 | "bundled": true,
1487 | "dev": true
1488 | },
1489 | "pinkie": {
1490 | "version": "2.0.4",
1491 | "bundled": true,
1492 | "dev": true
1493 | },
1494 | "pinkie-promise": {
1495 | "version": "2.0.1",
1496 | "bundled": true,
1497 | "dev": true,
1498 | "requires": {
1499 | "pinkie": "^2.0.0"
1500 | }
1501 | },
1502 | "pkg-dir": {
1503 | "version": "1.0.0",
1504 | "bundled": true,
1505 | "dev": true,
1506 | "requires": {
1507 | "find-up": "^1.0.0"
1508 | },
1509 | "dependencies": {
1510 | "find-up": {
1511 | "version": "1.1.2",
1512 | "bundled": true,
1513 | "dev": true,
1514 | "requires": {
1515 | "path-exists": "^2.0.0",
1516 | "pinkie-promise": "^2.0.0"
1517 | }
1518 | }
1519 | }
1520 | },
1521 | "preserve": {
1522 | "version": "0.2.0",
1523 | "bundled": true,
1524 | "dev": true
1525 | },
1526 | "pseudomap": {
1527 | "version": "1.0.2",
1528 | "bundled": true,
1529 | "dev": true
1530 | },
1531 | "randomatic": {
1532 | "version": "1.1.7",
1533 | "bundled": true,
1534 | "dev": true,
1535 | "requires": {
1536 | "is-number": "^3.0.0",
1537 | "kind-of": "^4.0.0"
1538 | },
1539 | "dependencies": {
1540 | "is-number": {
1541 | "version": "3.0.0",
1542 | "bundled": true,
1543 | "dev": true,
1544 | "requires": {
1545 | "kind-of": "^3.0.2"
1546 | },
1547 | "dependencies": {
1548 | "kind-of": {
1549 | "version": "3.2.2",
1550 | "bundled": true,
1551 | "dev": true,
1552 | "requires": {
1553 | "is-buffer": "^1.1.5"
1554 | }
1555 | }
1556 | }
1557 | },
1558 | "kind-of": {
1559 | "version": "4.0.0",
1560 | "bundled": true,
1561 | "dev": true,
1562 | "requires": {
1563 | "is-buffer": "^1.1.5"
1564 | }
1565 | }
1566 | }
1567 | },
1568 | "read-pkg": {
1569 | "version": "1.1.0",
1570 | "bundled": true,
1571 | "dev": true,
1572 | "requires": {
1573 | "load-json-file": "^1.0.0",
1574 | "normalize-package-data": "^2.3.2",
1575 | "path-type": "^1.0.0"
1576 | }
1577 | },
1578 | "read-pkg-up": {
1579 | "version": "1.0.1",
1580 | "bundled": true,
1581 | "dev": true,
1582 | "requires": {
1583 | "find-up": "^1.0.0",
1584 | "read-pkg": "^1.0.0"
1585 | },
1586 | "dependencies": {
1587 | "find-up": {
1588 | "version": "1.1.2",
1589 | "bundled": true,
1590 | "dev": true,
1591 | "requires": {
1592 | "path-exists": "^2.0.0",
1593 | "pinkie-promise": "^2.0.0"
1594 | }
1595 | }
1596 | }
1597 | },
1598 | "regenerator-runtime": {
1599 | "version": "0.11.1",
1600 | "bundled": true,
1601 | "dev": true
1602 | },
1603 | "regex-cache": {
1604 | "version": "0.4.4",
1605 | "bundled": true,
1606 | "dev": true,
1607 | "requires": {
1608 | "is-equal-shallow": "^0.1.3"
1609 | }
1610 | },
1611 | "remove-trailing-separator": {
1612 | "version": "1.1.0",
1613 | "bundled": true,
1614 | "dev": true
1615 | },
1616 | "repeat-element": {
1617 | "version": "1.1.2",
1618 | "bundled": true,
1619 | "dev": true
1620 | },
1621 | "repeat-string": {
1622 | "version": "1.6.1",
1623 | "bundled": true,
1624 | "dev": true
1625 | },
1626 | "repeating": {
1627 | "version": "2.0.1",
1628 | "bundled": true,
1629 | "dev": true,
1630 | "requires": {
1631 | "is-finite": "^1.0.0"
1632 | }
1633 | },
1634 | "require-directory": {
1635 | "version": "2.1.1",
1636 | "bundled": true,
1637 | "dev": true
1638 | },
1639 | "require-main-filename": {
1640 | "version": "1.0.1",
1641 | "bundled": true,
1642 | "dev": true
1643 | },
1644 | "resolve-from": {
1645 | "version": "2.0.0",
1646 | "bundled": true,
1647 | "dev": true
1648 | },
1649 | "right-align": {
1650 | "version": "0.1.3",
1651 | "bundled": true,
1652 | "dev": true,
1653 | "optional": true,
1654 | "requires": {
1655 | "align-text": "^0.1.1"
1656 | }
1657 | },
1658 | "rimraf": {
1659 | "version": "2.6.2",
1660 | "bundled": true,
1661 | "dev": true,
1662 | "requires": {
1663 | "glob": "^7.0.5"
1664 | }
1665 | },
1666 | "semver": {
1667 | "version": "5.4.1",
1668 | "bundled": true,
1669 | "dev": true
1670 | },
1671 | "set-blocking": {
1672 | "version": "2.0.0",
1673 | "bundled": true,
1674 | "dev": true
1675 | },
1676 | "shebang-command": {
1677 | "version": "1.2.0",
1678 | "bundled": true,
1679 | "dev": true,
1680 | "requires": {
1681 | "shebang-regex": "^1.0.0"
1682 | }
1683 | },
1684 | "shebang-regex": {
1685 | "version": "1.0.0",
1686 | "bundled": true,
1687 | "dev": true
1688 | },
1689 | "signal-exit": {
1690 | "version": "3.0.2",
1691 | "bundled": true,
1692 | "dev": true
1693 | },
1694 | "slide": {
1695 | "version": "1.1.6",
1696 | "bundled": true,
1697 | "dev": true
1698 | },
1699 | "source-map": {
1700 | "version": "0.5.7",
1701 | "bundled": true,
1702 | "dev": true
1703 | },
1704 | "spawn-wrap": {
1705 | "version": "1.4.2",
1706 | "bundled": true,
1707 | "dev": true,
1708 | "requires": {
1709 | "foreground-child": "^1.5.6",
1710 | "mkdirp": "^0.5.0",
1711 | "os-homedir": "^1.0.1",
1712 | "rimraf": "^2.6.2",
1713 | "signal-exit": "^3.0.2",
1714 | "which": "^1.3.0"
1715 | }
1716 | },
1717 | "spdx-correct": {
1718 | "version": "1.0.2",
1719 | "bundled": true,
1720 | "dev": true,
1721 | "requires": {
1722 | "spdx-license-ids": "^1.0.2"
1723 | }
1724 | },
1725 | "spdx-expression-parse": {
1726 | "version": "1.0.4",
1727 | "bundled": true,
1728 | "dev": true
1729 | },
1730 | "spdx-license-ids": {
1731 | "version": "1.2.2",
1732 | "bundled": true,
1733 | "dev": true
1734 | },
1735 | "string-width": {
1736 | "version": "2.1.1",
1737 | "bundled": true,
1738 | "dev": true,
1739 | "requires": {
1740 | "is-fullwidth-code-point": "^2.0.0",
1741 | "strip-ansi": "^4.0.0"
1742 | },
1743 | "dependencies": {
1744 | "ansi-regex": {
1745 | "version": "3.0.0",
1746 | "bundled": true,
1747 | "dev": true
1748 | },
1749 | "is-fullwidth-code-point": {
1750 | "version": "2.0.0",
1751 | "bundled": true,
1752 | "dev": true
1753 | },
1754 | "strip-ansi": {
1755 | "version": "4.0.0",
1756 | "bundled": true,
1757 | "dev": true,
1758 | "requires": {
1759 | "ansi-regex": "^3.0.0"
1760 | }
1761 | }
1762 | }
1763 | },
1764 | "strip-ansi": {
1765 | "version": "3.0.1",
1766 | "bundled": true,
1767 | "dev": true,
1768 | "requires": {
1769 | "ansi-regex": "^2.0.0"
1770 | }
1771 | },
1772 | "strip-bom": {
1773 | "version": "2.0.0",
1774 | "bundled": true,
1775 | "dev": true,
1776 | "requires": {
1777 | "is-utf8": "^0.2.0"
1778 | }
1779 | },
1780 | "strip-eof": {
1781 | "version": "1.0.0",
1782 | "bundled": true,
1783 | "dev": true
1784 | },
1785 | "supports-color": {
1786 | "version": "2.0.0",
1787 | "bundled": true,
1788 | "dev": true
1789 | },
1790 | "test-exclude": {
1791 | "version": "4.1.1",
1792 | "bundled": true,
1793 | "dev": true,
1794 | "requires": {
1795 | "arrify": "^1.0.1",
1796 | "micromatch": "^2.3.11",
1797 | "object-assign": "^4.1.0",
1798 | "read-pkg-up": "^1.0.1",
1799 | "require-main-filename": "^1.0.1"
1800 | }
1801 | },
1802 | "to-fast-properties": {
1803 | "version": "1.0.3",
1804 | "bundled": true,
1805 | "dev": true
1806 | },
1807 | "trim-right": {
1808 | "version": "1.0.1",
1809 | "bundled": true,
1810 | "dev": true
1811 | },
1812 | "uglify-js": {
1813 | "version": "2.8.29",
1814 | "bundled": true,
1815 | "dev": true,
1816 | "optional": true,
1817 | "requires": {
1818 | "source-map": "~0.5.1",
1819 | "uglify-to-browserify": "~1.0.0",
1820 | "yargs": "~3.10.0"
1821 | },
1822 | "dependencies": {
1823 | "yargs": {
1824 | "version": "3.10.0",
1825 | "bundled": true,
1826 | "dev": true,
1827 | "optional": true,
1828 | "requires": {
1829 | "camelcase": "^1.0.2",
1830 | "cliui": "^2.1.0",
1831 | "decamelize": "^1.0.0",
1832 | "window-size": "0.1.0"
1833 | }
1834 | }
1835 | }
1836 | },
1837 | "uglify-to-browserify": {
1838 | "version": "1.0.2",
1839 | "bundled": true,
1840 | "dev": true,
1841 | "optional": true
1842 | },
1843 | "validate-npm-package-license": {
1844 | "version": "3.0.1",
1845 | "bundled": true,
1846 | "dev": true,
1847 | "requires": {
1848 | "spdx-correct": "~1.0.0",
1849 | "spdx-expression-parse": "~1.0.0"
1850 | }
1851 | },
1852 | "which": {
1853 | "version": "1.3.0",
1854 | "bundled": true,
1855 | "dev": true,
1856 | "requires": {
1857 | "isexe": "^2.0.0"
1858 | }
1859 | },
1860 | "which-module": {
1861 | "version": "2.0.0",
1862 | "bundled": true,
1863 | "dev": true
1864 | },
1865 | "window-size": {
1866 | "version": "0.1.0",
1867 | "bundled": true,
1868 | "dev": true,
1869 | "optional": true
1870 | },
1871 | "wordwrap": {
1872 | "version": "0.0.3",
1873 | "bundled": true,
1874 | "dev": true
1875 | },
1876 | "wrap-ansi": {
1877 | "version": "2.1.0",
1878 | "bundled": true,
1879 | "dev": true,
1880 | "requires": {
1881 | "string-width": "^1.0.1",
1882 | "strip-ansi": "^3.0.1"
1883 | },
1884 | "dependencies": {
1885 | "string-width": {
1886 | "version": "1.0.2",
1887 | "bundled": true,
1888 | "dev": true,
1889 | "requires": {
1890 | "code-point-at": "^1.0.0",
1891 | "is-fullwidth-code-point": "^1.0.0",
1892 | "strip-ansi": "^3.0.0"
1893 | }
1894 | }
1895 | }
1896 | },
1897 | "wrappy": {
1898 | "version": "1.0.2",
1899 | "bundled": true,
1900 | "dev": true
1901 | },
1902 | "write-file-atomic": {
1903 | "version": "1.3.4",
1904 | "bundled": true,
1905 | "dev": true,
1906 | "requires": {
1907 | "graceful-fs": "^4.1.11",
1908 | "imurmurhash": "^0.1.4",
1909 | "slide": "^1.1.5"
1910 | }
1911 | },
1912 | "y18n": {
1913 | "version": "3.2.1",
1914 | "bundled": true,
1915 | "dev": true
1916 | },
1917 | "yallist": {
1918 | "version": "2.1.2",
1919 | "bundled": true,
1920 | "dev": true
1921 | },
1922 | "yargs": {
1923 | "version": "10.0.3",
1924 | "bundled": true,
1925 | "dev": true,
1926 | "requires": {
1927 | "cliui": "^3.2.0",
1928 | "decamelize": "^1.1.1",
1929 | "find-up": "^2.1.0",
1930 | "get-caller-file": "^1.0.1",
1931 | "os-locale": "^2.0.0",
1932 | "require-directory": "^2.1.1",
1933 | "require-main-filename": "^1.0.1",
1934 | "set-blocking": "^2.0.0",
1935 | "string-width": "^2.0.0",
1936 | "which-module": "^2.0.0",
1937 | "y18n": "^3.2.1",
1938 | "yargs-parser": "^8.0.0"
1939 | },
1940 | "dependencies": {
1941 | "cliui": {
1942 | "version": "3.2.0",
1943 | "bundled": true,
1944 | "dev": true,
1945 | "requires": {
1946 | "string-width": "^1.0.1",
1947 | "strip-ansi": "^3.0.1",
1948 | "wrap-ansi": "^2.0.0"
1949 | },
1950 | "dependencies": {
1951 | "string-width": {
1952 | "version": "1.0.2",
1953 | "bundled": true,
1954 | "dev": true,
1955 | "requires": {
1956 | "code-point-at": "^1.0.0",
1957 | "is-fullwidth-code-point": "^1.0.0",
1958 | "strip-ansi": "^3.0.0"
1959 | }
1960 | }
1961 | }
1962 | }
1963 | }
1964 | },
1965 | "yargs-parser": {
1966 | "version": "8.0.0",
1967 | "bundled": true,
1968 | "dev": true,
1969 | "requires": {
1970 | "camelcase": "^4.1.0"
1971 | },
1972 | "dependencies": {
1973 | "camelcase": {
1974 | "version": "4.1.0",
1975 | "bundled": true,
1976 | "dev": true
1977 | }
1978 | }
1979 | }
1980 | }
1981 | },
1982 | "once": {
1983 | "version": "1.4.0",
1984 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1985 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1986 | "dev": true,
1987 | "requires": {
1988 | "wrappy": "1"
1989 | }
1990 | },
1991 | "path-to-regexp": {
1992 | "version": "2.2.1",
1993 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
1994 | "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==",
1995 | "dev": true
1996 | },
1997 | "pathval": {
1998 | "version": "1.1.0",
1999 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
2000 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
2001 | "dev": true
2002 | },
2003 | "pino": {
2004 | "version": "4.17.3",
2005 | "resolved": "https://registry.npmjs.org/pino/-/pino-4.17.3.tgz",
2006 | "integrity": "sha512-3CBWMG1k6QdOyz9br3WzOhUQD52QFskbmlgX51wGXLPAY0UbKPsUIayYcVOQMCqjmeqEPCAG3V/Uvry+FjwtoQ==",
2007 | "dev": true,
2008 | "requires": {
2009 | "chalk": "^2.4.1",
2010 | "fast-json-parse": "^1.0.3",
2011 | "fast-safe-stringify": "^1.2.3",
2012 | "flatstr": "^1.0.5",
2013 | "pino-std-serializers": "^2.0.0",
2014 | "pump": "^3.0.0",
2015 | "quick-format-unescaped": "^1.1.2",
2016 | "split2": "^2.2.0"
2017 | }
2018 | },
2019 | "pino-std-serializers": {
2020 | "version": "2.1.0",
2021 | "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.1.0.tgz",
2022 | "integrity": "sha512-NqWvrQD/GpY78ybiNBzi/dg8ylERhDo6nB33j5sfCKpUmWLc3lYzeoBjyRoCMvEpDpL9lmH6ufRd0jw6rcd1pQ==",
2023 | "dev": true
2024 | },
2025 | "process-nextick-args": {
2026 | "version": "2.0.0",
2027 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
2028 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
2029 | "dev": true
2030 | },
2031 | "pump": {
2032 | "version": "3.0.0",
2033 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
2034 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
2035 | "dev": true,
2036 | "requires": {
2037 | "end-of-stream": "^1.1.0",
2038 | "once": "^1.3.1"
2039 | }
2040 | },
2041 | "punycode": {
2042 | "version": "2.1.1",
2043 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
2044 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
2045 | "dev": true
2046 | },
2047 | "quick-format-unescaped": {
2048 | "version": "1.1.2",
2049 | "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-1.1.2.tgz",
2050 | "integrity": "sha1-DKWB3jF0vs7yWsPC6JVjQjgdtpg=",
2051 | "dev": true,
2052 | "requires": {
2053 | "fast-safe-stringify": "^1.0.8"
2054 | }
2055 | },
2056 | "readable-stream": {
2057 | "version": "2.3.6",
2058 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
2059 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
2060 | "dev": true,
2061 | "requires": {
2062 | "core-util-is": "~1.0.0",
2063 | "inherits": "~2.0.3",
2064 | "isarray": "~1.0.0",
2065 | "process-nextick-args": "~2.0.0",
2066 | "safe-buffer": "~5.1.1",
2067 | "string_decoder": "~1.1.1",
2068 | "util-deprecate": "~1.0.1"
2069 | }
2070 | },
2071 | "ret": {
2072 | "version": "0.1.15",
2073 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
2074 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
2075 | "dev": true
2076 | },
2077 | "reusify": {
2078 | "version": "1.0.4",
2079 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
2080 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
2081 | "dev": true
2082 | },
2083 | "safe-buffer": {
2084 | "version": "5.1.2",
2085 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
2086 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
2087 | "dev": true
2088 | },
2089 | "safe-regex": {
2090 | "version": "1.1.0",
2091 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
2092 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
2093 | "dev": true,
2094 | "requires": {
2095 | "ret": "~0.1.10"
2096 | }
2097 | },
2098 | "semver": {
2099 | "version": "5.5.0",
2100 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
2101 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
2102 | },
2103 | "source-map": {
2104 | "version": "0.6.1",
2105 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
2106 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
2107 | },
2108 | "source-map-support": {
2109 | "version": "0.5.3",
2110 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz",
2111 | "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==",
2112 | "requires": {
2113 | "source-map": "^0.6.0"
2114 | }
2115 | },
2116 | "split2": {
2117 | "version": "2.2.0",
2118 | "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
2119 | "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
2120 | "dev": true,
2121 | "requires": {
2122 | "through2": "^2.0.2"
2123 | }
2124 | },
2125 | "string_decoder": {
2126 | "version": "1.1.1",
2127 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
2128 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
2129 | "dev": true,
2130 | "requires": {
2131 | "safe-buffer": "~5.1.0"
2132 | }
2133 | },
2134 | "supports-color": {
2135 | "version": "5.4.0",
2136 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
2137 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
2138 | "dev": true,
2139 | "requires": {
2140 | "has-flag": "^3.0.0"
2141 | }
2142 | },
2143 | "through2": {
2144 | "version": "2.0.3",
2145 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
2146 | "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
2147 | "dev": true,
2148 | "requires": {
2149 | "readable-stream": "^2.1.5",
2150 | "xtend": "~4.0.1"
2151 | }
2152 | },
2153 | "tiny-lru": {
2154 | "version": "1.6.1",
2155 | "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-1.6.1.tgz",
2156 | "integrity": "sha512-m8oyPnHjnQlbDk8+MCw33qRMp6+BxPxoayN9C743VToeyQ5zZV6F6vkklrYVEI0z9MQ3+jmc+22tKmvPg4gmoA==",
2157 | "dev": true
2158 | },
2159 | "type-detect": {
2160 | "version": "4.0.7",
2161 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.7.tgz",
2162 | "integrity": "sha512-4Rh17pAMVdMWzktddFhISRnUnFIStObtUMNGzDwlA6w/77bmGv3aBbRdCmQR6IjzfkTo9otnW+2K/cDRhKSxDA==",
2163 | "dev": true
2164 | },
2165 | "uri-js": {
2166 | "version": "4.2.2",
2167 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
2168 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
2169 | "dev": true,
2170 | "requires": {
2171 | "punycode": "^2.1.0"
2172 | }
2173 | },
2174 | "util-deprecate": {
2175 | "version": "1.0.2",
2176 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2177 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
2178 | "dev": true
2179 | },
2180 | "wrappy": {
2181 | "version": "1.0.2",
2182 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2183 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
2184 | "dev": true
2185 | },
2186 | "xtend": {
2187 | "version": "4.0.1",
2188 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
2189 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
2190 | "dev": true
2191 | }
2192 | }
2193 | }
2194 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fastify-graphql",
3 | "version": "4.0.0",
4 | "description": "Apollo server plugin for Fastify",
5 | "main": "out/FastifyGraphQL.js",
6 | "typings": "out/FastifyGraphQL.d.ts",
7 | "engines": {
8 | "npm": "=< ~5.1.0"
9 | },
10 | "scripts": {
11 | "prepare": "./node_modules/typescript/bin/tsc --extendedDiagnostics",
12 | "release": "standard-version",
13 | "test": "./node_modules/mocha/bin/mocha $NODE_DEBUG_OPTION --require ts-node/register ./test/**/*.test.ts"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/sirsavary/fastify-graphql.git"
18 | },
19 | "keywords": [
20 | "fastify",
21 | "apollo",
22 | "graphql"
23 | ],
24 | "author": "Jesse Savary",
25 | "contributors": [
26 | {
27 | "name": "Nickolena Coop",
28 | "url": "https://github.com/coopnd/"
29 | }
30 | ],
31 | "license": "MIT",
32 | "homepage": "https://github.com/sirsavary/fastify-graphql#readme",
33 | "bugs": {
34 | "url": "https://github.com/sirsavary/fastify-graphql/issues"
35 | },
36 | "dependencies": {
37 | "apollo-server-core": "^1.3.2",
38 | "apollo-server-module-graphiql": "^1.3.2",
39 | "fastify-plugin": "^0.2.2"
40 | },
41 | "devDependencies": {
42 | "@types/chai": "^4.1.2",
43 | "@types/graphql": "^0.12.4",
44 | "@types/mocha": "^2.2.48",
45 | "@types/sinon": "^4.3.0",
46 | "@types/supertest": "^2.0.4",
47 | "apollo-server-module-operation-store": "^1.3.2",
48 | "chai": "^4.1.2",
49 | "chai-graphql": "^4.0.0",
50 | "fastify": "^1.5.0",
51 | "graphql": "^0.12.3",
52 | "graphql-tools": "^2.21.0",
53 | "mocha": "^5.0.1",
54 | "nyc": "^11.4.1",
55 | "sinon": "^4.4.2",
56 | "standard-version": "^4.3.0",
57 | "supertest": "^3.0.0",
58 | "supertest-as-promised": "^4.0.2",
59 | "ts-node": "^5.0.1",
60 | "typescript": "^2.7.2"
61 | },
62 | "peerDependencies": {
63 | "graphql": "^0.12"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/FastifyGraphQL.ts:
--------------------------------------------------------------------------------
1 | import FastifyPlugin from 'fastify-plugin';
2 |
3 | import GraphQLPlugin from "./GraphQLPlugin";
4 | import GraphiQLPlugin from "./GraphiQLPlugin";
5 | import {FastifyInstance, Middleware} from "fastify";
6 |
7 | // prevent fastify-plugin from stripping our prefix
8 | const fp = (plugin: Middleware) =>
9 | FastifyPlugin(function (fastify: FastifyInstance, opts: object, next: Function) {
10 | fastify.register(plugin, opts);
11 | next()
12 | }, {
13 | fastify: '>=0.40.0',
14 | });
15 |
16 | const graphqlFastify = fp(GraphQLPlugin);
17 | const graphiqlFastify = fp(GraphiQLPlugin);
18 |
19 | export { graphqlFastify, graphiqlFastify };
20 |
--------------------------------------------------------------------------------
/src/GraphQLPlugin.ts:
--------------------------------------------------------------------------------
1 | import { runHttpQuery, GraphQLOptions } from 'apollo-server-core';
2 | import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
3 | import { IncomingMessage, OutgoingMessage, Server } from 'http';
4 |
5 | function GraphQLPlugin(fastify: FastifyInstance, pluginOptions: { prefix: string, graphql: Function | GraphQLOptions }, next: (err?: Error) => void) {
6 | if (!pluginOptions) throw new Error('Fastify GraphQL requires options!');
7 | else if (!pluginOptions.prefix) throw new Error('Fastify GraphQL requires `prefix` to be part of passed options!');
8 | else if (!pluginOptions.graphql) throw new Error('Fastify GraphQL requires `graphql` to be part of passed options!');
9 |
10 | const handler = async (request: FastifyRequest, reply: FastifyReply) => {
11 | try {
12 | let method = request.req.method;
13 | const gqlResponse = await runHttpQuery([request, reply], {
14 | method : method,
15 | options: pluginOptions.graphql,
16 | query : method === 'POST' ? request.body : request.query,
17 | });
18 |
19 | // bypass Fastify's response layer, so we can avoid having to
20 | // parse the serialized gqlResponse due to Fastify's internal
21 | // JSON serializer seeing our Content-Type header and assuming
22 | // the response payload is unserialized
23 | reply.sent = true
24 | reply.res.setHeader('Content-Type', 'application/json');
25 | reply.res.end(gqlResponse);
26 | } catch (error) {
27 | if ('HttpQueryError' !== error.name) {
28 | throw error;
29 | }
30 |
31 | if (error.headers) {
32 | Object.keys(error.headers).forEach(header => {
33 | reply.header(header, error.headers[header]);
34 | });
35 | }
36 |
37 | reply.code(error.statusCode);
38 | // error.message is actually a stringified GQL response, see
39 | // comment @ line 19 for why we bypass Fastify's response layer
40 | if (error.isGraphQLError) {
41 | reply.sent = true
42 | reply.res.setHeader('Content-Type', 'application/json');
43 | reply.res.end(error.message);
44 | } else {
45 | reply.send(error.message);
46 | }
47 | }
48 | };
49 |
50 | fastify.get('/', handler);
51 | fastify.post('/', handler);
52 |
53 | //TODO determine if this is really the best way to have Fastify not 404 on an invalid HTTP method
54 | fastify.setNotFoundHandler((request, reply) => {
55 | if (request.req.method !== 'POST' && request.req.method !== 'POST') {
56 | reply.code(405);
57 | reply.header('allow', ['GET', 'POST']);
58 | } else {
59 | reply.code(404);
60 | }
61 | reply.send();
62 | });
63 |
64 | next();
65 | }
66 |
67 | export default GraphQLPlugin;
68 |
--------------------------------------------------------------------------------
/src/GraphiQLPlugin.ts:
--------------------------------------------------------------------------------
1 | import URL from 'url';
2 | import { GraphiQLData, resolveGraphiQLString } from 'apollo-server-module-graphiql';
3 | import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
4 | import { IncomingMessage, OutgoingMessage, Server } from 'http';
5 |
6 | function GraphiQLPlugin(fastify: FastifyInstance, options: { prefix: string, graphiql: GraphiQLData | Function }, next: (err?: Error) => void) {
7 | options = Object.assign({
8 | prefix : '/graphiql',
9 | graphiql: {
10 | endpointURL: '/graphql',
11 | },
12 | }, options);
13 |
14 | const handler = async (request: FastifyRequest, reply: FastifyReply) => {
15 | try {
16 | const query = request.req.url && URL.parse(request.req.url, true).query;
17 | const graphiqlString = await resolveGraphiQLString(query, options.graphiql, [request, reply]);
18 | reply.type('text/html').send(graphiqlString);
19 | } catch (error) {
20 | reply.code(500);
21 | reply.send(error.message);
22 | }
23 | };
24 |
25 | fastify.get('/', handler);
26 |
27 | next();
28 | }
29 |
30 | export default GraphiQLPlugin;
--------------------------------------------------------------------------------
/src/Typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'fastify-plugin';
2 |
3 | // chai-graphql definitions
4 | declare module 'chai-graphql';
5 | declare namespace Chai {
6 | interface Assertion {
7 | graphQL: Equal
8 | graphQLError(): void;
9 | }
10 | }
--------------------------------------------------------------------------------
/test/FastifyGraphql.test.ts:
--------------------------------------------------------------------------------
1 | import Fastify from 'fastify';
2 | import * as http from 'http';
3 | import { graphiqlFastify, graphqlFastify } from '../src/FastifyGraphQL';
4 | import testSuite, { CreateAppOptions, schema, } from './apollo-server-integration-testsuite';
5 |
6 | async function createFastifyApp(options: CreateAppOptions = {}): Promise {
7 | const app = Fastify();
8 |
9 | options.graphqlOptions = options.graphqlOptions || { schema: schema };
10 |
11 | app.register(graphqlFastify, {
12 | prefix : '/graphql',
13 | graphql: options.graphqlOptions,
14 | });
15 |
16 | if (options.graphiqlOptions) {
17 | app.register(graphiqlFastify, {
18 | prefix : '/graphiql',
19 | graphiql: options.graphiqlOptions,
20 | });
21 | }
22 |
23 | await app.listen(0);
24 | return app.server;
25 | }
26 |
27 | async function destroyFastifyApp(app: http.Server): Promise {
28 | await app.close();
29 | }
30 |
31 | describe('integration:Fastify', () => {
32 | testSuite(createFastifyApp, destroyFastifyApp);
33 | });
--------------------------------------------------------------------------------
/test/apollo-server-integration-testsuite.ts:
--------------------------------------------------------------------------------
1 | // borrowed from
2 | // https://github.com/apollographql/apollo-server/blob/master/packages/apollo-server-integration-testsuite/src/index.ts
3 | // because apollo-server-integration-testsuite is not a published module
4 |
5 |
6 | import { expect } from 'chai';
7 | import { stub } from 'sinon';
8 | import 'mocha';
9 |
10 | import {
11 | GraphQLSchema,
12 | GraphQLObjectType,
13 | GraphQLString,
14 | GraphQLInt,
15 | GraphQLError,
16 | GraphQLNonNull,
17 | introspectionQuery,
18 | BREAK,
19 | } from 'graphql';
20 |
21 | // tslint:disable-next-line
22 | const request = require('supertest');
23 |
24 | import { GraphQLOptions } from 'apollo-server-core';
25 | import * as GraphiQL from 'apollo-server-module-graphiql';
26 | import { OperationStore } from 'apollo-server-module-operation-store';
27 |
28 | const queryType = new GraphQLObjectType({
29 | name: 'QueryType',
30 | fields: {
31 | testString: {
32 | type: GraphQLString,
33 | resolve() {
34 | return 'it works';
35 | },
36 | },
37 | testStringWithDelay: {
38 | type: GraphQLString,
39 | args: {
40 | delay: { type: new GraphQLNonNull(GraphQLInt) },
41 | },
42 | resolve(root, args) {
43 | return new Promise((resolve, reject) => {
44 | setTimeout(() => resolve('it works'), args['delay']);
45 | });
46 | },
47 | },
48 | testContext: {
49 | type: GraphQLString,
50 | resolve(_, args, context) {
51 | if (context.otherField) {
52 | return 'unexpected';
53 | }
54 | context.otherField = true;
55 | return context.testField;
56 | },
57 | },
58 | testRootValue: {
59 | type: GraphQLString,
60 | resolve(rootValue) {
61 | return rootValue;
62 | },
63 | },
64 | testArgument: {
65 | type: GraphQLString,
66 | args: { echo: { type: GraphQLString } },
67 | resolve(root, { echo }) {
68 | return `hello ${echo}`;
69 | },
70 | },
71 | testError: {
72 | type: GraphQLString,
73 | resolve() {
74 | throw new Error('Secret error message');
75 | },
76 | },
77 | },
78 | });
79 |
80 | const personType = new GraphQLObjectType({
81 | name: 'PersonType',
82 | fields: {
83 | firstName: {
84 | type: GraphQLString,
85 | },
86 | lastName: {
87 | type: GraphQLString,
88 | },
89 | },
90 | });
91 |
92 | const mutationType = new GraphQLObjectType({
93 | name: 'MutationType',
94 | fields: {
95 | testMutation: {
96 | type: GraphQLString,
97 | args: { echo: { type: GraphQLString } },
98 | resolve(root, { echo }) {
99 | return `not really a mutation, but who cares: ${echo}`;
100 | },
101 | },
102 | testPerson: {
103 | type: personType,
104 | args: {
105 | firstName: {
106 | type: new GraphQLNonNull(GraphQLString),
107 | },
108 | lastName: {
109 | type: new GraphQLNonNull(GraphQLString),
110 | },
111 | },
112 | resolve(root, args) {
113 | return args;
114 | },
115 | },
116 | },
117 | });
118 |
119 | export const schema = new GraphQLSchema({
120 | query: queryType,
121 | mutation: mutationType,
122 | });
123 |
124 | export interface CreateAppOptions {
125 | excludeParser?: boolean;
126 | graphqlOptions?:
127 | | GraphQLOptions
128 | | { (): GraphQLOptions | Promise };
129 | graphiqlOptions?:
130 | | GraphiQL.GraphiQLData
131 | | { (): GraphiQL.GraphiQLData | Promise };
132 | }
133 |
134 | export interface CreateAppFunc {
135 | (options?: CreateAppOptions): any | Promise;
136 | }
137 |
138 | export interface DestroyAppFunc {
139 | (app: any): void | Promise;
140 | }
141 |
142 | export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => {
143 | describe('apolloServer', () => {
144 | let app;
145 |
146 | afterEach(async () => {
147 | if (app) {
148 | if (destroyApp) {
149 | await destroyApp(app);
150 | app = null;
151 | } else {
152 | app = null;
153 | }
154 | }
155 | });
156 |
157 | describe('graphqlHTTP', () => {
158 | it('can be called with an options function', async () => {
159 | app = await createApp({
160 | graphqlOptions: (): GraphQLOptions => ({ schema }),
161 | });
162 | const expected = {
163 | testString: 'it works',
164 | };
165 | const req = request(app)
166 | .post('/graphql')
167 | .send({
168 | query: 'query test{ testString }',
169 | });
170 | return req.then(res => {
171 | expect(res.status).to.equal(200);
172 | return expect(res.body.data).to.deep.equal(expected);
173 | });
174 | });
175 |
176 | it('can be called with an options function that returns a promise', async () => {
177 | app = await createApp({
178 | graphqlOptions: () => {
179 | return new Promise(resolve => {
180 | resolve({ schema });
181 | });
182 | },
183 | });
184 | const expected = {
185 | testString: 'it works',
186 | };
187 | const req = request(app)
188 | .post('/graphql')
189 | .send({
190 | query: 'query test{ testString }',
191 | });
192 | return req.then(res => {
193 | expect(res.status).to.equal(200);
194 | return expect(res.body.data).to.deep.equal(expected);
195 | });
196 | });
197 |
198 | it('throws an error if options promise is rejected', async () => {
199 | app = await createApp({
200 | graphqlOptions: () => {
201 | return (Promise.reject({}) as any) as GraphQLOptions;
202 | },
203 | });
204 | const expected = 'Invalid options';
205 | const req = request(app)
206 | .post('/graphql')
207 | .send({
208 | query: 'query test{ testString }',
209 | });
210 | return req.then(res => {
211 | expect(res.status).to.equal(500);
212 | return expect(res.error.text).to.contain(expected);
213 | });
214 | });
215 |
216 | it('rejects the request if the method is not POST or GET', async () => {
217 | app = await createApp({ excludeParser: true });
218 | const req = request(app)
219 | .head('/graphql')
220 | .send();
221 | return req.then(res => {
222 | expect(res.status).to.equal(405);
223 | expect(res.headers['allow']).to.equal('GET, POST');
224 | });
225 | });
226 |
227 | it('throws an error if POST body is missing', async () => {
228 | app = await createApp({ excludeParser: true });
229 | const req = request(app)
230 | .post('/graphql')
231 | .send();
232 | return req.then(res => {
233 | expect(res.status).to.equal(500);
234 | return expect(res.error.text).to.contain('POST body missing.');
235 | });
236 | });
237 |
238 | it('throws an error if GET query is missing', async () => {
239 | app = await createApp();
240 | const req = request(app).get(`/graphql`);
241 | return req.then(res => {
242 | expect(res.status).to.equal(400);
243 | return expect(res.error.text).to.contain('GET query missing.');
244 | });
245 | });
246 |
247 | it('can handle a basic GET request', async () => {
248 | app = await createApp();
249 | const expected = {
250 | testString: 'it works',
251 | };
252 | const query = {
253 | query: 'query test{ testString }',
254 | };
255 | const req = request(app)
256 | .get('/graphql')
257 | .query(query);
258 | return req.then(res => {
259 | expect(res.status).to.equal(200);
260 | return expect(res.body.data).to.deep.equal(expected);
261 | });
262 | });
263 |
264 | it('can handle a basic implicit GET request', async () => {
265 | app = await createApp();
266 | const expected = {
267 | testString: 'it works',
268 | };
269 | const query = {
270 | query: '{ testString }',
271 | };
272 | const req = request(app)
273 | .get('/graphql')
274 | .query(query);
275 | return req.then(res => {
276 | expect(res.status).to.equal(200);
277 | return expect(res.body.data).to.deep.equal(expected);
278 | });
279 | });
280 |
281 | it('throws error if trying to use mutation using GET request', async () => {
282 | app = await createApp();
283 | const query = {
284 | query: 'mutation test{ testMutation(echo: "ping") }',
285 | };
286 | const req = request(app)
287 | .get('/graphql')
288 | .query(query);
289 | return req.then(res => {
290 | expect(res.status).to.equal(405);
291 | expect(res.headers['allow']).to.equal('POST');
292 | return expect(res.error.text).to.contain(
293 | 'GET supports only query operation',
294 | );
295 | });
296 | });
297 |
298 | it('throws error if trying to use mutation with fragment using GET request', async () => {
299 | app = await createApp();
300 | const query = {
301 | query: `fragment PersonDetails on PersonType {
302 | firstName
303 | }
304 |
305 | mutation test {
306 | testPerson(firstName: "Test", lastName: "Me") {
307 | ...PersonDetails
308 | }
309 | }`,
310 | };
311 | const req = request(app)
312 | .get('/graphql')
313 | .query(query);
314 | return req.then(res => {
315 | expect(res.status).to.equal(405);
316 | expect(res.headers['allow']).to.equal('POST');
317 | return expect(res.error.text).to.contain(
318 | 'GET supports only query operation',
319 | );
320 | });
321 | });
322 |
323 | it('can handle a GET request with variables', async () => {
324 | app = await createApp();
325 | const query = {
326 | query: 'query test($echo: String){ testArgument(echo: $echo) }',
327 | variables: JSON.stringify({ echo: 'world' }),
328 | };
329 | const expected = {
330 | testArgument: 'hello world',
331 | };
332 | const req = request(app)
333 | .get('/graphql')
334 | .query(query);
335 | return req.then(res => {
336 | expect(res.status).to.equal(200);
337 | return expect(res.body.data).to.deep.equal(expected);
338 | });
339 | });
340 |
341 | it('can handle a basic request', async () => {
342 | app = await createApp();
343 | const expected = {
344 | testString: 'it works',
345 | };
346 | const req = request(app)
347 | .post('/graphql')
348 | .send({
349 | query: 'query test{ testString }',
350 | });
351 | return req.then(res => {
352 | expect(res.status).to.equal(200);
353 | return expect(res.body.data).to.deep.equal(expected);
354 | });
355 | });
356 |
357 | it('can handle a request with variables', async () => {
358 | app = await createApp();
359 | const expected = {
360 | testArgument: 'hello world',
361 | };
362 | const req = request(app)
363 | .post('/graphql')
364 | .send({
365 | query: 'query test($echo: String){ testArgument(echo: $echo) }',
366 | variables: { echo: 'world' },
367 | });
368 | return req.then(res => {
369 | expect(res.status).to.equal(200);
370 | return expect(res.body.data).to.deep.equal(expected);
371 | });
372 | });
373 |
374 | it('can handle a request with variables as string', async () => {
375 | app = await createApp();
376 | const expected = {
377 | testArgument: 'hello world',
378 | };
379 | const req = request(app)
380 | .post('/graphql')
381 | .send({
382 | query: 'query test($echo: String!){ testArgument(echo: $echo) }',
383 | variables: '{ "echo": "world" }',
384 | });
385 | return req.then(res => {
386 | expect(res.status).to.equal(200);
387 | return expect(res.body.data).to.deep.equal(expected);
388 | });
389 | });
390 |
391 | it('can handle a request with variables as an invalid string', async () => {
392 | app = await createApp();
393 | const req = request(app)
394 | .post('/graphql')
395 | .send({
396 | query: 'query test($echo: String!){ testArgument(echo: $echo) }',
397 | variables: '{ echo: "world" }',
398 | });
399 | return req.then(res => {
400 | expect(res.status).to.equal(400);
401 | return expect(res.error.text).to.contain(
402 | 'Variables are invalid JSON.',
403 | );
404 | });
405 | });
406 |
407 | it('can handle a request with operationName', async () => {
408 | app = await createApp();
409 | const expected = {
410 | testString: 'it works',
411 | };
412 | const req = request(app)
413 | .post('/graphql')
414 | .send({
415 | query: `
416 | query test($echo: String){ testArgument(echo: $echo) }
417 | query test2{ testString }`,
418 | variables: { echo: 'world' },
419 | operationName: 'test2',
420 | });
421 | return req.then(res => {
422 | expect(res.status).to.equal(200);
423 | return expect(res.body.data).to.deep.equal(expected);
424 | });
425 | });
426 |
427 | it('can handle introspection request', async () => {
428 | app = await createApp();
429 | const req = request(app)
430 | .post('/graphql')
431 | .send({ query: introspectionQuery });
432 | return req.then(res => {
433 | expect(res.status).to.equal(200);
434 | return expect(
435 | res.body.data.__schema.types[0].fields[0].name,
436 | ).to.equal('testString');
437 | });
438 | });
439 |
440 | it('can handle batch requests', async () => {
441 | app = await createApp();
442 | const expected = [
443 | {
444 | data: {
445 | testString: 'it works',
446 | },
447 | },
448 | {
449 | data: {
450 | testArgument: 'hello yellow',
451 | },
452 | },
453 | ];
454 | const req = request(app)
455 | .post('/graphql')
456 | .send([
457 | {
458 | query: `
459 | query test($echo: String){ testArgument(echo: $echo) }
460 | query test2{ testString }`,
461 | variables: { echo: 'world' },
462 | operationName: 'test2',
463 | },
464 | {
465 | query: `
466 | query testX($echo: String){ testArgument(echo: $echo) }`,
467 | variables: { echo: 'yellow' },
468 | operationName: 'testX',
469 | },
470 | ]);
471 | return req.then(res => {
472 | expect(res.status).to.equal(200);
473 | return expect(res.body).to.deep.equal(expected);
474 | });
475 | });
476 |
477 | it('can handle batch requests', async () => {
478 | app = await createApp();
479 | const expected = [
480 | {
481 | data: {
482 | testString: 'it works',
483 | },
484 | },
485 | ];
486 | const req = request(app)
487 | .post('/graphql')
488 | .send([
489 | {
490 | query: `
491 | query test($echo: String){ testArgument(echo: $echo) }
492 | query test2{ testString }`,
493 | variables: { echo: 'world' },
494 | operationName: 'test2',
495 | },
496 | ]);
497 | return req.then(res => {
498 | expect(res.status).to.equal(200);
499 | return expect(res.body).to.deep.equal(expected);
500 | });
501 | });
502 |
503 | it('can handle batch requests in parallel', async function() {
504 | // this test will fail due to timeout if running serially.
505 | const parallels = 100;
506 | const delayPerReq = 40;
507 | this.timeout(3000);
508 |
509 | app = await createApp();
510 | const expected = Array(parallels).fill({
511 | data: { testStringWithDelay: 'it works' },
512 | });
513 | const req = request(app)
514 | .post('/graphql')
515 | .send(
516 | Array(parallels).fill({
517 | query: `query test($delay: Int!) { testStringWithDelay(delay: $delay) }`,
518 | operationName: 'test',
519 | variables: { delay: delayPerReq },
520 | }),
521 | );
522 | return req.then(res => {
523 | expect(res.status).to.equal(200);
524 | return expect(res.body).to.deep.equal(expected);
525 | });
526 | });
527 |
528 | it('clones batch context', async () => {
529 | app = await createApp({
530 | graphqlOptions: {
531 | schema,
532 | context: { testField: 'expected' },
533 | },
534 | });
535 | const expected = [
536 | {
537 | data: {
538 | testContext: 'expected',
539 | },
540 | },
541 | {
542 | data: {
543 | testContext: 'expected',
544 | },
545 | },
546 | ];
547 | const req = request(app)
548 | .post('/graphql')
549 | .send([
550 | {
551 | query: 'query test{ testContext }',
552 | },
553 | {
554 | query: 'query test{ testContext }',
555 | },
556 | ]);
557 | return req.then(res => {
558 | expect(res.status).to.equal(200);
559 | return expect(res.body).to.deep.equal(expected);
560 | });
561 | });
562 |
563 | it('executes batch context if it is a function', async () => {
564 | let callCount = 0;
565 | app = await createApp({
566 | graphqlOptions: {
567 | schema,
568 | context: () => {
569 | callCount++;
570 | return { testField: 'expected' };
571 | },
572 | },
573 | });
574 | const expected = [
575 | {
576 | data: {
577 | testContext: 'expected',
578 | },
579 | },
580 | {
581 | data: {
582 | testContext: 'expected',
583 | },
584 | },
585 | ];
586 | const req = request(app)
587 | .post('/graphql')
588 | .send([
589 | {
590 | query: 'query test{ testContext }',
591 | },
592 | {
593 | query: 'query test{ testContext }',
594 | },
595 | ]);
596 | return req.then(res => {
597 | expect(callCount).to.equal(2);
598 | expect(res.status).to.equal(200);
599 | return expect(res.body).to.deep.equal(expected);
600 | });
601 | });
602 |
603 | it('can handle a request with a mutation', async () => {
604 | app = await createApp();
605 | const expected = {
606 | testMutation: 'not really a mutation, but who cares: world',
607 | };
608 | const req = request(app)
609 | .post('/graphql')
610 | .send({
611 | query: 'mutation test($echo: String){ testMutation(echo: $echo) }',
612 | variables: { echo: 'world' },
613 | });
614 | return req.then(res => {
615 | expect(res.status).to.equal(200);
616 | return expect(res.body.data).to.deep.equal(expected);
617 | });
618 | });
619 |
620 | it('applies the formatResponse function', async () => {
621 | app = await createApp({
622 | graphqlOptions: {
623 | schema,
624 | formatResponse(response) {
625 | response['extensions'] = { it: 'works' };
626 | return response;
627 | },
628 | },
629 | });
630 | const expected = { it: 'works' };
631 | const req = request(app)
632 | .post('/graphql')
633 | .send({
634 | query: 'mutation test($echo: String){ testMutation(echo: $echo) }',
635 | variables: { echo: 'world' },
636 | });
637 | return req.then(res => {
638 | expect(res.status).to.equal(200);
639 | return expect(res.body.extensions).to.deep.equal(expected);
640 | });
641 | });
642 |
643 | it('passes the context to the resolver', async () => {
644 | const expected = 'context works';
645 | app = await createApp({
646 | graphqlOptions: {
647 | schema,
648 | context: { testField: expected },
649 | },
650 | });
651 | const req = request(app)
652 | .post('/graphql')
653 | .send({
654 | query: 'query test{ testContext }',
655 | });
656 | return req.then(res => {
657 | expect(res.status).to.equal(200);
658 | return expect(res.body.data.testContext).to.equal(expected);
659 | });
660 | });
661 |
662 | it('passes the rootValue to the resolver', async () => {
663 | const expected = 'it passes rootValue';
664 | app = await createApp({
665 | graphqlOptions: {
666 | schema,
667 | rootValue: expected,
668 | },
669 | });
670 | const req = request(app)
671 | .post('/graphql')
672 | .send({
673 | query: 'query test{ testRootValue }',
674 | });
675 | return req.then(res => {
676 | expect(res.status).to.equal(200);
677 | return expect(res.body.data.testRootValue).to.equal(expected);
678 | });
679 | });
680 |
681 | it('returns errors', async () => {
682 | const expected = 'Secret error message';
683 | app = await createApp({
684 | graphqlOptions: {
685 | schema,
686 | },
687 | });
688 | const req = request(app)
689 | .post('/graphql')
690 | .send({
691 | query: 'query test{ testError }',
692 | });
693 | return req.then(res => {
694 | expect(res.status).to.equal(200);
695 | return expect(res.body.errors[0].message).to.equal(expected);
696 | });
697 | });
698 |
699 | it('applies formatError if provided', async () => {
700 | const expected = '--blank--';
701 | app = await createApp({
702 | graphqlOptions: {
703 | schema,
704 | formatError: err => ({ message: expected }),
705 | },
706 | });
707 | const req = request(app)
708 | .post('/graphql')
709 | .send({
710 | query: 'query test{ testError }',
711 | });
712 | return req.then(res => {
713 | expect(res.status).to.equal(200);
714 | return expect(res.body.errors[0].message).to.equal(expected);
715 | });
716 | });
717 |
718 | it('sends internal server error when formatError fails', async () => {
719 | app = await createApp({
720 | graphqlOptions: {
721 | schema,
722 | formatError: err => {
723 | throw new Error('I should be caught');
724 | },
725 | },
726 | });
727 | const req = request(app)
728 | .post('/graphql')
729 | .send({
730 | query: 'query test{ testError }',
731 | });
732 | return req.then(res => {
733 | return expect(res.body.errors[0].message).to.equal(
734 | 'Internal server error',
735 | );
736 | });
737 | });
738 |
739 | it('sends stack trace to error if debug mode is set', async () => {
740 | const expected = /at resolveFieldValueOrError/;
741 | const stackTrace = [];
742 | const origError = console.error;
743 | console.error = (...args) => stackTrace.push(args);
744 | app = await createApp({
745 | graphqlOptions: {
746 | schema,
747 | debug: true,
748 | },
749 | });
750 | const req = request(app)
751 | .post('/graphql')
752 | .send({
753 | query: 'query test{ testError }',
754 | });
755 | return req.then(res => {
756 | console.error = origError;
757 | return expect(stackTrace[0][0]).to.match(expected);
758 | });
759 | });
760 |
761 | it('sends stack trace to error log if debug mode is set', async () => {
762 | const logStub = stub(console, 'error');
763 | const expected = /at resolveFieldValueOrError/;
764 | app = await createApp({
765 | graphqlOptions: {
766 | schema,
767 | debug: true,
768 | },
769 | });
770 | const req = request(app)
771 | .post('/graphql')
772 | .send({
773 | query: 'query test{ testError }',
774 | });
775 | return req.then(res => {
776 | logStub.restore();
777 | expect(logStub.callCount).to.equal(1);
778 | return expect(logStub.getCall(0).args[0]).to.match(expected);
779 | });
780 | });
781 |
782 | it('applies additional validationRules', async () => {
783 | const expected = 'alwaysInvalidRule was really invalid!';
784 | const alwaysInvalidRule = function(context) {
785 | return {
786 | enter() {
787 | context.reportError(new GraphQLError(expected));
788 | return BREAK;
789 | },
790 | };
791 | };
792 | app = await createApp({
793 | graphqlOptions: {
794 | schema,
795 | validationRules: [alwaysInvalidRule],
796 | },
797 | });
798 | const req = request(app)
799 | .post('/graphql')
800 | .send({
801 | query: 'query test{ testString }',
802 | });
803 | return req.then(res => {
804 | expect(res.status).to.equal(400);
805 | return expect(res.body.errors[0].message).to.equal(expected);
806 | });
807 | });
808 | });
809 |
810 | describe('renderGraphiQL', () => {
811 | it('presents GraphiQL when accepting HTML', async () => {
812 | app = await createApp({
813 | graphiqlOptions: {
814 | endpointURL: '/graphql',
815 | },
816 | });
817 |
818 | const req = request(app)
819 | .get('/graphiql')
820 | .query('query={test}')
821 | .set('Accept', 'text/html');
822 | return req.then(response => {
823 | expect(response.status).to.equal(200);
824 | expect(response.type).to.equal('text/html');
825 | expect(response.text).to.include('{test}');
826 | expect(response.text).to.include('/graphql');
827 | expect(response.text).to.include('graphiql.min.js');
828 | });
829 | });
830 |
831 | it('allows options to be a function', async () => {
832 | app = await createApp({
833 | graphiqlOptions: () => ({
834 | endpointURL: '/graphql',
835 | }),
836 | });
837 |
838 | const req = request(app)
839 | .get('/graphiql')
840 | .set('Accept', 'text/html');
841 | return req.then(response => {
842 | expect(response.status).to.equal(200);
843 | });
844 | });
845 |
846 | it('handles options function errors', async () => {
847 | app = await createApp({
848 | graphiqlOptions: () => {
849 | throw new Error('I should be caught');
850 | },
851 | });
852 |
853 | const req = request(app)
854 | .get('/graphiql')
855 | .set('Accept', 'text/html');
856 | return req.then(response => {
857 | expect(response.status).to.equal(500);
858 | });
859 | });
860 |
861 | it('presents options variables', async () => {
862 | app = await createApp({
863 | graphiqlOptions: {
864 | endpointURL: '/graphql',
865 | variables: { key: 'optionsValue' },
866 | },
867 | });
868 |
869 | const req = request(app)
870 | .get('/graphiql')
871 | .set('Accept', 'text/html');
872 | return req.then(response => {
873 | expect(response.status).to.equal(200);
874 | expect(response.text.replace(/\s/g, '')).to.include(
875 | 'variables:"{\\n\\"key\\":\\"optionsValue\\"\\n}"',
876 | );
877 | });
878 | });
879 |
880 | it('presents query variables over options variables', async () => {
881 | app = await createApp({
882 | graphiqlOptions: {
883 | endpointURL: '/graphql',
884 | variables: { key: 'optionsValue' },
885 | },
886 | });
887 |
888 | const req = request(app)
889 | .get('/graphiql?variables={"key":"queryValue"}')
890 | .set('Accept', 'text/html');
891 | return req.then(response => {
892 | expect(response.status).to.equal(200);
893 | expect(response.text.replace(/\s/g, '')).to.include(
894 | 'variables:"{\\n\\"key\\":\\"queryValue\\"\\n}"',
895 | );
896 | });
897 | });
898 | });
899 |
900 | describe('stored queries', () => {
901 | it('works with formatParams', async () => {
902 | const store = new OperationStore(schema);
903 | store.put('query testquery{ testString }');
904 | app = await createApp({
905 | graphqlOptions: {
906 | schema,
907 | formatParams(params) {
908 | params['query'] = store.get(params.operationName);
909 | return params;
910 | },
911 | },
912 | });
913 | const expected = { testString: 'it works' };
914 | const req = request(app)
915 | .post('/graphql')
916 | .send({
917 | operationName: 'testquery',
918 | });
919 | return req.then(res => {
920 | expect(res.status).to.equal(200);
921 | return expect(res.body.data).to.deep.equal(expected);
922 | });
923 | });
924 |
925 | it('can reject non-whitelisted queries', async () => {
926 | const store = new OperationStore(schema);
927 | store.put('query testquery{ testString }');
928 | app = await createApp({
929 | graphqlOptions: {
930 | schema,
931 | formatParams(params) {
932 | if (params.query) {
933 | throw new Error('Must not provide query, only operationName');
934 | }
935 | params['query'] = store.get(params.operationName);
936 | return params;
937 | },
938 | },
939 | });
940 | const expected = [
941 | {
942 | data: {
943 | testString: 'it works',
944 | },
945 | },
946 | {
947 | errors: [
948 | {
949 | message: 'Must not provide query, only operationName',
950 | },
951 | ],
952 | },
953 | ];
954 |
955 | const req = request(app)
956 | .post('/graphql')
957 | .send([
958 | {
959 | operationName: 'testquery',
960 | },
961 | {
962 | query: '{ testString }',
963 | },
964 | ]);
965 | return req.then(res => {
966 | expect(res.status).to.equal(200);
967 | return expect(res.body).to.deep.equal(expected);
968 | });
969 | });
970 | });
971 |
972 | describe('server setup', () => {
973 | it('throws error on 404 routes', async () => {
974 | app = await createApp();
975 |
976 | const query = {
977 | query: '{ testString }',
978 | };
979 | const req = request(app)
980 | .get('/bogus-route')
981 | .query(query);
982 | return req.then(res => {
983 | expect(res.status).to.equal(404);
984 | });
985 | });
986 | });
987 | });
988 | };
989 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "experimentalDecorators": true,
8 | "lib": ["es6", "esnext", "dom"],
9 | "declaration": true,
10 | "noImplicitAny": true,
11 | "allowSyntheticDefaultImports": true,
12 | "esModuleInterop": true,
13 | "outDir": "./out/"
14 | },
15 | "include": [
16 | "./src/**/*.ts"
17 | ],
18 | "exclude": [
19 | "node_modules",
20 | "./out"
21 | ],
22 | "compileOnSave": true
23 | }
--------------------------------------------------------------------------------