diff --git a/defer/client/yarn.lock b/defer/client/yarn.lock index a0dac5c..1bc0f17 100644 --- a/defer/client/yarn.lock +++ b/defer/client/yarn.lock @@ -8,7 +8,7 @@ "@types/graphql@0.12.6": version "0.12.6" - resolved "http://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz#3d619198585fcabe5f4e1adfb5cf5f3388c66c13" + resolved "https://registry.npmjs.org/@types/graphql/-/graphql-0.12.6.tgz#3d619198585fcabe5f4e1adfb5cf5f3388c66c13" "@types/zen-observable@^0.8.0": version "0.8.0" @@ -22,12 +22,12 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -accepts@~1.3.4, accepts@~1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" dependencies: - mime-types "~2.1.18" - negotiator "0.6.1" + mime-types "~2.1.34" + negotiator "0.6.3" acorn-dynamic-import@^2.0.0: version "2.0.2" @@ -49,7 +49,7 @@ acorn-jsx@^3.0.0: acorn@^3.0.4: version "3.3.0" - resolved "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" acorn@^4.0.3, acorn@^4.0.4: version "4.0.13" @@ -394,7 +394,7 @@ async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.2, async@^2.1.4, async@^2.4.1, async@^2.5.0: +async@^2.1.2, async@^2.1.4, async@^2.4.1: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: @@ -669,7 +669,7 @@ babel-plugin-dynamic-import-node@1.1.0: babel-plugin-istanbul@^4.0.0: version "4.1.6" - resolved "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" dependencies: babel-plugin-syntax-object-rest-spread "^6.13.0" find-up "^2.1.0" @@ -682,31 +682,31 @@ babel-plugin-jest-hoist@^20.0.3: babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + resolved "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" babel-plugin-syntax-dynamic-import@6.18.0, babel-plugin-syntax-dynamic-import@^6.18.0: version "6.18.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + resolved "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" babel-plugin-syntax-flow@^6.18.0: version "6.18.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + resolved "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + resolved "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" - resolved "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + resolved "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" @@ -1151,23 +1151,25 @@ bluebird@^3.4.7: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" -body-parser@1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" dependencies: - bytes "3.0.0" + bytes "3.1.2" content-type "~1.0.4" debug "2.6.9" - depd "~1.1.1" - http-errors "~1.6.2" - iconv-lite "0.4.19" - on-finished "~2.3.0" - qs "6.5.1" - raw-body "2.3.2" - type-is "~1.6.15" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" bonjour@^3.5.0: version "3.5.0" @@ -1238,7 +1240,7 @@ browser-resolve@^1.11.2: browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" - resolved "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" dependencies: buffer-xor "^1.0.3" cipher-base "^1.0.0" @@ -1266,7 +1268,7 @@ browserify-des@^1.0.0: browserify-rsa@^4.0.0: version "4.0.1" - resolved "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + resolved "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" dependencies: bn.js "^4.1.0" randombytes "^2.0.1" @@ -1329,7 +1331,7 @@ buffer-xor@^1.0.3: buffer@^4.3.0: version "4.9.1" - resolved "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1347,6 +1349,10 @@ bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -1361,6 +1367,13 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -1443,7 +1456,7 @@ center-align@^0.1.1: chalk@1.1.3, chalk@^1.1.3: version "1.1.3" - resolved "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1699,9 +1712,11 @@ contains-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + dependencies: + safe-buffer "5.2.1" content-type-parser@^1.0.1: version "1.0.2" @@ -1721,9 +1736,9 @@ cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" -cookie@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" copy-descriptor@^0.1.0: version "0.1.1" @@ -1768,7 +1783,7 @@ create-error-class@^3.0.0: create-hash@^1.1.0, create-hash@^1.1.2: version "1.2.0" - resolved "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" dependencies: cipher-base "^1.0.1" inherits "^2.0.1" @@ -1778,7 +1793,7 @@ create-hash@^1.1.0, create-hash@^1.1.2: create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: version "1.1.7" - resolved "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" dependencies: cipher-base "^1.0.3" create-hash "^1.1.0" @@ -1949,12 +1964,6 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6. dependencies: ms "2.0.0" -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - debug@^3.0.1, debug@^3.1.0: version "3.2.5" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.5.tgz#c2418fbfd7a29f4d4f70ff4cea604d4b64c46407" @@ -2047,11 +2056,11 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" -depd@~1.1.1, depd@~1.1.2: +depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2062,9 +2071,9 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" detect-indent@^4.0.0: version "4.0.0" @@ -2093,7 +2102,7 @@ diff@^3.2.0: diffie-hellman@^5.0.0: version "5.0.3" - resolved "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" dependencies: bn.js "^4.1.0" miller-rabin "^4.0.0" @@ -2131,7 +2140,7 @@ doctrine@^2.0.0: dom-converter@~0.1: version "0.1.4" - resolved "http://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + resolved "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" dependencies: utila "~0.3" @@ -2199,7 +2208,7 @@ duplexer3@^0.1.4: duplexer@^0.1.1: version "0.1.1" - resolved "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" ecc-jsbn@~0.1.1: version "0.1.2" @@ -2217,8 +2226,8 @@ electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.67.tgz#5e8f3ffac89b4b0402c7e1a565be06f3a109abbc" elliptic@^6.0.0: - version "6.4.1" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.1.tgz#c2d0b7776911b86722c632c3c06c60f2f819939a" + version "6.5.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -2543,9 +2552,9 @@ event-emitter@~0.3.5: d "1" es5-ext "~0.10.14" -eventemitter3@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" events@^1.0.0: version "1.1.1" @@ -2613,37 +2622,38 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: homedir-polyfill "^1.0.1" express@^4.16.2: - version "4.16.3" - resolved "http://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + version "4.18.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" dependencies: - accepts "~1.3.5" + accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.18.2" - content-disposition "0.5.2" + body-parser "1.20.1" + content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.3.1" + cookie "0.5.0" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.2" + depd "2.0.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.1" + finalhandler "1.2.0" fresh "0.5.2" + http-errors "2.0.0" merge-descriptors "1.0.1" methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.2" + on-finished "2.4.1" + parseurl "~1.3.3" path-to-regexp "0.1.7" - proxy-addr "~2.0.3" - qs "6.5.1" - range-parser "~1.2.0" - safe-buffer "5.1.1" - send "0.16.2" - serve-static "1.13.2" - setprototypeof "1.1.0" - statuses "~1.4.0" - type-is "~1.6.16" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" utils-merge "1.0.1" vary "~1.1.2" @@ -2666,7 +2676,7 @@ extend@~3.0.2: external-editor@^2.0.4: version "2.2.0" - resolved "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: chardet "^0.4.0" iconv-lite "^0.4.17" @@ -2822,16 +2832,16 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -finalhandler@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" dependencies: debug "2.6.9" encodeurl "~1.0.2" escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.4.0" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" unpipe "~1.0.0" find-cache-dir@^0.1.1: @@ -2877,10 +2887,8 @@ flatten@^1.0.2: resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" follow-redirects@^1.0.0: - version "1.5.8" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.8.tgz#1dbfe13e45ad969f813e86c00e5296f525c885a1" - dependencies: - debug "=3.1.0" + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" @@ -2904,9 +2912,9 @@ form-data@~2.3.2: combined-stream "1.0.6" mime-types "^2.1.12" -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" fragment-cache@^0.2.1: version "0.2.1" @@ -2978,6 +2986,14 @@ get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" +get-intrinsic@^1.0.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -3078,7 +3094,7 @@ globby@^6.1.0: got@^6.7.1: version "6.7.1" - resolved "http://registry.npmjs.org/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" dependencies: create-error-class "^3.0.0" duplexer3 "^0.1.4" @@ -3133,12 +3149,13 @@ handle-thing@^1.2.5: resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" handlebars@^4.0.3: - version "4.0.12" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + version "4.7.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" dependencies: - async "^2.5.0" - optimist "^0.6.1" + minimist "^1.2.5" + neo-async "^2.6.0" source-map "^0.6.1" + wordwrap "^1.0.0" optionalDependencies: uglify-js "^3.1.4" @@ -3171,6 +3188,10 @@ has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -3202,7 +3223,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1: +has@^1.0.1, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: @@ -3216,8 +3237,8 @@ hash-base@^3.0.0: safe-buffer "^5.0.1" hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.5.tgz#e38ab4b85dfb1e0c40fe9265c0e9b54854c23812" + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" dependencies: inherits "^2.0.3" minimalistic-assert "^1.0.1" @@ -3314,18 +3335,19 @@ http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" -http-errors@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" http-errors@~1.6.2: version "1.6.3" - resolved "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: depd "~1.1.2" inherits "2.0.3" @@ -3346,10 +3368,10 @@ http-proxy-middleware@~0.17.4: micromatch "^2.3.11" http-proxy@^1.16.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" dependencies: - eventemitter3 "^3.0.0" + eventemitter3 "^4.0.0" follow-redirects "^1.0.0" requires-port "^1.0.0" @@ -3365,17 +3387,13 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -iconv-lite@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -3441,14 +3459,18 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -3496,9 +3518,9 @@ ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" -ipaddr.js@1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" is-absolute-url@^2.0.0: version "2.1.0" @@ -3673,7 +3695,7 @@ is-number@^4.0.0: is-obj@^1.0.0: version "1.0.1" - resolved "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-path-cwd@^1.0.0: version "1.0.0" @@ -4174,7 +4196,7 @@ json5@^0.5.0, json5@^0.5.1: jsonfile@^2.1.0: version "2.4.0" - resolved "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" @@ -4477,8 +4499,8 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" methods@~1.1.2: version "1.1.2" @@ -4527,21 +4549,27 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + "mime-db@>= 1.34.0 < 2", mime-db@~1.36.0: version "1.36.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.36.0.tgz#5020478db3c7fe93aad7bbcc4dcf869c43363397" -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19: version "2.1.20" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.20.tgz#930cb719d571e903738520f8470911548ca2cc19" dependencies: mime-db "~1.36.0" -mime@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + dependencies: + mime-db "1.52.0" -mime@^1.4.1, mime@^1.5.0: +mime@1.6.0, mime@^1.4.1, mime@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -4571,15 +4599,11 @@ minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: minimist@0.0.8: version "0.0.8" - resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: - version "1.2.0" - resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@~0.0.1: - version "0.0.10" - resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" minipass@^2.2.1, minipass@^2.3.3: version "2.3.4" @@ -4603,7 +4627,7 @@ mixin-deep@^1.2.0: mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" - resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" @@ -4611,6 +4635,10 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + ms@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" @@ -4662,13 +4690,13 @@ needle@^2.2.1: iconv-lite "^0.4.4" sax "^1.2.4" -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" -neo-async@^2.5.0: - version "2.5.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.2.tgz#489105ce7bc54e709d736b195f82135048c50fcc" +neo-async@^2.5.0, neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" next-tick@1: version "1.0.0" @@ -4846,6 +4874,10 @@ object-hash@^1.1.4: version "1.3.0" resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.0.tgz#76d9ba6ff113cf8efc0d996102851fe6723963e2" +object-inspect@^1.9.0: + version "1.12.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" + object-keys@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" @@ -4873,9 +4905,9 @@ obuf@^1.0.0, obuf@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" dependencies: ee-first "1.1.1" @@ -4907,13 +4939,6 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" -optimist@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -4941,7 +4966,7 @@ os-homedir@^1.0.0, os-homedir@^1.0.1: os-locale@^1.4.0: version "1.4.0" - resolved "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" dependencies: lcid "^1.0.0" @@ -5009,7 +5034,7 @@ param-case@2.1.x: parse-asn1@^5.0.0: version "5.1.1" - resolved "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" + resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -5040,9 +5065,9 @@ parse5@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" -parseurl@~1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" pascalcase@^0.1.1: version "0.1.1" @@ -5518,12 +5543,12 @@ prop-types@^15.5.10, prop-types@^15.6.0, prop-types@^15.6.2: loose-envify "^1.3.1" object-assign "^4.1.1" -proxy-addr@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" dependencies: - forwarded "~0.1.2" - ipaddr.js "1.8.0" + forwarded "0.2.0" + ipaddr.js "1.9.1" prr@~1.0.1: version "1.0.1" @@ -5539,7 +5564,7 @@ psl@^1.1.24: public-encrypt@^4.0.0: version "4.0.2" - resolved "http://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" + resolved "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz#46eb9107206bf73489f8b85b69d91334c6610994" dependencies: bn.js "^4.1.0" browserify-rsa "^4.0.0" @@ -5563,9 +5588,11 @@ q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" -qs@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" +qs@6.11.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + dependencies: + side-channel "^1.0.4" qs@~6.5.2: version "6.5.2" @@ -5617,17 +5644,17 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.0.3, range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" +range-parser@^1.0.3, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" -raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" dependencies: - bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" unpipe "1.0.0" rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: @@ -5771,7 +5798,7 @@ read-pkg@^2.0.0: readable-stream@1.0: version "1.0.34" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -5780,7 +5807,7 @@ readable-stream@1.0: readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.6: version "2.3.6" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -6060,14 +6087,14 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -safe-buffer@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -6126,23 +6153,23 @@ semver-diff@^2.0.0: version "5.5.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477" -send@0.16.2: - version "0.16.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" +send@0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" dependencies: debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" + depd "2.0.0" + destroy "1.2.0" encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" - http-errors "~1.6.2" - mime "1.4.1" - ms "2.0.0" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.4.0" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" serve-index@^1.7.2: version "1.9.1" @@ -6156,14 +6183,14 @@ serve-index@^1.7.2: mime-types "~2.1.17" parseurl "~1.3.2" -serve-static@1.13.2: - version "1.13.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" - parseurl "~1.3.2" - send "0.16.2" + parseurl "~1.3.3" + send "0.18.0" serviceworker-cache-polyfill@^4.0.0: version "4.0.0" @@ -6195,17 +6222,17 @@ setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" - resolved "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" dependencies: inherits "^2.0.1" safe-buffer "^5.0.1" @@ -6233,6 +6260,14 @@ shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -6407,14 +6442,14 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + +"statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" -statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -6584,7 +6619,7 @@ symbol-tree@^3.2.1: table@^4.0.1: version "4.0.3" - resolved "http://registry.npmjs.org/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" + resolved "https://registry.npmjs.org/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" dependencies: ajv "^6.0.1" ajv-keywords "^3.0.0" @@ -6635,7 +6670,7 @@ throat@^3.0.0: through@^2.3.6: version "2.3.8" - resolved "http://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" thunky@^1.0.2: version "1.0.2" @@ -6695,6 +6730,10 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + toposort@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" @@ -6738,12 +6777,12 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-is@~1.6.15, type-is@~1.6.16: - version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" dependencies: media-typer "0.3.0" - mime-types "~2.1.18" + mime-types "~2.1.24" typedarray@^0.0.6: version "0.0.6" @@ -6753,7 +6792,7 @@ ua-parser-js@^0.7.18: version "0.7.18" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" -uglify-js@3.4.x, uglify-js@^3.0.13, uglify-js@^3.1.4: +uglify-js@3.4.x, uglify-js@^3.0.13: version "3.4.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" dependencies: @@ -6769,6 +6808,10 @@ uglify-js@^2.8.29: optionalDependencies: uglify-to-browserify "~1.0.0" +uglify-js@^3.1.4: + version "3.10.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.10.4.tgz#dd680f5687bc0d7a93b14a3482d16db6eba2bfbb" + uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" @@ -7076,8 +7119,8 @@ websocket-driver@>=0.5.1: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" whatwg-encoding@^1.0.1: version "1.0.4" @@ -7138,11 +7181,7 @@ wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - -wordwrap@~1.0.0: +wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -7154,7 +7193,7 @@ worker-farm@^1.3.1: wrap-ansi@^2.0.0: version "2.1.0" - resolved "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -7221,7 +7260,7 @@ yargs-parser@^7.0.0: yargs@6.6.0: version "6.6.0" - resolved "http://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + resolved "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" dependencies: camelcase "^3.0.0" cliui "^3.2.0" @@ -7275,7 +7314,7 @@ yargs@^8.0.2: yargs@~3.10.0: version "3.10.0" - resolved "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" diff --git a/performance-checks/.gitignore b/performance-checks/.gitignore new file mode 100644 index 0000000..9243c63 --- /dev/null +++ b/performance-checks/.gitignore @@ -0,0 +1,26 @@ +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/performance-checks/README.md b/performance-checks/README.md new file mode 100644 index 0000000..686df65 --- /dev/null +++ b/performance-checks/README.md @@ -0,0 +1,122 @@ +# Performance checks + +This example has a few mechanisms to prevent your GraphQL server from dealing with expensive queries sent by abusive clients +(or maybe legitimate clients that running expensive queries unaware of the negative impacts they might cause). +Also, it has a couple of timeout strategies that, although won't help ease the burden on the server (since the expensive +operations are already under way), will provide a better experience to the consumer that won't have to wait forever for +their requests to return. + +Here we introduce 4 mechanisms to help with that task. 3 of them are based on GraphQL Java instrumentation capabilities, +and the forth one is a bit out GraphQL Java jurisdiction and more related to web servers. + +1. MaxQueryDepthInstrumentation: limit the depth of queries to 5 +2. MaxQueryComplexityInstrumentation: set complexity values to fields and limit query complexity to 5 +3. A custom Instrumentation that sets a timeout period of 3 seconds for DataFetchers +4. A hard request timeout of 10 seconds, specified in the web server level (Spring) + +The first 2 items will actually prevent server overload, since they act before the request reach the DataFetchers, which +perform the expensive operations. Number 3 and 4 are timeouts that force long running executions to return early to customers. + +# The schema +The schema we're using is quite simple: + +```graphql +type Query { + instrumentedField(sleep: Int): String + characters: [Character] +} + +type Character { + name: String! + friends: [Character] + energy: Float +} +``` + +There are a few interesting facts related to this example. + +* instrumentedField: returns a fixed string ("value"). It receives a parameter "sleep" that forces the DataFetcher to + take that amount of seconds to return. Set that value to anything above 3 seconds and a timeout error will be thrown. + This simulates a long running DataFetcher that would be forcefully stopped. + +```graphql +{ + instrumentedField(sleep: 4) # will result in an error +} +``` + +* friends: will return a list of characters, that can themselves have friends, and so on... It's quite clear that queries + might overuse this field and end up having a large number of nested friends and characters. Add 5 or more levels of + friends and an error will be thrown. + +```graphql +{ + characters { + name + friends { + name + friends { + name + friends { + name + friends { + name # an error will be thrown, since the depth is higher than the limit + } + } + } + } + } +} +``` + +* energy: getting this field involves some expensive calculations, so we've established that it has a complexity value + of 3 (all the other fields have complexity 0). We've also defined that a query can have a maximum complexity of 5. So, + if "energy" is present 2 times or more in a given query, an error will be thrown. + +```graphql +{ + characters { + name + energy + friends { + name + energy # an error will be thrown, since we've asked for "energy" 2 times + } + } +} +``` + +# Request timeout +Although this is not really GraphQL Java business, it might be useful to set a hard request timeout on the web server +level. +To achieve this using Spring, the following property can be used: + +``` +spring.mvc.async.request-timeout=10000 +``` + + +# Running the code + + To build the example code in this repository type: + +``` +./gradlew build + ``` + +To run the example code type: + +``` +./gradlew bootRun +``` + +To access the example application, point your browser at: + http://localhost:8080/ + +## Note about introspection and max query depth +A bad side effect of specifying a maximum depth for queries is that this will prevent introspection queries to properly +execute. This affects GraphiQL's documentation and autocomplete features, that will simply not work. +This is a tricky problem to fix and [has been discussed in the past](https://github.com/graphql-java/graphql-java/issues/1055). + +You can still use GraphiQL to execute queries and inspect results. If you want documentation and autocomplete back in +GraphiQL, just temporarily disable the max depth instrumentation. diff --git a/performance-checks/build.gradle b/performance-checks/build.gradle new file mode 100644 index 0000000..91aa379 --- /dev/null +++ b/performance-checks/build.gradle @@ -0,0 +1,33 @@ +buildscript { + ext { + springBootVersion = '2.0.5.RELEASE' + } + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + } +} + +apply plugin: 'java' +apply plugin: 'eclipse' +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +group = 'com.graphql-java.examples' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + + +dependencies { + compile "io.reactivex.rxjava2:rxjava:2.1.5" + implementation('org.springframework.boot:spring-boot-starter-web') + implementation('com.graphql-java:graphql-java:10.0') + implementation('com.google.guava:guava:26.0-jre') + testImplementation('org.springframework.boot:spring-boot-starter-test') +} diff --git a/performance-checks/gradle/wrapper/gradle-wrapper.jar b/performance-checks/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..1ce6e58 Binary files /dev/null and b/performance-checks/gradle/wrapper/gradle-wrapper.jar differ diff --git a/performance-checks/gradle/wrapper/gradle-wrapper.properties b/performance-checks/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3953aff --- /dev/null +++ b/performance-checks/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sun Oct 07 10:24:43 AEDT 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-all.zip diff --git a/performance-checks/gradlew b/performance-checks/gradlew new file mode 100755 index 0000000..4453cce --- /dev/null +++ b/performance-checks/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/performance-checks/gradlew.bat b/performance-checks/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/performance-checks/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/performance-checks/settings.gradle b/performance-checks/settings.gradle new file mode 100644 index 0000000..4febc54 --- /dev/null +++ b/performance-checks/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'performance-checks' diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/Application.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/Application.java new file mode 100644 index 0000000..91ffe44 --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/Application.java @@ -0,0 +1,12 @@ +package com.graphql.java.examples.performance.checks; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLController.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLController.java new file mode 100644 index 0000000..8693d6b --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLController.java @@ -0,0 +1,82 @@ +package com.graphql.java.examples.performance.checks; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import graphql.ExecutionInput; +import graphql.GraphQL; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * The controller that exposes the GET and POST /graphql endpoints + * + * What is special about this controller is that the request methods return a {@link Callable} wrapping the actual + * value maps. This is to activate the global timeout property, defined by `spring.mvc.async.request-timeout` in the + * `application.properties` file. + */ +@RestController +public class GraphQLController { + private final GraphQL graphql; + private final ObjectMapper objectMapper; + + @Autowired + public GraphQLController(GraphQL graphql, ObjectMapper objectMapper) { + this.graphql = graphql; + this.objectMapper = objectMapper; + } + + @RequestMapping(value = "/graphql", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @CrossOrigin + public Callable> graphqlGET(@RequestParam("query") String query, + @RequestParam(value = "operationName", required = false) String operationName, + @RequestParam("variables") String variablesJson + ) throws IOException { + final Map variables = new LinkedHashMap<>(); + + if (variablesJson != null) { + variables.putAll(objectMapper.readValue(variablesJson, new TypeReference>() {})); + } + + return () -> executeGraphqlQuery(query, operationName, variables); + } + + @SuppressWarnings("unchecked") + @RequestMapping(value = "/graphql", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + @CrossOrigin + public Callable> graphql(@RequestBody Map body) { + + final String query = (String) body.get("query"); + + String operationName = (String) body.get("operationName"); + + final Map variables = new LinkedHashMap<>(); + + if (body.get("variables") != null) { + variables.putAll((Map) body.get("variables")); + } + + return () -> executeGraphqlQuery(query, operationName, variables); + } + + private Map executeGraphqlQuery(String query, String operationName, Map variables) { + ExecutionInput executionInput = ExecutionInput.newExecutionInput() + .query(query) + .operationName(operationName) + .variables(variables) + .build(); + return this.graphql.execute(executionInput).toSpecification(); + } + + +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLDataFetchers.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLDataFetchers.java new file mode 100644 index 0000000..1c45dba --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLDataFetchers.java @@ -0,0 +1,57 @@ +package com.graphql.java.examples.performance.checks; + +import com.graphql.java.examples.performance.checks.data.FilmCharacter; +import com.graphql.java.examples.performance.checks.data.StarWarsData; +import graphql.schema.DataFetcher; +import org.springframework.stereotype.Component; + +import javax.naming.Context; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; + +@Component +public class GraphQLDataFetchers { + public DataFetcher getInstrumentedFieldDataFetcher() { + return environment -> { + final Integer sleepTime = environment.getArgument("sleep"); + + sleep(sleepTime); + + return "value"; + }; + } + + public DataFetcher getCharactersDataFetcher() { + return environment -> StarWarsData.getAllCharacters(); + } + + public DataFetcher getFriendsDataFetcher() { + return environment -> { + FilmCharacter character = environment.getSource(); + List friendIds = character.getFriends(); + + return friendIds.stream().map(StarWarsData::getCharacter).collect(toList()); + }; + } + + public DataFetcher getEnergyDataFetcher() { + return environment -> Math.random() * 1000; + } + + static void sleep(Integer seconds) { + if(seconds == null) { + return; + } + + try { + TimeUnit.SECONDS.sleep(seconds); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLProvider.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLProvider.java new file mode 100644 index 0000000..f735a28 --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/GraphQLProvider.java @@ -0,0 +1,82 @@ +package com.graphql.java.examples.performance.checks; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableMap; +import com.google.common.io.Resources; +import com.graphql.java.examples.performance.checks.instrumentation.InstrumentationFactory; +import graphql.GraphQL; +import graphql.execution.instrumentation.ChainedInstrumentation; +import graphql.execution.instrumentation.Instrumentation; +import graphql.schema.GraphQLSchema; +import graphql.schema.idl.RuntimeWiring; +import graphql.schema.idl.SchemaGenerator; +import graphql.schema.idl.SchemaParser; +import graphql.schema.idl.TypeDefinitionRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; + +import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; + +@Component +public class GraphQLProvider { + @Autowired + private GraphQLDataFetchers graphQLDataFetchers; + + private GraphQL graphQL; + + @PostConstruct + public void init() throws IOException { + URL url = Resources.getResource("schema.graphql"); + String sdl = Resources.toString(url, Charsets.UTF_8); + GraphQLSchema graphQLSchema = buildSchema(sdl); + + Instrumentation chainedInstrumentation = new ChainedInstrumentation(Arrays.asList( + InstrumentationFactory.maxDepthInstrumentation(5), + InstrumentationFactory.timeoutInstrumentation(3, "instrumentedField"), + InstrumentationFactory.maxComplexityInstrumentation( + 5, + ImmutableMap.builder() + .put("energy", 3) + .build() + ) + )); + + this.graphQL = GraphQL + .newGraphQL(graphQLSchema) + .instrumentation(chainedInstrumentation) + .build(); + } + + private GraphQLSchema buildSchema(String sdl) { + TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl); + RuntimeWiring runtimeWiring = buildWiring(); + SchemaGenerator schemaGenerator = new SchemaGenerator(); + return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); + } + + private RuntimeWiring buildWiring() { + return RuntimeWiring.newRuntimeWiring() + .type(newTypeWiring("Query") + .dataFetcher("instrumentedField", graphQLDataFetchers.getInstrumentedFieldDataFetcher()) + .dataFetcher("characters", graphQLDataFetchers.getCharactersDataFetcher()) + .build()) + .type(newTypeWiring("Character") + .dataFetcher("friends", graphQLDataFetchers.getFriendsDataFetcher()) + .dataFetcher("energy", graphQLDataFetchers.getEnergyDataFetcher()) + ) + .build(); + + } + + @Bean + public GraphQL graphQL() { + return graphQL; + } + +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/data/FilmCharacter.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/data/FilmCharacter.java new file mode 100644 index 0000000..27e2495 --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/data/FilmCharacter.java @@ -0,0 +1,30 @@ +package com.graphql.java.examples.performance.checks.data; + +import java.util.List; + +/** + * A character from the movie Star Wars + */ +public class FilmCharacter { + final String id; + final String name; + final List friends; + + public FilmCharacter(String id, String name, List friends) { + this.id = id; + this.name = name; + this.friends = friends; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public List getFriends() { + return friends; + } +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/data/StarWarsData.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/data/StarWarsData.java new file mode 100644 index 0000000..50891a0 --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/data/StarWarsData.java @@ -0,0 +1,70 @@ +package com.graphql.java.examples.performance.checks.data; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import static java.util.Arrays.asList; + +/** + * A fake, static, "database" containing data about a few Star Wars characters + */ +@SuppressWarnings("unused") +public class StarWarsData { + static FilmCharacter luke = new FilmCharacter( + "1000", + "Luke Skywalker", + asList("1002", "1003") + ); + + static FilmCharacter vader = new FilmCharacter( + "1001", + "Darth Vader", + asList("1004") + ); + + static FilmCharacter han = new FilmCharacter( + "1002", + "Han Solo", + asList("1000", "1003") + ); + + static FilmCharacter leia = new FilmCharacter( + "1003", + "Leia Organa", + asList("1000", "1002") + ); + + static FilmCharacter tarkin = new FilmCharacter( + "1004", + "Wilhuff Tarkin", + asList("1001") + ); + + static Map characterData = new LinkedHashMap<>(); + + static { + characterData.put("1000", luke); + characterData.put("1001", vader); + characterData.put("1002", han); + characterData.put("1003", leia); + characterData.put("1004", tarkin); + } + + public static boolean isFilmCharacter(String id) { + return characterData.get(id) != null; + } + + public static Collection getAllCharacters() { + return characterData.values(); + } + + public static FilmCharacter getCharacter(String id) { + if (characterData.get(id) != null) { + return characterData.get(id); + } else if (characterData.get(id) != null) { + return characterData.get(id); + } + return null; + } +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/instrumentation/InstrumentationFactory.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/instrumentation/InstrumentationFactory.java new file mode 100644 index 0000000..d50309d --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/instrumentation/InstrumentationFactory.java @@ -0,0 +1,70 @@ +package com.graphql.java.examples.performance.checks.instrumentation; + +import graphql.analysis.MaxQueryComplexityInstrumentation; +import graphql.analysis.MaxQueryDepthInstrumentation; +import graphql.execution.instrumentation.Instrumentation; + +import java.util.Map; + +/** + * Contains methods to create instances of the 3 {@link Instrumentation} used in this example + */ +public class InstrumentationFactory { + + /** + * Creates an instance of our custom {@link TimeoutInstrumentation} + * + * @param timeoutSeconds the timeout period in seconds + * @param fields which fields should have their {@link graphql.schema.DataFetcher} instrumented + * @return an instance of {@link TimeoutInstrumentation} + * @see TimeoutInstrumentation + */ + public static Instrumentation timeoutInstrumentation(int timeoutSeconds, String... fields) { + return new TimeoutInstrumentation(timeoutSeconds, fields); + } + + /** + * Creates an instance of the {@link MaxQueryDepthInstrumentation}, defined in the GraphQL Java library + *

+ * This Instrumentation will analyze the incoming GraphQL queries and, if they contain more nested fields than + * the limit specified by maxDepth, an error will be thrown before any data fetchers execute. + * + * @param maxDepth the maximum depth allowed in the queries + * @return an instance of {@link MaxQueryDepthInstrumentation} + */ + public static Instrumentation maxDepthInstrumentation(int maxDepth) { + return new MaxQueryDepthInstrumentation(maxDepth); + } + + /** + * Creates an instance of the {@link MaxQueryComplexityInstrumentation}, defined in the GraphQL Java library + *

+ * This Instrumentation will analyze the incoming GraphQL queries and, if the sum of the complexity of the fields + * used in the query is higher than the limit specified by maxComplexity an error will be thrown before any + * data fetchers execute. + *

+ * The default implementation of {@link MaxQueryComplexityInstrumentation} considers that every field has a + * complexity of 1. This behaviour can be extended by providing an implementation of + * {@link graphql.analysis.FieldComplexityCalculator}. + *

+ * The example {@link Instrumentation} created by this method allows the consumer to specify arbitrary + * complexity for each field. + * + * @param maxComplexity the maximum complexity allowed in the query + * @param fieldsComplexity a map containing the complexity of each field. Fields that are not contained in the map + * are considered to have complexity equal to 0. + * @return an instance of {@link MaxQueryComplexityInstrumentation} + */ + public static Instrumentation maxComplexityInstrumentation( + int maxComplexity, Map fieldsComplexity + ) { + return new MaxQueryComplexityInstrumentation(maxComplexity, (environment, childComplexity) -> { + final String fieldName = environment.getField().getName(); + + final int thisComplexity = fieldsComplexity.getOrDefault(fieldName, 0); + + return thisComplexity + childComplexity; + }); + } + +} diff --git a/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/instrumentation/TimeoutInstrumentation.java b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/instrumentation/TimeoutInstrumentation.java new file mode 100644 index 0000000..999876b --- /dev/null +++ b/performance-checks/src/main/java/com/graphql/java/examples/performance/checks/instrumentation/TimeoutInstrumentation.java @@ -0,0 +1,60 @@ +package com.graphql.java.examples.performance.checks.instrumentation; + +import graphql.execution.instrumentation.SimpleInstrumentation; +import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters; +import graphql.schema.DataFetcher; +import io.reactivex.Observable; +import io.reactivex.schedulers.Schedulers; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * A custom Instrumentation that will stop a Data Fetcher that takes too long to return a value. + *

+ * This Instrumentation will act only when the query is being executed. Some other Instrumentations + * (like {@link graphql.analysis.MaxQueryDepthInstrumentation} and {@link graphql.analysis.MaxQueryComplexityInstrumentation}) + * have their rules applied when the query is being analyzed. + */ +public class TimeoutInstrumentation extends SimpleInstrumentation { + private final int timeoutSeconds; + private final List fields; + + /** + * @param timeoutSeconds the timeout period in seconds + * @param fields which fields should have their {@link DataFetcher} instrumented + */ + public TimeoutInstrumentation(int timeoutSeconds, String... fields) { + this.timeoutSeconds = timeoutSeconds; + this.fields = Arrays.asList(fields); + } + + /** + * Wraps the {@link DataFetcher} in another instance of {@link DataFetcher} that will throw a Timeout error + * if the original one takes too long to return. + * + * @param dataFetcher the original {@link DataFetcher} + * @param parameters contains data about the environment and parameters + * @return + */ + @Override + public DataFetcher instrumentDataFetcher( + DataFetcher dataFetcher, InstrumentationFieldFetchParameters parameters + ) { + // Only apply instrumentation to specified fields + if (!fields.contains(parameters.getEnvironment().getField().getName())) { + return dataFetcher; + } + + // Times out if the original dataFetcher doesn't return before the specified period. + // This implementation is using RxJava Observables but it could very well be implemented using + // CompletableFutures or Threads + return environment -> + Observable.fromCallable(() -> dataFetcher.get(environment)) + .subscribeOn(Schedulers.computation()) + .timeout(timeoutSeconds, TimeUnit.SECONDS) + .blockingFirst(); + + } +} diff --git a/performance-checks/src/main/resources/application.properties b/performance-checks/src/main/resources/application.properties new file mode 100644 index 0000000..de3799f --- /dev/null +++ b/performance-checks/src/main/resources/application.properties @@ -0,0 +1,4 @@ +# Specifies a timeout for all requests served by this application +# This is kind of a "last resource" timeout. If any of the mechanisms implemented programmatically in the app +# fail to prevent long running requests, they will still be killed by this global timeout. +spring.mvc.async.request-timeout=10000 diff --git a/performance-checks/src/main/resources/schema.graphql b/performance-checks/src/main/resources/schema.graphql new file mode 100644 index 0000000..f30e2a3 --- /dev/null +++ b/performance-checks/src/main/resources/schema.graphql @@ -0,0 +1,16 @@ + +type Query { + instrumentedField(sleep: Int): String + characters: [Character] +} + +type Character { + # "name" is cheap to obtain, so its complexity value is 0. + name: String! + # a list of "friends" can nest another list of friends, and so on. This nesting can go on forever, + # so, in the code, we limit the amount of nested fields to 5. + friends: [Character] + # the "energy" field is very expensive to calculate. So it has a complexity of value of 3. + energy: Float +} + diff --git a/performance-checks/src/main/resources/static/index.html b/performance-checks/src/main/resources/static/index.html new file mode 100644 index 0000000..8efc68c --- /dev/null +++ b/performance-checks/src/main/resources/static/index.html @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + +

+

Welcome to spring-boot integration example

+
+
Loading graphiql editor...
+ + \ No newline at end of file diff --git a/performance-checks/src/test/java/com/graphql/java/examples/performance/checks/ApplicationTests.java b/performance-checks/src/test/java/com/graphql/java/examples/performance/checks/ApplicationTests.java new file mode 100644 index 0000000..86f56e4 --- /dev/null +++ b/performance-checks/src/test/java/com/graphql/java/examples/performance/checks/ApplicationTests.java @@ -0,0 +1,16 @@ +package com.graphql.java.examples.performance.checks; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/settings.gradle b/settings.gradle index 491bd6e..4547ad1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,5 +4,4 @@ include 'http-example' include 'spring-boot-integration' include 'hibernate-example' include 'subscription-example' - - +include 'performance-checks' diff --git a/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/Application.java b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/Application.java new file mode 100644 index 0000000..91ffe44 --- /dev/null +++ b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/Application.java @@ -0,0 +1,12 @@ +package com.graphql.java.examples.performance.checks; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLController.java b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLController.java new file mode 100644 index 0000000..c5d2488 --- /dev/null +++ b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLController.java @@ -0,0 +1,74 @@ +package com.graphql.java.examples.performance.checks; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import graphql.ExecutionInput; +import graphql.GraphQL; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +@RestController +public class GraphQLController { + + + private final GraphQL graphql; + private final ObjectMapper objectMapper; + + @Autowired + public GraphQLController(GraphQL graphql, ObjectMapper objectMapper) { + this.graphql = graphql; + this.objectMapper = objectMapper; + } + + @RequestMapping(value = "/graphql", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) + @CrossOrigin + public Map graphqlGET(@RequestParam("query") String query, + @RequestParam(value = "operationName", required = false) String operationName, + @RequestParam("variables") String variablesJson + ) throws IOException { + Map variables = new LinkedHashMap<>(); + if (variablesJson != null) { + variables = objectMapper.readValue(variablesJson, new TypeReference>() { + }); + } + return executeGraphqlQuery(query, operationName, variables); + } + + + @SuppressWarnings("unchecked") + @RequestMapping(value = "/graphql", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + @CrossOrigin + public Map graphql(@RequestBody Map body) { + String query = (String) body.get("query"); + if (query == null) { + query = ""; + } + String operationName = (String) body.get("operationName"); + Map variables = (Map) body.get("variables"); + if (variables == null) { + variables = new LinkedHashMap<>(); + } + return executeGraphqlQuery(query, operationName, variables); + } + + private Map executeGraphqlQuery(String query, String operationName, Map variables) { + ExecutionInput executionInput = ExecutionInput.newExecutionInput() + .query(query) + .operationName(operationName) + .variables(variables) + .build(); + return this.graphql.execute(executionInput).toSpecification(); + } + + +} diff --git a/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLDataFetchers.java b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLDataFetchers.java new file mode 100644 index 0000000..622cb01 --- /dev/null +++ b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLDataFetchers.java @@ -0,0 +1,19 @@ +package com.graphql.java.examples.performance.checks; + +import graphql.schema.DataFetcher; +import org.springframework.stereotype.Component; + +@Component +public class GraphQLDataFetchers { + + + public DataFetcher getHelloWorldDataFetcher() { + return environment -> "world"; + } + + public DataFetcher getEchoDataFetcher() { + return environment -> environment.getArgument("toEcho"); + } + + +} diff --git a/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLProvider.java b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLProvider.java new file mode 100644 index 0000000..d052213 --- /dev/null +++ b/spring-boot-integration/src/main/java/com/graphql/java/examples/performance/checks/GraphQLProvider.java @@ -0,0 +1,60 @@ +package com.graphql.java.examples.performance.checks; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import graphql.GraphQL; +import graphql.schema.GraphQLSchema; +import graphql.schema.idl.RuntimeWiring; +import graphql.schema.idl.SchemaGenerator; +import graphql.schema.idl.SchemaParser; +import graphql.schema.idl.TypeDefinitionRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.net.URL; + +import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring; + +@Component +public class GraphQLProvider { + + + @Autowired + GraphQLDataFetchers graphQLDataFetchers; + + private GraphQL graphQL; + + @PostConstruct + public void init() throws IOException { + URL url = Resources.getResource("schema.graphql"); + String sdl = Resources.toString(url, Charsets.UTF_8); + GraphQLSchema graphQLSchema = buildSchema(sdl); + this.graphQL = GraphQL.newGraphQL(graphQLSchema).build(); + } + + private GraphQLSchema buildSchema(String sdl) { + TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl); + RuntimeWiring runtimeWiring = buildWiring(); + SchemaGenerator schemaGenerator = new SchemaGenerator(); + return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); + } + + private RuntimeWiring buildWiring() { + return RuntimeWiring.newRuntimeWiring() + .type(newTypeWiring("Query") + .dataFetcher("hello", graphQLDataFetchers.getHelloWorldDataFetcher()) + .dataFetcher("echo", graphQLDataFetchers.getEchoDataFetcher()) + .build()) + .build(); + + } + + @Bean + public GraphQL graphQL() { + return graphQL; + } + +} diff --git a/spring-boot-integration/src/test/java/com/graphql/java/examples/performance/checks/ApplicationTests.java b/spring-boot-integration/src/test/java/com/graphql/java/examples/performance/checks/ApplicationTests.java new file mode 100644 index 0000000..86f56e4 --- /dev/null +++ b/spring-boot-integration/src/test/java/com/graphql/java/examples/performance/checks/ApplicationTests.java @@ -0,0 +1,16 @@ +package com.graphql.java.examples.performance.checks; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + + @Test + public void contextLoads() { + } + +}